Jump to content

    
Sign in to follow this  
Alex_Golubev

Switch и прием команд

Recommended Posts

Добрый день.

Подскажите как проще всего распознать входную команду составленную из нескольких байт и выполнить необходимое действие? 

Пример.

У нас на входе есть последовательность байт вида:

пришла команда 0x01 0x02 0x01 -> вызываем обработчик команды 0x01 0x02 0x01

пришла команда 0x01 0x02 0x02 -> вызываем обработчик команды 0x01 0x02 0x02

пришла команда 0x01 0x02 0x03 -> вызываем обработчик команды 0x01 0x02 0x03

пришла команда 0x01 0x03 0x01 -> вызываем обработчик команды 0x01 0x03 0x01

пришла команда 0x03 0x03 0x01 -> вызываем обработчик команды 0x03 0x03 0x01

и так далее. 

На if else не охота будет много ветвлений и плохо читабельный код. 

С помощью хэш тоже не охота из - за коллизии. 

Share this post


Link to post
Share on other sites

if ((Command[0]==0x01)&&(Command[1]==0x02)&&(Command[2]==0x01)) {

//обработчик
}

else if ((Command[0]==0x01)&&(Command[1]==0x02)&&(Command[2]==0x02)) {

//обработчик
}

Где тут проблема с читаемостью?

 

Share this post


Link to post
Share on other sites
18 minutes ago, Priest_89 said:

Где тут проблема с читаемостью?

1. Неудобно выискивать и проверять коды в тексте

2. Забитые вручную индексы - лишний источник опечаток

3. Про скобки вообще молчу

 

По-моему, так много лучше:

{
    {0x01, 0x02, 0x03, &f1},
    {0x01, 0x01, 0x03, &f2},
    {0x02, 0x02, 0x03, &f3},
}

 

Share this post


Link to post
Share on other sites

Соглашусь с aaarrr, лучше соответствие всех команд и их кодов описать в одном месте, например:

void command_a();
void command_b(); // функции-обработчики команд
void command_c();

typedef struct // структура, объединяющая массив с кодом команды и функцией-обработчиком
{
    char code[3];
    void (*pfunc)();
} Command;

Command commands[] = // всё описано в одном месте
{
    {{0x01, 0x02, 0x01}, command_a},
    {{0x01, 0x02, 0x02}, command_b},
    {{0x01, 0x03, 0x01}, command_c},
};

bool parse_command(char *input_command)
{
    int commadns_number = sizeof(commands) / sizeof(commands[0]);
  
    for (int i = 0; i < commadns_number; i++) // ищем в списке команд
    {
        if (memcmp(input_command, commands[i].code, 3))
        {
            commands[i].pfunc(); // вызов функции-обработчика
            return true;
        }
    }

    return false;  // команда не найдена в списке комманд
}

 

 

Share this post


Link to post
Share on other sites

Если формат пакета фиксированый и не планируется его расширение как по формату, так и по функциям - табличный вариант, который приводили выше.

Я бы также не исключал switch-case в этом случае.

Если формат "изменчивый", то, IMHO, будет не просто его описать в унифицированной таблице или она будет очень избыточной.

Если формат пакетов меняется (дополняется), и требуется потоковая обработка принятых байт "на лету" (например в векторе прерывания)

опять же IMHO, принимаемые байты считать событиями для FSM. Как будет FSM реализовано - на switch или иначе - не принципиально.

 

 

 

Share this post


Link to post
Share on other sites

Спасём отца русской демократии:  :umnik2:

enum {
  API_K_type, API_K_cfg, API_K_addr,
  API_K_success, API_K_error, API_K_version, API_K_title, API_K_dive,
  API_K_scale, API_K_mode, API_K_min, API_K_max, API_K_offset,
  ...
  API_K_n
};

#define apiKeyLen  12 //[байт]

char const apiKeys[apiKeyLen * API_K_n + 1] __attribute__ ((aligned (4))) =
  "type        " //API_K_type
  "cfg         " //API_K_cfg
  "addr        " //API_K_addr
  "success     " //API_K_success
  "error       " //API_K_error
  "version     " //API_K_version
  "title       " //API_K_title
  "dive        " //API_K_dive
  "scale       " //API_K_scale
  "mode        " //API_K_mode
  "min         " //API_K_min
  "max         " //API_K_max
  "offset      " //API_K_offset
  ...
;

void (* const cmdHandler[API_K_n])(char const *cmdTail) = {
  CmdType,       //API_K_type
  CmdCfg,        //API_K_cfg
  CmdAddr,       //API_K_addr
  ...
};

 

Share this post


Link to post
Share on other sites
1 hour ago, arhiv6 said:

Соглашусь с aaarrr, лучше соответствие всех команд и их кодов описать в одном месте, например:

а потом ещё заменить перебор на бинарный поиск.

и если ограничиться 3-4 байтными командами, то среди uint32_t значений 0x010102, 0x010201, ... а не строк.

 

Share this post


Link to post
Share on other sites
22 minutes ago, jcxz said:

Спасём отца русской демократии:  :umnik2: . . . 

enum {
  API_K_type, API_K_cfg, API_K_addr,
  API_K_success, API_K_error, API_K_version, API_K_title, API_K_dive,
  API_K_scale, API_K_mode, API_K_min, API_K_max, API_K_offset,
  ...
  API_K_n
};


struct_array[] = 
{
	[API_K_type] = { 0x01, 0x02, 0x03, &fun_1 },
	[API_K_cfg]  = { 0x21, 0x12, 0x13, &fun_2 },
	[API_K_addr] = { 0x31, 0x22, 0x23, &fun_3 },
. . . .
}

Это "прокатывает" для IAR. Очень удобный формат, можно произвольно добавлять-удалять занчения из enum, менять местами очередность итп.

Если ошибка - ее покажет сразу компилятор, а не придется юлозить исходник и искать места, где требуется поменять индексы массива.

 

Share this post


Link to post
Share on other sites
4 hours ago, aaarrr said:

По-моему, так много лучше:


{
    {0x01, 0x02, 0x03, &f1},
    {0x01, 0x01, 0x03, &f2},
    {0x02, 0x02, 0x03, &f3},
}

 

Алгоритм полного перебора?
Полагаете три байта на команду сделано для того чтобы три команды передать. 
И ТС про хэши вспомнил просто потому что слово такое знает? 

Что-то мне кажется вопрос не так прост. 

Начать надо как минимум с n-D таблицы.

Share this post


Link to post
Share on other sites

 

7 minutes ago, AlexandrY said:

Полагаете три байта на команду сделано для того чтобы три команды передать. 

Мне известны в том числе и такие протоколы.

Share this post


Link to post
Share on other sites
17 minutes ago, aaarrr said:

Мне известны в том числе и такие протоколы.

Ну и мне известны. Это обычный CAN.
Но делать табличный поиск простым перебором в CAN-е - последнее дело.  

Share this post


Link to post
Share on other sites
14 hours ago, Alex_Golubev said:

Добрый день.

С помощью хэш тоже не охота из - за коллизии. 

Добрый день! Если памяти не жалко, можете std::map использовать. Ключом будет ваша последовательность из трёх байт, а вторым параметром указатель на обработчик.

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Sign in to follow this