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;
}
}
}