led.c 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328
  1. /*
  2. * Copyright (C) 2009 by Rittal GmbH & Co. KG,
  3. * Ulrich Prinz <prinz.u@rittal.de> All rights reserved.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions
  7. * are met:
  8. *
  9. * 1. Redistributions of source code must retain the above copyright
  10. * notice, this list of conditions and the following disclaimer.
  11. * 2. Redistributions in binary form must reproduce the above copyright
  12. * notice, this list of conditions and the following disclaimer in the
  13. * documentation and/or other materials provided with the distribution.
  14. * 3. Neither the name of the copyright holders nor the names of
  15. * contributors may be used to endorse or promote products derived
  16. * from this software without specific prior written permission.
  17. *
  18. * THIS SOFTWARE IS PROVIDED BY EMBEDDED IT AND CONTRIBUTORS
  19. * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  20. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  21. * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL EMBEDDED IT
  22. * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  23. * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  24. * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
  25. * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
  26. * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
  27. * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
  28. * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  29. *
  30. * For additional information see http://www.ethernut.de/
  31. *
  32. */
  33. /*!
  34. * \file dev/led.c
  35. * \brief LED driver and event handler.
  36. *
  37. * This device driver provieds flexible handling of multiple LEDs
  38. *
  39. * \verbatim
  40. * $Log$
  41. *
  42. * Revision 0.3 2009/09/17 ulrichprinz
  43. * Changed parameters and added more flexible functionalities by reducing
  44. * command tokens.
  45. * (currently SAM7X256 is tested only)
  46. *
  47. * Revision 0.2 2009/04/13 ulrichprinz
  48. * First checkin, led driver with extra functionality and variable io-access
  49. * (currently SAM7X256 is tested only)
  50. *
  51. * \endverbatim
  52. */
  53. #include <cfg/os.h>
  54. #include <compiler.h>
  55. #include <dev/board.h>
  56. #include <dev/gpio.h>
  57. #include <stdlib.h>
  58. #include <string.h>
  59. #include <sys/heap.h>
  60. #include <sys/event.h>
  61. #include <sys/timer.h>
  62. #include <sys/atom.h>
  63. #include <sys/nutdebug.h>
  64. #include <cfg/pca9555.h>
  65. #ifdef LED_SUPPORT_IOEXP
  66. #include <dev/pca9555.h>
  67. #endif
  68. #include "cfg/led.h"
  69. #include "dev/led.h"
  70. /*!
  71. * \addtogroup xgDevLED
  72. */
  73. /*@{*/
  74. /* define inverted LED states as LEDs are driven by low side switching */
  75. #ifdef LED_ON_HIGH
  76. #define LED_SET_ON 1
  77. #define LED_SET_OFF 0
  78. #else
  79. #define LED_SET_ON 0
  80. #define LED_SET_OFF 1
  81. #endif
  82. typedef struct
  83. {
  84. void *next; /**< Pointer to next LED descriptor. */
  85. uint32_t timOn; /**< Time the LED is on. */
  86. uint32_t timOff; /**< Time the LED is off. */
  87. uint32_t tim; /**< Internal current time of a LED */
  88. int bank; /**< Port where led is connected */
  89. int pin; /**< Pin on port, where led is connected */
  90. int state; /**< Current state */
  91. uint_fast8_t fx; /**< Selected function of led */
  92. } LEDEventT;
  93. /* Pointer to first led registered */
  94. LEDEventT *first_led = NULL;
  95. /* Timer- and Timer-Event-Handler */
  96. HANDLE led_tmr = NULL;
  97. HANDLE led_evt = NULL;
  98. /*!
  99. * \brief Configures LED connection port.
  100. *
  101. * This is an internal function called by NutRegisterLED().
  102. */
  103. int InitLED(LEDEventT *led)
  104. {
  105. #ifdef LED_SUPPORT_IOEXP
  106. if( led->bank >= IOXP_PORT0) {
  107. IOExpPinConfigSet(led->bank, led->pin, GPIO_CFG_OUTPUT);
  108. IOExpSetBitHigh( led->bank, led->pin);
  109. return 0;
  110. }
  111. else
  112. #else
  113. {
  114. GpioPinConfigSet( led->bank, led->pin, GPIO_CFG_OUTPUT);
  115. GpioPinSetHigh( led->bank, led->pin);
  116. return 0;
  117. }
  118. #endif
  119. return -1;
  120. }
  121. /*!
  122. * \brief Callback function for LED blink and flash timer.
  123. *
  124. * This is an internal function of the led driver.
  125. * It posts the event to the LED thread.
  126. *
  127. * \param timer Handle of the elapsed timeout timer.
  128. * \param arg Handle of an event queue.
  129. *
  130. */
  131. static void LedTimerCb(HANDLE timer, void *arg)
  132. {
  133. NutEventPostAsync( arg);
  134. }
  135. /*!
  136. * \brief Thread to control blinking and flashing of all registered LEDs.
  137. *
  138. * This is the internal LED handler thread. It si blocked by default, waiting
  139. * for a timer event to run.
  140. * The thread handles LED timing through reverse calculation of the actual
  141. * timeout. This uses mor system time, but makes blinking effects more smooth
  142. * even in situation where high priority tasks are delaying the timer interrupt
  143. * or this threadf to be executed.
  144. *
  145. * \param arg Handle of an event queue.
  146. *
  147. */
  148. /****************************************************************************/
  149. THREAD( sys_led, arg)
  150. /****************************************************************************/
  151. {
  152. LEDEventT *led;
  153. uint32_t now, last, dur;
  154. NUTASSERT( arg != NULL);
  155. last = NutGetMillis();
  156. NutThreadSetPriority(16);
  157. for(;;) {
  158. if (NutEventWait(arg, NUT_WAIT_INFINITE)==0) {
  159. now = NutGetMillis();
  160. dur = now-last;
  161. last = now;
  162. led = first_led;
  163. while( led)
  164. {
  165. switch( led->fx) {
  166. case LED_ON:
  167. if( led->timOn > 0) {
  168. if( led->tim >= dur) led->tim -= dur;
  169. else
  170. NutSetLed( led, LED_OFF, 0, 0);
  171. }
  172. break;
  173. case LED_OFF:
  174. if( led->timOff > 0) {
  175. if( led->tim >= dur) led->tim -= dur;
  176. else
  177. NutSetLed( led, LED_ON, 0, 0);
  178. }
  179. break;
  180. case LED_BLINK:
  181. if( led->tim >= dur) led->tim -= dur;
  182. else {
  183. NutSetLed( led, LED_FLIP, 0, 0);
  184. led->fx = LED_BLINK;
  185. if( led->state)
  186. led->tim = led->timOff;
  187. else
  188. led->tim = led->timOn;
  189. }
  190. break;
  191. }
  192. led = led->next;
  193. }
  194. }
  195. }
  196. }
  197. /*!
  198. * \brief sets state of a LED
  199. *
  200. * \param ledh The handle to the LED that should be controlled.
  201. * \param fxin Effect to set
  202. * \param timOn Duration of the LED's on-time of the effect given.
  203. * \param timOff Duration of the LED's off time of the effect given.
  204. *
  205. * \note Timeout is limited to the granularity of the system timer.
  206. */
  207. void NutSetLed( HANDLE ledh, uint_fast8_t fxin, uint32_t timOn, uint32_t timOff)
  208. {
  209. LEDEventT *led = (LEDEventT *)ledh;
  210. NUTASSERT( ledh != NULL);
  211. led->fx = fxin;
  212. switch( fxin) {
  213. case LED_BLINK:
  214. led->state ^= 1;
  215. led->timOn = timOn;
  216. led->timOff = timOff;
  217. if( led->state==LED_SET_ON)
  218. led->tim = timOff;
  219. else
  220. led->tim = timOn;
  221. break;
  222. case LED_FLIP:
  223. led->state ^= 1;
  224. break;
  225. case LED_ON:
  226. led->state = LED_SET_ON;
  227. led->timOn = led->tim = timOn;
  228. break;
  229. case LED_OFF:
  230. default:
  231. led->state = LED_SET_OFF;
  232. led->timOff = led->tim = timOff;
  233. break;
  234. }
  235. #ifdef LED_SUPPORT_IOEXP
  236. if( led->bank < IOXP_PORT0)
  237. GpioPinSet( led->bank, led->pin, led->state);
  238. else
  239. IOExpSetBit( led->bank, led->pin, led->state);
  240. #else
  241. GpioPinSet( led->bank, led->pin, led->state);
  242. #endif
  243. }
  244. /*!
  245. * \brief Register an LED for handling.
  246. *
  247. * Register a LED for beeing controlled by this driver. LED can then be
  248. * set by NutSetLed() by passing over the LEDs handler to that function.
  249. * Also LEDs connectd through external (I2C / SPI) port chips can be
  250. * driven, if the control for that chips is enabled in Nutconf.
  251. * The desired GPIO pin (internal or external) should be configured
  252. * correct before you can register a LED on it.
  253. *
  254. * \param ledh Pointer to a HANDLE for accessing the LED after registering.
  255. * \param bank Port of CPU or IO-Expander the LED is connected to.
  256. * \param pin Pin at the given port.
  257. *
  258. * \return -1 if registering failed, else 0.
  259. *
  260. */
  261. int NutRegisterLed( HANDLE * ledh, int bank, int pin)
  262. {
  263. LEDEventT *led;
  264. /* Check memory constraints and assign memory to new led struct */
  265. led = malloc(sizeof( LEDEventT));
  266. *ledh = (void*)led;
  267. if( led == NULL) {
  268. return -1;
  269. }
  270. /* Preset new led struct */
  271. memset( led, 0, sizeof( LEDEventT));
  272. led->bank = bank;
  273. led->pin = pin;
  274. led->state = LED_SET_OFF;
  275. /* Assign the led to the chain */
  276. NutEnterCritical();
  277. if( first_led == NULL) {
  278. /* it is the first led */
  279. first_led = led;
  280. }
  281. else {
  282. /* if not first, put it into the chain at first position */
  283. led->next = first_led;
  284. first_led = led;
  285. }
  286. NutExitCritical();
  287. /* Start timer for LED effects, but only one timer for all */
  288. if( led_tmr == NULL) {
  289. NutThreadCreate("sys_led", sys_led, &led_evt, 192);
  290. led_tmr = NutTimerStart(10, LedTimerCb, &led_evt, 0);
  291. }
  292. return InitLED( led);
  293. }
  294. /*@}*/