current lighthouse target app.
--- /dev/null
+protocol_bridge
--- /dev/null
+# Basic control protocol for LightHouse over UDP.
+# Should be replaced by MQTT in the future
+
+# Set Led
+SL addr branche [ledx R G B] [ledy R G B] [....]
+# addr : 0 -> 16K (0 == broadcast)
+# branche : 0 - 64 (port * 32 + pin)
+# led : 0 -> 255
+# R, G et B : 0 -> 255
+
+# Get Leds info
+GI
+# Replies :
+GI addr branche nbleds
+
+# Get Leds Colors
+GLC addr branche
+# Reply :
+GLC addr branche [R G B] [R G B] ....
+
+
+
--- /dev/null
+#CROSS_COMPILE ?= arm-linux-gnueabihf-
+CC = $(CROSS_COMPILE)gcc
+
+CFLAGS = -Wall -O2 -Wextra -DHOST_HAS_STDINT
+
+EXEC = protocol_bridge
+
+all: $(EXEC)
+
+
+OBJDIR = objs
+SRC = $(shell find . -name \*.c)
+OBJS = ${SRC:%.c=${OBJDIR}/%.o}
+INCLUDES = includes/
+
+${OBJDIR}/%.o: %.c
+ @mkdir -p $(dir $@)
+ @echo "-- compiling" $<
+ @$(CC) -MMD -MP -MF ${OBJDIR}/$*.d $(CFLAGS) $< -c -o $@ -I$(INCLUDES)
+
+$(EXEC): $(OBJS)
+ @echo "Linking $@ ..."
+ @$(CC) $(LDFLAGS) -o $@ $(OBJS)
+ @echo Done.
+
+
+clean:
+ find ${OBJDIR} -name "*.o" -exec rm {} \;
+ find ${OBJDIR} -name "*.d" -exec rm {} \;
+
+mrproper: clean
+ rm -f $(EXEC)
--- /dev/null
+../../../../include/lib/protocols/dtplug/defs.h
\ No newline at end of file
--- /dev/null
+/****************************************************************************
+ * dtplug_protocol_host.c
+ *
+ *
+ * Copyright 2013-2015 Nathael Pajani <nathael.pajani@ed3l.fr>
+ *
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ ****************************************************************************/
+
+
+/* Host side implementation of the DTPlug communication protocol */
+
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>
+
+#undef DEBUG
+
+#ifdef DEBUG
+#include <stdio.h>
+#endif
+
+#include "dtplug_protocol_host.h"
+
+
+/******************************************************************************/
+/* Handle packet reception, including checksums */
+/* 'sum' is used to sum all the received characters, and if the last byte of sum is 0 for each
+ * part (header and data) then the packet is valid.
+ * 'full_size' is the size of the whole packet, including header, updated as soon as the header
+ * is checked and valid
+ *
+ * This function must be called for every received character.
+ * If the character is part of a packet but the packet is being built, then the function returns 0.
+ * When the character is the last one of a valid packet, then the function returns the packet size
+ * and the packet in rx_data->rx_packet is valid.
+ * If the character is the last one of a packet which has an invalid data checksum, this function
+ * returns -2 and the data is lost.
+ * If the character is not part of a packet it returns -1. The character may then be part of
+ * a debug message (and displayed by the host), or any other kind of communication.
+ * When a set of consecutive characters have been used to build a packet but the packet is
+ * not valid due to header error, then the function returns -3 (checksum error) or -4 (data size
+ * error). The data in rx_data->rx_packet is the received data but is not valid.
+ * The corresponding data size is always sizeof(struct header).
+ */
+int dtplug_protocol_decode(uint8_t c, struct line_transceiver* rx_data)
+{
+ struct header* info = (struct header*)(&(rx_data->rx_packet));
+ int ret = 0;
+
+ /* Do not start reception before receiving the packet start character */
+ if ((rx_data->rx_ptr == 0) && (c != FIRST_PACKET_CHAR)) {
+ return -1;
+ }
+
+ /* Store the new byte in the packet */
+ ((uint8_t*)(&(rx_data->rx_packet)))[rx_data->rx_ptr++] = c;
+ rx_data->sum += c;
+
+ /* Is this packet valid ? (at end of header reception) */
+ if (rx_data->rx_ptr == sizeof(struct header)) {
+ /* Checksum OK ? */
+ if (rx_data->sum != 0) {
+ rx_data->errors_count++;
+ ret = -3;
+ goto next_packet;
+ }
+ /* Start the new checksum for data (if any) */
+ rx_data->sum = 0;
+
+ rx_data->full_size = sizeof(struct header);
+ /* If the packet is not a quick data or error packet it has a data part. Get it's size */
+ if (!(info->seq_num & QUICK_DATA_PACKET) && !(info->seq_num & PACKET_IS_ERROR)) {
+ rx_data->full_size += (info->data.size & PKT_SIZE_MASK); /* Don't care about big packets here */
+ /* Make sure the packet will fit in the buffer */
+ if (rx_data->full_size > sizeof(struct packet)) {
+ rx_data->errors_count++;
+ ret = -4;
+ goto next_packet;
+ }
+ }
+ }
+
+ /* Did we receive the whole packet ? */
+ if (rx_data->rx_ptr == rx_data->full_size) {
+ /* From here on, the packet is valid, we can provide some feedback */
+ /* Check data checksum if we have a normal data packet */
+ if (!(info->seq_num & QUICK_DATA_PACKET) && !(info->seq_num & PACKET_IS_ERROR)) {
+ if (rx_data->sum != info->data.checksum) {
+ rx_data->errors_count++;
+ ret = -2;
+ goto next_packet;
+ }
+ }
+ /* Count received packets */
+ rx_data->packet_rx_count++;
+ ret = rx_data->full_size;
+ /* And get ready to receive the next packet */
+ goto next_packet;
+ }
+
+ return 0;
+
+next_packet:
+#ifdef DEBUG
+ printf("Current rx pointer: %d, packet full size: %d\n", rx_data->rx_ptr, rx_data->full_size);
+ printf("Packets received count: %d, packets errors: %d\n",
+ rx_data->packet_rx_count, rx_data->errors_count);
+ if (rx_data->rx_ptr >= sizeof(struct header)) {
+ struct header* h = info;
+ printf("Pkt: type: %d, seq: %d, err: %d, quick: %d\n", h->type, (h->seq_num & 0x1F),
+ (h->seq_num & PACKET_IS_ERROR), (h->seq_num & QUICK_DATA_PACKET));
+ if (!(h->seq_num & QUICK_DATA_PACKET) && !(h->seq_num & PACKET_IS_ERROR)) {
+ printf("Pkt: data_size: %d, data_cksum: 0x%02x\n", h->data.size, h->data.checksum);
+ printf("rx_data_cksum: 0x%02x\n", rx_data->sum);
+ }
+ }
+#endif
+ /* Wether the packet was OK or not doesn't matter, go on for a new one :) */
+ rx_data->full_size = 0;
+ rx_data->rx_ptr = 0;
+ rx_data->sum = 0;
+ return ret;
+}
+
+
+/******************************************************************************/
+/* This function handles sending packets to slave
+ * It returns the number of bytes of data sent.
+ */
+int host_send_packet(struct line_transceiver* slave, uint8_t type, uint32_t size, uint8_t* data, int need_reply)
+{
+ struct packet cmd;
+ struct header* cmd_info = &(cmd.info);
+ unsigned int i = 0, sent = 0, len = sizeof(struct header);
+ uint8_t sum = 0;
+ unsigned int data_send_size = size, data_sent = 0;
+
+ /* Loop to send all data, possibly split in several packets */
+ do {
+ memset(&cmd, 0, sizeof(struct packet));
+ if (data_send_size > PACKET_DATA_SIZE) {
+ data_send_size = PACKET_DATA_SIZE;
+ }
+ /* Set packet header */
+ cmd_info->start = FIRST_PACKET_CHAR;
+ cmd_info->type = type;
+ cmd_info->seq_num = (slave->sequence_number++ & SEQUENCE_MASK);
+ /* Set the need reply bit only on the last packet */
+ if ((need_reply != 0) && ((data_sent + data_send_size) == size)) {
+ cmd_info->seq_num |= PACKET_NEEDS_REPLY;
+ }
+ /* Setup data */
+ if (data != NULL) {
+ /* Only use quick data packet for short packet, not continued data */
+ if (size && (size <= 2)) {
+ cmd_info->seq_num |= QUICK_DATA_PACKET;
+ cmd_info->quick_data[0] = data[0];
+ if (size == 2) {
+ cmd_info->seq_num |= QUICK_DATA_PACKET_TWO_BYTES;
+ cmd_info->quick_data[1] = data[1];
+ }
+ } else {
+ /* Copy data, compute checksum (also OK for a data_send_size of 0) */
+ for (i = 0; i < data_send_size; i++) {
+ cmd.data[i] = data[i];
+ sum += data[i]; /* Build checksum */
+ }
+ /* And update header information */
+ cmd_info->data.size = data_send_size;
+ /* Will this packet be continued in the following one ? */
+ if (data_send_size < (size - data_sent)) {
+ cmd_info->data.size |= BIG_DATA_PKT;
+ }
+ cmd_info->data.checksum = sum;
+ /* Update length of data to send on serial link */
+ len += data_send_size;
+ }
+ }
+
+ /* Compute header checksum */
+ sum = 0;
+ cmd_info->checksum = 0;
+ for (i = 0; i < sizeof(struct header); i++) {
+ sum += ((uint8_t*)cmd_info)[i];
+ }
+ cmd_info->checksum = ((uint8_t)(256 - sum));
+
+ /* And send the packet on the serial link */
+ while (sent < len) {
+ int ret = write(slave->fd, (((char*)(&cmd)) + sent), (len - sent));
+ if (ret >= 0) {
+ sent += ret;
+ } else {
+ /* Sending error ... */
+ /* FIXME : handle / report errors */
+ return data_sent;
+ }
+ }
+ data_sent += data_send_size;
+
+ /* Need to send more ? */
+ if (data && (data_sent <= size)) {
+ /* Move data pointer */
+ data += data_send_size;
+ /* Update size to send. check against PACKET_DATA_SIZE is done at beginning of loop */
+ data_send_size = (size - data_sent);
+ /* Set packet type to continued data packet for following packets */
+ type = PKT_TYPE_CONTINUED_DATA;
+ /* And prepare sending of the next packet (reset internal loop counters) */
+ sum = 0;
+ len = sizeof(struct header);
+ sent = 0;
+ } else {
+ /* No data, everything got sent */
+ data_send_size = 0;
+ }
+ } while (data_send_size != 0);
+
+ return data_sent;
+}
+
+
--- /dev/null
+/****************************************************************************
+ * dtplug_protocol_host.h
+ *
+ *
+ * Copyright 2013-2015 Nathael Pajani <nathael.pajani@ed3l.fr>
+ *
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ ****************************************************************************/
+
+
+/* Host side implementation of the DTPlug communication protocol */
+
+#ifndef DTPLUG_PROTOCOL_HOST_H
+#define DTPLUG_PROTOCOL_HOST_H
+
+
+#include <stdint.h>
+#include "dtplug_protocol_defs.h"
+
+
+/******************************************************************************/
+/* Handle packet reception, including checksums */
+/* 'sum' is used to sum all the received characters, and if the last byte of sum is 0 for each
+ * part (header and data) then the packet is valid.
+ * 'full_size' is the size of the whole packet, including header, updated as soon as the header
+ * is checked and valid
+ */
+struct line_transceiver {
+ int fd;
+ /* The packet being built */
+ struct packet rx_packet;
+ /* Sequence number for this line */
+ uint8_t sequence_number;
+ /* Packet building data */
+ uint8_t rx_ptr;
+ uint8_t sum;
+ uint8_t full_size;
+ /* packet counts */
+ uint32_t packet_rx_count;
+ uint32_t packet_tx_count;
+ uint32_t errors_count;
+};
+
+/* This function must be called for every received character.
+ * If the character is part of a packet but the packet is being built, then the function returns 0.
+ * When the character is the last one of a valid packet, then the function returns the packet size
+ * and the packet in rx_data->rx_packet is valid.
+ * If the character is the last one of a packet which has an invalid data checksum, this function
+ * returns -2 and the data is lost.
+ * If the character is not part of a packet it returns -1. The character may then be part of
+ * a debug message (and displayed by the host), or any other kind of communication.
+ * When a set of consecutive characters have been used to build a packet but the packet is
+ * not valid due to header error, then the function returns -3 (checksum error) or -4 (data size
+ * error). The data in rx_data->rx_packet is the received data but is not valid.
+ * The corresponding data size is always sizeof(struct header).
+ */
+int dtplug_protocol_decode(uint8_t c, struct line_transceiver* rx_data);
+
+/* This function handles sending packets to slave
+ * It returns the number of bytes of data sent.
+ */
+int host_send_packet(struct line_transceiver* slave, uint8_t type, uint32_t size, uint8_t* data, int need_reply);
+
+
+#endif /* DTPLUG_PROTOCOL_HOST_H */
+
--- /dev/null
+/****************************************************************************
+ * LightHouse UDP to RF Sub1GHz module bridge.
+ *
+ * handlers.c
+ *
+ *
+ * Copyright 2016 Nathael Pajani <nathael.pajani@ed3l.fr>
+ *
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ ****************************************************************************/
+
+
+/* This protocol handler is designed to run on a host. */
+
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include "list.h"
+#include "dtplug_protocol_host.h"
+
+
+#define BUFF_LEN 60
+
+struct info_data {
+ struct list_head head;
+ int type; /* Information type */
+ int addr; /* Source address */
+ int function; /* Information function */
+ int number; /* Information number */
+ int value; /* Information */
+ struct timeval last_update; /* Information timestamp */
+};
+
+
+struct list_head* all_info = NULL;
+int nb_info = 0;
+
+int create_info(int type, int addr, int func, int num)
+{
+ struct info_data* addinfo = malloc(sizeof(struct info_data));
+
+ if (addinfo == NULL) {
+ return -1;
+ }
+
+ if (all_info == NULL) {
+ all_info = &(addinfo->head);
+ INIT_LIST_HEAD(&(addinfo->head));
+ } else {
+ list_add_tail(&addinfo->head, all_info);
+ }
+ addinfo->type = type;
+ addinfo->addr = addr;
+ addinfo->function = func;
+ addinfo->number = num;
+ nb_info++;
+
+ return 0;
+}
+
+void delete_info(struct info_data* oldinfo)
+{
+ if (oldinfo == NULL) {
+ return;
+ }
+ list_del(&(oldinfo->head));
+ if (list_empty(all_info)) {
+ all_info = NULL;
+ }
+ free(oldinfo);
+ nb_info--;
+}
+
+/* Find exactly matching information */
+struct info_data* find_info(int type, int addr, int func, int num)
+{
+ struct info_data* info = NULL;
+ if (all_info == NULL) {
+ return NULL;
+ }
+ list_for_each_entry(info, all_info, head) {
+ if ((info->type == type) && (info->addr == addr) && (info->function == func) && (info->number == num)) {
+ return info;
+ }
+ }
+ return info;
+}
+/* TOTO : find all info_data matching given criteria */
+
+
+
+int handle_module_data(struct line_transceiver* slave)
+{
+ struct header* head = &(slave->rx_packet.info);
+ /* If this packet holds no valid data, it indicates that there are errors */
+ if (head->seq_num & PACKET_IS_ERROR) {
+ printf("Received a packet indicating errors (%d - %d)\n",
+ head->err.error_code, head->err.info);
+ /* Request the list of errors */
+ host_send_packet(slave, PKT_TYPE_GET_ERRORS, 0, NULL, 1);
+ return 0;
+ }
+ /* Move data from "QUICK_DATA_PACKET" packets to the data part of the packet for easy handling */
+ if (head->seq_num & QUICK_DATA_PACKET) {
+ slave->rx_packet.data[0] = head->quick_data[0];
+ slave->rx_packet.data[1] = head->quick_data[1];
+ if (head->seq_num & QUICK_DATA_PACKET_ONE_BYTE) {
+ head->data.size = 1;
+ } else {
+ head->data.size = 2;
+ }
+ }
+
+ switch (head->type) {
+ case PKT_TYPE_PING:
+ break;
+
+ case PKT_TYPE_GET_BOARD_INFO:
+ break;
+
+ case PKT_TYPE_GET_NUM_PACKETS:
+ break;
+
+ case PKT_TYPE_GET_ERRORS:
+ /* FIXME */
+ printf("Received error list: ... implement error decoding.\n");
+ break;
+
+ case PKT_TYPE_GET_NUM_ERRORS:
+ /* FIXME */
+ printf("Received number of errors: %d.\n", 0);
+ break;
+
+ case PKT_TYPE_CONTINUED_DATA:
+ break;
+
+ case PKT_TYPE_GET_TEMPERATURE:
+ {
+ struct info_data* info = find_info('T', 0, 0, 0); /* FIXME */
+ uint16_t* tmp = (uint16_t*)(&(slave->rx_packet.data[0]));
+ gettimeofday(&(info->last_update), NULL);
+ info->value = (int16_t)ntohs(tmp[0]);
+ }
+ break;
+
+ case PKT_TYPE_GET_ADC_VALUE:
+ break;
+
+ default:
+ printf("Received packet type %d. Not handled.\n", head->type);
+ break;
+ }
+ return 0;
+}
+
+#define REP_SIZE_MAX 1024
+
+int handle_udp_request(char* buf, int len, struct sockaddr* addr, socklen_t addr_len,
+ int sock, struct line_transceiver* slave)
+{
+ struct info_data* info = NULL;
+ if ((len == 0) || (buf == NULL)) {
+ return -1;
+ }
+ if (buf[0] == 'G') {
+ char obuf[REP_SIZE_MAX];
+ int len = 0;
+ /* GET command : Return the last updated value with the update timestamp */
+ switch (buf[1]) {
+ case 'L':
+ info = find_info('L', 0, 0, 0); /* FIXME */
+ if (info != NULL) {
+ len = snprintf(obuf, REP_SIZE_MAX, "GL %d %d %d : %d at %ld.%03ld",
+ info->addr, info->function, info->number, info->value,
+ info->last_update.tv_sec, (info->last_update.tv_usec / 1000));
+ }
+ break;
+ case 'I':
+ list_for_each_entry(info, all_info, head) {
+ if (info->type == 'I') {
+ len = snprintf(obuf, REP_SIZE_MAX, "GI: %d %d %d\n",
+ info->addr, info->function, info->value);
+ sendto(sock, obuf, len, 0, addr, addr_len);
+ }
+ }
+ break;
+ }
+ sendto(sock, obuf, len, 0, addr, addr_len);
+ printf("Handled GET request type: %c\n", buf[1]);
+ } else if (buf[0] == 'U') {
+ uint8_t num = 0;
+ /* Request a value update */
+ switch (buf[1]) {
+ case 'T':
+ host_send_packet(slave, PKT_TYPE_START_TEMP_CONVERSION, 0, NULL, 0);
+ usleep(200 * 1000); /* Temp conversion at 11 bits resolution is about 160ms */
+ host_send_packet(slave, PKT_TYPE_GET_TEMPERATURE, 0, NULL, 1);
+ break;
+ case 'A':
+ num = (uint8_t)(strtoul(&buf[2], NULL, 10) & 0xFF);
+ host_send_packet(slave, PKT_TYPE_GET_ADC_VALUE, 1, &num, 1);
+ break;
+ }
+ printf("Handled UPDATE request type: %c\n", buf[1]);
+ } else if (buf[0] == 'S') {
+ /* Send new values to the micro-controller */
+ uint8_t obuf[BUFF_LEN];
+ char* tmp = NULL;
+ int i = 0;
+
+ switch (buf[1]) {
+ case 'L': /* FIXME */
+ obuf[0] = (strtoul(&buf[2], &tmp, 10) & 0xFF); /* Address */
+ obuf[1] = (strtoul(tmp, &tmp, 10) & 0x3F); /* Function */
+ for (i = 2; ((i < (BUFF_LEN - 4)) && (tmp < buf + len)); i += 4) {
+ obuf[i] = (strtoul(tmp, &tmp, 10) & 0xFF); /* Number */
+ obuf[i + 1] = (strtoul(tmp, &tmp, 10) & 0xFF); /* Red Value */
+ obuf[i + 2] = (strtoul(tmp, &tmp, 10) & 0xFF); /* Green Value */
+ obuf[i + 3] = (strtoul(tmp, &tmp, 10) & 0xFF); /* Blue Value */
+ }
+ host_send_packet(slave, PKT_TYPE_SET_RGB_LED, i, obuf, 0);
+ break;
+ }
+ printf("Handled SET request type: %c\n", buf[1]);
+ } else {
+ printf("Unhandled request type: '0x%02x'\n", buf[0]);
+ return -2;
+ }
+
+ return 0;
+}
+
+
+
--- /dev/null
+/****************************************************************************
+ * LightHouse UDP to RF Sub1GHz module bridge.
+ *
+ * handlers.h
+ *
+ *
+ * Copyright 2013-2014 Nathael Pajani <nathael.pajani@ed3l.fr>
+ *
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ ****************************************************************************/
+
+
+/* This protocol handler is designed to run on a host replacing the DTPlug,
+ * but should be easy to use as a source for the protocol handling code for
+ * the DTPlug itself.
+ */
+
+#ifndef HANDLERS_H
+#define HANDLERS_H
+
+#include <stdint.h>
+#include <sys/types.h>
+#include "dtplug_protocol_host.h"
+
+
+
+int handle_module_data(struct line_transceiver* slave);
+
+
+int handle_udp_request(char* buf, int len, struct sockaddr* addr, socklen_t addr_len,
+ int sock, struct line_transceiver* slave);
+
+
+#endif /* HANDLERS_H */
--- /dev/null
+/*
+ * list.h
+ *
+ * This code is from the linux kernel. It is a very simple and powerfull doubly
+ * linked list implementation.
+ * Not everything has been taken from the original file.
+ */
+
+#ifndef _LINUX_LIST_H
+#define _LINUX_LIST_H
+
+
+/* linux/kernel.h */
+
+/**
+ * container_of - cast a member of a structure out to the containing structure
+ * @ptr: the pointer to the member.
+ * @type: the type of the container struct this is embedded in.
+ * @member: the name of the member within the struct.
+ *
+ */
+#define container_of(ptr, type, member) ({ \
+ const typeof( ((type *)0)->member ) *__mptr = (ptr); \
+ (type *)( (char *)__mptr - offsetof(type,member) );})
+
+
+
+/* linux/stddef.h */
+
+#ifdef __compiler_offsetof
+#define offsetof(TYPE,MEMBER) __compiler_offsetof(TYPE,MEMBER)
+#else
+#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
+#endif
+
+
+
+/* linux/list.h */
+
+/*
+ * Simple doubly linked list implementation.
+ *
+ * Some of the internal functions ("__xxx") are useful when
+ * manipulating whole lists rather than single entries, as
+ * sometimes we already know the next/prev entries and we can
+ * generate better code by using them directly rather than
+ * using the generic single-entry routines.
+ */
+
+struct list_head {
+ struct list_head *next, *prev;
+};
+
+/*
+ * These are non-NULL pointers that will result in page faults
+ * under normal circumstances, used to verify that nobody uses
+ * non-initialized list entries.
+ */
+#define LIST_POISON1 ((void *) 0x00100100)
+#define LIST_POISON2 ((void *) 0x00200200)
+
+
+#define LIST_HEAD_INIT(name) { &(name), &(name) }
+
+#define LIST_HEAD(name) \
+ struct list_head name = LIST_HEAD_INIT(name)
+
+static inline void INIT_LIST_HEAD(struct list_head *list)
+{
+ list->next = list;
+ list->prev = list;
+}
+
+/*
+ * Insert a new entry between two known consecutive entries.
+ *
+ * This is only for internal list manipulation where we know
+ * the prev/next entries already!
+ */
+static inline void __list_add(struct list_head *new,
+ struct list_head *prev,
+ struct list_head *next)
+{
+ next->prev = new;
+ new->next = next;
+ new->prev = prev;
+ prev->next = new;
+}
+
+/**
+ * list_add - add a new entry
+ * @new: new entry to be added
+ * @head: list head to add it after
+ *
+ * Insert a new entry after the specified head.
+ * This is good for implementing stacks.
+ */
+static inline void list_add(struct list_head *new, struct list_head *head)
+{
+ __list_add(new, head, head->next);
+}
+
+
+/**
+ * list_add_tail - add a new entry
+ * @new: new entry to be added
+ * @head: list head to add it before
+ *
+ * Insert a new entry before the specified head.
+ * This is useful for implementing queues.
+ */
+static inline void list_add_tail(struct list_head *new, struct list_head *head)
+{
+ __list_add(new, head->prev, head);
+}
+
+/*
+ * Delete a list entry by making the prev/next entries
+ * point to each other.
+ *
+ * This is only for internal list manipulation where we know
+ * the prev/next entries already!
+ */
+static inline void __list_del(struct list_head * prev, struct list_head * next)
+{
+ next->prev = prev;
+ prev->next = next;
+}
+
+/**
+ * list_del - deletes entry from list.
+ * @entry: the element to delete from the list.
+ * Note: list_empty() on entry does not return true after this, the entry is
+ * in an undefined state.
+ */
+static inline void __list_del_entry(struct list_head *entry)
+{
+ __list_del(entry->prev, entry->next);
+}
+
+static inline void list_del(struct list_head *entry)
+{
+ __list_del(entry->prev, entry->next);
+ entry->next = LIST_POISON1;
+ entry->prev = LIST_POISON2;
+}
+
+/**
+ * list_is_last - tests whether @list is the last entry in list @head
+ * @list: the entry to test
+ * @head: the head of the list
+ */
+static inline int list_is_last(const struct list_head *list,
+ const struct list_head *head)
+{
+ return list->next == head;
+}
+
+/**
+ * list_empty - tests whether a list is empty
+ * @head: the list to test.
+ */
+static inline int list_empty(const struct list_head *head)
+{
+ return head->next == head;
+}
+
+/**
+ * list_entry - get the struct for this entry
+ * @ptr: the &struct list_head pointer.
+ * @type: the type of the struct this is embedded in.
+ * @member: the name of the list_struct within the struct.
+ */
+#define list_entry(ptr, type, member) \
+ container_of(ptr, type, member)
+
+/**
+ * list_first_entry - get the first element from a list
+ * @ptr: the list head to take the element from.
+ * @type: the type of the struct this is embedded in.
+ * @member: the name of the list_struct within the struct.
+ *
+ * Note, that list is expected to be not empty.
+ */
+#define list_first_entry(ptr, type, member) \
+ list_entry((ptr)->next, type, member)
+
+/**
+ * list_last_entry - get the last element from a list
+ * @ptr: the list head to take the element from.
+ * @type: the type of the struct this is embedded in.
+ * @member: the name of the list_struct within the struct.
+ *
+ * Note, that list is expected to be not empty.
+ */
+#define list_last_entry(ptr, type, member) \
+ list_entry((ptr)->prev, type, member)
+
+/**
+ * list_next_entry - get the next element in list
+ * @pos: the type * to cursor
+ * @member: the name of the list_struct within the struct.
+ */
+#define list_next_entry(pos, member) \
+ list_entry((pos)->member.next, typeof(*(pos)), member)
+
+/**
+ * list_for_each_entry - iterate over list of given type
+ * @pos: the type * to use as a loop cursor.
+ * @head: the head for your list.
+ * @member: the name of the list_struct within the struct.
+ */
+#define list_for_each_entry(pos, head, member) \
+ for (pos = list_first_entry(head, typeof(*pos), member); \
+ &pos->member != (head); \
+ pos = list_next_entry(pos, member))
+
+/**
+ * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry
+ * @pos: the type * to use as a loop cursor.
+ * @n: another type * to use as temporary storage
+ * @head: the head for your list.
+ * @member: the name of the list_struct within the struct.
+ */
+#define list_for_each_entry_safe(pos, n, head, member) \
+ for (pos = list_first_entry(head, typeof(*pos), member), \
+ n = list_next_entry(pos, member); \
+ &pos->member != (head); \
+ pos = n, n = list_next_entry(n, member))
+
+#endif /* _LINUX_LIST_H */
--- /dev/null
+/****************************************************************************
+ * LightHouse UDP to RF Sub1GHz module bridge.
+ *
+ * main.c
+ *
+ *
+ * Copyright 2013-2014 Nathael Pajani <nathael.pajani@ed3l.fr>
+ *
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ ****************************************************************************/
+
+
+/* this protocol handler is designed to run on a host replacing the DTPlug,
+ * but should be easy to use as a source for the protocol handling code for
+ * the DTPlug itself.
+ */
+
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <termios.h>
+#include <string.h>
+#include <errno.h>
+#include <getopt.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/select.h>
+#include <sys/time.h>
+#include <arpa/inet.h>
+#include "dtplug_protocol_host.h"
+#include "serial_utils.h"
+#include "sock_utils.h"
+#include "handlers.h"
+
+
+#define BUF_SIZE 1024
+
+#define PROG_NAME "DTPlug protocol test bridge"
+#define VERSION "0.1"
+
+
+void help(char *prog_name)
+{
+ fprintf(stderr, "---------------- "PROG_NAME" --------------------------------\n");
+ fprintf(stderr, "Usage: %s [options]\n" \
+ " Available options:\n" \
+ " \t -p | --port : Start listening for messages on this port\n" \
+ " \t -d | --device : Serial device to use for serial communication with the module\n" \
+ " \t -h | --help : Print this help\n" \
+ " \t -v | --version : Print programm version\n" \
+ " All other arguments are data for the command, handled depending on the command.\n", prog_name);
+ fprintf(stderr, "-----------------------------------------------------------------------\n");
+}
+
+
+int main(int argc, char* argv[])
+{
+ /* Serial */
+ char* device = NULL;
+ struct line_transceiver slave;
+ /* TCP Server */
+ int port = -1;
+ int server_socket = -1;
+ /* For select */
+ struct timeval next_periodic_round;
+ struct timeval period;
+ fd_set read_fds;
+ int max_fd = 0;
+
+ while(1) {
+ int option_index = 0;
+ int c = 0;
+
+ struct option long_options[] = {
+ {"port", required_argument, 0, 'p'},
+ {"device", required_argument, 0, 'd'},
+ {"help", no_argument, 0, 'h'},
+ {"version", no_argument, 0, 'v'},
+ {0, 0, 0, 0}
+ };
+
+ c = getopt_long(argc, argv, "p:d:hv", long_options, &option_index);
+
+ /* no more options to parse */
+ if (c == -1) break;
+ switch (c) {
+ /* a, board address */
+ case 'p':
+ port = strtoul(optarg, NULL, 0);
+ break;
+
+ /* c, command */
+ case 'd':
+ device = optarg;
+ break;
+
+ /* v, version */
+ case 'v':
+ printf("%s Version %s\n", PROG_NAME, VERSION);
+ return 0;
+ break;
+
+ /* h, help */
+ case 'h':
+ default:
+ help(argv[0]);
+ return 0;
+ }
+ }
+
+
+ /* Need Serial port and destination file as parameter */
+ if ((port == -1) || (device == NULL)) {
+ printf("Error, need both serial (tty) device and IP port number\n");
+ help(argv[0]);
+ return -1;
+ }
+
+ /* Open tty */
+ memset(&slave, 0, sizeof(struct line_transceiver));
+ slave.fd = serial_setup(device);
+ if (slave.fd < 0) {
+ printf("Unable to open specified serial port %s\n", device);
+ return -2;
+ }
+
+ /* Create UDP server socket */
+ server_socket = create_bound_udp_socket(port, NULL);
+ if (server_socket <= 0) {
+ printf("Unable to open the server UDP socket on port %d\n", port);
+ return -3;
+ }
+
+ /* ************************************************* */
+ /* Initial FD set setup */
+ FD_ZERO(&read_fds);
+ FD_SET(STDIN_FILENO, &read_fds); /* Add stdin */
+ FD_SET(slave.fd, &read_fds); /* Serial link */
+ FD_SET(server_socket, &read_fds); /* New connexions */
+ max_fd = server_socket + 1; /* No close, this one is the last open, so it's the higest */
+
+ /* Periodic actions setup */
+ gettimeofday(&next_periodic_round, NULL);
+ period.tv_sec = 1; /* "Timer" granularitu is 1 second */
+ period.tv_usec = 0;
+ timeradd(&next_periodic_round, &period, &next_periodic_round);
+
+
+ /* ************************************************* */
+ /* And never stop handling data ! */
+ while (1) {
+ int nb = 0, len = 0, ret = 0;
+ struct timeval timeout;
+ struct timeval now;
+ fd_set tmp_read_fds = read_fds;
+ char buf[BUF_SIZE];
+
+ /* Send periodic requests for temperature */
+ gettimeofday(&now, NULL);
+
+ if (timercmp(&now, &next_periodic_round, >=)) {
+ timeout.tv_sec = 0;
+ timeout.tv_usec = 0;
+ } else {
+ timersub(&next_periodic_round, &now, &timeout);
+ }
+
+ /* select() call .... be kind to other processes */
+ nb = select(max_fd, &tmp_read_fds, NULL, NULL, &timeout);
+ /* Errors here are bad ones .. exit ?? */
+ if (nb < 0) {
+ perror ("select failed");
+ printf("Error: select failed, this is critical.\n");
+ return -10;
+ }
+ /* In case of timeout ... perform periodic actions if a period has been defined */
+ if (nb == 0) {
+ int misses = 0;
+ /* Setup next periodic request date */
+ timeradd(&next_periodic_round, &period, &next_periodic_round);
+ gettimeofday(&now, NULL);
+ /* Did we miss some rounds ? */
+ while (timercmp(&now, &next_periodic_round, >=)) {
+ /* Count misses (and catch up) */
+ timeradd(&next_periodic_round, &period, &next_periodic_round);
+ misses++;
+ }
+ /* FIXME : parse the list of periodic actions for new packets */
+ continue;
+ }
+
+ /* Data from Ethernet side */
+ if (FD_ISSET(server_socket, &tmp_read_fds)) {
+ struct sockaddr_in addr;
+ socklen_t addr_len = sizeof(struct sockaddr_in);
+
+ /* Receive the new data */
+ memset(buf, 0, BUF_SIZE);
+ len = recvfrom(server_socket, buf, BUF_SIZE, 0, (struct sockaddr *)&addr, &addr_len);
+ if (len > 0) {
+ handle_udp_request(buf, len, (struct sockaddr *)&addr, addr_len, server_socket, &slave);
+ } else {
+ /* Wait .. we received something but nothing came in ? */
+ perror("UDP receive error");
+ printf("\nError on UDP packet reception (ret: %d)\n", len);
+ }
+ }
+
+ /* Read user input if any */
+ if (FD_ISSET(STDIN_FILENO, &tmp_read_fds)) {
+ memset(buf, 0, BUF_SIZE);
+ len = read(STDIN_FILENO, buf, BUF_SIZE);
+ /* Do not know how to handle it yet, nothing defined. */
+ }
+
+ /* Handle module messages */
+ if (FD_ISSET(slave.fd, &tmp_read_fds)) {
+ int idx = 0;
+ memset(buf, 0, BUF_SIZE);
+ /* Get serial data and try to build a packet */
+ len = read(slave.fd, buf, BUF_SIZE);
+ if (len < 0) {
+ perror("serial read error");
+ /* FIXME : handle errors */
+ } else if (len == 0) {
+ /* Wait .. we received something but nothing came in ? */
+ printf("\nError, got activity on serial link, but no data ...\n");
+ }
+ while (idx < len) {
+ ret = dtplug_protocol_decode(buf[idx], &slave);
+ /* Check return code to know if we have a valid packet */
+ if (ret == -1) {
+ /* Anything that's not part of a packet is printed as is (debug output) */
+ printf("%c", buf[idx]);
+ } else if (ret < 0) {
+ printf("\nError in received packet. (ret: %d)\n", ret);
+ /* FIXME : dump packet for debugging */
+ } else if (ret == 0) {
+ /* Packet is being built */
+ } else {
+ /* Valid packet received */
+ handle_module_data(&slave);
+ }
+ idx++;
+ }
+ }
+
+ } /* End of infinite loop */
+
+ close(slave.fd);
+ close(server_socket);
+ return 0;
+}
+
+
--- /dev/null
+#!/usr/bin/perl -w
+
+use strict;
+use warnings;
+
+# Author : Nathael Pajani
+# Copyright 2015 Nathael Pajani <nathael.pajani@techno-innov.fr>
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+
+use IO::Socket::INET;
+use Scalar::Util qw(looks_like_number);
+
+
+#######################################
+# Base package parts
+my $server = 'localhost';
+
+
+# UDP Helper
+sub send_to {
+ my ($port, $request, $type) = @_;
+ my $socket = new IO::Socket::INET(Proto => 'udp');
+ my $servaddr = sockaddr_in($port, inet_aton($server));
+ $socket->send($request, 0, $servaddr);
+ unless ($request =~ /G/) {
+ print "Request sent.\n";
+ return;
+ }
+ my $data;
+ $socket->recv($data, 1024, 0);
+ print "Reply: $data\n";
+ $socket->close();
+}
+
+
+#######################################
+my ($port, $req, $type, @args) = @ARGV;
+
+unless (defined($port) && looks_like_number($port) && defined($req) && defined($type)) {
+ print "Usage: $0 port request type [red green blue] ...\n";
+ exit 1;
+}
+
+my $full = "$req$type ";
+my $sep = ' ';
+foreach (@args) {
+ $full .= "$sep";
+ $full .= "$_";
+ #$sep = ', ';
+}
+print "Req to $port : $full\n";
+
+send_to($port, $full, $type);
+
--- /dev/null
+/*********************************************************************
+ *
+ * Serial utility functions
+ *
+ *
+ * Copyright 2012-2014 Nathael Pajani <nathael.pajani@ed3l.fr>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ *********************************************************************/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <termios.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <errno.h>
+
+
+#define SERIAL_BAUD B115200
+
+
+int serial_setup(char* name)
+{
+ struct termios tio;
+ int fd = -1;
+
+ /* Open serial port */
+ fd = open(name, O_RDWR);
+ if (fd < 0) {
+ perror("Unable to open communication with companion chip");
+ return -1;
+ }
+ /* Setup serial port */
+ memset(&tio, 0, sizeof(tio));
+ tio.c_cflag = CS8 | CREAD | CLOCAL; /* 8n1, see termios.h for more information */
+ tio.c_cc[VMIN] = 1;
+ tio.c_cc[VTIME] = 5;
+ cfsetospeed(&tio, SERIAL_BAUD);
+ cfsetispeed(&tio, SERIAL_BAUD);
+ tcsetattr(fd, TCSANOW, &tio);
+
+ return fd;
+}
+
--- /dev/null
+/*********************************************************************
+ *
+ * Serial utility functions
+ *
+ *
+ * Copyright 2012 Nathael Pajani <nathael.pajani@ed3l.fr>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ *********************************************************************/
+#ifndef SERIAL_UTILS_H
+#define SERIAL_UTILS_H
+
+/* Setup serial comunication, using name if given or saved name if name is NULL
+ * SERIAL_BAUD B38400
+ * c_cflag (CS7 | PARENB | CREAD | CLOCAL) (7e1)
+ */
+int serial_setup(char* name);
+
+#endif /* SERIAL_UTILS_H */
+
--- /dev/null
+/*****************************************************************************
+ *
+ * socket utils
+ *
+ *
+ * Copyright 2012 Nathael Pajani <nathael.pajani@ed3l.fr>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ *****************************************************************************/
+
+#include <stdio.h> /* perror */
+#include <string.h> /* memset */
+#include <unistd.h> /* close, fcntl */
+#include <fcntl.h> /* F_SETFL and O_NONBLOCK for fcntl */
+
+/* For socket stuff */
+#include <sys/types.h> /* For portability for socket stuff */
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h> /* For TCP_NODELAY to disable nagle algorithm */
+
+
+/* This is used to allow quicker sending of small packets on wires */
+static void sox_disable_nagle_algorithm(int socket)
+{
+ const int on = 1;
+ setsockopt(socket, IPPROTO_TCP, TCP_NODELAY, (char*)&on, sizeof( int ));
+}
+
+/* Creates a TCP socket on the specified "port", bind to port and setup to
+ * accept connections with listen, with up to "nb_pending" pending connections
+ * in the queue.
+ * Returns the socket, after disabling nagle algorithm.
+ * If "our" is not null, it will be used to store the listening socket information.
+ * If "port" is 0, then "our" must contain all requiered information for bind call.
+ */
+int socket_tcp_server(int port, int nb_pending, struct sockaddr_in* our)
+{
+ struct sockaddr_in local;
+ struct sockaddr_in* tmp;
+ int s;
+ int optval = 1;
+
+ if (our == NULL ) {
+ tmp = &local;
+ if (port == 0) {
+ fprintf(stderr, "No port and no address information provided, won't be able to bind, aborting\n");
+ return -1;
+ }
+ } else {
+ tmp = our;
+ }
+
+ if (port != 0) {
+ memset(tmp, 0, sizeof(struct sockaddr_in));
+ tmp->sin_family = AF_INET;
+ tmp->sin_addr.s_addr = htonl(INADDR_ANY);
+ tmp->sin_port = htons((short)port);
+ }
+
+ if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+ perror("Unable to create TCP socket");
+ return -1;
+ }
+
+ if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (void *)&optval, sizeof(int)) == -1) {
+ perror("Unable to set reuseaddress on socket");
+ goto err_close;
+ }
+ if (setsockopt(s, SOL_SOCKET, SO_KEEPALIVE, (void *)&optval, sizeof(int)) == -1) {
+ perror("Unable to set keepalive on socket");
+ goto err_close;
+ }
+
+ if (bind(s, (struct sockaddr *)tmp, sizeof(struct sockaddr_in)) < 0) {
+ perror("Unable to bind TCP port");
+ goto err_close;
+ }
+
+ if (listen(s, nb_pending)) {
+ perror("Unable to listen to TCP port");
+ goto err_close;
+ }
+
+ sox_disable_nagle_algorithm(s);
+ return s;
+
+err_close:
+ close(s);
+ return -1;
+}
+
+
+/* Creates an UDP socket on the specified "port" and bind to port but no specific interface.
+ * Returns the socket.
+ * If "our" is not null, it will be used to store the listening socket information.
+ * "port" must not be 0..
+ */
+int create_bound_udp_socket(int port, struct sockaddr_in* our)
+{
+ struct sockaddr_in local;
+ struct sockaddr_in* tmp;
+ int s;
+ int optval = 1;
+
+ if (port == 0) {
+ return -1;
+ }
+
+ if (our == NULL ) {
+ tmp = &local;
+ } else {
+ tmp = our;
+ }
+
+ memset(tmp, 0, sizeof(struct sockaddr_in));
+ tmp->sin_family = AF_INET;
+ tmp->sin_addr.s_addr = htonl(INADDR_ANY);
+ tmp->sin_port = htons((short)port);
+
+ if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+ perror("Unable to create UDP socket");
+ return -1;
+ }
+
+ if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (void *)&optval, sizeof(int)) == -1) {
+ perror("Unable to set reuseaddress on socket");
+ goto err_close;
+ }
+
+ if (bind(s, (struct sockaddr *)tmp, sizeof(struct sockaddr_in)) < 0) {
+ perror("Unable to bind UDP port");
+ goto err_close;
+ }
+
+ return s;
+
+err_close:
+ close(s);
+ return -1;
+}
+
+
+
+/* Creates an UDP socket bound to no specific interface.
+ * The kernel choses the port to bind to.
+ * Returns the socket.
+ */
+int create_broadcast_udp_socket(void)
+{
+ struct sockaddr_in local;
+ struct sockaddr_in* tmp = &local;
+ int s;
+ int optval = 1;
+
+ memset(tmp, 0, sizeof(struct sockaddr_in));
+ tmp->sin_family = AF_INET;
+ tmp->sin_addr.s_addr = htonl(INADDR_ANY);
+ tmp->sin_port = 0;
+
+ if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+ perror("Unable to create UDP socket");
+ return -1;
+ }
+
+ if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (void *)&optval, sizeof(int)) == -1) {
+ perror("Unable to set reuseaddress on socket");
+ goto err_close;
+ }
+
+ if (setsockopt(s, SOL_SOCKET, SO_BROADCAST, (void *)&optval, sizeof(int)) == -1) {
+ perror("Unable to set broadcast on socket");
+ goto err_close;
+ }
+
+ if (bind(s, (struct sockaddr *)tmp, sizeof(struct sockaddr_in)) < 0) {
+ perror("Unable to bind UDP port");
+ goto err_close;
+ }
+
+ return s;
+
+err_close:
+ close(s);
+ return -1;
+}
+
+
--- /dev/null
+/*****************************************************************************
+ *
+ * socket utils
+ *
+ *
+ * Copyright 2012 Nathael Pajani <nathael.pajani@ed3l.fr>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ *****************************************************************************/
+
+#ifndef SOCK_UTILS_H
+#define SOCK_UTILS_H
+
+#include <netinet/in.h> /* struct sockaddr_in */
+
+/* Creates a socket on the specified "port", bind to port and setup to
+ accept connections with listen, with up to "nb_pending" pending connections
+ in the queue.
+ Returns the socket, after disabling nagle algorithm.
+ If "our" is not null, it will be used to store the listening socket information.
+ */
+int socket_tcp_server(int port, int nb_pending, struct sockaddr_in* our);
+
+
+/* Creates an UDP socket on the specified "port" and bind to port but no specific interface.
+ * Returns the socket.
+ * If "our" is not null, it will be used to store the listening socket information.
+ * "port" must not be 0..
+ */
+int create_bound_udp_socket(int port, struct sockaddr_in* our);
+
+
+/* Creates an UDP socket bound to no specific interface.
+ * The kernel choses the port to bind to.
+ * Returns the socket.
+ */
+int create_broadcast_udp_socket(void);
+
+#endif /* SOCK_UTILS_H */
+
+++ /dev/null
-protocol_bridge
+++ /dev/null
-# Basic control protocol for LightHouse over UDP.
-# Should be replaced by MQTT in the future
-
-# Set Led
-SL addr branche [ledx R G B] [ledy R G B] [....]
-# addr : 0 -> 16K (0 == broadcast)
-# branche : 0 - 64 (port * 32 + pin)
-# led : 0 -> 255
-# R, G et B : 0 -> 255
-
-# Get Leds info
-GI
-# Replies :
-GI addr branche nbleds
-
-# Get Leds Colors
-GLC addr branche
-# Reply :
-GLC addr branche [R G B] [R G B] ....
-
-
-
+++ /dev/null
-#CROSS_COMPILE ?= arm-linux-gnueabihf-
-CC = $(CROSS_COMPILE)gcc
-
-CFLAGS = -Wall -O2 -Wextra -DHOST_HAS_STDINT
-
-EXEC = protocol_bridge
-
-all: $(EXEC)
-
-
-OBJDIR = objs
-SRC = $(shell find . -name \*.c)
-OBJS = ${SRC:%.c=${OBJDIR}/%.o}
-INCLUDES = includes/
-
-${OBJDIR}/%.o: %.c
- @mkdir -p $(dir $@)
- @echo "-- compiling" $<
- @$(CC) -MMD -MP -MF ${OBJDIR}/$*.d $(CFLAGS) $< -c -o $@ -I$(INCLUDES)
-
-$(EXEC): $(OBJS)
- @echo "Linking $@ ..."
- @$(CC) $(LDFLAGS) -o $@ $(OBJS)
- @echo Done.
-
-
-clean:
- find ${OBJDIR} -name "*.o" -exec rm {} \;
- find ${OBJDIR} -name "*.d" -exec rm {} \;
-
-mrproper: clean
- rm -f $(EXEC)
+++ /dev/null
-../../../../include/lib/protocols/dtplug/defs.h
\ No newline at end of file
+++ /dev/null
-/****************************************************************************
- * dtplug_protocol_host.c
- *
- *
- * Copyright 2013-2015 Nathael Pajani <nathael.pajani@ed3l.fr>
- *
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- ****************************************************************************/
-
-
-/* Host side implementation of the DTPlug communication protocol */
-
-#include <stdint.h>
-#include <string.h>
-#include <unistd.h>
-
-#undef DEBUG
-
-#ifdef DEBUG
-#include <stdio.h>
-#endif
-
-#include "dtplug_protocol_host.h"
-
-
-/******************************************************************************/
-/* Handle packet reception, including checksums */
-/* 'sum' is used to sum all the received characters, and if the last byte of sum is 0 for each
- * part (header and data) then the packet is valid.
- * 'full_size' is the size of the whole packet, including header, updated as soon as the header
- * is checked and valid
- *
- * This function must be called for every received character.
- * If the character is part of a packet but the packet is being built, then the function returns 0.
- * When the character is the last one of a valid packet, then the function returns the packet size
- * and the packet in rx_data->rx_packet is valid.
- * If the character is the last one of a packet which has an invalid data checksum, this function
- * returns -2 and the data is lost.
- * If the character is not part of a packet it returns -1. The character may then be part of
- * a debug message (and displayed by the host), or any other kind of communication.
- * When a set of consecutive characters have been used to build a packet but the packet is
- * not valid due to header error, then the function returns -3 (checksum error) or -4 (data size
- * error). The data in rx_data->rx_packet is the received data but is not valid.
- * The corresponding data size is always sizeof(struct header).
- */
-int dtplug_protocol_decode(uint8_t c, struct line_transceiver* rx_data)
-{
- struct header* info = (struct header*)(&(rx_data->rx_packet));
- int ret = 0;
-
- /* Do not start reception before receiving the packet start character */
- if ((rx_data->rx_ptr == 0) && (c != FIRST_PACKET_CHAR)) {
- return -1;
- }
-
- /* Store the new byte in the packet */
- ((uint8_t*)(&(rx_data->rx_packet)))[rx_data->rx_ptr++] = c;
- rx_data->sum += c;
-
- /* Is this packet valid ? (at end of header reception) */
- if (rx_data->rx_ptr == sizeof(struct header)) {
- /* Checksum OK ? */
- if (rx_data->sum != 0) {
- rx_data->errors_count++;
- ret = -3;
- goto next_packet;
- }
- /* Start the new checksum for data (if any) */
- rx_data->sum = 0;
-
- rx_data->full_size = sizeof(struct header);
- /* If the packet is not a quick data or error packet it has a data part. Get it's size */
- if (!(info->seq_num & QUICK_DATA_PACKET) && !(info->seq_num & PACKET_IS_ERROR)) {
- rx_data->full_size += (info->data.size & PKT_SIZE_MASK); /* Don't care about big packets here */
- /* Make sure the packet will fit in the buffer */
- if (rx_data->full_size > sizeof(struct packet)) {
- rx_data->errors_count++;
- ret = -4;
- goto next_packet;
- }
- }
- }
-
- /* Did we receive the whole packet ? */
- if (rx_data->rx_ptr == rx_data->full_size) {
- /* From here on, the packet is valid, we can provide some feedback */
- /* Check data checksum if we have a normal data packet */
- if (!(info->seq_num & QUICK_DATA_PACKET) && !(info->seq_num & PACKET_IS_ERROR)) {
- if (rx_data->sum != info->data.checksum) {
- rx_data->errors_count++;
- ret = -2;
- goto next_packet;
- }
- }
- /* Count received packets */
- rx_data->packet_rx_count++;
- ret = rx_data->full_size;
- /* And get ready to receive the next packet */
- goto next_packet;
- }
-
- return 0;
-
-next_packet:
-#ifdef DEBUG
- printf("Current rx pointer: %d, packet full size: %d\n", rx_data->rx_ptr, rx_data->full_size);
- printf("Packets received count: %d, packets errors: %d\n",
- rx_data->packet_rx_count, rx_data->errors_count);
- if (rx_data->rx_ptr >= sizeof(struct header)) {
- struct header* h = info;
- printf("Pkt: type: %d, seq: %d, err: %d, quick: %d\n", h->type, (h->seq_num & 0x1F),
- (h->seq_num & PACKET_IS_ERROR), (h->seq_num & QUICK_DATA_PACKET));
- if (!(h->seq_num & QUICK_DATA_PACKET) && !(h->seq_num & PACKET_IS_ERROR)) {
- printf("Pkt: data_size: %d, data_cksum: 0x%02x\n", h->data.size, h->data.checksum);
- printf("rx_data_cksum: 0x%02x\n", rx_data->sum);
- }
- }
-#endif
- /* Wether the packet was OK or not doesn't matter, go on for a new one :) */
- rx_data->full_size = 0;
- rx_data->rx_ptr = 0;
- rx_data->sum = 0;
- return ret;
-}
-
-
-/******************************************************************************/
-/* This function handles sending packets to slave
- * It returns the number of bytes of data sent.
- */
-int host_send_packet(struct line_transceiver* slave, uint8_t type, uint32_t size, uint8_t* data, int need_reply)
-{
- struct packet cmd;
- struct header* cmd_info = &(cmd.info);
- unsigned int i = 0, sent = 0, len = sizeof(struct header);
- uint8_t sum = 0;
- unsigned int data_send_size = size, data_sent = 0;
-
- /* Loop to send all data, possibly split in several packets */
- do {
- memset(&cmd, 0, sizeof(struct packet));
- if (data_send_size > PACKET_DATA_SIZE) {
- data_send_size = PACKET_DATA_SIZE;
- }
- /* Set packet header */
- cmd_info->start = FIRST_PACKET_CHAR;
- cmd_info->type = type;
- cmd_info->seq_num = (slave->sequence_number++ & SEQUENCE_MASK);
- /* Set the need reply bit only on the last packet */
- if ((need_reply != 0) && ((data_sent + data_send_size) == size)) {
- cmd_info->seq_num |= PACKET_NEEDS_REPLY;
- }
- /* Setup data */
- if (data != NULL) {
- /* Only use quick data packet for short packet, not continued data */
- if (size && (size <= 2)) {
- cmd_info->seq_num |= QUICK_DATA_PACKET;
- cmd_info->quick_data[0] = data[0];
- if (size == 2) {
- cmd_info->seq_num |= QUICK_DATA_PACKET_TWO_BYTES;
- cmd_info->quick_data[1] = data[1];
- }
- } else {
- /* Copy data, compute checksum (also OK for a data_send_size of 0) */
- for (i = 0; i < data_send_size; i++) {
- cmd.data[i] = data[i];
- sum += data[i]; /* Build checksum */
- }
- /* And update header information */
- cmd_info->data.size = data_send_size;
- /* Will this packet be continued in the following one ? */
- if (data_send_size < (size - data_sent)) {
- cmd_info->data.size |= BIG_DATA_PKT;
- }
- cmd_info->data.checksum = sum;
- /* Update length of data to send on serial link */
- len += data_send_size;
- }
- }
-
- /* Compute header checksum */
- sum = 0;
- cmd_info->checksum = 0;
- for (i = 0; i < sizeof(struct header); i++) {
- sum += ((uint8_t*)cmd_info)[i];
- }
- cmd_info->checksum = ((uint8_t)(256 - sum));
-
- /* And send the packet on the serial link */
- while (sent < len) {
- int ret = write(slave->fd, (((char*)(&cmd)) + sent), (len - sent));
- if (ret >= 0) {
- sent += ret;
- } else {
- /* Sending error ... */
- /* FIXME : handle / report errors */
- return data_sent;
- }
- }
- data_sent += data_send_size;
-
- /* Need to send more ? */
- if (data && (data_sent <= size)) {
- /* Move data pointer */
- data += data_send_size;
- /* Update size to send. check against PACKET_DATA_SIZE is done at beginning of loop */
- data_send_size = (size - data_sent);
- /* Set packet type to continued data packet for following packets */
- type = PKT_TYPE_CONTINUED_DATA;
- /* And prepare sending of the next packet (reset internal loop counters) */
- sum = 0;
- len = sizeof(struct header);
- sent = 0;
- } else {
- /* No data, everything got sent */
- data_send_size = 0;
- }
- } while (data_send_size != 0);
-
- return data_sent;
-}
-
-
+++ /dev/null
-/****************************************************************************
- * dtplug_protocol_host.h
- *
- *
- * Copyright 2013-2015 Nathael Pajani <nathael.pajani@ed3l.fr>
- *
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- ****************************************************************************/
-
-
-/* Host side implementation of the DTPlug communication protocol */
-
-#ifndef DTPLUG_PROTOCOL_HOST_H
-#define DTPLUG_PROTOCOL_HOST_H
-
-
-#include <stdint.h>
-#include "dtplug_protocol_defs.h"
-
-
-/******************************************************************************/
-/* Handle packet reception, including checksums */
-/* 'sum' is used to sum all the received characters, and if the last byte of sum is 0 for each
- * part (header and data) then the packet is valid.
- * 'full_size' is the size of the whole packet, including header, updated as soon as the header
- * is checked and valid
- */
-struct line_transceiver {
- int fd;
- /* The packet being built */
- struct packet rx_packet;
- /* Sequence number for this line */
- uint8_t sequence_number;
- /* Packet building data */
- uint8_t rx_ptr;
- uint8_t sum;
- uint8_t full_size;
- /* packet counts */
- uint32_t packet_rx_count;
- uint32_t packet_tx_count;
- uint32_t errors_count;
-};
-
-/* This function must be called for every received character.
- * If the character is part of a packet but the packet is being built, then the function returns 0.
- * When the character is the last one of a valid packet, then the function returns the packet size
- * and the packet in rx_data->rx_packet is valid.
- * If the character is the last one of a packet which has an invalid data checksum, this function
- * returns -2 and the data is lost.
- * If the character is not part of a packet it returns -1. The character may then be part of
- * a debug message (and displayed by the host), or any other kind of communication.
- * When a set of consecutive characters have been used to build a packet but the packet is
- * not valid due to header error, then the function returns -3 (checksum error) or -4 (data size
- * error). The data in rx_data->rx_packet is the received data but is not valid.
- * The corresponding data size is always sizeof(struct header).
- */
-int dtplug_protocol_decode(uint8_t c, struct line_transceiver* rx_data);
-
-/* This function handles sending packets to slave
- * It returns the number of bytes of data sent.
- */
-int host_send_packet(struct line_transceiver* slave, uint8_t type, uint32_t size, uint8_t* data, int need_reply);
-
-
-#endif /* DTPLUG_PROTOCOL_HOST_H */
-
+++ /dev/null
-/****************************************************************************
- * LightHouse UDP to RF Sub1GHz module bridge.
- *
- * handlers.c
- *
- *
- * Copyright 2016 Nathael Pajani <nathael.pajani@ed3l.fr>
- *
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- ****************************************************************************/
-
-
-/* This protocol handler is designed to run on a host. */
-
-
-#include <stdint.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <string.h>
-#include <errno.h>
-#include <sys/time.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <arpa/inet.h>
-#include "list.h"
-#include "dtplug_protocol_host.h"
-
-
-#define BUFF_LEN 60
-
-struct info_data {
- struct list_head head;
- int type; /* Information type */
- int addr; /* Source address */
- int function; /* Information function */
- int number; /* Information number */
- int value; /* Information */
- struct timeval last_update; /* Information timestamp */
-};
-
-
-struct list_head* all_info = NULL;
-int nb_info = 0;
-
-int create_info(int type, int addr, int func, int num)
-{
- struct info_data* addinfo = malloc(sizeof(struct info_data));
-
- if (addinfo == NULL) {
- return -1;
- }
-
- if (all_info == NULL) {
- all_info = &(addinfo->head);
- INIT_LIST_HEAD(&(addinfo->head));
- } else {
- list_add_tail(&addinfo->head, all_info);
- }
- addinfo->type = type;
- addinfo->addr = addr;
- addinfo->function = func;
- addinfo->number = num;
- nb_info++;
-
- return 0;
-}
-
-void delete_info(struct info_data* oldinfo)
-{
- if (oldinfo == NULL) {
- return;
- }
- list_del(&(oldinfo->head));
- if (list_empty(all_info)) {
- all_info = NULL;
- }
- free(oldinfo);
- nb_info--;
-}
-
-/* Find exactly matching information */
-struct info_data* find_info(int type, int addr, int func, int num)
-{
- struct info_data* info = NULL;
- if (all_info == NULL) {
- return NULL;
- }
- list_for_each_entry(info, all_info, head) {
- if ((info->type == type) && (info->addr == addr) && (info->function == func) && (info->number == num)) {
- return info;
- }
- }
- return info;
-}
-/* TOTO : find all info_data matching given criteria */
-
-
-
-int handle_module_data(struct line_transceiver* slave)
-{
- struct header* head = &(slave->rx_packet.info);
- /* If this packet holds no valid data, it indicates that there are errors */
- if (head->seq_num & PACKET_IS_ERROR) {
- printf("Received a packet indicating errors (%d - %d)\n",
- head->err.error_code, head->err.info);
- /* Request the list of errors */
- host_send_packet(slave, PKT_TYPE_GET_ERRORS, 0, NULL, 1);
- return 0;
- }
- /* Move data from "QUICK_DATA_PACKET" packets to the data part of the packet for easy handling */
- if (head->seq_num & QUICK_DATA_PACKET) {
- slave->rx_packet.data[0] = head->quick_data[0];
- slave->rx_packet.data[1] = head->quick_data[1];
- if (head->seq_num & QUICK_DATA_PACKET_ONE_BYTE) {
- head->data.size = 1;
- } else {
- head->data.size = 2;
- }
- }
-
- switch (head->type) {
- case PKT_TYPE_PING:
- break;
-
- case PKT_TYPE_GET_BOARD_INFO:
- break;
-
- case PKT_TYPE_GET_NUM_PACKETS:
- break;
-
- case PKT_TYPE_GET_ERRORS:
- /* FIXME */
- printf("Received error list: ... implement error decoding.\n");
- break;
-
- case PKT_TYPE_GET_NUM_ERRORS:
- /* FIXME */
- printf("Received number of errors: %d.\n", 0);
- break;
-
- case PKT_TYPE_CONTINUED_DATA:
- break;
-
- case PKT_TYPE_GET_TEMPERATURE:
- {
- struct info_data* info = find_info('T', 0, 0, 0); /* FIXME */
- uint16_t* tmp = (uint16_t*)(&(slave->rx_packet.data[0]));
- gettimeofday(&(info->last_update), NULL);
- info->value = (int16_t)ntohs(tmp[0]);
- }
- break;
-
- case PKT_TYPE_GET_ADC_VALUE:
- break;
-
- default:
- printf("Received packet type %d. Not handled.\n", head->type);
- break;
- }
- return 0;
-}
-
-#define REP_SIZE_MAX 1024
-
-int handle_udp_request(char* buf, int len, struct sockaddr* addr, socklen_t addr_len,
- int sock, struct line_transceiver* slave)
-{
- struct info_data* info = NULL;
- if ((len == 0) || (buf == NULL)) {
- return -1;
- }
- if (buf[0] == 'G') {
- char obuf[REP_SIZE_MAX];
- int len = 0;
- /* GET command : Return the last updated value with the update timestamp */
- switch (buf[1]) {
- case 'L':
- info = find_info('L', 0, 0, 0); /* FIXME */
- if (info != NULL) {
- len = snprintf(obuf, REP_SIZE_MAX, "GL %d %d %d : %d at %ld.%03ld",
- info->addr, info->function, info->number, info->value,
- info->last_update.tv_sec, (info->last_update.tv_usec / 1000));
- }
- break;
- case 'I':
- list_for_each_entry(info, all_info, head) {
- if (info->type == 'I') {
- len = snprintf(obuf, REP_SIZE_MAX, "GI: %d %d %d\n",
- info->addr, info->function, info->value);
- sendto(sock, obuf, len, 0, addr, addr_len);
- }
- }
- break;
- }
- sendto(sock, obuf, len, 0, addr, addr_len);
- printf("Handled GET request type: %c\n", buf[1]);
- } else if (buf[0] == 'U') {
- uint8_t num = 0;
- /* Request a value update */
- switch (buf[1]) {
- case 'T':
- host_send_packet(slave, PKT_TYPE_START_TEMP_CONVERSION, 0, NULL, 0);
- usleep(200 * 1000); /* Temp conversion at 11 bits resolution is about 160ms */
- host_send_packet(slave, PKT_TYPE_GET_TEMPERATURE, 0, NULL, 1);
- break;
- case 'A':
- num = (uint8_t)(strtoul(&buf[2], NULL, 10) & 0xFF);
- host_send_packet(slave, PKT_TYPE_GET_ADC_VALUE, 1, &num, 1);
- break;
- }
- printf("Handled UPDATE request type: %c\n", buf[1]);
- } else if (buf[0] == 'S') {
- /* Send new values to the micro-controller */
- uint8_t obuf[BUFF_LEN];
- char* tmp = NULL;
- int i = 0;
-
- switch (buf[1]) {
- case 'L': /* FIXME */
- obuf[0] = (strtoul(&buf[2], &tmp, 10) & 0xFF); /* Address */
- obuf[1] = (strtoul(tmp, &tmp, 10) & 0x3F); /* Function */
- for (i = 2; ((i < (BUFF_LEN - 4)) && (tmp < buf + len)); i += 4) {
- obuf[i] = (strtoul(tmp, &tmp, 10) & 0xFF); /* Number */
- obuf[i + 1] = (strtoul(tmp, &tmp, 10) & 0xFF); /* Red Value */
- obuf[i + 2] = (strtoul(tmp, &tmp, 10) & 0xFF); /* Green Value */
- obuf[i + 3] = (strtoul(tmp, &tmp, 10) & 0xFF); /* Blue Value */
- }
- host_send_packet(slave, PKT_TYPE_SET_RGB_LED, i, obuf, 0);
- break;
- }
- printf("Handled SET request type: %c\n", buf[1]);
- } else {
- printf("Unhandled request type: '0x%02x'\n", buf[0]);
- return -2;
- }
-
- return 0;
-}
-
-
-
+++ /dev/null
-/****************************************************************************
- * LightHouse UDP to RF Sub1GHz module bridge.
- *
- * handlers.h
- *
- *
- * Copyright 2013-2014 Nathael Pajani <nathael.pajani@ed3l.fr>
- *
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- ****************************************************************************/
-
-
-/* This protocol handler is designed to run on a host replacing the DTPlug,
- * but should be easy to use as a source for the protocol handling code for
- * the DTPlug itself.
- */
-
-#ifndef HANDLERS_H
-#define HANDLERS_H
-
-#include <stdint.h>
-#include <sys/types.h>
-#include "dtplug_protocol_host.h"
-
-
-
-int handle_module_data(struct line_transceiver* slave);
-
-
-int handle_udp_request(char* buf, int len, struct sockaddr* addr, socklen_t addr_len,
- int sock, struct line_transceiver* slave);
-
-
-#endif /* HANDLERS_H */
+++ /dev/null
-/*
- * list.h
- *
- * This code is from the linux kernel. It is a very simple and powerfull doubly
- * linked list implementation.
- * Not everything has been taken from the original file.
- */
-
-#ifndef _LINUX_LIST_H
-#define _LINUX_LIST_H
-
-
-/* linux/kernel.h */
-
-/**
- * container_of - cast a member of a structure out to the containing structure
- * @ptr: the pointer to the member.
- * @type: the type of the container struct this is embedded in.
- * @member: the name of the member within the struct.
- *
- */
-#define container_of(ptr, type, member) ({ \
- const typeof( ((type *)0)->member ) *__mptr = (ptr); \
- (type *)( (char *)__mptr - offsetof(type,member) );})
-
-
-
-/* linux/stddef.h */
-
-#ifdef __compiler_offsetof
-#define offsetof(TYPE,MEMBER) __compiler_offsetof(TYPE,MEMBER)
-#else
-#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
-#endif
-
-
-
-/* linux/list.h */
-
-/*
- * Simple doubly linked list implementation.
- *
- * Some of the internal functions ("__xxx") are useful when
- * manipulating whole lists rather than single entries, as
- * sometimes we already know the next/prev entries and we can
- * generate better code by using them directly rather than
- * using the generic single-entry routines.
- */
-
-struct list_head {
- struct list_head *next, *prev;
-};
-
-/*
- * These are non-NULL pointers that will result in page faults
- * under normal circumstances, used to verify that nobody uses
- * non-initialized list entries.
- */
-#define LIST_POISON1 ((void *) 0x00100100)
-#define LIST_POISON2 ((void *) 0x00200200)
-
-
-#define LIST_HEAD_INIT(name) { &(name), &(name) }
-
-#define LIST_HEAD(name) \
- struct list_head name = LIST_HEAD_INIT(name)
-
-static inline void INIT_LIST_HEAD(struct list_head *list)
-{
- list->next = list;
- list->prev = list;
-}
-
-/*
- * Insert a new entry between two known consecutive entries.
- *
- * This is only for internal list manipulation where we know
- * the prev/next entries already!
- */
-static inline void __list_add(struct list_head *new,
- struct list_head *prev,
- struct list_head *next)
-{
- next->prev = new;
- new->next = next;
- new->prev = prev;
- prev->next = new;
-}
-
-/**
- * list_add - add a new entry
- * @new: new entry to be added
- * @head: list head to add it after
- *
- * Insert a new entry after the specified head.
- * This is good for implementing stacks.
- */
-static inline void list_add(struct list_head *new, struct list_head *head)
-{
- __list_add(new, head, head->next);
-}
-
-
-/**
- * list_add_tail - add a new entry
- * @new: new entry to be added
- * @head: list head to add it before
- *
- * Insert a new entry before the specified head.
- * This is useful for implementing queues.
- */
-static inline void list_add_tail(struct list_head *new, struct list_head *head)
-{
- __list_add(new, head->prev, head);
-}
-
-/*
- * Delete a list entry by making the prev/next entries
- * point to each other.
- *
- * This is only for internal list manipulation where we know
- * the prev/next entries already!
- */
-static inline void __list_del(struct list_head * prev, struct list_head * next)
-{
- next->prev = prev;
- prev->next = next;
-}
-
-/**
- * list_del - deletes entry from list.
- * @entry: the element to delete from the list.
- * Note: list_empty() on entry does not return true after this, the entry is
- * in an undefined state.
- */
-static inline void __list_del_entry(struct list_head *entry)
-{
- __list_del(entry->prev, entry->next);
-}
-
-static inline void list_del(struct list_head *entry)
-{
- __list_del(entry->prev, entry->next);
- entry->next = LIST_POISON1;
- entry->prev = LIST_POISON2;
-}
-
-/**
- * list_is_last - tests whether @list is the last entry in list @head
- * @list: the entry to test
- * @head: the head of the list
- */
-static inline int list_is_last(const struct list_head *list,
- const struct list_head *head)
-{
- return list->next == head;
-}
-
-/**
- * list_empty - tests whether a list is empty
- * @head: the list to test.
- */
-static inline int list_empty(const struct list_head *head)
-{
- return head->next == head;
-}
-
-/**
- * list_entry - get the struct for this entry
- * @ptr: the &struct list_head pointer.
- * @type: the type of the struct this is embedded in.
- * @member: the name of the list_struct within the struct.
- */
-#define list_entry(ptr, type, member) \
- container_of(ptr, type, member)
-
-/**
- * list_first_entry - get the first element from a list
- * @ptr: the list head to take the element from.
- * @type: the type of the struct this is embedded in.
- * @member: the name of the list_struct within the struct.
- *
- * Note, that list is expected to be not empty.
- */
-#define list_first_entry(ptr, type, member) \
- list_entry((ptr)->next, type, member)
-
-/**
- * list_last_entry - get the last element from a list
- * @ptr: the list head to take the element from.
- * @type: the type of the struct this is embedded in.
- * @member: the name of the list_struct within the struct.
- *
- * Note, that list is expected to be not empty.
- */
-#define list_last_entry(ptr, type, member) \
- list_entry((ptr)->prev, type, member)
-
-/**
- * list_next_entry - get the next element in list
- * @pos: the type * to cursor
- * @member: the name of the list_struct within the struct.
- */
-#define list_next_entry(pos, member) \
- list_entry((pos)->member.next, typeof(*(pos)), member)
-
-/**
- * list_for_each_entry - iterate over list of given type
- * @pos: the type * to use as a loop cursor.
- * @head: the head for your list.
- * @member: the name of the list_struct within the struct.
- */
-#define list_for_each_entry(pos, head, member) \
- for (pos = list_first_entry(head, typeof(*pos), member); \
- &pos->member != (head); \
- pos = list_next_entry(pos, member))
-
-/**
- * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry
- * @pos: the type * to use as a loop cursor.
- * @n: another type * to use as temporary storage
- * @head: the head for your list.
- * @member: the name of the list_struct within the struct.
- */
-#define list_for_each_entry_safe(pos, n, head, member) \
- for (pos = list_first_entry(head, typeof(*pos), member), \
- n = list_next_entry(pos, member); \
- &pos->member != (head); \
- pos = n, n = list_next_entry(n, member))
-
-#endif /* _LINUX_LIST_H */
+++ /dev/null
-/****************************************************************************
- * LightHouse UDP to RF Sub1GHz module bridge.
- *
- * main.c
- *
- *
- * Copyright 2013-2014 Nathael Pajani <nathael.pajani@ed3l.fr>
- *
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- ****************************************************************************/
-
-
-/* this protocol handler is designed to run on a host replacing the DTPlug,
- * but should be easy to use as a source for the protocol handling code for
- * the DTPlug itself.
- */
-
-
-#include <stdint.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <termios.h>
-#include <string.h>
-#include <errno.h>
-#include <getopt.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/select.h>
-#include <sys/time.h>
-#include <arpa/inet.h>
-#include "dtplug_protocol_host.h"
-#include "serial_utils.h"
-#include "sock_utils.h"
-#include "handlers.h"
-
-
-#define BUF_SIZE 1024
-
-#define PROG_NAME "DTPlug protocol test bridge"
-#define VERSION "0.1"
-
-
-void help(char *prog_name)
-{
- fprintf(stderr, "---------------- "PROG_NAME" --------------------------------\n");
- fprintf(stderr, "Usage: %s [options]\n" \
- " Available options:\n" \
- " \t -p | --port : Start listening for messages on this port\n" \
- " \t -d | --device : Serial device to use for serial communication with the module\n" \
- " \t -h | --help : Print this help\n" \
- " \t -v | --version : Print programm version\n" \
- " All other arguments are data for the command, handled depending on the command.\n", prog_name);
- fprintf(stderr, "-----------------------------------------------------------------------\n");
-}
-
-
-int main(int argc, char* argv[])
-{
- /* Serial */
- char* device = NULL;
- struct line_transceiver slave;
- /* TCP Server */
- int port = -1;
- int server_socket = -1;
- /* For select */
- struct timeval next_periodic_round;
- struct timeval period;
- fd_set read_fds;
- int max_fd = 0;
-
- while(1) {
- int option_index = 0;
- int c = 0;
-
- struct option long_options[] = {
- {"port", required_argument, 0, 'p'},
- {"device", required_argument, 0, 'd'},
- {"help", no_argument, 0, 'h'},
- {"version", no_argument, 0, 'v'},
- {0, 0, 0, 0}
- };
-
- c = getopt_long(argc, argv, "p:d:hv", long_options, &option_index);
-
- /* no more options to parse */
- if (c == -1) break;
- switch (c) {
- /* a, board address */
- case 'p':
- port = strtoul(optarg, NULL, 0);
- break;
-
- /* c, command */
- case 'd':
- device = optarg;
- break;
-
- /* v, version */
- case 'v':
- printf("%s Version %s\n", PROG_NAME, VERSION);
- return 0;
- break;
-
- /* h, help */
- case 'h':
- default:
- help(argv[0]);
- return 0;
- }
- }
-
-
- /* Need Serial port and destination file as parameter */
- if ((port == -1) || (device == NULL)) {
- printf("Error, need both serial (tty) device and IP port number\n");
- help(argv[0]);
- return -1;
- }
-
- /* Open tty */
- memset(&slave, 0, sizeof(struct line_transceiver));
- slave.fd = serial_setup(device);
- if (slave.fd < 0) {
- printf("Unable to open specified serial port %s\n", device);
- return -2;
- }
-
- /* Create UDP server socket */
- server_socket = create_bound_udp_socket(port, NULL);
- if (server_socket <= 0) {
- printf("Unable to open the server UDP socket on port %d\n", port);
- return -3;
- }
-
- /* ************************************************* */
- /* Initial FD set setup */
- FD_ZERO(&read_fds);
- FD_SET(STDIN_FILENO, &read_fds); /* Add stdin */
- FD_SET(slave.fd, &read_fds); /* Serial link */
- FD_SET(server_socket, &read_fds); /* New connexions */
- max_fd = server_socket + 1; /* No close, this one is the last open, so it's the higest */
-
- /* Periodic actions setup */
- gettimeofday(&next_periodic_round, NULL);
- period.tv_sec = 1; /* "Timer" granularitu is 1 second */
- period.tv_usec = 0;
- timeradd(&next_periodic_round, &period, &next_periodic_round);
-
-
- /* ************************************************* */
- /* And never stop handling data ! */
- while (1) {
- int nb = 0, len = 0, ret = 0;
- struct timeval timeout;
- struct timeval now;
- fd_set tmp_read_fds = read_fds;
- char buf[BUF_SIZE];
-
- /* Send periodic requests for temperature */
- gettimeofday(&now, NULL);
-
- if (timercmp(&now, &next_periodic_round, >=)) {
- timeout.tv_sec = 0;
- timeout.tv_usec = 0;
- } else {
- timersub(&next_periodic_round, &now, &timeout);
- }
-
- /* select() call .... be kind to other processes */
- nb = select(max_fd, &tmp_read_fds, NULL, NULL, &timeout);
- /* Errors here are bad ones .. exit ?? */
- if (nb < 0) {
- perror ("select failed");
- printf("Error: select failed, this is critical.\n");
- return -10;
- }
- /* In case of timeout ... perform periodic actions if a period has been defined */
- if (nb == 0) {
- int misses = 0;
- /* Setup next periodic request date */
- timeradd(&next_periodic_round, &period, &next_periodic_round);
- gettimeofday(&now, NULL);
- /* Did we miss some rounds ? */
- while (timercmp(&now, &next_periodic_round, >=)) {
- /* Count misses (and catch up) */
- timeradd(&next_periodic_round, &period, &next_periodic_round);
- misses++;
- }
- /* FIXME : parse the list of periodic actions for new packets */
- continue;
- }
-
- /* Data from Ethernet side */
- if (FD_ISSET(server_socket, &tmp_read_fds)) {
- struct sockaddr_in addr;
- socklen_t addr_len = sizeof(struct sockaddr_in);
-
- /* Receive the new data */
- memset(buf, 0, BUF_SIZE);
- len = recvfrom(server_socket, buf, BUF_SIZE, 0, (struct sockaddr *)&addr, &addr_len);
- if (len > 0) {
- handle_udp_request(buf, len, (struct sockaddr *)&addr, addr_len, server_socket, &slave);
- } else {
- /* Wait .. we received something but nothing came in ? */
- perror("UDP receive error");
- printf("\nError on UDP packet reception (ret: %d)\n", len);
- }
- }
-
- /* Read user input if any */
- if (FD_ISSET(STDIN_FILENO, &tmp_read_fds)) {
- memset(buf, 0, BUF_SIZE);
- len = read(STDIN_FILENO, buf, BUF_SIZE);
- /* Do not know how to handle it yet, nothing defined. */
- }
-
- /* Handle module messages */
- if (FD_ISSET(slave.fd, &tmp_read_fds)) {
- int idx = 0;
- memset(buf, 0, BUF_SIZE);
- /* Get serial data and try to build a packet */
- len = read(slave.fd, buf, BUF_SIZE);
- if (len < 0) {
- perror("serial read error");
- /* FIXME : handle errors */
- } else if (len == 0) {
- /* Wait .. we received something but nothing came in ? */
- printf("\nError, got activity on serial link, but no data ...\n");
- }
- while (idx < len) {
- ret = dtplug_protocol_decode(buf[idx], &slave);
- /* Check return code to know if we have a valid packet */
- if (ret == -1) {
- /* Anything that's not part of a packet is printed as is (debug output) */
- printf("%c", buf[idx]);
- } else if (ret < 0) {
- printf("\nError in received packet. (ret: %d)\n", ret);
- /* FIXME : dump packet for debugging */
- } else if (ret == 0) {
- /* Packet is being built */
- } else {
- /* Valid packet received */
- handle_module_data(&slave);
- }
- idx++;
- }
- }
-
- } /* End of infinite loop */
-
- close(slave.fd);
- close(server_socket);
- return 0;
-}
-
-
+++ /dev/null
-#!/usr/bin/perl -w
-
-use strict;
-use warnings;
-
-# Author : Nathael Pajani
-# Copyright 2015 Nathael Pajani <nathael.pajani@techno-innov.fr>
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-
-use IO::Socket::INET;
-use Scalar::Util qw(looks_like_number);
-
-
-#######################################
-# Base package parts
-my $server = 'localhost';
-
-
-# UDP Helper
-sub send_to {
- my ($port, $request, $type) = @_;
- my $socket = new IO::Socket::INET(Proto => 'udp');
- my $servaddr = sockaddr_in($port, inet_aton($server));
- $socket->send($request, 0, $servaddr);
- unless ($request =~ /G/) {
- print "Request sent.\n";
- return;
- }
- my $data;
- $socket->recv($data, 1024, 0);
- print "Reply: $data\n";
- $socket->close();
-}
-
-
-#######################################
-my ($port, $req, $type, @args) = @ARGV;
-
-unless (defined($port) && looks_like_number($port) && defined($req) && defined($type)) {
- print "Usage: $0 port request type [red green blue] ...\n";
- exit 1;
-}
-
-my $full = "$req$type ";
-my $sep = ' ';
-foreach (@args) {
- $full .= "$sep";
- $full .= "$_";
- #$sep = ', ';
-}
-print "Req to $port : $full\n";
-
-send_to($port, $full, $type);
-
+++ /dev/null
-/*********************************************************************
- *
- * Serial utility functions
- *
- *
- * Copyright 2012-2014 Nathael Pajani <nathael.pajani@ed3l.fr>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- *********************************************************************/
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <termios.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <errno.h>
-
-
-#define SERIAL_BAUD B115200
-
-
-int serial_setup(char* name)
-{
- struct termios tio;
- int fd = -1;
-
- /* Open serial port */
- fd = open(name, O_RDWR);
- if (fd < 0) {
- perror("Unable to open communication with companion chip");
- return -1;
- }
- /* Setup serial port */
- memset(&tio, 0, sizeof(tio));
- tio.c_cflag = CS8 | CREAD | CLOCAL; /* 8n1, see termios.h for more information */
- tio.c_cc[VMIN] = 1;
- tio.c_cc[VTIME] = 5;
- cfsetospeed(&tio, SERIAL_BAUD);
- cfsetispeed(&tio, SERIAL_BAUD);
- tcsetattr(fd, TCSANOW, &tio);
-
- return fd;
-}
-
+++ /dev/null
-/*********************************************************************
- *
- * Serial utility functions
- *
- *
- * Copyright 2012 Nathael Pajani <nathael.pajani@ed3l.fr>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- *********************************************************************/
-#ifndef SERIAL_UTILS_H
-#define SERIAL_UTILS_H
-
-/* Setup serial comunication, using name if given or saved name if name is NULL
- * SERIAL_BAUD B38400
- * c_cflag (CS7 | PARENB | CREAD | CLOCAL) (7e1)
- */
-int serial_setup(char* name);
-
-#endif /* SERIAL_UTILS_H */
-
+++ /dev/null
-/*****************************************************************************
- *
- * socket utils
- *
- *
- * Copyright 2012 Nathael Pajani <nathael.pajani@ed3l.fr>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- *****************************************************************************/
-
-#include <stdio.h> /* perror */
-#include <string.h> /* memset */
-#include <unistd.h> /* close, fcntl */
-#include <fcntl.h> /* F_SETFL and O_NONBLOCK for fcntl */
-
-/* For socket stuff */
-#include <sys/types.h> /* For portability for socket stuff */
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <netinet/tcp.h> /* For TCP_NODELAY to disable nagle algorithm */
-
-
-/* This is used to allow quicker sending of small packets on wires */
-static void sox_disable_nagle_algorithm(int socket)
-{
- const int on = 1;
- setsockopt(socket, IPPROTO_TCP, TCP_NODELAY, (char*)&on, sizeof( int ));
-}
-
-/* Creates a TCP socket on the specified "port", bind to port and setup to
- * accept connections with listen, with up to "nb_pending" pending connections
- * in the queue.
- * Returns the socket, after disabling nagle algorithm.
- * If "our" is not null, it will be used to store the listening socket information.
- * If "port" is 0, then "our" must contain all requiered information for bind call.
- */
-int socket_tcp_server(int port, int nb_pending, struct sockaddr_in* our)
-{
- struct sockaddr_in local;
- struct sockaddr_in* tmp;
- int s;
- int optval = 1;
-
- if (our == NULL ) {
- tmp = &local;
- if (port == 0) {
- fprintf(stderr, "No port and no address information provided, won't be able to bind, aborting\n");
- return -1;
- }
- } else {
- tmp = our;
- }
-
- if (port != 0) {
- memset(tmp, 0, sizeof(struct sockaddr_in));
- tmp->sin_family = AF_INET;
- tmp->sin_addr.s_addr = htonl(INADDR_ANY);
- tmp->sin_port = htons((short)port);
- }
-
- if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
- perror("Unable to create TCP socket");
- return -1;
- }
-
- if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (void *)&optval, sizeof(int)) == -1) {
- perror("Unable to set reuseaddress on socket");
- goto err_close;
- }
- if (setsockopt(s, SOL_SOCKET, SO_KEEPALIVE, (void *)&optval, sizeof(int)) == -1) {
- perror("Unable to set keepalive on socket");
- goto err_close;
- }
-
- if (bind(s, (struct sockaddr *)tmp, sizeof(struct sockaddr_in)) < 0) {
- perror("Unable to bind TCP port");
- goto err_close;
- }
-
- if (listen(s, nb_pending)) {
- perror("Unable to listen to TCP port");
- goto err_close;
- }
-
- sox_disable_nagle_algorithm(s);
- return s;
-
-err_close:
- close(s);
- return -1;
-}
-
-
-/* Creates an UDP socket on the specified "port" and bind to port but no specific interface.
- * Returns the socket.
- * If "our" is not null, it will be used to store the listening socket information.
- * "port" must not be 0..
- */
-int create_bound_udp_socket(int port, struct sockaddr_in* our)
-{
- struct sockaddr_in local;
- struct sockaddr_in* tmp;
- int s;
- int optval = 1;
-
- if (port == 0) {
- return -1;
- }
-
- if (our == NULL ) {
- tmp = &local;
- } else {
- tmp = our;
- }
-
- memset(tmp, 0, sizeof(struct sockaddr_in));
- tmp->sin_family = AF_INET;
- tmp->sin_addr.s_addr = htonl(INADDR_ANY);
- tmp->sin_port = htons((short)port);
-
- if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
- perror("Unable to create UDP socket");
- return -1;
- }
-
- if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (void *)&optval, sizeof(int)) == -1) {
- perror("Unable to set reuseaddress on socket");
- goto err_close;
- }
-
- if (bind(s, (struct sockaddr *)tmp, sizeof(struct sockaddr_in)) < 0) {
- perror("Unable to bind UDP port");
- goto err_close;
- }
-
- return s;
-
-err_close:
- close(s);
- return -1;
-}
-
-
-
-/* Creates an UDP socket bound to no specific interface.
- * The kernel choses the port to bind to.
- * Returns the socket.
- */
-int create_broadcast_udp_socket(void)
-{
- struct sockaddr_in local;
- struct sockaddr_in* tmp = &local;
- int s;
- int optval = 1;
-
- memset(tmp, 0, sizeof(struct sockaddr_in));
- tmp->sin_family = AF_INET;
- tmp->sin_addr.s_addr = htonl(INADDR_ANY);
- tmp->sin_port = 0;
-
- if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
- perror("Unable to create UDP socket");
- return -1;
- }
-
- if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (void *)&optval, sizeof(int)) == -1) {
- perror("Unable to set reuseaddress on socket");
- goto err_close;
- }
-
- if (setsockopt(s, SOL_SOCKET, SO_BROADCAST, (void *)&optval, sizeof(int)) == -1) {
- perror("Unable to set broadcast on socket");
- goto err_close;
- }
-
- if (bind(s, (struct sockaddr *)tmp, sizeof(struct sockaddr_in)) < 0) {
- perror("Unable to bind UDP port");
- goto err_close;
- }
-
- return s;
-
-err_close:
- close(s);
- return -1;
-}
-
-
+++ /dev/null
-/*****************************************************************************
- *
- * socket utils
- *
- *
- * Copyright 2012 Nathael Pajani <nathael.pajani@ed3l.fr>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- *****************************************************************************/
-
-#ifndef SOCK_UTILS_H
-#define SOCK_UTILS_H
-
-#include <netinet/in.h> /* struct sockaddr_in */
-
-/* Creates a socket on the specified "port", bind to port and setup to
- accept connections with listen, with up to "nb_pending" pending connections
- in the queue.
- Returns the socket, after disabling nagle algorithm.
- If "our" is not null, it will be used to store the listening socket information.
- */
-int socket_tcp_server(int port, int nb_pending, struct sockaddr_in* our);
-
-
-/* Creates an UDP socket on the specified "port" and bind to port but no specific interface.
- * Returns the socket.
- * If "our" is not null, it will be used to store the listening socket information.
- * "port" must not be 0..
- */
-int create_bound_udp_socket(int port, struct sockaddr_in* our);
-
-
-/* Creates an UDP socket bound to no specific interface.
- * The kernel choses the port to bind to.
- * Returns the socket.
- */
-int create_broadcast_udp_socket(void);
-
-#endif /* SOCK_UTILS_H */
-