woensdag 16 oktober 2013

Proportional fonts

In this post I added the code so far. It basically has the control for the LCD display (some of it came from the original sample code, although I changed quite a few pieces to be more readable/faster/more efficient) and connects the output of the SIM900 to the display (although everything is still copied to the PC using the hardware serial port as well). Once I have an input device on my phone this connection will be severed, which hopefully will return the 4k memory currently in use for the software serial connection (as I can switch the SIM900 to use the hardware UART). The part that changed compared to yesterday is highlighted in yellow. Basically, when the left side of a font is empty, I shift the character one to the left (which is fine, because there is always a single pixel between characters). If there are one, two or three columns to the right of the font empty, I will reduce the width of the character accordingly. If the bottom row is empty, and it is a character, I shift the character one down (which is fine, because there is always a single pixel below characters). This means a lot more characters might fit on a line, if they are of the narrow variety (e.g. 'i' and 'l').

// Maarten's phone.
// Copyright 2013, Maarten Hofman.

#include

byte Font[] = {
  0x00, 0x00, //
  0x09, 0x10, // !
  0x05, 0x00, // "
  0xC5, 0x86, // #
  0xDA, 0xA8, // $
  0x85, 0x52, // %
  0xC3, 0x76, // &
  0x04, 0x00, // '
  0x04, 0xC4, // (
  0x41, 0x12, // )
  0xD5, 0xD6, // *
  0xD0, 0x80, // +
  0x00, 0x12, // ,
  0xC0, 0x80, // -
  0x00, 0x10, // .
  0x84, 0x12, // /
  0xAA, 0x29, // 0
  0x24, 0x48, // 1
  0xE2, 0xF1, // 2
  0xA2, 0xE8, // 3
  0xE8, 0xC8, // 4
  0xCA, 0xB8, // 5
  0xCA, 0xA9, // 6
  0xA2, 0xC8, // 7
  0xEA, 0xA9, // 8
  0xEA, 0xC8, // 9
  0x10, 0x00, // :
  0x10, 0x12, // ;
  0x84, 0x44, // <
  0xC0, 0xA0, // =
  0x81, 0x12, // >
  0xE2, 0x90, // ?
  0x2A, 0xE1, // @
  0xEA, 0xD9, // A
  0xEB, 0xB9, // B
  0x0A, 0x21, // C
  0x2B, 0x39, // D
  0xCA, 0x31, // E
  0xCA, 0x11, // F 
  0x0A, 0xA9, // G
  0xE8, 0xD9, // H
  0x92, 0x20, // I
  0x20, 0x38, // J
  0xCC, 0x55, // K
  0x08, 0x71, // L  
  0xAD, 0x59, // M
  0xA9, 0x5D, // N
  0x2A, 0x29, // O
  0xEA, 0x91, // P
  0xAA, 0x6D, // Q
  0xEA, 0xD5, // R
  0xCA, 0xA8, // S
  0x92, 0x00, // T
  0x28, 0x29, // U
  0x45, 0xA6, // V
  0xB8, 0x79, // W
  0x85, 0x56, // X
  0x95, 0x00, // Y
  0x86, 0x72, // Z
  0x0B, 0x31, // [
  0x81, 0x44, //
  0x26, 0x68, // ]
  0x2A, 0x00, // ^
  0x00, 0x70, // _
  0x01, 0x00, // `
  0xE2, 0xE9, // a
  0xC8, 0xB9, // b
  0xC0, 0xA1, // c
  0xE0, 0xE9, // d
  0xEA, 0xA1, // e
  0x4A, 0x11, // f 
  0xEA, 0xB8, // g
  0xC8, 0xD9, // h
  0x01, 0x11, // i
  0x04, 0x28, // j
  0xC8, 0xD5, // k
  0x08, 0x11, // l  
  0xD0, 0xD9, // m
  0xC0, 0xD9, // n
  0xC0, 0xA9, // o
  0xEA, 0x81, // p
  0xEA, 0xC8, // q
  0xC0, 0x91, // r
  0x84, 0xA8, // s
  0x48, 0x21, // t
  0x00, 0x79, // u
  0x00, 0x29, // v
  0x90, 0x29, // w
  0x85, 0x06, // x
  0xE8, 0xA8, // y
  0xC0, 0xE4, // z
  0x4B, 0x21, // {
  0x90, 0x00, // |
  0x26, 0xA8, // }
  0xAD, 0x00, // ~
  0xFF, 0xFF, // DEL
};

