/**************************************************************************** * apps/graphics/nuttx/pdcdisp.c * * Copyright (C) 2017, 2019 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * 3. Neither the name NuttX nor the names of its contributors may be * used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * ****************************************************************************/ /**************************************************************************** * Included Files ****************************************************************************/ #include #include #ifdef CONFIG_SYSTEM_TERMCURSES #include #endif #include #include "pdcnuttx.h" /**************************************************************************** * Public Data ****************************************************************************/ /* A port of PDCurses must provide acs_map[], a 128-element array of chtypes, * with values laid out based on the Alternate Character Set of the VT100 * (see curses.h). PDC_transform_line() must use this table; when it * encounters a chtype with the A_ALTCHARSET flag set, and an A_CHARTEXT * value in the range 0-127, it must render it using the A_CHARTEXT portion * of the corresponding value from this table, instead of the original * value. Also, values may be read from this table by apps, and passed * through functions such as waddch(), which does no special processing on * control characters (0-31 and 127) when the A_ALTCHARSET flag is set. * Thus, any control characters used in acs_map[] should also have the * A_ALTCHARSET flag set. Implementations should provide suitable values * for all the ACS_ macros defined in curses.h; other values in the table * should be filled with their own indices (e.g., acs_map['E'] == 'E'). The * table can be either hardwired, or filled by PDC_scr_open(). Existing * ports define it in pdcdisp.c, but this is not required. */ #ifdef CONFIG_PDCURSES_CHTYPE_LONG # define A(x) ((chtype)x | A_ALTCHARSET) chtype acs_map[128] = { A(0), A(1), A(2), A(3), A(4), A(5), A(6), A(7), A(8), A(9), A(10), A(11), A(12), A(13), A(14), A(15), A(16), A(17), A(18), A(19), A(20), A(21), A(22), A(23), A(24), A(25), A(26), A(27), A(28), A(29), A(30), A(31), ' ', '!', '"', '#', '$', '%', '&', '\'', '(', ')', '*', A(0x1a), A(0x1b), A(0x18), A(0x19), '/', 0xdb, '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '<', '=', '>', '?', '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '[', '\\', ']', '^', '_', A(0x04), 0xb1, 'b', 'c', 'd', 'e', 0xf8, 0xf1, 0xb0, A(0x0f), 0xd9, 0xbf, 0xda, 0xc0, 0xc5, 0x2d, 0x2d, 0xc4, 0x2d, 0x5f, 0xc3, 0xb4, 0xc1, 0xc2, 0xb3, 0xf3, 0xf2, 0xe3, 0xd8, 0x9c, 0xf9, A(127) }; #endif /**************************************************************************** * Private Functions ****************************************************************************/ /**************************************************************************** * Name: PDC_pixel_[x|y] * * Description: * Convert row or column text position to framebuffer x/y positions * in pixels. * ****************************************************************************/ static inline fb_coord_t PDC_pixel_x(FAR struct pdc_fbstate_s *fbstate, int col) { return col * fbstate->fwidth + fbstate->hoffset; } static inline fb_coord_t PDC_pixel_y(FAR struct pdc_fbstate_s *fbstate, int row) { return row * fbstate->fheight + fbstate->voffset; } /**************************************************************************** * Name: PDC_fbmem_[x|y] * * Description: * Convert row or column pixel position to framebuffer x/y byte offsets. * * NOTE: For BPP={8,16,32} this function returns the exact positions. For * the case of BPP={1,2,4}, PDC_fbmem_x() aligns down to the address of * the byte Aligns down to the byte that contains the 'col' pixel. * ****************************************************************************/ static inline uintptr_t PDC_fbmem_x(FAR struct pdc_fbstate_s *fbstate, int col) { return (PDC_pixel_x(fbstate, col) * PDCURSES_BPP) >> 3; } static inline uintptr_t PDC_fbmem_y(FAR struct pdc_fbstate_s *fbstate, int row) { return PDC_pixel_y(fbstate, row) * fbstate->stride; } /**************************************************************************** * Name: PDC_color * * Description: * Convert a pixel code to a RGB device pixel. * ****************************************************************************/ static inline pdc_color_t PDC_color(FAR struct pdc_fbstate_s *fbstate, short color) { #if defined (CONFIG_PDCURSES_COLORFMT_Y1) /* Returns 8 pixels packed into a byte */ return (fbstate->greylevel[color] & 0xc0) == 0 ? 0x00 : 0xff; #elif defined (CONFIG_PDCURSES_COLORFMT_Y2) uint8_t color8; /* Returns 4 pixels packed into a byte */ color8 = fbstate->greylevel[color] >> 6; color8 = color8 << 2 | color8; color8 = color8 << 4 | color8; return color8; #elif defined (CONFIG_PDCURSES_COLORFMT_Y4) uint8_t color8; /* Returns 2 pixels packed into a byte */ color8 = fbstate->greylevel[color] >> 4; color8 = color8 << 4 | color8; return color8; #elif defined(CONFIG_PDCURSES_COLORFMT_RGB332) /* Returns 8-bit RGB332 */ return RGBTO8(fbstate->rgbcolor[color].red, fbstate->rgbcolor[color].green, fbstate->rgbcolor[color].blue); #elif defined(CONFIG_PDCURSES_COLORFMT_RGB565) /* Returns 16-bit RGB565 */ return RGBTO16(fbstate->rgbcolor[color].red, fbstate->rgbcolor[color].green, fbstate->rgbcolor[color].blue); #elif defined(CONFIG_PDCURSES_COLORFMT_RGB888) /* Returns 32-bit RGB888 */ return RGBTO24(fbstate->rgbcolor[color].red, fbstate->rgbcolor[color].green, fbstate->rgbcolor[color].blue); #else # error No color format selected return 0; #endif } /**************************************************************************** * Name: PDC_set_bg * * Description: * Set memory to the device background RGB color. For the case of BPP < 8, * this is byte-aligned font buffer. For other cases, this clears a patch * of memory in the framebuffer. * ****************************************************************************/ #if PDCURSES_BPP < 8 static inline void PDC_set_bg(FAR struct pdc_fbstate_s *fbstate, FAR uint8_t *fbuffer, short bg) { uint8_t color8; int row; int col; /* Get a byte that packs multiple pixels into one byte */ color8 = PDC_color(fbstate, bg); /* Now copy the color into the entire glyph region */ for (row = 0; row < fbstate->fheight; row++, fbuffer += fbstate->fstride) { FAR uint8_t *fbdest = fbuffer; /* Note that there is no masking on the "right" side, so this will * set color in the unused bits in the final byte of the glyph row. * This should be harmless. */ for (col = 0; col < fbstate->fwidth; col += PDCURSES_PPB) { *fbdest++ = color8; } } } #else static inline void PDC_set_bg(FAR struct pdc_fbstate_s *fbstate, FAR uint8_t *fbstart, short bg) { pdc_color_t bgcolor = PDC_color(fbstate, bg); int row; int col; /* Set the glyph to the background color. */ for (row = 0; row < fbstate->fheight; row++, fbstart += fbstate->stride) { FAR pdc_color_t *fbdest; for (col = 0, fbdest = (FAR pdc_color_t *)fbstart; col < fbstate->fwidth; col++) { *fbdest++ = bgcolor; } } } #endif /**************************************************************************** * Name: PDC_render_glyph * * Description: * Render the font into the glyph memory using the foreground RGB color. * ****************************************************************************/ static inline void PDC_render_glyph(FAR struct pdc_fbstate_s *fbstate, FAR const struct nx_fontbitmap_s *fbm, FAR uint8_t *fbstart, short fg) { pdc_color_t fgcolor = PDC_color(fbstate, fg); unsigned int stride; int ret; /* Are we rendering into the framebuffer or the font buffer. The only * difference here is the stride value. */ #if PDCURSES_BPP < 8 stride = fbstate->fstride; /* Width of the font buffer in bytes */ #else stride = fbstate->stride; /* Width of the framebuffer in bytes */ #endif /* Then render the glyph into the allocated memory * * REVISIT: The case where visibility==1 is not yet handled. In that * case, only the lower quarter of the glyph should be reversed. */ ret = RENDERER((FAR pdc_color_t *)fbstart, fbstate->fheight, fbstate->fwidth, stride, fbm, fgcolor); if (ret < 0) { /* Actually, the RENDERER never returns a failure */ PDC_LOG(("ERROR: RENDERER failed: %d\n", ret)); } } /**************************************************************************** * Name: PDC_copy_glyph * * Description: * Copy the font from the the font buffer into the correct location in the * the frame buffer. * * For the case of pixel depth less then 1-byte, we will need to rend the * font into a font buffer first, then copy it into the frame buffer at * the correct position when the font is completely rendered. * ****************************************************************************/ #if PDCURSES_BPP < 8 static inline void PDC_copy_glyph(FAR struct pdc_fbstate_s *fbstate, FAR uint8_t *dest, unsigned int xpos) { FAR const uint8_t *srcrow; FAR const uint8_t *sptr; FAR uint8_t *destrow; FAR uint8_t *dptr; unsigned int srcend; unsigned int dststart; unsigned int dstend; unsigned int row; unsigned int npixels; uint8_t lshift; uint8_t rshift; uint8_t lmask; uint8_t rmask; int n; /* Handle the case where the first or last bytes may require read, modify, * write operations. * * Get the start and end column in pixels (relative to the start position). */ dststart = PDC_pixel_x(fbstate, xpos) & PDCURSES_PPB_MASK; dstend = dststart + fbstate->fwidth; /* The data in the font buffer is probably shifted with respect to the * byte position in the framebuffer. */ lshift = (PDCURSES_PPB - dststart) << PDCURSES_BPP_SHIFT; rshift = (dstend & PDCURSES_PPB_MASK) << PDCURSES_BPP_SHIFT; #ifdef CONFIG_NXFONTS_PACKEDMSFIRST /* Get the mask for pixels that are ordered so that they pack from the * MS byte down. */ lmask = 0xff << lshift; rmask = 0xff >> rshift; #else # warning Unverified /* Get the mask for pixels that are ordered so that they pack from the * LS byte up. */ lmask = 0xff >> lshift; rmask = 0xff << rshift; #endif /* Fixups. Range of lshift should be 0-7, not 1-8; Make all masks 0x00 * if no masking is needed. Convert dstend to a byte offset into the frame * buffer. */ lshift &= 7; rmask = (rmask == 0xff) ? 0x00 : rmask; /* Convert dstend to a byte offset into the frame buffer. * Calculate srcend, the byte offset into the font buffer. */ srcend = (fbstate->fwidth - 1) >> PDCURSES_PPB_SHIFT; dstend = (dstend - 1) >> PDCURSES_PPB_SHIFT; /* Then copy the image */ for (row = 0, srcrow = fbstate->fbuffer, destrow = dest; row < fbstate->fheight; row++, srcrow += fbstate->fstride, destrow += fbstate->stride) { /* Handle masking of the fractional initial byte */ sptr = srcrow; /* Set to the beginning of the src row */ dptr = destrow; /* Set to the beginning of the dest row */ npixels = fbstate->fwidth; /* Number of pixels to copy */ /* Special case: Only one byte will be transferred */ if (dstend == 0) { uint8_t dmask = lmask | rmask; /* Perform the read/modify/write */ #ifdef CONFIG_NXFONTS_PACKEDMSFIRST *destrow = (*destrow & dmask) | ((*srcrow >> (8 - lshift)) & ~rmask); #else # warning Unverified *destrow = (*destrow & dmask) | ((*srcrow << (8 - lshift)) & ~rmask); #endif continue; } /* Handle masking of the left, leading byte */ if (lmask != 0x00) { /* Perform the read/modify/write */ #ifdef CONFIG_NXFONTS_PACKEDMSFIRST *destrow = (*destrow & lmask) | (*srcrow >> (8 - lshift)); #else # warning Unverified *destrow = (*destrow & lmask) | (*srcrow << (8 - lshift)); #endif dptr++; /* Skip to the next destination byte */ npixels -= lshift; /* Decrement number of pixels to copy */ } /* Handle masking of the fractional final byte */ if (rmask != 0x00) { /* Perform the read/modify/write */ #ifdef CONFIG_NXFONTS_PACKEDMSFIRST destrow[dstend] = (destrow[dstend] & rmask) | ((srcrow[srcend] << lshift) & ~rmask); #else # warning Unverified destrow[dstend] = (destrow[dstend] & rmask) | ((srcrow[srcend] >> lshift) & ~rmask); #endif npixels -= rshift; /* Decrement number of pixels to copy */ } /* Handle all of the unmasked bytes in-between */ if (lshift > 0) { #ifdef CONFIG_NXFONTS_PACKEDMSFIRST uint16_t shifted; shifted = (uint16_t)sptr[0] << (8 + lshift) | (uint16_t)sptr[1] << lshift; sptr++; for (n = lshift; n < npixels; n += 8) { *dptr++ = (shifted >> 8); shifted = (shifted << 8) | (uint16_t)sptr[1] << lshift; sptr++; } #else # error Missing logic #endif } else { for (n = 0; n < npixels; n += 8) { *dptr++ = *sptr++; } } } } #endif /**************************************************************************** * Name: PDC_update * * Description: * Update the LCD display is necessary. * ****************************************************************************/ #ifdef CONFIG_FB_UPDATE static void PDC_update(FAR struct pdc_fbstate_s *fbstate, int row, int col, int nchars) { struct fb_area_s area; int ret; if (nchars > 0) { /* Setup the bounding rectangle */ area.x = PDC_pixel_x(fbstate, col); area.y = PDC_pixel_y(fbstate, row); area.w = nchars * fbstate->fwidth; area.h = fbstate->fheight; /* Then perform the update via IOCTL */ ret = ioctl(fbstate->fbfd, FBIO_UPDATE, (unsigned long)((uintptr_t)&area)); if (ret < 0) { PDC_LOG(("ERROR: ioctl(FBIO_UPDATE) failed: %d\n", errno)); } } } #else # define PDC_update(f,r,c,n) #endif /**************************************************************************** * Name: PDC_putc * * Description: * Put one character with selected attributes at the selected drawing * position. * ****************************************************************************/ static void PDC_putc(FAR struct pdc_fbstate_s *fbstate, int row, int col, chtype ch) { FAR const struct nx_fontbitmap_s *fbm; FAR uint8_t *dest; short fg; short bg; #ifdef HAVE_BOLD_FONT bool bold = ((ch & A_BOLD) != 0); #endif #ifdef CONFIG_PDCURSES_MULTITHREAD FAR struct pdc_context_s *ctx = PDC_ctx(); #endif /* Clip */ if (row < 0 || row >= SP->lines || col < 0 || col >= SP->cols) { PDC_LOG(("ERROR: Position out of range: row=%d col=%d\n", row, col)); return; } /* Get the foreground and background colors of the character */ PDC_pair_content(PAIR_NUMBER(ch), &fg, &bg); /* Handle the A_REVERSE attribute. */ if ((ch & A_REVERSE) != 0) { /* Swap the foreground and background colors if reversed */ short tmp = fg; fg = bg; bg = tmp; } #ifdef CONFIG_PDCURSES_CHTYPE_LONG /* Translate characters 0-127 via acs_map[], if they're flagged with * A_ALTCHARSET in the attribute portion of the chtype. */ if (ch & A_ALTCHARSET && !(ch & 0xff80)) { ch = (ch & (A_ATTRIBUTES ^ A_ALTCHARSET)) | acs_map[ch & 0x7f]; } #endif #if PDCURSES_BPP < 8 /* For the case of pixel depth less then 1-byte, we will need to rend the * font into a font buffer first, then copy it into the frame buffer at * the correct position when the font is completely rendered. */ dest = fbstate->fbuffer; #else /* Otherwise, we can rend directly into the frame buffer. Calculate the * destination address in the framebuffer. */ dest = (FAR uint8_t *)fbstate->fbmem + PDC_fbmem_y(fbstate, row) + PDC_fbmem_x(fbstate, col); #endif /* Initialize the glyph to the (possibly reversed) background color */ PDC_set_bg(fbstate, dest, bg); /* Does the code map to a font? */ #ifdef HAVE_BOLD_FONT fbm = nxf_getbitmap(bold ? fbstate->hfont : fbstate->hbold, ch & A_CHARTEXT); #else fbm = nxf_getbitmap(fbstate->hfont, ch & A_CHARTEXT); #endif if (fbm != NULL) { /* Yes.. render the glyph */ PDC_render_glyph(fbstate, fbm, dest, fg); } /* Apply more attributes */ if ((ch & (A_UNDERLINE | A_LEFTLINE | A_RIGHTLINE)) != 0) { #warning Missing logic } #if PDCURSES_BPP < 8 /* Font is now completely rendered into the font buffer and can be copied * to the framebuffer. * * Calculate the destination address in the framebuffer. */ dest = (FAR uint8_t *)fbstate->fbmem + PDC_fbmem_y(fbstate, row) + PDC_fbmem_x(fbstate, col); /* Then copy the glyph */ PDC_copy_glyph(fbstate, dest, col); #endif } /**************************************************************************** * Name: PDC_gotoyx * * Description: * Move the physical cursor (as opposed to the logical cursor affected by * wmove()) to the given location. T his is called mainly from doupdate(). * In general, this function need not compare the old location with the * new one, and should just move the cursor unconditionally. * ****************************************************************************/ #ifdef CONFIG_SYSTEM_TERMCURSES static void PDC_gotoyx_term(FAR SCREEN *s, int row, int col) { FAR struct pdc_termscreen_s *termscreen = (FAR struct pdc_termscreen_s *)s; FAR struct pdc_termstate_s *termstate; termstate = &termscreen->termstate; termcurses_moveyx(termstate->tcurs, row, col); } #endif /**************************************************************************** * Name: PDC_set_char_attrib_term * * Description: * Sets the specified character attributes. * ****************************************************************************/ #ifdef CONFIG_SYSTEM_TERMCURSES static void PDC_set_char_attrib_term(FAR struct pdc_termscreen_s *termscreen, chtype ch) { FAR struct pdc_termstate_s *termstate = &termscreen->termstate; struct termcurses_colors_s colors; short fg; short bg; long attrib; long term_attrib; /* Handle the attributes */ #ifdef CONFIG_PDCURSES_CHTYPE_LONG attrib = ch & (A_BOLD | A_BLINK | A_UNDERLINE | A_INVIS); #else attrib = ch & (A_BOLD | A_BLINK); #endif if (attrib != termstate->attrib) { /* Send the ioctl to set the attributes */ term_attrib = 0; if (attrib & A_BOLD) { term_attrib |= TCURS_ATTRIB_BOLD; } if (attrib & A_BLINK) { term_attrib |= TCURS_ATTRIB_BLINK; } #ifdef CONFIG_PDCURSES_CHTYPE_LONG if (attrib & A_UNDERLINE) { term_attrib |= TCURS_ATTRIB_UNDERLINE; } if (attrib & A_INVIS) { term_attrib |= TCURS_ATTRIB_INVIS; } termcurses_setattribute(termstate->tcurs, term_attrib); #endif termstate->attrib = attrib; } /* Get the character colors */ PDC_pair_content(PAIR_NUMBER(ch), &fg, &bg); /* Handle the A_REVERSE attribute. */ if ((ch & A_REVERSE) != 0) { /* Swap the foreground and background colors if reversed */ short tmp = fg; fg = bg; bg = tmp; } /* Set the color */ colors.color_mask = 0; #ifdef PDCURSES_MONOCHROME if (fg != termstate->fg) { colors.fg_red = termstate->graylevel[fg]; colors.fg_green = termstate->graylevel[fg]; colors.fg_blue = termstate->graylevel[fg]; colors.color_mask |= TCURS_COLOR_FG; } if (bg != termstate->bg) { colors.bg_red = termstate->graylevel[bg]; colors.bg_green = termstate->graylevel[bg]; colors.bg_blue = termstate->graylevel[bg]; colors.color_mask |= TCURS_COLOR_BG; } #else if (termstate->rgbcolor[fg].red != termstate->fg_red || termstate->rgbcolor[fg].green != termstate->fg_green || termstate->rgbcolor[fg].blue != termstate->fg_blue) { colors.fg_red = termstate->rgbcolor[fg].red; colors.fg_green = termstate->rgbcolor[fg].green; colors.fg_blue = termstate->rgbcolor[fg].blue; colors.color_mask |= TCURS_COLOR_FG; } if (termstate->rgbcolor[bg].red != termstate->bg_red || termstate->rgbcolor[bg].green != termstate->bg_green || termstate->rgbcolor[bg].blue != termstate->bg_blue) { colors.bg_red = termstate->rgbcolor[bg].red; colors.bg_green = termstate->rgbcolor[bg].green; colors.bg_blue = termstate->rgbcolor[bg].blue; colors.color_mask |= TCURS_COLOR_BG; } #endif if (colors.color_mask) { /* Set selected colors with the terminal emulation */ termcurses_setcolors(termstate->tcurs, &colors); /* Save a reference to the last colors sent */ termstate->fg_red = termstate->rgbcolor[fg].red; termstate->fg_green = termstate->rgbcolor[fg].green; termstate->fg_blue = termstate->rgbcolor[fg].blue; termstate->bg_red = termstate->rgbcolor[bg].red; termstate->bg_green = termstate->rgbcolor[bg].green; termstate->bg_blue = termstate->rgbcolor[bg].blue; } } #endif /* CONFIG_SYSTEM_TERMCURSES */ /**************************************************************************** * Name: PDC_transform_line_term * * Description: * The core output routine. It takes len chtype entities from srcp (a * pointer into curscr) and renders them to the physical screen at line * lineno, column x. It must also translate characters 0-127 via acs_map[], * if they're flagged with A_ALTCHARSET in the attribute portion of the * chtype. * ****************************************************************************/ #ifdef CONFIG_SYSTEM_TERMCURSES static void PDC_transform_line_term(FAR SCREEN *s, int lineno, int x, int len, FAR const chtype *srcp) { FAR struct pdc_termscreen_s *termscreen = (FAR struct pdc_termscreen_s *)s; FAR struct pdc_termstate_s *termstate = &termscreen->termstate; int c; int i; char ch; char buffer[128]; /* Move to the specified line / col */ PDC_gotoyx_term(sp, lineno, x); /* Loop through all characters to be displayed */ for (c = 0; c < len; ) { /* Get the foreground and background colors of the character */ PDC_set_char_attrib_term(termscreen, *srcp); /* Write next character(s) */ ch = *srcp & 0x7f; buffer[0] = ch; for (i = 1; i < sizeof(buffer) && c + i < len; i++) { /* Break if the attributes change */ if ((*(srcp + i) & A_ATTRIBUTES) != (*srcp & A_ATTRIBUTES)) { break; } ch = *(srcp + i) & 0x7f; buffer[i] = ch; } /* Update source pointer and write data */ if (*srcp & A_ALTCHARSET) { write(termstate->out_fd, "\x1b(0", 3); write(termstate->out_fd, buffer, i); write(termstate->out_fd, "\x1b(B", 3); } else { write(termstate->out_fd, buffer, i); } srcp += i; c += i; } } #endif /* CONFIG_SYSTEM_TERMCURSES */ /**************************************************************************** * Public Functions ****************************************************************************/ /**************************************************************************** * Name: PDC_gotoyx * * Description: * Move the physical cursor (as opposed to the logical cursor affected by * wmove()) to the given location. T his is called mainly from doupdate(). * In general, this function need not compare the old location with the * new one, and should just move the cursor unconditionally. * ****************************************************************************/ void PDC_gotoyx(int row, int col) { #ifdef CONFIG_PDCURSES_MULTITHREAD FAR struct pdc_context_s *ctx = PDC_ctx(); #endif FAR struct pdc_fbscreen_s *fbscreen = (FAR struct pdc_fbscreen_s *)SP; FAR struct pdc_fbstate_s *fbstate; int oldrow; int oldcol; chtype ch; PDC_LOG(("PDC_gotoyx() - called: row %d col %d\n", row, col)); #ifdef CONFIG_SYSTEM_TERMCURSES if (!graphic_screen) { PDC_gotoyx_term(SP, row, col); return; } #endif DEBUGASSERT(fbscreen != NULL); fbstate = &fbscreen->fbstate; /* Clear the old cursor */ oldrow = SP->cursrow; oldcol = SP->curscol; PDC_putc(fbstate, oldrow, oldcol, curscr->_y[oldrow][oldcol]); PDC_update(fbstate, oldrow, oldcol, 1); if (SP->visibility != 0) { /* Draw a new cursor by overprinting the existing character in * reverse. NOTE: visibility {1, 2} are treated the same. */ ch = curscr->_y[row][col] ^ A_REVERSE; PDC_putc(fbstate, row, col, ch); PDC_update(fbstate, row, col, 1); } } /**************************************************************************** * Name: PDC_transform_line * * Description: * The core output routine. It takes len chtype entities from srcp (a * pointer into curscr) and renders them to the physical screen at line * lineno, column x. It must also translate characters 0-127 via acs_map[], * if they're flagged with A_ALTCHARSET in the attribute portion of the * chtype. * ****************************************************************************/ void PDC_transform_line(int lineno, int x, int len, const chtype *srcp) { #ifdef CONFIG_PDCURSES_MULTITHREAD FAR struct pdc_context_s *ctx = PDC_ctx(); #endif FAR struct pdc_fbscreen_s *fbscreen = (FAR struct pdc_fbscreen_s *)SP; FAR struct pdc_fbstate_s *fbstate; int nextx; int i; PDC_LOG(("PDC_transform_line() - called: lineno=%d x=%d len=%d\n", lineno, x, len)); #ifdef CONFIG_SYSTEM_TERMCURSES if (!graphic_screen) { /* User terminal transformation routine */ PDC_transform_line_term(SP, lineno, x, len, srcp); return; } #endif DEBUGASSERT(fbscreen != NULL); fbstate = &fbscreen->fbstate; /* Add each character to the framebuffer at the current position, * incrementing the horizontal position after each character. */ for (i = 0, nextx = x; i < len; i++, nextx++) { if (nextx >= SP->cols) { PDC_LOG(("ERROR: Write past end of line\n")); break; } /* Render the font glyph into the framebuffer */ PDC_putc(fbstate, lineno, nextx, srcp[i]); } PDC_update(fbstate, lineno, x, nextx - x); } /**************************************************************************** * Name: PDC_clear_screen * * Description: * Set the framebuffer content to a single color * ****************************************************************************/ void PDC_clear_screen(FAR struct pdc_fbstate_s *fbstate) { FAR pdc_color_t *dest; FAR pdc_color_t bgcolor; FAR uint8_t *line; int width; int row; int col; #ifdef CONFIG_FB_UPDATE struct fb_area_s area; int ret; #endif /* Get the background color and display width */ bgcolor = PDCURSES_INIT_COLOR; /* Background color for one pixel */ width = fbstate->xres; /* Width in units of pixels */ #if PDCURSES_BPP < 8 /* Pack multiple pixels into one byte. Works for BPP={1,2,4} */ #if PDCURSES_BPP == 1 /* BPP = 1 */ bgcolor &= 1; /* Isolate 0 */ bgcolor = bgcolor << 1 | bgcolor; /* Replicate 0 to 1 */ bgcolor = bgcolor << 2 | bgcolor; /* Replicate 0-1 to 2-3 */ bgcolor = bgcolor << 4 | bgcolor; /* Replicate 0-3 to 4-7 */ #elif PDCURSES_BPP == 2 /* BPP = 2 */ bgcolor &= 3; /* Isolate 0-1 */ bgcolor = bgcolor << 2 | bgcolor; /* Replicate 0-1 to 2-3 */ bgcolor = bgcolor << 4 | bgcolor; /* Replicate 0-3 to 4-7 */ #else /* BPP = 4 */ bgcolor &= 15; /* Isolate 0-3 */ bgcolor = bgcolor << 4 | bgcolor; /* Replicate 0-3 to 4-7 */ #endif /* Convert the width of the display to units of bytes. */ width = (width + PDCURSES_PPB - 1) / PDCURSES_PPB; #endif /* Write the initial color into the entire framebuffer */ for (row = 0, line = (FAR uint8_t *)fbstate->fbmem; row < fbstate->yres; row++, line += fbstate->stride) { for (col = 0, dest = (FAR pdc_color_t *)line; col < width; col++) { *dest++ = bgcolor; } } #ifdef CONFIG_FB_UPDATE /* Update the entire display */ /* Setup the bounding rectangle */ area.x = 0; area.y = 0; area.w = fbstate->xres; area.h = fbstate->yres; /* Then perform the update via IOCTL */ ret = ioctl(fbstate->fbfd, FBIO_UPDATE, (unsigned long)((uintptr_t)&area)); if (ret < 0) { PDC_LOG(("ERROR: ioctl(FBIO_UPDATE) failed: %d\n", errno)); } #endif }