]> git.tdb.fi Git - model-railway-devices.git/blob - arducontrol/monitor.c
c3804fc5c5632f37b3941e9feff83994105f31ac
[model-railway-devices.git] / arducontrol / monitor.c
1 #include "adc.h"
2 #include "interface.h"
3 #include "monitor.h"
4 #include "output.h"
5 #include "serial.h"
6
7 static uint16_t track_current_samples[16] = { 0 };
8 static uint8_t track_current_head = 0;
9 static uint16_t track_current_sum = 0;
10 static uint16_t overcurrent_limit = 9707;
11 static uint8_t overcurrent_sent = 0;
12
13 static uint16_t input_voltage_samples[16] = { 0 };
14 static uint8_t input_voltage_head = 0;
15 static uint16_t input_voltage_sum = 0;
16
17 static volatile uint8_t adc_state = 0;
18 static volatile uint16_t adc_value = 0;
19
20 void monitor_init(void)
21 {
22         DDRB |= 0x02;
23         adc_init();
24 }
25
26 void monitor_check(void)
27 {
28         if(!(adc_state&1))
29         {
30                 uint16_t value = adc_value;
31
32                 if(adc_state==2)
33                 {
34                         uint8_t i = track_current_head;
35                         track_current_sum -= track_current_samples[i];
36                         track_current_samples[i] = value;
37                         track_current_sum += value;
38                         track_current_head = (i+1)&15;
39
40                         if(track_current_sum>overcurrent_limit)
41                         {
42                                 output_set_power(0);
43                                 PORTB |= 0x02;
44                                 if(!overcurrent_sent)
45                                 {
46                                         overcurrent_sent = 1;
47                                         interface_send1(OVERCURRENT);
48                                 }
49                         }
50                         else if(overcurrent_sent && output_is_power_on())
51                         {
52                                 PORTB &= ~0x02;
53                                 overcurrent_sent = 0;
54                         }
55                 }
56                 else if(adc_state==4)
57                 {
58                         uint8_t i = input_voltage_head;
59                         input_voltage_sum -= input_voltage_samples[i];
60                         input_voltage_samples[i] = value;
61                         input_voltage_sum += value;
62                         input_voltage_head = (i+1)&15;
63                 }
64
65                 adc_state = (adc_state+1)&3;
66                 adc_read_async(adc_state>>1);
67         }
68 }
69
70 uint8_t monitor_command(const uint8_t *cmd_buf, uint8_t cmd_length)
71 {
72         if(cmd_buf[0]==READ_TRACK_CURRENT)
73         {
74                 if(cmd_length!=1)
75                         return LENGTH_ERROR;
76
77                 uint16_t value = monitor_track_current();
78                 uint8_t reply[3];
79                 reply[0] = TRACK_CURRENT;
80                 reply[1] = value>>8;
81                 reply[2] = value;
82                 interface_send(reply, sizeof(reply));
83         }
84         else if(cmd_buf[0]==SET_OVERCURRENT_LIMIT)
85         {
86                 if(cmd_length!=3)
87                         return LENGTH_ERROR;
88
89                 uint16_t value = (cmd_buf[1]<<8) | cmd_buf[2];
90                 if(value>4000)  // Safe maximum value
91                         return INVALID_VALUE;
92
93                 // Convert from milliamps: (512+v/1000*0.185/5*1024)*16
94                 // multiply by 16384*0.185/5000 = 0.1001101100110b
95                 uint16_t v_3 = value*3;
96                 overcurrent_limit = 8192+(value>>1)+(v_3>>5)+(v_3>>8)+(v_3>>12);
97         }
98         else if(cmd_buf[0]==READ_INPUT_VOLTAGE)
99         {
100                 if(cmd_length!=1)
101                         return LENGTH_ERROR;
102
103                 uint16_t value = monitor_input_voltage();
104                 uint8_t reply[3];
105                 reply[0] = INPUT_VOLTAGE;
106                 reply[1] = value>>8;
107                 reply[2] = value;
108                 interface_send(reply, sizeof(reply));
109         }
110         else
111                 return INVALID_COMMAND;
112
113         return COMMAND_OK;
114 }
115
116 uint16_t monitor_track_current(void)
117 {
118         uint16_t value = track_current_sum;
119
120         // Convert to milliamps: (v/16*5/1024-2.5)*1000/0.185
121         if(value<8192)  // Ignore negative current readings
122                 return 0;
123         else
124         {
125                 value -= 8192;
126
127                 // multiply by 5000/0.185/16384 = 1.1010011001001b
128                 int16_t v_3 = value*3;
129                 return (v_3>>1)+(value>>3)+(v_3>>7)+(value>>10)+(v_3>>13);
130         }
131 }
132
133 uint16_t monitor_input_voltage(void)
134 {
135         uint16_t value = input_voltage_sum;
136
137         // Convert to millivolts: (v/16*5/1024)*1000*11
138         // multiply by 55000/16384 = 11.0101101101100b
139         uint16_t v_3 = value*3;
140         return v_3+(value>>2)+(v_3>>5)+(v_3>>8)+(v_3>>11);
141 }
142
143 static inline void adc_complete(uint16_t value)
144 {
145         adc_value = value;
146         ++adc_state;
147 }
148
149 ADC_SET_CALLBACK(adc_complete)