--- /dev/null
+#CROSS_COMPILE ?= arm-linux-gnueabihf-
+CC = $(CROSS_COMPILE)gcc
+
+CFLAGS = -Wall -O2 -Wextra
+
+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 2 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>
+#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,
+ (h->seq_num & PACKET_IS_ERROR), (h->seq_num & QUICK_DATA_PACKET));
+ }
+#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 {
+ 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 */
+ /* Only use quick data packet for short packet, not continued data */
+ if (size <= 2) {
+ cmd_info->seq_num |= QUICK_DATA_PACKET;
+ cmd_info->quick_data[0] = data[0];
+ 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_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;
+ }
+ } 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 2 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
+/****************************************************************************
+ * DTPlug serial communication protocol handler for tests.
+ *
+ * handlers.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 2 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 <string.h>
+#include <errno.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include "dtplug_protocol_host.h"
+
+
+
+#define PKT_TYPE_GET_DISTANCES (PKT_TYPE_LAST + 40)
+#define PKT_TYPE_GET_SMOKE (PKT_TYPE_LAST + 41)
+#define PKT_TYPE_GET_BATTERY (PKT_TYPE_LAST + 42)
+#define PKT_TYPE_GET_IR (PKT_TYPE_LAST + 43)
+
+#define PKT_TYPE_SET_SPEED (PKT_TYPE_LAST + 50)
+#define PKT_TYPE_SET_DIRECTION (PKT_TYPE_LAST + 51)
+
+
+
+int16_t temperature = 0;
+struct timeval temp_timestamp;
+
+uint16_t adc = 0;
+struct timeval adc_timestamp;
+
+uint16_t smoke = 0;
+struct timeval smoke_timestamp;
+
+#define NB_PULSE_SENSORS 6
+uint16_t distances[NB_PULSE_SENSORS] = {0};
+struct timeval distances_timestamp;
+
+uint8_t red = 0;
+uint8_t green = 0;
+uint8_t blue = 0;
+struct timeval led_timestamp;
+
+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:
+ {
+ uint16_t* tmp = (uint16_t*)(&(slave->rx_packet.data));
+ gettimeofday(&temp_timestamp, NULL);
+ temperature = (int16_t)ntohs(tmp[0]);
+ }
+ break;
+
+ case PKT_TYPE_GET_ADC_VALUE:
+ {
+ uint16_t* tmp = (uint16_t*)(&(slave->rx_packet.data));
+ gettimeofday(&adc_timestamp, NULL);
+ adc = ntohs(tmp[0]);
+ }
+ break;
+
+ case PKT_TYPE_GET_SMOKE:
+ {
+ uint16_t* tmp = (uint16_t*)(&(slave->rx_packet.data));
+ gettimeofday(&smoke_timestamp, NULL);
+ smoke = ntohs(tmp[0]);
+ }
+ break;
+
+ case PKT_TYPE_GET_DISTANCES:
+ {
+ uint16_t* tmp = (uint16_t*)(&(slave->rx_packet.data));
+ int i = 0;
+ gettimeofday(&distances_timestamp, NULL);
+ for (i = 0; i < NB_PULSE_SENSORS; i++) {
+ distances[i] = ntohs(tmp[i]);
+ }
+ }
+ break;
+
+ case PKT_TYPE_GET_GPIO:
+ break;
+
+ case PKT_TYPE_GET_RGB_LED:
+ gettimeofday(&led_timestamp, NULL);
+ red = slave->rx_packet.data[1];
+ green = slave->rx_packet.data[2];
+ blue = slave->rx_packet.data[3];
+ break;
+
+ case PKT_TYPE_SEND_ON_BUS:
+ 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)
+{
+ 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 'T':
+ len = snprintf(obuf, REP_SIZE_MAX, "GT: %d at %ld.%03ld",
+ temperature, temp_timestamp.tv_sec, (temp_timestamp.tv_usec / 1000));
+ break;
+ case 'L':
+ len = snprintf(obuf, REP_SIZE_MAX, "GL: %d, %d, %d at %ld.%03ld",
+ red, green, blue, led_timestamp.tv_sec, (led_timestamp.tv_usec / 1000));
+ break;
+ case 'A':
+ len = snprintf(obuf, REP_SIZE_MAX, "GA: %d at %ld.%03ld",
+ adc, adc_timestamp.tv_sec, (adc_timestamp.tv_usec / 1000));
+ 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 'L':
+ num = (uint8_t)(strtoul(&buf[2], NULL, 10) & 0xFF);
+ host_send_packet(slave, PKT_TYPE_GET_RGB_LED, 1, &num, 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;
+ case 'S':
+ host_send_packet(slave, PKT_TYPE_GET_SMOKE, 0, NULL, 1);
+ break;
+ case 'D':
+ host_send_packet(slave, PKT_TYPE_GET_DISTANCES, 0, NULL, 1);
+ break;
+ }
+ printf("Handled UPDATE request type: %c\n", buf[1]);
+ } else if (buf[0] == 'S') {
+ /* Send a new value to the micro-controller */
+ uint8_t obuf[4] = {0, 0, 0, 0};
+ char* tmp = NULL;
+
+ switch (buf[1]) {
+ case 'L':
+ obuf[0] = (strtoul(&buf[2], &tmp, 10) & 0xFF);
+ obuf[1] = (strtoul(tmp, &tmp, 10) & 0xFF);
+ obuf[2] = (strtoul(tmp, &tmp, 10) & 0xFF);
+ obuf[3] = (strtoul(tmp, &tmp, 10) & 0xFF);
+ host_send_packet(slave, PKT_TYPE_SET_RGB_LED, 4, obuf, 0);
+ break;
+ case 'D': /* Direction */
+ obuf[0] = (strtoul(&buf[2], NULL, 10) & 0xFF);
+ host_send_packet(slave, PKT_TYPE_SET_DIRECTION, 1, obuf, 0);
+ break;
+ case 'S': /* Speed */
+ obuf[0] = (strtoul(&buf[2], NULL, 10) & 0xFF);
+ host_send_packet(slave, PKT_TYPE_SET_SPEED, 1, 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
+/****************************************************************************
+ * DTPlug serial communication protocol handler for tests.
+ *
+ * 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 2 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
+/****************************************************************************
+ * DTPlug serial communication protocol handler for tests.
+ *
+ * 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 2 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 2 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 ($type =~ /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 2 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 2 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 2 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 2 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 */
+