diff --git a/configs/pcblogic-pic32mx/src/pic32mx_lcd1602.c b/configs/pcblogic-pic32mx/src/pic32mx_lcd1602.c index 50697c587f..bf564cf96a 100644 --- a/configs/pcblogic-pic32mx/src/pic32mx_lcd1602.c +++ b/configs/pcblogic-pic32mx/src/pic32mx_lcd1602.c @@ -116,7 +116,17 @@ # undef CONFIG_DEBUG_LCD #endif -/* Pin configuratin *********************************************************/ +/* The ever-present MIN/MAX macros ******************************************/ + +#ifndef MIN +# define MIN(a,b) (a < b ? a : b) +#endif + +#ifndef MAX +# define MAX(a,b) (a > b ? a : b) +#endif + +/* Pin configuration ********************************************************/ /* RB15, RS -- High values selects data */ #define GPIO_LCD_RS (GPIO_OUTPUT|GPIO_VALUE_ZERO|GPIO_PORTB|GPIO_PIN15) @@ -166,8 +176,11 @@ struct lcd1602_2 #if defined(CONFIG_DEBUG_LCD) && defined(CONFIG_DEBUG_VERBOSE) static void lcd_dumpstate(FAR const char *msg); +static void lcd_dumpstream(FAR const char *msg, + FAR const struct lcd_instream_s *stream); #else # define lcd_dumpstate(msg) +# define lcd_dumpstream(msg, stream) #endif /* Internal functions */ @@ -252,6 +265,21 @@ static void lcd_dumpstate(FAR const char *msg) } #endif +/**************************************************************************** + * Name: lcd_dumpstate + ****************************************************************************/ + +#if defined(CONFIG_DEBUG_LCD) && defined(CONFIG_DEBUG_VERBOSE) +static void lcd_dumpstream(FAR const char *msg, + FAR const struct lcd_instream_s *stream) +{ + lcdvdbg("%s:\n", msg); + lcdvdbg(" nget: %d nbytes: %d\n", + stream->stream.nget, stream->nbytes); + lib_dumpbuffer("STREAM", stream->buffer, stream->nbytes); +} +#endif + /**************************************************************************** * Name: lcd_getstream * @@ -418,61 +446,86 @@ static void lcd_action(enum slcdcode_e code, uint8_t count) case SLCDCODE_BACKDEL: /* Backspace (backward delete) N characters */ { - /* If we are at the home position, then ignore the action */ + int tmp; - if (g_lcd1602.curcol < 1) + /* If we are at the home position or if the count is zero, then ignore the action */ + + if (g_lcd1602.curcol < 1 || count < 1) { break; } - /* Otherwise, BACKDEL is like moving the cursor back one then doing a + /* Otherwise, BACKDEL is like moving the cursor back N characters then doing a * forward deletion. Decrement the cursor position and fall through. */ - g_lcd1602.curcol--; + tmp = (int)g_lcd1602.curcol - count; + if (tmp < 0) + { + tmp = 0; + count = g_lcd1602.curcol; + } + + /* Save the updated cursor positions */ + + g_lcd1602.curcol = tmp; } case SLCDCODE_FWDDEL: /* DELete (forward delete) N characters moving text */ - { - uint8_t ch; - int i; + if (count > 0) + { + int nchars; + int nmove; + int i; - /* Move all characters after the current cursor position left by one */ + /* How many characters are to the right of the cursor position + * (including the one at the cursor position)? Then get the + * number of characters to move. + */ - for (i = g_lcd1602.curcol + 1; i < LCD_NCOLUMNS - 1; i++) - { - ch = lcd_readch(g_lcd1602.currow, i); - lcd_writech(ch, g_lcd1602.currow, i - 1); - } + nchars = LCD_NCOLUMNS - g_lcd1602.curcol; + nmove = MIN(nchars, count) - 1; - /* Erase the last character on the display */ + /* Move all characters after the current cursor position left by 'nmove' characters */ - lcd_writech(' ', g_lcd1602.currow, LCD_NCOLUMNS - 1); - } + for (i = g_lcd1602.curcol + nmove; i < LCD_NCOLUMNS - 1; i++) + { + uint8_t ch = lcd_readch(g_lcd1602.currow, i); + lcd_writech(ch, g_lcd1602.currow, i - nmove); + } + + /* Erase the last 'nmove' characters on the display */ + + for (i = LCD_NCOLUMNS - nmove; i < LCD_NCOLUMNS; i++) + { + lcd_writech(' ', i, 0); + } + } break; case SLCDCODE_ERASE: /* Erase N characters from the cursor position */ - { - int last; - int i; + if (count > 0) + { + int last; + int i; - /* Get the last position to clear and make sure that the last - * position is on the SLCD. - */ + /* Get the last position to clear and make sure that the last + * position is on the SLCD. + */ - last = g_lcd1602.curcol + count - 1; - if (last >= LCD_NCOLUMNS) - { - last = LCD_NCOLUMNS - 1; - } + last = g_lcd1602.curcol + count - 1; + if (last >= LCD_NCOLUMNS) + { + last = LCD_NCOLUMNS - 1; + } - /* Erase N characters after the current cursor position left by one */ + /* Erase N characters after the current cursor position left by one */ - for (i = g_lcd1602.curcol; i < last; i++) - { - lcd_writech(' ', g_lcd1602.currow, i); - } - } + for (i = g_lcd1602.curcol; i < last; i++) + { + lcd_writech(' ', g_lcd1602.currow, i); + } + } break; case SLCDCODE_CLEAR: /* Home the cursor and erase the entire display */ @@ -518,45 +571,69 @@ static void lcd_action(enum slcdcode_e code, uint8_t count) case SLCDCODE_LEFT: /* Cursor left by N characters */ { + int tmp = (int)g_lcd1602.curcol - count; + /* Don't permit movement past the beginning of the SLCD */ - if (g_lcd1602.curcol > 0) + if (tmp < 0) { - g_lcd1602.curcol--; + tmp = 0; } + + /* Save the new cursor position */ + + g_lcd1602.curcol = (uint8_t)tmp; } break; case SLCDCODE_RIGHT: /* Cursor right by N characters */ { + int tmp = (int)g_lcd1602.curcol + count; + /* Don't permit movement past the end of the SLCD */ - if (g_lcd1602.curcol < (LCD_NCOLUMNS - 1)) + if (tmp >= LCD_NCOLUMNS) { - g_lcd1602.curcol++; + tmp = LCD_NCOLUMNS - 1; } + + /* Save the new cursor position */ + + g_lcd1602.curcol = (uint8_t)tmp; } break; case SLCDCODE_UP: /* Cursor up by N lines */ { + int tmp = (int)g_lcd1602.currow - count; + /* Don't permit movement past the top of the SLCD */ - if (g_lcd1602.currow > 0) + if (tmp < 0) { - g_lcd1602.currow--; + tmp = 0; } + + /* Save the new cursor position */ + + g_lcd1602.currow = (uint8_t)tmp; } break; case SLCDCODE_DOWN: /* Cursor down by N lines */ { + int tmp = (int)g_lcd1602.currow + count; + /* Don't permit movement past the bottom of the SLCD */ - if (g_lcd1602.currow < (LCD_NCOLUMNS - 1)) + if (tmp >= LCD_NROWS) { - g_lcd1602.currow++; + tmp = LCD_NROWS - 1; } + + /* Save the new cursor position */ + + g_lcd1602.currow = (uint8_t)tmp; } break; @@ -627,8 +704,6 @@ static ssize_t lcd_write(FAR struct file *filp, FAR const char *buffer, enum slcdret_e result; uint8_t ch; uint8_t count; - uint8_t prev = ' '; - bool valid = false; /* Initialize the stream for use with the SLCD CODEC */ @@ -637,33 +712,11 @@ static ssize_t lcd_write(FAR struct file *filp, FAR const char *buffer, instream.buffer = buffer; instream.nbytes = len; - /* Prime the pump */ - - memset(&state, 0, sizeof(struct slcdstate_s)); - result = slcd_decode(&instream.stream, &state, &prev, &count); - - lcdvdbg("slcd_decode returned result=%d char=%d count=%d\n", - result, prev, count); - - switch (result) - { - case SLCDRET_CHAR: - valid = true; - break; - - case SLCDRET_SPEC: - { - lcd_action((enum slcdcode_e)prev, count); - prev = ' '; - } - break; - - case SLCDRET_EOF: - return 0; - } + lcd_dumpstream("BEFORE WRITE", &instream); /* Now decode and process every byte in the input buffer */ + memset(&state, 0, sizeof(struct slcdstate_s)); while ((result = slcd_decode(&instream.stream, &state, &ch, &count)) != SLCDRET_EOF) { lcdvdbg("slcd_decode returned result=%d char=%d count=%d\n", @@ -679,37 +732,25 @@ static ssize_t lcd_write(FAR struct file *filp, FAR const char *buffer, if (ch == ASCII_BS) { + /* Perform the backward deletion */ + lcd_action(SLCDCODE_BACKDEL, 1); } else if (ch == ASCII_CR) { - lcd_action(SLCDCODE_HOME, 0); + /* Perform the carriage return */ + + g_lcd1602.curcol = 0; + lcd_action(SLCDCODE_DOWN, 1); } } - /* Handle characters decoreated with a period or a colon */ - - else if (ch == '.') - { - /* Write the previous character with the decimal point appended */ - - lcd_appendch(prev); - prev = ' '; - valid = false; - } - else if (ch == ':') - { - /* Write the previous character with the colon appended */ - - lcd_appendch(prev); - prev = ' '; - valid = false; - } - /* Handle ASCII_DEL */ else if (ch == ASCII_DEL) { + /* Perform the forward deletion */ + lcd_action(SLCDCODE_FWDDEL, 1); } @@ -717,34 +758,22 @@ static ssize_t lcd_write(FAR struct file *filp, FAR const char *buffer, else if (ch < 128) { - /* Write the previous character if it valid */ + /* Write the character if it valid */ - if (valid) - { - lcd_appendch(prev); - } - - /* There is now a valid output character */ - - prev = ch; - valid = true; + lcd_appendch(ch); } } else /* (result == SLCDRET_SPEC) */ /* A special SLCD action was returned */ { + /* Then Perform the action */ + lcd_action((enum slcdcode_e)ch, count); } } - /* Handle any unfinished output */ - - if (valid) - { - lcd_appendch(prev); - } - /* Assume that the entire input buffer was processed */ + lcd_dumpstream("AFTER WRITE", &instream); return (ssize_t)len; } diff --git a/configs/stm32ldiscovery/src/stm32_lcd.c b/configs/stm32ldiscovery/src/stm32_lcd.c index abc9a06443..d843fba7ee 100644 --- a/configs/stm32ldiscovery/src/stm32_lcd.c +++ b/configs/stm32ldiscovery/src/stm32_lcd.c @@ -94,6 +94,8 @@ # undef CONFIG_DEBUG_LCD #endif +/* The ever-present MIN/MAX macros ******************************************/ + #ifndef MIN # define MIN(a,b) (a < b ? a : b) #endif @@ -896,59 +898,85 @@ static void slcd_action(enum slcdcode_e code, uint8_t count) case SLCDCODE_BACKDEL: /* Backspace (backward delete) N characters */ { - /* If we are at the home position, then ignore the action */ + int tmp; - if (g_slcdstate.curpos < 1) + /* If we are at the home position or if the count is zero, then ignore the action */ + + if (g_slcdstate.curpos < 1 || count < 1) { break; } - /* Otherwise, BACKDEL is like moving the cursor back one then doing a + /* Otherwise, BACKDEL is like moving the cursor back N characters then doing a * forward deletion. Decrement the cursor position and fall through. */ - g_slcdstate.curpos--; + tmp = (int)g_slcdstate.curpos - count; + if (tmp < 0) + { + tmp = 0; + count = g_slcdstate.curpos; + } + + /* Save the updated cursor positions */ + + g_slcdstate.curpos = tmp; } case SLCDCODE_FWDDEL: /* DELete (forward delete) N characters moving text */ - { - int i; + if (count > 0) + { + int nchars; + int nmove; + int i; - /* Move all characters after the current cursor position left by one */ + /* How many characters are to the right of the cursor position + * (including the one at the cursor position)? Then get the + * number of characters to move. + */ - for (i = g_slcdstate.curpos + 1; i < SLCD_NCHARS - 1; i++) - { - slcd_writech(g_slcdstate.buffer[i-1], i, g_slcdstate.options[i-1]); - } + nchars = SLCD_CHARS - g_slcdstate.curpos; + nmove = MIN(nchars, count) - 1; - /* Erase the last character on the display */ + /* Move all characters after the current cursor position left by 'nmove' characters */ - slcd_writech(' ', SLCD_NCHARS - 1, 0); - } + for (i = g_slcdstate.curpos + nmove; i < SLCD_NCHARS - 1; i++) + { + slcd_writech(g_slcdstate.buffer[i-nmove], i, g_slcdstate.options[i-nmove]); + } + + /* Erase the last 'nmove' characters on the display */ + + for (i = SLCD_NCHARS - nmove; i < SLCD_NCHARS; i++) + { + slcd_writech(' ', i, 0); + } + } break; case SLCDCODE_ERASE: /* Erase N characters from the cursor position */ - { - int last; - int i; + if (count > 0) + { + int last; + int i; - /* Get the last position to clear and make sure that the last - * position is on the SLCD. - */ + /* Get the last position to clear and make sure that the last + * position is on the SLCD. + */ - last = g_slcdstate.curpos + count - 1; - if (last >= SLCD_NCHARS) - { - last = SLCD_NCHARS - 1; - } + last = g_slcdstate.curpos + count - 1; + if (last >= SLCD_NCHARS) + { + last = SLCD_NCHARS - 1; + } - /* Erase N characters after the current cursor position left by one */ + /* Erase N characters after the current cursor position left by one */ - for (i = g_slcdstate.curpos; i < last; i++) - { - slcd_writech(' ', i, 0); - } - } + for (i = g_slcdstate.curpos; i < last; i++) + { + slcd_writech(' ', i, 0); + } + } break; case SLCDCODE_CLEAR: /* Home the cursor and erase the entire display */ @@ -989,23 +1017,35 @@ static void slcd_action(enum slcdcode_e code, uint8_t count) case SLCDCODE_LEFT: /* Cursor left by N characters */ { + int tmp = (int)g_slcdstate.curpos - count; + /* Don't permit movement past the beginning of the SLCD */ - if (g_slcdstate.curpos > 0) + if (tmp < 0) { - g_slcdstate.curpos--; + tmp = 0; } + + /* Save the new cursor position */ + + g_slcdstate.curpos = (uint8_t)tmp; } break; case SLCDCODE_RIGHT: /* Cursor right by N characters */ { + int tmp = (int)g_slcdstate.curpos + count; + /* Don't permit movement past the end of the SLCD */ - if (g_slcdstate.curpos < (SLCD_NCHARS - 1)) + if (tmp >= SLCD_NCHARS) { - g_slcdstate.curpos++; + tmp = SLCD_NCHARS - 1; } + + /* Save the new cursor position */ + + g_slcdstate.curpos = (uint8_t)tmp; } break; @@ -1096,7 +1136,9 @@ static ssize_t slcd_write(FAR struct file *filp, instream.buffer = buffer; instream.nbytes = len; - /* Prime the pump */ + /* Prime the pump. This is messy, but necessary to handle decoration on a + * character based on any following period or colon. + */ memset(&state, 0, sizeof(struct slcdstate_s)); result = slcd_decode(&instream.stream, &state, &prev, &count); @@ -1138,10 +1180,36 @@ static ssize_t slcd_write(FAR struct file *filp, if (ch == ASCII_BS) { + /* If there is a pending character, then output it now before + * performing the action. + */ + + if (valid) + { + slcd_appendch(prev, 0); + prev = ' '; + valid = false; + } + + /* Then perform the backward deletion */ + slcd_action(SLCDCODE_BACKDEL, 1); } else if (ch == ASCII_CR) { + /* If there is a pending character, then output it now before + * performing the action. + */ + + if (valid) + { + slcd_appendch(prev, 0); + prev = ' '; + valid = false; + } + + /* Then perform the carriage return */ + slcd_action(SLCDCODE_HOME, 0); } } @@ -1169,6 +1237,19 @@ static ssize_t slcd_write(FAR struct file *filp, else if (ch == ASCII_DEL) { + /* If there is a pending character, then output it now before + * performing the action. + */ + + if (valid) + { + slcd_appendch(prev, 0); + prev = ' '; + valid = false; + } + + /* Then perform the foward deletion */ + slcd_action(SLCDCODE_FWDDEL, 1); } @@ -1191,6 +1272,19 @@ static ssize_t slcd_write(FAR struct file *filp, } else /* (result == SLCDRET_SPEC) */ /* A special SLCD action was returned */ { + /* If there is a pending character, then output it now before + * performing the action. + */ + + if (valid) + { + slcd_appendch(prev, 0); + prev = ' '; + valid = false; + } + + /* Then perform the action */ + slcd_action((enum slcdcode_e)ch, count); } }