diff options
| author | shaolin <[email protected]> | 2014-03-04 09:14:48 +0800 |
|---|---|---|
| committer | shaolin <[email protected]> | 2014-03-04 09:14:48 +0800 |
| commit | 020e95d91b5e1d7f902674a320e42657bee3ebfe (patch) | |
| tree | 65b65bfa527e0e8670dc807a8fee8d507d67ca48 /components/external/espruino/src/jsdevices.c | |
| parent | 0fb9c54efda7fef4346523fdc4b92512a0441ee1 (diff) | |
| parent | 738871fd9ebbd53da6cfcc429dfdd5ffc17fd685 (diff) | |
Merge branch 'master' of https://github.com/RT-Thread/rt-thread
Diffstat (limited to 'components/external/espruino/src/jsdevices.c')
| -rw-r--r-- | components/external/espruino/src/jsdevices.c | 336 |
1 files changed, 336 insertions, 0 deletions
diff --git a/components/external/espruino/src/jsdevices.c b/components/external/espruino/src/jsdevices.c new file mode 100644 index 0000000000..4c7c9715f9 --- /dev/null +++ b/components/external/espruino/src/jsdevices.c @@ -0,0 +1,336 @@ +/* + * This file is part of Espruino, a JavaScript interpreter for Microcontrollers + * + * Copyright (C) 2013 Gordon Williams <[email protected]> + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * ---------------------------------------------------------------------------- + * Common low-level device handling (Events, IO buffers) + * ---------------------------------------------------------------------------- + */ +#include "jsdevices.h" +#include "jsparse.h" +#include "jsinteractive.h" + +#ifdef LINUX + #include <signal.h> +#endif//LINUX +#ifdef USE_TRIGGER +#include "trigger.h" +#endif +#ifdef USE_CC3000 +#include "board_spi.h" +#endif +// ---------------------------------------------------------------------------- +// BUFFERS + +// ---------------------------------------------------------------------------- +// DATA TRANSMIT BUFFER +typedef struct { + IOEventFlags flags; // Where this data should be transmitted + unsigned char data; // data to transmit +} PACKED_FLAGS TxBufferItem; + +TxBufferItem txBuffer[TXBUFFERMASK+1]; +volatile unsigned char txHead=0, txTail=0; +// ---------------------------------------------------------------------------- + +// Queue a character for transmission +void jshTransmit(IOEventFlags device, unsigned char data) { +#ifdef RT_USING_JS + rt_device_write(rt_console_get_device(), 0, &data, 1); +#else +#ifndef LINUX +#ifdef USB + if (device==EV_USBSERIAL && !jshIsUSBSERIALConnected()) { + jshTransmitClearDevice(EV_USBSERIAL); // clear out stuff already waiting + return; + } +#endif + if (device==EV_NONE) return; + unsigned char txHeadNext = (txHead+1)&TXBUFFERMASK; + if (txHeadNext==txTail) { + jsiSetBusy(BUSY_TRANSMIT, true); + while (txHeadNext==txTail) { + // wait for send to finish as buffer is about to overflow +#ifdef USB + // just in case USB was unplugged while we were waiting! + if (!jshIsUSBSERIALConnected()) jshTransmitClearDevice(EV_USBSERIAL); +#endif + } + jsiSetBusy(BUSY_TRANSMIT, false); + } + txBuffer[txHead].flags = device; + txBuffer[txHead].data = (char)data; + txHead = txHeadNext; + + jshUSARTKick(device); // set up interrupts if required + +#else // if PC, just put to stdout + if (device==DEFAULT_CONSOLE_DEVICE) { + fputc(data, stdout); + fflush(stdout); + } +#endif +#endif +} + +// Try and get a character for transmission - could just return -1 if nothing +int jshGetCharToTransmit(IOEventFlags device) { + unsigned char ptr = txTail; + while (txHead != ptr) { + if (IOEVENTFLAGS_GETTYPE(txBuffer[ptr].flags) == device) { + unsigned char data = txBuffer[ptr].data; + if (ptr != txTail) { // so we weren't right at the back of the queue + // we need to work back from ptr (until we hit tail), shifting everything forwards + unsigned char this = ptr; + unsigned char last = (unsigned char)((this+TXBUFFERMASK)&TXBUFFERMASK); + while (this!=txTail) { // if this==txTail, then last is before it, so stop here + txBuffer[this] = txBuffer[last]; + this = last; + last = (unsigned char)((this+TXBUFFERMASK)&TXBUFFERMASK); + } + } + txTail = (unsigned char)((txTail+1)&TXBUFFERMASK); // advance the tail + return data; // return data + } + ptr = (unsigned char)((ptr+1)&TXBUFFERMASK); + } + return -1; // no data :( +} + +void jshTransmitFlush() { + jsiSetBusy(BUSY_TRANSMIT, true); + while (jshHasTransmitData()) ; // wait for send to finish + jsiSetBusy(BUSY_TRANSMIT, false); +} + +// Clear everything from a device +void jshTransmitClearDevice(IOEventFlags device) { + while (jshGetCharToTransmit(device)>=0); +} + +bool jshHasTransmitData() { +#ifndef LINUX + return txHead != txTail; +#else + return false; +#endif +} + +// ---------------------------------------------------------------------------- +// IO EVENT BUFFER +IOEvent ioBuffer[IOBUFFERMASK+1]; +volatile unsigned char ioHead=0, ioTail=0; +// ---------------------------------------------------------------------------- + + +void jshIOEventOverflowed() { + // Error here - just light LED as we can't do much else right now +} + + +void jshPushIOCharEvent(IOEventFlags channel, char charData) { + if (charData==3 && channel==jsiGetConsoleDevice()) { + // Ctrl-C - force interrupt +#ifdef LINUX + raise(SIGINT); +#endif + jspSetInterrupted(true); + return; + } + if (DEVICE_IS_USART(channel) && jshGetEventsUsed() > IOBUFFER_XOFF) + jshSetFlowControlXON(channel, false); + // Check for existing buffer (we must have at least 2 in the queue to avoid dropping chars though!) + unsigned char nextTail = (unsigned char)((ioTail+1) & IOBUFFERMASK); + if (ioHead!=ioTail && ioHead!=nextTail) { + // we can do this because we only read in main loop, and we're in an interrupt here + unsigned char lastHead = (unsigned char)((ioHead+IOBUFFERMASK) & IOBUFFERMASK); // one behind head + if (IOEVENTFLAGS_GETTYPE(ioBuffer[lastHead].flags) == channel && + IOEVENTFLAGS_GETCHARS(ioBuffer[lastHead].flags) < IOEVENT_MAXCHARS) { + // last event was for this event type, and it has chars left + unsigned char c = (unsigned char)IOEVENTFLAGS_GETCHARS(ioBuffer[lastHead].flags); + ioBuffer[lastHead].data.chars[c] = charData; + IOEVENTFLAGS_SETCHARS(ioBuffer[lastHead].flags, c+1); + return; + } + } + // Make new buffer + unsigned char nextHead = (unsigned char)((ioHead+1) & IOBUFFERMASK); + if (ioTail == nextHead) { + jshIOEventOverflowed(); + return; // queue full - dump this event! + } + ioBuffer[ioHead].flags = channel; + IOEVENTFLAGS_SETCHARS(ioBuffer[ioHead].flags, 1); + ioBuffer[ioHead].data.chars[0] = charData; + ioHead = nextHead; +} + +void jshPushIOWatchEvent(IOEventFlags channel) { + JsSysTime time = jshGetSystemTime(); + bool state = jshGetWatchedPinState(channel); + +/* // This is some simple debounce code - however it requires that the event + // is not taken out of ioBuffer by the main thread, which will require + // a bit of fiddling in jsinteractive.c. In fact it might be worth just + // doing debounce outside of the interrupt + if (true) { // debounce + // scan back and see if we have an event for this pin + unsigned char prevHead = ioHead; + while (prevHead!=ioTail && (IOEVENTFLAGS_GETTYPE(ioBuffer[prevHead].flags)!=channel)) + prevHead = (unsigned char)((prevHead+IOBUFFERMASK) & IOBUFFERMASK); // step back + // if we have an event + if (prevHead!=ioTail && (IOEVENTFLAGS_GETTYPE(ioBuffer[prevHead].flags)==channel)) { + // just use it (with the same timestamp)... + ioBuffer[prevHead].flags = channel | (state?EV_EXTI_IS_HIGH:0); + return; + } + }*/ + +#ifdef USE_TRIGGER + if (trigHandleEXTI(channel | (state?EV_EXTI_IS_HIGH:0), time)) + return; +#endif +#ifdef USE_CC3000 + IOEvent event; + event.flags = channel; + if (!state && jshIsEventForPin(&event, WLAN_IRQ_PIN)) { + cc3000_irq_handler(); + } +#endif + // Otherwise add this event + jshPushIOEvent(channel | (state?EV_EXTI_IS_HIGH:0), time); +} + +void jshPushIOEvent(IOEventFlags channel, JsSysTime time) { + + unsigned char nextHead = (unsigned char)((ioHead+1) & IOBUFFERMASK); + if (ioTail == nextHead) { + jshIOEventOverflowed(); + return; // queue full - dump this event! + } + ioBuffer[ioHead].flags = channel; + ioBuffer[ioHead].data.time = time; + ioHead = nextHead; +} + +// returns true on success +bool jshPopIOEvent(IOEvent *result) { + if (ioHead==ioTail) return false; + *result = ioBuffer[ioTail]; + ioTail = (unsigned char)((ioTail+1) & IOBUFFERMASK); + return true; +} + +bool jshHasEvents() { + return ioHead!=ioTail; +} + +int jshGetEventsUsed() { + int spaceUsed = (ioHead >= ioTail) ? ((int)ioHead-(int)ioTail) : /*or rolled*/((int)ioHead+IOBUFFERMASK+1-(int)ioTail); + return spaceUsed; +} + +bool jshHasEventSpaceForChars(int n) { + int spacesNeeded = 4 + (n/IOEVENT_MAXCHARS); // be sensible - leave a little spare + int spaceUsed = jshGetEventsUsed(); + int spaceLeft = IOBUFFERMASK+1-spaceUsed; + return spaceLeft > spacesNeeded; +} + +// ---------------------------------------------------------------------------- +// DEVICES +const char *jshGetDeviceString(IOEventFlags device) { + switch (device) { +#ifdef USB + case EV_USBSERIAL: return "USB"; +#endif + case EV_SERIAL1: return "Serial1"; + case EV_SERIAL2: return "Serial2"; + case EV_SERIAL3: return "Serial3"; +#if USARTS>=4 + case EV_SERIAL4: return "Serial4"; +#endif +#if USARTS>=5 + case EV_SERIAL5: return "Serial5"; +#endif +#if USARTS>=6 + case EV_SERIAL6: return "Serial6"; +#endif +#if SPIS>=1 + case EV_SPI1: return "SPI1"; +#endif +#if SPIS>=2 + case EV_SPI2: return "SPI2"; +#endif +#if SPIS>=3 + case EV_SPI3: return "SPI3"; +#endif +#if I2CS>=1 + case EV_I2C1: return "I2C1"; +#endif +#if I2CS>=2 + case EV_I2C2: return "I2C2"; +#endif +#if I2CS>=3 + case EV_I2C3: return "I2C3"; +#endif + default: return ""; + } +} + +IOEventFlags jshFromDeviceString(const char *device) { + if (device[0]=='U') { +#ifdef USB + if (strcmp(device, "USB")==0) return EV_USBSERIAL; +#endif + } + else if (device[0]=='S') { + if (device[1]=='e' && device[2]=='r' && device[3]=='i' && device[4]=='a' && device[5]=='l') { + if (strcmp(device, "Serial1")==0) return EV_SERIAL1; + if (strcmp(device, "Serial2")==0) return EV_SERIAL2; + if (strcmp(device, "Serial3")==0) return EV_SERIAL3; +#if USARTS>=4 + if (strcmp(device, "Serial4")==0) return EV_SERIAL4; +#endif +#if USARTS>=5 + if (strcmp(device, "Serial5")==0) return EV_SERIAL5; +#endif +#if USARTS>=6 + if (strcmp(device, "Serial6")==0) return EV_SERIAL6; +#endif + } + if (device[1]=='P' && device[2]=='I') { +#if SPIS>=1 + if (strcmp(device, "SPI1")==0) return EV_SPI1; +#endif +#if SPIS>=2 + if (strcmp(device, "SPI2")==0) return EV_SPI2; +#endif +#if SPIS>=3 + if (strcmp(device, "SPI3")==0) return EV_SPI3; +#endif + } + } + else if (device[0]=='I' && device[1]=='2' && device[2]=='C') { +#if I2CS>=1 + if (strcmp(device, "I2C1")==0) return EV_I2C1; +#endif +#if I2CS>=2 + if (strcmp(device, "I2C2")==0) return EV_I2C2; +#endif +#if I2CS>=3 + if (strcmp(device, "I2C3")==0) return EV_I2C3; +#endif + } + return EV_NONE; +} + +/// Set whether the host should transmit or not +void jshSetFlowControlXON(IOEventFlags device, bool hostShouldTransmit) { +} + |
