Felipe Neves
/
ftf_mbed_lab3
ftf mbedos threads lab
main.cpp
- Committer:
- uLipe
- Date:
- 2016-11-05
- Revision:
- 1:e7266223f1fa
- Parent:
- 0:ead5ee0a33fa
File content as of revision 1:e7266223f1fa:
/** * @brief NXP FTF LAB3 - Mbed OS Threads control each thread execution */ #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 /** Instance a on board GLCD object */ ST7567 glcd(D11, D13, D12, D9, D10); /* allocate statically stacks for the three threads */ unsigned char app1_stk[1024]; unsigned char app2_stk[1024]; unsigned char app3_stk[1024]; unsigned char shell_stk[4096]; /* creates three tread objects with different priorities */ Thread app1_thread(osPriorityNormal, 1024, &app1_stk[0]); Thread app2_thread(osPriorityHigh, 1024, &app2_stk[0]); Thread app3_thread(osPriorityNormal, 1024, &app3_stk[0]); Thread shell_thread(osPriorityRealtime, 4096, &shell_stk[0]); /** Instance a UART class to communicate with pc */ Serial pc_serial(USBTX,USBRX); /** * @brief application demo task */ void app1_task(void) { const char thread_message[] = {"app1_task now running! \0"}; for(;;) { /* each thread has the same behavior * waits for a signal and when it asserted * executes and keep sending a signal_set * in order to suspend only when requested via * terminal */ app1_thread.signal_wait(1); app1_thread.signal_set(1); glcd.locate((LCD_WIDTH - (FONT_WIDTH * sizeof(thread_message)))/2, (LCD_HEIGHT - FONT_HEIGHT) / 2); glcd.printf(thread_message); } } /** * @brief application demo task */ void app2_task(void) { const char thread_message[] = {"app2_task now running! \0"}; for(;;) { app2_thread.signal_wait(1); app2_thread.signal_set(1); glcd.locate((LCD_WIDTH - (FONT_WIDTH * sizeof(thread_message)))/2, (LCD_HEIGHT - FONT_HEIGHT) / 2); glcd.printf(thread_message); } } /** * @brief application demo task */ void app3_task(void) { const char thread_message[] = {"app3_task now running! \0"}; for(;;) { app3_thread.signal_wait(1); app3_thread.signal_set(1); glcd.locate((LCD_WIDTH - (FONT_WIDTH * sizeof(thread_message)))/2, (LCD_HEIGHT - FONT_HEIGHT) / 2); glcd.printf(thread_message); } } /** * @brief thread_command interpreter */ void shell_thread_execute_command(int argc, char **argv){ Thread *ptr; /* check the argument number */ if(argc < 2) { pc_serial.printf("## thread: too few arguments, exiting \n\r"); return; } /* check which thread the shell command is claiming */ if(strcmp("app1", argv[0])== 0) { ptr = &app1_thread; }else if (strcmp("app2", argv[0])==0) { ptr = &app2_thread; } else if (strcmp("app3", argv[0])==0) { ptr = &app3_thread; }else { /* oops! invalid thread */ pc_serial.printf("## thread: invalid thread argument, exiting! \n\r"); return; } /* select which command */ if(strcmp("resume", argv[1])== 0) { glcd.cls(); ptr->signal_set(1); pc_serial.printf("## thread: Resuming the %s task! \n\r", argv[0]); }else if (strcmp("suspend", argv[1]) == 0) { glcd.cls(); ptr->signal_clr(1); pc_serial.printf("## thread: Suspending the %s task! \n\r", argv[0]); }else{ /* oops! invalid thread */ pc_serial.printf("## thread: invalid option argument, exiting! \n\r"); return; } } /** * @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("## thread <app1/2/3> <suspend|resume> : control thread execution \n\r"); pc_serial.printf("## app1/2/3: name of desired thread\n\r"); pc_serial.printf("## suspend: suspend selected thread from execution \n\r"); pc_serial.printf("## resume: resume selected thread execution \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("thread", cmd) == 0) { shell_thread_execute_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(">>"); } } } } static void idle_hook(void) { const char thread_message[] = {"No thread running!"}; glcd.locate((LCD_WIDTH - (FONT_WIDTH * sizeof(thread_message)))/2, (LCD_HEIGHT - FONT_HEIGHT) / 2); glcd.printf(thread_message); } /** * @brief main application loop */ int main(void) { glcd.cls(); /* starts the shell task and applications task*/ shell_thread.attach_idle_hook(idle_hook); shell_thread.start(shell_task); app1_thread.start(app1_task); app2_thread.start(app2_task); app3_thread.start(app3_task); return 0; }