Перейти к содержанию
    

Добрый день.

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

Пример.

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

пришла команда 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 не охота будет много ветвлений и плохо читабельный код. 

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

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

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

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

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

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

18 minutes ago, Priest_89 said:

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

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

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

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

 

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

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

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Соглашусь с 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;  // команда не найдена в списке комманд
}

 

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

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

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

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

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

 

 

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Спасём отца русской демократии:  :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
  ...
};

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

1 hour ago, arhiv6 said:

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

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

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

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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, менять местами очередность итп.

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

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

2 hours ago, k155la3 said:

Это "прокатывает" для IAR

И для gcc (откуда, собственно, "это" пришло), и для чего угодно современного.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

4 hours ago, aaarrr said:

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


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

 

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

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

 

7 minutes ago, AlexandrY said:

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

17 minutes ago, aaarrr said:

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

1 hour ago, AlexandrY said:

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

Поясните наглядным примером.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

14 hours ago, Alex_Golubev said:

Добрый день.

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...