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);
    }
}

Files at this revision

API Documentation at this revision

Comitter:
chris215
Date:
Sat Jul 05 15:11:57 2014 +0000
Parent:
6:f4d3977b0eae
Child:
8:b5ba0df2d0db
Commit message:
Restored rx by interrupt feature. Added following features : read_obj, write_str, userHandler callback when frame is received. Ran stable for 12 hours.

Changed in this revision

mbed_genie.cpp Show annotated file Show diff for this revision Revisions of this file
mbed_genie.h Show annotated file Show diff for this revision Revisions of this file
--- a/mbed_genie.cpp	Fri Jul 04 02:44:49 2014 +0000
+++ b/mbed_genie.cpp	Sat Jul 05 15:11:57 2014 +0000
@@ -6,18 +6,79 @@
     //reset the 4d screen
     _reset = 0;
     _screen.baud(9600);
+    _genieUserHandler = NULL;
 }
 void Mbed4dGenie::Start()
 {
     _reset = 1;
-    wait(0.2);  //wait some time to let the lcd screen intialised itself
-    //empty the uart buffer
-    while(_screen.readable())
-        _screen.getc();
+    wait(3.0);  //4D datasheet says that the screen can take up to 3000 ms before
+                //becomming responsive to serial commands.        
+    _t.start();
+    Reset();
+    _genieFlushEventQueue();
+    _screen.attach(this,&Mbed4dGenie::RxIrqHandler,Serial::RxIrq);
+}
+
+
+void Mbed4dGenie::RxIrqHandler(void)
+{
+    char c;
+    //Loop to read all byte present in UART FIFO
+    do
+    {
+        c = _screen.getc();
+        ManageReceiveData(c);
+    }
+    while(_screen.readable());
+}
+
+void Mbed4dGenie::ManageReceiveData(char data)
+{
+    switch(state)
+    {
+        case CommIdle: 
         
-    _t.start();
+            if(data == GENIE_ACK || data == GENIE_NAK)
+            {
+                LastResponse = data;
+            }   
+            else if(data == GENIE_REPORT_OBJ || data == GENIE_REPORT_EVENT)
+            {
+                checksum = data;
+                rx_data[rxframe_count++] = data;
+                state = CommInProgress; 
+                LastResponse = NO_RESPONSE;             
+            }                     
+            break;
+        
+        
+        case CommInProgress: 
+            checksum = checksum ^ data;
+            rx_data[rxframe_count++] = data;
+            
+            if(rxframe_count >= GENIE_FRAME_SIZE)
+            {
+                if (checksum == 0) {
+                        _genieEnqueueEvent(rx_data); 
+                        if(_genieUserHandler != NULL)
+                        {
+                            (_genieUserHandler)();
+                        }
+                    } 
+                state = CommIdle;
+                rxframe_count = 0;
+                LastResponse = NO_RESPONSE;
+            }        
+            break;
+        default:
+            state = CommIdle;
+            rxframe_count = 0;
+            LastResponse = NO_RESPONSE;
+            break;
+    }
 }
 
+
 ///////////////////////// genieWriteObject //////////////////////
 //
 // Write data to an object on the display
@@ -27,6 +88,10 @@
     uint16_t msb, lsb ;
     uint8_t checksum ;
     
+    //wait for interface to be ready before sending stuff
+    if(WaitForIdle())
+        return ERROR_RESYNC;
+
     lsb = data&0xFF;
     msb = (data>>8) & 0xFF;
     
@@ -42,32 +107,159 @@
     checksum ^= lsb;
     _screen.putc(checksum) ;
     
-       
+     return Mbed4dGenie::WaitForAnswer();    
+}
+int8_t Mbed4dGenie::genieWriteStr (uint16_t index, char *string)
+{
+        char *p ;
+        unsigned int checksum ;
+        int len = strlen (string) ;
+
+
+        if (len > 255)
+        return -1 ;
+
+
+        //wait for interface to be ready before sending stuff
+        if(WaitForIdle())
+            return ERROR_RESYNC;
+
+
+        _screen.putc(GENIE_WRITE_STR) ;               checksum  = GENIE_WRITE_STR ;
+        _screen.putc(index) ;              checksum ^= index ;
+        _screen.putc((unsigned char)len) ; checksum ^= len ;
+        for (p = string ; *p ; ++p)        {
+                _screen.putc (*p) ;
+                checksum ^= *p ;
+        }
+        _screen.putc(checksum) ;
 
-     return  Mbed4dGenie::WaitForAnswer();    
+        return  Mbed4dGenie::WaitForAnswer();
+}
+int8_t  Mbed4dGenie::genieReadObj (uint16_t object, uint16_t index)
+{
+    //wait for interface to be ready before sending stuff
+    if(WaitForIdle())
+        return ERROR_RESYNC;
+    unsigned int checksum ;
+    
+    _screen.putc(GENIE_READ_OBJ) ;     checksum  = GENIE_READ_OBJ ;
+    _screen.putc(object) ;             checksum ^= object ;   
+    _screen.putc(index) ;              checksum ^= index ; 
+    _screen.putc(checksum) ;
+        
+    return  0;//Mbed4dGenie::WaitForAnswer();
 }
