main.c

/******************************************************************************/

/* Files to Include */

/******************************************************************************/

#if defined(__XC)

#include <xc.h> /* XC8 General Include File */

#elif defined(HI_TECH_C)

#include <htc.h> /* HiTech General Include File */

#elif defined(__18CXX)

#include <p18cxxx.h> /* C18 General Include File */

#endif

#if defined(__XC) || defined(HI_TECH_C)

#include <stdint.h> /* For uint8_t definition */

#include <stdbool.h> /* For true/false definition */

#endif

#include <stdlib.h>

#include <string.h>

#include "system.h" /* System funct/params, like osc/peripheral config */

#include "user.h" /* User funct/params, such as InitApp */

#include "globals.h"

// global variables

volatile TICK zero_cross = 0;

volatile unsigned char updated = 0;

#define NUM_CHANNELS 6

#define TICKS_PZC 129 //Ticks per zero cross

void program_decode();

void run_channels();

/******************************************************************************/

/* User Global Variable Declaration */

/******************************************************************************/

/* i.e. uint8_t <variable_name>; */

/******************************************************************************/

/* Main Program */

/******************************************************************************/

typedef enum {steady=0,blink,fade,seesaw,off} state_t;

typedef struct{

unsigned char mask;

state_t state;

union{

struct{ // steady

unsigned char brightness;

};

struct{ // blink

unsigned char on_brightness;

unsigned char off_brightness;

unsigned char cur_brightness;

TICK on_time;

TICK off_time;

TICK time;

};

struct{ // fade and seesaw

unsigned char start_brightness;

unsigned char stop_brightness;

unsigned char cur_brightness;

char slope;

};

}options;

} Channel;

state_t state;

Channel channels[NUM_CHANNELS] = {{(0x01<<0),off},

{(0x01<<1),off},

{(0x01<<2),off},

{(0x01<<3),off},

{(0x01<<4),off},

{(0x01<<5),off}

};

TICK program_start_time;

unsigned short program_len;

// return position of first occurenc of c, return 0xFF if not found

unsigned char indexOf(char str[], char c)

{

unsigned char i=0;

while(str[i] != '\0'){

if(str[i] == c)

return i;

i++;

}

return 0xFF;

}

// returns a pointer to the first occurence of c, null if not found

char* findChr(char str[], char c)

{

unsigned char i=0;

while(str[i] != '\0'){

if(str[i] == c)

&str[i];

i++;

}

return NULL;

}

// moved to global to avoid stack frame errors

// c -steady, opt1 = brightness

// s -seesaw, opt1 start_brightness, opt2 stop_brightness, opt3 cur_brightness, opt4 slope

// f -fase, opt1 start_brightness, opt2 stop_brightness, opt3 slope

// b -blink, opt1 on_brightness, opt2 off_brightness, opt3 on_time, opt4 off_time

// l -loop

//start_time channel state opt1 opt2 op3... \0

#pragma idata lightshow

// light show 1

char program_str[] =

"0 loop 2\n"

"0 loop 10\n"

"0 3 c 1\n"

"150 3 z\n"

"0 4 c 1\n"

"150 4 z\n"

"0 5 c 1\n"

"150 5 z\n"

"0 end \n"

"0 3 b 1 120 4000 4000\n"

"0 4 b 1 120 4000 4000\n"

"0 5 b 1 120 4000 4000\n"

"910 loop 10\n"

"0 3 c 1\n"

"150 3 z\n"

"0 5 c 1\n"

"150 5 z\n"

"0 4 c 1\n"

"150 4 z\n"

"0 end \n"

"0 3 b 1 120 4000 4000\n"

"0 4 b 1 120 4000 4000\n"

"0 5 b 1 120 4000 4000\n"

"1000 5 z\n"

"0 loop 5\n"

"0 3 f 120 1 -2\n"

"150 4 f 120 1 -2\n"

"150 5 f 120 1 -2\n"

"150 3 f 1 120 2\n"

"150 4 f 1 120 2\n"

"150 5 f 1 120 2\n"

"150 end \n"

"0 3 b 1 120 4000 4000\n"

"0 4 b 1 120 4000 4000\n"

"0 5 b 1 120 4000 4000\n"

"1000 5 z\n"

"0 end \n"

"0 loop 3\n"

"0 3 c 100\n"

"0 4 c 80\n"

"0 5 c 80\n"

