BeRTOS
thermo.c
Go to the documentation of this file.
00001 
00047 #include "hw/thermo_map.h"
00048 #include "hw/hw_thermo.h"
00049 
00050 #include "cfg/cfg_thermo.h"
00051 
00052 #include <cfg/module.h>
00053 #include <cfg/macros.h>
00054 #include <cfg/debug.h>
00055 // Define logging setting (for cfg/log.h module).
00056 #define LOG_LEVEL         CONFIG_THERMO_LOG_LEVEL
00057 #define LOG_VERBOSITY     CONFIG_THERMO_LOG_FORMAT
00058 #include <cfg/log.h>
00059 
00060 #include <drv/thermo.h>
00061 #include <drv/timer.h>
00062 #include <drv/ntc.h>
00063 
00064 #include <kern/proc.h>
00065 
00066 #define THERMO_OFF          0
00067 #define THERMO_HEATING      BV(0)
00068 #define THERMO_FREEZING     BV(1)
00069 #define THERMO_TGT_REACH    BV(2)
00070 #define THERMOERRF_NTCSHORT BV(3)
00071 #define THERMOERRF_NTCOPEN  BV(4)
00072 #define THERMOERRF_TIMEOUT  BV(5)
00073 #define THERMO_ACTIVE       BV(6)
00074 #define THERMO_TIMER        BV(7)
00075 
00076 #define THERMO_ERRMASK      (THERMOERRF_NTCSHORT | THERMOERRF_NTCOPEN | THERMOERRF_TIMEOUT)
00077 
00078 
00079 #if CONFIG_KERN
00080 
00081     static PROC_DEFINE_STACK(thermo_poll_stack, 400);
00082 #else
00083 
00084     static Timer thermo_timer;
00085 #endif
00086 
00087 typedef struct ThermoControlDev
00088 {
00089     deg_t          hifi_samples[CONFIG_THERMO_HIFI_NUM_SAMPLES];
00090     deg_t          cur_hifi_sample;
00091     deg_t          target;
00092     thermostatus_t status;
00093     ticks_t        expire;
00094     ticks_t        on_time;
00095 } ThermoControlDev;
00096 
00098 ThermoControlDev devs[THERMO_CNT];
00099 
00103 thermostatus_t thermo_status(ThermoDev dev)
00104 {
00105     ASSERT(dev < THERMO_CNT);
00106     return devs[dev].status;
00107 }
00108 
00109 
00113 static void thermo_do(ThermoDev index)
00114 {
00115     ThermoControlDev* dev = &devs[index];
00116     deg_t cur_temp;
00117     deg_t tolerance = thermo_hw_tolerance(index);
00118 
00119     cur_temp = thermo_hw_read(index);
00120 
00121     // Store the sample into the hifi FIFO buffer for later interpolation
00122     dev->hifi_samples[dev->cur_hifi_sample] = cur_temp;
00123     if (++dev->cur_hifi_sample == CONFIG_THERMO_HIFI_NUM_SAMPLES)
00124         dev->cur_hifi_sample = 0;
00125 
00126     cur_temp = thermo_readTemperature(index);
00127 
00128     if (cur_temp == NTC_SHORT_CIRCUIT || cur_temp == NTC_OPEN_CIRCUIT)
00129     {
00130         if (cur_temp == NTC_SHORT_CIRCUIT)
00131         {
00132             LOG_INFOB(if (!(dev->status & THERMOERRF_NTCSHORT))
00133                 LOG_INFO("dev[%d], thermo_do: NTC_SHORT\n",index););
00134 
00135             dev->status |= THERMOERRF_NTCSHORT;
00136         }
00137         else
00138         {
00139 
00140             LOG_INFOB(if (!(dev->status & THERMOERRF_NTCOPEN))
00141                 LOG_INFO("dev[%d], thermo_do: NTC_OPEN\n", index););
00142 
00143             dev->status |= THERMOERRF_NTCOPEN;
00144         }
00145 
00146         /* Reset timeout when there is an ntc error */
00147         dev->expire = thermo_hw_timeout(index) + timer_clock();
00148         thermo_hw_off(index);
00149         return;
00150     }
00151     dev->status &= ~(THERMOERRF_NTCOPEN | THERMOERRF_NTCSHORT);
00152 
00153     if ((cur_temp < dev->target - tolerance) || (cur_temp > dev->target + tolerance))
00154     {
00155         dev->status &= ~THERMO_TGT_REACH;
00156 
00157         /* Check for timeout */
00158         if (timer_clock() - dev->expire > 0)
00159         {
00160             dev->status |= THERMOERRF_TIMEOUT;
00161             LOG_INFO("dev[%d], thermo_do: TIMEOUT\n", index);
00162         }
00163     }
00164     else /* In target */
00165     {
00166         /* Clear errors */
00167         dev->status &= ~THERMO_ERRMASK;
00168         dev->status |= THERMO_TGT_REACH;
00169 
00170         /* Reset timeout in case we go out of target in the future */
00171         dev->expire = thermo_hw_timeout(index) + timer_clock();
00172     }
00173 
00174     if (cur_temp < dev->target)
00175         dev->status = (dev->status | THERMO_HEATING) & ~THERMO_FREEZING;
00176     else
00177         dev->status = (dev->status & ~THERMO_HEATING) | THERMO_FREEZING;
00178 
00179     thermo_hw_set(index, dev->target, cur_temp);
00180 
00181 }
00182 
00183 static void poll(void)
00184 {
00185     for (int i = 0; i < THERMO_CNT; ++i)
00186         if (devs[i].status & THERMO_ACTIVE)
00187         {
00188             LOG_INFO("THERMO [%d] on_time[%ld],\n", i, ticks_to_ms(devs[i].on_time));
00189             if ((devs[i].status & THERMO_TIMER) && (devs[i].on_time - timer_clock() < 0))
00190             {
00191                 thermo_stop(i);
00192                 continue;
00193             }
00194 
00195             thermo_do((ThermoDev)i);
00196         }
00197 }
00198 
00199 #if CONFIG_KERN
00200     static void NORETURN thermo_poll(void)
00201     {
00202         for (;;)
00203         {
00204             poll();
00205             timer_delay(CONFIG_THERMO_INTERVAL_MS);
00206         }
00207     }
00208 #else
00209 
00212     static void thermo_softint(void)
00213     {
00214         poll();
00215         timer_add(&thermo_timer);
00216     }
00217 #endif
00218 
00223 void thermo_timer(ThermoDev dev, mtime_t on_time)
00224 {
00225     ASSERT(dev < THERMO_CNT);
00226     devs[dev].on_time = timer_clock() + ms_to_ticks(on_time);
00227     devs[dev].status |= THERMO_TIMER;
00228     thermo_start(dev);
00229 }
00230 
00231 
00235 void thermo_setTarget(ThermoDev dev, deg_t temperature)
00236 {
00237     ASSERT(dev < THERMO_CNT);
00238     devs[dev].target = temperature;
00239     devs[dev].expire = timer_clock() + thermo_hw_timeout(dev);
00240 
00241     LOG_INFO("THERMO Set Target dev[%d], T[%d.%d]\n", dev, temperature / 10, temperature % 10);
00242 }
00243 
00247 void thermo_start(ThermoDev dev)
00248 {
00249     int i;
00250     deg_t temp;
00251 
00252     ASSERT(dev < THERMO_CNT);
00253 
00254     devs[dev].status |= THERMO_ACTIVE;
00255     LOG_INFO("THERMO Start dev[%d], status[%04x]\n", dev, devs[dev].status);
00256 
00257     /* Initialize the hifi FIFO with a constant value (the current temperature) */
00258     temp = thermo_hw_read(dev);
00259     for (i = 0; i < CONFIG_THERMO_HIFI_NUM_SAMPLES; ++i)
00260         devs[dev].hifi_samples[i] = temp;
00261     devs[dev].cur_hifi_sample = 0;
00262 
00263     /* Reset timeout */
00264     devs[dev].expire = timer_clock() + thermo_hw_timeout(dev);
00265 }
00266 
00270 void thermo_stop(ThermoDev dev)
00271 {
00272     ASSERT(dev < THERMO_CNT);
00273 
00274     devs[dev].status &= ~THERMO_ACTIVE;
00275     thermo_hw_off(dev);
00276 }
00277 
00278 
00282 void thermo_clearErrors(ThermoDev dev)
00283 {
00284     ASSERT(dev < THERMO_CNT);
00285     devs[dev].status &= ~(THERMO_ERRMASK);
00286 }
00287 
00288 
00292 deg_t thermo_readTemperature(ThermoDev dev)
00293 {
00294     int i;
00295     long accum = 0;
00296 
00297     MOD_CHECK(thermo);
00298 
00299     for (i = 0; i < CONFIG_THERMO_HIFI_NUM_SAMPLES; i++)
00300         accum += devs[dev].hifi_samples[i];
00301 
00302     return (deg_t)(accum / CONFIG_THERMO_HIFI_NUM_SAMPLES);
00303 }
00304 
00305 MOD_DEFINE(thermo)
00306 
00307 
00310 void thermo_init(void)
00311 {
00312     THERMO_HW_INIT;
00313 
00314     /* Set all status to off */
00315     for (int i = 0; i < THERMO_CNT; i++)
00316         devs[i].status = THERMO_OFF;
00317 
00318     MOD_INIT(thermo);
00319 
00320     #if CONFIG_KERN
00321         proc_new_with_name("Thermo", thermo_poll, NULL, sizeof(thermo_poll_stack), thermo_poll_stack);
00322     #else
00323         timer_setDelay(&thermo_timer, ms_to_ticks(CONFIG_THERMO_INTERVAL_MS));
00324         timer_setSoftint(&thermo_timer, (Hook)thermo_softint, 0);
00325         timer_add(&thermo_timer);
00326     #endif
00327 }