From ad9fa4ad26182767dd0ced09d0dba2a986fa922b Mon Sep 17 00:00:00 2001 From: Alexey 'Cluster' Avdyukhin Date: Sun, 16 Dec 2018 07:01:14 +0300 Subject: Done. --- Makefile | 3 + clunet.c | 410 +++++++++++++++++++++++++++++++++++---------------------------- clunet.h | 137 +++++++++++++++++++++ 3 files changed, 367 insertions(+), 183 deletions(-) diff --git a/Makefile b/Makefile index 5b0332e..62df8d0 100644 --- a/Makefile +++ b/Makefile @@ -5,3 +5,6 @@ all: clean: make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean + +install: all + cp -f clunet.ko /lib/modules/$(shell uname -r)/ diff --git a/clunet.c b/clunet.c index 7c5862a..f7cf2f0 100644 --- a/clunet.c +++ b/clunet.c @@ -5,25 +5,25 @@ #include #include #include -#include #include #include #include #include #include #include -#include #include "clunet.h" MODULE_LICENSE("GPL"); MODULE_AUTHOR("Cluster"); MODULE_DESCRIPTION("CLUNET driver"); +// Module parameters static u8 receive_pin = 2; static u8 transmit_pin = 3; static u8 transmit_value = 1; static u8 clunet_t = 64; static u8 address = 0; +static char* device_name = "Linux CLUNET driver"; module_param(receive_pin, byte, 0); MODULE_PARM_DESC(receive_pin,"CLUNET receiver pin number (default 2)"); module_param(transmit_pin, byte, 0); @@ -33,9 +33,11 @@ MODULE_PARM_DESC(transmit_value,"0 = direct send logic, 1 = inverse send logic ( module_param(clunet_t, byte, 0); MODULE_PARM_DESC(clunet_t,"CLUNET bit 0 length (default 64us)"); module_param(address, byte, 0); -MODULE_PARM_DESC(clunet_t,"Local address (default 0)"); -static u8 clunet_sending = 0; -static unsigned int irqNumber = 0xffff; +MODULE_PARM_DESC(address,"Local address (default 0)"); +module_param(device_name, charp, 0); +MODULE_PARM_DESC(device_name,"Local device name"); + +static unsigned int irq_number = 0xffff; static struct class* clunet_class = NULL; static struct device* clunet_bus_device = NULL; static struct cdev clunet_bus_cdev; @@ -47,20 +49,20 @@ static struct file* opened_files[MAX_OPENED_FILES]; static DECLARE_WAIT_QUEUE_HEAD(wq_data); static DEFINE_MUTEX(m_wait_for_line); static struct hrtimer* data_send_timer = NULL; - -static u8 clunetSendingState = CLUNET_SENDING_STATE_IDLE; -static u8 clunetSendingDataLength; -static u8 clunetSendingCurrentByte; -static u8 clunetSendingCurrentBit; -static u8 dataToSend[CLUNET_SEND_BUFFER_SIZE]; static u64 last_rising_time = 0; static u64 last_falling_time = 0; -static u8 clunetReadingState = CLUNET_READING_STATE_IDLE; -static u8 clunetReadingCurrentByte = 0; -static u8 clunetReadingCurrentBit = 0; -static u8 dataToRead[CLUNET_READ_BUFFER_SIZE]; -static u8 recvPriority = 0; -static u8 sendPriority; +static u8 clunet_sending = 0; +static u8 clunet_sending_state = CLUNET_SENDING_STATE_IDLE; +static u8 clunet_sending_priority; +static u8 clunet_sending_data_length; +static u8 clunet_sending_current_byte; +static u8 clunet_sending_current_bit; +static u8 out_buffer[CLUNET_SEND_BUFFER_SIZE]; +static u8 clunet_reading_state = CLUNET_READING_STATE_IDLE; +static u8 clunet_reading_priority = 0; +static u8 clunet_reading_current_byte = 0; +static u8 clunet_reading_current_bit = 0; +static u8 in_buffer[CLUNET_READ_BUFFER_SIZE]; static u8 check_crc(const char* data, const uint8_t size) { @@ -85,14 +87,15 @@ static void set_send_timer(u16 t) if (data_send_timer) { hrtimer_try_to_cancel(data_send_timer); - hrtimer_start(data_send_timer, ktime_set(0, t * 1000UL), HRTIMER_MODE_REL); + if (t) + hrtimer_start(data_send_timer, ktime_set(0, t * 1000UL), HRTIMER_MODE_REL); } } static void clunet_set_line(u8 value) { - clunet_sending = value; - gpio_direction_output(transmit_pin, value ? transmit_value : !transmit_value); + clunet_sending = value; + gpio_direction_output(transmit_pin, value ? transmit_value : !transmit_value); } static void clunet_data_received(const uint8_t prio, const uint8_t src_address, const uint8_t dst_address, const uint8_t command, char* data, const uint8_t size) @@ -101,16 +104,18 @@ static void clunet_data_received(const uint8_t prio, const uint8_t src_address, char* buffer; int d_address; buffer = kmalloc(2 + 3 + 3 + 3 + size * 2 + 1 + 1, GFP_ATOMIC); // 'P SR DS CM DATA\n0' - if (!buffer) - { - printk(KERN_ERR "CLUNET: can't allocatate memory"); - return; - } - sprintf(buffer, "%d %02X %02X %02X ", prio, src_address, dst_address, command); + if (!buffer) + { + printk(KERN_ERR "CLUNET: can't allocatate memory"); + return; + } + sprintf(buffer, "%d %02X %02X %02X ", prio, src_address, dst_address, command); for (i = 0; i < size; i++) sprintf(buffer + 2 + 3 + 3 + 3 + i*2, "%02X", data[i]); strcat(buffer, "\n"); +#ifdef CLUNET_DEBUG printk(KERN_DEBUG "CLUNET received: %s", buffer); +#endif p = 0; while (buffer[p]) { @@ -118,19 +123,40 @@ static void clunet_data_received(const uint8_t prio, const uint8_t src_address, { d_address = ((struct cfile_t*)opened_files[i]->private_data)->device_address; if ((d_address < 0) // bus devices - || (src_address == d_address// source address matched - && (dst_address == address // destination address is my address - || dst_address == CLUNET_BROADCAST_ADDRESS) // or broadcast address - && p >= 2 + 3 + 3) // skip 'P SR DS ' + || ((src_address == d_address) // source address matched + && ((dst_address == address) // destination address is my address + || (dst_address == CLUNET_BROADCAST_ADDRESS)) // or broadcast address + && (p >= 2 + 3 + 3)) // skip 'P SR DS ' ) ((struct cfile_t*)opened_files[i]->private_data)->receiver_buffer[ ((struct cfile_t*)opened_files[i]->private_data)->receiver_write_pos++ - % RECEIVER_BUFFER_SIZE] = buffer[p]; + % RECEIVER_BUFFER_SIZE] = buffer[p]; } - p++; + p++; }; - kfree(buffer); - wake_up_interruptible(&wq_data); + kfree(buffer); + + /* Some reserved commands */ + if (((dst_address == address) // destination address is my address + || (dst_address == CLUNET_BROADCAST_ADDRESS)) // or broadcast address + && ((clunet_sending_state == CLUNET_SENDING_STATE_IDLE) // Not busy + || (clunet_sending_priority <= CLUNET_PRIORITY_MESSAGE)) // Or not very busy + ) + { + /* Ответ на поиск устройств */ + if (command == CLUNET_COMMAND_DISCOVERY) + { + uint8_t len = 0; while(device_name[len]) len++; + clunet_send(address, src_address, CLUNET_PRIORITY_MESSAGE, CLUNET_COMMAND_DISCOVERY_RESPONSE, device_name, len); + } + /* Ответ на пинг */ + else if (command == CLUNET_COMMAND_PING) + { + clunet_send(address, src_address, CLUNET_PRIORITY_COMMAND, CLUNET_COMMAND_PING_REPLY, data, size); + } + } + + wake_up_interruptible(&wq_data); } static irq_handler_t clunet_irq_handler(unsigned int irq, void *dev_id, struct pt_regs *regs) @@ -138,24 +164,40 @@ static irq_handler_t clunet_irq_handler(unsigned int irq, void *dev_id, struct p u64 now = ktime_to_us(ktime_get_boottime()); u8 value = CLUNET_READING; uint64_t ticks; - if (!value && last_falling_time > 0) // high + if (value && last_rising_time > 0) + { + ticks = now - last_rising_time; // Idle time + if (clunet_reading_state != CLUNET_READING_STATE_IDLE + && ticks >= CLUNET_IDLE_TIMEOUT_T) // Timeout + { + clunet_reading_state = CLUNET_READING_STATE_IDLE; + printk(KERN_WARNING "CLUNET recv timeout\n"); + } + if (clunet_sending_state && !clunet_sending) // Collision + { + /* Stop transmission and wait for line */ + set_send_timer(0); + clunet_sending_state = CLUNET_SENDING_STATE_WAITING_LINE; + } + } + else if (!value && last_falling_time > 0) // high { /* Линия свободна, пробуем запланировать отправку */ - if (clunetSendingState == CLUNET_SENDING_STATE_WAITING_LINE) - { - clunetSendingState = CLUNET_SENDING_STATE_INIT; - set_send_timer(CLUNET_1_T); - } + if (clunet_sending_state == CLUNET_SENDING_STATE_WAITING_LINE) + { + clunet_sending_state = CLUNET_SENDING_STATE_INIT; + set_send_timer(CLUNET_SEND_PAUSE_T); + } ticks = now - last_falling_time; // Вычислим время сигнала /* Если кто-то долго жмёт линию (время >= 6.5Т) - это инициализация */ if (ticks >= (CLUNET_INIT_T + CLUNET_1_T) / 2) - clunetReadingState = CLUNET_READING_STATE_PRIO1; + clunet_reading_state = CLUNET_READING_STATE_PRIO1; /* Иначе если недолго, то смотрим на этап */ else - switch (clunetReadingState) + switch (clunet_reading_state) { /* Чтение данных */ @@ -163,47 +205,47 @@ static irq_handler_t clunet_irq_handler(unsigned int irq, void *dev_id, struct p /* Если бит значащий (время > 2Т), то установим его в приемном буфере */ if (ticks > (CLUNET_0_T + CLUNET_1_T) / 2) - dataToRead[clunetReadingCurrentByte] |= (1 << clunetReadingCurrentBit); + in_buffer[clunet_reading_current_byte] |= (1 << clunet_reading_current_bit); /* Инкрементируем указатель бита, и при полной обработке всех 8 бит в байте выполним: */ - if (++clunetReadingCurrentBit & 8) + if (++clunet_reading_current_bit & 8) { /* Проверка на окончание чтения пакета */ - if ((++clunetReadingCurrentByte > CLUNET_OFFSET_SIZE) && (clunetReadingCurrentByte > dataToRead[CLUNET_OFFSET_SIZE] + CLUNET_OFFSET_DATA)) + if ((++clunet_reading_current_byte > CLUNET_OFFSET_SIZE) && (clunet_reading_current_byte > in_buffer[CLUNET_OFFSET_SIZE] + CLUNET_OFFSET_DATA)) { - clunetReadingState = CLUNET_READING_STATE_IDLE; + clunet_reading_state = CLUNET_READING_STATE_IDLE; /* Проверяем CRC, при успехе начнем обработку принятого пакета */ - if (!check_crc((char*)dataToRead + CLUNET_OFFSET_SRC_ADDRESS, clunetReadingCurrentByte - CLUNET_OFFSET_SRC_ADDRESS)) + if (!check_crc((char*)in_buffer + CLUNET_OFFSET_SRC_ADDRESS, clunet_reading_current_byte - CLUNET_OFFSET_SRC_ADDRESS)) clunet_data_received ( - recvPriority, - dataToRead[CLUNET_OFFSET_SRC_ADDRESS], - dataToRead[CLUNET_OFFSET_DST_ADDRESS], - dataToRead[CLUNET_OFFSET_COMMAND], - (char*)(dataToRead + CLUNET_OFFSET_DATA), - dataToRead[CLUNET_OFFSET_SIZE] + clunet_reading_priority, + 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 printk(KERN_WARNING "CLUNET CRC error: prio %d from %02X to %02X cmd %02X size %d\n", - recvPriority, - dataToRead[CLUNET_OFFSET_SRC_ADDRESS], - dataToRead[CLUNET_OFFSET_DST_ADDRESS], - dataToRead[CLUNET_OFFSET_COMMAND], - dataToRead[CLUNET_OFFSET_SIZE]); + clunet_reading_priority, + in_buffer[CLUNET_OFFSET_SRC_ADDRESS], + in_buffer[CLUNET_OFFSET_DST_ADDRESS], + in_buffer[CLUNET_OFFSET_COMMAND], + in_buffer[CLUNET_OFFSET_SIZE]); } /* Иначе если пакет не прочитан и буфер не закончился - подготовимся к чтению следующего байта */ - else if (clunetReadingCurrentByte < CLUNET_READ_BUFFER_SIZE) + else if (clunet_reading_current_byte < CLUNET_READ_BUFFER_SIZE) { - clunetReadingCurrentBit = 0; - dataToRead[clunetReadingCurrentByte] = 0; + clunet_reading_current_bit = 0; + in_buffer[clunet_reading_current_byte] = 0; } /* Иначе - нехватка приемного буфера -> игнорируем пакет */ else { - clunetReadingState = CLUNET_READING_STATE_IDLE; + clunet_reading_state = CLUNET_READING_STATE_IDLE; printk(KERN_ERR "CLUNET out of revc buffer\n"); } } @@ -212,32 +254,24 @@ static irq_handler_t clunet_irq_handler(unsigned int irq, void *dev_id, struct p /* Получение приоритета (младший бит), клиенту он не нужен */ case CLUNET_READING_STATE_PRIO2: /* Если бит значащий (время > 2Т), то установим его в приемном буфере */ - clunetReadingState++; + clunet_reading_state++; if (ticks > (CLUNET_0_T + CLUNET_1_T) / 2) - recvPriority |= 1; - recvPriority++; - clunetReadingCurrentByte = CLUNET_OFFSET_SRC_ADDRESS; - clunetReadingCurrentBit = 0; - dataToRead[CLUNET_OFFSET_SRC_ADDRESS] = 0; + clunet_reading_priority |= 1; + clunet_reading_priority++; + clunet_reading_current_byte = CLUNET_OFFSET_SRC_ADDRESS; + clunet_reading_current_bit = 0; + in_buffer[CLUNET_OFFSET_SRC_ADDRESS] = 0; break; /* Получение приоритета (старший бит), клиенту он не нужен */ case CLUNET_READING_STATE_PRIO1: - clunetReadingState++; + clunet_reading_state++; /* Если бит значащий (время > 2Т), то установим его в приемном буфере */ if (ticks > (CLUNET_0_T + CLUNET_1_T) / 2) - recvPriority = 1 << 1; + clunet_reading_priority = 1 << 1; else - recvPriority = 0; + clunet_reading_priority = 0; } - } else { - ticks = now - last_rising_time; // Idle time - if (clunetReadingState != CLUNET_READING_STATE_IDLE - && ticks >= CLUNET_IDLE_TIMEOUT_T) // Timeout - { - clunetReadingState = CLUNET_READING_STATE_IDLE; - printk(KERN_WARNING "CLUNET recv timeout\n"); - } } if (!value) @@ -250,109 +284,110 @@ static irq_handler_t clunet_irq_handler(unsigned int irq, void *dev_id, struct p /* Таймер */ static enum hrtimer_restart send_timer_callback(struct hrtimer *timer) { - /* Если достигли фазы завершения передачи, то завершим ее и освободим передатчик */ - if (clunetSendingState == CLUNET_SENDING_STATE_DONE) - { - clunetSendingState = CLUNET_SENDING_STATE_IDLE; // Указываем, что передатчик свободен - clunet_set_line(0); // Отпускаем линию + if (!clunet_sending_state) return HRTIMER_NORESTART; // Nothing to do + /* Если достигли фазы завершения передачи, то завершим ее и освободим передатчик */ + if (clunet_sending_state == CLUNET_SENDING_STATE_DONE) + { + clunet_sending_state = CLUNET_SENDING_STATE_IDLE; // Указываем, что передатчик свободен + clunet_set_line(0); // Отпускаем линию wake_up_interruptible(&wq_data); // Wake up, i'm ready for new data! - } - /* Иначе если передачу необходимо продолжить, то сначала проверим на конфликт */ - else if (!clunet_sending && CLUNET_READING) - { - clunetSendingState = CLUNET_SENDING_STATE_WAITING_LINE; // Переходим в режим ожидания линии - } - /* Все в порядке, можем продолжать */ - else - { - clunet_set_line(!clunet_sending); // Инвертируем значение сигнала - - /* Если отпустили линию, то запланируем время паузы перед следующей передачей длительностью 1Т */ - if (!clunet_sending) - { - set_send_timer(CLUNET_T); - } - /* Если прижали линию к земле, то запланируем время передачи сигнала в зависимости от текущей фазы передачи */ - /* Фаза передачи данных */ - else if (clunetSendingState == CLUNET_SENDING_STATE_DATA) - { - /* Планируем следующее прерывание в зависимости от значения бита */ - set_send_timer((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: - set_send_timer(CLUNET_INIT_T); - break; - /* Фаза передачи приоритета (старший бит) */ - case CLUNET_SENDING_STATE_PRIO1: - set_send_timer((sendPriority > 2) ? CLUNET_1_T : CLUNET_0_T); - break; - /* Фаза передачи приоритета (младший бит) */ - case CLUNET_SENDING_STATE_PRIO2: - set_send_timer((sendPriority & 1) ? CLUNET_0_T : CLUNET_1_T); - clunetSendingCurrentByte = clunetSendingCurrentBit = 0; // Готовим счётчики передачи данных - break; - } - } + } + /* Иначе если передачу необходимо продолжить, то сначала проверим на конфликт */ + else if (!clunet_sending && CLUNET_READING) + { + clunet_sending_state = CLUNET_SENDING_STATE_WAITING_LINE; // Переходим в режим ожидания линии + } + /* Все в порядке, можем продолжать */ + else + { + clunet_set_line(!clunet_sending); // Инвертируем значение сигнала + + /* Если отпустили линию, то запланируем время паузы перед следующей передачей длительностью 1Т */ + if (!clunet_sending) + { + set_send_timer(CLUNET_T); + } + /* Если прижали линию к земле, то запланируем время передачи сигнала в зависимости от текущей фазы передачи */ + /* Фаза передачи данных */ + else if (clunet_sending_state == CLUNET_SENDING_STATE_DATA) + { + /* Планируем следующее прерывание в зависимости от значения бита */ + set_send_timer((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: + set_send_timer(CLUNET_INIT_T); + break; + /* Фаза передачи приоритета (старший бит) */ + case CLUNET_SENDING_STATE_PRIO1: + set_send_timer((clunet_sending_priority > 2) ? CLUNET_1_T : CLUNET_0_T); + break; + /* Фаза передачи приоритета (младший бит) */ + case CLUNET_SENDING_STATE_PRIO2: + set_send_timer((clunet_sending_priority & 1) ? CLUNET_0_T : CLUNET_1_T); + clunet_sending_current_byte = clunet_sending_current_bit = 0; // Готовим счётчики передачи данных + break; + } + } return HRTIMER_NORESTART; } -void clunet_send(const uint8_t src_address, const uint8_t dst_address, const uint8_t prio, const uint8_t command, const char* data, const uint8_t size) +static void clunet_send(const uint8_t src_address, const uint8_t dst_address, const uint8_t prio, const uint8_t command, const char* data, const uint8_t size) { u8 i; - /* Если размер данных в пределах буфера передачи (максимально для протокола 250 байт) */ - if (size < (CLUNET_SEND_BUFFER_SIZE - CLUNET_OFFSET_DATA)) - { - /* Прерываем текущую передачу, если есть такая */ - if (clunetSendingState) - { + /* Если размер данных в пределах буфера передачи (максимально для протокола 250 байт) */ + if (size < (CLUNET_SEND_BUFFER_SIZE - CLUNET_OFFSET_DATA)) + { + /* Прерываем текущую передачу, если есть такая */ + if (clunet_sending_state) + { if (data_send_timer) hrtimer_try_to_cancel(data_send_timer); - clunet_set_line(0); - } - - /* Заполняем переменные */ - sendPriority = (prio > 4) ? 4 : prio ? : 1; // Ограничим приоритет диапазоном (1 ; 4) - dataToSend[CLUNET_OFFSET_SRC_ADDRESS] = src_address; - dataToSend[CLUNET_OFFSET_DST_ADDRESS] = dst_address; - dataToSend[CLUNET_OFFSET_COMMAND] = command; - dataToSend[CLUNET_OFFSET_SIZE] = size; - - /* Копируем данные в буфер */ - 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) - { - clunetSendingState = CLUNET_SENDING_STATE_INIT; - set_send_timer(CLUNET_1_T); - } - // Иначе будем ожидать когда освободится в процедуре внешнего прерывания - else + clunet_set_line(0); + } + + /* Заполняем переменные */ + clunet_sending_priority = (prio > 4) ? 4 : prio ? : 1; // Ограничим приоритет диапазоном (1 ; 4) + out_buffer[CLUNET_OFFSET_SRC_ADDRESS] = src_address; + out_buffer[CLUNET_OFFSET_DST_ADDRESS] = dst_address; + out_buffer[CLUNET_OFFSET_COMMAND] = command; + out_buffer[CLUNET_OFFSET_SIZE] = size; + + /* Копируем данные в буфер */ + 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_sending_state = CLUNET_SENDING_STATE_INIT; + set_send_timer(CLUNET_SEND_PAUSE_T); + } + // Иначе будем ожидать когда освободится в процедуре внешнего прерывания + else { - clunetSendingState = CLUNET_SENDING_STATE_WAITING_LINE; + clunet_sending_state = CLUNET_SENDING_STATE_WAITING_LINE; } - } + } } /** @brief The device open function that is called each time the device is opened @@ -408,7 +443,7 @@ static ssize_t clunet_dev_read(struct file *filep, char *buffer, size_t len, lof return -EIO; buffer++; r++; - (*offset)++; + (*offset)++; len--; } return r; @@ -491,7 +526,7 @@ static ssize_t clunet_dev_write(struct file *filep, const char *buffer, size_t l return -ERESTARTSYS; } // Line is busy - if (clunetSendingState != CLUNET_SENDING_STATE_IDLE) + if (clunet_sending_state != CLUNET_SENDING_STATE_IDLE) { if (filep->f_flags & O_NONBLOCK) { @@ -501,7 +536,7 @@ static ssize_t clunet_dev_write(struct file *filep, const char *buffer, size_t l return -EBUSY; } // Waiting... - if (wait_event_interruptible(wq_data, clunetSendingState == CLUNET_SENDING_STATE_IDLE)) + if (wait_event_interruptible(wq_data, clunet_sending_state == CLUNET_SENDING_STATE_IDLE)) { kfree(decoded); mutex_unlock(&m_wait_for_line); @@ -517,7 +552,7 @@ static ssize_t clunet_dev_write(struct file *filep, const char *buffer, size_t l } ((struct cfile_t*)filep->private_data)->transmitter_buffer[ ((struct cfile_t*)filep->private_data)->transmitter_write_pos++ - ] = ch; + ] = ch; } return r; } @@ -552,12 +587,12 @@ static int __init clunet_init(void) dev_t dev; memset(opened_files, 0, sizeof(opened_files)); data_send_timer = kmalloc(sizeof(struct hrtimer), GFP_KERNEL); - if (!data_send_timer) - { + if (!data_send_timer) + { printk(KERN_ERR "CLUNET: can't allocate memory for timer\n"); clunet_free(); return -1; - } + } hrtimer_init(data_send_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); data_send_timer->function = send_timer_callback; gpio_free(receive_pin); @@ -578,8 +613,8 @@ static int __init clunet_init(void) return -1; } clunet_set_line(0); - irqNumber = gpio_to_irq(receive_pin); - r = request_irq(irqNumber, // The interrupt number requested + irq_number = gpio_to_irq(receive_pin); + r = request_irq(irq_number, // The interrupt number requested (irq_handler_t) clunet_irq_handler, // The pointer to the handler function below IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, // Interrupt on falling edge "clunet_handler", // Used in /proc/interrupts to identify the owner @@ -640,7 +675,16 @@ static int __init clunet_init(void) clunet_free(); return -1; } - printk(KERN_INFO "CLUNET: started, major numbers: %d (bus), %d (devices)\n", clunet_bus_major, clunet_device_major); + clunet_send ( + address, + CLUNET_BROADCAST_ADDRESS, + CLUNET_PRIORITY_MESSAGE, + CLUNET_COMMAND_BOOT_COMPLETED, + NULL, + 0 + ); + printk(KERN_INFO "CLUNET: started, major numbers: %d (bus), %d (devices), local address: 0x%02X, device name: %s\n", + clunet_bus_major, clunet_device_major, address, device_name); return 0; } @@ -670,8 +714,8 @@ static void clunet_free(void) class_unregister(clunet_class); // unregister the device class class_destroy(clunet_class); // remove the device class } - if (irqNumber != 0xffff) - free_irq(irqNumber, NULL); + if (irq_number != 0xffff) + free_irq(irq_number, NULL); gpio_free(receive_pin); gpio_free(transmit_pin); } diff --git a/clunet.h b/clunet.h index 150ff30..e35073d 100644 --- a/clunet.h +++ b/clunet.h @@ -6,6 +6,8 @@ #define DEVICE_NAME_BUS_FILE "clunet" #define DEVICE_NAME_CUSTOM "clunet_device" +//#define CLUNET_DEBUG + #define CLUNET_READ_BUFFER_SIZE 256 #define CLUNET_SEND_BUFFER_SIZE 256 @@ -15,8 +17,142 @@ #define CLUNET_0_T (CLUNET_T) #define CLUNET_1_T (3*CLUNET_T) #define CLUNET_INIT_T (10*CLUNET_T) +#define CLUNET_SEND_PAUSE_T (5*CLUNET_T) #define CLUNET_IDLE_TIMEOUT_T (10*CLUNET_T) +#define CLUNET_COMMAND_DISCOVERY 0x00 +/* Поиск других устройств, параметров нет */ + +#define CLUNET_COMMAND_DISCOVERY_RESPONSE 0x01 +/* Ответ устройств на поиск, в качестве параметра - название устройства (текст) */ + +#define CLUNET_COMMAND_BOOT_CONTROL 0x02 +/* Работа с загрузчиком. Данные - субкоманда. +<-0 - загрузчик запущен +->1 - перейти в режим обновления прошивки +<-2 - подтверждение перехода, плюс два байта - размер страницы +->3 запись прошивки, 4 байта - адрес, всё остальное - данные (равные размеру страницы) +<-4 блок прошивки записан +->5 выход из режима прошивки */ + +#define CLUNET_COMMAND_REBOOT 0x03 +/* Перезагружает устройство в загрузчик. */ + +#define CLUNET_COMMAND_BOOT_COMPLETED 0x04 +/* Посылается устройством после инициализации библиотеки, сообщает об успешной загрузке устройства. Параметр - содержимое MCU регистра, говорящее о причине перезагрузки. */ + +#define CLUNET_COMMAND_DOOR_INFO 0x05 +/*Информация об открытии двери. +0 - закрыта +1 - открыта +2 - тревога */ + +#define CLUNET_COMMAND_DEVICE_POWER_INFO_REQUEST 0x06 +/* Запрашивает информацию о состоянии выключателей */ + +#define CLUNET_COMMAND_DEVICE_POWER_INFO 0x07 +/* Состояние выключателей. Параметр - битовая маска состояния выключателей. */ + +#define CLUNET_COMMAND_DEVICE_POWER_COMMAND 0x08 +/* Включает/выключает выключатели. Параметр - битовая маска. Для света 0xFE - убавить свет, а 0xFF - прибавить. */ + +#define CLUNET_COMMAND_SET_TIMER 0x09 +/* Установка таймера. Параметр - кол-во секунд (два байта) */ + +#define CLUNET_COMMAND_RC_BUTTON_PRESSED 0x0A +/* Нажата кнопка на пульте. Первый байт - тип кода, далее - номер кнопки. +На данный момент 01 - самый популярный стандарт (Sony вроде?) длина кода кнопки - 4 байта. +02 - удержание кнопки его же. */ + +#define CLUNET_COMMAND_RC_BUTTON_PRESSED_RAW 0x0B +/* Недекодированные данные о нажатой кнопке на пульте для нестандартных пультов. Идут пачками по 4 байта. 2 из которых - длительность сигнала и 2 - длительность его отсутствия в 0.032 долях миллисекунды. (1/8000000*256 сек) */ + +#define CLUNET_COMMAND_RC_BUTTON_SEND 0x0C +/* Заэмулировать кнопку пульта. Формат данных аналогичен CLUNET_COMMAND_RC_BUTTON_PRESSED, плюс в конце опциональный байт длительности удержания кнопки (кол-во дополнительных сигналов), для Sony это ~30мс */ + +#define CLUNET_COMMAND_RC_BUTTON_SEND_RAW 0x0D +/* Заэмулировать кнопку пульта на основе сырых данных. Формат данных аналогичен CLUNET_COMMAND_RC_BUTTON_PRESSED_RAW. */ + +#define CLUNET_COMMAND_LIGHT_LEVEL 0x0E +/* Сообщает об уровне освещения. Параметр - 2 байта (0x0000 - 0x1FFF, где 0x1FFF - 0 вольт между фотодиодом и землёй, а 0x0000 - 5 вольт). */ + +#define CLUNET_COMMAND_ONEWIRE_START_SEARCH 0x0F +/* Запуск поиска 1-wire устройств, данные пустые. */ + +#define CLUNET_COMMAND_ONEWIRE_DEVICE_FOUND 0x10 +/* Сообщает о найденном 1-wire устройсте. Данные - 8 байт, включающие тип устройства, серийный номер и CRC. */ + +#define CLUNET_COMMAND_TEMPERATURE 0x11 +/* Сообщает о температуре. 1 байт - тип устройства, 6 - серийник, 2 - температура в формате устройства (смотреть на тип, чтобы декодировать!) */ + +#define CLUNET_COMMAND_TIME 0x12 +/* Сообщает время. Шесть байт - часы, минуты, секунды, год (от 1900), месяц (от 0), день (от 1) */ + +#define CLUNET_COMMAND_WHEEL 0x13 +/* Сообщает обороты колеса мыши, первый байт - ID колеса, далее два байта - обороты */ + +#define CLUNET_COMMAND_VOLTAGE 0x14 +/* Сообщает напряжение на батарейке, первый байт - ID устройства, далее два байта - вольтаж, где 0x3FF = 5.12 */ + +#define CLUNET_COMMAND_MOTION 0x15 +/* Сообщает, что в помещении есть движение, первый байт - ID датчика/камеры */ + +#define CLUNET_COMMAND_INTERCOM_RING 0x16 +/* Звонок в домофон */ + +#define CLUNET_COMMAND_INTERCOM_MESSAGE 0x17 +/* Новое сообщение на автоответчике домофона, в данных 4 байта - номер сообщения */ + +#define CLUNET_COMMAND_INTERCOM_MODE_REQUEST 0x18 +/* Запрашивает режим работы домофона */ + +#define CLUNET_COMMAND_INTERCOM_MODE_INFO 0x19 +/* Сообщает режим работы домофона, первый байт - постоянный режим, второй - временный */ + +#define CLUNET_COMMAND_INTERCOM_MODE_SET 0x1A +/* Задаёт режим работы домофона, первый байт - постоянный режим (или 0xFF, чтобы не трогать), второй - временный (опционально) */ + +#define CLUNET_COMMAND_INTERCOM_RECORD_REQUEST 0x1B +/* Запрашивает запись у домофона, подтверждает доставку или завершает передачу + Если 4 байта, то это номер запрашиваемой записи + Если 1 байт, то 1 в случае подтверждения получения пакета, 0 - завершение передачи */ + +#define CLUNET_COMMAND_INTERCOM_RECORD_DATA 0x1C +/* Передаёт кусок записи с автоответчика. Первые 4 байта - номер записи, далее 4 байта - смещение от начала файла, всё далее - данные из файла */ + +#define CLUNET_COMMAND_DOOR_LOCK_COMMAND 0x1D +/* Открывает или закрывает дверь. Один байт данных. 1 - открыть, 2 - закрыть */ + +#define CLUNET_COMMAND_DOOR_LOCK_INFO 0x1E +/* Сообщает об открытии или закрытии двери. 1 - открыта, 2 - закрыта */ + +#define CLUNET_COMMAND_DOOR_LOCK_INFO_REQUEST 0x1F +/* Запрашивает текущее состояние дверного замка */ + +#define CLUNET_COMMAND_BUTTON 0x20 +/* Нажата кнопка, в данных номер кнопки */ + +#define CLUNET_COMMAND_WINDOW_COMMAND 0x21 +/* Открывает или закрывает окно. Один байт данных. 1 - открыть, 2 - закрыть */ + +#define CLUNET_COMMAND_WINDOW_INFO 0x22 +/* Сообщает об открытии или закрытии окна. 1 - открыто, 2 - закрыто */ + +#define CLUNET_COMMAND_WINDOW_INFO_REQUEST 0x23 +/* Запрашивает текущее состояние окна */ + +#define CLUNET_COMMAND_DOOR_BELL 0x24 +/* Звонок в дверь */ + +#define CLUNET_COMMAND_ALARM 0x25 +/* Тревога. 1 - включить, 0 - выключить */ + +#define CLUNET_COMMAND_PING 0xFE +/* Пинг, на эту команду устройство должно ответить следующей командой, возвратив весь буфер */ + +#define CLUNET_COMMAND_PING_REPLY 0xFF +/* Ответ на пинг, в данных то, что было прислано в предыдущей команде */ + #define CLUNET_PRIORITY_NOTICE 1 /* Приоритет пакета 1 - неважное уведомление, которое вообще может быть потеряно без последствий */ #define CLUNET_PRIORITY_INFO 2 @@ -63,5 +199,6 @@ struct cfile_t { static int clunet_init(void); static void clunet_free(void); +static void clunet_send(const uint8_t src_address, const uint8_t dst_address, const uint8_t prio, const uint8_t command, const char* data, const uint8_t size); #endif \ No newline at end of file -- cgit v1.2.3