/* 4-bit serial communication LDS183 LCD module */
const int SCOMMAND = 0;
const int SDATA = 1;

#define DC PIND4
#define CS PIND2
#define SDA PIND6
#define RESET PIND3
#define CLK PIND5

#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))

byte gr = 255;
byte gg = 255;
byte gb = 255;

SoftwareSerial GPRS(7, 8);
unsigned char buffer[64]; // buffer array for data receive over serial port
int count = 0;     // counter for buffer array 

byte cursor_x = 0;
byte cursor_y = 0;

void setup () {
  DDRD = 0x7C;  
  lcdInit();
  GPRS.begin(9600);               // the GPRS baud rate   
  Serial.begin(9600);             // the Serial port of Arduino baud rate.
}

void loop() {
  int i, j, k, l;
  setXY(0, 0, 128, 128); // Initial screen size    
  for (i = 0; i < 128 * 128; i++) { // black background
      clearPixel();
  }
  setColor(255, 255, 255);
  printString("Goliath online...\n");
  //printString("!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~");

  while (true) {  
    if (GPRS.available()) {
      // if date is comming from softwareserial port ==> data is comming from gprs shield
      while(GPRS.available()) {
        // reading data into char array 
        byte in = GPRS.read();
        buffer[count++] = in;
        printChar(in);
        // writing data into array
        if(count == 64) break;
      }
      // if no data transmission ends, write buffer to hardware serial port
      Serial.write(buffer, count);      
      // set counter of while loop to zero
      count = 0;
    }
    if (Serial.available())            // if data is available on hardwareserial port ==> data is comming from PC or notebook
      GPRS.write(Serial.read());       // write it to the GPRS shield
  }
}

void lcdInit() {
  cbi(PORTD, CS);
  cbi(PORTD, SDA);
  sbi(PORTD, CLK);
  sbi(PORTD, RESET);
  cbi(PORTD, RESET);
  sbi(PORTD, RESET);
  sbi(PORTD, CLK);
  sbi(PORTD, SDA);
  sbi(PORTD, CLK);
  delay(10);
  sendCMD(0x01); // Software Reset
  // Write Contrast
  sendCMD(0x25);
  sendData(64);
  //Sleep Out and booster on
  sendCMD(0x11);
  delay(10);
  // Display Inversion off
  sendCMD(0x20);
  // Idle Mode off
  sendCMD(0x38);
  // Display on
  sendCMD(0x29);
  // Normal Mode on
  sendCMD(0x13);
  // Memory Data Access control
  sendCMD(0x36);
  sendData(0x60);
  sendCMD(0x3A);
  sendData(5);   //16-Bit per Pixel
  // Frame Frequency Select
  sendCMD(0xB4);
  sendData(0x03);
  sendData(0x08);
  sendData(0x0b);
  sendData(0x0e);
  // Display Control
  sendCMD(0xBA);
  sendData(0x07);
  sendData(0x0D);
}

void shiftBits(byte b, int dc) {
  cbi(PORTD, CLK);
  if ((b&128)!=0) sbi(PORTD, SDA); else cbi(PORTD, SDA);
  sbi(PORTD, CLK);
  cbi(PORTD, CLK);
  if ((b&64)!=0) sbi(PORTD, SDA); else cbi(PORTD, SDA);
  sbi(PORTD, CLK);
  cbi(PORTD, CLK);
  if ((b&32)!=0) sbi(PORTD, SDA); else cbi(PORTD, SDA);
  sbi(PORTD, CLK);
  cbi(PORTD, CLK);
  if ((b&16)!=0) sbi(PORTD, SDA); else cbi(PORTD, SDA);
  sbi(PORTD, CLK);
  cbi(PORTD, CLK);
  if ((b&8)!=0) sbi(PORTD, SDA); else cbi(PORTD, SDA);
  sbi(PORTD, CLK);
  cbi(PORTD, CLK);
  if ((b&4)!=0) sbi(PORTD, SDA); else cbi(PORTD, SDA);
  sbi(PORTD, CLK);
  cbi(PORTD, CLK);
  if ((b&2)!=0) sbi(PORTD, SDA); else cbi(PORTD, SDA);
  sbi(PORTD, CLK);
  cbi(PORTD, CLK);
  if ((b&1)!=0) sbi(PORTD, SDA); else cbi(PORTD, SDA);
  if (dc == SDATA) sbi(PORTD, DC); else cbi(PORTD, DC);
  sbi(PORTD, CLK);
}