"0 0 f 120 1 -1\n"

"250 1 f 120 1 -1\n"

"250 2 f 120 1 -1\n"

"10 0 f 1 120 1\n"

"260 1 f 1 120 1\n"

"260 2 f 1 120 1\n"

"500 end \n"

"0 loop 3\n"

"0 2 f 120 1 -1\n"

"250 1 f 120 1 -1\n"

"250 0 f 120 1 -1\n"

"10 2 f 1 120 1\n"

"260 1 f 1 120 1\n"

"260 0 f 1 120 1\n"

"500 end \n"

"0 loop 3\n"

"0 0 f 120 1 -1\n"

"250 1 f 120 1 -1\n"

"250 2 f 120 1 -1\n"

"10 0 f 1 120 1\n"

"260 1 f 1 120 1\n"

"260 2 f 1 120 1\n"

"250 2 f 120 1 -1\n"

"250 1 f 120 1 -1\n"

"250 0 f 120 1 -1\n"

"10 2 f 1 120 1\n"

"260 1 f 1 120 1\n"

"260 0 f 1 120 1\n"

"500 end \n"

"0 loop 5\n"

"0 3 f 120 1 -2\n"

"150 4 f 120 1 -2\n"

"150 5 f 120 1 -2\n"

"150 3 f 1 120 2\n"

"150 4 f 1 120 2\n"

"150 5 f 1 120 2\n"

"150 end \n"

"0 loop 2\n"

"0 0 z\n"

"0 1 z\n"

"0 2 z\n"

"0 3 c 100\n"

"0 4 c 80\n"

"0 5 c 80\n"

"250 loop 3\n"

"0 0 f 120 1 -1\n"

"150 1 f 120 1 -1\n"

"150 2 f 120 1 -1\n"

"800 2 f 1 120 1\n"

"150 1 f 1 120 1\n"

"150 0 f 1 120 1\n"

"700 end \n"

"0 0 b 30 70 2000 2000\n"

"0 1 b 30 70 2000 2000\n"

"0 2 b 30 70 2000 2000\n"

"1000 end \n" // need to space after the end to make it recognize it

"0 0 z\n"

"0 1 z\n"

"0 2 z\n"

"0 3 z\n"

"0 4 z\n"

"0 5 z\n"

"1000 0 c 1\n"

"0 1 c 1\n"

"0 2 c 1\n"

"1000 0 z\n"

"0 1 z\n"

"0 2 z\n";

#pragma udata

void main(void)

{

TICK t1, t2;

unsigned char tw=0;

/* Configure the oscillator for the device */

ConfigureOscillator();

/* Initialize I/O and Peripherals for application */

InitApp();

program_start_time = TickGet();

program_len = strlen(program_str);

// start the channels off dark

// channels[0].state = steady;

// channels[0].options.brightness = 95;

//

// channels[1].state = fade;

// channels[1].options.start_brightness = 125;

// channels[1].options.stop_brightness = 2;

// channels[1].options.cur_brightness = 125;

// channels[1].options.slope = -1;

// //channels[1].options.brightness = 95;

//

// channels[2].state = steady;

// channels[2].options.brightness = 95;

TRISCbits.TRISC3 = 0;

t1 = 0;

while(1)

{

if(TickGet() - t1 >= 224){ // only call program decode 25/sec

program_decode();

t1 = TickGet();

}

run_channels();

}

}

void program_decode()

