Powrót do strony głównej.

Command line. Czyli jak "pogadać" z własnym procesorem.



Wcześniej czy później zachodzi potrzeba zapewnić interaktywność z własnym programem.
Pozwoliłem sobie więc na lekką kosmetykę programu dostepnego na stronie traktujacej
o procesorach 8051.

Program przedstawię w dwóch wersja. Pierwsza dla "normalnego" programu pracującego
w pętli, natomiast druga wersja bedzie działać z naszym systemem RoundRobin opisanym
w innym miejscu mojej strony.

A więc po kolei.

Wersja 1.


void main (void)
{
    while (1)
    {
        const char *cmd;

        cmdb_init ();        /* init a new command instance */
        cmdb_prompt ();        /* prompt for the command */

        for (cmd = NULL; cmd == NULL; cmd = cmdb_scan ())    /* get a command */
        {
            /* you can do something useful here */
        }

        cmd_proc (cmd);        /* process the command */
    }
}







plik: cmdbuild.c

#include <stdlib.h>
#include <ctype.h>
#include "cmd.h"
#include "uart.h"
#include "hwd.h"
#include <avr/io.h>
#include <avr/pgmspace.h>

char cmdbuf [1 + MAX_CMD_LEN];    /* command buffer */
unsigned char cmdndx;                /* command index */

/*---------------------------------------------------------------------- 
  --------
  Initialize the command buffer and index.
  ------------------------------------------------------------------------ 
  ------*/
void cmdb_init (void)
{
    cmdndx = 0;
    cmdbuf [0] = '\0';
}

/*---------------------------------------------------------------------- 
  --------
  Prompt for a command and display the current command buffer.  Note that the
  com_puts was not included in my previous example since it is so trivial.
  ------------------------------------------------------------------------ 
  ------*/

static char textCOMMAND[] PROGMEM="COMMAND: ";

void cmdb_prompt (void)
{
    uart_puts_p (textCOMMAND);
    uart_puts (cmdbuf);
}

/*---------------------------------------------------------------------- 
  Build a command string.  This functions gets characters from the serial
  buffer   and appends them to the end of the command buffer.  If no character is
  available the function returns NULL.  If a newline character is read, a pointer to
  the   buffer is returned.  Do NOT reinvoke this function before extracting the
  command from the buffer.
  ----------------------------------------------------------*/
const char *cmdb_scan (void)
{
    char c;
    unsigned char BUFOR_CMD;
    /*------------------------------------------------
      ------------------------------------------------*/
   
    while(1)
    {
        if (get_rx_buf_queue() > 0)    /* Sprawdzamy, czy w buforze okrężnym jest jakiś znak do pobrania */
            c= BUFOR_CMD;
        else
            //return NULL;
            break;                    // Exit NOW
           
        LED_AMBER_EXOR();

    if (c == '\r')                        /* Newline? */
        {
            uart_puts ("\r\n");           /* Output it and ... */
            return (cmdbuf);              /* Return the buffer address */
        }

        else if (c == '\b')               /* Czy to znak BS - backspace? */
        {
            if (cmdndx != 0)              // jeśli index >0 to
            {                        
                uart_puts ("\b \b");      // odeślij znak BS i
                cmdbuf [--cmdndx] = '\0'; // kasuj znak w buforze
            }
            else                          // w przeciwnym wypadku jeśli index==0 to
            {
                uart_putchar ('\a');      // daj znać dzwonkiem
            }
        }
        else if (cmdndx >= MAX_CMD_LEN)        // Jeśli przekroczona długość bufora to
        {
            uart_putchar ('\a');               // dzwonimy
        }
   
        else if (!isprint (c))                        /* Znak drukowalny? */
        {
            uart_putchar ('x');
        }
        else
        {
            uart_putchar (c);                        /* Output char */
            cmdbuf [cmdndx++] = (unsigned char) c;   /* Add to the buffer */
            cmdbuf [cmdndx]   = '\0';                /* NULL-Terminate buffer */
        }

    }
    return (NULL);
}


