diff --git a/.gitignore b/.gitignore index 2c78d695..d01e3dc5 100644 --- a/.gitignore +++ b/.gitignore @@ -7,4 +7,5 @@ *.dSYM *.pyc *.o +*.d tags diff --git a/Makefile b/Makefile index 9bd69d1c..c680c555 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,12 @@ +UNAME := $(shell uname) + +ifeq ($(UNAME), Linux) PORT=/dev/ttyACM0 +endif +ifeq ($(UNAME), Darwin) +PORT=/dev/tty.usbmodem1411 +endif + all: platformio -f -c vim run --target upload diff --git a/README.md b/README.md index 9dd8caf8..5b6a6436 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # KBox Firmware [![Travis -status](https://api.travis-ci.org/sarfata/kbox-firmware.svg)](https://travis-ci.org/sarfata/kbox-firmware) - [Buy KBox on +status](https://api.travis-ci.org/sarfata/kbox-firmware.svg?branch=master)](https://travis-ci.org/sarfata/kbox-firmware) - [Buy KBox on Tindie!](https://www.tindie.com/products/sarfata/kbox-open-source-boat-gateway/) ## What is KBox? diff --git a/lib/ILI9341_t3/ILI9341_t3.cpp b/lib/ILI9341_t3/ILI9341_t3.cpp index 40b18555..8b36b86f 100644 --- a/lib/ILI9341_t3/ILI9341_t3.cpp +++ b/lib/ILI9341_t3/ILI9341_t3.cpp @@ -16,6 +16,38 @@ MIT license, all text above must be included in any redistribution ****************************************************/ +// + +//Additional graphics routines by Tim Trzepacz, SoftEgg LLC added December 2015 +//(And then accidentally deleted and rewritten March 2016. Oops!) +//Gradient support +//---------------- +// fillRectVGradient - fills area with vertical gradient +// fillRectHGradient - fills area with horizontal gradient +// fillScreenVGradient - fills screen with vertical gradient +// fillScreenHGradient - fills screen with horizontal gradient + +//Additional Color Support +//------------------------ +// color565toRGB - converts 565 format 16 bit color to RGB +// color565toRGB14 - converts 16 bit 565 format color to 14 bit RGB (2 bits clear for math and sign) +// RGB14tocolor565 - converts 14 bit RGB back to 16 bit 565 format color + +//Low Memory Bitmap Support +//------------------------- +// writeRect8BPP - write 8 bit per pixel paletted bitmap +// writeRect4BPP - write 4 bit per pixel paletted bitmap +// writeRect2BPP - write 2 bit per pixel paletted bitmap +// writeRect1BPP - write 1 bit per pixel paletted bitmap + +//TODO: transparent bitmap writing routines for sprites + +//String Pixel Length support +//--------------------------- +// strPixelLen - gets pixel length of given ASCII string + +// <\SoftEgg> + #include "ILI9341_t3.h" #include @@ -44,6 +76,7 @@ ILI9341_t3::ILI9341_t3(uint8_t cs, uint8_t dc, uint8_t rst, uint8_t mosi, uint8_ textcolor = textbgcolor = 0xFFFF; wrap = true; setClipRect(); + setOrigin(); font = NULL; } @@ -63,8 +96,9 @@ void ILI9341_t3::pushColor(uint16_t color) } void ILI9341_t3::drawPixel(int16_t x, int16_t y, uint16_t color) { - - if((x < _clipx1) ||(x >= _clipx2) || (y < _clipy1) || (y >= _clipy2)) return; + x += _originx; + y += _originy; + if((x < _displayclipx1) ||(x >= _displayclipx2) || (y < _displayclipy1) || (y >= _displayclipy2)) return; SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE0)); setAddr(x, y, x, y); @@ -75,10 +109,12 @@ void ILI9341_t3::drawPixel(int16_t x, int16_t y, uint16_t color) { void ILI9341_t3::drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color) { + x+=_originx; + y+=_originy; // Rectangular clipping - if((x < _clipx1) || (x >= _clipx2) || (y >= _clipy2)) return; - if(y < _clipy1) { h = h - (_clipy1 - y); y = _clipy1;} - if((y+h-1) >= _clipy2) h = _clipy2-y; + if((x < _displayclipx1) || (x >= _displayclipx2) || (y >= _displayclipy2)) return; + if(y < _displayclipy1) { h = h - (_displayclipy1 - y); y = _displayclipy1;} + if((y+h-1) >= _displayclipy2) h = _displayclipy2-y; if(h<1) return; SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE0)); @@ -89,15 +125,17 @@ void ILI9341_t3::drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color) } writedata16_last(color); SPI.endTransaction(); - } void ILI9341_t3::drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color) { + x+=_originx; + y+=_originy; + // Rectangular clipping - if((y < _clipy1) || (x >= _clipx2) || (y >= _clipy2)) return; - if(x<_clipx1) { w = w - (_clipx1 - x); x = _clipx1; } - if((x+w-1) >= _clipx2) w = _clipx2-x; + if((y < _displayclipy1) || (x >= _displayclipx2) || (y >= _displayclipy2)) return; + if(x<_displayclipx1) { w = w - (_displayclipx1 - x); x = _displayclipx1; } + if((x+w-1) >= _displayclipx2) w = _displayclipx2-x; if (w<1) return; SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE0)); @@ -110,20 +148,137 @@ void ILI9341_t3::drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color) SPI.endTransaction(); } +void ILI9341_t3::drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t* colors) +{ + x+=_originx; + y+=_originy; + // Rectangular clipping + if((x < _displayclipx1) || (x >= _displayclipx2) || (y >= _displayclipy2)) return; + if(y < _displayclipy1) { h = h - (_displayclipy1 - y); y = _displayclipy1;} + if((y+h-1) >= _displayclipy2) h = _displayclipy2-y; + if(h<1) return; + + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE0)); + setAddr(x, y, x, y+h-1); + writecommand_cont(ILI9341_RAMWR); + int16_t i = 0; + while (i < (h-1)) { + writedata16_cont(colors[i]); + i++; + } + writedata16_last(colors[i]); + SPI.endTransaction(); +} + +void ILI9341_t3::drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t* colors) +{ + x+=_originx; + y+=_originy; + + // Rectangular clipping + if((y < _displayclipy1) || (x >= _displayclipx2) || (y >= _displayclipy2)) return; + if(x<_displayclipx1) { w = w - (_displayclipx1 - x); x = _displayclipx1; } + if((x+w-1) >= _displayclipx2) w = _displayclipx2-x; + if (w<1) return; + + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE0)); + setAddr(x, y, x+w-1, y); + writecommand_cont(ILI9341_RAMWR); + int16_t i = 0; + while (i < (w-1)) { + writedata16_cont(colors[i]); + i++; + } + writedata16_last(colors[i]); + SPI.endTransaction(); +} + void ILI9341_t3::fillScreen(uint16_t color) { - fillRect(_clipx1, _clipy1, _clipx2, _clipy2, color); + fillRect(0, 0, _width, _height, color); } // fill a rectangle void ILI9341_t3::fillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color) { + x+=_originx; + y+=_originy; + // Rectangular clipping (drawChar w/big text requires this) - if((x >= _clipx2) || (y >= _clipy2)) return; - if((x + w - 1) >= _clipx2) w = _clipx2 - x; - if((y + h - 1) >= _clipy2) h = _clipy2 - y; - if(x < _clipx1) x = _clipx1; - if(y < _clipy1) y = _clipy1; + if((x >= _displayclipx2) || (y >= _displayclipy2)) return; + if((x + w - 1) >= _displayclipx2) w = _displayclipx2 - x; + if((y + h - 1) >= _displayclipy2) h = _displayclipy2 - y; + if(x < _displayclipx1) x = _displayclipx1; + if(y < _displayclipy1) y = _displayclipy1; + + // TODO: this can result in a very long transaction time + // should break this into multiple transactions, even though + // it'll cost more overhead, so we don't stall other SPI libs + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE0)); + setAddr(x, y, x+w-1, y+h-1); + writecommand_cont(ILI9341_RAMWR); + for(y=h; y>0; y--) { + for(x=w; x>1; x--) { + writedata16_cont(color); + } + writedata16_last(color); + if (y > 1 && (y & 1)) { + SPI.endTransaction(); + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE0)); + } + } + SPI.endTransaction(); +} + +// fillRectVGradient - fills area with vertical gradient +void ILI9341_t3::fillRectVGradient(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color1, uint16_t color2) +{ + // rudimentary clipping (drawChar w/big text requires this) + if((x >= _width) || (y >= _height)) return; + if((x + w - 1) >= _width) w = _width - x; + if((y + h - 1) >= _height) h = _height - y; + + int16_t r1, g1, b1, r2, g2, b2, dr, dg, db, r, g, b; + color565toRGB14(color1,r1,g1,b1); + color565toRGB14(color2,r2,g2,b2); + dr=(r2-r1)/h; dg=(g2-g1)/h; db=(b2-b1)/h; + r=r1;g=g1;b=b1; + + // TODO: this can result in a very long transaction time + // should break this into multiple transactions, even though + // it'll cost more overhead, so we don't stall other SPI libs + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE0)); + setAddr(x, y, x+w-1, y+h-1); + writecommand_cont(ILI9341_RAMWR); + for(y=h; y>0; y--) { + uint16_t color = RGB14tocolor565(r,g,b); + + for(x=w; x>1; x--) { + writedata16_cont(color); + } + writedata16_last(color); + if (y > 1 && (y & 1)) { + SPI.endTransaction(); + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE0)); + } + r+=dr;g+=dg; b+=db; + } + SPI.endTransaction(); +} + +// fillRectHGradient - fills area with horizontal gradient +void ILI9341_t3::fillRectHGradient(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color1, uint16_t color2) +{ + // rudimentary clipping (drawChar w/big text requires this) + if((x >= _width) || (y >= _height)) return; + if((x + w - 1) >= _width) w = _width - x; + if((y + h - 1) >= _height) h = _height - y; + + int16_t r1, g1, b1, r2, g2, b2, dr, dg, db, r, g, b; + color565toRGB14(color1,r1,g1,b1); + color565toRGB14(color2,r2,g2,b2); + dr=(r2-r1)/h; dg=(g2-g1)/h; db=(b2-b1)/h; + r=r1;g=g1;b=b1; // TODO: this can result in a very long transaction time // should break this into multiple transactions, even though @@ -132,18 +287,34 @@ void ILI9341_t3::fillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t c setAddr(x, y, x+w-1, y+h-1); writecommand_cont(ILI9341_RAMWR); for(y=h; y>0; y--) { + uint16_t color; for(x=w; x>1; x--) { + color = RGB14tocolor565(r,g,b); writedata16_cont(color); + r+=dr;g+=dg; b+=db; } + color = RGB14tocolor565(r,g,b); writedata16_last(color); if (y > 1 && (y & 1)) { SPI.endTransaction(); SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE0)); } + r=r1;g=g1;b=b1; } SPI.endTransaction(); } +// fillScreenVGradient - fills screen with vertical gradient +void ILI9341_t3::fillScreenVGradient(uint16_t color1, uint16_t color2) +{ + fillRectVGradient(0,0,_width,_height,color1,color2); +} + +// fillScreenHGradient - fills screen with horizontal gradient +void ILI9341_t3::fillScreenHGradient(uint16_t color1, uint16_t color2) +{ + fillRectHGradient(0,0,_width,_height,color1,color2); +} #define MADCTL_MY 0x80 @@ -183,10 +354,9 @@ void ILI9341_t3::setRotation(uint8_t m) } SPI.endTransaction(); setClipRect(); + setOrigin(); cursor_x = 0; cursor_y = 0; - origin_x = 0; - origin_y = 0; } void ILI9341_t3::setScroll(uint16_t offset) @@ -385,6 +555,100 @@ void ILI9341_t3::writeRect(int16_t x, int16_t y, int16_t w, int16_t h, const uin SPI.endTransaction(); } +// writeRect8BPP - write 8 bit per pixel paletted bitmap +// bitmap data in array at pixels, one byte per pixel +// color palette data in array at palette +void ILI9341_t3::writeRect8BPP(int16_t x, int16_t y, int16_t w, int16_t h, const uint8_t *pixels, const uint16_t * palette ) +{ + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE0)); + setAddr(x, y, x+w-1, y+h-1); + writecommand_cont(ILI9341_RAMWR); + for(y=h; y>0; y--) { + for(x=w; x>1; x--) { + writedata16_cont(palette[*pixels++]); + } + writedata16_last(palette[*pixels++]); + } + SPI.endTransaction(); +} + +// writeRect4BPP - write 4 bit per pixel paletted bitmap +// bitmap data in array at pixels, 4 bits per pixel +// color palette data in array at palette +// width must be at least 2 pixels +void ILI9341_t3::writeRect4BPP(int16_t x, int16_t y, int16_t w, int16_t h, const uint8_t *pixels, const uint16_t * palette ) +{ + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE0)); + setAddr(x, y, x+w-1, y+h-1); + writecommand_cont(ILI9341_RAMWR); + for(y=h; y>0; y--) { + for(x=w; x>2; x-=2) { + writedata16_cont(palette[((*pixels)>>4)&0xF]); + writedata16_cont(palette[(*pixels++)&0xF]); + } + writedata16_cont(palette[((*pixels)>>4)&0xF]); + writedata16_last(palette[(*pixels++)&0xF]); + } + SPI.endTransaction(); +} + +// writeRect2BPP - write 2 bit per pixel paletted bitmap +// bitmap data in array at pixels, 4 bits per pixel +// color palette data in array at palette +// width must be at least 4 pixels +void ILI9341_t3::writeRect2BPP(int16_t x, int16_t y, int16_t w, int16_t h, const uint8_t *pixels, const uint16_t * palette ) +{ + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE0)); + setAddr(x, y, x+w-1, y+h-1); + writecommand_cont(ILI9341_RAMWR); + for(y=h; y>0; y--) { + for(x=w; x>4; x-=4) { + //unrolled loop might be faster? + writedata16_cont(palette[((*pixels)>>6)&0x3]); + writedata16_cont(palette[((*pixels)>>4)&0x3]); + writedata16_cont(palette[((*pixels)>>2)&0x3]); + writedata16_cont(palette[(*pixels++)&0x3]); + } + writedata16_cont(palette[((*pixels)>>6)&0x3]); + writedata16_cont(palette[((*pixels)>>4)&0x3]); + writedata16_cont(palette[((*pixels)>>2)&0x3]); + writedata16_last(palette[(*pixels++)&0x3]); + } + SPI.endTransaction(); +} + +// writeRect1BPP - write 1 bit per pixel paletted bitmap +// bitmap data in array at pixels, 4 bits per pixel +// color palette data in array at palette +// width must be at least 8 pixels +void ILI9341_t3::writeRect1BPP(int16_t x, int16_t y, int16_t w, int16_t h, const uint8_t *pixels, const uint16_t * palette ) +{ + SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE0)); + setAddr(x, y, x+w-1, y+h-1); + writecommand_cont(ILI9341_RAMWR); + for(y=h; y>0; y--) { + for(x=w; x>8; x-=8) { + //unrolled loop might be faster? + writedata16_cont(palette[((*pixels)>>7)&0x1]); + writedata16_cont(palette[((*pixels)>>6)&0x1]); + writedata16_cont(palette[((*pixels)>>5)&0x1]); + writedata16_cont(palette[((*pixels)>>4)&0x1]); + writedata16_cont(palette[((*pixels)>>3)&0x1]); + writedata16_cont(palette[((*pixels)>>2)&0x1]); + writedata16_cont(palette[((*pixels)>>1)&0x1]); + writedata16_cont(palette[(*pixels++)&0x1]); + } + writedata16_cont(palette[((*pixels)>>7)&0x1]); + writedata16_cont(palette[((*pixels)>>6)&0x1]); + writedata16_cont(palette[((*pixels)>>5)&0x1]); + writedata16_cont(palette[((*pixels)>>4)&0x1]); + writedata16_cont(palette[((*pixels)>>3)&0x1]); + writedata16_cont(palette[((*pixels)>>2)&0x1]); + writedata16_cont(palette[((*pixels)>>1)&0x1]); + writedata16_last(palette[(*pixels++)&0x1]); + } + SPI.endTransaction(); +} static const uint8_t init_commands[] = { @@ -409,13 +673,19 @@ static const uint8_t init_commands[] = { 0x4E, 0xF1, 0x37, 0x07, 0x10, 0x03, 0x0E, 0x09, 0x00, // Set Gamma 16, ILI9341_GMCTRN1, 0x00, 0x0E, 0x14, 0x03, 0x11, 0x07, 0x31, 0xC1, 0x48, 0x08, 0x0F, 0x0C, 0x31, 0x36, 0x0F, // Set Gamma + 3, 0xb1, 0x00, 0x10, // FrameRate Control 119Hz 0 }; void ILI9341_t3::begin(void) { // verify SPI pins are valid; + #if defined(__MK64FX512__) || defined(__MK66FX1M0__) + if ((_mosi == 11 || _mosi == 7 || _mosi == 28) && (_miso == 12 || _miso == 8 || _miso == 39) + && (_sclk == 13 || _sclk == 14 || _sclk == 27)) { + #else if ((_mosi == 11 || _mosi == 7) && (_miso == 12 || _miso == 8) && (_sclk == 13 || _sclk == 14)) { + #endif SPI.setMOSI(_mosi); SPI.setMISO(_miso); SPI.setSCK(_sclk); @@ -907,7 +1177,7 @@ size_t ILI9341_t3::write(uint8_t c) { if (font) { if (c == '\n') { - //cursor_y += ?? + cursor_y += font->line_space; // Fix linefeed. Added by T.T., SoftEgg cursor_x = 0; } else { drawFontChar(c); @@ -921,7 +1191,7 @@ size_t ILI9341_t3::write(uint8_t c) } else { drawChar(cursor_x, cursor_y, c, textcolor, textbgcolor, textsize); cursor_x += textsize*6; - if (wrap && (cursor_x > (_clipx2 - textsize*6))) { + if (wrap && (cursor_x > (_clipx2 - textsize*6))) { cursor_y += textsize*8; cursor_x = _clipx1; } @@ -1018,11 +1288,15 @@ void ILI9341_t3::drawChar(int16_t x, int16_t y, unsigned char c, } } } else { + + x+=_originx; + y+=_originy; + // Rectangular clipping - if((x >= _clipx2) || // Clip right - (y >= _clipy2) || // Clip bottom - ((x + 6 * size - 1) < _clipx1) || // Clip left TODO: this is not correct - ((y + 8 * size - 1) < _clipy1)) // Clip top TODO: this is not correct + if((x >= _displayclipx2) || // Clip right + (y >= _displayclipy2) || // Clip bottom + ((x + 6 * size - 1) < _displayclipx1) || // Clip left TODO: this is not correct + ((y + 8 * size - 1) < _displayclipy1)) // Clip top TODO: this is not correct return; // This solid background approach is about 5 time faster @@ -1146,6 +1420,8 @@ void ILI9341_t3::measureChar(unsigned char c, uint16_t* w, uint16_t* h) { void ILI9341_t3::drawFontChar(unsigned int c) { + if (_invisible) return; + uint32_t bitoffset; const uint8_t *data; @@ -1212,11 +1488,9 @@ void ILI9341_t3::drawFontChar(unsigned int c) // TODO: compute top skip and number of lines int32_t linecount = height; //uint32_t loopcount = 0; - uint32_t y = origin_y; + int32_t y = origin_y; bool opaque = (textbgcolor != textcolor); if (opaque) { -// Serial.printf("cursor_x %d, cursor_y %d, delta %d, line_space %d, width %d, height %d\n", -// cursor_x , cursor_y , delta, font->line_space, width, height); int header = origin_y-cursor_y; // clear above character fillRect(cursor_x-delta,cursor_y,delta,header, textbgcolor); @@ -1237,11 +1511,7 @@ void ILI9341_t3::drawFontChar(unsigned int c) uint32_t xsize = width - x; if (xsize > 32) xsize = 32; uint32_t bits = fetchbits_unsigned(data, bitoffset, xsize); - if (!opaque) { - drawFontBits(bits, xsize, origin_x + x, y, 1); - } else { - drawFontBitsOpaque(bits, xsize, origin_x + x, y, 1); - } + drawFontBits(opaque, bits, xsize, origin_x + x, y, 1); bitoffset += xsize; x += xsize; } while (x < width); @@ -1261,15 +1531,11 @@ void ILI9341_t3::drawFontChar(unsigned int c) bitoffset += 3; uint32_t x = 0; do { - uint32_t xsize = width - x; + int32_t xsize = width - x; if (xsize > 32) xsize = 32; //Serial.printf(" multi line %d\n", n); uint32_t bits = fetchbits_unsigned(data, bitoffset, xsize); - if (!opaque) { - drawFontBits(bits, xsize, origin_x + x, y, n); - } else { - drawFontBitsOpaque(bits, xsize, origin_x + x, y, n); - } + drawFontBits(opaque, bits, xsize, origin_x + x, y, n); bitoffset += xsize; x += xsize; } while (x < width); @@ -1289,33 +1555,110 @@ void ILI9341_t3::drawFontChar(unsigned int c) } } -void ILI9341_t3::drawFontBits(uint32_t bits, uint32_t numbits, uint32_t x, uint32_t y, uint32_t repeat) +//strPixelLen - gets pixel length of given ASCII string +int16_t ILI9341_t3::strPixelLen(char * str) { -#if 0 - // TODO: replace this *slow* code with something fast... - //Serial.printf(" %d bits at %d,%d: %X\n", numbits, x, y, bits); - if (bits == 0) return; - do { - uint32_t x1 = x; - uint32_t n = numbits; - do { - n--; - if (bits & (1 << n)) { - drawPixel(x1, y, textcolor); - //Serial.printf(" pixel at %d,%d\n", x1, y); +// Serial.printf("strPixelLen %s\n", str); + if (!str) return(0); + uint16_t len=0, maxlen=0; + while (*str) + { + if (*str=='\n') + { + if ( len > maxlen ) + { + maxlen=len; + len=0; } - x1++; - } while (n > 0); - y++; - repeat--; - } while (repeat); -#endif -#if 1 + } + else + { + if (!font) + { + len+=textsize*6; + } + else + { + + uint32_t bitoffset; + const uint8_t *data; + uint16_t c = *str; + +// Serial.printf("char %c(%d)\n", c,c); + + if (c >= font->index1_first && c <= font->index1_last) { + bitoffset = c - font->index1_first; + bitoffset *= font->bits_index; + } else if (c >= font->index2_first && c <= font->index2_last) { + bitoffset = c - font->index2_first + font->index1_last - font->index1_first + 1; + bitoffset *= font->bits_index; + } else if (font->unicode) { + continue; + } else { + continue; + } + //Serial.printf(" index = %d\n", fetchbits_unsigned(font->index, bitoffset, font->bits_index)); + data = font->data + fetchbits_unsigned(font->index, bitoffset, font->bits_index); + + uint32_t encoding = fetchbits_unsigned(data, 0, 3); + if (encoding != 0) continue; +// uint32_t width = fetchbits_unsigned(data, 3, font->bits_width); +// Serial.printf(" width = %d\n", width); + bitoffset = font->bits_width + 3; + bitoffset += font->bits_height; + +// int32_t xoffset = fetchbits_signed(data, bitoffset, font->bits_xoffset); +// Serial.printf(" xoffset = %d\n", xoffset); + bitoffset += font->bits_xoffset; + bitoffset += font->bits_yoffset; + + uint32_t delta = fetchbits_unsigned(data, bitoffset, font->bits_delta); + bitoffset += font->bits_delta; +// Serial.printf(" delta = %d\n", delta); + + len += delta;//+width-xoffset; +// Serial.printf(" len = %d\n", len); + if ( len > maxlen ) + { + maxlen=len; +// Serial.printf(" maxlen = %d\n", maxlen); + } + + } + } + str++; + } +// Serial.printf("Return maxlen = %d\n", maxlen); + return( maxlen ); +} + +#if 0 +// todo: make this draw opaqe +void ILI9341_t3::drawFontBits(uint32_t bits, uint32_t numbits, int32_t x, int32_t y, uint32_t repeat) +{ + x+=_originx; + y+=_originy; + + if( + (x < _displayclipx1) || + (x >= _displayclipx2) || + (y < _displayclipy1) || + (y >= _displayclipy2)) + return; + + if ((x+(int32_t)numbits) > _displayclipx2) { + numbits -= ((x+numbits) - _displayclipx2); + } + + if (y+(int32_t)repeat > _displayclipy2) { + repeat -= ((y+repeat) - _displayclipy2); + } + if (bits == 0) return; SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE0)); int w = 0; do { - uint32_t x1 = x; + int32_t x1 = x; uint32_t n = numbits; writecommand_cont(ILI9341_PASET); // Row addr set @@ -1358,22 +1701,24 @@ void ILI9341_t3::drawFontBits(uint32_t bits, uint32_t numbits, uint32_t x, uint3 repeat--; } while (repeat); SPI.endTransaction(); -#endif } +#endif + -void ILI9341_t3::drawFontBitsOpaque(uint32_t bits, uint32_t numbits, uint32_t x, uint32_t y, uint32_t repeat) +void ILI9341_t3::drawFontBits(bool opaque, uint32_t bits, uint32_t numbits, int32_t x, int32_t y, uint32_t repeat) { - // TODO: replace this *slow* code with something fast... if (bits == 0) { - while (repeat) { - drawFastHLine(x,y++, numbits, textbgcolor); - repeat--; - }; + if (opaque) { + while (repeat) { + drawFastHLine(x,y++, numbits, textbgcolor); + repeat--; + }; + } return; } do { - uint32_t x1 = x; + int32_t x1 = x; uint32_t n = numbits; int w; int bgw; @@ -1385,7 +1730,9 @@ void ILI9341_t3::drawFontBitsOpaque(uint32_t bits, uint32_t numbits, uint32_t x, n--; if (bits & (1 << n)) { if (bgw>0) { - drawFastHLine(x1 - bgw, y, bgw, textbgcolor); + if (opaque) { + drawFastHLine(x1 - bgw, y, bgw, textbgcolor); + } bgw=0; } w++; @@ -1404,7 +1751,9 @@ void ILI9341_t3::drawFontBitsOpaque(uint32_t bits, uint32_t numbits, uint32_t x, } if (bgw > 0) { - drawFastHLine(x1 - bgw, y, bgw, textbgcolor); + if (opaque) { + drawFastHLine(x1 - bgw, y, bgw, textbgcolor); + } } y++; @@ -1421,6 +1770,11 @@ void ILI9341_t3::setCursor(int16_t x, int16_t y) { cursor_y = y; } +void ILI9341_t3::getCursor(int16_t *x, int16_t *y) { + *x = cursor_x; + *y = cursor_y; +} + void ILI9341_t3::setTextSize(uint8_t s) { textsize = (s > 0) ? s : 1; } @@ -1441,7 +1795,7 @@ void ILI9341_t3::setTextColor(uint16_t c, uint16_t b) { } void ILI9341_t3::setTextWrap(boolean w) { - wrap = w; + wrap = w; } boolean ILI9341_t3::getTextWrap() @@ -1462,7 +1816,8 @@ void ILI9341_t3::drawText(const char* text, const char* wrapChars) { // don't wrap to the left, wrap to the original spot if (wrap && text[i] == '\n') { cursor_x = origx; - cursor_y += fontLineSpace(); + // disable this here, write() now moves down + // cursor_y += fontLineSpace(); } i++; } diff --git a/lib/ILI9341_t3/ILI9341_t3.h b/lib/ILI9341_t3/ILI9341_t3.h index 04d972d8..56daafb3 100644 --- a/lib/ILI9341_t3/ILI9341_t3.h +++ b/lib/ILI9341_t3/ILI9341_t3.h @@ -16,6 +16,36 @@ MIT license, all text above must be included in any redistribution ****************************************************/ +// + +//Additional graphics routines by Tim Trzepacz, SoftEgg LLC added December 2015 +//(And then accidentally deleted and rewritten March 2016. Oops!) +//Gradient support +//---------------- +// fillRectVGradient - fills area with vertical gradient +// fillRectHGradient - fills area with horizontal gradient +// fillScreenVGradient - fills screen with vertical gradient +// fillScreenHGradient - fills screen with horizontal gradient + +//Additional Color Support +//------------------------ +// color565toRGB - converts 565 format 16 bit color to RGB +// color565toRGB14 - converts 16 bit 565 format color to 14 bit RGB (2 bits clear for math and sign) +// RGB14tocolor565 - converts 14 bit RGB back to 16 bit 565 format color + +//Low Memory Bitmap Support +//------------------------- +// writeRect8BPP - write 8 bit per pixel paletted bitmap +// writeRect4BPP - write 4 bit per pixel paletted bitmap +// writeRect2BPP - write 2 bit per pixel paletted bitmap +// writeRect1BPP - write 1 bit per pixel paletted bitmap + +//String Pixel Length support +//--------------------------- +// strPixelLen - gets pixel length of given ASCII string + +// <\SoftEgg> + #ifndef _ILI9341_t3H_ #define _ILI9341_t3H_ @@ -105,6 +135,9 @@ #define ILI9341_GREENYELLOW 0xAFE5 /* 173, 255, 47 */ #define ILI9341_PINK 0xF81F +#define CL(_r,_g,_b) ((((_r)&0xF8)<<8)|(((_g)&0xFC)<<3)|((_b)>>3)) + +#define sint16_t int16_t typedef struct { const unsigned char *index; @@ -140,7 +173,15 @@ class ILI9341_t3 : public Print void drawPixel(int16_t x, int16_t y, uint16_t color); void drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color); void drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color); + void drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t* colors); + void drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t* colors); void fillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color); + + void fillRectHGradient(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color1, uint16_t color2); + void fillRectVGradient(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color1, uint16_t color2); + void fillScreenVGradient(uint16_t color1, uint16_t color2); + void fillScreenHGradient(uint16_t color1, uint16_t color2); + void setRotation(uint8_t r); void setScroll(uint16_t offset); void invertDisplay(boolean i); @@ -150,6 +191,28 @@ class ILI9341_t3 : public Print return ((r & 0xF8) << 8) | ((g & 0xFC) << 3) | (b >> 3); } + //color565toRGB - converts 565 format 16 bit color to RGB + static void color565toRGB(uint16_t color, uint8_t &r, uint8_t &g, uint8_t &b) { + r = (color>>8)&0x00F8; + g = (color>>3)&0x00FC; + b = (color<<3)&0x00F8; + } + + //color565toRGB14 - converts 16 bit 565 format color to 14 bit RGB (2 bits clear for math and sign) + //returns 00rrrrr000000000,00gggggg00000000,00bbbbb000000000 + //thus not overloading sign, and allowing up to double for additions for fixed point delta + static void color565toRGB14(uint16_t color, int16_t &r, int16_t &g, int16_t &b) { + r = (color>>2)&0x3E00; + g = (color<<3)&0x3F00; + b = (color<<9)&0x3E00; + } + + //RGB14tocolor565 - converts 14 bit RGB back to 16 bit 565 format color + static uint16_t RGB14tocolor565(int16_t r, int16_t g, int16_t b) + { + return (((r & 0x3E00) << 2) | ((g & 0x3F00) >>3) | ((b & 0x3E00) >> 9)); + } + //uint8_t readdata(void); uint8_t readcommand8(uint8_t reg, uint8_t index = 0); @@ -158,6 +221,29 @@ class ILI9341_t3 : public Print void readRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t *pcolors); void writeRect(int16_t x, int16_t y, int16_t w, int16_t h, const uint16_t *pcolors); + // writeRect8BPP - write 8 bit per pixel paletted bitmap + // bitmap data in array at pixels, one byte per pixel + // color palette data in array at palette + void writeRect8BPP(int16_t x, int16_t y, int16_t w, int16_t h, const uint8_t *pixels, const uint16_t * palette ); + + // writeRect4BPP - write 4 bit per pixel paletted bitmap + // bitmap data in array at pixels, 4 bits per pixel + // color palette data in array at palette + // width must be at least 2 pixels + void writeRect4BPP(int16_t x, int16_t y, int16_t w, int16_t h, const uint8_t *pixels, const uint16_t * palette ); + + // writeRect2BPP - write 2 bit per pixel paletted bitmap + // bitmap data in array at pixels, 4 bits per pixel + // color palette data in array at palette + // width must be at least 4 pixels + void writeRect2BPP(int16_t x, int16_t y, int16_t w, int16_t h, const uint8_t *pixels, const uint16_t * palette ); + + // writeRect1BPP - write 1 bit per pixel paletted bitmap + // bitmap data in array at pixels, 4 bits per pixel + // color palette data in array at palette + // width must be at least 8 pixels + void writeRect1BPP(int16_t x, int16_t y, int16_t w, int16_t h, const uint8_t *pixels, const uint16_t * palette ); + // from Adafruit_GFX.h void drawCircle(int16_t x0, int16_t y0, int16_t r, uint16_t color); void drawCircleHelper(int16_t x0, int16_t y0, int16_t r, uint8_t cornername, uint16_t color); @@ -173,6 +259,7 @@ class ILI9341_t3 : public Print void draw8Bitmap(int16_t x, int16_t y, const uint8_t *bitmap, int16_t w, int16_t h, uint8_t transparent); void drawChar(int16_t x, int16_t y, unsigned char c, uint16_t color, uint16_t bg, uint8_t size); void setCursor(int16_t x, int16_t y); + void getCursor(int16_t *x, int16_t *y); void setTextColor(uint16_t c); void setTextColor(uint16_t c, uint16_t bg); void setTextSize(uint8_t s); @@ -180,10 +267,16 @@ class ILI9341_t3 : public Print void setTextWrap(boolean w); boolean getTextWrap(); - void setOrigin(int16_t x = 0, int16_t y = 0) { origin_x = x; origin_y = y; } - void getOrigin(int16_t* x, int16_t* y) { *x = origin_x; *y = origin_y; } - void setClipRect(int16_t x1, int16_t y1, int16_t x2, int16_t y2) { _clipx1 = x1; _clipy1 = y1; _clipx2 = x2; _clipy2 = y2; } - void setClipRect() { _clipx1 = 0; _clipy1 = 0; _clipx2 = _width; _clipy2 = _height; } + // setOrigin sets an offset in display pixels where drawing to (0,0) will appear + // for example: setOrigin(10,10); drawPixel(5,5); will cause a pixel to be drawn at hardware pixel (15,15) + void setOrigin(int16_t x = 0, int16_t y = 0) { _originx = x; _originy = y; updateDisplayClip();} + void getOrigin(int16_t* x, int16_t* y) { *x = _originx; *y = _originy; } + + // setClipRect() sets a clipping rectangle (relative to any set origin) for drawing to be limited to. + // Drawing is also restricted to the bounds of the display + + void setClipRect(int16_t x1, int16_t y1, int16_t w, int16_t h) { _clipx1 = x1; _clipy1 = y1; _clipx2 = x1+w; _clipy2 = y1+h; updateDisplayClip();} + void setClipRect() { _clipx1 = 0; _clipy1 = 0; _clipx2 = _width; _clipy2 = _height; updateDisplayClip(); } virtual size_t write(uint8_t); int16_t width(void) { return _width; } @@ -205,14 +298,26 @@ class ILI9341_t3 : public Print const char* lineBreakChars = " -"; uint16_t measureTextWidth(const char* text); uint16_t measureTextHeight(const char* text); + int16_t strPixelLen(char * str); protected: int16_t _width, _height; // Display w/h as modified by current rotation int16_t cursor_x, cursor_y; + int16_t _clipx1, _clipy1, _clipx2, _clipy2; + int16_t _originx, _originy; + int16_t _displayclipx1, _displayclipy1, _displayclipx2, _displayclipy2; + bool _invisible = false; + + inline void updateDisplayClip() { + _displayclipx1 = max(0,min(_clipx1+_originx,width())); + _displayclipx2 = max(0,min(_clipx2+_originx,width())); + + _displayclipy1 = max(0,min(_clipy1+_originy,height())); + _displayclipy2 = max(0,min(_clipy2+_originy,height())); + _invisible = (_displayclipx1 == _displayclipx2 || _displayclipy1 == _displayclipy2); + } - int16_t origin_x, origin_y; - int16_t rel_clipx1, rel_clipy1, rel_clipx2, rel_clipy2; uint16_t textcolor, textbgcolor; uint8_t textsize, rotation; boolean wrap; // If set, 'wrap' text at right edge of display @@ -297,10 +402,13 @@ class ILI9341_t3 : public Print void HLine(int16_t x, int16_t y, int16_t w, uint16_t color) __attribute__((always_inline)) { + x+=_originx; + y+=_originy; + // Rectangular clipping - if((y < _clipy1) || (x >= _clipx2) || (y >= _clipy2)) return; - if(x<_clipx1) { w = w - (_clipx1 - x); x = _clipx1; } - if((x+w-1) >= _clipx2) w = _clipx2-x; + if((y < _displayclipy1) || (x >= _displayclipx2) || (y >= _displayclipy2)) return; + if(x<_displayclipx1) { w = w - (_displayclipx1 - x); x = _displayclipx1; } + if((x+w-1) >= _displayclipx2) w = _displayclipx2-x; if (w<1) return; setAddr(x, y, x+w-1, y); @@ -310,13 +418,15 @@ class ILI9341_t3 : public Print void VLine(int16_t x, int16_t y, int16_t h, uint16_t color) __attribute__((always_inline)) { + x+=_originx; + y+=_originy; + // Rectangular clipping - if((x < _clipx1) || (x >= _clipx2) || (y >= _clipy2)) return; - if(y < _clipy1) { h = h - (_clipy1 - y); y = _clipy1;} - if((y+h-1) >= _clipy2) h = _clipy2-y; + if((x < _displayclipx1) || (x >= _displayclipx2) || (y >= _displayclipy2)) return; + if(y < _displayclipy1) { h = h - (_displayclipy1 - y); y = _displayclipy1;} + if((y+h-1) >= _displayclipy2) h = _displayclipy2-y; if(h<1) return; - setAddr(x, y, x, y+h-1); writecommand_cont(ILI9341_RAMWR); do { writedata16_cont(color); } while (--h > 0); @@ -324,14 +434,16 @@ class ILI9341_t3 : public Print void Pixel(int16_t x, int16_t y, uint16_t color) __attribute__((always_inline)) { - if((x < _clipx1) ||(x >= _clipx2) || (y < _clipy1) || (y >= _clipy2)) return; + x+=_originx; + y+=_originy; + + if((x < _displayclipx1) ||(x >= _displayclipx2) || (y < _displayclipy1) || (y >= _displayclipy2)) return; setAddr(x, y, x, y); writecommand_cont(ILI9341_RAMWR); writedata16_cont(color); } - void drawFontBits(uint32_t bits, uint32_t numbits, uint32_t x, uint32_t y, uint32_t repeat); - void drawFontBitsOpaque(uint32_t bits, uint32_t numbits, uint32_t x, uint32_t y, uint32_t repeat); + void drawFontBits(bool opaque, uint32_t bits, uint32_t numbits, int32_t x, int32_t y, uint32_t repeat); }; #ifndef swap diff --git a/lib/ILI9341_t3/examples/graphicstest/graphicstest.ino b/lib/ILI9341_t3/examples/graphicstest/graphicstest.ino index 4e18f5fe..a31dc5b8 100644 --- a/lib/ILI9341_t3/examples/graphicstest/graphicstest.ino +++ b/lib/ILI9341_t3/examples/graphicstest/graphicstest.ino @@ -233,7 +233,7 @@ unsigned long testFilledRects(uint16_t color1, uint16_t color2) { cy = tft.height() / 2 - 1; tft.fillScreen(ILI9341_BLACK); - n = min(tft.width(), tft.height()); + n = min(tft.width(), tft.height()) - 1; for(i=n; i>0; i-=6) { i2 = i / 2; start = micros(); @@ -324,7 +324,7 @@ unsigned long testRoundRects() { cy = tft.height() / 2 - 1; tft.fillScreen(ILI9341_BLACK); - w = min(tft.width(), tft.height()); + w = min(tft.width(), tft.height()) - 1; start = micros(); for(i=0; i20; i-=6) { + for(i=min(tft.width(), tft.height()) - 1; i>20; i-=6) { i2 = i / 2; tft.fillRoundRect(cx-i2, cy-i2, i, i, i/8, tft.color565(0, i, 0)); } diff --git a/lib/ILI9341_t3/examples/pictureEmbed/pictureEmbed.ino b/lib/ILI9341_t3/examples/pictureEmbed/pictureEmbed.ino index f01492c5..e283de43 100644 --- a/lib/ILI9341_t3/examples/pictureEmbed/pictureEmbed.ino +++ b/lib/ILI9341_t3/examples/pictureEmbed/pictureEmbed.ino @@ -13,6 +13,25 @@ // #include "picture.c" //the picture +/* GIMP (https://www.gimp.org/) can also be used to export the image using the following steps: + + 1. File -> Export As + 2. In the Export Image dialog, use 'C source code (*.c)' as filetype. + 3. Press export to get the export options dialog. + 4. Type the desired variable name into the 'prefixed name' box. + 5. Uncheck 'GLIB types (guint8*)' + 6. Check 'Save as RGB565 (16-bit)' + 7. Press export to save your image. + + Assuming 'image_name' was typed in the 'prefixed name' box of step 4, you can have to include the c file as above, + using the image can be done with: + + tft.writeRect(0, 0, image_name.width, image_name.height, (uint16_t*)(image_name.pixel_data)); + + See also https://forum.pjrc.com/threads/35575-Export-for-ILI9341_t3-with-GIMP +*/ + + // Normal Connections #define TFT_DC 9 #define TFT_CS 10 diff --git a/lib/KBox/src/util/SlipStream.cpp b/lib/KBox/src/util/SlipStream.cpp index 8dbe9bb1..db344e83 100644 --- a/lib/KBox/src/util/SlipStream.cpp +++ b/lib/KBox/src/util/SlipStream.cpp @@ -87,12 +87,19 @@ size_t SlipStream::readFrame(uint8_t *ptr, size_t len) { if (len > index) { len = index; } - memcpy(ptr, buffer, len); + if (len > 0) { + memcpy(ptr, buffer, len); + } messageComplete = false; index = 0; return len; } +size_t SlipStream::peekFrame(uint8_t **ptr) { + *ptr = buffer; + return index; +} + size_t SlipStream::writeFrame(const uint8_t *ptr, size_t len) { _stream.write(0xc0); for (size_t i = 0; i < len; i++) { diff --git a/lib/KBox/src/util/SlipStream.h b/lib/KBox/src/util/SlipStream.h index 1123f041..e2ec16f0 100644 --- a/lib/KBox/src/util/SlipStream.h +++ b/lib/KBox/src/util/SlipStream.h @@ -56,6 +56,18 @@ class SlipStream { */ size_t readFrame(uint8_t *ptr, size_t len); + /** + * Allows caller to peek at current frame and get access to the internal + * buffer where it is stored. + * Caller needs to call readFrame() afterwards to discard the frame and + * start receiving another one. Note that readFrame(0,0) is valid. + * + * @param out ptr: Pointer will be updated to point to internal buffer. + * @return number of bytes that can be read in buffer or 0 if buffer is + * invalid. + */ + size_t peekFrame(uint8_t **ptr); + /** * Writes a frame to the underlying Stream, using SLIP framing and * escaping. diff --git a/lib/KBox/test/Makefile b/lib/KBox/test/Makefile index 455b8ff5..a1d014fb 100644 --- a/lib/KBox/test/Makefile +++ b/lib/KBox/test/Makefile @@ -8,7 +8,7 @@ FRAMEWORK := $(HOME)/.platformio/packages/framework-arduinoteensy/cores/teensy3 # Build flags - Including all dependencies of the test -CFLAGS := -g -Wall -D_NEWLIB_VERSION=1 +CFLAGS := -g -Wall CFLAGS := $(CFLAGS) -Iarduinomock/ -I$(FRAMEWORK) -I../../KBoxDebug/src CFLAGS := $(CFLAGS) -I../../List/src -I../../NMEA2000 -I../src CPPFLAGS := $(CFLAGS) -std=c++11 @@ -31,6 +31,11 @@ test: nmea_test slip_test NMEASentenceBuilderTest KMessageNMEAVisitorTest # Object dependencies of the tests. Without them tests cannot run. TEST_DEPS=teensy_compat.o maintest.o $(FRAMEWORK)/WString.o $(FRAMEWORK)/Print.o +$(FRAMEWORK)/WString.o: $(FRAMEWORK)/WString.cpp + # Add the _NEWLIB_VERSION define when building WString to include + # itoa, utoa, etc (see avr_functions.h in the teensy framework). + $(CXX) $(CPPFLAGS) -D_NEWLIB_VERSION=1 -c $^ -o $@ + # Test the NMEA helper functions nmea_test: nmea_test.o ../src/util/nmea.o $(TEST_DEPS) $(CXX) $(CFLAGS) -o $@ $^ diff --git a/lib/KBox/test/slip_test.cpp b/lib/KBox/test/slip_test.cpp index 23ce1e68..f3ffd1e9 100644 --- a/lib/KBox/test/slip_test.cpp +++ b/lib/KBox/test/slip_test.cpp @@ -118,6 +118,11 @@ TEST_CASE("reading an empty stream") { uint8_t ptr[100]; REQUIRE( slip.readFrame(ptr, sizeof(ptr)) == 0 ); } + + THEN("peek should return 0") { + uint8_t *ptr; + REQUIRE( slip.peekFrame(&ptr) == 0 ); + } } TEST_CASE("reading EOM bytes repeatedly") { @@ -143,11 +148,32 @@ TEST_CASE("reading simple message") { StreamMock bytesStream(1, &b); SlipStream slip(bytesStream, 100); + THEN("should be able to peek 10 bytes") { + uint8_t *ptr; + REQUIRE( slip.available() == 10 ); + REQUIRE( slip.peekFrame(&ptr) == 10 ); + REQUIRE( memcmp(ptr, b.data+1, 10) == 0 ); + + THEN("packet should still be available after peek") { + REQUIRE( slip.available() == 10 ); + + THEN("packet should be discarded after a readFrame(0,0)") { + slip.readFrame(0, 0); + REQUIRE( slip.available() == 0 ); + } + } + } + THEN("should be able to read 10 bytes") { REQUIRE( slip.available() == 10 ); REQUIRE( slip.readFrame(ptr, sizeof(ptr)) == 10); REQUIRE( memcmp(ptr, b.data+1, 10) == 0 ); + + THEN("message should be discarded after calling readFrame") { + REQUIRE( slip.available() == 0 ); + } } + } TEST_CASE("reading message with end of frame header") { @@ -160,6 +186,17 @@ TEST_CASE("reading message with end of frame header") { StreamMock bytesStream(1, &b); SlipStream slip(bytesStream, 100); + THEN("should be able to peek 10 bytes") { + uint8_t *p; + REQUIRE( slip.available() == 10 ); + REQUIRE( slip.peekFrame(&p) == 10); + REQUIRE( memcmp(p, b.data+2, 10) == 0 ); + + THEN("packet should still be available after peek") { + REQUIRE( slip.available() == 10 ); + } + } + THEN("should be able to read 10 bytes") { REQUIRE( slip.available() == 10 ); REQUIRE( slip.readFrame(ptr, sizeof(ptr)) == 10);