A port of the arduino voltmeter example for the mbed using the 4.3' PCT 4d systems touch screen display. Uses the mbed_genie library ported from the arduino visie-genie library by Christian B

Dependencies:   mbed

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers mbed_genie.cpp Source File

mbed_genie.cpp

00001 
00002 #include "mbed.h"
00003 #include "mbed_genie.h"
00004 
00005 DigitalOut genieReset(p8);  //genie reset pin on pin 8 of the mbed
00006 
00007 Serial screen(p9,p10);
00008 Serial pc(USBTX,USBRX);
00009 Timer t;
00010 
00011 
00012 
00013 void           _genieFlushEventQueue        (void);
00014 void           _handleError                        (void);
00015 void           _geniePutchar                        (uint8_t c);
00016 uint8_t        _genieGetchar                        (void);
00017 void           _genieSetLinkState                (uint16_t newstate);
00018 uint16_t       _genieGetLinkState                (void);        
00019 bool           _genieEnqueueEvent                (uint8_t * data);
00020 //////////////////////////////////////////////////////////////
00021 // A structure to hold up to MAX_GENIE_EVENTS events receive
00022 // from the display
00023 //
00024 static genieEventQueueStruct _genieEventQueue;
00025 
00026 //////////////////////////////////////////////////////////////
00027 // Pointer to the user's event handler function
00028 //
00029 static genieUserEventHandlerPtr _genieUserHandler = NULL;
00030 
00031 
00032 //////////////////////////////////////////////////////////////
00033 // Simple 5-deep stack for the link state, this allows 
00034 // genieDoEvents() to save the current state, receive a frame,
00035 // then restore the state
00036 //
00037 static uint8_t _genieLinkStates[5] = {GENIE_LINK_IDLE};
00038 //
00039 // Stack pointer
00040 //
00041 static uint8_t *_genieLinkState = &_genieLinkStates[0];
00042 
00043 
00044 //////////////////////////////////////////////////////////////
00045 // Number of mS the genieGetChar() function will wait before
00046 // giving up on the display
00047 static int _genieTimeout = TIMEOUT_PERIOD;
00048 
00049 
00050 //////////////////////////////////////////////////////////////
00051 // Number of times we have had a timeout
00052 static int _genieTimeouts = 0;
00053 
00054 
00055 //////////////////////////////////////////////////////////////
00056 // Global error variable
00057 static int _genieError = ERROR_NONE;
00058 
00059 
00060 
00061 
00062 static uint8_t        rxframe_count = 0;
00063 
00064 
00065 //////////////////////////////////////////////////////////////
00066 // Number of fatal errors encountered
00067 static int _genieFatalErrors = 0;
00068 ////////////////////// genieGetEventData ////////////////////////
00069 //
00070 // Returns the LSB and MSB of the event's data combined into
00071 // a single uint16
00072 //
00073 // The data is transmitted from the display in big-endian format 
00074 // and stored the same so the user can't just access it as an int 
00075 // directly from the structure. 
00076 //
00077 uint16_t genieGetEventData (genieFrame * e) {
00078         return  (e->reportObject.data_msb << 8) + e->reportObject.data_lsb;
00079 }
00080 
00081 
00082 
00083 
00084 //////////////////////// genieEventIs ///////////////////////////
00085 //
00086 // Compares the cmd, object and index fields of the event's 
00087 // structure.
00088 //
00089 // Returns:                TRUE if all the fields match the caller's parms
00090 //                                FALSE if any of them don't
00091 //
00092 bool genieEventIs(genieFrame * e, uint8_t cmd, uint8_t object, uint8_t index) {
00093 
00094 
00095         return (e->reportObject.cmd == cmd &&
00096                 e->reportObject.object == object &&
00097                 e->reportObject.index == index);
00098 
00099 
00100 }
00101 
00102 ////////////////////// _geniePushLinkState //////////////////////
00103 //
00104 // Push a link state onto a FILO stack
00105 //
00106 void _geniePushLinkState (uint8_t newstate) {
00107 
00108 
00109         _genieLinkState++;
00110         _genieSetLinkState(newstate);
00111 
00112 
00113 }
00114 
00115 
00116 ////////////////////// _geniePopLinkState //////////////////////
00117 //
00118 // Pop a link state from a FILO stack
00119 //
00120 void _geniePopLinkState (void) {
00121         if (_genieLinkState > &_genieLinkStates[0]) {
00122                 *_genieLinkState = 0xFF;
00123                 _genieLinkState--;
00124         }
00125 }
00126 
00127 ///////////////// _genieFlushSerialInput ///////////////////
00128 //
00129 // Removes and discards all characters from the currently 
00130 // used serial port's Rx buffer.
00131 //
00132 void _genieFlushSerialInput(void) {
00133         do {
00134                 _genieGetchar();
00135         } while (_genieError != ERROR_NOCHAR);
00136 }
00137 
00138 ///////////////////////// _handleError /////////////////////////
00139 //
00140 // So far really just a debugging aid, but can be enhanced to
00141 // help recover from errors.
00142 //
00143 void _handleError (void) {
00144 //        Serial2.write (_genieError + (1<<5));
00145 //        if (_genieError == GENIE_NAK) genieResync();
00146 }
00147 
00148 
00149 
00150 
00151 ////////////////////// _genieFlushEventQueue ////////////////////
00152 //
00153 // Reset all the event queue variables and start from scratch.
00154 //
00155 void _genieFlushEventQueue(void) {
00156         _genieEventQueue.rd_index = 0;
00157         _genieEventQueue.wr_index = 0;
00158         _genieEventQueue.n_events = 0;
00159 }
00160 bool GenieReadable(void){
00161     if (screen.readable())
00162     {
00163         return TRUE;
00164     }
00165     else
00166     {
00167         return FALSE;
00168     }
00169 }
00170 ///////////////////////// genieDoEvents /////////////////////////
00171 //
00172 // This is the heart of the Genie comms state machine.
00173 //
00174 uint16_t genieDoEvents (void) {
00175         uint8_t c;
00176         static uint8_t        rx_data[6];
00177         static uint8_t        checksum = 0;
00178 
00179         if (GenieReadable())
00180         {
00181             c = _genieGetchar();
00182             //pc.putc(c);
00183     
00184             ////////////////////////////////////////////
00185             //
00186             // If there are no characters to process and we have 
00187             // queued events call the user's handler function.
00188             //
00189             if (_genieError == ERROR_NOCHAR) {
00190             //pc.printf("EventCalled!\n\r");
00191                     if (_genieEventQueue.n_events > 0 && _genieUserHandler!= NULL) (_genieUserHandler)();
00192                     return GENIE_EVENT_NONE;
00193             }
00194             
00195             ///////////////////////////////////////////
00196             //
00197             // Main state machine
00198             //
00199             switch (_genieGetLinkState()) {
00200                     case GENIE_LINK_IDLE:
00201                             switch (c) {
00202                                     case GENIE_REPORT_EVENT:
00203                                     // event frame out of the blue, set the link state
00204                                     // and fall through to the frame-accumulate code
00205                                     // at the end of this function
00206                                     _geniePushLinkState(GENIE_LINK_RXEVENT);
00207                                     break;
00208                                             
00209                                     default:
00210                                     // error, bad character, no other character 
00211                                     // is acceptable in this state
00212                                     return GENIE_EVENT_RXCHAR;
00213                                     
00214                             }
00215                             break;
00216                                     
00217                     case GENIE_LINK_WFAN:
00218                             switch (c) {
00219     
00220     
00221                                     case GENIE_ACK:
00222                                             _geniePopLinkState();
00223                                             return GENIE_EVENT_RXCHAR;
00224     
00225     
00226                                     case GENIE_NAK:
00227                                             _geniePopLinkState();
00228                                             _genieError = ERROR_NAK;
00229                                             _handleError();
00230                                             return GENIE_EVENT_RXCHAR;
00231                             
00232                                     case GENIE_REPORT_EVENT:
00233                                             // event frame out of the blue while waiting for an ACK
00234                                             // save/set the link state and fall through to the 
00235                                             // frame-accumulate code at the end of this function
00236                                             _geniePushLinkState(GENIE_LINK_RXEVENT);
00237                                             break;
00238     
00239     
00240                                     case GENIE_REPORT_OBJ:
00241                                     default:
00242                                             // error, bad character
00243                                             return GENIE_EVENT_RXCHAR;        
00244                             }
00245                             break;
00246     
00247     
00248                     case GENIE_LINK_WF_RXREPORT: // waiting for the first byte of a report
00249                             switch (c) {
00250                             
00251                                     case GENIE_REPORT_EVENT:
00252                                     // event frame out of the blue while waiting for the first
00253                                     // byte of a report frame
00254                                     // save/set the link state and fall through to the
00255                                     // frame-accumulate code at the end of this function
00256                                     _geniePushLinkState(GENIE_LINK_RXEVENT);
00257                                     break;
00258     
00259     
00260                                     case GENIE_REPORT_OBJ:
00261                                     // first byte of a report frame
00262                                     // replace the GENIE_LINK_WF_RXREPORT link state 
00263                                     // with GENIE_LINK_RXREPORT to indicate that we
00264                                     // are now receiving a report frame
00265                                     _geniePopLinkState();
00266                                     _geniePushLinkState(GENIE_LINK_RXREPORT);
00267                                     break;
00268     
00269     
00270                                     case GENIE_ACK:
00271                                     case GENIE_NAK:
00272                                     default:
00273                                     // error, bad character
00274                                     return GENIE_EVENT_RXCHAR;
00275     //                                break;
00276                             }
00277     
00278     
00279                     case GENIE_LINK_RXREPORT:                // already receiving report
00280                     case GENIE_LINK_RXEVENT:                // already receiving event
00281                     default:
00282                             break;
00283                     
00284             }
00285     
00286     
00287             ///////////////////////////////////////////////////////
00288             // We get here if we are in the process of receiving 
00289             // a report or event frame. Accumulate GENIE_FRAME_SIZE 
00290             // bytes into a local buffer then queue them as a frame
00291             // into the event queue
00292             //
00293             if (_genieGetLinkState() == GENIE_LINK_RXREPORT || \
00294                     _genieGetLinkState() == GENIE_LINK_RXEVENT) {
00295                             
00296                     checksum = (rxframe_count == 0) ? c : checksum ^ c;
00297     
00298     
00299                     rx_data[rxframe_count] = c;
00300     
00301     
00302                     if (rxframe_count == GENIE_FRAME_SIZE -1) {
00303                     //pc.printf("FrameReceived!\n\r");
00304                             // all bytes received, if the CS is good 
00305                             // queue the frame and restore the link state
00306                             if (checksum == 0) {
00307                                     _genieEnqueueEvent(rx_data);
00308                                     if (_genieEventQueue.n_events > 0 && _genieUserHandler!= NULL) (_genieUserHandler)();
00309                                     //return GENIE_EVENT_NONE;
00310                                     rxframe_count = 0;
00311                                     // revert the link state to whatever it was before
00312                                     // we started accumulating this frame
00313                                     _geniePopLinkState();
00314                                     return GENIE_EVENT_RXCHAR;
00315                             } else {
00316                                     _genieError = ERROR_BAD_CS;
00317                                     _handleError();
00318                             }        
00319                     }
00320                     rxframe_count++;
00321                     return GENIE_EVENT_RXCHAR;
00322             }
00323     }   
00324 }
00325 
00326 ////////////////////// genieDequeueEvent ///////////////////
00327 //
00328 // Copy the bytes from a queued input event to a buffer supplied 
00329 // by the caller.
00330 //
00331 // Parms:        genieFrame * buff, a pointer to the user's buffer
00332 //
00333 // Returns:        TRUE if there was an event to copy
00334 //                        FALSE if not
00335 //
00336 bool genieDequeueEvent(genieFrame * buff) {
00337 
00338 
00339         if (_genieEventQueue.n_events > 0) {
00340                 memcpy (buff, &_genieEventQueue.frames[_genieEventQueue.rd_index], 
00341                                 GENIE_FRAME_SIZE);
00342                 _genieEventQueue.rd_index++;
00343                 _genieEventQueue.rd_index &= MAX_GENIE_EVENTS -1;
00344                 _genieEventQueue.n_events--;
00345                 return TRUE;
00346         } 
00347         return FALSE;
00348 }
00349 
00350 
00351 
00352 
00353 
00354 ////////////////////// _genieWaitForIdle ////////////////////////
00355 //
00356 // Wait for the link to become idle or for the timeout period, 
00357 // whichever comes first.
00358 //
00359 void _genieWaitForIdle (void) {
00360         uint16_t do_event_result;
00361         long timeout = t.read_ms() + _genieTimeout;
00362 
00363         for ( ; t.read_ms() < timeout;) {
00364 
00365          
00366             do_event_result = genieDoEvents();             
00367                 // if there was a character received from the 
00368                 // display restart the timeout because doEvents
00369                 // is in the process of receiving something
00370                 if (do_event_result == GENIE_EVENT_RXCHAR) {
00371                         timeout = t.read_ms() + _genieTimeout;
00372                         return;
00373                 }
00374                 
00375                 if (_genieGetLinkState() == GENIE_LINK_IDLE) {
00376                         return;
00377                 }
00378         }
00379         _genieError = ERROR_TIMEOUT;
00380         _handleError();
00381         return;
00382 }
00383 
00384 ///////////////////////// genieWriteObject //////////////////////
00385 //
00386 // Write data to an object on the display
00387 //
00388 uint16_t genieWriteObject (uint16_t object, uint16_t index, uint16_t data)
00389 {
00390         uint16_t msb, lsb ;
00391         uint8_t checksum ;
00392 
00393 
00394         _genieWaitForIdle();
00395 
00396 
00397         lsb = data&0xFF;
00398         msb = (data>>8) & 0xFF;
00399 
00400 
00401         _genieError = ERROR_NONE;
00402 
00403 
00404         _geniePutchar(GENIE_WRITE_OBJ) ; checksum  = GENIE_WRITE_OBJ ;
00405         _geniePutchar(object) ;          checksum ^= object ;
00406         _geniePutchar(index) ;           checksum ^= index ;
00407         _geniePutchar(msb) ;             checksum ^= msb;
00408         _geniePutchar(lsb) ;             checksum ^= lsb;
00409         _geniePutchar(checksum) ;
00410 
00411 
00412         _geniePushLinkState(GENIE_LINK_WFAN);        
00413 }
00414 
00415 /////////////////////// genieWriteContrast //////////////////////
00416 // 
00417 // Alter the display contrast (backlight)
00418 //
00419 // Parms:        uint8_t value: The required contrast setting, only
00420 //                values from 0 to 15 are valid. 0 or 1 for most displays
00421 //      and 0 to 15 for the uLCD-43
00422 //
00423 void genieWriteContrast (uint16_t value) {
00424         unsigned int checksum ;
00425 
00426 
00427         _genieWaitForIdle();
00428 
00429 
00430         _geniePutchar(GENIE_WRITE_CONTRAST) ; checksum  = GENIE_WRITE_CONTRAST ;
00431         _geniePutchar(value) ;                checksum ^= value ;
00432         _geniePutchar(checksum) ;
00433 
00434 
00435         _geniePushLinkState(GENIE_LINK_WFAN);
00436 
00437 
00438 }
00439 
00440 
00441 //////////////////////// _genieWriteStrX ///////////////////////
00442 //
00443 // Non-user function used by genieWriteStr() and genieWriteStrU()
00444 //
00445 static int _genieWriteStrX (uint16_t code, uint16_t index, char *string)
00446 {
00447         char *p ;
00448         unsigned int checksum ;
00449         int len = strlen (string) ;
00450 
00451 
00452         if (len > 255)
00453         return -1 ;
00454 
00455 
00456         _genieWaitForIdle();
00457 
00458 
00459         _geniePutchar(code) ;               checksum  = code ;
00460         _geniePutchar(index) ;              checksum ^= index ;
00461         _geniePutchar((unsigned char)len) ; checksum ^= len ;
00462         for (p = string ; *p ; ++p)        {
00463                 _geniePutchar (*p) ;
00464                 checksum ^= *p ;
00465         }
00466         _geniePutchar(checksum) ;
00467 
00468 
00469         _geniePushLinkState(GENIE_LINK_WFAN);
00470 
00471 
00472         return 0 ;
00473 }
00474 /////////////////////// genieWriteStr ////////////////////////
00475 //
00476 // Write a string to the display (ASCII)
00477 //
00478 uint16_t genieWriteStr (uint16_t index, char *string) {
00479  
00480   return _genieWriteStrX (GENIE_WRITE_STR, index, string);
00481 }
00482 
00483 
00484 /////////////////////// genieWriteStrU ////////////////////////
00485 //
00486 // Write a string to the display (Unicode)
00487 //
00488 uint16_t genieWriteStrU (uint16_t index, char *string) {
00489 
00490 
00491   return _genieWriteStrX (GENIE_WRITE_STRU, index, string);
00492 
00493 
00494 }
00495 /////////////////// genieAttachEventHandler //////////////////////
00496 //
00497 // "Attaches" a pointer to the users event handler by writing 
00498 // the pointer into the variable used by doEVents()
00499 //
00500 void genieAttachEventHandler (genieUserEventHandlerPtr handler) {
00501         _genieUserHandler = handler;
00502 }
00503 
00504 
00505 ////////////////////// _genieEnqueueEvent ///////////////////
00506 //
00507 // Copy the bytes from a buffer supplied by the caller 
00508 // to the input queue 
00509 //
00510 // Parms:        uint8_t * data, a pointer to the user's data
00511 //
00512 // Returns:        TRUE if there was an empty location in the queue
00513 //                                to copy the data into
00514 //                        FALSE if not
00515 // Sets:        ERROR_REPLY_OVR if there was no room in the queue
00516 //
00517 bool _genieEnqueueEvent (uint8_t * data) {
00518 
00519 
00520         if (_genieEventQueue.n_events < MAX_GENIE_EVENTS-2) {
00521                 memcpy (&_genieEventQueue.frames[_genieEventQueue.wr_index], data, 
00522                                 GENIE_FRAME_SIZE);
00523                 _genieEventQueue.wr_index++;
00524                 _genieEventQueue.wr_index &= MAX_GENIE_EVENTS -1;
00525                 _genieEventQueue.n_events++;
00526                 return TRUE;
00527         } else {
00528                 _genieError = ERROR_REPLY_OVR;
00529                 _handleError();
00530                 return FALSE;
00531         }
00532 }
00533 ///////////////////// _genieSetLinkState ////////////////////////
00534 //
00535 // Set the logical state of the link to the display.
00536 //
00537 // Parms:        uint16_t newstate, a value to be written to the 
00538 //                                link's _genieLinkState variable. Valid values are
00539 //                GENIE_LINK_IDLE                        0
00540 //                GENIE_LINK_WFAN                        1 // waiting for Ack or Nak
00541 //                GENIE_LINK_WF_RXREPORT        2 // waiting for a report frame
00542 //                GENIE_LINK_RXREPORT                3 // receiving a report frame
00543 //                GENIE_LINK_RXEVENT                4 // receiving an event frame
00544 //                GENIE_LINK_SHDN                        5
00545 //
00546 void _genieSetLinkState (uint16_t newstate) {
00547         
00548         *_genieLinkState = newstate;
00549 
00550 
00551         if (newstate == GENIE_LINK_RXREPORT || \
00552                 newstate == GENIE_LINK_RXEVENT)
00553                 rxframe_count = 0;        
00554 }
00555 
00556 
00557 /////////////////////// _genieGetLinkState //////////////////////
00558 //
00559 // Get the current logical state of the link to the display.
00560 //
00561 uint16_t _genieGetLinkState (void) {
00562         return *_genieLinkState;
00563 }
00564 
00565 /////////////////////// _geniePutchar ///////////////////////////
00566 //
00567 // Output the supplied character to the Genie display over 
00568 // the selected serial port
00569 //
00570 void _geniePutchar (uint8_t c) {
00571   //      if (screen != NULL)
00572                 screen.putc(c);
00573 }
00574 
00575 
00576 //////////////////////// _genieGetchar //////////////////////////
00577 //
00578 // Get a character from the selected Genie serial port
00579 //
00580 // Returns:        ERROR_NOHANDLER if an Rx handler has not 
00581 //                                been defined
00582 //                        ERROR_NOCHAR if no bytes have beeb received
00583 //                        The char if there was one to get
00584 // Sets:        _genieError with any errors encountered
00585 //
00586 uint8_t _genieGetchar() {
00587         uint16_t result;
00588 
00589 
00590         _genieError = ERROR_NONE;
00591 
00592         return (screen.getc());
00593 }
00594 
00595 void RxIrqHandler(void)
00596 {
00597     do 
00598     {
00599         genieDoEvents();
00600     }
00601     while(screen.readable ());
00602 }
00603 
00604 
00605 void TickerIrq(void)
00606 {
00607 }
00608 
00609 
00610 void SetupGenie(void)
00611 {
00612     screen.baud(115200);
00613     pc.baud(115200);
00614     screen.attach(&RxIrqHandler,Serial::RxIrq);
00615     t.start();
00616  //   EventChk.attach(&TickerIrq,0.05);
00617 }