ftf connects queue lab

Dependencies:   ST7567

Revision:
0:684e5d5adc13
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Sun Nov 06 16:54:35 2016 +0000
@@ -0,0 +1,459 @@
+/**
+ *  @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;
+}