
/*
 * Font.c

 *
 *  Created on: 20 Dec 2015
 *      Author: Mike
 */
#include <stdint.h>
#include <string.h>
#include "libSSD1306/ap_math.h"
#include "libSSD1306/SSD1306.h"

#include "libSSD1306/Font.h"

#include "libSSD1306/ascii-lucida.h"

uint8_t cursor_x;
uint8_t cursor_y;

/*
 * display text using a 5x7 bitmap font in ASCII letters
 */
static const unsigned char font[][5] =
  {
        { 0x00, 0x00, 0x00, 0x00, 0x00 },   //   0x20 32
	{ 0x00, 0x00, 0x6f, 0x00, 0x00 },   // ! 0x21 33
	{ 0x00, 0x07, 0x00, 0x07, 0x00 },   // " 0x22 34
	{ 0x14, 0x7f, 0x14, 0x7f, 0x14 },   // # 0x23 35
	{ 0x2e, 0x2a, 0xff, 0x2a, 0x3a },  // $ 0x24 36
	{ 0x23, 0x13, 0x08, 0x64, 0x62 },   // % 0x25 37
	{ 0x36, 0x49, 0x56, 0x20, 0x50 },   // & 0x26 38
	{ 0x00, 0x00, 0x07, 0x00, 0x00 },   // ' 0x27 39
	{ 0x00, 0x1c, 0x22, 0x41, 0x00 },   // ( 0x28 40
	{ 0x00, 0x41, 0x22, 0x1c, 0x00 },   // ) 0x29 41
	{ 0x14, 0x08, 0x3e, 0x08, 0x14 },   // * 0x2a 42
	{ 0x08, 0x08, 0x3e, 0x08, 0x08 },   // + 0x2b 43
	{ 0x00, 0x50, 0x30, 0x00, 0x00 },   // , 0x2c 44
	{ 0x08, 0x08, 0x08, 0x08, 0x08 },   // - 0x2d 45
	{ 0x00, 0x60, 0x60, 0x00, 0x00 },   // . 0x2e 46
	{ 0x20, 0x10, 0x08, 0x04, 0x02 },   // / 0x2f 47
	{ 0x3e, 0x51, 0x49, 0x45, 0x3e },   // 0 0x30 48
	{ 0x00, 0x42, 0x7f, 0x40, 0x00 },   // 1 0x31 49
	{ 0x42, 0x61, 0x51, 0x49, 0x46 },   // 2 0x32 50
	{ 0x21, 0x41, 0x45, 0x4b, 0x31 },   // 3 0x33 51
	{ 0x18, 0x14, 0x12, 0x7f, 0x10 },   // 4 0x34 52
	{ 0x27, 0x45, 0x45, 0x45, 0x39 },   // 5 0x35 53
	{ 0x3c, 0x4a, 0x49, 0x49, 0x30 },   // 6 0x36 54
	{ 0x01, 0x71, 0x09, 0x05, 0x03 },   // 7 0x37 55
	{ 0x36, 0x49, 0x49, 0x49, 0x36 },   // 8 0x38 56
	{ 0x06, 0x49, 0x49, 0x29, 0x1e },   // 9 0x39 57
	{ 0x00, 0x36, 0x36, 0x00, 0x00 },   // : 0x3a 58
	{ 0x00, 0x56, 0x36, 0x00, 0x00 },   // ; 0x3b 59
	{ 0x08, 0x14, 0x22, 0x41, 0x00 },   // < 0x3c 60
	{ 0x14, 0x14, 0x14, 0x14, 0x14 },   // = 0x3d 61
	{ 0x00, 0x41, 0x22, 0x14, 0x08 },   // > 0x3e 62
	{ 0x02, 0x01, 0x51, 0x09, 0x06 },   // ? 0x3f 63
	{ 0x3e, 0x41, 0x5d, 0x49, 0x4e },   // @ 0x40 64
	{ 0x7e, 0x09, 0x09, 0x09, 0x7e },   // A 0x41 65
	{ 0x7f, 0x49, 0x49, 0x49, 0x36 },   // B 0x42 66
	{ 0x3e, 0x41, 0x41, 0x41, 0x22 },   // C 0x43 67
	{ 0x7f, 0x41, 0x41, 0x41, 0x3e },   // D 0x44 68
	{ 0x7f, 0x49, 0x49, 0x49, 0x41 },   // E 0x45 69
	{ 0x7f, 0x09, 0x09, 0x09, 0x01 },   // F 0x46 70
	{ 0x3e, 0x41, 0x49, 0x49, 0x7a },   // G 0x47 71
	{ 0x7f, 0x08, 0x08, 0x08, 0x7f },   // H 0x48 72
	{ 0x00, 0x41, 0x7f, 0x41, 0x00 },   // I 0x49 73
	{ 0x20, 0x40, 0x41, 0x3f, 0x01 },   // J 0x4a 74
	{ 0x7f, 0x08, 0x14, 0x22, 0x41 },   // K 0x4b 75
	{ 0x7f, 0x40, 0x40, 0x40, 0x40 },   // L 0x4c 76
	{ 0x7f, 0x02, 0x0c, 0x02, 0x7f },   // M 0x4d 77
	{ 0x7f, 0x04, 0x08, 0x10, 0x7f },   // N 0x4e 78
	{ 0x3e, 0x41, 0x41, 0x41, 0x3e },   // O 0x4f 79
	{ 0x7f, 0x09, 0x09, 0x09, 0x06 },   // P 0x50 80
	{ 0x3e, 0x41, 0x51, 0x21, 0x5e },   // Q 0x51 81
	{ 0x7f, 0x09, 0x19, 0x29, 0x46 },   // R 0x52 82
	{ 0x46, 0x49, 0x49, 0x49, 0x31 },   // S 0x53 83
	{ 0x01, 0x01, 0x7f, 0x01, 0x01 },   // T 0x54 84
	{ 0x3f, 0x40, 0x40, 0x40, 0x3f },   // U 0x55 85
	{ 0x0f, 0x30, 0x40, 0x30, 0x0f },   // V 0x56 86
	{ 0x3f, 0x40, 0x30, 0x40, 0x3f },   // W 0x57 87
	{ 0x63, 0x14, 0x08, 0x14, 0x63 },   // X 0x58 88
	{ 0x07, 0x08, 0x70, 0x08, 0x07 },   // Y 0x59 89
	{ 0x61, 0x51, 0x49, 0x45, 0x43 },   // Z 0x5a 90
	{ 0x00, 0x00, 0x7f, 0x41, 0x00 },   // [ 0x5b 91
	{ 0x02, 0x04, 0x08, 0x10, 0x20 },   // \ 0x5c 92
	{ 0x00, 0x41, 0x7f, 0x00, 0x00 },   // ] 0x5d 93
	{ 0x04, 0x02, 0x01, 0x02, 0x04 },   // ^ 0x5e 94
	{ 0x40, 0x40, 0x40, 0x40, 0x40 },   // _ 0x5f 95
	{ 0x00, 0x00, 0x03, 0x04, 0x00 },   // ` 0x60 96
	{ 0x20, 0x54, 0x54, 0x54, 0x78 },   // a 0x61 97
	{ 0x7f, 0x48, 0x44, 0x44, 0x38 },   // b 0x62 98
	{ 0x38, 0x44, 0x44, 0x44, 0x44 },   // c 0x63 99
	{ 0x38, 0x44, 0x44, 0x48, 0x7f },   // d 0x64 100
	{ 0x38, 0x54, 0x54, 0x54, 0x18 },   // e 0x65 101
	{ 0x08, 0x7e, 0x09, 0x01, 0x02 },   // f 0x66 102
	{ 0x0c, 0x52, 0x52, 0x52, 0x3e },   // g 0x67 103
	{ 0x7f, 0x08, 0x04, 0x04, 0x78 },   // h 0x68 104
	{ 0x00, 0x44, 0x7d, 0x40, 0x00 },   // i 0x69 105
	{ 0x20, 0x40, 0x44, 0x3d, 0x00 },   // j 0x6a 106
	{ 0x00, 0x7f, 0x10, 0x28, 0x44 },   // k 0x6b 107
	{ 0x00, 0x41, 0x7f, 0x40, 0x00 },   // l 0x6c 108
	{ 0x7c, 0x04, 0x18, 0x04, 0x78 },   // m 0x6d 109
	{ 0x7c, 0x08, 0x04, 0x04, 0x78 },   // n 0x6e 110
	{ 0x38, 0x44, 0x44, 0x44, 0x38 },   // o 0x6f 111
	{ 0x7c, 0x14, 0x14, 0x14, 0x08 },   // p 0x70 112
	{ 0x08, 0x14, 0x14, 0x14, 0x7c },   // q 0x71 113
	{ 0x7c, 0x08, 0x04, 0x04, 0x08 },   // r 0x72 114
	{ 0x48, 0x54, 0x54, 0x54, 0x20 },   // s 0x73 115
	{ 0x04, 0x3f, 0x44, 0x40, 0x20 },   // t 0x74 116
	{ 0x3c, 0x40, 0x40, 0x20, 0x7c },   // u 0x75 117
	{ 0x1c, 0x20, 0x40, 0x20, 0x1c },   // v 0x76 118
	{ 0x3c, 0x40, 0x30, 0x40, 0x3c },   // w 0x77 119
	{ 0x44, 0x28, 0x10, 0x28, 0x44 },   // x 0x78 120
	{ 0x0c, 0x50, 0x50, 0x50, 0x3c },   // y 0x79 121
	{ 0x44, 0x64, 0x54, 0x4c, 0x44 },   // z 0x7a 122
	{ 0x00, 0x08, 0x36, 0x41, 0x41 },   // { 0x7b 123
	{ 0x00, 0x00, 0x7f, 0x00, 0x00 },   // | 0x7c 124
	{ 0x41, 0x41, 0x36, 0x08, 0x00 },   // } 0x7d 125
	{ 0x08, 0x0c, 0x08, 0x18, 0x08 }, // ~ 0x7e 126

  };

