-
-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)