Experiment of serial command protocol

Dependencies:   RingBuffer SerialInterfaceProtocol duinotech_16x2_LCD mbed

You can edit this area

main.cpp

Committer:
rba90
Date:
2016-06-04
Revision:
0:2ba6a9f316b6
Child:
2:54932809c7b2

File content as of revision 0:2ba6a9f316b6:

#include "mbed.h"
#include "freetronicsLCDShield.h"
#include "buffer.h"
#include "CommandPacket.h"

// #define DEBUG_MESSAGE
 
freetronicsLCDShield lcd(D8, D9, D4, D5, D6, D7, D10, A0); // rs, e, d0, d1, d2, d3, bl, a0
Serial pc(USBTX, USBRX);
CircularBuffer<uint8_t> SerialBuffer;
CommandPacket SerialCommandProtocol;

void serialInterruptHandler() {
    // Note: you need to actually read from the serial to clear the RX interrupt
    int c = pc.getc();
    
    // add to buffer
    if (SerialBuffer.isLocked())
    {
        printf("Mutex Locked\r\n");
    }
    else
    {
        SerialBuffer.enqueue((uint8_t) c);   
    }
}

void lcdCommandController()
{   
    switch (SerialCommandProtocol.command & 0xf) // lower four bits
    {
        case 0x0: // turn on or off lcd back light
            lcd.setBackLight((bool) SerialCommandProtocol.payload[0]); 
            break;
        
        case 0x1: // adjust the duty cycle of lcd
            lcd.setBackLight((float) atof((char *)SerialCommandProtocol.payload));
            break;
            
        case 0x2: // clear the display and reset the cursor
            lcd.cls();
            break;
        
        case 0x3: // set current cursor position (line, col)
            lcd.setCursorPosition(
                SerialCommandProtocol.payload[0], 
                SerialCommandProtocol.payload[1]
            );
            break;
        
        case 0x4: // set cursor visible or not and if it blink
            lcd.setCursor(
                (bool) SerialCommandProtocol.payload[0],
                (bool) SerialCommandProtocol.payload[1]
            );
            break;            
            
        case 0x5: // print to line
            lcd.setCursorPosition(SerialCommandProtocol.payload[0], 0);
            lcd.printf((char *) &SerialCommandProtocol.payload[1]);
            break;
            
        case 0x6: // append text to current position
            lcd.printf((char *) SerialCommandProtocol.payload);
            break;
            
            
        default:
            break;
    }
}

void commandExecutor()
{
#ifdef DEBUG_MESSAGE
    printf("SFLAG: 0x%x\r\nCMD: 0x%x\r\nLEN: 0x%x\r\n",
        SerialCommandProtocol.sflag,
        SerialCommandProtocol.command,
        SerialCommandProtocol.length
    );
    
    printf("PL: ");
    for (int i = 0; i < SerialCommandProtocol.length; i++)
    {
        printf("0x%x ", SerialCommandProtocol.payload[i]);
    }
    printf("\r\n");
    
    printf("CS: 0x%x\r\nEFLAG: 0x%x\r\n", 
        SerialCommandProtocol.checksum,
        SerialCommandProtocol.eflag
    );
#endif
    // execute
    switch (SerialCommandProtocol.command >> 4) // higher four bits
    {
        case 0xf: // lcd control
            lcdCommandController();
            break;
            
        
        default:
            break;
    }
}