//send data
inline void sendData(byte data) {
  shiftBits(data, SDATA);
}

//send cmd
inline void sendCMD(byte data) {
  shiftBits(data, SCOMMAND);
}

// Defines the area in which the pixels will be written, (x,y) is the top left, (dx,dy) is the size.
void setXY(byte x, byte y, byte dx, byte dy) {
  sendCMD(0x2A);
  sendData(x);
  sendData(x+dx-1);
  sendCMD(0x2B);
  sendData(y);
  sendData(y+dy-1);
  sendCMD(0x2C);
}

//converts a 3*8Bit-RGB-Pixel to the 2-Byte-RGBRGB 565 Format of the Display
inline void setPixel(byte r, byte g, byte b) {
   sendData((r & 248) | g >> 5);
   sendData((g & 7) << 5 | b >> 3);
}

inline void setPixel() {
  setPixel(gr, gg, gb);
}

inline void clearPixel() {
  setPixel(0, 0, 0);
}

void printString(char *st) {
  int stl, i;
  
  stl = strlen(st);
  
  for (i=0; i
    printChar(*st++);
}

void newLine() {
  cursor_x = 0;
  cursor_y += 6;
  if (cursor_y >= 122) {
    cursor_y = 0;
  }
  setXY(0, cursor_y, 128, 6);
  for (int i = 0; i < 128 * 6; i++) clearPixel();
}

void printChar(byte c) {
  if (c < 32) {
    if (c == 10) newLine();
  } else {
    cursor_x += printChar(c, cursor_x, cursor_y);
  }
  if (cursor_x > 122) newLine();
}

// Returns the width of the character.
byte printChar(byte c, byte x, byte y) {
  byte p1, p2;
  int iFont;
  byte width = 6;
  
  iFont = (c - ' ') * 2;
  if ((iFont < 0) || (iFont > 254)) iFont = 254;
  p1 = Font[iFont];
  p2 = Font[iFont+1];
  
  // Handle proportional fonts.
  if ((p1 & 9) + (p2 & 17) == 0) {
    width--;
    x--;
  }
  if ((p1 & 36) + (p2 & 72) == 0) {
    width--;
    if ((p1 & 6) + (p2 & 164) == 0) {
      width--;
      if ((p1 & 146) + (p2 & 32) == 0) width--;
    }
  }
  if ((c & 64) && ((p2 & 112) == 0)) y++;
  
  setXY(x, y, 5, 5);
  // Line 1
  if (p1 & 1) setPixel(); else clearPixel();
  if (p1 & 2) {
    setPixel();
    setPixel();
    setPixel();
  } else {
    clearPixel();
    clearPixel();
    clearPixel();
  }
  if (p1 & 4) setPixel(); else clearPixel();
  // Line 2
  if (p1 & 8) setPixel(); else clearPixel();
  if (p1 & 1) setPixel(); else clearPixel();
  if (p1 & 16) setPixel(); else clearPixel();
  if (p1 & 4) setPixel(); else clearPixel();
  if (p1 & 32) setPixel(); else clearPixel();
  // Line 3
  if (p1 & 8) setPixel(); else clearPixel();
  if (p1 & 64) setPixel(); else clearPixel();
  if (p1 & 128) setPixel(); else clearPixel();
  if (p2 & 128) setPixel(); else clearPixel();
  if (p1 & 32) setPixel(); else clearPixel();
  // Line 4
  if (p2 & 1) setPixel(); else clearPixel();
  if (p2 & 2) setPixel(); else clearPixel();
  if (p1 & 16) setPixel(); else clearPixel();
  if (p2 & 4) setPixel(); else clearPixel();
  if (p2 & 8) setPixel(); else clearPixel();
  // Line 5
  if (p2 & 16) setPixel(); else clearPixel();
  if (p2 & 32) {
    setPixel();
    setPixel();
    setPixel();
  } else {
    clearPixel();
    clearPixel();
    clearPixel();
  }
  if (p2 & 64) setPixel(); else clearPixel();
  return width;
}

void setColor(byte r, byte g, byte b) {
  gr = r;
  gg = g;
  gb = b;
}

Geen opmerkingen: