/*
   *** DMX QUAD DIMMERPACK FIRMWARE ***
   http://clx.freeshell.org/dmx-dimmer.html


   2018 - GNU PUBLIC LICENCE (GPL)

   Compiler used: CCS (PCM or PCW)
*/

#include <16f870.h>
#include "defines.h"
#include "dmx.h"

#fuses HS, NOWDT, NOLVP, NOPROTECT
#use delay (clock=20000000)
#use rs232 (baud=250000, xmit=PIN_C6, rcv=PIN_C7)

#bit  SYNC50HZ  = PORTB.0

#byte _A8TO2    = PORTB
#bit  _A1       = PORTC.4
#bit  _A0       = PORTC.5
#bit  TRIG1     = PORTC.0
#bit  TRIG2     = PORTC.1
#bit  TRIG3     = PORTC.3
#bit  TRIG4     = PORTC.2

void init(void){
	PORTA = 0; PORTB = 0; PORTC = 0;
	TRISA = 0b00000000;
	TRISB = 0b11111111;
	TRISC = 0b10110000;

	setup_adc_ports(NO_ANALOGS);
	port_b_pullups(TRUE);
	setup_timer_1(T1_INTERNAL|T1_DIV_BY_8);
	enable_interrupts(int_rda);

	ext_int_edge(L_TO_H);
	enable_interrupts(INT_EXT);
	enable_interrupts(global);
	delay_ms(50);
	SPEN = 1;
}

int16 read_dip_switches(void){
	int16 value = (~_A8TO2&0xFE)<<1;
	if (!_A1) { value|=2; }
	if (!_A0) { value|=1; }
#ifdef DEBUG
	value&=0x7F;
#endif
	return value;
}

const int16 dmx2durations_lut[256] = {
	/* ANTI S-CURVE LINEARISATION */
	9999, 6080, 5954, 5914, 5878, 5846, 5815, 5786,
	5758, 5731, 5705, 5681, 5656, 5633, 5610, 5587,
	5565, 5544, 5523, 5502, 5481, 5461, 5441, 5422,
	5402, 5383, 5365, 5346, 5327, 5309, 5291, 5273,
	5255, 5238, 5220, 5203, 5186, 5169, 5152, 5135,
	5118, 5102, 5085, 5069, 5053, 5037, 5020, 5005,
	4989, 4973, 4957, 4941, 4926, 4910, 4895, 4879,
	4864, 4849, 4833, 4818, 4803, 4788, 4773, 4758,
	4743, 4728, 4713, 4699, 4684, 4669, 4654, 4640,
	4625, 4611, 4596, 4581, 4567, 4552, 4538, 4524,
	4509, 4495, 4481, 4466, 4452, 4438, 4423, 4409,
	4395, 4381, 4366, 4352, 4338, 4324, 4310, 4295,
	4281, 4267, 4253, 4239, 4225, 4211, 4197, 4182,
	4168, 4154, 4140, 4126, 4112, 4098, 4084, 4069,
	4055, 4041, 4027, 4013, 3999, 3984, 3970, 3956,
	3942, 3928, 3913, 3899, 3885, 3871, 3856, 3842,
	3828, 3813, 3799, 3784, 3770, 3756, 3741, 3727,
	3712, 3697, 3683, 3668, 3654, 3639, 3624, 3609,
	3595, 3580, 3565, 3550, 3535, 3520, 3505, 3490,
	3475, 3460, 3445, 3429, 3414, 3399, 3383, 3368,
	3353, 3337, 3321, 3306, 3290, 3274, 3258, 3242,
	3226, 3210, 3194, 3178, 3162, 3145, 3129, 3113,
	3096, 3079, 3063, 3046, 3029, 3012, 2995, 2977,
	2960, 2943, 2925, 2907, 2889, 2872, 2854, 2835,
	2817, 2799, 2780, 2761, 2743, 2724, 2704, 2685,
	2666, 2646, 2626, 2606, 2586, 2565, 2545, 2524,
	2503, 2482, 2460, 2438, 2416, 2394, 2371, 2348,
	2325, 2302, 2278, 2254, 2229, 2204, 2179, 2153,
	2127, 2100, 2073, 2045, 2016, 1987, 1958, 1927,
	1896, 1864, 1831, 1798, 1763, 1727, 1690, 1651,
	1611, 1569, 1525, 1479, 1430, 1379, 1324, 1264,
	1199, 1127, 1046,  951,  835,  676,  362,    0
};

int1 trigged = 0, recompute_flag = 0;
#int_ext
void exttrig(void){ //sync input and loopback, trig. on falling edges
	trigged = 1;
	set_timer1(0);

	if (dmx.data[0] != 255) { TRIG1 = 0; }
	if (dmx.data[1] != 255) { TRIG2 = 0; }
	if (dmx.data[2] != 255) { TRIG3 = 0; }
	if (dmx.data[3] != 255) { TRIG4 = 0; }
	recompute_flag = 1;
}

void main(void){
	unsigned int16 timervalue;
	int16 computed_delays[4] = {0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF};

	init();
	dmx.firstchannel = read_dip_switches();
	dmx_init();

	for(;;){ // main loop
		do {
			trigged = 0;
			timervalue = get_timer1();
		} while (trigged);

		if (recompute_flag) {
			recompute_flag = 0;
			computed_delays[0] = dmx2durations_lut[dmx.data[0]];
			computed_delays[1] = dmx2durations_lut[dmx.data[1]];
			computed_delays[2] = dmx2durations_lut[dmx.data[2]];
			computed_delays[3] = dmx2durations_lut[dmx.data[3]];
			dmx_check_for_overflow();
			dmx.firstchannel = read_dip_switches();
		}

		if (timervalue > 6100) { continue; }
		if (timervalue > computed_delays[0]) { TRIG1 = 1; }
		if (timervalue > computed_delays[1]) { TRIG2 = 1; }
		if (timervalue > computed_delays[2]) { TRIG3 = 1; }
		if (timervalue > computed_delays[3]) { TRIG4 = 1; }
	} // main loop end
}
