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