-
+void Mbed4dGenie::writec(char data)
+{
+    _screen.putc(data);
+}
+bool Mbed4dGenie::WaitForIdle()
+{
+    long timeout = _t.read_ms() + TIMEOUT_PERIOD;
+    long timerReading = 0;
+    
+    while(timerReading < timeout && state != CommIdle)
+    {
+        timerReading = _t.read_ms();
+    }
+    LastResponse = 0;
+    return (timerReading >= timeout);
+}
 
 int8_t Mbed4dGenie::WaitForAnswer()
 {
-    int8_t operation_result = 0; 
     
     long timeout = _t.read_ms() + TIMEOUT_PERIOD;
     long timerReading = 0;
-    while(operation_result != GENIE_ACK && operation_result != ERROR_NAK && timerReading < timeout)
+    while(LastResponse != GENIE_ACK && LastResponse != ERROR_NAK && timerReading < timeout)
     {
-        if(_screen.readable())
-            operation_result = _screen.getc();
         timerReading = _t.read_ms();
     }
            
-    if(operation_result == ERROR_NAK)
+    if(LastResponse == ERROR_NAK)
     {
         return ERROR_NONE;
     }
-    else if(timerReading >= timeout)
+    else if(LastResponse >= timeout)
     {   
         return ERROR_TIMEOUT;
     }
     return ERROR_NONE;
+}
+
+void Mbed4dGenie::Reset(void)
+{
+    LastResponse = NO_RESPONSE;
+    state = CommIdle;
+    while(_screen.readable())
+        _screen.getc();
+}
+
+////////////////////// _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;
+}
+
+////////////////////// _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 {
+                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;
+}
+void Mbed4dGenie::genieAttachEventHandler(genieUserEventHandlerPtr handler)
+{
+    _genieUserHandler = handler;
+}
+bool Mbed4dGenie::PendingFrames(void)
+{
+    return (_genieEventQueue.n_events>0);
 }
\ No newline at end of file
--- a/mbed_genie.h	Fri Jul 04 02:44:49 2014 +0000
+++ b/mbed_genie.h	Sat Jul 05 15:11:57 2014 +0000
@@ -1,3 +1,5 @@
+
+
 // Genie commands & replys:
 
 #define GENIE_ACK       0x06
@@ -83,8 +85,51 @@
 #define        FALSE        (!TRUE)
 #endif
 
+#define NO_RESPONSE     0
+
+#define     GENIE_FRAME_SIZE    6
+// Structure to store replys returned from a display
+struct genieFrameReportObj {
+    uint8_t     cmd;
+    uint8_t     object;
+    uint8_t     index;
+    uint8_t     data_msb;
+    uint8_t     data_lsb;
+};
+/////////////////////////////////////////////////////////////////////
+// The Genie frame definition
+//
+// The union allows the data to be referenced as an array of uint8_t
+// or a structure of type genieFrameReportObj, eg
+//
+//  genieFrame f;
+//  f.bytes[4];
+//  f.reportObject.data_lsb
+//
+//  both methods get the same byte
+//
+union genieFrame {
+    uint8_t             bytes[GENIE_FRAME_SIZE];
+    genieFrameReportObj reportObject;
+};
+#define MAX_GENIE_EVENTS    16  // MUST be a power of 2
+struct genieEventQueueStruct {
+    genieFrame  frames[MAX_GENIE_EVENTS];
+    uint8_t     rd_index;
+    uint8_t     wr_index;
+    uint8_t     n_events;
+};
+ 
+typedef void        (*genieUserEventHandlerPtr) (void); 
+
 class Mbed4dGenie{
     public:
+    
+    typedef enum{
+        CommIdle = 0,
+        CommInProgress = 1
+        }CommState;
+    
     /*
         Constructor to initialise the pins used to control the lcd screen
         Note: When the class is first initialised, the lcd screen will be put
@@ -95,23 +140,49 @@
         Deassert the reset pin and give some time to the lcd to 
         initialise itself before sending any commands.
     */
-    void Start();
+    void    Start();
+    void    Reset(void);
     /*
         Generic command to write data to a Genie object
         returns the status code of operation
     */
-    int8_t genieWriteObject (uint16_t object, uint16_t index, uint16_t data); 
+    int8_t  genieWriteObject (uint16_t object, uint16_t index, uint16_t data); 
+    int8_t  genieWriteStr (uint16_t index, char *string);
+    int8_t  genieReadObj (uint16_t object, uint16_t index);
+      
+    bool    genieDequeueEvent(genieFrame * buff);
+    void    genieAttachEventHandler (genieUserEventHandlerPtr handler);
+    bool    PendingFrames(void);
     
-    private:    
+    private:   
+    void    writec(char data); 
+    void    RxIrqHandler(void);
+    void    ManageReceiveData(char data);
+    bool    _genieEnqueueEvent (uint8_t * data);
+    void    _genieFlushEventQueue(void);
     /*
         Wait for the screen to aknowledge the command
         returns the status code of operation
     */
-    int8_t WaitForAnswer();
+    int8_t  WaitForAnswer();
+    bool    WaitForIdle();   
     
-    
+    //////////////////////////////////////////////////////////////
+    // A structure to hold up to MAX_GENIE_EVENTS events receive
+    // from the display
+    //
+    genieEventQueueStruct _genieEventQueue;
+    uint8_t     rxframe_count;
+    uint8_t     rx_data[GENIE_FRAME_SIZE];
+    uint8_t     checksum;
+    //////////////////////////////////////////////////////////////
+    // Pointer to the user's event handler function
+    //
+    genieUserEventHandlerPtr _genieUserHandler;
     
     Serial _screen;
     DigitalOut _reset;
     Timer _t;
+    int             state; 
+    int            LastResponse; 
     };
\ No newline at end of file