fb8cbb7958ccda1bedc1a59444bcd58534118b18
[bertos.git] / drv / thermo.c
1 /**
2  * \file
3  * <!--
4  * This file is part of BeRTOS.
5  *
6  * Bertos is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19  *
20  * As a special exception, you may use this file as part of a free software
21  * library without restriction.  Specifically, if other files instantiate
22  * templates or use macros or inline functions from this file, or you compile
23  * this file and link it with other files to produce an executable, this
24  * file does not by itself cause the resulting executable to be covered by
25  * the GNU General Public License.  This exception does not however
26  * invalidate any other reasons why the executable file might be covered by
27  * the GNU General Public License.
28  *
29  * Copyright 2005 Develer S.r.l. (http://www.develer.com/)
30  *
31  * -->
32  *
33  * \brief Thermo-control driver
34  *
35  * \version $Id$
36  *
37  * \author Giovanni Bajo <rasky@develer.com>
38  * \author Francesco Sacchi <batt@develer.com>
39  */
40
41 /*#*
42  *#* $Log$
43  *#* Revision 1.3  2006/09/20 20:12:41  marco
44  *#* Names convention, MOD_* macros.
45  *#*
46  *#* Revision 1.2  2006/07/19 12:56:26  bernie
47  *#* Convert to new Doxygen style.
48  *#*
49  *#* Revision 1.1  2005/11/04 17:59:47  bernie
50  *#* Import into DevLib.
51  *#*
52  *#*/
53 #include <thermo_map.h>
54 #include <hw_thermo.h>
55
56 #include <drv/thermo.h>
57 #include <drv/timer.h>
58 #include <drv/ntc.h>
59
60 #include <cfg/macros.h>
61 #include <cfg/debug.h>
62
63
64 /** Interval at which thermo control is performed. */
65 #define THERMO_INTERVAL_MS      100
66
67 /** Number of different samples we interpolate over to get the hifi temperature. */
68 #define THERMO_HIFI_NUM_SAMPLES 10
69
70 /** Timer for thermo-regulation. */
71 static Timer thermo_timer;
72
73 typedef struct ThermoControlDev
74 {
75         deg_t          hifi_samples[THERMO_HIFI_NUM_SAMPLES];
76         deg_t          cur_hifi_sample;
77         deg_t          target;
78         thermostatus_t status;
79         ticks_t        expire;
80 } ThermoControlDev;
81
82 /** Array of thermo-devices. */
83 ThermoControlDev devs[THERMO_CNT];
84
85
86 /**
87  * Return the status of the specific \a dev thermo-device.
88  */
89 thermostatus_t thermo_status(ThermoDev dev)
90 {
91         return devs[dev].status;
92 }
93
94
95 /**
96  * Do a single thermo control for device \a dev.
97  */
98 static void thermo_do(ThermoDev index)
99 {
100         ThermoControlDev* dev = &devs[index];
101         deg_t cur_temp;
102         deg_t tolerance = thermo_hw_tolerance(index);
103
104         cur_temp = thermo_hw_read(index);
105
106         // Store the sample into the hifi FIFO buffer for later interpolation
107         dev->hifi_samples[dev->cur_hifi_sample] = cur_temp;
108         if (++dev->cur_hifi_sample == THERMO_HIFI_NUM_SAMPLES)
109                 dev->cur_hifi_sample = 0;
110
111         cur_temp = thermo_readTemperature(index);
112
113         if (cur_temp == NTC_SHORT_CIRCUIT || cur_temp == NTC_OPEN_CIRCUIT)
114         {
115                 if (cur_temp == NTC_SHORT_CIRCUIT)
116                 {
117                         #ifdef _DEBUG
118                         if (!(dev->status & THERMOERRF_NTCSHORT))
119                                 kprintf("dev[%d], thermo_do: NTC_SHORT\n",index);
120                         #endif
121                         dev->status |= THERMOERRF_NTCSHORT;
122                 }
123                 else
124                 {
125                         #ifdef _DEBUG
126                         if (!(dev->status & THERMOERRF_NTCOPEN))
127                                 kprintf("dev[%d], thermo_do: NTC_OPEN\n", index);
128                         #endif
129                         dev->status |= THERMOERRF_NTCOPEN;
130                 }
131
132                 /* Reset timeout when there is an ntc error */
133                 dev->expire = thermo_hw_timeout(index) + timer_clock();
134                 thermo_hw_off(index);
135                 return;
136         }
137         dev->status &= ~(THERMOERRF_NTCOPEN | THERMOERRF_NTCSHORT);
138
139         if ((cur_temp < dev->target - tolerance) || (cur_temp > dev->target + tolerance))
140         {
141                 dev->status &= ~THERMO_TGT_REACH;
142
143                 /* Check for timeout */
144                 if (timer_clock() - dev->expire > 0)
145                 {
146                         dev->status |= THERMOERRF_TIMEOUT;
147                         kprintf("dev[%d], thermo_do: TIMEOUT\n", index);
148                 }
149         }
150         else /* In target */
151         {
152                 /* Clear errors */
153                 dev->status &= ~THERMO_ERRMASK;
154                 dev->status |= THERMO_TGT_REACH;
155
156                 /* Reset timeout in case we go out of target in the future */
157                 dev->expire = thermo_hw_timeout(index) + timer_clock();
158         }
159
160         if (cur_temp < dev->target)
161                 dev->status = (dev->status | THERMO_HEATING) & ~THERMO_FREEZING;
162         else
163                 dev->status = (dev->status & ~THERMO_HEATING) | THERMO_FREEZING;
164
165         thermo_hw_set(index, dev->target, cur_temp);
166
167 }
168
169
170 /**
171  * Thermo soft interrupt.
172  */
173 static void thermo_softint(void)
174 {
175         int i;
176         for (i = 0; i < THERMO_CNT; ++i)
177                 if (devs[i].status & THERMO_ACTIVE)
178                         thermo_do((ThermoDev)i);
179
180         timer_add(&thermo_timer);
181 }
182
183
184 /**
185  * Set the target temperature \a temperature for a specific \a dev thermo-device.
186  */
187 void thermo_setTarget(ThermoDev dev, deg_t temperature)
188 {
189         ASSERT(dev < THERMO_CNT);
190         devs[dev].target = temperature;
191         devs[dev].expire = timer_clock() + thermo_hw_timeout(dev);
192
193         kprintf("setTarget dev[%d], T[%d.%d]\n", dev, temperature / 10, temperature % 10);
194 }
195
196 /**
197  * Starts a thermo-regulation for channel \a dev.
198  */
199 void thermo_start(ThermoDev dev)
200 {
201         int i;
202         deg_t temp;
203
204         ASSERT(dev < THERMO_CNT);
205
206         devs[dev].status |= THERMO_ACTIVE;
207
208         /* Initialize the hifi FIFO with a constant value (the current temperature) */
209         temp = thermo_hw_read(dev);
210         for (i = 0; i < THERMO_HIFI_NUM_SAMPLES; ++i)
211                 devs[dev].hifi_samples[i] = temp;
212         devs[dev].cur_hifi_sample = 0;
213
214         /* Reset timeout */
215         devs[dev].expire = timer_clock() + thermo_hw_timeout(dev);
216 }
217
218 /**
219  * Stops a thermo-regulation for channel \a dev.
220  */
221 void thermo_stop(ThermoDev dev)
222 {
223         ASSERT(dev < THERMO_CNT);
224
225         devs[dev].status &= ~THERMO_ACTIVE;
226         thermo_hw_off(dev);
227 }
228
229
230 /**
231  * Clear errors for channel \a dev.
232  */
233 void thermo_clearErrors(ThermoDev dev)
234 {
235         ASSERT(dev < THERMO_CNT);
236         devs[dev].status &= ~(THERMO_ERRMASK);
237 }
238
239
240 /**
241  * Read the temperature of the thermo-device \a dev using mobile mean.
242  */
243 deg_t thermo_readTemperature(ThermoDev dev)
244 {
245         int i;
246         long accum = 0;
247
248         MOD_CHECK(thermo);
249
250         for (i = 0; i < THERMO_HIFI_NUM_SAMPLES; i++)
251                 accum += devs[dev].hifi_samples[i];
252
253         return (deg_t)(accum / THERMO_HIFI_NUM_SAMPLES);
254 }
255
256 MOD_DEFINE(thermo)
257
258 /**
259  * Init thermo-control and associated hw.
260  */
261 void thermo_init(void)
262 {
263         THERMO_HW_INIT;
264
265         /* Set all status to off */
266         for (int i = 0; i < THERMO_CNT; i++)
267                 devs[i].status = THERMO_OFF;
268
269         MOD_INIT(thermo);
270
271         timer_setDelay(&thermo_timer, ms_to_ticks(THERMO_INTERVAL_MS));
272         timer_set_event_softint(&thermo_timer, (Hook)thermo_softint, 0);
273         timer_add(&thermo_timer);
274 }