Convert to new Doxygen style.
[bertos.git] / drv / thermo.c
1 /**
2  * \file
3  * <!--
4  * Copyright 2005 Develer S.r.l. (http://www.develer.com/)
5  * This file is part of DevLib - See README.devlib for information.
6  * -->
7  *
8  * \brief Thermo-control driver
9  *
10  * \version $Id$
11  *
12  * \author Giovanni Bajo <rasky@develer.com>
13  * \author Francesco Sacchi <batt@develer.com>
14  */
15
16 /*#*
17  *#* $Log$
18  *#* Revision 1.2  2006/07/19 12:56:26  bernie
19  *#* Convert to new Doxygen style.
20  *#*
21  *#* Revision 1.1  2005/11/04 17:59:47  bernie
22  *#* Import into DevLib.
23  *#*
24  *#*/
25 #include <thermo_map.h>
26 #include <hw_thermo.h>
27
28 #include <drv/thermo.h>
29 #include <drv/timer.h>
30 #include <drv/ntc.h>
31
32 #include <cfg/macros.h>
33 #include <cfg/debug.h>
34
35
36 /** Interval at which thermo control is performed. */
37 #define THERMO_INTERVAL_MS      100
38
39 /** Number of different samples we interpolate over to get the hifi temperature. */
40 #define THERMO_HIFI_NUM_SAMPLES 10
41
42 /** Timer for thermo-regulation. */
43 static Timer thermo_timer;
44
45 typedef struct ThermoControlDev
46 {
47         deg_t          hifi_samples[THERMO_HIFI_NUM_SAMPLES];
48         deg_t          cur_hifi_sample;
49         deg_t          target;
50         thermostatus_t status;
51         ticks_t        expire;
52 } ThermoControlDev;
53
54 /** Array of thermo-devices. */
55 ThermoControlDev devs[THERMO_CNT];
56
57
58 /**
59  * Return the status of the specific \a dev thermo-device.
60  */
61 thermostatus_t thermo_status(ThermoDev dev)
62 {
63         return devs[dev].status;
64 }
65
66
67 /**
68  * Do a single thermo control for device \a dev.
69  */
70 static void thermo_do(ThermoDev index)
71 {
72         ThermoControlDev* dev = &devs[index];
73         deg_t cur_temp;
74         deg_t tolerance = thermo_hw_tolerance(index);
75
76         cur_temp = thermo_hw_read(index);
77
78         // Store the sample into the hifi FIFO buffer for later interpolation
79         dev->hifi_samples[dev->cur_hifi_sample] = cur_temp;
80         if (++dev->cur_hifi_sample == THERMO_HIFI_NUM_SAMPLES)
81                 dev->cur_hifi_sample = 0;
82
83         cur_temp = thermo_read_temperature(index);
84
85         if (cur_temp == NTC_SHORT_CIRCUIT || cur_temp == NTC_OPEN_CIRCUIT)
86         {
87                 if (cur_temp == NTC_SHORT_CIRCUIT)
88                 {
89                         #ifdef _DEBUG
90                         if (!(dev->status & THERMOERRF_NTCSHORT))
91                                 kprintf("dev[%d], thermo_do: NTC_SHORT\n",index);
92                         #endif
93                         dev->status |= THERMOERRF_NTCSHORT;
94                 }
95                 else
96                 {
97                         #ifdef _DEBUG
98                         if (!(dev->status & THERMOERRF_NTCOPEN))
99                                 kprintf("dev[%d], thermo_do: NTC_OPEN\n", index);
100                         #endif
101                         dev->status |= THERMOERRF_NTCOPEN;
102                 }
103
104                 /* Reset timeout when there is an ntc error */
105                 dev->expire = thermo_hw_timeout(index) + timer_clock();
106                 thermo_hw_off(index);
107                 return;
108         }
109         dev->status &= ~(THERMOERRF_NTCOPEN | THERMOERRF_NTCSHORT);
110
111         if ((cur_temp < dev->target - tolerance) || (cur_temp > dev->target + tolerance))
112         {
113                 dev->status &= ~THERMO_TGT_REACH;
114
115                 /* Check for timeout */
116                 if (timer_clock() - dev->expire > 0)
117                 {
118                         dev->status |= THERMOERRF_TIMEOUT;
119                         kprintf("dev[%d], thermo_do: TIMEOUT\n", index);
120                 }
121         }
122         else /* In target */
123         {
124                 /* Clear errors */
125                 dev->status &= ~THERMO_ERRMASK;
126                 dev->status |= THERMO_TGT_REACH;
127
128                 /* Reset timeout in case we go out of target in the future */
129                 dev->expire = thermo_hw_timeout(index) + timer_clock();
130         }
131
132         if (cur_temp < dev->target)
133                 dev->status = (dev->status | THERMO_HEATING) & ~THERMO_FREEZING;
134         else
135                 dev->status = (dev->status & ~THERMO_HEATING) | THERMO_FREEZING;
136
137         thermo_hw_set(index, dev->target, cur_temp);
138
139 }
140
141
142 /**
143  * Thermo soft interrupt.
144  */
145 static void thermo_softint(void)
146 {
147         int i;
148         for (i = 0; i < THERMO_CNT; ++i)
149                 if (devs[i].status & THERMO_ACTIVE)
150                         thermo_do((ThermoDev)i);
151
152         timer_add(&thermo_timer);
153 }
154
155
156 /**
157  * Set the target temperature \a temperature for a specific \a dev thermo-device.
158  */
159 void thermo_setTarget(ThermoDev dev, deg_t temperature)
160 {
161         ASSERT(dev < THERMO_CNT);
162         devs[dev].target = temperature;
163         devs[dev].expire = timer_clock() + thermo_hw_timeout(dev);
164
165         kprintf("setTarget dev[%d], T[%d.%d]\n", dev, temperature / 10, temperature % 10);
166 }
167
168 /**
169  * Starts a thermo-regulation for channel \a dev.
170  */
171 void thermo_start(ThermoDev dev)
172 {
173         int i;
174         deg_t temp;
175
176         ASSERT(dev < THERMO_CNT);
177
178         devs[dev].status |= THERMO_ACTIVE;
179
180         /* Initialize the hifi FIFO with a constant value (the current temperature) */
181         temp = thermo_hw_read(dev);
182         for (i = 0; i < THERMO_HIFI_NUM_SAMPLES; ++i)
183                 devs[dev].hifi_samples[i] = temp;
184         devs[dev].cur_hifi_sample = 0;
185
186         /* Reset timeout */
187         devs[dev].expire = timer_clock() + thermo_hw_timeout(dev);
188 }
189
190 /**
191  * Stops a thermo-regulation for channel \a dev.
192  */
193 void thermo_stop(ThermoDev dev)
194 {
195         ASSERT(dev < THERMO_CNT);
196
197         devs[dev].status &= ~THERMO_ACTIVE;
198         thermo_hw_off(dev);
199 }
200
201
202 /**
203  * Clear errors for channel \a dev.
204  */
205 void thermo_clearErrors(ThermoDev dev)
206 {
207         ASSERT(dev < THERMO_CNT);
208         devs[dev].status &= ~(THERMO_ERRMASK);
209 }
210
211
212 /**
213  * Read the temperature of the thermo-device \a dev using mobile mean.
214  */
215 deg_t thermo_read_temperature(ThermoDev dev)
216 {
217         int i;
218         long accum = 0;
219
220         for (i = 0; i < THERMO_HIFI_NUM_SAMPLES; i++)
221                 accum += devs[dev].hifi_samples[i];
222
223         return (deg_t)(accum / THERMO_HIFI_NUM_SAMPLES);
224 }
225
226
227 /**
228  * Init thermo-control and associated hw.
229  */
230 void thermo_init(void)
231 {
232         THERMO_HW_INIT;
233
234         /* Set all status to off */
235         for (int i = 0; i < THERMO_CNT; i++)
236                 devs[i].status = THERMO_OFF;
237
238         timer_setDelay(&thermo_timer, ms_to_ticks(THERMO_INTERVAL_MS));
239         timer_set_event_softint(&thermo_timer, (Hook)thermo_softint, 0);
240         timer_add(&thermo_timer);
241 }