Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/ClusterM/clunet-lkm.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexey 'Cluster' Avdyukhin <cluster@raspberrypi>2018-12-16 07:01:14 +0300
committerAlexey 'Cluster' Avdyukhin <cluster@raspberrypi>2018-12-16 07:01:14 +0300
commitad9fa4ad26182767dd0ced09d0dba2a986fa922b (patch)
treef820fa86289f5833b7341c187b68aa518995e6ba
parent0fe00227df3ae33fd2531ee31ebd9d42e7af8b47 (diff)
Done.
-rw-r--r--Makefile3
-rw-r--r--clunet.c410
-rw-r--r--clunet.h137
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 <linux/gpio.h>
#include <linux/interrupt.h>
#include <linux/mutex.h>
-#include <linux/delay.h>
#include <linux/timekeeping.h>
#include <linux/ktime.h>
#include <linux/hrtimer.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/string.h>
-#include <asm/div64.h>
#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