include ../common/build.mk
-arducontrol.elf: adc.o motorola.o packet.o serial.o timer.o
+arducontrol.elf: adc.o interface.o monitor.o motorola.o output.o serial.o timer.o
its data to the track can start.
*/
#include <avr/io.h>
-#include "adc.h"
-#include "commands.h"
-#include "motorola.h"
-#include "packet.h"
-#include "serial.h"
-#include "timer.h"
-
-Packet packet;
-uint8_t out_bit;
-uint8_t out_time;
-uint8_t out_data;
-uint8_t delay_time;
-
-volatile uint8_t recv_buf[32];
-uint8_t recv_head = 0;
-uint8_t recv_tail = 0;
-volatile uint8_t recv_fill = 0;
-volatile uint8_t recv_overrun = 0;
-uint8_t cmd_buf[15];
-uint8_t cmd_length;
-
-uint16_t track_current_samples[16] = { 0 };
-uint8_t track_current_head = 0;
-volatile uint16_t track_current_sum = 0;
-uint16_t overcurrent_limit = 1000<<4;
-uint8_t overcurrent_sent = 0;
-
-uint16_t input_voltage_samples[16] = { 0 };
-uint8_t input_voltage_head = 0;
-volatile uint16_t input_voltage_sum = 0;
-
-volatile uint8_t adc_state = 0;
-
-void process_commands();
-uint8_t process_command();
+#include <avr/interrupt.h>
+#include "interface.h"
+#include "monitor.h"
+#include "output.h"
int main()
{
- DDRD = 0x0E;
- PORTD = 0;
-
- serial_init(9600);
- timer_start_hz(0, 80000, 1);
- adc_init();
+ output_init();
+ interface_init();
+ monitor_init();
sei();
while(1)
{
- if(recv_overrun)
- {
- serial_write(0xFE);
- serial_write(RECEIVE_OVERRUN);
- recv_overrun = 0;
- }
- if(recv_fill>0)
- process_commands();
- if(!(adc_state&1))
- {
- ++adc_state;
- adc_read_async(adc_state>>1);
- }
- if(track_current_sum>overcurrent_limit)
- {
- PORTD &= ~0x08;
- if(!overcurrent_sent)
- {
- overcurrent_sent = 1;
- serial_write(0xFE);
- serial_write(OVERCURRENT);
- }
- }
- else
- overcurrent_sent = 0;
+ interface_check();
+ monitor_check();
}
return 0;
}
-
-static inline void receive(uint8_t c)
-{
- if(recv_fill>=sizeof(recv_buf))
- {
- recv_overrun = 1;
- return;
- }
-
- recv_buf[recv_head++] = c;
- if(recv_head>=sizeof(recv_buf))
- recv_head = 0;
- ++recv_fill;
-}
-
-SERIAL_SET_CALLBACK(receive)
-
-void process_commands()
-{
- while(recv_fill>0)
- {
- uint8_t consumed;
- uint8_t c = recv_buf[recv_tail];
-
- cmd_length = 0;
-
- if(c>=0xF0)
- {
- cmd_length = ~c;
- if(recv_fill<=cmd_length)
- break;
-
- uint8_t i, j;
- for(i=0, j=recv_tail+1; i<cmd_length; ++i, ++j)
- {
- if(j>=sizeof(recv_buf))
- j = 0;
- cmd_buf[i] = recv_buf[j];
- }
-
- consumed = 1+cmd_length;
- }
- else
- {
- serial_write(0xFE);
- serial_write(FRAMING_ERROR);
- consumed = 1;
- }
-
- recv_tail += consumed;
- if(recv_tail>=sizeof(recv_buf))
- recv_tail -= sizeof(recv_buf);
- recv_fill -= consumed;
-
- if(cmd_length>0)
- {
- uint8_t result = process_command();
- serial_write(0xFE);
- serial_write(result);
- }
- }
-}
-
-uint8_t process_command()
-{
- if(cmd_buf[0]==POWER_ON || cmd_buf[0]==POWER_OFF)
- {
- if(cmd_length!=1)
- return LENGTH_ERROR;
-
- if(cmd_buf[0]==POWER_ON)
- PORTD |= 0x08;
- else
- PORTD &= ~0x08;
- }
- else if(cmd_buf[0]==READ_TRACK_CURRENT)
- {
- if(cmd_length!=1)
- return LENGTH_ERROR;
-
- serial_write(0xFC);
- serial_write(TRACK_CURRENT);
- uint16_t value = track_current_sum>>4;
- serial_write(value>>8);
- serial_write(value);
- }
- else if(cmd_buf[0]==SET_OVERCURRENT_LIMIT)
- {
- if(cmd_length!=3)
- return LENGTH_ERROR;
-
- if(cmd_buf[1]&0xF0)
- return INVALID_VALUE;
-
- overcurrent_limit = (cmd_buf[1]<<12) | (cmd_buf[2]<<4);
- }
- else if(cmd_buf[0]==READ_INPUT_VOLTAGE)
- {
- if(cmd_length!=1)
- return LENGTH_ERROR;
-
- serial_write(0xFC);
- serial_write(INPUT_VOLTAGE);
- uint16_t value = (input_voltage_sum>>3)*5;
- serial_write(value>>8);
- serial_write(value);
- }
- else if(cmd_buf[0]==MOTOROLA_SPEED || cmd_buf[0]==MOTOROLA_SPEED_DIRECTION || cmd_buf[0]==MOTOROLA_SPEED_FUNCTION)
- {
- if(cmd_length!=4)
- return LENGTH_ERROR;
-
- uint8_t addr = cmd_buf[1];
- if(addr>80)
- return INVALID_VALUE;
-
- if(cmd_buf[2]&0x0E)
- return INVALID_VALUE;
- uint8_t aux = cmd_buf[2]&0x01;
-
- uint8_t func = (cmd_buf[2]&0xF0)>>4;
- if(cmd_buf[0]==MOTOROLA_SPEED_FUNCTION)
- {
- if(func<1 || func>4)
- return INVALID_VALUE;
- }
- else if(cmd_buf[2]&0xFE)
- return INVALID_VALUE;
- uint8_t state = cmd_buf[2]&0x02;
-
- uint8_t speed = cmd_buf[3]&0x7F;
- if(speed>14)
- return INVALID_VALUE;
-
- uint8_t dir = !(cmd_buf[3]&0x80);
-
- while(packet.ready && !packet.done) ;
-
- if(cmd_buf[0]==MOTOROLA_SPEED)
- motorola_locomotive_speed_packet(addr, aux, speed);
- else if(cmd_buf[0]==MOTOROLA_SPEED_DIRECTION)
- motorola_locomotive_speed_direction_packet(addr, aux, speed, dir);
- else if(cmd_buf[0]==MOTOROLA_SPEED_FUNCTION)
- motorola_locomotive_speed_function_packet(addr, aux, speed, func, state);
- }
- else if(cmd_buf[0]==MOTOROLA_REVERSE)
- {
- if(cmd_length!=3)
- return LENGTH_ERROR;
-
- uint8_t addr = cmd_buf[1];
- if(addr>80)
- return INVALID_VALUE;
-
- if(cmd_buf[2]&0xFE)
- return INVALID_VALUE;
- uint8_t aux = cmd_buf[2]&0x01;
-
- while(packet.ready && !packet.done) ;
-
- motorola_locomotive_reverse_packet(addr, aux);
- }
- else if(cmd_buf[0]==MOTOROLA_SOLENOID)
- {
- if(cmd_length!=3)
- return LENGTH_ERROR;
-
- uint8_t addr = cmd_buf[1];
- if(addr>80)
- return INVALID_VALUE;
-
- if(cmd_buf[2]&0x8E)
- return INVALID_VALUE;
- uint8_t output = (cmd_buf[2]&0x70)>>4;
- uint8_t state = cmd_buf[2]&1;
-
- while(packet.ready && !packet.done) ;
-
- motorola_solenoid_packet(addr, output, state);
- }
- else
- return INVALID_COMMAND;
-
- return COMMAND_OK;
-}
-
-static inline void tick()
-{
- if(delay_time && --delay_time)
- return;
-
- if(out_time && !--out_time)
- {
- ++out_bit;
- if(out_bit>=packet.length)
- {
- PORTD &= ~0x04;
- if(packet.repeat_count>1)
- {
- if(packet.repeat_count<0xFF)
- --packet.repeat_count;
- delay_time = packet.repeat_delay;
- packet.sending = 0;
- }
- else
- {
- delay_time = packet.final_delay;
- packet.done = 1;
- }
- }
- else
- {
- if((out_bit&7)==0)
- out_data = packet.data[out_bit>>3];
- else
- out_data >>= 1;
-
- if(out_data&1)
- PORTD |= 0x04;
- else
- PORTD &= ~0x04;
-
- out_time = packet.bit_duration;
- }
-
- return;
- }
-
- if(packet.ready && !packet.sending)
- {
- packet.sending = 1;
- out_bit = 0;
- out_time = packet.bit_duration;
- out_data = packet.data[0];
- if(out_data&1)
- PORTD |= 0x04;
- else
- PORTD &= ~0x04;
- }
-}
-
-TIMER_SET_CALLBACK(0, tick)
-
-static inline void adc_complete(uint16_t value)
-{
- if(adc_state==1)
- {
- // Convert to milliamps: (v*5/1024-2.5)*1000/0.185
- if(value<512) // Ignore negative current readings
- value = 0;
- else if(value>663) // Limit range so averaging won't overflow
- value = 4000;
- else
- value = (value-512)*132/5;
-
- uint8_t i = track_current_head;
- track_current_sum -= track_current_samples[i];
- track_current_samples[i] = value;
- track_current_sum += value;
- track_current_head = (i+1)&15;
- }
- else if(adc_state==3)
- {
- // Convert to centivolts: (v*5/1024)*100*11
- if(value>744) // Limit range so averaging won't overflow
- value = 4000;
- else
- value = value*43/8;
-
- uint8_t i = input_voltage_head;
- input_voltage_sum -= input_voltage_samples[i];
- input_voltage_samples[i] = value;
- input_voltage_sum += value;
- input_voltage_head = (i+1)&15;
- }
-
- ++adc_state;
-}
-
-ADC_SET_CALLBACK(adc_complete)
{
POWER_ON = 0x01,
POWER_OFF = 0x02,
- READ_TRACK_CURRENT = 0x03,
- SET_OVERCURRENT_LIMIT = 0x04,
- READ_INPUT_VOLTAGE = 0x05,
+ READ_TRACK_CURRENT = 0x08,
+ SET_OVERCURRENT_LIMIT = 0x09,
+ READ_INPUT_VOLTAGE = 0x0A,
MOTOROLA_SPEED = 0x11,
MOTOROLA_REVERSE = 0x12,
MOTOROLA_SPEED_DIRECTION = 0x13,
--- /dev/null
+#include "interface.h"
+#include "monitor.h"
+#include "motorola.h"
+#include "output.h"
+#include "serial.h"
+
+volatile uint8_t recv_buf[32];
+uint8_t recv_head = 0;
+uint8_t recv_tail = 0;
+volatile uint8_t recv_fill = 0;
+volatile uint8_t recv_overrun = 0;
+uint8_t cmd_buf[15];
+uint8_t cmd_length;
+
+void process_commands();
+uint8_t process_command();
+
+void interface_init()
+{
+ DDRD = (DDRD&0xFC)|0x02;
+
+ serial_init(9600);
+}
+
+void interface_check()
+{
+ if(recv_overrun)
+ {
+ serial_write(0xFE);
+ serial_write(RECEIVE_OVERRUN);
+ recv_overrun = 0;
+ }
+ if(recv_fill>0)
+ process_commands();
+}
+
+void process_commands()
+{
+ while(recv_fill>0)
+ {
+ uint8_t consumed;
+ uint8_t c = recv_buf[recv_tail];
+
+ cmd_length = 0;
+
+ if(c>=0xF0)
+ {
+ cmd_length = ~c;
+ if(recv_fill<=cmd_length)
+ break;
+
+ uint8_t i, j;
+ for(i=0, j=recv_tail+1; i<cmd_length; ++i, ++j)
+ {
+ if(j>=sizeof(recv_buf))
+ j = 0;
+ cmd_buf[i] = recv_buf[j];
+ }
+
+ consumed = 1+cmd_length;
+ }
+ else
+ {
+ serial_write(0xFE);
+ serial_write(FRAMING_ERROR);
+ consumed = 1;
+ }
+
+ recv_tail += consumed;
+ if(recv_tail>=sizeof(recv_buf))
+ recv_tail -= sizeof(recv_buf);
+ recv_fill -= consumed;
+
+ if(cmd_length>0)
+ {
+ uint8_t result = process_command();
+ serial_write(0xFE);
+ serial_write(result);
+ }
+ }
+}
+
+uint8_t process_command()
+{
+ uint8_t type = cmd_buf[0]>>4;
+ if(type==0)
+ {
+ uint8_t subtype = (cmd_buf[0]>>3)&1;
+ if(subtype==0)
+ return output_command();
+ else
+ return monitor_command();
+ }
+ else if(type==1)
+ return motorola_command();
+ else
+ return INVALID_COMMAND;
+}
+
+static inline void receive(uint8_t c)
+{
+ if(recv_fill>=sizeof(recv_buf))
+ {
+ recv_overrun = 1;
+ return;
+ }
+
+ recv_buf[recv_head++] = c;
+ if(recv_head>=sizeof(recv_buf))
+ recv_head = 0;
+ ++recv_fill;
+}
+
+SERIAL_SET_CALLBACK(receive)
--- /dev/null
+#ifndef COMMAND_H_
+#define COMMAND_H_
+
+#include <stdint.h>
+#include "commands.h"
+
+extern uint8_t cmd_buf[];
+extern uint8_t cmd_length;
+
+void interface_init();
+void interface_check();
+
+#endif
--- /dev/null
+#include "adc.h"
+#include "interface.h"
+#include "monitor.h"
+#include "output.h"
+#include "serial.h"
+
+uint16_t track_current_samples[16] = { 0 };
+uint8_t track_current_head = 0;
+volatile uint16_t track_current_sum = 0;
+uint16_t overcurrent_limit = 1000<<4;
+uint8_t overcurrent_sent = 0;
+
+uint16_t input_voltage_samples[16] = { 0 };
+uint8_t input_voltage_head = 0;
+volatile uint16_t input_voltage_sum = 0;
+
+volatile uint8_t adc_state = 0;
+
+void monitor_init()
+{
+ adc_init();
+}
+
+void monitor_check()
+{
+ if(!(adc_state&1))
+ {
+ ++adc_state;
+ adc_read_async(adc_state>>1);
+ }
+
+ if(track_current_sum>overcurrent_limit)
+ {
+ output_set_power(0);
+ if(!overcurrent_sent)
+ {
+ overcurrent_sent = 1;
+ serial_write(0xFE);
+ serial_write(OVERCURRENT);
+ }
+ }
+ else
+ overcurrent_sent = 0;
+}
+
+uint8_t monitor_command()
+{
+ if(cmd_buf[0]==READ_TRACK_CURRENT)
+ {
+ if(cmd_length!=1)
+ return LENGTH_ERROR;
+
+ serial_write(0xFC);
+ serial_write(TRACK_CURRENT);
+ uint16_t value = track_current_sum>>4;
+ serial_write(value>>8);
+ serial_write(value);
+ }
+ else if(cmd_buf[0]==SET_OVERCURRENT_LIMIT)
+ {
+ if(cmd_length!=3)
+ return LENGTH_ERROR;
+
+ if(cmd_buf[1]&0xF0)
+ return INVALID_VALUE;
+
+ overcurrent_limit = (cmd_buf[1]<<12) | (cmd_buf[2]<<4);
+ }
+ else if(cmd_buf[0]==READ_INPUT_VOLTAGE)
+ {
+ if(cmd_length!=1)
+ return LENGTH_ERROR;
+
+ serial_write(0xFC);
+ serial_write(INPUT_VOLTAGE);
+ uint16_t value = (input_voltage_sum>>3)*5;
+ serial_write(value>>8);
+ serial_write(value);
+ }
+ else
+ return INVALID_COMMAND;
+
+ return COMMAND_OK;
+}
+
+static inline void adc_complete(uint16_t value)
+{
+ if(adc_state==1)
+ {
+ // Convert to milliamps: (v*5/1024-2.5)*1000/0.185
+ if(value<512) // Ignore negative current readings
+ value = 0;
+ else if(value>663) // Limit range so averaging won't overflow
+ value = 4000;
+ else
+ value = (value-512)*132/5;
+
+ uint8_t i = track_current_head;
+ track_current_sum -= track_current_samples[i];
+ track_current_samples[i] = value;
+ track_current_sum += value;
+ track_current_head = (i+1)&15;
+ }
+ else if(adc_state==3)
+ {
+ // Convert to centivolts: (v*5/1024)*100*11
+ if(value>744) // Limit range so averaging won't overflow
+ value = 4000;
+ else
+ value = value*43/8;
+
+ uint8_t i = input_voltage_head;
+ input_voltage_sum -= input_voltage_samples[i];
+ input_voltage_samples[i] = value;
+ input_voltage_sum += value;
+ input_voltage_head = (i+1)&15;
+ }
+
+ ++adc_state;
+}
+
+ADC_SET_CALLBACK(adc_complete)
--- /dev/null
+#ifndef MONITOR_H_
+#define MONITOR_H_
+
+#include <stdint.h>
+
+void monitor_init();
+void monitor_check();
+uint8_t monitor_command();
+
+#endif
-#include "packet.h"
+#include "interface.h"
+#include "motorola.h"
+#include "output.h"
static uint8_t motorola_speed_to_value(uint8_t speed)
{
packet.ready = 1;
}
+
+uint8_t motorola_command()
+{
+ if(cmd_buf[0]==MOTOROLA_SPEED || cmd_buf[0]==MOTOROLA_SPEED_DIRECTION || cmd_buf[0]==MOTOROLA_SPEED_FUNCTION)
+ {
+ if(cmd_length!=4)
+ return LENGTH_ERROR;
+
+ uint8_t addr = cmd_buf[1];
+ if(addr>80)
+ return INVALID_VALUE;
+
+ if(cmd_buf[2]&0x0E)
+ return INVALID_VALUE;
+ uint8_t aux = cmd_buf[2]&0x01;
+
+ uint8_t func = (cmd_buf[2]&0xF0)>>4;
+ if(cmd_buf[0]==MOTOROLA_SPEED_FUNCTION)
+ {
+ if(func<1 || func>4)
+ return INVALID_VALUE;
+ }
+ else if(cmd_buf[2]&0xFE)
+ return INVALID_VALUE;
+ uint8_t state = cmd_buf[2]&0x02;
+
+ uint8_t speed = cmd_buf[3]&0x7F;
+ if(speed>14)
+ return INVALID_VALUE;
+
+ uint8_t dir = !(cmd_buf[3]&0x80);
+
+ while(packet.ready && !packet.done) ;
+
+ if(cmd_buf[0]==MOTOROLA_SPEED)
+ motorola_locomotive_speed_packet(addr, aux, speed);
+ else if(cmd_buf[0]==MOTOROLA_SPEED_DIRECTION)
+ motorola_locomotive_speed_direction_packet(addr, aux, speed, dir);
+ else if(cmd_buf[0]==MOTOROLA_SPEED_FUNCTION)
+ motorola_locomotive_speed_function_packet(addr, aux, speed, func, state);
+ }
+ else if(cmd_buf[0]==MOTOROLA_REVERSE)
+ {
+ if(cmd_length!=3)
+ return LENGTH_ERROR;
+
+ uint8_t addr = cmd_buf[1];
+ if(addr>80)
+ return INVALID_VALUE;
+
+ if(cmd_buf[2]&0xFE)
+ return INVALID_VALUE;
+ uint8_t aux = cmd_buf[2]&0x01;
+
+ while(packet.ready && !packet.done) ;
+
+ motorola_locomotive_reverse_packet(addr, aux);
+ }
+ else if(cmd_buf[0]==MOTOROLA_SOLENOID)
+ {
+ if(cmd_length!=3)
+ return LENGTH_ERROR;
+
+ uint8_t addr = cmd_buf[1];
+ if(addr>80)
+ return INVALID_VALUE;
+
+ if(cmd_buf[2]&0x8E)
+ return INVALID_VALUE;
+ uint8_t output = (cmd_buf[2]&0x70)>>4;
+ uint8_t state = cmd_buf[2]&1;
+
+ while(packet.ready && !packet.done) ;
+
+ motorola_solenoid_packet(addr, output, state);
+ }
+ else
+ return INVALID_COMMAND;
+
+ return COMMAND_OK;
+}
#ifndef MOTOROLA_H_
#define MOTOROLA_H_
+#include <stdint.h>
+
void motorola_locomotive_speed_packet(uint8_t, uint8_t, uint8_t);
void motorola_locomotive_reverse_packet(uint8_t, uint8_t);
void motorola_locomotive_speed_direction_packet(uint8_t, uint8_t, uint8_t, uint8_t);
void motorola_locomotive_speed_function_packet(uint8_t, uint8_t, uint8_t, uint8_t, uint8_t);
void motorola_solenoid_packet(uint8_t, uint8_t, uint8_t);
void motorola_set_repeat_count(uint8_t);
+uint8_t motorola_command();
#endif
--- /dev/null
+#include <avr/io.h>
+#include "interface.h"
+#include "output.h"
+#include "timer.h"
+
+OutputPacket packet;
+uint8_t out_bit;
+uint8_t out_time;
+uint8_t out_data;
+uint8_t delay_time;
+
+void output_init()
+{
+ DDRD = (DDRD&0xF3)|0x0C;
+ PORTD &= ~0x08;
+
+ timer_start_hz(0, 80000, 1);
+}
+
+void clear_packet()
+{
+ packet.ready = 0;
+ packet.sending = 0;
+ packet.done = 0;
+}
+
+void output_set_power(uint8_t p)
+{
+ if(p==POWER_ON)
+ PORTD |= 0x08;
+ else
+ PORTD &= ~0x08;
+}
+
+uint8_t output_command()
+{
+ if(cmd_buf[0]==POWER_ON || cmd_buf[0]==POWER_OFF)
+ {
+ if(cmd_length!=1)
+ return LENGTH_ERROR;
+
+ output_set_power(cmd_buf[0]==POWER_ON);
+ }
+ else
+ return INVALID_COMMAND;
+
+ return COMMAND_OK;
+}
+
+static inline void output_tick()
+{
+ if(delay_time && --delay_time)
+ return;
+
+ if(out_time && !--out_time)
+ {
+ ++out_bit;
+ if(out_bit>=packet.length)
+ {
+ PORTD &= ~0x04;
+ if(packet.repeat_count>1)
+ {
+ if(packet.repeat_count<0xFF)
+ --packet.repeat_count;
+ delay_time = packet.repeat_delay;
+ packet.sending = 0;
+ }
+ else
+ {
+ delay_time = packet.final_delay;
+ packet.done = 1;
+ }
+ }
+ else
+ {
+ if((out_bit&7)==0)
+ out_data = packet.data[out_bit>>3];
+ else
+ out_data >>= 1;
+
+ if(out_data&1)
+ PORTD |= 0x04;
+ else
+ PORTD &= ~0x04;
+
+ out_time = packet.bit_duration;
+ }
+
+ return;
+ }
+
+ if(packet.ready && !packet.sending)
+ {
+ packet.sending = 1;
+ out_bit = 0;
+ out_time = packet.bit_duration;
+ out_data = packet.data[0];
+ if(out_data&1)
+ PORTD |= 0x04;
+ else
+ PORTD &= ~0x04;
+ }
+}
+
+TIMER_SET_CALLBACK(0, output_tick)
--- /dev/null
+#ifndef PACKET_H_
+#define PACKET_H_
+
+#include <stdint.h>
+
+typedef struct
+{
+ uint8_t bit_duration:5;
+ uint8_t ready:1;
+ uint8_t sending:1;
+ volatile uint8_t done:1;
+ uint8_t length;
+ uint8_t data[32];
+ uint8_t repeat_count;
+ uint8_t repeat_delay;
+ uint8_t final_delay;
+} OutputPacket;
+
+extern OutputPacket packet;
+
+void output_init();
+void clear_packet();
+void output_set_power(uint8_t);
+uint8_t output_command();
+
+#endif
+++ /dev/null
-#include "packet.h"
-
-void clear_packet()
-{
- packet.ready = 0;
- packet.sending = 0;
- packet.done = 0;
-}
+++ /dev/null
-#ifndef PACKET_H_
-#define PACKET_H_
-
-#include <stdint.h>
-
-typedef struct
-{
- uint8_t bit_duration:5;
- uint8_t ready:1;
- uint8_t sending:1;
- volatile uint8_t done:1;
- uint8_t length;
- uint8_t data[32];
- uint8_t repeat_count;
- uint8_t repeat_delay;
- uint8_t final_delay;
-} Packet;
-
-extern Packet packet;
-
-void clear_packet();
-
-#endif