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-07-08
Revision:
10:4d9f1be4a901
Parent:
9:b74deaac80f9
Child:
11:9196f72fc325

File content as of revision 10:4d9f1be4a901:

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

Mbed4dGenie::Mbed4dGenie(PinName TxPin,PinName RxPin, PinName resetpin) : _screen(TxPin,RxPin) , _reset(resetpin)
{
    //reset the 4d screen
    _reset = 0;
    _screen.baud(9600);
    _genieUserHandler = NULL;
    RxStateTimeoutErrors = 0;
}
void Mbed4dGenie::Start()
{
    _reset = 1;
    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);
}

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

void Mbed4dGenie::RxIrqHandler(void)
{
    char c;
    //Loop to read all byte present in UART FIFO
    do
    {
        c = _screen.getc();
        if(_t.read_ms() >= RxMaxTimeout && state == CommInProgress)
        {
            Reset();
        }
        ManageReceiveData(c);
    }
    while(_screen.readable());
}

void Mbed4dGenie::ManageReceiveData(char data)
{
    switch(state)
    {
        case CommIdle: 
        
            if(data == GENIE_ACK || data == GENIE_NAK)
            {
                LastResponse = data;
            }   
            else if(data == GENIE_REPORT_OBJ || data == GENIE_REPORT_EVENT)
            {
                RxMaxTimeout = _t.read_ms() + RESYNC_PERIOD;
                checksum = data;
                rx_data[rxframe_count++] = data;
                state = CommInProgress;              
            }                     
            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
//
int8_t Mbed4dGenie::genieWriteObject (uint16_t object, uint16_t index, uint16_t data)
{
    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;
    
    _screen.putc(GENIE_WRITE_OBJ) ; 
    checksum  = GENIE_WRITE_OBJ ;
    _screen.putc(object) ;          
    checksum ^= object ;
    _screen.putc(index) ;           
    checksum ^= index ;
    _screen.putc(msb) ;             
    checksum ^= msb;
    _screen.putc(lsb) ;             
    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();
}
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) ;
        
    //Here we dont wiat for a typical answer
    //The screen will respond with an NACK if the command was not understood, otherwise it will send a report object frame    
    return  0;//WaitForReadAnswer();
}
void Mbed4dGenie::writec(char data)
{
    _screen.putc(data);
}
bool Mbed4dGenie::WaitForIdle()
{
    if(state != CommIdle)
    {
        long timeout = _t.read_ms() + TIMEOUT_PERIOD;
        long timerReading = 0;
        if(_t.read_ms() >= RxMaxTimeout)
        {
            Reset();
            RxStateTimeoutErrors++;
        }
        while(timerReading < timeout && state != CommIdle)
        {
            timerReading = _t.read_ms();
        }
        LastResponse = 0;
        return (timerReading >= timeout);
    }
    
    return false;    
}

int8_t Mbed4dGenie::WaitForReadAnswer()
{
    long timeout = _t.read_ms() + TIMEOUT_PERIOD;
    long timerReading = 0;
    while(state == CommIdle && LastResponse != ERROR_NAK && timerReading < timeout)
    {
        timerReading = _t.read_ms();
    }
    if(LastResponse == ERROR_NAK)//check if the screen returned a NACK
    {
        LastResponse = NO_RESPONSE;
        return ERROR_NAK;
    }
    else if(_t.read_ms() >= timeout) //check if we timed out while waiting for response
    {   
    
        LastResponse = NO_RESPONSE;
        return ERROR_TIMEOUT;
    }
    //if we get here it means we didnt timeout and the screen did accept the command
    LastResponse = NO_RESPONSE;
    return ERROR_NONE;
}

int8_t Mbed4dGenie::WaitForAnswer()
{
    
    long timeout = _t.read_ms() + TIMEOUT_PERIOD;
    long timerReading = 0;
    while(LastResponse != GENIE_ACK && LastResponse != ERROR_NAK && timerReading < timeout)
    {
        timerReading = _t.read_ms();
    }
           
    if(LastResponse == ERROR_NAK)
    {
        LastResponse = NO_RESPONSE;
        return ERROR_NAK;
    }
    else if(_t.read_ms() >= timeout)
    {   
        printf("Current timer:%d ; timeout:%d\n\r",_t.read_ms(),timeout);
        LastResponse = NO_RESPONSE;
        return ERROR_TIMEOUT;
    }
    LastResponse = NO_RESPONSE;
    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);
}