Mbed 4dGenie class
Dependents: Genie_Test 039847382-S3_DS1621_and_LCD_V1
This is a work in progress.
4dGenie class to use with 4dLCD screens that are using the genie environment.
There are still some rare occasions where the 4dLCD might crash, for now i have no solution to this except doing a reset of the 4dLCD.
Please make sure to have the most up to date PmmC loaded on the screen.
usage example :
Mbed4dGenie test program
#include "mbed.h" #include "mbed_genie.h" DigitalOut myled(LED1); /* The Mbed4dGenie class requires 3 parameters 1 - Tx pin 2 - Rx pin 3 - Reset pin */ Mbed4dGenie lcd4d(PTE0,PTE1,PTB9); int main() { int temp = 0; printf("Mbed Genie demo \n\r"); lcd4d.Start(); /* for example, in this loop we increment the thermometer0 object from 0 to 100 */ while(1) { if(temp >= 100) { temp = -1; } else { temp++; } lcd4d.genieWriteObject(GENIE_OBJ_LED_DIGITS,1,temp); myled = 1; wait(0.05); myled = 0; wait(0.05); } }
mbed_genie.cpp
- Committer:
- chris215
- Date:
- 2014-06-18
- Revision:
- 5:3eb81723edc5
- Parent:
- 4:23c46eb6f0db
File content as of revision 5:3eb81723edc5:
#include "mbed.h" #include "mbed_genie.h" Serial pc(USBTX,USBRX); Mbed4dGenie::Mbed4dGenie(PinName TxPin,PinName RxPin, PinName resetpin) : _screen(TxPin,RxPin) , _reset(resetpin) { //reset the 4d screen _screen.baud(115200); _reset = 0; wait(0.25); _reset = 1; _genieLinkStates[4] = GENIE_LINK_IDLE; _genieLinkStates[3] = GENIE_LINK_IDLE; _genieLinkStates[2] = GENIE_LINK_IDLE; _genieLinkStates[1] = GENIE_LINK_IDLE; _genieLinkStates[0] = GENIE_LINK_IDLE; _genieLinkState = &_genieLinkStates[0]; _genieTimeout = TIMEOUT_PERIOD; _genieError = ERROR_NONE; rxframe_count = 0; _genieUserHandler = NULL; _screen.attach(this,&Mbed4dGenie::RxIrqHandler,Serial::RxIrq); _t.start(); } void Mbed4dGenie::genieAttachEventHandler(genieUserEventHandlerPtr handler) { _genieUserHandler = handler; } void Mbed4dGenie::RxIrqHandler(void) { do { genieDoEvents(); } while(_screen.readable ()); } //////////////////////// _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 Mbed4dGenie::_genieGetchar() { _genieError = ERROR_NONE; return (_screen.getc()); } ///////////////////// _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 Mbed4dGenie::_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 Mbed4dGenie::_genieGetLinkState (void) { return *_genieLinkState; } /////////////////////// _geniePutchar /////////////////////////// // // Output the supplied character to the Genie display over // the selected serial port // void Mbed4dGenie::_geniePutchar (uint8_t c) { // if (screen != NULL) _screen.putc(c); } ////////////////////// _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 Mbed4dGenie::_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; } } ////////////////////// 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 Mbed4dGenie::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 Mbed4dGenie::_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 Mbed4dGenie::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); return GENIE_EVENT_NONE; } /////////////////////// 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 Mbed4dGenie::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() // int Mbed4dGenie::_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 Mbed4dGenie::genieWriteStr (uint16_t index, char *string) { return _genieWriteStrX (GENIE_WRITE_STR, index, string); } /////////////////////// genieWriteStrU //////////////////////// // // Write a string to the display (Unicode) // uint16_t Mbed4dGenie::genieWriteStrU (uint16_t index, char *string) { return _genieWriteStrX (GENIE_WRITE_STRU, index, string); } ////////////////////////////////////////////////////////////// // 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 Mbed4dGenie::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 Mbed4dGenie::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 Mbed4dGenie::_geniePushLinkState (uint8_t newstate) { _genieLinkState++; _genieSetLinkState(newstate); } ////////////////////// _geniePopLinkState ////////////////////// // // Pop a link state from a FILO stack // void Mbed4dGenie::_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 Mbed4dGenie::_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 Mbed4dGenie::_handleError (void) { _genieError = ERROR_NONE; } ////////////////////// _genieFlushEventQueue //////////////////// // // Reset all the event queue variables and start from scratch. // void Mbed4dGenie::_genieFlushEventQueue(void) { _genieEventQueue.rd_index = 0; _genieEventQueue.wr_index = 0; _genieEventQueue.n_events = 0; } bool Mbed4dGenie::GenieReadable(void){ if (_screen.readable()) { return TRUE; } else { return FALSE; } } ///////////////////////// genieDoEvents ///////////////////////// // // This is the heart of the Genie comms state machine. // uint16_t Mbed4dGenie::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 pc.printf("error1\n\r"); 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(); pc.printf("error2:NAK\n\r"); 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 pc.printf("error3\n\r"); 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(); pc.printf("error4\n\r"); } } rxframe_count++; return GENIE_EVENT_RXCHAR; } } return GENIE_EVENT_NONE; }