static void lm70_chipselect(struct spi_device *spi, int value)
{
	struct spi_lm70llp *pp = spidev_to_pp(spi);

	if (value)
		assertCS(pp);
	else
		deassertCS(pp);
}
Ejemplo n.º 2
0
template<typename SourceType> BMP_Status OLED::_displayBMP(SourceType &source, const int from_x, const int from_y, const int to_x, const int to_y)
{
  SourceType &f = source;
  f.seek(0);

  // File header, check magic number 'BM'
  if(f.read() != 'B' || f.read() != 'M')
    return BMP_INVALID_FORMAT;

  // Read DIB header with image properties
  f.seek(OFFS_DIB_HEADER);
  uint16_t dib_headersize = readLong(f);
  uint16_t width, height, bpp, compression;


  bool v2header = (dib_headersize == 12); // BMPv2 header, no compression, no additional options
  if(v2header) {
    width = readShort(f);
    height = readShort(f);
    if(readShort(f) != 1)
      return BMP_UNSUPPORTED_HEADER;
    bpp = readShort(f);
    compression = BMP_NoCompression;
  }
  else {
    width = readLong(f);
    height = readLong(f);
    if(readShort(f) != 1)
      return BMP_UNSUPPORTED_HEADER;
    bpp = readShort(f);
    compression = readLong(f);
  }

  // Verify image properties from header
  if(bpp > 24)
    return BMP_TOO_MANY_COLOURS;
  if(bpp != 1 && bpp != 4 && bpp != 8 && bpp != 16 && bpp != 24)
    return BMP_UNSUPPORTED_COLOURS;

  if(!(compression == BMP_NoCompression
       || (compression == BMP_BITFIELDS && bpp == 16))) {
    return BMP_COMPRESSION_NOT_SUPPORTED;
  }

  // In case of the bitfields option, determine the pixel format. We support RGB565 & RGB555 only
  bool rgb565 = true;
  if(compression == BMP_BITFIELDS) {
    f.seek(0x36);
    uint16_t b = readLong(f);
    uint16_t g = readLong(f);
    uint16_t r = readLong(f);
    if(r == 0x001f && g == 0x07e0 && b == 0xf800)
      rgb565 = true;
    else if(r != 0x001f && g != 0x03e0 && b != 0x7c00)
      return BMP_UNSUPPORTED_COLOURS; // Not RGB555 either
  }

  if (width < from_x || height < from_y)
    return BMP_ORIGIN_OUTSIDE_IMAGE; // source in BMP is offscreen

  // Find the starting offset for the data in the first row
  f.seek(0x0a);
  uint32_t data_offs = readLong(f);

  assertCS();
  // Trim height to 128, anything bigger gets cut off, then set up row span in memory
  height = height - from_y;
  if(to_y + height > 128)
    height = 128-to_y;

  // Calculate outputtable width and set up column span in memory
  uint16_t out_width = width - from_x;
  if(to_x + out_width > 128)
    out_width = 128-to_x;

  // Calculate the width in bits of each row (rounded up to nearest byte)
  uint16_t row_bits = (width*bpp + 7) & ~7;
  // Calculate width in bytes (4-byte boundary aligned)
  uint16_t row_bytes = (row_bits/8 + 3) & ~3;

  startWrite(to_x,to_y,to_x+out_width-1,to_y+height-1,false);

  releaseCS();

  // Read colour palette to RAM. It's quite hefty to hold in RAM (512 bytes for a full 8-bit palette)
  // but don't have much choice as seeking back and forth on SD is painfully slow
  OLED_Colour *palette;
  if(bpp < 16) {
    uint16_t palette_size = 1<<bpp;
    palette = (OLED_Colour *)malloc(sizeof(OLED_Colour)*palette_size);
    f.seek(OFFS_DIB_HEADER + dib_headersize);
    for(uint16_t i = 0; i < palette_size; i++) {
      uint8_t pal[4];
      f.read(pal, v2header ? 3 : 4);
      palette[i].blue = pal[0] >> 3;
      palette[i].green = pal[1] >> 2;
      palette[i].red = pal[2] >> 3;
    }
  }
Ejemplo n.º 3
0
int OLED::drawChar(const int x, const int y, const char letter, const OLED_Colour colour, const OLED_Colour background)
{
  if (x <0 || y < 0 || x >= COLUMNS || y >= ROWS) return -1;

  struct FontHeader header;
  memcpy_P(&header, (void*)this->font, sizeof(FontHeader));

  uint8_t c = letter;
  if (c == ' ') {
    int charWide = charWidth(' ');
    this->drawFilledBox(x, y-1, x + charWide, y + header.height, background);
    return charWide;
  }
  uint8_t width = 0;
  uint8_t bytes = (header.height + 7) / 8; // Number of bytes in a single column

  uint16_t index = 0;

  if (c < header.firstChar || c >= (header.firstChar + header.charCount)) return 0;
  c -= header.firstChar;

  if (header.size == 0) {
    // zero length is flag indicating fixed width font (array does not contain width data entries)
    width = header.fixedWidth;
    index = sizeof(FontHeader) + c * bytes * width;
  } else {
    // variable width font, read width data, to get the index
    for (uint8_t i = 0; i < c; i++) {
      index += pgm_read_byte(this->font + sizeof(FontHeader) + i);
    }
    index = index * bytes + sizeof(FontHeader) + header.charCount;
    width = pgm_read_byte(this->font + sizeof(FontHeader) + c);
  }
  if (x < -width || y < -header.height)
    return width;

  assertCS();
  startWrite(x > 0 ? x : 0, y > 0 ? y : 0, 
             x+width > 127 ? 127 : x+width-1, y+header.height > 127 ? 127 : y+header.height-1,
             true);

  /* Characters are stored as follows:
   *
   * Each byte is up to 8 vertical pixels (LSB @ top)
   * Each row of bytes is adjacent
   * For fonts >8 pixels high, the bytes are strided by width
   *
   * ie for a font 16 pixels high and 8 pixels wide:
   *
   * P(0,0) P(0,1) P(1,0) P(1,1) P(2,0) P(2,1) P(3,0) P(3,1) ... etc
   *
   *
   * Things are made more annoying for OLED because we need to write to the display
   * bottom-to-top for each column, so striding backwards instead of forwards...
   */

  for(int16_t ox = 0; ox < width; ox++) {
    if(ox+x >= COLUMNS)
      break;
    int16_t oy = 0;
    for(int8_t byte_y = bytes-1; byte_y >= 0; byte_y--) {
      uint8_t data = pgm_read_byte(this->font + index + ox + byte_y * width);
      int8_t start_bit;
      int8_t end_bit;
      if(bytes == 1) {
        start_bit = header.height-1;
        end_bit = 0;
      }
      else {
        start_bit = 7;
        end_bit = (byte_y < bytes-1) ? 0: 7-((header.height-1)%8);
      }
      for(int8_t bit_y = start_bit; bit_y >= end_bit; bit_y--) {
        if(oy+y < ROWS && ox+x >= 0 && oy+y >= 0) {
          writeData( (data & 1<<bit_y) ? colour : background);
        }
        oy++;
        if(oy == header.height)
          break;
      }
    }
  }
  releaseCS();
  return width;
}