4D display working with Gecko board STK3600
Fork of 4dGENIE by
Diff: mbed_genie.cpp
- Revision:
- 0:d2ed5a44c802
- Child:
- 1:95e0e194a412
diff -r 000000000000 -r d2ed5a44c802 mbed_genie.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mbed_genie.cpp Fri Feb 21 01:42:46 2014 +0000 @@ -0,0 +1,613 @@ + +#include "mbed.h" +#include "mbed_genie.h" + +Serial screen(p9,p10); +Serial pc(USBTX,USBRX); +Timer t; + + + +void _genieFlushEventQueue (void); +void _handleError (void); +void _geniePutchar (uint8_t c); +uint8_t _genieGetchar (void); +void _genieSetLinkState (uint16_t newstate); +uint16_t _genieGetLinkState (void); +bool _genieEnqueueEvent (uint8_t * data); +////////////////////////////////////////////////////////////// +// A structure to hold up to MAX_GENIE_EVENTS events receive +// from the display +// +static genieEventQueueStruct _genieEventQueue; + +////////////////////////////////////////////////////////////// +// Pointer to the user's event handler function +// +static genieUserEventHandlerPtr _genieUserHandler = NULL; + + +////////////////////////////////////////////////////////////// +// Simple 5-deep stack for the link state, this allows +// genieDoEvents() to save the current state, receive a frame, +// then restore the state +// +static uint8_t _genieLinkStates[5] = {GENIE_LINK_IDLE}; +// +// Stack pointer +// +static uint8_t *_genieLinkState = &_genieLinkStates[0]; + + +////////////////////////////////////////////////////////////// +// Number of mS the genieGetChar() function will wait before +// giving up on the display +static int _genieTimeout = TIMEOUT_PERIOD; + + +////////////////////////////////////////////////////////////// +// Number of times we have had a timeout +static int _genieTimeouts = 0; + + +////////////////////////////////////////////////////////////// +// Global error variable +static int _genieError = ERROR_NONE; + + + + +static uint8_t rxframe_count = 0; + + +////////////////////////////////////////////////////////////// +// Number of fatal errors encountered +static int _genieFatalErrors = 0; +////////////////////// genieGetEventData //////////////////////// +// +// Returns the LSB and MSB of the event's data combined into +// a single uint16 +// +// The data is transmitted from the display in big-endian format +// and stored the same so the user can't just access it as an int +// directly from the structure. +// +uint16_t genieGetEventData (genieFrame * e) { + return (e->reportObject.data_msb << 8) + e->reportObject.data_lsb; +} + + + + +//////////////////////// genieEventIs /////////////////////////// +// +// Compares the cmd, object and index fields of the event's +// structure. +// +// Returns: TRUE if all the fields match the caller's parms +// FALSE if any of them don't +// +bool genieEventIs(genieFrame * e, uint8_t cmd, uint8_t object, uint8_t index) { + + + return (e->reportObject.cmd == cmd && + e->reportObject.object == object && + e->reportObject.index == index); + + +} + +////////////////////// _geniePushLinkState ////////////////////// +// +// Push a link state onto a FILO stack +// +void _geniePushLinkState (uint8_t newstate) { + + + _genieLinkState++; + _genieSetLinkState(newstate); + + +} + + +////////////////////// _geniePopLinkState ////////////////////// +// +// Pop a link state from a FILO stack +// +void _geniePopLinkState (void) { + if (_genieLinkState > &_genieLinkStates[0]) { + *_genieLinkState = 0xFF; + _genieLinkState--; + } +} + +///////////////// _genieFlushSerialInput /////////////////// +// +// Removes and discards all characters from the currently +// used serial port's Rx buffer. +// +void _genieFlushSerialInput(void) { + do { + _genieGetchar(); + } while (_genieError != ERROR_NOCHAR); +} + +///////////////////////// _handleError ///////////////////////// +// +// So far really just a debugging aid, but can be enhanced to +// help recover from errors. +// +void _handleError (void) { +// Serial2.write (_genieError + (1<<5)); +// if (_genieError == GENIE_NAK) genieResync(); +} + + + + +////////////////////// _genieFlushEventQueue //////////////////// +// +// Reset all the event queue variables and start from scratch. +// +void _genieFlushEventQueue(void) { + _genieEventQueue.rd_index = 0; + _genieEventQueue.wr_index = 0; + _genieEventQueue.n_events = 0; +} +bool GenieReadable(void){ + if (screen.readable()) + { + return TRUE; + } + else + { + return FALSE; + } +} +///////////////////////// genieDoEvents ///////////////////////// +// +// This is the heart of the Genie comms state machine. +// +uint16_t genieDoEvents (void) { + uint8_t c; + static uint8_t rx_data[6]; + static uint8_t checksum = 0; + + if (GenieReadable()) + { + c = _genieGetchar(); + //pc.putc(c); + + //////////////////////////////////////////// + // + // If there are no characters to process and we have + // queued events call the user's handler function. + // + if (_genieError == ERROR_NOCHAR) { + //pc.printf("EventCalled!\n\r"); + if (_genieEventQueue.n_events > 0 && _genieUserHandler!= NULL) (_genieUserHandler)(); + return GENIE_EVENT_NONE; + } + + /////////////////////////////////////////// + // + // Main state machine + // + switch (_genieGetLinkState()) { + case GENIE_LINK_IDLE: + switch (c) { + case GENIE_REPORT_EVENT: + // event frame out of the blue, set the link state + // and fall through to the frame-accumulate code + // at the end of this function + _geniePushLinkState(GENIE_LINK_RXEVENT); + break; + + default: + // error, bad character, no other character + // is acceptable in this state + return GENIE_EVENT_RXCHAR; + + } + break; + + case GENIE_LINK_WFAN: + switch (c) { + + + case GENIE_ACK: + _geniePopLinkState(); + return GENIE_EVENT_RXCHAR; + + + case GENIE_NAK: + _geniePopLinkState(); + _genieError = ERROR_NAK; + _handleError(); + return GENIE_EVENT_RXCHAR; + + case GENIE_REPORT_EVENT: + // event frame out of the blue while waiting for an ACK + // save/set the link state and fall through to the + // frame-accumulate code at the end of this function + _geniePushLinkState(GENIE_LINK_RXEVENT); + break; + + + case GENIE_REPORT_OBJ: + default: + // error, bad character + return GENIE_EVENT_RXCHAR; + } + break; + + + case GENIE_LINK_WF_RXREPORT: // waiting for the first byte of a report + switch (c) { + + case GENIE_REPORT_EVENT: + // event frame out of the blue while waiting for the first + // byte of a report frame + // save/set the link state and fall through to the + // frame-accumulate code at the end of this function + _geniePushLinkState(GENIE_LINK_RXEVENT); + break; + + + case GENIE_REPORT_OBJ: + // first byte of a report frame + // replace the GENIE_LINK_WF_RXREPORT link state + // with GENIE_LINK_RXREPORT to indicate that we + // are now receiving a report frame + _geniePopLinkState(); + _geniePushLinkState(GENIE_LINK_RXREPORT); + break; + + + case GENIE_ACK: + case GENIE_NAK: + default: + // error, bad character + return GENIE_EVENT_RXCHAR; + // break; + } + + + case GENIE_LINK_RXREPORT: // already receiving report + case GENIE_LINK_RXEVENT: // already receiving event + default: + break; + + } + + + /////////////////////////////////////////////////////// + // We get here if we are in the process of receiving + // a report or event frame. Accumulate GENIE_FRAME_SIZE + // bytes into a local buffer then queue them as a frame + // into the event queue + // + if (_genieGetLinkState() == GENIE_LINK_RXREPORT || \ + _genieGetLinkState() == GENIE_LINK_RXEVENT) { + + checksum = (rxframe_count == 0) ? c : checksum ^ c; + + + rx_data[rxframe_count] = c; + + + if (rxframe_count == GENIE_FRAME_SIZE -1) { + //pc.printf("FrameReceived!\n\r"); + // all bytes received, if the CS is good + // queue the frame and restore the link state + if (checksum == 0) { + _genieEnqueueEvent(rx_data); + if (_genieEventQueue.n_events > 0 && _genieUserHandler!= NULL) (_genieUserHandler)(); + //return GENIE_EVENT_NONE; + rxframe_count = 0; + // revert the link state to whatever it was before + // we started accumulating this frame + _geniePopLinkState(); + return GENIE_EVENT_RXCHAR; + } else { + _genieError = ERROR_BAD_CS; + _handleError(); + } + } + rxframe_count++; + return GENIE_EVENT_RXCHAR; + } + } +} + +////////////////////// genieDequeueEvent /////////////////// +// +// Copy the bytes from a queued input event to a buffer supplied +// by the caller. +// +// Parms: genieFrame * buff, a pointer to the user's buffer +// +// Returns: TRUE if there was an event to copy +// FALSE if not +// +bool genieDequeueEvent(genieFrame * buff) { + + + if (_genieEventQueue.n_events > 0) { + memcpy (buff, &_genieEventQueue.frames[_genieEventQueue.rd_index], + GENIE_FRAME_SIZE); + _genieEventQueue.rd_index++; + _genieEventQueue.rd_index &= MAX_GENIE_EVENTS -1; + _genieEventQueue.n_events--; + return TRUE; + } + return FALSE; +} + + + + + +////////////////////// _genieWaitForIdle //////////////////////// +// +// Wait for the link to become idle or for the timeout period, +// whichever comes first. +// +void _genieWaitForIdle (void) { + uint16_t do_event_result; + long timeout = t.read_ms() + _genieTimeout; + + for ( ; t.read_ms() < timeout;) { + + + do_event_result = genieDoEvents(); + // if there was a character received from the + // display restart the timeout because doEvents + // is in the process of receiving something + if (do_event_result == GENIE_EVENT_RXCHAR) { + timeout = t.read_ms() + _genieTimeout; + return; + } + + if (_genieGetLinkState() == GENIE_LINK_IDLE) { + return; + } + } + _genieError = ERROR_TIMEOUT; + _handleError(); + return; +} + +///////////////////////// genieWriteObject ////////////////////// +// +// Write data to an object on the display +// +uint16_t genieWriteObject (uint16_t object, uint16_t index, uint16_t data) +{ + uint16_t msb, lsb ; + uint8_t checksum ; + + + _genieWaitForIdle(); + + + lsb = data&0xFF; + msb = (data>>8) & 0xFF; + + + _genieError = ERROR_NONE; + + + _geniePutchar(GENIE_WRITE_OBJ) ; checksum = GENIE_WRITE_OBJ ; + _geniePutchar(object) ; checksum ^= object ; + _geniePutchar(index) ; checksum ^= index ; + _geniePutchar(msb) ; checksum ^= msb; + _geniePutchar(lsb) ; checksum ^= lsb; + _geniePutchar(checksum) ; + + + _geniePushLinkState(GENIE_LINK_WFAN); +} + +/////////////////////// genieWriteContrast ////////////////////// +// +// Alter the display contrast (backlight) +// +// Parms: uint8_t value: The required contrast setting, only +// values from 0 to 15 are valid. 0 or 1 for most displays +// and 0 to 15 for the uLCD-43 +// +void genieWriteContrast (uint16_t value) { + unsigned int checksum ; + + + _genieWaitForIdle(); + + + _geniePutchar(GENIE_WRITE_CONTRAST) ; checksum = GENIE_WRITE_CONTRAST ; + _geniePutchar(value) ; checksum ^= value ; + _geniePutchar(checksum) ; + + + _geniePushLinkState(GENIE_LINK_WFAN); + + +} + + +//////////////////////// _genieWriteStrX /////////////////////// +// +// Non-user function used by genieWriteStr() and genieWriteStrU() +// +static int _genieWriteStrX (uint16_t code, uint16_t index, char *string) +{ + char *p ; + unsigned int checksum ; + int len = strlen (string) ; + + + if (len > 255) + return -1 ; + + + _genieWaitForIdle(); + + + _geniePutchar(code) ; checksum = code ; + _geniePutchar(index) ; checksum ^= index ; + _geniePutchar((unsigned char)len) ; checksum ^= len ; + for (p = string ; *p ; ++p) { + _geniePutchar (*p) ; + checksum ^= *p ; + } + _geniePutchar(checksum) ; + + + _geniePushLinkState(GENIE_LINK_WFAN); + + + return 0 ; +} +/////////////////////// genieWriteStr //////////////////////// +// +// Write a string to the display (ASCII) +// +uint16_t genieWriteStr (uint16_t index, char *string) { + + return _genieWriteStrX (GENIE_WRITE_STR, index, string); +} + + +/////////////////////// genieWriteStrU //////////////////////// +// +// Write a string to the display (Unicode) +// +uint16_t genieWriteStrU (uint16_t index, char *string) { + + + return _genieWriteStrX (GENIE_WRITE_STRU, index, string); + + +} +/////////////////// genieAttachEventHandler ////////////////////// +// +// "Attaches" a pointer to the users event handler by writing +// the pointer into the variable used by doEVents() +// +void genieAttachEventHandler (genieUserEventHandlerPtr handler) { + _genieUserHandler = handler; +} + + +////////////////////// _genieEnqueueEvent /////////////////// +// +// Copy the bytes from a buffer supplied by the caller +// to the input queue +// +// Parms: uint8_t * data, a pointer to the user's data +// +// Returns: TRUE if there was an empty location in the queue +// to copy the data into +// FALSE if not +// Sets: ERROR_REPLY_OVR if there was no room in the queue +// +bool _genieEnqueueEvent (uint8_t * data) { + + + if (_genieEventQueue.n_events < MAX_GENIE_EVENTS-2) { + memcpy (&_genieEventQueue.frames[_genieEventQueue.wr_index], data, + GENIE_FRAME_SIZE); + _genieEventQueue.wr_index++; + _genieEventQueue.wr_index &= MAX_GENIE_EVENTS -1; + _genieEventQueue.n_events++; + return TRUE; + } else { + _genieError = ERROR_REPLY_OVR; + _handleError(); + return FALSE; + } +} +///////////////////// _genieSetLinkState //////////////////////// +// +// Set the logical state of the link to the display. +// +// Parms: uint16_t newstate, a value to be written to the +// link's _genieLinkState variable. Valid values are +// GENIE_LINK_IDLE 0 +// GENIE_LINK_WFAN 1 // waiting for Ack or Nak +// GENIE_LINK_WF_RXREPORT 2 // waiting for a report frame +// GENIE_LINK_RXREPORT 3 // receiving a report frame +// GENIE_LINK_RXEVENT 4 // receiving an event frame +// GENIE_LINK_SHDN 5 +// +void _genieSetLinkState (uint16_t newstate) { + + *_genieLinkState = newstate; + + + if (newstate == GENIE_LINK_RXREPORT || \ + newstate == GENIE_LINK_RXEVENT) + rxframe_count = 0; +} + + +/////////////////////// _genieGetLinkState ////////////////////// +// +// Get the current logical state of the link to the display. +// +uint16_t _genieGetLinkState (void) { + return *_genieLinkState; +} + +/////////////////////// _geniePutchar /////////////////////////// +// +// Output the supplied character to the Genie display over +// the selected serial port +// +void _geniePutchar (uint8_t c) { + // if (screen != NULL) + screen.putc(c); +} + + +//////////////////////// _genieGetchar ////////////////////////// +// +// Get a character from the selected Genie serial port +// +// Returns: ERROR_NOHANDLER if an Rx handler has not +// been defined +// ERROR_NOCHAR if no bytes have beeb received +// The char if there was one to get +// Sets: _genieError with any errors encountered +// +uint8_t _genieGetchar() { + uint16_t result; + + + _genieError = ERROR_NONE; + + return (screen.getc()); +} + +void RxIrqHandler(void) +{ + do + { + genieDoEvents(); + } + while(screen.readable ()); +} + + +void TickerIrq(void) +{ +} + + +void SetupGenie(void) +{ + screen.attach(&RxIrqHandler,Serial::RxIrq); + t.start(); + // EventChk.attach(&TickerIrq,0.05); +}