void commandDecoder()
{
    static CommandPacket::State_t state = CommandPacket::NONE;
    static uint8_t payload_counter = 0;
    
    while (SerialBuffer.getCounter() > 0)
    {
        uint8_t ch;
        ch = SerialBuffer.dequeue();
        
        // reset state to keep sync
        if (ch == CommandPacket::CP_SFLAG)
        {
            state = CommandPacket::SFLAG;
            
            // reset variable
            payload_counter = 0;
            memset(SerialCommandProtocol.payload, 0x0, sizeof(SerialCommandProtocol.payload));
        }
        
        switch (state)
        {
            case CommandPacket::SFLAG:
                SerialCommandProtocol.sflag = ch;
                state = CommandPacket::COMMAND_H;
#ifdef DEBUG_MESSAGE
                printf("CommandPacket::SFLAG: 0x%x\r\n", SerialCommandProtocol.sflag);
#endif
                break;
                
            case CommandPacket::COMMAND_H:
                SerialCommandProtocol.command = hexchar_to_uint8(ch) << 4;
                state = CommandPacket::COMMAND_L;
#ifdef DEBUG_MESSAGE
                printf("CommandPacket::COMMAND_H: 0x%x\r\n", SerialCommandProtocol.command);
#endif
                break;
                
            case CommandPacket::COMMAND_L:
                SerialCommandProtocol.command |= (hexchar_to_uint8(ch) & 0x0f);
                state = CommandPacket::LENGTH_H;
#ifdef DEBUG_MESSAGE
                printf("CommandPacket::COMMAND_L: 0x%x\r\n", SerialCommandProtocol.command);
#endif
                break;
                
            case CommandPacket::LENGTH_H:
                SerialCommandProtocol.length = hexchar_to_uint8(ch) << 4;
                state = CommandPacket::LENGTH_L;
#ifdef DEBUG_MESSAGE
                printf("CommandPacket::LENGTH_H: 0x%x\r\n", SerialCommandProtocol.length);
#endif
                break;
                
            case CommandPacket::LENGTH_L:
                SerialCommandProtocol.length |= (hexchar_to_uint8(ch) & 0x0f);
                if (SerialCommandProtocol.length != 0) // if the length is not zero, then proceed to payload state
                {
                    state = CommandPacket::PAYLOAD_H;
                }
                else // otherwise proceed to checksum state
                {
                    state = CommandPacket::CHECKSUM_H;
                }
#ifdef DEBUG_MESSAGE
                printf("CommandPacket::LENGTH_L: 0x%x\r\n", SerialCommandProtocol.length);
#endif
                break;
            
            case CommandPacket::PAYLOAD_H:
                SerialCommandProtocol.payload[payload_counter] = hexchar_to_uint8(ch) << 4; // store higher 4 bits of payload
                state = CommandPacket::PAYLOAD_L;
#ifdef DEBUG_MESSAGE
                printf("CommandPacket::PAYLOAD_H: 0x%x\r\n", SerialCommandProtocol.payload[payload_counter]);
#endif
                break;
                
            case CommandPacket::PAYLOAD_L:
                SerialCommandProtocol.payload[payload_counter++] |= (hexchar_to_uint8(ch) & 0x0f); // store lower 4 bits of payload
                if (payload_counter < SerialCommandProtocol.length) // append ch to payload until reach the length
                {
                    state = CommandPacket::PAYLOAD_H;
                }
                else
                {
                    state = CommandPacket::CHECKSUM_H;
                }
#ifdef DEBUG_MESSAGE
                printf("CommandPacket::PAYLOAD_L: 0x%x\r\n", SerialCommandProtocol.payload[payload_counter - 1]);
#endif
                break;
                
            case CommandPacket::CHECKSUM_H:
                SerialCommandProtocol.checksum = hexchar_to_uint8(ch) << 4;
                state = CommandPacket::CHECKSUM_L;
#ifdef DEBUG_MESSAGE
                printf("CommandPacket::CHECKSUM_H: 0x%x\r\n", SerialCommandProtocol.checksum);
#endif
                break;
                
            case CommandPacket::CHECKSUM_L:
                SerialCommandProtocol.checksum |= (hexchar_to_uint8(ch) & 0x0f);
                if (true) // disable the checksum 
                {
                    state = CommandPacket::EFLAG;
                }
                else
                {
                    SerialCommandProtocol.errno = CommandPacket::INVALID_CS_ERROR;
                    pc.printf("%s\r\n", SerialCommandProtocol.getErrorCode());
                    state = CommandPacket::NONE;
                }
#ifdef DEBUG_MESSAGE
                printf("CommandPacket::CHECKSUM_L: 0x%x\r\n", SerialCommandProtocol.checksum);
#endif
                break;
                
            case CommandPacket::EFLAG:
                if (ch == CommandPacket::CP_EFLAG)
                {
                    SerialCommandProtocol.eflag = ch;
                    
                    // TODO:: execute command here
                    commandExecutor();
                }
                state = CommandPacket::NONE;
#ifdef DEBUG_MESSAGE
                printf("CommandPacket::EFLAG: 0x%x\r\n", SerialCommandProtocol.eflag);
#endif
                break;
                
            case CommandPacket::NONE:
                SerialCommandProtocol.errno = CommandPacket::INVALID_SFLAG_ERROR;
                pc.printf("%s\r\n", SerialCommandProtocol.getErrorCode());
#ifdef DEBUG_MESSAGE
                printf("CommandPacket::NONE\r\n");
#endif
                break;
                
            default:
                break;
        }
    }
}
 
int main() {
    // turn on the back light (it's off by default)
    lcd.setBackLight(true);
    lcd.setCursor(true, true);
    lcd.cls();
    
    pc.attach(&serialInterruptHandler);
    
    while (1)
    {
        // button event
        switch (lcd.readButton())
        {
            case freetronicsLCDShield::BTN_SELECT:
                lcd.cls();
                break;
            case freetronicsLCDShield::BTN_UP:
                break;
            case freetronicsLCDShield::BTN_DOWN:
                break;
            case freetronicsLCDShield::BTN_LEFT:
                break;
            case freetronicsLCDShield::BTN_RIGHT:
                break;
            default:
                break;
        }
        
        
        commandDecoder();
    }
}