plik: cmdproc.c

/*------------------------------------------------
  The next series of functions were originally saved
  in the CMDPROC.C file.  These functions process
  a single command.
  ------------------------------------------------*/

#include <ctype.h>
#include <string.h>
#include "cmd.h"
#include "uart.h"
#include <avr/pgmspace.h>
#include <avr/wdt.h>
#include <util/delay.h>
#include <avr/wdt.h>
#include "hwd.h"

/*---------------------------------------------------------------------- 
  --------
  ------------------------------------------------------------------------ 
  ------*/
static char helptext [] PROGMEM=
"\r\n\r\n"
"HELP:\r\n"
"STMAC hhmmss -- Ustawia MAC karty\r\n"
"STCALL       -- Ustawia znak stacji SP0XYZ-15\r\n"
"STPASS       -- Haslo dla znaku\r\n"
"STALM hhmm   -- Set Alarm\r\n"
"RDEEP        -- Biezace ustawienia\r\n"
"POS_N        -- Pozycja N\r\n"
"POS_E        -- Pozycja E\r\n"
"EXIT         -- opuszczenie linii komend\r\n"
"\r\n";

/*---------------------------------------------------------------------- 
  --------
Commands:
HELP
STCLK HHMMSS
RDCLK
SCCLK
STALM HHMM
RDALM
CLALM
EXIT

Responses:
TIME: HH:MM:SS.HH    (current time)
ALARM: HH:MM        (alarm time)
<beep>            (alarm - for one minute only)
------------------------------------------------------------------------ 
------*/
enum
{
    CID_SET_CLK,
    CID_READ_CLK,
    CID_SCAN_CLK,

    CID_SET_ALM,
    CID_READ_ALM,
    CID_CLR_ALM,

    CID_EXIT,
    CID_LAST

};

struct cmd_st
{
    const char *cmdstr;
    unsigned char id;
};

static struct cmd_st cmd_tbl []  =
{
    { "STCLK",        CID_SET_CLK },
    { "RDCLK",        CID_READ_CLK },
    { "SCCLK",        CID_SCAN_CLK },
    { "STALM",        CID_SET_ALM },
    { "RDALM",        CID_READ_ALM },
    { "CLALM",        CID_CLR_ALM },
    { "EXIT",       CID_EXIT},
};

#define CMD_TBL_LEN (sizeof (cmd_tbl) / sizeof (cmd_tbl [0]))

/*---------------------------------------------------------------------- 
  --------
  This function searches the cmd_tbl for a specific command and returns the
  ID
  associated with that command or CID_LAST if there is no matching command.
  ------------------------------------------------------------------------ 
  ------*/
static unsigned char cmdid_search (char *cmdstr)
{
    struct cmd_st *ctp;

   
   // uart_puts(cmdstr);

    for (ctp = cmd_tbl; ctp < &cmd_tbl [CMD_TBL_LEN]; ctp++)
    {
        if (strlen(ctp->cmdstr) == strlen(cmdstr) &&
            strcmp (ctp->cmdstr, cmdstr) == 0)
            return (ctp->id);
    }

    return (CID_LAST);
}

/*---------------------------------------------------------------------- 
  --------
  No programmer's library would be complete without strupr!
  ------------------------------------------------------------------------ 
  ------*/
char *strupr (char *src)
{
    char *s;

    for (s = src; *s != '\0'; s++)
        *s = toupper (*s);

    return (src);
}

