ftf connects queue lab

Dependencies:   ST7567

main.cpp

Committer:
uLipe
Date:
2016-11-06
Revision:
0:684e5d5adc13

File content as of revision 0:684e5d5adc13:

/**
 *  @brief NXP FTF LAB3 - Mbed OS Queue message to control tasks
 */


#include "mbed.h"
#include "ST7567.h"
#include "rtos.h"

/* LCD screen dimensions */
#define LCD_HEIGHT          64
#define LCD_WIDTH           128

/* LCD font dimensions */
#define FONT_HEIGHT         10
#define FONT_WIDTH          5


/** led task command descriptor */
typedef struct  {
    int led_nbr;
    bool on_off;
    bool make_color;
    uint8_t color;

}led_cmd_desc_t;


/** glcd command descriptor */
typedef struct  {
    char message[64];
    int x;
    int y;
}glcd_cmd_desc_t;



/** Instance a on board GLCD object */
 ST7567 glcd(D11, D13, D12, D9, D10); 
 
 /* allocate statically stacks for the three threads */
unsigned char led_stk[1024];
unsigned char disp_stk[1024];
unsigned char shell_stk[8192];

/* creates three tread objects with different priorities */
Thread led_thread(osPriorityRealtime, 1024, &led_stk[0]);
Thread disp_thread(osPriorityRealtime, 1024, &disp_stk[0]);
Thread shell_thread(osPriorityNormal, 8192, &shell_stk[0]);

/* create two queues, one for led commands other to lcd commands */
Mail<led_cmd_desc_t, 16> led_q;
Mail<glcd_cmd_desc_t, 16> disp_q;


 /** Instance a UART class to communicate with pc */
Serial pc_serial(USBTX,USBRX);


/**
 * @brief application demo task 
 */
void led_task(void) {
    osEvent evt;
    DigitalOut leds[3] = {LED1, LED2, LED3};
    led_cmd_desc_t *cmd;

    
    leds[0] = leds[1] = leds[2] = 1;
    
    for(;;) {
 
        /* wait for a new command */
        evt = led_q.get(osWaitForever);
        if(evt.status != osEventMail) continue;                
        cmd = (led_cmd_desc_t *)evt.value.p;
        if(cmd == NULL) continue;
        
        
        
        if(cmd->make_color != true) {
                        
            /* is a led on_off command */
            if(cmd->on_off == true) {
                
                if(cmd->led_nbr == 0) {
                    /* handle all leds */
                    leds[0] = leds[1] = leds[2] = 0;    
                } else { 
                    /* handle specific led */
                    leds[cmd->led_nbr - 1] = 0;
                }                   
            } else {
                if(cmd->led_nbr == 0) {
                    /* handle all leds */
                    leds[0] = leds[1] = leds[2] = 1;    
                } else { 
                    /* handle specific led */
                    leds[cmd->led_nbr - 1] = 1;
                }                                   
            }
            
            /* free memory for next message */
            led_q.free(cmd);
 
        } else {
            /* is a make color command */
            int r, b, g;

            
            /* extract color bitfields */
            r = (cmd->color & 0x04 )>> 2;
            b = cmd->color & 0x01;
            g = (cmd->color & 0x02) >> 1;            
            
            leds[0] = ~(r) & 0x1;
            leds[1] = ~(b) & 0x1;
            leds[2] = ~(g) & 0x1;
            
            /* free memory for next message */
            led_q.free(cmd);

        }
        
    }
}

/**
 * @brief application demo task 
 */
void disp_task(void) {
    osEvent evt;
    glcd_cmd_desc_t *gl;
 
    for(;;) {
        /* wait for a new command */
        evt = disp_q.get(osWaitForever);
        /* check if not corrupted */
        if(evt.status != osEventMail) continue;                
        gl = (glcd_cmd_desc_t *)evt.value.p;
        if(gl == NULL) continue;
        
        /* check consistency */
        //pc_serial.printf("## %3d \n\r", gl->x);
        //pc_serial.printf("## %2d \n\r", gl->y);
        //pc_serial.printf("## %s \n\r", gl->message);

        
        
        glcd.cls();
        /* set the glcd cursor */
        glcd.locate(gl->x * FONT_WIDTH,  gl->y * FONT_HEIGHT);        
        /* and prints the message */
        glcd.printf("%s", gl->message);
        
        disp_q.free(gl);
    }
}




/**
 * @brief thread_command interpreter
 */
