| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328 |
- /*
- * Copyright (C) 2009 by Rittal GmbH & Co. KG,
- * Ulrich Prinz <prinz.u@rittal.de> All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the copyright holders nor the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY EMBEDDED IT AND CONTRIBUTORS
- * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL EMBEDDED IT
- * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
- * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * For additional information see http://www.ethernut.de/
- *
- */
- /*!
- * \file dev/led.c
- * \brief LED driver and event handler.
- *
- * This device driver provieds flexible handling of multiple LEDs
- *
- * \verbatim
- * $Log$
- *
- * Revision 0.3 2009/09/17 ulrichprinz
- * Changed parameters and added more flexible functionalities by reducing
- * command tokens.
- * (currently SAM7X256 is tested only)
- *
- * Revision 0.2 2009/04/13 ulrichprinz
- * First checkin, led driver with extra functionality and variable io-access
- * (currently SAM7X256 is tested only)
- *
- * \endverbatim
- */
- #include <cfg/os.h>
- #include <compiler.h>
- #include <dev/board.h>
- #include <dev/gpio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <sys/heap.h>
- #include <sys/event.h>
- #include <sys/timer.h>
- #include <sys/atom.h>
- #include <sys/nutdebug.h>
- #include <cfg/pca9555.h>
- #ifdef LED_SUPPORT_IOEXP
- #include <dev/pca9555.h>
- #endif
- #include "cfg/led.h"
- #include "dev/led.h"
- /*!
- * \addtogroup xgDevLED
- */
- /*@{*/
- /* define inverted LED states as LEDs are driven by low side switching */
- #ifdef LED_ON_HIGH
- #define LED_SET_ON 1
- #define LED_SET_OFF 0
- #else
- #define LED_SET_ON 0
- #define LED_SET_OFF 1
- #endif
- typedef struct
- {
- void *next; /**< Pointer to next LED descriptor. */
- uint32_t timOn; /**< Time the LED is on. */
- uint32_t timOff; /**< Time the LED is off. */
- uint32_t tim; /**< Internal current time of a LED */
- int bank; /**< Port where led is connected */
- int pin; /**< Pin on port, where led is connected */
- int state; /**< Current state */
- uint_fast8_t fx; /**< Selected function of led */
- } LEDEventT;
- /* Pointer to first led registered */
- LEDEventT *first_led = NULL;
- /* Timer- and Timer-Event-Handler */
- HANDLE led_tmr = NULL;
- HANDLE led_evt = NULL;
- /*!
- * \brief Configures LED connection port.
- *
- * This is an internal function called by NutRegisterLED().
- */
- int InitLED(LEDEventT *led)
- {
- #ifdef LED_SUPPORT_IOEXP
- if( led->bank >= IOXP_PORT0) {
- IOExpPinConfigSet(led->bank, led->pin, GPIO_CFG_OUTPUT);
- IOExpSetBitHigh( led->bank, led->pin);
- return 0;
- }
- else
- #else
- {
- GpioPinConfigSet( led->bank, led->pin, GPIO_CFG_OUTPUT);
- GpioPinSetHigh( led->bank, led->pin);
- return 0;
- }
- #endif
- return -1;
- }
- /*!
- * \brief Callback function for LED blink and flash timer.
- *
- * This is an internal function of the led driver.
- * It posts the event to the LED thread.
- *
- * \param timer Handle of the elapsed timeout timer.
- * \param arg Handle of an event queue.
- *
- */
- static void LedTimerCb(HANDLE timer, void *arg)
- {
- NutEventPostAsync( arg);
- }
- /*!
- * \brief Thread to control blinking and flashing of all registered LEDs.
- *
- * This is the internal LED handler thread. It si blocked by default, waiting
- * for a timer event to run.
- * The thread handles LED timing through reverse calculation of the actual
- * timeout. This uses mor system time, but makes blinking effects more smooth
- * even in situation where high priority tasks are delaying the timer interrupt
- * or this threadf to be executed.
- *
- * \param arg Handle of an event queue.
- *
- */
- /****************************************************************************/
- THREAD( sys_led, arg)
- /****************************************************************************/
- {
- LEDEventT *led;
- uint32_t now, last, dur;
- NUTASSERT( arg != NULL);
- last = NutGetMillis();
- NutThreadSetPriority(16);
- for(;;) {
- if (NutEventWait(arg, NUT_WAIT_INFINITE)==0) {
- now = NutGetMillis();
- dur = now-last;
- last = now;
- led = first_led;
- while( led)
- {
- switch( led->fx) {
- case LED_ON:
- if( led->timOn > 0) {
- if( led->tim >= dur) led->tim -= dur;
- else
- NutSetLed( led, LED_OFF, 0, 0);
- }
- break;
- case LED_OFF:
- if( led->timOff > 0) {
- if( led->tim >= dur) led->tim -= dur;
- else
- NutSetLed( led, LED_ON, 0, 0);
- }
- break;
- case LED_BLINK:
- if( led->tim >= dur) led->tim -= dur;
- else {
- NutSetLed( led, LED_FLIP, 0, 0);
- led->fx = LED_BLINK;
- if( led->state)
- led->tim = led->timOff;
- else
- led->tim = led->timOn;
- }
- break;
- }
- led = led->next;
- }
- }
- }
- }
- /*!
- * \brief sets state of a LED
- *
- * \param ledh The handle to the LED that should be controlled.
- * \param fxin Effect to set
- * \param timOn Duration of the LED's on-time of the effect given.
- * \param timOff Duration of the LED's off time of the effect given.
- *
- * \note Timeout is limited to the granularity of the system timer.
- */
- void NutSetLed( HANDLE ledh, uint_fast8_t fxin, uint32_t timOn, uint32_t timOff)
- {
- LEDEventT *led = (LEDEventT *)ledh;
- NUTASSERT( ledh != NULL);
- led->fx = fxin;
- switch( fxin) {
- case LED_BLINK:
- led->state ^= 1;
- led->timOn = timOn;
- led->timOff = timOff;
- if( led->state==LED_SET_ON)
- led->tim = timOff;
- else
- led->tim = timOn;
- break;
- case LED_FLIP:
- led->state ^= 1;
- break;
- case LED_ON:
- led->state = LED_SET_ON;
- led->timOn = led->tim = timOn;
- break;
- case LED_OFF:
- default:
- led->state = LED_SET_OFF;
- led->timOff = led->tim = timOff;
- break;
- }
- #ifdef LED_SUPPORT_IOEXP
- if( led->bank < IOXP_PORT0)
- GpioPinSet( led->bank, led->pin, led->state);
- else
- IOExpSetBit( led->bank, led->pin, led->state);
- #else
- GpioPinSet( led->bank, led->pin, led->state);
- #endif
- }
- /*!
- * \brief Register an LED for handling.
- *
- * Register a LED for beeing controlled by this driver. LED can then be
- * set by NutSetLed() by passing over the LEDs handler to that function.
- * Also LEDs connectd through external (I2C / SPI) port chips can be
- * driven, if the control for that chips is enabled in Nutconf.
- * The desired GPIO pin (internal or external) should be configured
- * correct before you can register a LED on it.
- *
- * \param ledh Pointer to a HANDLE for accessing the LED after registering.
- * \param bank Port of CPU or IO-Expander the LED is connected to.
- * \param pin Pin at the given port.
- *
- * \return -1 if registering failed, else 0.
- *
- */
- int NutRegisterLed( HANDLE * ledh, int bank, int pin)
- {
- LEDEventT *led;
- /* Check memory constraints and assign memory to new led struct */
- led = malloc(sizeof( LEDEventT));
- *ledh = (void*)led;
- if( led == NULL) {
- return -1;
- }
- /* Preset new led struct */
- memset( led, 0, sizeof( LEDEventT));
- led->bank = bank;
- led->pin = pin;
- led->state = LED_SET_OFF;
- /* Assign the led to the chain */
- NutEnterCritical();
- if( first_led == NULL) {
- /* it is the first led */
- first_led = led;
- }
- else {
- /* if not first, put it into the chain at first position */
- led->next = first_led;
- first_led = led;
- }
- NutExitCritical();
- /* Start timer for LED effects, but only one timer for all */
- if( led_tmr == NULL) {
- NutThreadCreate("sys_led", sys_led, &led_evt, 192);
- led_tmr = NutTimerStart(10, LedTimerCb, &led_evt, 0);
- }
- return InitLED( led);
- }
- /*@}*/
|