#define extDegrees 0

static const unsigned char font_ext[][5] =
  {

  [extDegrees] =
    { 0x00, 0x06, 0x09, 0x06, 0x00 }, // a ° sign

    };

void
font_gotoxy (uint8_t x, uint8_t y)
{
  cursor_x = x;
  cursor_y = y;
}

void
font_putchar (uint8_t c)
{
  uint8_t *ptr = display_address () + cursor_x * 6 + cursor_y * WIDTH;
  int i;
  if ('\r' == c)
    {
      cursor_x = 0;
      cursor_y++;
      if (cursor_y >= HEIGHT / 8)
	{
	  cursor_y = 0;
	}
      return;
    }

  for (i = 0; i < 5; i++)
    {
      if (c > ' ' && c < 0x80)
	{
	  *ptr++ = font[c - ' '][i];
	}
      else if (c == '°')
	{
	  *ptr++ = font_ext[extDegrees][i];
	}
      else
	{
	  *ptr++ = 0;
	}
    }
  *ptr++ = 0;

  // move cursor
  cursor_x++;
  if (cursor_x >= WIDTH / 6)
    {
      cursor_x = 0;
      cursor_y++;
      if (cursor_y == HEIGHT / 8)
	{
	  cursor_y = 0;
	}
    }

}

