]> git.tdb.fi Git - model-railway-devices.git/blob - arducontrol/output.c
Rewrite ringbuffer implementation to be interrupt-safe
[model-railway-devices.git] / arducontrol / output.c
1 #include <avr/io.h>
2 #include "commands.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 OutputPacket packet;
11 uint8_t out_bit;
12 uint8_t out_time;
13 uint8_t out_data;
14 uint8_t delay_time;
15
16 void output_init(void)
17 {
18         DDRD = (DDRD&0xF3)|0x0C;
19         PORTD &= ~BIT(ENABLE);
20
21         timer_start_hz(2, 80000, 1);
22 }
23
24 void clear_packet(void)
25 {
26         packet.ready = 0;
27         packet.sending = 0;
28         packet.done = 0;
29 }
30
31 void output_set_power(uint8_t p)
32 {
33         if(p==POWER_ON)
34                 PORTD |= BIT(ENABLE);
35         else
36                 PORTD &= ~BIT(ENABLE);
37 }
38
39 uint8_t output_command(const uint8_t *cmd_buf, uint8_t cmd_length)
40 {
41         if(cmd_buf[0]==POWER_ON || cmd_buf[0]==POWER_OFF)
42         {
43                 if(cmd_length!=1)
44                         return LENGTH_ERROR;
45
46                 output_set_power(cmd_buf[0]==POWER_ON);
47         }
48         else
49                 return INVALID_COMMAND;
50
51         return COMMAND_OK;
52 }
53
54 static inline void output_tick(void)
55 {
56         if(delay_time && --delay_time)
57                 return;
58
59         if(out_time && !--out_time)
60         {
61                 ++out_bit;
62                 if(out_bit>=packet.length)
63                 {
64                         PORTD &= ~BIT(POLARITY);
65                         if(packet.repeat_count>1)
66                         {
67                                 if(packet.repeat_count<0xFF)
68                                         --packet.repeat_count;
69                                 delay_time = packet.repeat_delay;
70                                 packet.sending = 0;
71                         }
72                         else
73                         {
74                                 delay_time = packet.final_delay;
75                                 packet.done = 1;
76                         }
77                 }
78                 else
79                 {
80                         if((out_bit&7)==0)
81                                 out_data = packet.data[out_bit>>3];
82                         else
83                                 out_data >>= 1;
84
85                         if(out_data&1)
86                                 PORTD |= BIT(POLARITY);
87                         else
88                                 PORTD &= ~BIT(POLARITY);
89
90                         out_time = packet.bit_duration;
91                 }
92
93                 return;
94         }
95
96         if(packet.ready && !packet.sending)
97         {
98                 packet.sending = 1;
99                 out_bit = 0;
100                 out_time = packet.bit_duration;
101                 out_data = packet.data[0];
102                 if(out_data&1)
103                         PORTD |= BIT(POLARITY);
104                 else
105                         PORTD &= ~BIT(POLARITY);
106         }
107 }
108
109 TIMER_SET_CALLBACK(2, output_tick)