ftf mbedos threads lab

Dependencies:   ST7567

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;
}