]> git.tdb.fi Git - model-railway-devices.git/blob - arducontrol/output.c
Support chaining packets to create a larger packet
[model-railway-devices.git] / arducontrol / output.c
1 #include <avr/io.h>
2 #include "interface.h"
3 #include "output.h"
4 #include "timer.h"
5
6 #define POLARITY PORTD2
7 #define ENABLE PORTD3
8 #define BIT(x) (1<<(x))
9
10 enum State
11 {
12         IDLE,
13         READY,
14         SENDING
15 };
16
17 OutputPacket packets[4];
18 uint8_t chain_length;
19 uint8_t current_packet;
20 volatile uint8_t packet_state = IDLE;
21 static uint8_t out_bit;
22 static uint8_t out_time;
23 static uint8_t out_data;
24 static uint8_t delay_time;
25
26 void output_init(void)
27 {
28         DDRD = (DDRD&0xF3)|0x0C;
29         PORTD &= ~BIT(ENABLE);
30
31         timer_start_hz(2, 80000, 1);
32 }
33
34 OutputPacket *output_create_packet(void)
35 {
36         while(packet_state!=IDLE) ;
37         chain_length = 1;
38         return &packets[0];
39 }
40
41 OutputPacket *output_create_chained_packet(void)
42 {
43         ++chain_length;
44         return &packets[chain_length-1];
45 }
46
47 void output_send_packet(void)
48 {
49         if(packet_state!=IDLE)
50                 return;
51
52         current_packet = 0;
53         packet_state = READY;
54 }
55
56 void output_set_power(uint8_t p)
57 {
58         if(p==POWER_ON)
59                 PORTD |= BIT(ENABLE);
60         else
61                 PORTD &= ~BIT(ENABLE);
62 }
63
64 uint8_t output_is_power_on()
65 {
66         return (PORTD&BIT(ENABLE))!=0;
67 }
68
69 uint8_t output_command(const uint8_t *cmd_buf, uint8_t cmd_length)
70 {
71         if(cmd_buf[0]==POWER_ON || cmd_buf[0]==POWER_OFF)
72         {
73                 if(cmd_length!=1)
74                         return LENGTH_ERROR;
75
76                 output_set_power(cmd_buf[0]==POWER_ON);
77         }
78         else if(cmd_buf[0]==READ_POWER_STATE)
79         {
80                 if(cmd_length!=1)
81                         return LENGTH_ERROR;
82
83                 uint8_t reply[2];
84                 reply[0] = POWER_STATE;
85                 reply[1] = output_is_power_on();
86                 interface_send(reply, 2);
87         }
88         else
89                 return INVALID_COMMAND;
90
91         return COMMAND_OK;
92 }
93
94 static inline void output_tick(void)
95 {
96         if(delay_time && --delay_time)
97                 return;
98
99         if(out_time && !--out_time)
100         {
101                 OutputPacket *packet = &packets[current_packet];
102                 ++out_bit;
103                 if(out_bit>=packet->length)
104                 {
105                         PORTD &= ~BIT(POLARITY);
106                         if(--packet->repeat_count)
107                         {
108                                 delay_time = packet->repeat_delay;
109                                 packet_state = READY;
110                         }
111                         else
112                         {
113                                 delay_time = packet->final_delay;
114                                 if(++current_packet<chain_length)
115                                         packet_state = READY;
116                                 else
117                                         packet_state = IDLE;
118                         }
119                 }
120                 else
121                 {
122                         if((out_bit&7)==0)
123                                 out_data = packet->data[out_bit>>3];
124                         else
125                                 out_data >>= 1;
126
127                         if(out_data&1)
128                                 PORTD |= BIT(POLARITY);
129                         else
130                                 PORTD &= ~BIT(POLARITY);
131
132                         out_time = packet->bit_duration;
133                 }
134
135                 return;
136         }
137
138         if(packet_state==READY)
139         {
140                 OutputPacket *packet = &packets[current_packet];
141                 packet_state = SENDING;
142                 out_bit = 0;
143                 out_time = packet->bit_duration;
144                 out_data = packet->data[0];
145                 if(out_data&1)
146                         PORTD |= BIT(POLARITY);
147                 else
148                         PORTD &= ~BIT(POLARITY);
149         }
150 }
151
152 TIMER_SET_CALLBACK(2, output_tick)