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-02-23
Revision:
2:f283764fe9b7
Parent:
1:95e0e194a412
Child:
3:11c49c49cd1a

File content as of revision 2:f283764fe9b7:


#include "mbed.h"
#include "mbed_genie.h"

Serial pc(USBTX,USBRX);

Mbed4dGenie::Mbed4dGenie(PinName TxPin,PinName RxPin) : _screen(TxPin,RxPin)
{
    _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) {
}




////////////////////// _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
                                    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;
            }
    }  
    return GENIE_EVENT_NONE; 
}