/*---------------------------------------------------------------------- 
 
  This function processes the cmd command.
  ---------------------------------------------------------------------- 
*/
void cmd_proc (const char *cmd)
{
    char cmdstr_buf [1 + MAX_CMD_LEN];
    char argstr_buf [1 + MAX_CMD_LEN];
    char *argsep;
    unsigned char id;
   
        char *p;
        char c;
    /*------------------------------------------------
      First, copy the command and convert it to all
      uppercase.
      ------------------------------------------------*/
    strncpy (cmdstr_buf, cmd, sizeof (cmdstr_buf) - 1);
    cmdstr_buf [sizeof (cmdstr_buf) - 1] = '\0';
    strupr (cmdstr_buf);



    /*------------------------------------------------
      Next, find the end of the first thing in the
      buffer.  Since the command ends with a space,
      we'll look for that.  NULL-Terminate the command
      and keep a pointer to the arguments.
      ------------------------------------------------*/
    argsep = strchr (cmdstr_buf, ' ');

    if (argsep == NULL)
    {
        argstr_buf [0] = '\0';
    }
    else
    {
        strcpy (argstr_buf, argsep + 1);
        *argsep = '\0';
    }

    /*------------------------------------------------
      Search for a command ID, then switch on it.  Note
      that I removed my action items for each command,
      but you would invoke each function here.
      ------------------------------------------------*/
    id = cmdid_search (cmdstr_buf);

    switch (id)
    {
        case CID_SET_CLK:
           
        break;
        case CID_READ_CLK:
           
        break;
        case CID_SCAN_CLK:
         
        break;
        case CID_SET_ALM:
           
        break;
        case CID_READ_ALM:
           
        break;
        case CID_CLR_ALM:
           
        break;
        case CID_EXIT:

       
//        deleteTask(5);      // opuszczenie obsługi linii komend
        break;

        case CID_LAST:
        uart_puts_p(helptext);  
        break;
       
    }
}

void COMMAND_LINE(void)
{
           
        static uint8_t i=0;


   
        while (1)
        {
            const char *cmd;

            cmdb_init ();        /* init a new command instance */
            cmdb_prompt ();        /* prompt for the command */
            uart_puts_p(helptext);

            for (cmd = NULL; cmd == NULL; cmd = cmdb_scan ())    /* get a command */
            {
               
            
                if (i==1000)
                {
                    LED_BLUE_EXOR(); // mrugamy diodą
                    i=0;
                }
                i++;
               
            }

             cmd_proc (cmd);        /* process the command */
        }
 

}

plik: cmd.h


#ifndef __CMD_H_
#define __CMD_H_

#define MAX_CMD_LEN 30

void cmdb_init (void);
void cmdb_prompt (void);
const char *cmdb_scan (void);
void cmd_proc (const char *cmd);
void COMMAND_LINE(void);

#endif




Wersja 2 - pracująca w systemie RR.



Najpierw powołujemy zadanie w funkcji main().
Ostatnia liczba w powołaniu TASK'u określa co jaki czas zadanie będzie wywoływane,
w tym wypadku będzie to 20*10[ms]. Biorąc pod uwagę szybkość transmisji
oraz szybkość z jaką możemy wpisywać komendy na klawiaturze to dochodzimy do wniosku, że nie ma sensu
wywoływać tego zadania częściej niż kilka razy na sekundę.

 addTask(5, TASK_COMMAND_LINE, 20);


w pliku cmdproc.c pojawia się zamiast funkcji COMMAND_LINE zadanie TASK_COMMAND_LINE()
o nieco zmienionej zawartości.

void TASK_COMMAND_LINE(void)
{
       
   
        static const char *cmd;
        static uint8_t i=0;

// pierwsze wywolanie linii komend
    if (!i)
    {
    // linia komend
       uart_puts ("\r\n");
       cmdb_init ();        // init a new command instance
       cmdb_prompt ();        // prompt for the command
       i=1;
     }

    
   
     if ((cmd = cmdb_scan ()) != NULL)
     {
          cmd_proc (cmd);
           
          if (getTaskStatus(5) != STOPPED) // zapobiegamy wyswietleniu COMMAND po likwidacji watku
          {
            uart_puts ("\r\n");            /* Output it and ... */
            cmdb_init ();                // init a new command instance
            cmdb_prompt ();      
          }
          else
            uart_puts ("Bye Bye...");            /* Zakonczenie zadania */
     }

      
        return;
}