Felipe Neves
/
ftf_mbed_lab5
ftf connects queue lab
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; }