// ES449 Sample Program
// Copyright (c) 2002 Rowley Associates Limited

#include <msp430x44x.h>
#include <string.h>

// Starburst segment definitions.
#define _N 0x0001
#define _M 0x0002
#define _K 0x0004
#define _J 0x0008
#define _D 0x0010
#define _C 0x0020
#define _B 0x0040
#define _A 0x0080
#define _P 0x0100
#define _Q 0x0200
#define _G 0x0400
#define _H 0x0800
#define _E 0x2000
#define _F 0x4000

static const unsigned starburst_segments[] =
{
  /* */   0,
  /*!*/   _F | _E,    // Lame
  /*"*/   _H | _K,
  /*#*/   _J | _B | _P | _C | _G | _M,
  /*$*/   _A | _F | _G | _M | _C | _D | _J | _P,
  /*%*/   0,          // No good idea
  /*&*/   0,          // No good idea
  /*'*/   _K,
  /*(*/   _A | _F | _E | _D,
  /*)*/   _A | _B | _C | _D,
  /***/   _H | _J | _K | _G | _M | _Q | _P | _N,
  /*+*/   _J | _G | _M | _P,
  /*,*/   0,          // No good idea
  /*-*/   _G | _M,
  /*.*/   0,          // Should use decimal point, but...
  /*/*/   _K | _Q,
  /*0*/   _A | _B | _C | _D | _E | _F | _Q | _K,
  /*1*/   _C | _B,
  /*2*/   _A | _B | _M | _G | _E | _D,
  /*3*/   _A | _B | _M | _G | _C | _D,
  /*4*/   _F | _G | _M | _B | _C,
  /*5*/   _A | _F | _G | _M | _C | _D,
  /*6*/   _A | _F | _E | _D | _C | _M | _G,
  /*7*/   _F | _A | _B | _C,
  /*8*/   _A | _B | _C | _D | _E | _F | _G | _M,
  /*9*/   _A | _F | _G | _M | _B | _C | _D,
  /*:*/   0,          // No good idea
  /*;*/   0,          // No good idea
  /*<*/   _K | _N,
  /*=*/   _G | _M | _D,
  /*>*/   _H | _Q,
  /*?*/   _A | _B | _M | _G | _E,
  /*@*/   0,          // No good idea
  /*A*/   _E | _F | _A | _B | _C | _G | _M,
  /*B*/   _A | _B | _C | _D | _J | _P | _M,
  /*C*/   _A | _F | _E | _D,
  /*D*/   _A | _B | _C | _D | _J | _P,
  /*E*/   _A | _F | _E | _D | _G | _M,
  /*F*/   _A | _F | _E | _G | _M,
  /*G*/   _A | _F | _E | _D | _C | _M,
  /*H*/   _F | _E | _G | _M | _B | _C,
  /*I*/   _A | _J | _P | _D,
  /*J*/   _B | _C | _D | _E,
  /*K*/   _F | _E | _G | _K | _N,
  /*L*/   _F | _E | _D,
  /*M*/   _E | _F | _H | _K | _B | _C,
  /*N*/   _E | _F | _H | _N | _C | _B,
  /*O*/   _A | _B | _C | _D | _E | _F,
  /*P*/   _E | _F | _A | _B | _G | _M,
  /*Q*/   _A | _B | _C | _D | _E | _F | _N,
  /*R*/   _E | _F | _A | _B | _G | _M | _N,
  /*S*/   _A | _F | _G | _M | _C | _D,
  /*T*/   _A | _J | _P,
  /*U*/   _F | _E | _D | _C | _B,
  /*V*/   _F | _E | _Q | _K,
  /*W*/   _F | _E | _Q | _N | _C | _B,
  /*X*/   _H | _K | _Q | _N,
  /*Y*/   _H | _K | _P,
  /*Z*/   _A | _K | _Q | _D
};

static void
sblcd_init(void)
{
  P2SEL = 0xff;
  P3SEL = 0xff;
  P4SEL = 0xff;
  P5SEL = 0xff;

  // Setup LCD
  LCDCTL = LCDSG0_7 | LCD4MUX | LCDSON | LCDON;
  
  // Clear display.
  memset(LCDMEM, 0, 20);
}

static void
timer_interrupt(void) __interrupt[BASICTIMER_VECTOR]
{
  // Wake processor when delay expires.
  _BIC_SR_IRQ(CPUOFF | OSCOFF | SCG1 | SCG0);
}
  
static void
sblcd_display_char(char c, int position)
{
  unsigned char *base = (unsigned char *)0x97+14 - position*2;
  unsigned digits = starburst_segments[c-' '];
  base[0] = (unsigned char)digits;  
  base[1] = (unsigned char)(digits>>8);  
}

static void
sblcd_display_scrolling_message(const char *msg)
{
  int len = strlen(msg);
  int i, j;
    
  // Scroll leader in.
  for (;;)
    for (i = 0; i < len-7; ++i)
      {
        for (j = 0; j < 7; ++j)
          sblcd_display_char(msg[i+j], j);
        
        // Turn CPU off and wait for a basic timer interrupt.
        _BIS_SR(CPUOFF | SCG1 | SCG0);
      }
}

void main(void)
{
  // Stop watchdog.
  WDTCTL = WDTHOLD | WDTPW;

  // Set FLL.
  FLL_CTL0 |= XCAP18PF;

  P5DIR |= 0xc0;
  P5OUT |= 0x80;
  P5OUT &= ~0x80;
  P5OUT |= 0x80;
  P5OUT &= ~0x80;

  // Set up basic timer for LCD
  BTCTL = BT_fLCD_DIV64 + 0x23;

  // Turn on Basic Timer interrupts
  IE2 |= BTIE;

  P1SEL = 0x32;
  P2SEL = 0x00;
  P3SEL = 0x00;
  P4SEL = 0xfc;
  P5SEL = 0xff;

  // Start things up  
  sblcd_init();
  _EINT();
  sblcd_display_scrolling_message("     *** ROWLEY ASSOCIATES CROSSWORKS FOR MSP430 --- SOFTBAUGH ES449 ***     ");
}
