]> git.tdb.fi Git - model-railway-devices.git/blob - arducontrol/output.c
Hide details of output packet lifecycle
[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 packet;
18 volatile uint8_t packet_state = IDLE;
19 static uint8_t out_bit;
20 static uint8_t out_time;
21 static uint8_t out_data;
22 static uint8_t delay_time;
23
24 void output_init(void)
25 {
26         DDRD = (DDRD&0xF3)|0x0C;
27         PORTD &= ~BIT(ENABLE);
28
29         timer_start_hz(2, 80000, 1);
30 }
31
32 OutputPacket *output_create_packet(void)
33 {
34         while(packet_state!=IDLE) ;
35         return &packet;
36 }
37
38 void output_send_packet(void)
39 {
40         if(packet_state!=IDLE)
41                 return;
42
43         packet_state = READY;
44 }
45
46 void output_set_power(uint8_t p)
47 {
48         if(p==POWER_ON)
49                 PORTD |= BIT(ENABLE);
50         else
51                 PORTD &= ~BIT(ENABLE);
52 }
53
54 uint8_t output_is_power_on()
55 {
56         return (PORTD&BIT(ENABLE))!=0;
57 }
58
59 uint8_t output_command(const uint8_t *cmd_buf, uint8_t cmd_length)
60 {
61         if(cmd_buf[0]==POWER_ON || cmd_buf[0]==POWER_OFF)
62         {
63                 if(cmd_length!=1)
64                         return LENGTH_ERROR;
65
66                 output_set_power(cmd_buf[0]==POWER_ON);
67         }
68         else if(cmd_buf[0]==READ_POWER_STATE)
69         {
70                 if(cmd_length!=1)
71                         return LENGTH_ERROR;
72
73                 uint8_t reply[2];
74                 reply[0] = POWER_STATE;
75                 reply[1] = output_is_power_on();
76                 interface_send(reply, 2);
77         }
78         else
79                 return INVALID_COMMAND;
80
81         return COMMAND_OK;
82 }
83
84 static inline void output_tick(void)
85 {
86         if(delay_time && --delay_time)
87                 return;
88
89         if(out_time && !--out_time)
90         {
91                 ++out_bit;
92                 if(out_bit>=packet.length)
93                 {
94                         PORTD &= ~BIT(POLARITY);
95                         if(packet.repeat_count>1)
96                         {
97                                 if(packet.repeat_count<0xFF)
98                                         --packet.repeat_count;
99                                 delay_time = packet.repeat_delay;
100                                 packet_state = READY;
101                         }
102                         else
103                         {
104                                 delay_time = packet.final_delay;
105                                 packet_state = IDLE;
106                         }
107                 }
108                 else
109                 {
110                         if((out_bit&7)==0)
111                                 out_data = packet.data[out_bit>>3];
112                         else
113                                 out_data >>= 1;
114
115                         if(out_data&1)
116                                 PORTD |= BIT(POLARITY);
117                         else
118                                 PORTD &= ~BIT(POLARITY);
119
120                         out_time = packet.bit_duration;
121                 }
122
123                 return;
124         }
125
126         if(packet_state==READY)
127         {
128                 packet_state = SENDING;
129                 out_bit = 0;
130                 out_time = packet.bit_duration;
131                 out_data = packet.data[0];
132                 if(out_data&1)
133                         PORTD |= BIT(POLARITY);
134                 else
135                         PORTD &= ~BIT(POLARITY);
136         }
137 }
138
139 TIMER_SET_CALLBACK(2, output_tick)