void shell_led_command(int argc, char **argv){
    led_cmd_desc_t *led_cmd = led_q.alloc();

    if(led_cmd == NULL) {
        pc_serial.printf("leds: FATAL! Not enough memory! \n\r");
        return;
    }
    if(argc < 1) {
        pc_serial.printf("## leds: too few arguments! \n\r");
        led_q.free(led_cmd);
        return;    
    }
    
    /* if has only one argument, the command can be  a color */
    if(argc == 1) {
        /* extract and limit the color value */
        sscanf(argv[0],"%d", &led_cmd->color);
        led_cmd->color &= 0x07;
        led_cmd->on_off = false;
        led_cmd->make_color = true;
    } else if(( argc > 1) && (argc <= 2)) {
        /* selects the led */
        if(strcmp("LED1", argv[0]) == 0) {
            led_cmd->led_nbr = 1;
        }else if(strcmp("LED2",argv[0]) == 0) {
            led_cmd->led_nbr = 2;            
        }else if(strcmp("LED3",argv[0]) == 0) {
            led_cmd->led_nbr = 3;
        }else if(strcmp("all",argv[0]) == 0) {
            led_cmd->led_nbr = 0;
        }else {
            pc_serial.printf("## leds: invalid led! \n\r");
            led_q.free(led_cmd);
            return;
        }
        
        
        /* take the action */
        if(strcmp("on", argv[1])== 0) {
            led_cmd->make_color = false;
            led_cmd->on_off = true;
        }else if (strcmp("off", argv[1])==0){
            led_cmd->make_color = false;
            led_cmd->on_off = false;
        } else {
            pc_serial.printf("## leds: invalid option! \n\r");
            led_q.free(led_cmd);
            return;
        }
    } else {
        pc_serial.printf("## leds: too many arguments! \n\r");
        led_q.free(led_cmd);
        return;
    }
    
    /* send the command descriptor to be executed in thread */
    led_q.put(led_cmd); 
    pc_serial.printf("## leds: running! \n\r");


}

/**
 * @brief parses the glcd commands 
 */
static void shell_disp_command(int argc, char **argv){
    glcd_cmd_desc_t *gl = disp_q.alloc();

    memset(&gl->message,0, 64);
    
    int position_x = 0;
    int position_y = 0;    
    
    if(argc < 3) {
        pc_serial.printf("display: Too few arguments, exiting \n\r");
        disp_q.free(gl);
    } else {
        sscanf(argv[0], "%3d", &gl->x);
        sscanf(argv[1], "%2d", &gl->y);

        /* check position range */
        if(position_x > 127 || position_x < 0) {
            pc_serial.printf("## display: Invalid arguments, exiting");    
            disp_q.free(gl);            
            return;
        }

        if(position_y > 63 || position_y < 0) {
            pc_serial.printf("## display: Invalid arguments, exiting");    
            disp_q.free(gl);
            return;
        }

        /* rebuild the string */
        for(int i = 0; i < (argc - 2); i++) {
            strcat(&gl->message[0], argv[2 + i]);
            strcat(&gl->message[0],(const char *)" ");
        }

        
        /* check consistency */
        //pc_serial.printf("## %3d \n\r", gl->x);
        //pc_serial.printf("## %2d \n\r", gl->y);
        //pc_serial.printf("## %s \n\r", gl->message);
        
        /* sends the text command to lcd task */
        disp_q.put(gl);
    }
}

/**
 * @brief show help menu 
 */
static void print_usage(void) {
    pc_serial.printf("## use with the syntax below:         \n\r");
    pc_serial.printf("## command <arg1> <arg2> ... <arg16>  \n\r");
    pc_serial.printf("## Available commands:                \n\r");
    pc_serial.printf ("## leds [LED1/2/3] [color1 -- 8] [on/off] : controls on board leds in multithread mode \n\r");
    pc_serial.printf ("## leds LED1 on                    : for example turns on led 1\n\r");
    pc_serial.printf ("## leds 5                          : for example show purple color \n\r"); 
    pc_serial.printf ("##\n\r");
    pc_serial.printf ("## disp <x>  <y> <message>         : prints a message on lcd \n\r"); 
    pc_serial.printf ("## disp 0 3 Hello world!           : prints hello world at 0 colunm and 3 row \n\r");      
}

 
/**
 * @brief parse the command received via comport
 */