{

TICK switch_time;

static TICK previous_time=0;

static unsigned short program_pos=0;

static unsigned short loop_stack[3];

static unsigned char loop_cnt[3];

static unsigned char loop_ptr=0;

Channel channel;

char mode;

unsigned char cmd_len, str_pos=0,ch;

unsigned long opt;

signed char slope_opt;

unsigned char w = 0;

// parse program string

// update channels

// unsigned long atoul (const auto char *s);

// signed char atob (const auto char *s);

// void *memset (auto void *s, auto unsigned char c, auto size_t n);

// void *memcpy (auto void *s1, auto const void *s2, auto size_t n);

// start_time channel state opt1 opt2 op3... \0

switch_time = atoul(&program_str[program_pos]);

if(TickGet() - previous_time >= (switch_time*TICK_SECOND)/1000){

previous_time = TickGet();

PORTCbits.RC3 ^= 1;

memset(&channel,0,sizeof(channel));

cmd_len = indexOf(&program_str[program_pos],'\n'); // find length of next command

// get past the time part

str_pos += indexOf(&program_str[program_pos+str_pos], ' ') + 1; // +1 for the space

// determine if it's loop or end of loop

w = indexOf(&program_str[program_pos+str_pos],' ');

if(w==4){ // for loop

// // do loop stuff

loop_stack[loop_ptr] = program_pos+cmd_len+1; // +1 for'\n'

str_pos += indexOf(&program_str[program_pos+str_pos], ' ') + 1; // +1 for the space

loop_cnt[loop_ptr] = atoi(&program_str[program_pos+str_pos]);

loop_ptr++;

program_pos += cmd_len+1; // move to next command

Nop();

return;

}else if(w==3){ // end

loop_cnt[loop_ptr-1]--; // loop_ptr points to the next free spot

if(loop_cnt[loop_ptr-1] == 0){

loop_ptr--;

Nop();

Nop();

program_pos += cmd_len+1; // move to next command

Nop();

Nop();

}else{

program_pos = loop_stack[loop_ptr-1];

}

Nop();

Nop();

return;

}

// normal channel command

ch = atoi(&program_str[program_pos+str_pos]);

channel.mask = (0x01 << ch);

str_pos += indexOf(&program_str[program_pos+str_pos], ' ') + 1; // +1 for the space

mode = program_str[program_pos + str_pos];

// now get the options

str_pos += indexOf(&program_str[program_pos+str_pos], ' ') + 1; // +1 for the space

switch(mode){

Nop();

case 'c': // steady

channel.state = steady;

opt = atoi(&program_str[program_pos+str_pos]);

channel.options.brightness = opt;

memcpy((void*)&channels[ch],(void*)&channel,sizeof(channel));

break;

case 'b':

channel.state = blink;

// b -blink, opt1 on_brightness, opt2 off_brightness, opt3 on_time, opt4 off_time

// opt1 start_brightness

opt = atoi(&program_str[program_pos+str_pos]);

str_pos += indexOf(&program_str[program_pos+str_pos], ' ') + 1; // +1 for the space

channel.options.on_brightness = opt;

channel.options.cur_brightness = opt;

// opt2 stop_brightness

opt = atoi(&program_str[program_pos+str_pos]);

str_pos += indexOf(&program_str[program_pos+str_pos], ' ') + 1; // +1 for the space

channel.options.off_brightness = opt;

// opt3 on_time

opt = atoi(&program_str[program_pos+str_pos]);

str_pos += indexOf(&program_str[program_pos+str_pos], ' ') + 1; // +1 for the space

channel.options.on_time = opt;

// opt4 off_time

opt = atoi(&program_str[program_pos+str_pos]);

str_pos += indexOf(&program_str[program_pos+str_pos], ' ') + 1; // +1 for the space

channel.options.off_time = opt;

memcpy((void*)&channels[ch],(void*)&channel,sizeof(channel));

break;

case 'f':

channel.state = fade;

// opt1 start brightness

Nop();

opt = atoi(&program_str[program_pos+str_pos]);

str_pos += indexOf(&program_str[program_pos+str_pos], ' ') + 1; // +1 for the space

channel.options.start_brightness = opt;

channel.options.cur_brightness = opt;

// opt2 stop brightness

opt = atoi(&program_str[program_pos+str_pos]);

str_pos += indexOf(&program_str[program_pos+str_pos], ' ') + 1; // +1 for the space

channel.options.stop_brightness = opt;

// // opt3 cur_brightness

// opt = atoi(&program_str[program_pos+str_pos]);

// str_pos += indexOf(&program_str[program_pos+str_pos], ' ') + 1; // +1 for the space

// channel.options.cur_brightness = opt;

// opt4 slope

slope_opt = atoi(&program_str[program_pos+str_pos]);

str_pos += indexOf(&program_str[program_pos+str_pos], ' ') + 1; // +1 for the space

channel.options.slope = slope_opt;

Nop();

memcpy((void*)&channels[ch],(void*)&channel,sizeof(channel));

break;

case 's':

channel.state = seesaw;

// opt1 start brightness

opt = atoi(&program_str[program_pos+str_pos]);

str_pos += indexOf(&program_str[program_pos+str_pos], ' ') + 1; // +1 for the space

channel.options.start_brightness = opt;

// opt2 stop brightness

opt = atoi(&program_str[program_pos+str_pos]);

str_pos += indexOf(&program_str[program_pos+str_pos], ' ') + 1; // +1 for the space

channel.options.stop_brightness = opt;

// opt3 cur_brightness

opt = atoi(&program_str[program_pos+str_pos]);

str_pos += indexOf(&program_str[program_pos+str_pos], ' ') + 1; // +1 for the space

channel.options.cur_brightness = opt;

// opt4 slope

slope_opt = atoi(&program_str[program_pos+str_pos]);

str_pos += indexOf(&program_str[program_pos+str_pos], ' ') + 1; // +1 for the space

channel.options.slope = slope_opt;

memcpy((void*)&channels[ch],(void*)&channel,sizeof(channel));

break;

case 'z':

channel.state = off;

memcpy((void*)&channels[ch],(void*)&channel,sizeof(channel));

break;

}

// move program_pos to the next command

if(cmd_len == 0xFF){ // not found

program_pos = 0;

program_start_time = TickGet();

// program_pos = 0xFFFFFF;

}else{

program_pos += cmd_len+1; // move to next command

}

}

}

