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

#include <In430.h>
#include <msp430x41x.h>
#include <string.h>

// Starburst segment definitions.
#define _F 0x02
#define _G 0x04
#define _E 0x08
#define _H 0x10
#define _J 0x20
#define _Q 0x40
#define _D 0x80
#define _A 0x100
#define _K 0x200
#define _P 0x400
#define _N 0x800
#define _B 0x1000
#define _M 0x2000
#define _C 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 = 0xfd;
  
  // Clear display.
  LCDM1 = 0x00;
  LCDM2 = 0x00;
  LCDM3 = 0x00;
  LCDM4 = 0x00;
  LCDM5 = 0x00;
  LCDM6 = 0x00;
  LCDM7 = 0x00;
  LCDM8 = 0x00;
  LCDM9 = 0x00;
  LCDM10 = 0x00;
  LCDM11 = 0x00;
  LCDM12 = 0x00;
}

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 *)0x92 + position*2;
  unsigned digits = starburst_segments[c-' '];
  base[0] = base[0] & 0x1 | digits;  
  base[1] = base[1] & 0x80 | (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-5; ++i)
      {
        for (j = 0; j < 5; ++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)
{ 
  // Turn off the watchdog.
  WDTCTL = WDTHOLD + WDTPW;

  // Set up interrupts and LCD.
  IE1 = 0;
  IE2 = 0;
  IFG1 = 0;
  IFG2 = 0;
  BTCTL = BT_fLCD_DIV32 + 0x24;
  
  // Turn on Basic Timer interrupts
  IE2 |= BTIE;

  // Enable interrupts.
  _EINT();

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