diff options
author | Alexey 'Cluster' Avdyukhin <clusterrr@clusterrr.com> | 2018-12-16 07:01:49 +0300 |
---|---|---|
committer | Alexey 'Cluster' Avdyukhin <clusterrr@clusterrr.com> | 2018-12-16 07:01:49 +0300 |
commit | 01b2f44bd5c15e591e40dd76f784beccf5cdff6b (patch) | |
tree | abf97106a98c989c79792a015cea077796b2e0d9 | |
parent | ee44314e53b62ea5f48b76dd2222d2a3a11b33ac (diff) |
-rw-r--r-- | clunet.c | 489 | ||||
-rw-r--r-- | clunet.h | 2 |
2 files changed, 243 insertions, 248 deletions
@@ -1,5 +1,5 @@ /* Name: clunet.c - * Project: CLUNET network driver + * Project: CLUNET bus driver * Author: Alexey Avdyukhin * Creation Date: 2013-09-09 * License: DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE @@ -17,27 +17,25 @@ void (*on_data_received)(uint8_t src_address, uint8_t dst_address, uint8_t command, char* data, uint8_t size) = 0; void (*on_data_received_sniff)(uint8_t src_address, uint8_t dst_address, uint8_t command, char* data, uint8_t size) = 0; -volatile uint8_t clunetSendingState = CLUNET_SENDING_STATE_IDLE; -volatile uint8_t clunetSendingDataLength; -volatile uint8_t clunetSendingCurrentByte; -volatile uint8_t clunetSendingCurrentBit; -volatile uint8_t clunetReadingState = CLUNET_READING_STATE_IDLE; -volatile uint8_t clunetReadingCurrentByte; -volatile uint8_t clunetReadingCurrentBit; -volatile uint8_t clunetCurrentPrio; - +volatile uint8_t clunet_sending_state = CLUNET_SENDING_STATE_IDLE; +volatile uint8_t clunet_sending_data_length; +volatile uint8_t clunet_sending_current_byte; +volatile uint8_t clunet_sending_current_bit; +volatile uint8_t clunet_reading_state = CLUNET_READING_STATE_IDLE; +volatile uint8_t clunet_reading_current_byte; +volatile uint8_t clunet_reading_current_bit; +volatile uint8_t clunet_sending_priority; volatile uint8_t clunetTimerStart = 0; - -volatile char dataToSend[CLUNET_SEND_BUFFER_SIZE]; -volatile char dataToRead[CLUNET_READ_BUFFER_SIZE]; +volatile char out_buffer[CLUNET_SEND_BUFFER_SIZE]; +volatile char in_buffer[CLUNET_READ_BUFFER_SIZE]; static inline void clunet_start_send() { - clunetSendingState = CLUNET_SENDING_STATE_INIT; - // подождем 1.5Т, чтобы нас гарантированно могли остановить при передаче на линии со стороны другого устройства в процедуре внешнего прерывания - CLUNET_TIMER_REG_OCR = CLUNET_TIMER_REG + (CLUNET_T + CLUNET_T / 2); - CLUNET_ENABLE_TIMER_COMP; // Включаем прерывание сравнения таймера (передачу) + clunet_sending_state = CLUNET_SENDING_STATE_INIT; + // подождем 1.5Т, чтобы нас гарантированно могли остановить при передаче на линии со стороны другого устройства в процедуре внешнего прерывания + CLUNET_TIMER_REG_OCR = CLUNET_TIMER_REG + (CLUNET_T + CLUNET_T / 2); + CLUNET_ENABLE_TIMER_COMP; // Включаем прерывание сравнения таймера (передачу) } static inline char @@ -62,273 +60,270 @@ check_crc(const char* data, const uint8_t size) static inline void clunet_data_received(const uint8_t src_address, const uint8_t dst_address, const uint8_t command, char* data, const uint8_t size) { - if (on_data_received_sniff) - (*on_data_received_sniff)(src_address, dst_address, command, data, size); - - if (src_address == CLUNET_DEVICE_ID) return; // Игнорируем сообщения от самого себя! - - if ((dst_address != CLUNET_DEVICE_ID) && - (dst_address != CLUNET_BROADCAST_ADDRESS)) return; // Игнорируем сообщения не для нас - - // Команда перезагрузки. Перезагрузим по сторожевому таймеру - if (command == CLUNET_COMMAND_REBOOT) - { - cli(); - set_bit(WDTCR, WDE); - while(1); - } - - if ((clunetSendingState == CLUNET_SENDING_STATE_IDLE) || (clunetCurrentPrio <= CLUNET_PRIORITY_MESSAGE)) - { - /* Ответ на поиск устройств */ - if (command == CLUNET_COMMAND_DISCOVERY) - { + if (on_data_received_sniff) + (*on_data_received_sniff)(src_address, dst_address, command, data, size); + + if (src_address == CLUNET_DEVICE_ID) return; // Игнорируем сообщения от самого себя! + + if ((dst_address != CLUNET_DEVICE_ID) && + (dst_address != CLUNET_BROADCAST_ADDRESS)) return; // Игнорируем сообщения не для нас + + // Команда перезагрузки. Перезагрузим по сторожевому таймеру + if (command == CLUNET_COMMAND_REBOOT) + { + cli(); + set_bit(WDTCR, WDE); + while(1); + } + + if ((clunet_sending_state == CLUNET_SENDING_STATE_IDLE) || (clunet_sending_priority <= CLUNET_PRIORITY_MESSAGE)) + { + /* Ответ на поиск устройств */ + if (command == CLUNET_COMMAND_DISCOVERY) + { #ifdef CLUNET_DEVICE_NAME - char buf[] = CLUNET_DEVICE_NAME; - uint8_t len = 0; while(buf[len]) len++; - clunet_send(src_address, CLUNET_PRIORITY_MESSAGE, CLUNET_COMMAND_DISCOVERY_RESPONSE, buf, len); + char buf[] = CLUNET_DEVICE_NAME; + uint8_t len = 0; while(buf[len]) len++; + clunet_send(src_address, CLUNET_PRIORITY_MESSAGE, CLUNET_COMMAND_DISCOVERY_RESPONSE, buf, len); #else - clunet_send(src_address, CLUNET_PRIORITY_MESSAGE, CLUNET_COMMAND_DISCOVERY_RESPONSE, 0, 0); + clunet_send(src_address, CLUNET_PRIORITY_MESSAGE, CLUNET_COMMAND_DISCOVERY_RESPONSE, 0, 0); #endif - } - /* Ответ на пинг */ - else if (command == CLUNET_COMMAND_PING) - clunet_send(src_address, CLUNET_PRIORITY_COMMAND, CLUNET_COMMAND_PING_REPLY, data, size); - } - - if (on_data_received) - (*on_data_received)(src_address, dst_address, command, data, size); - + } + /* Ответ на пинг */ + else if (command == CLUNET_COMMAND_PING) + clunet_send(src_address, CLUNET_PRIORITY_COMMAND, CLUNET_COMMAND_PING_REPLY, data, size); + } + + if (on_data_received) + (*on_data_received)(src_address, dst_address, command, data, size); } /* Процедура прерывания сравнения таймера */ ISR(CLUNET_TIMER_COMP_VECTOR) { - /* Если достигли фазы завершения передачи, то завершим ее и освободим передатчик */ - if (clunetSendingState == CLUNET_SENDING_STATE_DONE) - { - CLUNET_DISABLE_TIMER_COMP; // Выключаем прерывание сравнения таймера - clunetSendingState = CLUNET_SENDING_STATE_IDLE; // Указываем, что передатчик свободен - CLUNET_SEND_0; // Отпускаем линию - } - /* Иначе если передачу необходимо продолжить, то сначала проверим на конфликт */ - else if (!CLUNET_SENDING && CLUNET_READING) - { - CLUNET_DISABLE_TIMER_COMP; // Выключаем прерывание сравнения таймера (передачу) - clunetSendingState = CLUNET_SENDING_STATE_WAITING_LINE; // Переходим в режим ожидания линии - } - /* Все в порядке, можем продолжать */ - else - { - CLUNET_SEND_INVERT; // Инвертируем значение сигнала - - /* Если отпустили линию, то запланируем время паузы перед следующей передачей длительностью 1Т */ - if (!CLUNET_SENDING) - CLUNET_TIMER_REG_OCR += CLUNET_T; - - /* Если прижали линию к земле, то запланируем время передачи сигнала в зависимости от текущей фазы передачи */ - /* Фаза передачи данных */ - else if (clunetSendingState == CLUNET_SENDING_STATE_DATA) - { - /* Планируем следующее прерывание в зависимости от значения бита */ - CLUNET_TIMER_REG_OCR += ((dataToSend[clunetSendingCurrentByte] & (1 << clunetSendingCurrentBit)) ? CLUNET_1_T : CLUNET_0_T); - /* Если передан байт данных */ - if (++clunetSendingCurrentBit & 8) - { - /* Если не все данные отосланы */ - if (++clunetSendingCurrentByte < clunetSendingDataLength) - clunetSendingCurrentBit = 0; // начинаем передачу следующего байта с бита 0 - /* Иначе передача всех данных закончена */ - else - clunetSendingState++; // переходим к следующей фазе завершения передачи пакета - } - } - else - switch (clunetSendingState++) - { - /* Фаза инициализации передачи пакета (время 10Т) */ - case CLUNET_SENDING_STATE_INIT: - CLUNET_TIMER_REG_OCR += CLUNET_INIT_T; - break; - /* Фаза передачи приоритета (старший бит) */ - case CLUNET_SENDING_STATE_PRIO1: - CLUNET_TIMER_REG_OCR += ((clunetCurrentPrio > 2) ? CLUNET_1_T : CLUNET_0_T); - break; - /* Фаза передачи приоритета (младший бит) */ - case CLUNET_SENDING_STATE_PRIO2: - CLUNET_TIMER_REG_OCR += ((clunetCurrentPrio & 1) ? CLUNET_0_T : CLUNET_1_T); - clunetSendingCurrentByte = clunetSendingCurrentBit = 0; // Готовим счётчики передачи данных - } - } + /* Если достигли фазы завершения передачи, то завершим ее и освободим передатчик */ + if (clunet_sending_state == CLUNET_SENDING_STATE_DONE) + { + CLUNET_DISABLE_TIMER_COMP; // Выключаем прерывание сравнения таймера + clunet_sending_state = CLUNET_SENDING_STATE_IDLE; // Указываем, что передатчик свободен + CLUNET_SEND_0; // Отпускаем линию + } + /* Иначе если передачу необходимо продолжить, то сначала проверим на конфликт */ + else if (!CLUNET_SENDING && CLUNET_READING) + { + CLUNET_DISABLE_TIMER_COMP; // Выключаем прерывание сравнения таймера (передачу) + clunet_sending_state = CLUNET_SENDING_STATE_WAITING_LINE; // Переходим в режим ожидания линии + } + /* Все в порядке, можем продолжать */ + else + { + CLUNET_SEND_INVERT; // Инвертируем значение сигнала + + /* Если отпустили линию, то запланируем время паузы перед следующей передачей длительностью 1Т */ + if (!CLUNET_SENDING) + CLUNET_TIMER_REG_OCR += CLUNET_T; + + /* Если прижали линию к земле, то запланируем время передачи сигнала в зависимости от текущей фазы передачи */ + /* Фаза передачи данных */ + else if (clunet_sending_state == CLUNET_SENDING_STATE_DATA) + { + /* Планируем следующее прерывание в зависимости от значения бита */ + CLUNET_TIMER_REG_OCR += ((out_buffer[clunet_sending_current_byte] & (1 << clunet_sending_current_bit)) ? CLUNET_1_T : CLUNET_0_T); + /* Если передан байт данных */ + if (++clunet_sending_current_bit & 8) + { + /* Если не все данные отосланы */ + if (++clunet_sending_current_byte < clunet_sending_data_length) + clunet_sending_current_bit = 0; // начинаем передачу следующего байта с бита 0 + /* Иначе передача всех данных закончена */ + else + clunet_sending_state++; // переходим к следующей фазе завершения передачи пакета + } + } + else + switch (clunet_sending_state++) + { + /* Фаза инициализации передачи пакета (время 10Т) */ + case CLUNET_SENDING_STATE_INIT: + CLUNET_TIMER_REG_OCR += CLUNET_INIT_T; + break; + /* Фаза передачи приоритета (старший бит) */ + case CLUNET_SENDING_STATE_PRIO1: + CLUNET_TIMER_REG_OCR += ((clunet_sending_priority > 2) ? CLUNET_1_T : CLUNET_0_T); + break; + /* Фаза передачи приоритета (младший бит) */ + case CLUNET_SENDING_STATE_PRIO2: + CLUNET_TIMER_REG_OCR += ((clunet_sending_priority & 1) ? CLUNET_0_T : CLUNET_1_T); + clunet_sending_current_byte = clunet_sending_current_bit = 0; // Готовим счётчики передачи данных + } + } } void clunet_send(const uint8_t address, const uint8_t prio, const uint8_t command, const char* data, const uint8_t size) { - /* Если размер данных в пределах буфера передачи (максимально для протокола 250 байт) */ - if (size < (CLUNET_SEND_BUFFER_SIZE - CLUNET_OFFSET_DATA)) - { - /* Прерываем текущую передачу, если есть такая */ - if (clunetSendingState) - { - CLUNET_DISABLE_TIMER_COMP; - CLUNET_SEND_0; - } - - /* Заполняем переменные */ - clunetCurrentPrio = (prio > 4) ? 4 : prio ? : 1; // Ограничим приоритет диапазоном (1 ; 4) - dataToSend[CLUNET_OFFSET_SRC_ADDRESS] = CLUNET_DEVICE_ID; - dataToSend[CLUNET_OFFSET_DST_ADDRESS] = address; - dataToSend[CLUNET_OFFSET_COMMAND] = command; - dataToSend[CLUNET_OFFSET_SIZE] = size; - - /* Копируем данные в буфер */ - uint8_t i; - for (i = 0; i < size; i++) - dataToSend[CLUNET_OFFSET_DATA + i] = data[i]; - - /* Добавляем контрольную сумму */ - dataToSend[CLUNET_OFFSET_DATA + size] = check_crc((char*)dataToSend, CLUNET_OFFSET_DATA + size); - - clunetSendingDataLength = size + (CLUNET_OFFSET_DATA + 1); - - // Если линия свободна, то запланируем передачу сразу - if (!CLUNET_READING) - clunet_start_send(); - // Иначе будем ожидать когда освободится в процедуре внешнего прерывания - else - clunetSendingState = CLUNET_SENDING_STATE_WAITING_LINE; - - } + /* Если размер данных в пределах буфера передачи (максимально для протокола 250 байт) */ + if (size < (CLUNET_SEND_BUFFER_SIZE - CLUNET_OFFSET_DATA)) + { + /* Прерываем текущую передачу, если есть такая */ + if (clunet_sending_state) + { + CLUNET_DISABLE_TIMER_COMP; + CLUNET_SEND_0; + } + + /* Заполняем переменные */ + clunet_sending_priority = (prio > 4) ? 4 : prio ? : 1; // Ограничим приоритет диапазоном (1 ; 4) + out_buffer[CLUNET_OFFSET_SRC_ADDRESS] = CLUNET_DEVICE_ID; + out_buffer[CLUNET_OFFSET_DST_ADDRESS] = address; + out_buffer[CLUNET_OFFSET_COMMAND] = command; + out_buffer[CLUNET_OFFSET_SIZE] = size; + + /* Копируем данные в буфер */ + uint8_t i; + for (i = 0; i < size; i++) + out_buffer[CLUNET_OFFSET_DATA + i] = data[i]; + + /* Добавляем контрольную сумму */ + out_buffer[CLUNET_OFFSET_DATA + size] = check_crc((char*)out_buffer, CLUNET_OFFSET_DATA + size); + + clunet_sending_data_length = size + (CLUNET_OFFSET_DATA + 1); + + // Если линия свободна, то запланируем передачу сразу + if (!CLUNET_READING) + clunet_start_send(); + // Иначе будем ожидать когда освободится в процедуре внешнего прерывания + else + clunet_sending_state = CLUNET_SENDING_STATE_WAITING_LINE; + } } /* Процедура внешнего прерывания по фронту и спаду сигнала */ ISR(CLUNET_INT_VECTOR) { - - uint8_t now = CLUNET_TIMER_REG; // Текущие значение таймера - - /* Если линию прижало к нулю */ - if (CLUNET_READING) - { - clunetTimerStart = now; // Запомним время начала сигнала - /* Если мы в режиме передачи и прижали не мы, то замолкаем и ожидаем, тем более, что наши передаваемые данные уже битые */ - /* Обеспечивается быстрая отработка ошибки на линии во избежание конфликтов */ - if (clunetSendingState && !CLUNET_SENDING) - { - CLUNET_DISABLE_TIMER_COMP; - clunetSendingState = CLUNET_SENDING_STATE_WAITING_LINE; - } - } - - /* Иначе если линию отпустило */ - else - { - /* Линия свободна, пробуем запланировать отправку */ - if (clunetSendingState == CLUNET_SENDING_STATE_WAITING_LINE) - clunet_start_send(); - - uint8_t ticks = now - clunetTimerStart; // Вычислим время сигнала в тиках таймера - - /* Если кто-то долго жмёт линию (время >= 6.5Т) - это инициализация */ - if (ticks >= (CLUNET_INIT_T + CLUNET_1_T) / 2) - clunetReadingState = CLUNET_READING_STATE_PRIO1; - - /* Иначе если недолго, то смотрим на этап */ - else - switch (clunetReadingState) - { - - /* Чтение данных */ - case CLUNET_READING_STATE_DATA: - - /* Если бит значащий (время > 2Т), то установим его в приемном буфере */ - if (ticks > (CLUNET_0_T + CLUNET_1_T) / 2) - dataToRead[clunetReadingCurrentByte] |= (1 << clunetReadingCurrentBit); - - /* Инкрементируем указатель бита, и при полной обработке всех 8 бит в байте выполним: */ - if (++clunetReadingCurrentBit & 8) - { - - /* Проверка на окончание чтения пакета */ - if ((++clunetReadingCurrentByte > CLUNET_OFFSET_SIZE) && (clunetReadingCurrentByte > dataToRead[CLUNET_OFFSET_SIZE] + CLUNET_OFFSET_DATA)) - { - - clunetReadingState = CLUNET_READING_STATE_IDLE; - - /* Проверяем CRC, при успехе начнем обработку принятого пакета */ - if (!check_crc((char*)dataToRead, clunetReadingCurrentByte)) - clunet_data_received ( - dataToRead[CLUNET_OFFSET_SRC_ADDRESS], - dataToRead[CLUNET_OFFSET_DST_ADDRESS], - dataToRead[CLUNET_OFFSET_COMMAND], - (char*)(dataToRead + CLUNET_OFFSET_DATA), - dataToRead[CLUNET_OFFSET_SIZE] - ); - - } - - /* Иначе если пакет не прочитан и буфер не закончился - подготовимся к чтению следующего байта */ - else if (clunetReadingCurrentByte < CLUNET_READ_BUFFER_SIZE) - { - clunetReadingCurrentBit = 0; - dataToRead[clunetReadingCurrentByte] = 0; - } - - /* Иначе - нехватка приемного буфера -> игнорируем пакет */ - else - clunetReadingState = CLUNET_READING_STATE_IDLE; - - } - break; - - /* Получение приоритета (младший бит), клиенту он не нужен */ - case CLUNET_READING_STATE_PRIO2: - clunetReadingCurrentByte = clunetReadingCurrentBit = 0; - dataToRead[0] = 0; - - /* Получение приоритета (старший бит), клиенту он не нужен */ - case CLUNET_READING_STATE_PRIO1: - clunetReadingState++; - - } - } + uint8_t now = CLUNET_TIMER_REG; // Текущие значение таймера + + /* Если линию прижало к нулю */ + if (CLUNET_READING) + { + clunetTimerStart = now; // Запомним время начала сигнала + /* Если мы в режиме передачи и прижали не мы, то замолкаем и ожидаем, тем более, что наши передаваемые данные уже битые */ + /* Обеспечивается быстрая отработка ошибки на линии во избежание конфликтов */ + if (clunet_sending_state && !CLUNET_SENDING) + { + CLUNET_DISABLE_TIMER_COMP; + clunet_sending_state = CLUNET_SENDING_STATE_WAITING_LINE; + } + } + /* Иначе если линию отпустило */ + else + { + /* Линия свободна, пробуем запланировать отправку */ + if (clunet_sending_state == CLUNET_SENDING_STATE_WAITING_LINE) + clunet_start_send(); + + uint8_t ticks = now - clunetTimerStart; // Вычислим время сигнала в тиках таймера + + /* Если кто-то долго жмёт линию (время >= 6.5Т) - это инициализация */ + if (ticks >= (CLUNET_INIT_T + CLUNET_1_T) / 2) + { + clunet_reading_state = CLUNET_READING_STATE_PRIO1; + } + /* Иначе если недолго, то смотрим на этап */ + else + switch (clunet_reading_state) + { + + /* Чтение данных */ + case CLUNET_READING_STATE_DATA: + + /* Если бит значащий (время > 2Т), то установим его в приемном буфере */ + if (ticks > (CLUNET_0_T + CLUNET_1_T) / 2) + in_buffer[clunet_reading_current_byte] |= (1 << clunet_reading_current_bit); + + /* Инкрементируем указатель бита, и при полной обработке всех 8 бит в байте выполним: */ + if (++clunet_reading_current_bit & 8) + { + + /* Проверка на окончание чтения пакета */ + if ((++clunet_reading_current_byte > CLUNET_OFFSET_SIZE) && (clunet_reading_current_byte > in_buffer[CLUNET_OFFSET_SIZE] + CLUNET_OFFSET_DATA)) + { + + clunet_reading_state = CLUNET_READING_STATE_IDLE; + + /* Проверяем CRC, при успехе начнем обработку принятого пакета */ + if (!check_crc((char*)in_buffer, clunet_reading_current_byte)) + clunet_data_received ( + in_buffer[CLUNET_OFFSET_SRC_ADDRESS], + in_buffer[CLUNET_OFFSET_DST_ADDRESS], + in_buffer[CLUNET_OFFSET_COMMAND], + (char*)(in_buffer + CLUNET_OFFSET_DATA), + in_buffer[CLUNET_OFFSET_SIZE] + ); + + } + + /* Иначе если пакет не прочитан и буфер не закончился - подготовимся к чтению следующего байта */ + else if (clunet_reading_current_byte < CLUNET_READ_BUFFER_SIZE) + { + clunet_reading_current_bit = 0; + in_buffer[clunet_reading_current_byte] = 0; + } + + /* Иначе - нехватка приемного буфера -> игнорируем пакет */ + else + clunet_reading_state = CLUNET_READING_STATE_IDLE; + + } + break; + + /* Получение приоритета (младший бит), клиенту он не нужен */ + case CLUNET_READING_STATE_PRIO2: + clunet_reading_current_byte = clunet_reading_current_bit = 0; + in_buffer[0] = 0; + + /* Получение приоритета (старший бит), клиенту он не нужен */ + case CLUNET_READING_STATE_PRIO1: + clunet_reading_state++; + break; + } + } } void clunet_init() { - sei(); - CLUNET_SEND_INIT; - CLUNET_READ_INIT; - CLUNET_TIMER_INIT; - CLUNET_INIT_INT; - char reset_source = MCUCSR; - clunet_send ( - CLUNET_BROADCAST_ADDRESS, - CLUNET_PRIORITY_MESSAGE, - CLUNET_COMMAND_BOOT_COMPLETED, - &reset_source, - sizeof(reset_source) - ); - MCUCSR = 0; + sei(); + CLUNET_SEND_INIT; + CLUNET_READ_INIT; + CLUNET_TIMER_INIT; + CLUNET_INIT_INT; + char reset_source = MCUCSR; + clunet_send ( + CLUNET_BROADCAST_ADDRESS, + CLUNET_PRIORITY_MESSAGE, + CLUNET_COMMAND_BOOT_COMPLETED, + &reset_source, + sizeof(reset_source) + ); + MCUCSR = 0; } /* Возвращает 0, если готов к передаче, иначе приоритет текущей задачи */ uint8_t clunet_ready_to_send() { - return clunetSendingState ? clunetCurrentPrio : 0; + return clunet_sending_state ? clunet_sending_priority : 0; } void clunet_set_on_data_received(void (*f)(uint8_t src_address, uint8_t dst_address, uint8_t command, char* data, uint8_t size)) { - on_data_received = f; + on_data_received = f; } void clunet_set_on_data_received_sniff(void (*f)(uint8_t src_address, uint8_t dst_address, uint8_t command, char* data, uint8_t size)) { - on_data_received_sniff = f; + on_data_received_sniff = f; } @@ -33,7 +33,7 @@ #define CLUNET_OFFSET_DATA 4 #define CLUNET_BROADCAST_ADDRESS 255 -#define CLUNET_COMMAND_DISCOVERY 0 +#define CLUNET_COMMAND_DISCOVERY 0x00 /* Поиск других устройств, параметров нет */ #define CLUNET_COMMAND_DISCOVERY_RESPONSE 0x01 |