--- /dev/null
+#define F_CPU 6000000UL\r
+\r
+#include <avr/interrupt.h>\r
+// #include <util/delay.h>\r
+// #include <avr/sleep.h>\r
+// #include <stdint.h>\r
+#include <avr/io.h>\r
+#include <string.h>\r
+\r
+\r
+//A0 Aref In\r
+//A1 Adc2 In (ADC1)\r
+//A2 Relay2 Out\r
+//A3 Relay1 Out\r
+//A4 RX In\r
+//A5 TX Out\r
+//A6 Switch1 In\r
+//A7 Adc1 In (ADC7)\r
+\r
+//B0 X --\r
+//B1 X --\r
+//B2 Switch2 In \r
+//B3 Reset --\r
+\r
+// cc -- channel address in hex \r
+//Scc(0|1|/) -- switch channel off/on/toggle\r
+//Scc? -- read channel status\r
+//Ccc? -- read current\r
+//Lccxxx -- set current limit (hex)\r
+//Lcc? -- read current limit\r
+//Axxx -- answer - three hex digits or chars\r
+\r
+#define STARTTX(i) txcnt = (i);UCSR1B |= (1<< UDRIE1)\r
+#define ISMYADDR() (rxbuf[1] == '0' && (rxbuf[2] == '0' || rxbuf[2] == '1'))\r
+\r
+\r
+uint8_t output_enable = 0;\r
+uint8_t output_error = 0;\r
+uint16_t adc[2];\r
+\r
+uint8_t rxcnt = 0, txcnt = 0, txpoint = 0;\r
+uint8_t rxbuf[6];\r
+uint8_t txbuf[6];\r
+uint16_t limit[2] = {0x0800,0x0800};\r
+\r
+uint8_t nib_to_hex(uint16_t in, uint8_t nib) {\r
+ uint8_t t = (in >> (nib*4)) & 0xF;\r
+ if (t <= 9) {return t + 0x30;}\r
+ return t - 10 + 0x61;\r
+ }\r
+ \r
+uint8_t hex_to_int(uint8_t h) { //assumes valid number\r
+ if (h < 0x40) return h-0x30;\r
+ if (h < 0x50) return h-0x41+10;\r
+ return h-0x61+10;\r
+ }\r
+ \r
+void sub2(uint8_t* c1, uint8_t* c2) {\r
+ uint8_t b = hex_to_int(*c1)*16 + hex_to_int(*c2);\r
+ b -= 2;\r
+ *c1 = nib_to_hex(b,1);\r
+ *c2 = nib_to_hex(b,0);\r
+ }\r
+\r
+void forward_msg(uint8_t i) {\r
+ sub2(&rxbuf[1],&rxbuf[2]);\r
+ memcpy ((uint8_t*)txbuf,(uint8_t*)rxbuf,i);\r
+ STARTTX(i);\r
+ } \r
+ \r
+void send_answer_hex(uint16_t v) {\r
+ txbuf[0]='A';\r
+ txbuf[1]=nib_to_hex(v,2);\r
+ txbuf[2]=nib_to_hex(v,1);\r
+ txbuf[3]=nib_to_hex(v,0);\r
+ STARTTX(4);\r
+ }\r
+ \r
+void send_answer_chars(uint8_t a, uint8_t b, uint8_t c) {\r
+ txbuf[0]='A';\r
+ txbuf[1]=a;\r
+ txbuf[2]=b;\r
+ txbuf[3]=c;\r
+ STARTTX(4);\r
+ }\r
+\r
+ \r
+void switchoutput(uint8_t chan, int8_t to) {\r
+ if(to == -1)\r
+ output_enable ^= (1<<chan);\r
+ else if (to == 0) {\r
+ output_enable &= ~(1<<chan);\r
+ output_error &= ~(1<<chan);\r
+ }\r
+ else if (to == 1)\r
+ output_enable |= (1<<chan);\r
+ \r
+ uint8_t en1 = ((output_enable & 1) && !(output_error & 1))?1:0;\r
+ uint8_t en2 = ((output_enable & 2) && !(output_error & 2))?1:0;\r
+ PORTA = (PORTA & ~(1<<3)) | ((en1&1)<<3);\r
+ PORTA = (PORTA & ~(1<<2)) | ((en2&1)<<2);\r
+ }\r
+\r
+ISR(TIMER0_OVF_vect) {\r
+ static uint8_t dwncnt[2] = {0,0};\r
+ if(!(PINA & 0x40)) {dwncnt[0]++;} else {dwncnt[0] = 0;}\r
+ if(!(PINB & 0x04)) {dwncnt[1]++;} else {dwncnt[1] = 0;}\r
+ \r
+ if(dwncnt[0] == 100) {switchoutput(0,-1);} \r
+ if(dwncnt[1] == 100) {switchoutput(1,-1);}\r
+ \r
+ ADCSRA |= (1<<ADSC); \r
+ }\r
+\r
+ISR(ADC_vect) {\r
+ static uint8_t channel = 0;\r
+ if(channel == 0) { \r
+ adc[0] = ADC; \r
+ ADMUXA = 1; \r
+ ADCSRA |= (1<<ADSC); \r
+ channel = 1;\r
+ if(limit[0]<adc[0]) {\r
+ output_error |= 2;\r
+ switchoutput(0,-2);\r
+ } \r
+ }\r
+ if(channel == 1) { \r
+ adc[1] = ADC; \r
+ ADMUXA = 7; \r
+ channel = 0;\r
+ if(limit[1]<adc[1]) {\r
+ output_error |= 2;\r
+ switchoutput(1,-2);\r
+ } \r
+ } \r
+ }\r
+\r
+ISR(USART1_UDRE_vect) {\r
+ UDR1 = txbuf[txpoint++];\r
+ if(--txcnt == 0) { \r
+ txpoint = 0;\r
+ UCSR1B &= ~(1<< UDRIE1);\r
+ }\r
+ }\r
+ \r
+ISR(USART1_RX_vect) {\r
+ uint8_t buf = UDR1;\r
+ if (rxcnt != 0 || (buf == 'S' || buf == 'A' || buf == 'L' || buf == 'C')) {\r
+ rxbuf[rxcnt++] = buf;\r
+ }\r
+ //Forward any incoming 4 letter answer \r
+ if (rxcnt == 4) {\r
+ if (rxbuf[0] == 'A') {\r
+ rxcnt = 0;\r
+ memcpy ((uint8_t*)txbuf,(uint8_t*)rxbuf,4);\r
+ STARTTX(4);\r
+ }\r
+ //Four letter 'switch' command \r
+ if (rxbuf[0] == 'S') { \r
+ rxcnt = 0;\r
+ if (ISMYADDR()) {\r
+ rxbuf[2] -= '0';\r
+ if (rxbuf[3] != '?') {\r
+ switchoutput(rxbuf[2],rxbuf[3]-'0');\r
+ }\r
+ send_answer_chars('0', (output_error & (1<<rxbuf[2]))?'e':'0', \r
+ (output_enable & (1<<rxbuf[2]))?'1':'0'); \r
+ }\r
+ else {\r
+ forward_msg(4);\r
+ }\r
+ }\r
+ //Read current command\r
+ if (rxbuf[0] == 'C') { \r
+ rxcnt = 0;\r
+ if (ISMYADDR()) {\r
+ if (rxbuf[3] == '?')\r
+ send_answer_hex(adc[rxbuf[2]-'0']);\r
+ }\r
+ else {\r
+ forward_msg(4);\r
+ }\r
+ }\r
+ //Read current limit \r
+ if (rxbuf[0] == 'L' && rxbuf[3] == '?') {\r
+ rxcnt = 0;\r
+ if (ISMYADDR()) {\r
+ send_answer_hex(limit[rxbuf[2]-'0']); \r
+ }\r
+ else {\r
+ forward_msg(4);\r
+ }\r
+ } \r
+ }\r
+ //Set current limit\r
+ if (rxcnt == 6 && rxbuf[0] == 'L') {\r
+ rxcnt = 0;\r
+ if (ISMYADDR()) {\r
+ rxbuf[2] -= '0';\r
+ if(rxbuf[3] != '?') {\r
+ uint16_t lim = hex_to_int(rxbuf[3])*256 + hex_to_int(rxbuf[4])*16 + hex_to_int(rxbuf[5]);\r
+ limit[rxbuf[2]] = lim;\r
+ }\r
+ send_answer_hex(limit[rxbuf[2]]); \r
+ }\r
+ else {\r
+ forward_msg(6);\r
+ }\r
+ } \r
+ \r
+ if (rxcnt >= 6) { rxcnt = 0; } \r
+ \r
+} \r
+\r
+\r
+__attribute__((naked)) int main(void) {\r
+ // Configure ports\r
+ DDRA = 0b00101100; \r
+ DDRB = 0b00000000;\r
+ \r
+ PORTA = 0b00000000;\r
+ PORTB = 0b00000000;\r
+\r
+ PUEA = 0b01011100;\r
+ PUEB = 0b00001100; \r
+ \r
+ CLKPR = (0 << CLKPS0); // no prescaler \r
+ PRR = (1 << PRTWI) | (0 << PRUSART1) | (1 << PRUSART0) | (1 << PRSPI) \r
+ |(1 << PRTIM2) | (1 << PRTIM1) | (0 << PRTIM0) | (0 << PRADC); \r
+ \r
+ TCCR0B = (4 << CS00); //prescaler 256 -> 6M/256*256 = 91.5 Hz\r
+ TIMSK0 = (1 << TOIE0); //Overflow interrupt`\r
+ \r
+ ADMUXA = 1; //(1 (Out2),7 (Out1))\r
+ ADMUXB = (6 << REFS0); //2.2V reference, with capacitor\r
+ ADCSRA = (1 << ADEN) | (1 << ADSC) | (1 << ADIE) | (7 << ADPS0); //enable, start, irq, /128\r
+ ADCSRB = 0;\r
+ DIDR0 = (1<<ADC1D) | (1<< ADC7D); //disable digital inputs\r
+ \r
+ UCSR1A = (1 << U2X1);\r
+ UCSR1B = (1 << RXCIE1) | (0 << TXCIE1) | (1 << RXEN1) | (1 << TXEN1);\r
+ UCSR1C = (3 << UCSZ10); //8 Bit\r
+ UBRR1 = 0x26; //19200\r
+ \r
+ sei(); \r
+ while(1) {\r
+ \r
+ }\r
+ }
\ No newline at end of file