static void shell_parser (char *cmd, int size) {
    int cmd_ptr = 0;
    int arg_ptr = 0;
    int cmd_size = 0;
    char command_buffer[256];
    
    int argc = 0;
    char *argv[16];    
    
    /* copy to the root command */
    memset(&command_buffer, 0, sizeof(command_buffer)); 
    
    /* find the root command terminator (space) */
    while(cmd_ptr < size) {
        if(cmd[cmd_ptr] == ' ') break;
        cmd_ptr++;
    }
    cmd_size = size - cmd_ptr;
    
    
    /* extract command arguments */
    strncpy(&command_buffer[0], &cmd[cmd_ptr + 1], (size - cmd_ptr));    
    
    /* terminates the root command */
    cmd[cmd_ptr] = 0;
    arg_ptr = 0;
    
    //pc_serial.printf("## command: %s \n\r", cmd);
    //pc_serial.printf("## arguments: %s \n\r", command_buffer);

  
    /* extract the further arguments */
    while(arg_ptr < (cmd_size)) {
 
        argc++;
        *(argv + (argc- 1)) = &command_buffer[arg_ptr];
 
        /* find terminator */
        while(command_buffer[arg_ptr] != ' ') {
            arg_ptr++;
        }
        
        /* adds to argument list */
        command_buffer[arg_ptr] = 0;
        arg_ptr++;       
       // pc_serial.printf("## argument no: %d : %s \n\r", argc, argv[argc-1]);
    }



    /* finds and execute the command table */
    if(strcmp("leds", cmd) == 0) { 
        shell_led_command(argc, argv);
    } else if(strcmp("disp", cmd) == 0){
        shell_disp_command(argc, argv);
    } else {
        print_usage();
    }    

}




/**
 * @brief shell commands processing thread 
 */
static void shell_task(void)
{
    char serial_buffer[1024] = {0};
    int read_ptr = 0;
    const char msg[] = {"Welcome to NXP FTF !\0"};
 
    /* setup the serial as 115200 bps */
    pc_serial.baud(115200);

/* setup our on-board glcd */
    glcd.set_contrast(0x35);
    glcd.cls();

   /* Center the LCD cursor based on message size*/
    glcd.locate(LCD_WIDTH - (sizeof(msg) * FONT_WIDTH), 
                    (LCD_HEIGHT - FONT_HEIGHT) / 2);

    
    /* prints a welcome message */
    glcd.printf(msg);
    
    glcd.cls();
    Thread::wait(1000);
    
  
    pc_serial.printf("******************************************************************\n\r");    
    pc_serial.printf("***         Welcome to NXP FTF Simple Shell application      ****\n\r");
    pc_serial.printf("*** Type some commands or just Enter key to see the available ****\n\r");
    pc_serial.printf("******************************************************************\n\r");            
    pc_serial.printf(">>");
    
    for(;;Thread::wait(50)) {        
        /* check if we have character available */
        if(pc_serial.readable()) {
            bool new_cmd = false;
            
            /* get the incoming character */
            char c = pc_serial.getc();
                       
            if( (c == '\n') || (c == '\r')) {
                /* handle enter key */
                new_cmd = true;
                pc_serial.printf("\n\r");
                
            }else if( (c == 0x7F) || (c == 0x08)){
                /* handle backspace and del keys */
                pc_serial.printf("\033[1D");
                pc_serial.putc(' ');
                pc_serial.printf("\033[1D");
                
                read_ptr--;
                if(read_ptr < -1) read_ptr = 1023;
                serial_buffer[read_ptr] = ' ';

                
            } else {
                /* loopback the pressed key */
                pc_serial.putc(c);
                
                /* store the incoming character on command circular buffer */
                serial_buffer[read_ptr] = c;
                read_ptr = (read_ptr + 1) % 1024;
            }
            
            
            
            if(new_cmd != false) {
                /* command arrived, has other characters? */
                if(read_ptr != 0) {
                    shell_parser(&serial_buffer[0], read_ptr);
                } else {
                    print_usage();
                }
                /* reset the buffer command */
                memset(&serial_buffer, 0, sizeof(serial_buffer));
                read_ptr = 0;
                pc_serial.printf(">>");
            } 

        }        
    }
}


/**
 * @brief main application loop
 */
int main(void) 
{   

    glcd.cls();

    /* starts the shell task and applications task*/
    shell_thread.start(shell_task);   
    led_thread.start(led_task);
    disp_thread.start(disp_task);
    return 0;
}