void
font_puts (uint8_t *s)
{
  while (s && *s)
    {
      font_putchar (*(s++));
    }
}

uint8_t
get_digits (uint16_t x, uint16_t y)
{
  return ((ascii_lucida_bits[(y * ascii_lucida_width) / 8 + (x / 8)]) >> (x & 7))
      & 1;
}

static uint8_t
format_num (char *buff, uint8_t digits, uint8_t dp_pos, int val)
{
  digits++;
  uint8_t pos = digits;
  uint8_t dp_loc = pos - dp_pos;
  uint8_t sign = 0;
  if (val < 0)
    {
      sign = 1;
      val = -val;
    }

  buff[pos] = 0;
  while (pos)
    {
      if (pos == dp_loc)
	{
	  buff[--pos] = '.';
	}
      else
	{
	  buff[--pos] = val % 10 + '0';
	  val /= 10;
	  if (val == 0 && pos < dp_loc)
	    break;
	}
    }
  if (sign)
    {
      buff[--pos] = '-';
    }
  return digits;
}

void
font_digits (uint8_t digits, uint8_t dp_pos, int val)
{
  char buff[10] = "        ";
  format_num (buff, digits, dp_pos, val);
  font_puts ((unsigned char *)buff);
}

void
font_sig_digits (uint8_t x, uint8_t y, uint8_t right_justify, uint8_t dp_pos,
		 int val)
{
  char digits;
  char sign = 0;
  int uval;
  if (val < 0)
    {
      uval = -val;
      sign = 1; // mark as negative
    }
  else
    {
      uval = val;
    }
  if (uval < 10) // always one digit for a sign or space, one for a digit
    {
      digits = 1;
    }
  if (uval >= 10 && uval < 100)
    {
      digits = 2;
    }
  if (uval >= 100 && uval < 1000)
    {
      digits = 3;
    }
  if (uval >= 1000)
    {
      digits = 4;
    }
  // backup for the - sign if right justified
  if (right_justify)
    {
      if (dp_pos < 10)
	{
	  digits += 2;
	}
      else
	{
	  digits += 1;
	}
      x -= (digits);
    }

  font_gotoxy (x, y);
  font_digits (digits, dp_pos, val);
}