void run_channels()

{

unsigned char i = 0;

unsigned char tmp;

for(i=0;i<NUM_CHANNELS;i++){

switch(channels[i].state){

case steady:

if(!(updated & channels[i].mask)){

if( (TickGet() - zero_cross) > channels[i].options.brightness){

PORTD |= channels[i].mask;

updated |= channels[i].mask;

}

}

break;

case blink:

if(!(updated & channels[i].mask)){

if( (TickGet() - zero_cross) > channels[i].options.cur_brightness){

PORTD |= channels[i].mask;

updated |= channels[i].mask;

}

if(channels[i].options.cur_brightness == channels[i].options.on_brightness){

if(TickGet() - channels[i].options.time > channels[i].options.on_time){

channels[i].options.cur_brightness = channels[i].options.off_brightness;

channels[i].options.time = TickGet();

}

}else{

if(TickGet() - channels[i].options.time > channels[i].options.off_time){

channels[i].options.cur_brightness = channels[i].options.on_brightness;

channels[i].options.time = TickGet();

}

}

}

break;

case fade:

if(!(updated & channels[i].mask)){

if(TickGet() - zero_cross > channels[i].options.cur_brightness){

PORTD |= channels[i].mask;

updated |= channels[i].mask;

channels[i].options.cur_brightness += channels[i].options.slope;

if(channels[i].options.slope>0){

if(channels[i].options.cur_brightness >= channels[i].options.stop_brightness){

// fade then stop

channels[i].state = steady;

tmp = channels[i].options.stop_brightness;

channels[i].options.brightness = tmp;

// uncomment following line to enable fade cycling

//channels[i].options.cur_brightness = channels[i].options.start_brightness;

}

}else{

if(channels[i].options.cur_brightness <= channels[i].options.stop_brightness){

channels[i].state = steady;

tmp = channels[i].options.stop_brightness;

channels[i].options.brightness = tmp;

// same deal as above

//channels[i].options.cur_brightness = channels[i].options.start_brightness;

}

}

}

}

break;

case seesaw:

if(!(updated & channels[i].mask)){

if(TickGet() - zero_cross > channels[i].options.cur_brightness){

PORTD |= channels[i].mask;

updated |= channels[i].mask;

channels[i].options.cur_brightness += channels[i].options.slope;

if(channels[i].options.slope>0){

if(channels[i].options.cur_brightness >= channels[i].options.stop_brightness){

//channels[i].options.cur_brightness = channels[i].options.start_brightness;

tmp = channels[i].options.start_brightness;

channels[i].options.start_brightness = channels[i].options.stop_brightness;

channels[i].options.stop_brightness = tmp;

channels[i].options.slope *= -1;

}

}else{

if(channels[i].options.cur_brightness <= channels[i].options.stop_brightness){

//channels[i].options.cur_brightness = channels[i].options.start_brightness;

tmp = channels[i].options.start_brightness;

channels[i].options.start_brightness = channels[i].options.stop_brightness;

channels[i].options.stop_brightness = tmp;

channels[i].options.slope *= -1;

}

}

}

}

break;

case off:

if(!(updated & channels[i].mask)){

PORTD &= ~channels[i].mask;

updated |= channels[i].mask;

}

break;

}

}

}