Import into DevLib.
authorbernie <bernie@38d2e660-2303-0410-9eaa-f027e97ec537>
Fri, 4 Nov 2005 18:00:42 +0000 (18:00 +0000)
committerbernie <bernie@38d2e660-2303-0410-9eaa-f027e97ec537>
Fri, 4 Nov 2005 18:00:42 +0000 (18:00 +0000)
git-svn-id: https://src.develer.com/svnoss/bertos/trunk@437 38d2e660-2303-0410-9eaa-f027e97ec537

drv/lcd_hd44.c [new file with mode: 0755]
drv/lcd_hd44.h [new file with mode: 0755]
drv/lcd_text.c [new file with mode: 0755]
drv/lcd_text.h [new file with mode: 0755]
drv/ntc.c [new file with mode: 0755]
drv/ntc.h [new file with mode: 0755]
drv/thermo.c [new file with mode: 0755]
drv/thermo.h [new file with mode: 0755]

diff --git a/drv/lcd_hd44.c b/drv/lcd_hd44.c
new file mode 100755 (executable)
index 0000000..ecfea36
--- /dev/null
@@ -0,0 +1,430 @@
+/*!
+ * \file
+ * <!--
+ * Copyright 2005 Develer S.r.l. (http://www.develer.com/)
+ * This file is part of DevLib - See README.devlib for information.
+ * -->
+ *
+ * \brief LM044L type LCD hardware module (impl.)
+ *
+ * \version $Id$
+ * \author Bernardo Innocenti <bernie@develer.com>
+ * \author Stefano Fedrigo <aleph@develer.com>
+ */
+
+/*#*
+ *#* $Log$
+ *#* Revision 1.1  2005/11/04 18:00:42  bernie
+ *#* Import into DevLib.
+ *#*
+ *#* Revision 1.2  2005/06/14 14:43:43  bernie
+ *#* Add DevLib headers.
+ *#*
+ *#* Revision 1.1  2005/05/24 09:17:58  batt
+ *#* Move drivers to top-level.
+ *#*
+ *#* Revision 1.9  2005/05/09 21:58:53  batt
+ *#* Fix doxygen tags.
+ *#*
+ *#* Revision 1.8  2005/05/09 12:52:46  batt
+ *#* lcd_dataRead(): Avoid bus collision; Add back *UNTESTED* 8bit bus support.
+ *#*
+ *#* Revision 1.7  2005/05/09 12:24:13  batt
+ *#* lcd_putc(): Fix latent bug; lcd_hw_init(): Extend timings.
+ *#*/
+
+#include "lcd_hd44.h"
+#include "lcd_bus_pz.h"
+#include <arch_config.h>
+#include <drv/timer.h>
+
+#if defined(LCD_READ_H) && defined(LCD_READ_L) && defined(LCD_WRITE_H) && defined(LCD_WRITE_L)
+       #define CONFIG_LCD_4BIT 1
+#elif defined(LCD_READ) && defined(LCD_WRITE)
+       #define CONFIG_LCD_4BIT 0
+#else
+       #error Incomplete or missing LCD_READ/LCD_WRITE macros
+#endif
+
+/*! Flag di stato del display */
+#define LCDF_BUSY  BV(7)
+
+/*!
+ * Addresses of LCD display character positions, expanded
+ * for faster access (DB7 = 1).
+ */
+static const uint8_t lcd_address[] =
+{
+       /* row 0 */
+       0x80, 0x81, 0x82, 0x83,
+       0x84, 0x85, 0x86, 0x87,
+       0x88, 0x89, 0x8A, 0x8B,
+       0x8C, 0x8D, 0x8E, 0x8F,
+#if LCD_COLS > 16
+       0x90, 0x91, 0x92, 0x93,
+#endif
+
+       /* row 1 */
+       0xC0, 0xC1, 0xC2, 0xC3,
+       0xC4, 0xC5, 0xC6, 0xC7,
+       0xC8, 0xC9, 0xCA, 0xCB,
+       0xCC, 0xCD, 0xCE, 0xCF,
+#if LCD_COLS > 16
+       0xD0, 0xD1, 0xD2, 0xD3,
+#endif
+
+#if LCD_ROWS > 2
+       /* row 2 */
+       0x94, 0x95, 0x96, 0x97,
+       0x98, 0x99, 0x9A, 0x9B,
+       0x9C, 0x9D, 0x9E, 0x9F,
+       0xA0, 0xA1, 0xA2, 0xA3,
+#if LCD_COLS > 16
+       0xA4, 0xA5, 0xA6, 0xA7,
+#endif
+
+       /* row 3 */
+       0xD4, 0xD5, 0xD6, 0xD7,
+       0xD8, 0xD9, 0xDA, 0xDB,
+       0xDC, 0xDD, 0xDE, 0xDF,
+       0xE0, 0xE1, 0xE2, 0xE3,
+#if LCD_COLS > 16
+       0xE4, 0xE5, 0xE6, 0xE7,
+#endif
+
+#endif /* LCD_ROWS > 2 */
+};
+
+STATIC_ASSERT(countof(lcd_address) == LCD_ROWS * LCD_COLS);
+
+/*!
+ * Current display position. We remember this to optimize
+ * LCD output by avoiding to set the address every time.
+ */
+static lcdpos_t lcd_current_addr;
+
+
+#if !defined(ARCH_EMUL) || !(ARCH & ARCH_EMUL)
+/*      __________________
+ * RS
+ *
+ * R/W  __________________
+ *            _______
+ * ENA  _____/       \____
+ *
+ * DATA -<================
+ */
+INLINE void lcd_dataWrite(uint8_t data)
+{
+#if CONFIG_LCD_4BIT
+       /* Write high nibble */
+       LCD_WRITE_H(data);
+       LCD_SET_E;
+       LCD_DELAY_WRITE;
+       LCD_CLR_E;
+       LCD_DELAY_WRITE;
+
+       /* Write low nibble */
+       LCD_WRITE_L(data);
+       LCD_SET_E;
+       LCD_DELAY_WRITE;
+       LCD_CLR_E;
+       LCD_DELAY_WRITE;
+
+#else /* !CONFIG_LCD_4BIT */
+
+       /* Write data */
+       LCD_WRITE(data);
+       LCD_SET_E;
+       LCD_DELAY_WRITE;
+       LCD_CLR_E;
+       LCD_DELAY_WRITE;
+
+#endif /* !CONFIG_LCD_4BIT */
+}
+
+/*      __________________
+ * RS
+ *         ____________
+ * R/W  __/            \__
+ *            _______
+ * ENA  _____/       \____
+ *        ______      ____
+ * DATA X/      \====/
+ */
+INLINE uint8_t lcd_dataRead(void)
+{
+       uint8_t data;
+
+       LCD_SET_RD;
+       LCD_DB_IN;      /* Set bus as input! */
+       LCD_DELAY_READ;
+
+#if CONFIG_LCD_4BIT
+
+       /* Read high nibble */
+       LCD_SET_E;
+       LCD_DELAY_READ;
+       data = LCD_READ_H;
+       LCD_CLR_E;
+       LCD_DELAY_READ;
+
+       /* Read low nibble */
+       LCD_SET_E;
+       LCD_DELAY_READ;
+       data |= LCD_READ_L;
+       LCD_CLR_E;
+       LCD_DELAY_READ;
+
+#else /* !CONFIG_LCD_4BIT */
+
+       /* Read data */
+       LCD_SET_E;
+       LCD_DELAY_READ;
+       data |= LCD_READ;
+       LCD_CLR_E;
+       LCD_DELAY_READ;
+
+#endif /* !CONFIG_LCD_4BIT */
+
+       LCD_CLR_RD;
+       LCD_DB_OUT;     /* Reset bus as output! */
+
+       return data;
+}
+
+/*      ___             __
+ * RS      \___________/
+ *
+ * READ __________________
+ *            _______
+ * ENA  _____/       \____
+ *
+ * DATA --<===============
+ */
+INLINE void lcd_regWrite(uint8_t data)
+{
+       LCD_CLR_RS;
+       lcd_dataWrite(data);
+       LCD_SET_RS;
+}
+
+/*      __               _
+ * RS     \_____________/
+ *          ___________
+ * READ ___/           \__
+ *            _______
+ * ENA  _____/       \____
+ *        ______      ____
+ * DATA X/      \====/
+ */
+INLINE uint8_t lcd_regRead(void)
+{
+       uint8_t data;
+
+       LCD_CLR_RS;
+       data = lcd_dataRead();
+       LCD_SET_RS;
+       return data;
+}
+
+#if CONFIG_LCD_4BIT
+
+INLINE void lcd_mode4Bit(void)
+{
+       LCD_CLR_RS;
+
+       LCD_WRITE_H(LCD_CMD_SETFUNC);
+       LCD_SET_E;
+       LCD_DELAY_WRITE;
+       LCD_CLR_E;
+       LCD_DELAY_WRITE;
+
+       LCD_SET_RS;
+}
+
+#endif /* CONFIG_LCD_4BIT */
+
+#else /* ARCH_EMUL */
+
+extern void Emul_LCDWriteReg(uint8_t d);
+extern uint8_t Emul_LCDReadReg(void);
+extern void Emul_LCDWriteData(uint8_t d);
+extern uint8_t Emul_LCDReadData(void);
+
+#define lcd_regWrite(d)   Emul_LCDWriteReg(d)
+#define lcd_regRead(d)    Emul_LCDReadReg()
+#define lcd_dataWrite(d)  Emul_LCDWriteData(d)
+#define lcd_dataRead(d)   Emul_LCDReadData()
+
+#endif /* ARCH_EMUL */
+
+
+/*!
+ * Wait until the LCD busy flag clears.
+ */
+void lcd_waitBusy(void)
+{
+       for (;;)
+       {
+               uint8_t val = lcd_regRead();
+               if (!(val & LCDF_BUSY))
+                       break;
+       }
+}
+
+
+/*!
+ * Move the cursor to \a addr, only if not already there.
+ */
+void lcd_moveTo(uint8_t addr)
+{
+       if (addr != lcd_current_addr)
+       {
+               lcd_waitBusy();
+               lcd_regWrite(lcd_address[addr]);
+               lcd_current_addr = addr;
+       }
+}
+
+
+/*!
+ * Write a value in LCD data register, waiting for the busy flag.
+ */
+void lcd_setReg(uint8_t val)
+{
+       lcd_waitBusy();
+       lcd_regWrite(val);
+}
+
+#include <cfg/debug.h>
+/*!
+ * Write the character \a c on display address \a addr.
+ *
+ * NOTE: argh, the HD44 lcd type is a bad beast: our
+ * move/write -> write optimization requires this mess
+ * because display lines are interleaved!
+ */
+void lcd_putc(uint8_t addr, uint8_t c)
+{
+       if (addr != lcd_current_addr)
+               lcd_setReg(lcd_address[addr]);
+
+       lcd_waitBusy();
+       lcd_dataWrite(c);
+       lcd_current_addr = addr + 1;
+
+       /* If we are at end of display wrap the address to 0 */
+       if (lcd_current_addr == LCD_COLS * LCD_ROWS)
+               lcd_current_addr = 0;
+
+       /* If we are at the end of a row put the cursor at the beginning of the next */
+       if (!(lcd_current_addr % LCD_COLS))
+               lcd_setReg(lcd_address[lcd_current_addr]);
+}
+
+
+/*!
+ * Remap the glyph of a character.
+ *
+ * glyph - bitmap of 8x8 bits.
+ * code - must be 0-7 for the Hitachi LCD-II controller.
+ */
+void lcd_remapChar(const char *glyph, char code)
+{
+       int i;
+
+       /* Set CG RAM address */
+       lcd_setReg((uint8_t)((1<<6) | (code << 3)));
+
+       /* Write bitmap data */
+       for (i = 0; i < 8; i++)
+       {
+               lcd_waitBusy();
+               lcd_dataWrite(glyph[i]);
+       }
+
+       /* Move back to original address */
+       lcd_setReg(lcd_address[lcd_current_addr]);
+}
+
+
+#if 0 /* unused */
+void lcd_remapfont(void)
+{
+       static const char lcd_glyphs[8] =
+       {
+               0x04, 0x0E, 0x15, 0x04, 0x04, 0x04, 0x04, 0x00 /* up arrow */
+       };
+       int i;
+
+       for (i = 0; i < 15; i++)
+               lcd_remapChar(i, bernie_char);
+
+
+       lcd_setAddr(lcd_DefLayer, 0);
+       for (i = 0; i < 80; i++)
+               lcd_putCharUnlocked(i);
+}
+#endif /* unused */
+
+void lcd_hw_init(void)
+{
+       lcd_bus_init();
+
+       timer_delay(50);
+
+#if CONFIG_LCD_4BIT
+       lcd_mode4Bit();
+       timer_delay(2);
+#endif /* CONFIG_LCD_4BIT */
+
+       lcd_regWrite(LCD_CMD_SETFUNC);
+       timer_delay(2);
+
+       lcd_regWrite(LCD_CMD_DISPLAY_ON);
+       timer_delay(2);
+
+       lcd_regWrite(LCD_CMD_CLEAR);
+       timer_delay(2);
+
+       //lcd_regWrite(LCD_CMD_RESET_DDRAM); 4 bit mode doesn't allow char reprogramming
+
+       lcd_regWrite(LCD_CMD_DISPLAYMODE);
+       timer_delay(2);
+}
+
+#if CONFIG_TEST
+
+void lcd_hw_test(void)
+{
+       lcd_regWrite(LCD_CMD_SET_DDRAMADDR | 3);
+       timer_delay(1);
+       kprintf("3 -> %02X\n", lcd_regRead());
+       timer_delay(1);
+
+       for (int i = 0; i < 10; i++)
+       {
+               lcd_dataWrite('c');
+               timer_delay(1);
+               kprintf("addr = %02X\n", lcd_regRead());
+               timer_delay(1);
+       }
+
+       lcd_regWrite(LCD_CMD_SET_DDRAMADDR | 0x4a);
+       timer_delay(1);
+       kprintf("4A -> %02X\n", lcd_regRead());
+       timer_delay(1);
+
+       lcd_regWrite(LCD_CMD_SET_DDRAMADDR | 0x52);
+       timer_delay(1);
+       kprintf("52 -> %02X\n", lcd_regRead());
+       timer_delay(1);
+
+       lcd_regWrite(LCD_CMD_SET_DDRAMADDR | 0x1F);
+       timer_delay(1);
+       kprintf("1F -> %02X\n", lcd_regRead());
+       timer_delay(1);
+}
+
+#endif /* CONFIG_TEST */
diff --git a/drv/lcd_hd44.h b/drv/lcd_hd44.h
new file mode 100755 (executable)
index 0000000..0413bed
--- /dev/null
@@ -0,0 +1,82 @@
+/*!
+ * \file
+ * <!--
+ * Copyright 2005 Develer S.r.l. (http://www.develer.com/)
+ * This file is part of DevLib - See README.devlib for information.
+ * -->
+ *
+ * \brief Hitachi HD44780 and clones LCD module (interface)
+ *
+ * \version $Id$
+ * \author Bernardo Innocenti <bernie@develer.com>
+ * \author Stefano Fedrigo <aleph@develer.com>
+ */
+
+/*#*
+ *#* $Log$
+ *#* Revision 1.1  2005/11/04 18:00:42  bernie
+ *#* Import into DevLib.
+ *#*
+ *#* Revision 1.2  2005/06/14 14:43:43  bernie
+ *#* Add DevLib headers.
+ *#*
+ *#* Revision 1.1  2005/05/24 09:17:58  batt
+ *#* Move drivers to top-level.
+ *#*
+ *#* Revision 1.3  2005/04/22 13:14:58  batt
+ *#* Better lcd rows and cols definition.
+ *#*
+ *#* Revision 1.2  2005/04/17 22:41:39  bernie
+ *#* lcd_test(): Rename to lcd_hw_test() and conditionalize on CONFIG_TEST.
+ *#*
+ *#* Revision 1.1  2005/04/16 19:48:35  aleph
+ *#* Rename lcd driver
+ *#*/
+
+#ifndef DRV_LCD_HD44_H
+#define DRV_LCD_HD44_H
+
+#include <cfg/compiler.h> /* For stdint types */
+
+/*!
+ * \name Display dimensions (in chars)
+ * \{
+ */
+#define LCD_ROWS  2
+#define LCD_COLS  16
+/* \} */
+
+/*!
+ * \name Hitachi HD44 commands.
+ * \{
+ */
+#define LCD_CMD_DISPLAY_INI      0x30
+//#define LCD_CMD_SETFUNC        0x38   /*!< 8 bits, 2 lines, 5x7 dots */
+#define LCD_CMD_SETFUNC          0x28   /*!< 4 bits, 2 lines, 5x7 dots */
+#define LCD_CMD_DISPLAY_ON       0x0F   /*!< Switch on display */
+#define LCD_CMD_DISPLAY_OFF      0x08   /*!< Switch off display */
+#define LCD_CMD_CLEAR            0x01   /*!< Clear display */
+#define LCD_CMD_CURSOR_BLOCK     0x0D   /*!< Show cursor (block) */
+#define LCD_CMD_CURSOR_LINE      0x0F   /*!< Show cursor (line) */
+#define LCD_CMD_CURSOR_OFF       0x0C   /*!< Hide cursor */
+#define LCD_CMD_DISPLAYMODE      0x06
+#define LCD_CMD_SET_CGRAMADDR    0x40
+#define LCD_CMD_RESET_DDRAM      0x80
+#define LCD_CMD_SET_DDRAMADDR    0x80
+#define LCD_CMD_DISPLAY_SHIFT    0x18
+#define LCD_CMD_MOVESHIFT_LEFT   0x00
+#define LCD_CMD_MOVESHIFT_RIGHT  0x04
+/*\}*/
+
+/*! Type for combined LCD cursor position (x,y). */
+typedef uint8_t lcdpos_t;
+
+void lcd_waitBusy(void);
+void lcd_moveTo(uint8_t addr);
+void lcd_setReg(uint8_t val);
+void lcd_putc(uint8_t a, uint8_t c);
+void lcd_remapChar(const char *glyph, char code);
+void lcd_hw_init(void);
+void lcd_hw_test(void);
+
+#endif /* DRV_LCD_HD44_H */
diff --git a/drv/lcd_text.c b/drv/lcd_text.c
new file mode 100755 (executable)
index 0000000..284c8b0
--- /dev/null
@@ -0,0 +1,464 @@
+/*!
+ * \file
+ * <!--
+ * Copyright 2005 Develer S.r.l. (http://www.develer.com/)
+ * This file is part of DevLib - See README.devlib for information.
+ * -->
+ *
+ * \brief Generic text LCD driver (impl.).
+ *
+ * \version $Id$
+ * \author Bernardo Innocenti <bernie@develer.com>
+ * \author Stefano Fedrigo <aleph@develer.com>
+ */
+
+/*#*
+ *#* $Log$
+ *#* Revision 1.1  2005/11/04 18:00:42  bernie
+ *#* Import into DevLib.
+ *#*
+ *#* Revision 1.11  2005/06/14 14:43:43  bernie
+ *#* Add DevLib headers.
+ *#*
+ *#* Revision 1.10  2005/06/06 17:41:57  batt
+ *#* Add lcd_layerSet function.
+ *#*
+ *#* Revision 1.9  2005/06/01 16:40:07  batt
+ *#* Remove debug string.
+ *#*
+ *#* Revision 1.8  2005/06/01 16:38:04  batt
+ *#* Adapt to changes in mware/list.h.
+ *#*
+ *#* Revision 1.7  2005/06/01 10:45:22  batt
+ *#* lcd_setAddr(): Bugfix boundary condition; Misc cleanup.
+ *#*
+ *#* Revision 1.6  2005/06/01 10:36:23  batt
+ *#* Layer: Rename member variables and Doxygenize.
+ *#*
+ *#* Revision 1.5  2005/05/27 11:05:58  batt
+ *#* Do not write on lcd if layer is hidden.
+ *#*/
+
+#include "lcd_text.h"
+#include "lcd_hd44.h"
+#include <drv/timer.h> // timer_delay()
+#include <mware/formatwr.h> // _formatted_write()
+#include <cfg/macros.h> // BV()
+#include <cfg/debug.h>
+
+#include <string.h> // strlen()
+
+
+/*! Maximum number of layers. */
+#define LCD_LAYERS 6
+
+#if CONFIG_KERNEL
+       /*! Semaphore to arbitrate access to the display. */
+       static struct Semaphore lcd_semaphore;
+       #define LOCK_LCD        sem_obtain(&lcd_semaphore)
+       #define UNLOCK_LCD      sem_release(&lcd_semaphore)
+#else /* !CONFIG_KERNEL */
+       #define LOCK_LCD        do {} while (0)
+       #define UNLOCK_LCD      do {} while (0)
+#endif /* !CONFIG_KERNEL */
+
+DECLARE_LIST_TYPE(Layer);
+
+Layer *lcd_DefLayer;
+static Layer lcd_LayersPool[LCD_LAYERS];
+static LIST_TYPE(Layer) lcd_Layers;
+static LIST_TYPE(Layer) lcd_FreeLayers;
+
+/*!
+ * Current cursor status.
+ *
+ * One of LCD_CMD_CURSOR_OFF, LCD_CMD_CURSOR_BLOCK or LCD_CMD_CURSOR_LINE.
+ */
+static uint8_t lcd_CursorStatus;
+
+/*! Current cursor position, encoded as a Cursor position and status. */
+static lcdpos_t lcd_CursorAddr;
+
+
+void lcd_setAddr(Layer *layer, lcdpos_t addr)
+{
+       /* Sanity check: wrap around to display limits */
+       while (addr >= LCD_ROWS * LCD_COLS)
+               addr -= LCD_ROWS * LCD_COLS;
+
+       layer->addr = addr;
+}
+
+#if CONFIG_KERNEL
+
+void lcd_lock(void)
+{
+       LOCK_LCD;
+}
+
+
+void lcd_unlock(void)
+{
+       UNLOCK_LCD;
+}
+
+#endif /* CONFIG_KERNEL */
+
+
+/*!
+ * Write one character to the display at the current
+ * cursor prosition, then move the cursor right. The
+ * cursor is wrapped to the next line when it moves
+ * beyond the end of the current line.
+ *
+ * \note Does _NOT_ lock the display semaphore.
+ */
+static void lcd_putCharUnlocked(char c, Layer *layer)
+{
+       Layer *l2;
+       lcdpos_t addr = layer->addr;
+
+       /* Store character in layer buffer */
+       layer->buf[addr] = c;
+
+       /* Move to next character */
+       if (++layer->addr >= LCD_COLS * LCD_ROWS)
+               layer->addr = 0;
+
+       /* Do not write on LCD if layer is hidden. */
+       if (layer->pri == LAYER_HIDDEN)
+               return;
+
+       /*
+        * Check if this location is obscured by
+        * other layers above us.
+        */
+       for (l2 = layer->pred; l2->pred; l2 = l2->pred)
+       {
+               if (l2->buf[addr])
+               {
+                       /* DB(kprintf("layer %04x obs %04x at %d\n", l2, layer, addr);) */
+                       return;
+               }
+       }
+
+       /* Write character */
+       if (c)
+               lcd_putc(addr, c);
+       else
+               /* FIXME: should look for layers beneath! */
+               lcd_putc(addr, ' ');
+}
+
+
+void lcd_putChar(char c, Layer *layer)
+{
+       LOCK_LCD;
+       lcd_putCharUnlocked(c, layer);
+       UNLOCK_LCD;
+}
+
+void lcd_layerSet(Layer *layer, char c)
+{
+       int i;
+
+       LOCK_LCD;
+       lcd_setAddr(layer, 0);
+       for (i = 0; i < LCD_COLS * LCD_ROWS; i++)
+               lcd_putCharUnlocked(c, layer);
+       UNLOCK_LCD;
+}
+
+
+void lcd_clear(Layer *layer)
+{
+       lcd_layerSet(layer, 0);
+}
+
+
+void lcd_clearLine(Layer *layer, int y)
+{
+       int i;
+
+       LOCK_LCD;
+       lcd_setAddr(layer, LCD_POS(0, y));
+       for (i = 0; i < LCD_COLS; i++)
+               lcd_putCharUnlocked(0, layer);
+       UNLOCK_LCD;
+}
+
+
+void lcd_moveCursor(lcdpos_t addr)
+{
+       LOCK_LCD;
+       lcd_moveTo(addr);
+       UNLOCK_LCD;
+}
+
+
+char lcd_setCursor(char mode)
+{
+       static const char cursor_cmd[3] =
+       {
+               LCD_CMD_CURSOR_OFF, LCD_CMD_CURSOR_BLOCK, LCD_CMD_CURSOR_LINE
+       };
+       char oldmode = lcd_CursorStatus;
+
+       LOCK_LCD;
+       lcd_CursorStatus = mode;
+       lcd_setReg(cursor_cmd[(int)mode]);
+       if (mode)
+               lcd_moveCursor(lcd_CursorAddr);
+       UNLOCK_LCD;
+
+       return oldmode;
+}
+
+
+int lcd_vprintf(Layer *layer, lcdpos_t addr, uint8_t mode, const char *format, va_list ap)
+{
+       int len;
+
+       LOCK_LCD;
+
+       /*
+        * Se il cursore era acceso, spegnilo durante
+        * l'output per evitare che salti alla posizione
+        * in cui si scrive.
+        */
+       if (lcd_CursorStatus)
+               lcd_setReg(LCD_CMD_CURSOR_OFF);
+
+       /* Spostamento del cursore */
+       lcd_setAddr(layer, addr);
+
+       if (mode & LCD_CENTER)
+       {
+               int pad;
+
+               /*
+                * NOTE: calculating the string lenght BEFORE it gets
+                * printf()-formatted. Real lenght may differ.
+                */
+               pad = (LCD_COLS - strlen(format)) / 2;
+               while (pad--)
+                       lcd_putCharUnlocked(' ', layer);
+       }
+
+       len = _formatted_write(format, (void (*)(char, void *))lcd_putCharUnlocked, layer, ap);
+
+       if (mode & (LCD_FILL | LCD_CENTER))
+               while (layer->addr % LCD_COLS)
+                       lcd_putCharUnlocked(' ', layer);
+
+       /*
+        * Riaccendi il cursore e riportalo alla
+        * vecchia posizione
+        */
+       if (lcd_CursorStatus)
+               lcd_setCursor(lcd_CursorStatus);
+
+       UNLOCK_LCD;
+
+       return len;
+}
+
+
+int lcd_printf(Layer *layer, lcdpos_t addr, uint8_t mode, const char *format, ...)
+{
+       int len;
+       va_list ap;
+
+       va_start(ap, format);
+       len = lcd_vprintf(layer, addr, mode, format, ap);
+       va_end(ap);
+
+       return len;
+}
+
+
+/*!
+ * Internal function to move a layer betweet two positions.
+ *
+ * \note The layer must be *already* enqueued in some list.
+ * \note The display must be already locked!
+ */
+static void lcd_enqueueLayer(Layer *layer, char pri)
+{
+       Layer *l2;
+
+       /* Remove layer from whatever list it was in before */
+       REMOVE(layer);
+
+       layer->pri = pri;
+
+       /*
+        * Search for the first layer whose priority
+        * is less or equal to the layer we are adding.
+        */
+       FOREACHNODE(l2, &lcd_Layers)
+               if (l2->pri <= pri)
+                       break;
+
+       /* Enqueue layer */
+       INSERTBEFORE(layer, l2);
+}
+
+Layer *lcd_newLayer(char pri)
+{
+       Layer *layer;
+
+       LOCK_LCD;
+
+       if (ISLISTEMPTY(&lcd_FreeLayers))
+       {
+               UNLOCK_LCD;
+               //ASSERT(false);
+               return NULL;
+       }
+
+       layer = (Layer *)LIST_HEAD(&lcd_FreeLayers);
+       layer->addr = 0;
+       memset(layer->buf, 0, LCD_ROWS * LCD_COLS);
+
+       lcd_enqueueLayer(layer, pri);
+
+       UNLOCK_LCD;
+       return layer;
+}
+
+/*!
+ * Redraw the display (internal).
+ *
+ * \note The display must be already locked.
+ */
+static void lcd_refresh(void)
+{
+       lcdpos_t addr;
+       Layer *l;
+
+       for (addr = 0; addr < LCD_ROWS * LCD_COLS; ++addr)
+       {
+               FOREACHNODE(l, &lcd_Layers)
+               {
+                       //kprintf("%d %x %p\n", addr, l->buf[0], l);
+                       if (l->pri == LAYER_HIDDEN)
+                               break;
+
+                       if (l->buf[addr])
+                       {
+                               /* Refresh location */
+                               lcd_putc(addr, l->buf[addr]);
+                               goto done;
+                       }
+               }
+
+               /* Draw background */
+               lcd_putc(addr, ' ');
+       done:
+               ;
+       }
+}
+
+/*!
+ * Rearrange layer depth and refresh display accordingly.
+ *
+ * \note Setting a priority of LAYER_HIDDEN makes the layer invisible.
+ */
+void lcd_setLayerDepth(Layer *layer, char pri)
+{
+       if (pri != layer->pri)
+       {
+               LOCK_LCD;
+               lcd_enqueueLayer(layer, pri);
+               /* Vile but simple */
+               lcd_refresh();
+               UNLOCK_LCD;
+       }
+}
+
+void lcd_deleteLayer(Layer *layer)
+{
+       LOCK_LCD;
+
+/* We use lcd_refresh() instead.  Much simpler than this mess, but slower. */
+#if 0
+       Layer *l2;
+       lcdpos_t addr;
+
+       /* Repair damage on underlaying layers */
+       for (addr = 0; addr < LCD_ROWS * LCD_COLS; ++addr)
+       {
+               /* If location was covered by us */
+               if (layer->buf[addr])
+               {
+                       /* ...and it wasn't covered by others above us... */
+                       for (l2 = layer->pred; l2->pred; l2 = l2->pred)
+                               if (l2->buf[addr])
+                                       /* can't just break here! */
+                                       goto not_visible;
+
+                       /* ...scan underlaying layers to repair damage */
+                       for (l2 = layer->succ; l2->succ; l2 = l2->succ)
+                               if (l2->buf[addr])
+                               {
+                                       /* Refresh character */
+                                       lcd_putc(addr, l2->buf[addr]);
+
+                                       /* No need to search on deeper layers */
+                                       break;
+                               }
+
+                       not_visible:
+                               ;
+               }
+       }
+#endif
+
+       // Remove layer from lcd_Layers list.
+       REMOVE(layer);
+
+       /* Put layer back into free list */
+       ADDHEAD(&lcd_FreeLayers, layer);
+
+       lcd_refresh();
+
+       UNLOCK_LCD;
+}
+
+
+static void lcd_setDefLayer(Layer *layer)
+{
+       lcd_DefLayer = layer;
+}
+
+#include <cfg/debug.h>
+void lcd_init(void)
+{
+       int i;
+
+       LIST_INIT(&lcd_Layers);
+       LIST_INIT(&lcd_FreeLayers);
+       for (i = 0; i < LCD_LAYERS; ++i)
+               ADDHEAD(&lcd_FreeLayers, &lcd_LayersPool[i]);
+
+       lcd_setDefLayer(lcd_newLayer(0));
+
+       lcd_hw_init();
+
+       lcd_setCursor(0);
+}
+
+#if CONFIG_TEST
+void lcd_test(void)
+{
+       int i;
+
+       for (i = 0; i < LCD_ROWS * LCD_COLS; ++i)
+       {
+               lcd_putCharUnlocked('0' + (i % 10), lcd_DefLayer);
+               timer_delay(100);
+       }
+}
+#endif /* CONFIG_TEST */
+
diff --git a/drv/lcd_text.h b/drv/lcd_text.h
new file mode 100755 (executable)
index 0000000..1a0ecae
--- /dev/null
@@ -0,0 +1,114 @@
+/*!
+ * \file
+ * <!--
+ * Copyright 2005 Develer S.r.l. (http://www.develer.com/)
+ * This file is part of DevLib - See README.devlib for information.
+ * -->
+ *
+ * \brief Generic text LCD driver (interface).
+ *
+ * \version $Id$
+ * \author Bernardo Innocenti <bernie@develer.com>
+ * \author Stefano Fedrigo <aleph@develer.com>
+ */
+
+/*#*
+ *#* $Log$
+ *#* Revision 1.1  2005/11/04 18:00:42  bernie
+ *#* Import into DevLib.
+ *#*
+ *#* Revision 1.5  2005/06/14 14:43:43  bernie
+ *#* Add DevLib headers.
+ *#*
+ *#* Revision 1.4  2005/06/06 17:41:57  batt
+ *#* Add lcd_layerSet function.
+ *#*
+ *#* Revision 1.3  2005/06/01 10:36:23  batt
+ *#* Layer: Rename member variables and Doxygenize.
+ *#*
+ *#* Revision 1.2  2005/05/26 08:31:23  batt
+ *#* Add layer hiding/showing.
+ *#*
+ *#* Revision 1.1  2005/05/24 09:17:58  batt
+ *#* Move drivers to top-level.
+ *#*/
+
+#ifndef DRV_LCD_H
+#define DRV_LCD_H
+
+#include "lcd_hd44.h"
+
+#include <cfg/macros.h>
+#include <cfg/compiler.h>
+#include <mware/list.h>
+
+#include <stdarg.h> // vprintf()
+
+
+/* flags for lcd_printf() */
+#define LCD_NORMAL     0       /* Scrittura normale */
+#define LCD_FILL       BV(0)   /* Fill rest of line with spaces */
+#define LCD_CENTER     BV(1)   /* Center string in line */
+#define LCD_NOCURSOR   BV(2)   /* Scrittura senza spostamento cursore */
+
+/*! Special priority value for lcd_setLayerDepth(). */
+#define LAYER_HIDDEN   -128
+
+/* Compute LCD address from x/y coordinates */
+#define LCD_POS(x,y)  ((lcdpos_t)((uint8_t)(x) + (uint8_t)(y) * (uint8_t)LCD_COLS))
+#define LCD_ROW0  (LCD_COLS * 0)
+#define LCD_ROW1  (LCD_COLS * 1)
+#define LCD_ROW2  (LCD_COLS * 2)
+#define LCD_ROW3  (LCD_COLS * 3)
+
+/*!
+ * Overwrapping layer context.
+ */
+typedef struct _Layer
+{
+       /*!
+        * Active layers are linked together in a list
+        * sorted in top to bottom order.
+        */
+       DECLARE_NODE_ANON(struct _Layer)
+
+       /*! Current XY address into this layer, for write operations. */
+       lcdpos_t addr;
+
+       /*! Priority of this layer (greater in front of lesser). */
+       char pri;
+
+       /*!
+        * Buffer per il salvataggio ed il ripristino del
+        * contenuto del display. Le posizioni che contengono
+        * il carattere '\0' sono trasparenti.
+        */
+       char buf[LCD_COLS * LCD_ROWS];
+} Layer;
+
+
+/* Global variables */
+extern Layer *lcd_DefLayer;
+
+/* Function prototypes */
+extern void lcd_init(void);
+extern void lcd_test(void);
+
+extern void lcd_moveCursor(lcdpos_t addr);
+extern char lcd_setCursor(char state);
+
+extern void lcd_setAddr(Layer *layer, lcdpos_t addr);
+extern void lcd_putChar(char c, Layer *layer);
+extern int  lcd_vprintf(Layer *layer, lcdpos_t addr, uint8_t mode, const char *format, va_list ap) FORMAT(printf, 4, 0);
+extern int  lcd_printf(Layer *layer, lcdpos_t addr, uint8_t mode, const char *format, ...) FORMAT(printf, 4, 5);
+extern void lcd_clear(Layer *layer);
+extern void lcd_layerSet(Layer *layer, char c);
+extern void lcd_clearLine(Layer *layer, int y);
+
+extern void lcd_setLayerDepth(Layer *layer, char pri);
+extern Layer *lcd_newLayer(char pri);
+extern void lcd_deleteLayer(Layer *layer);
+extern void lcd_lock(void);
+extern void lcd_unlock(void);
+
+#endif /* DRV_LCD_H */
diff --git a/drv/ntc.c b/drv/ntc.c
new file mode 100755 (executable)
index 0000000..5f02403
--- /dev/null
+++ b/drv/ntc.c
@@ -0,0 +1,133 @@
+/*!
+ * \file
+ * <!--
+ * Copyright 2004, 2005 Develer S.r.l. (http://www.de+veler.com/)
+ * All Rights Reserved.
+ * -->
+ *
+ * \brief Driver for NTC (reads a temperature through an ADC)
+ *
+ * \version $Id$
+ *
+ * \author Giovanni Bajo <rasky@develer.com>
+ * \author Francesco Sacchi <batt@develer.com>
+ *
+ *
+ * This module handles an external NTC bound to an AD converter. As usual,
+ * it relies on a low-level API (ntc_hw_*) (see below):
+ *
+ */
+
+/*#*
+ *#* $Log$
+ *#* Revision 1.1  2005/11/04 17:59:47  bernie
+ *#* Import into DevLib.
+ *#*
+ *#* Revision 1.1  2005/05/24 09:17:58  batt
+ *#* Move drivers to top-level.
+ *#*/
+
+#include <drv/ntc.h>
+#include <hw_ntc.h>
+#include <ntc_map.h>
+
+#include <cfg/debug.h>
+
+DB(bool ntc_initialized;)
+
+/*!
+ * Find in a table of values \a orig_table of size \a size, the index which
+ * value is less or equal to \a val.
+ *
+ * \retval 0 When \a val is higher than the first table entry.
+ * \retval size When \a val is lower than the last table entry.
+ * \retval 1..size-1 When \a val is within the table.
+ */
+static size_t upper_bound(const res_t *orig_table, size_t size, res_t val)
+{
+       const res_t *table = orig_table;
+
+       while (size)
+       {
+               size_t pos = size / 2;
+               if (val > table[pos])
+                       size = pos;
+               else
+               {
+                       table += pos+1;
+                       size -= pos+1;
+               }
+       }
+
+       return table - orig_table;
+}
+
+
+/*!
+ * Read the temperature for the NTC channel \a dev.
+ * First read the resistence of the NTC through ntc_hw_read(), then,
+ * for the conversion from resistance to temperature, since the formula
+ * varies from device to device, we implemented a generic system using
+ * a table of data which maps temperature (index) to resistance (data).
+ * The range of the table (min/max temperature) and the step
+ * (temperature difference between two consecutive elements of the table)
+ * is variable and can be specified. Notice that values inbetween the
+ * table elements are still possible as the library does a linear
+ * interpolation using the actual calculated resistance to find out
+ * the exact temperature.
+ *
+ * The low-level API provides a function to get access to a description
+ * of the NTC (ntc_hw_getInfo()), including the resistance table.
+ *
+ */
+deg_t ntc_read(NtcDev dev)
+{
+       const NtcHwInfo* hw = ntc_hw_getInfo(dev);
+       const res_t* r = hw->resistances;
+
+       float rx;
+       size_t i;
+       deg_t degrees;
+
+       rx = ntc_hw_read(dev);
+
+
+       i = upper_bound(r, hw->num_resistances, rx);
+       ASSERT(i <= hw->num_resistances);
+
+       if (i >= hw->num_resistances)
+               return NTC_SHORT_CIRCUIT;
+       else if (i == 0)
+               return NTC_OPEN_CIRCUIT;
+
+       /*
+        * Interpolated value in 0.1 degrees multiplied by 10:
+        *   delta t          step t
+        * ----------  = ----------------
+        * (rx - r[i])   (r[i-1] - r [i])
+        */
+       float tmp;
+       tmp = 10 * hw->degrees_step * (rx - r[i]) / (r[i - 1] - r[i]);
+
+       /*
+        * degrees = integer part corresponding to the superior index
+        *           in the table multiplied by 10
+        *           - decimal part interpolated (already multiplied by 10)
+        */
+       degrees = (i * hw->degrees_step + hw->degrees_min) * 10 - (int)(tmp);
+
+       //kprintf("dev= %d, I=%d, degrees = %d\n", dev, i , degrees);
+
+       return degrees;
+}
+
+
+/*!
+ * Init NTC hardware.
+ */
+void ntc_init(void)
+{
+       NTC_HW_INIT;
+       DB(ntc_initialized = true;)
+}
+
diff --git a/drv/ntc.h b/drv/ntc.h
new file mode 100755 (executable)
index 0000000..bf22136
--- /dev/null
+++ b/drv/ntc.h
@@ -0,0 +1,77 @@
+/*!
+ * \file
+ * <!--
+ * Copyright 2004, 2005 Develer S.r.l. (http://www.develer.com/)
+ * All Rights Reserved.
+ * -->
+ *
+ * \brief Driver for NTC (reads a temperature through an ADC)
+ *
+ * \version $Id$
+ *
+ * \author Giovanni Bajo <rasky@develer.com>
+ * \author Francesco Sacchi <batt@develer.com>
+ */
+
+/*#*
+ *#* $Log$
+ *#* Revision 1.1  2005/11/04 17:59:47  bernie
+ *#* Import into DevLib.
+ *#*
+ *#* Revision 1.3  2005/06/10 08:56:47  batt
+ *#* Avoid calling DEG_T_TO_DEG().
+ *#*
+ *#* Revision 1.2  2005/06/10 08:54:58  batt
+ *#* Rename deg_t conversion macros to accomplish coding standard.
+ *#*
+ *#* Revision 1.1  2005/05/24 09:17:58  batt
+ *#* Move drivers to top-level.
+ *#*/
+
+#ifndef DRV_NTC_H
+#define DRV_NTC_H
+
+#include <ntc_map.h>
+#include <cfg/debug.h>
+#include <cfg/compiler.h>
+
+#define NTC_OPEN_CIRCUIT  -32768
+#define NTC_SHORT_CIRCUIT 32767
+
+typedef int16_t  deg_t; /*! type for celsius degrees deg_t = °C * 10 */
+
+/*! Macro for converting from deg to deg_t type */
+#define DEG_TO_DEG_T(x)         ((deg_t)((x) * 10))
+
+/*! Macro for converting from deg_t to celsius degrees (returns only the integer part) */
+#define DEG_T_TO_INTDEG(x)      ((x) / 10)
+
+/*! Macro for converting from deg_t to celsius degrees (returns only the decimal part) */
+#define DEG_T_TO_DECIMALDEG(x)  ((x) % 10)
+
+/*! Macro for converting from deg_t to celsius degrees (returns type is float) */
+#define DEG_T_TO_FLOATDEG(x)    ((x) / 10.0)
+
+
+typedef uint32_t res_t; /*! type for resistor res_t = Ohm * 100 */
+typedef float    amp_t; /*! type for defining amplifications  amp_t = A, where A is a pure number */
+
+DB(extern bool ntc_initialized;)
+
+
+/*! Describe a NTC chip */
+typedef struct NtcHwInfo
+{
+       const res_t *resistances; //!< resistances of the NTC (ohms * 100)
+       size_t num_resistances;   //!< number of resistances
+       deg_t degrees_min;        //!< degrees corresponding to the first entry in the table (celsius * 10)
+       deg_t degrees_step;       //!< difference in degrees between two consecutive elements in the table (celsius * 10)
+} NtcHwInfo;
+
+/*! Initialize the NTC module */
+void ntc_init(void);
+
+/*! Read a single temperature value from the NTC */
+deg_t ntc_read(NtcDev dev);
+
+#endif /* DRV_NTC_H */
diff --git a/drv/thermo.c b/drv/thermo.c
new file mode 100755 (executable)
index 0000000..811ee25
--- /dev/null
@@ -0,0 +1,238 @@
+/*!
+ * \file
+ * <!--
+ * Copyright 2005 Develer S.r.l. (http://www.develer.com/)
+ * This file is part of DevLib - See README.devlib for information.
+ * -->
+ *
+ * \brief Thermo-control driver
+ *
+ * \version $Id$
+ *
+ * \author Giovanni Bajo <rasky@develer.com>
+ * \author Francesco Sacchi <batt@develer.com>
+ */
+
+/*#*
+ *#* $Log$
+ *#* Revision 1.1  2005/11/04 17:59:47  bernie
+ *#* Import into DevLib.
+ *#*
+ *#*/
+#include <thermo_map.h>
+#include <hw_thermo.h>
+
+#include <drv/thermo.h>
+#include <drv/timer.h>
+#include <drv/ntc.h>
+
+#include <cfg/macros.h>
+#include <cfg/debug.h>
+
+
+/*! Interval at which thermo control is performed. */
+#define THERMO_INTERVAL_MS      100
+
+/*! Number of different samples we interpolate over to get the hifi temperature. */
+#define THERMO_HIFI_NUM_SAMPLES 10
+
+/*! Timer for thermo-regulation. */
+static Timer thermo_timer;
+
+typedef struct ThermoControlDev
+{
+       deg_t          hifi_samples[THERMO_HIFI_NUM_SAMPLES];
+       deg_t          cur_hifi_sample;
+       deg_t          target;
+       thermostatus_t status;
+       ticks_t        expire;
+} ThermoControlDev;
+
+/*! Array of thermo-devices. */
+ThermoControlDev devs[THERMO_CNT];
+
+
+/*!
+ * Return the status of the specific \a dev thermo-device.
+ */
+thermostatus_t thermo_status(ThermoDev dev)
+{
+       return devs[dev].status;
+}
+
+
+/*!
+ * Do a single thermo control for device \a dev.
+ */
+static void thermo_do(ThermoDev index)
+{
+       ThermoControlDev* dev = &devs[index];
+       deg_t cur_temp;
+       deg_t tolerance = thermo_hw_tolerance(index);
+
+       cur_temp = thermo_hw_read(index);
+
+       // Store the sample into the hifi FIFO buffer for later interpolation
+       dev->hifi_samples[dev->cur_hifi_sample] = cur_temp;
+       if (++dev->cur_hifi_sample == THERMO_HIFI_NUM_SAMPLES)
+               dev->cur_hifi_sample = 0;
+
+       cur_temp = thermo_read_temperature(index);
+
+       if (cur_temp == NTC_SHORT_CIRCUIT || cur_temp == NTC_OPEN_CIRCUIT)
+       {
+               if (cur_temp == NTC_SHORT_CIRCUIT)
+               {
+                       #ifdef _DEBUG
+                       if (!(dev->status & THERMOERRF_NTCSHORT))
+                               kprintf("dev[%d], thermo_do: NTC_SHORT\n",index);
+                       #endif
+                       dev->status |= THERMOERRF_NTCSHORT;
+               }
+               else
+               {
+                       #ifdef _DEBUG
+                       if (!(dev->status & THERMOERRF_NTCOPEN))
+                               kprintf("dev[%d], thermo_do: NTC_OPEN\n", index);
+                       #endif
+                       dev->status |= THERMOERRF_NTCOPEN;
+               }
+
+               /* Reset timeout when there is an ntc error */
+               dev->expire = thermo_hw_timeout(index) + timer_clock();
+               thermo_hw_off(index);
+               return;
+       }
+       dev->status &= ~(THERMOERRF_NTCOPEN | THERMOERRF_NTCSHORT);
+
+       if ((cur_temp < dev->target - tolerance) || (cur_temp > dev->target + tolerance))
+       {
+               dev->status &= ~THERMO_TGT_REACH;
+
+               /* Check for timeout */
+               if (timer_clock() - dev->expire > 0)
+               {
+                       dev->status |= THERMOERRF_TIMEOUT;
+                       kprintf("dev[%d], thermo_do: TIMEOUT\n", index);
+               }
+       }
+       else /* In target */
+       {
+               /* Clear errors */
+               dev->status &= ~THERMO_ERRMASK;
+               dev->status |= THERMO_TGT_REACH;
+
+               /* Reset timeout in case we go out of target in the future */
+               dev->expire = thermo_hw_timeout(index) + timer_clock();
+       }
+
+       if (cur_temp < dev->target)
+               dev->status = (dev->status | THERMO_HEATING) & ~THERMO_FREEZING;
+       else
+               dev->status = (dev->status & ~THERMO_HEATING) | THERMO_FREEZING;
+
+       thermo_hw_set(index, dev->target, cur_temp);
+
+}
+
+
+/*!
+ * Thermo soft interrupt.
+ */
+static void thermo_softint(void)
+{
+       int i;
+       for (i = 0; i < THERMO_CNT; ++i)
+               if (devs[i].status & THERMO_ACTIVE)
+                       thermo_do((ThermoDev)i);
+
+       timer_add(&thermo_timer);
+}
+
+
+/*!
+ * Set the target temperature \a temperature for a specific \a dev thermo-device.
+ */
+void thermo_setTarget(ThermoDev dev, deg_t temperature)
+{
+       ASSERT(dev < THERMO_CNT);
+       devs[dev].target = temperature;
+       devs[dev].expire = timer_clock() + thermo_hw_timeout(dev);
+
+       kprintf("setTarget dev[%d], T[%d.%d]\n", dev, temperature / 10, temperature % 10);
+}
+
+/*!
+ * Starts a thermo-regulation for channel \a dev.
+ */
+void thermo_start(ThermoDev dev)
+{
+       int i;
+       deg_t temp;
+
+       ASSERT(dev < THERMO_CNT);
+
+       devs[dev].status |= THERMO_ACTIVE;
+
+       /* Initialize the hifi FIFO with a constant value (the current temperature) */
+       temp = thermo_hw_read(dev);
+       for (i = 0; i < THERMO_HIFI_NUM_SAMPLES; ++i)
+               devs[dev].hifi_samples[i] = temp;
+       devs[dev].cur_hifi_sample = 0;
+
+       /* Reset timeout */
+       devs[dev].expire = timer_clock() + thermo_hw_timeout(dev);
+}
+
+/*!
+ * Stops a thermo-regulation for channel \a dev.
+ */
+void thermo_stop(ThermoDev dev)
+{
+       ASSERT(dev < THERMO_CNT);
+
+       devs[dev].status &= ~THERMO_ACTIVE;
+       thermo_hw_off(dev);
+}
+
+
+/*!
+ * Clear errors for channel \a dev.
+ */
+void thermo_clearErrors(ThermoDev dev)
+{
+       ASSERT(dev < THERMO_CNT);
+       devs[dev].status &= ~(THERMO_ERRMASK);
+}
+
+
+/*!
+ * Read the temperature of the thermo-device \a dev using mobile mean.
+ */
+deg_t thermo_read_temperature(ThermoDev dev)
+{
+       int i;
+       long accum = 0;
+
+       for (i = 0; i < THERMO_HIFI_NUM_SAMPLES; i++)
+               accum += devs[dev].hifi_samples[i];
+
+       return (deg_t)(accum / THERMO_HIFI_NUM_SAMPLES);
+}
+
+
+/*!
+ * Init thermo-control and associated hw.
+ */
+void thermo_init(void)
+{
+       THERMO_HW_INIT;
+
+       /* Set all status to off */
+       for (int i = 0; i < THERMO_CNT; i++)
+               devs[i].status = THERMO_OFF;
+
+       timer_setDelay(&thermo_timer, ms_to_ticks(THERMO_INTERVAL_MS));
+       timer_set_event_softint(&thermo_timer, (Hook)thermo_softint, 0);
+       timer_add(&thermo_timer);
+}
diff --git a/drv/thermo.h b/drv/thermo.h
new file mode 100755 (executable)
index 0000000..361f966
--- /dev/null
@@ -0,0 +1,91 @@
+/*!
+ * \file
+ * <!--
+ * Copyright 2004, 2005 Develer S.r.l. (http://www.develer.com/)
+ * This file is part of DevLib - See README.devlib for information.
+ * -->
+ *
+ * \brief Thermo-control driver
+ *
+ * \version $Id$
+ *
+ * \author Giovanni Bajo <rasky@develer.com>
+ * \author Francesco Sacchi <batt@develer.com>
+ *
+ * This module implements multiple thermo controls, which is the logic needed to try
+ * keeping the temperature of a device constant. For this module, a "device" is a black box
+ * whose temperature can be measured, and which has a mean to make it hotter or colder.
+ * For instance, a device could be the combination of a NTC (analog temperature reader) and
+ * a Peltier connected to the same physic block.
+ *
+ * This module relies on a low-level driver to communicate with the device (implementation
+ * of the black box). This low-level driver also controls the units in which the temperature
+ * is expressed: thermo control treats it just as a number.
+ *
+ */
+
+/*#*
+ *#* $Log$
+ *#* Revision 1.1  2005/11/04 17:59:47  bernie
+ *#* Import into DevLib.
+ *#*
+ *#* Revision 1.2  2005/06/14 10:13:36  batt
+ *#* Better thermo errors handling.
+ *#*
+ *#* Revision 1.1  2005/05/24 09:17:58  batt
+ *#* Move drivers to top-level.
+ *#*
+ *#* Revision 1.4  2005/05/10 16:55:10  batt
+ *#* Add timeout to thermo-regulator; better thermo control handling; change thermo_getStatus() to thermo_status().
+ *#*
+ *#* Revision 1.3  2005/05/10 09:26:54  batt
+ *#* Add thermo_getStatus for getting status/errors of thermo control.
+ *#*
+ *#* Revision 1.2  2005/05/09 19:18:40  batt
+ *#* Remove old logs.
+ *#*
+ *#* Revision 1.1  2005/05/09 16:40:44  batt
+ *#* Add thermo-control driver
+ *#*/
+
+
+#ifndef DRV_THERMO_H
+#define DRV_THERMO_H
+
+#include <drv/ntc.h>
+#include <thermo_map.h>
+
+void thermo_init(void);
+
+
+/*!
+ * Set the target temperature at which a given device should be kept.
+ *
+ * \param dev Device
+ * \param temperature Target temperature
+ */
+void thermo_setTarget(ThermoDev dev, deg_t temperature);
+
+/*! Start thermo control for a certain device \a dev */
+void thermo_start(ThermoDev dev);
+
+/*! Stop thermo control for a certain device \a dev */
+void thermo_stop(ThermoDev dev);
+
+/*! Clear errors for channel \a dev */
+void thermo_clearErrors(ThermoDev dev);
+
+/*! Return the status of the specific \a dev thermo-device. */
+thermostatus_t thermo_status(ThermoDev dev);
+
+/*!
+ * Return the current temperature of a device currently under thermo
+ * control.
+ *
+ * \param dev Device
+ * \return Current temperature (Celsius degrees * 10)
+ */
+deg_t thermo_read_temperature(ThermoDev dev);
+
+
+#endif /* DRV_THERMO_H */