#define FONTX 10
#define FONTY 18

void
scan_xbm (void)
{

  int i, j;

  for (i = 0; i < FONTY; i++)
    {
      for (j = 0; j < FONTX * 6; j++)
	{
	  drawPixel (j, i, get_digits (j, i));
	}
    }
}

void
print_large_string (char *string, int x, int y, int digits)
{
  int xt, yt, j;
  for (yt = 0; yt < FONTY; yt++) // iterate down scan lines
    {
      for (xt = 0; xt < digits; xt++)
	{
	  for (j = 0; j < FONTX; j++)
	    {
	      unsigned char c = (string[xt] & 0x7F);
	      if (c < 32)
		c = 32;

	      drawPixel (x + j + xt * FONTX, y + yt,
			 get_digits (j + (c - 32) * FONTX, yt));
	    }
	}
    }

}

void
print_digits (uint8_t x, uint8_t y, uint8_t digits, uint8_t dp_pos, int val)
{

  char buff[10] = "        ";
  uint8_t len = format_num (buff, digits, dp_pos, val);
  print_large_string (buff, x, y, len);
}

/* print a digit value 0 to 9 (not ASCII)  rotated by ang */
void
print_rotated (uint8_t x, uint8_t y, int ang, uint8_t val)
{
  int co = ap_cos (ang);
  int si = ap_sin (ang);

  int xt, yt;

  for (yt = 0; yt < FONTY; yt++) // iterate down scan lines
    {
      for (xt = 0; xt < FONTX; xt++)
	{
	  if (get_digits (xt + (val + 16) * FONTX, yt))
	    {
	      int cx = xt - FONTX / 2;
	      int cy = yt - FONTY / 2;

	      int px = AP_SCALE(cx * co - cy * si);
	      int py = AP_SCALE(cx * si + cy * co);

	      drawPixel (x + px, y + py, WHITE);
	    }
	}
    }

}
