2016-11-26 16:49:03 +01:00
|
|
|
#include "libsss7.h"
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <termios.h>
|
2016-11-30 22:47:26 +01:00
|
|
|
#include <pthread.h>
|
2016-12-01 00:16:42 +01:00
|
|
|
#include <sys/time.h>
|
2016-11-30 22:47:26 +01:00
|
|
|
|
|
|
|
#include "sss7.h"
|
|
|
|
|
2016-12-03 22:58:55 +01:00
|
|
|
#if LIBSSS7_PAYLOAD_SIZE != SSS7_PAYLOAD_SIZE
|
|
|
|
#error LIBSSS7_PAYLOAD_SIZE is not equal to SSS7_PAYLOAD_SIZE
|
|
|
|
#endif
|
|
|
|
|
2016-12-03 19:17:54 +01:00
|
|
|
// A state kept a across eventloop iterations to emulate tx complete interrupts
|
2016-12-01 01:06:14 +01:00
|
|
|
enum UartTxState {
|
2016-12-03 19:17:54 +01:00
|
|
|
TX_IDLE, // Idle state
|
|
|
|
TX_HAS_BYTE, // There is a byte to be send in the next iteration
|
|
|
|
TX_COMPLETE // A byte has been sent in the current iteration
|
2016-12-01 01:06:14 +01:00
|
|
|
};
|
|
|
|
|
2016-12-03 19:17:54 +01:00
|
|
|
// The last byte that has been received, read by uart_get_byte
|
2016-11-26 16:49:03 +01:00
|
|
|
uint8_t uart_rx_byte;
|
2016-12-03 19:17:54 +01:00
|
|
|
|
|
|
|
// The byte to send in the next eventloop iteration
|
2016-12-01 01:06:14 +01:00
|
|
|
_Atomic uint8_t uart_tx_byte;
|
2016-12-03 19:17:54 +01:00
|
|
|
// TX state variable
|
2016-12-01 01:06:14 +01:00
|
|
|
_Atomic enum UartTxState uart_tx_state;
|
2016-11-26 16:49:03 +01:00
|
|
|
|
2016-12-03 19:17:54 +01:00
|
|
|
// Flag to stop the event loop thread
|
2016-12-01 01:06:14 +01:00
|
|
|
_Atomic int stop_event_thread;
|
2016-12-03 19:17:54 +01:00
|
|
|
// Handle to the event loop thread
|
2016-11-30 22:47:26 +01:00
|
|
|
pthread_t event_thread;
|
2016-11-26 16:49:03 +01:00
|
|
|
|
2016-12-03 19:17:54 +01:00
|
|
|
// Mutex that protects the general sss7 state from concurrent modification
|
|
|
|
pthread_mutex_t state_mutex;
|
|
|
|
// Mutex that protects the rx buffer from concurrent modification
|
|
|
|
pthread_mutex_t rx_buffer_mutex;
|
|
|
|
|
|
|
|
// File handle for the serial port
|
2016-11-30 22:47:26 +01:00
|
|
|
int serial_fd;
|
2016-11-26 16:49:03 +01:00
|
|
|
|
2016-12-03 19:17:54 +01:00
|
|
|
|
|
|
|
// Generate a millisecond timestamp from gettimeofday
|
|
|
|
unsigned long get_milliseconds(void) {
|
2016-12-01 00:16:42 +01:00
|
|
|
struct timeval tv;
|
|
|
|
gettimeofday(&tv,NULL);
|
|
|
|
return tv.tv_sec * 1000 + tv.tv_usec / 1000;
|
|
|
|
}
|
|
|
|
|
2016-12-03 19:17:54 +01:00
|
|
|
// Open the serial port and configure it
|
|
|
|
int serial_init(char *serialport) {
|
2016-11-26 16:49:03 +01:00
|
|
|
serial_fd = open(serialport, O_RDWR | O_NOCTTY | O_NDELAY);
|
|
|
|
if (serial_fd == -1) {
|
|
|
|
perror("Error: Unable to open serialport");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
//Switch to blocking mode
|
|
|
|
fcntl(serial_fd, F_SETFL, 0);
|
|
|
|
|
2016-12-03 19:17:54 +01:00
|
|
|
// Set baudrates for input and output
|
2016-11-26 16:49:03 +01:00
|
|
|
struct termios options;
|
|
|
|
cfsetispeed(&options, B9600);
|
|
|
|
cfsetospeed(&options, B9600);
|
|
|
|
|
|
|
|
// 8N1
|
|
|
|
options.c_cflag = (CLOCAL | CREAD);
|
|
|
|
options.c_cflag |= CS8;
|
|
|
|
|
|
|
|
// Raw mode, no features
|
|
|
|
options.c_lflag = 0;
|
|
|
|
|
|
|
|
// No parity checks, no flow control
|
|
|
|
options.c_iflag = 0;
|
|
|
|
|
|
|
|
// No output processing
|
|
|
|
options.c_oflag = 0;
|
|
|
|
|
2016-12-01 01:06:14 +01:00
|
|
|
// A timeout of 0.1 seconds for each character
|
2016-12-01 00:16:42 +01:00
|
|
|
options.c_cc[VTIME] = 1;
|
2016-11-26 16:49:03 +01:00
|
|
|
options.c_cc[VMIN] = 0;
|
|
|
|
tcsetattr(serial_fd, TCSAFLUSH, &options);
|
|
|
|
|
2016-11-30 22:47:26 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-12-03 19:17:54 +01:00
|
|
|
|
|
|
|
// Event loop thread, design to emulate the uart interrupts on AVR8
|
2016-12-01 01:06:14 +01:00
|
|
|
void *eventloop(void *arg) {
|
|
|
|
int res = 0;
|
2016-12-03 19:17:54 +01:00
|
|
|
unsigned long timestamp = get_milliseconds();
|
2016-12-01 01:06:14 +01:00
|
|
|
|
|
|
|
while(!stop_event_thread) {
|
2016-12-03 19:17:54 +01:00
|
|
|
|
|
|
|
// Send a byte, if there is one
|
2016-12-01 01:06:14 +01:00
|
|
|
if(uart_tx_state == TX_HAS_BYTE) {
|
|
|
|
write(serial_fd, &uart_tx_byte, 1);
|
|
|
|
printf("Send %x\n", uart_tx_byte);
|
|
|
|
uart_tx_state = TX_COMPLETE;
|
|
|
|
}
|
|
|
|
|
2016-12-03 19:17:54 +01:00
|
|
|
// Read back the byte, that was just send.
|
|
|
|
// Or read a byte send by somebody else.
|
2016-12-01 01:06:14 +01:00
|
|
|
res = read(serial_fd, &uart_rx_byte, 1);
|
|
|
|
if(res == 1) {
|
2016-12-04 20:51:19 +01:00
|
|
|
printf("Read %x\n", uart_rx_byte);
|
2016-12-03 19:17:54 +01:00
|
|
|
// Lock mutexes and call rx handler
|
2016-12-01 01:06:14 +01:00
|
|
|
pthread_mutex_lock(&state_mutex);
|
|
|
|
pthread_mutex_lock(&rx_buffer_mutex);
|
|
|
|
sss7_process_rx();
|
|
|
|
pthread_mutex_unlock(&rx_buffer_mutex);
|
|
|
|
pthread_mutex_unlock(&state_mutex);
|
|
|
|
}
|
|
|
|
|
2016-12-03 19:17:54 +01:00
|
|
|
// Call the tx handler if there has been a byte sent in this iteration
|
2016-12-01 01:06:14 +01:00
|
|
|
if(uart_tx_state == TX_COMPLETE) {
|
|
|
|
// Keep this before sss7_process_tx
|
|
|
|
// uart_put_byte might need to overwrite it
|
|
|
|
uart_tx_state = TX_IDLE;
|
|
|
|
|
|
|
|
pthread_mutex_lock(&state_mutex);
|
|
|
|
sss7_process_tx();
|
|
|
|
pthread_mutex_unlock(&state_mutex);
|
|
|
|
}
|
|
|
|
|
2016-12-03 19:17:54 +01:00
|
|
|
// Lock muxte and call the timeout handler
|
2016-12-01 01:06:14 +01:00
|
|
|
pthread_mutex_lock(&state_mutex);
|
|
|
|
int now = get_milliseconds();
|
|
|
|
sss7_process_ticks(now - timestamp);
|
|
|
|
timestamp = now;
|
|
|
|
pthread_mutex_unlock(&state_mutex);
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
2016-11-30 22:47:26 +01:00
|
|
|
|
2016-12-03 19:17:54 +01:00
|
|
|
|
|
|
|
// Setup function for the serialport and the eventloop thread
|
|
|
|
// Return 0 on succes -1 on failure.
|
2016-11-30 22:47:26 +01:00
|
|
|
int libsss7_start(char *serialport) {
|
2016-11-26 16:49:03 +01:00
|
|
|
int res = 0;
|
|
|
|
|
2016-11-30 22:47:26 +01:00
|
|
|
sss7_init();
|
2016-12-03 19:17:54 +01:00
|
|
|
res = serial_init(serialport);
|
2016-11-30 22:47:26 +01:00
|
|
|
if(res) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2016-12-01 01:06:14 +01:00
|
|
|
uart_tx_state = TX_IDLE;
|
|
|
|
stop_event_thread = 0;
|
2016-11-30 22:47:26 +01:00
|
|
|
|
|
|
|
pthread_mutex_init(&state_mutex, NULL);
|
|
|
|
pthread_mutex_init(&rx_buffer_mutex, NULL);
|
|
|
|
|
|
|
|
res = pthread_create(&event_thread, NULL, eventloop, NULL);
|
|
|
|
if(res) {
|
|
|
|
printf("Could not create eventloop thread\n");
|
|
|
|
return -1;
|
2016-11-26 16:49:03 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-12-03 19:17:54 +01:00
|
|
|
|
|
|
|
// Teardown function for serialport and event loop thread
|
2016-12-01 01:06:14 +01:00
|
|
|
void libsss7_stop() {
|
|
|
|
stop_event_thread = 1;
|
|
|
|
pthread_join(event_thread, NULL);
|
|
|
|
|
|
|
|
close(serial_fd);
|
|
|
|
}
|
|
|
|
|
2016-12-03 19:17:54 +01:00
|
|
|
// Wrapper for sss7_can_send
|
2016-11-26 16:49:03 +01:00
|
|
|
int libsss7_can_send(void) {
|
|
|
|
return sss7_can_send();
|
|
|
|
}
|
|
|
|
|
2016-12-03 19:17:54 +01:00
|
|
|
// Wrapper for sss7_send, also locks the state_mutex
|
2016-11-26 16:49:03 +01:00
|
|
|
void libsss7_send(uint8_t msg[SSS7_PAYLOAD_SIZE]) {
|
2016-11-30 22:47:26 +01:00
|
|
|
pthread_mutex_lock(&state_mutex);
|
|
|
|
sss7_send(msg);
|
|
|
|
pthread_mutex_unlock(&state_mutex);
|
2016-11-26 16:49:03 +01:00
|
|
|
}
|
|
|
|
|
2016-12-03 19:17:54 +01:00
|
|
|
// Wrapper for sss7_send_failed
|
2016-11-26 16:49:03 +01:00
|
|
|
int libsss7_send_failed(void) {
|
|
|
|
return sss7_send_failed();
|
|
|
|
}
|
|
|
|
|
2016-12-03 19:17:54 +01:00
|
|
|
// Wrapper for sss7_has_received
|
2016-11-26 16:49:03 +01:00
|
|
|
int libsss7_has_received(void) {
|
|
|
|
return sss7_has_received();
|
|
|
|
}
|
|
|
|
|
2016-12-03 19:17:54 +01:00
|
|
|
// Wrapper for sss7_get_received, takes care of locking rx buffer mutex
|
2016-11-26 16:49:03 +01:00
|
|
|
void libsss7_get_received(uint8_t msg[SSS7_PAYLOAD_SIZE]) {
|
2016-11-30 22:47:26 +01:00
|
|
|
pthread_mutex_lock(&rx_buffer_mutex);
|
|
|
|
sss7_get_received(msg);
|
|
|
|
pthread_mutex_unlock(&rx_buffer_mutex);
|
2016-11-26 16:49:03 +01:00
|
|
|
}
|
|
|
|
|
2016-12-03 19:17:54 +01:00
|
|
|
// Platform dependent function required by the sss7core
|
2016-11-26 16:49:03 +01:00
|
|
|
uint8_t uart_get_byte(void) {
|
|
|
|
return uart_rx_byte;
|
|
|
|
}
|
|
|
|
|
2016-12-03 19:17:54 +01:00
|
|
|
// Platform dependent function required by the sss7core
|
2016-11-26 16:49:03 +01:00
|
|
|
void uart_put_byte(uint8_t byte) {
|
2016-12-01 01:06:14 +01:00
|
|
|
uart_tx_state = TX_HAS_BYTE;
|
2016-11-26 16:49:03 +01:00
|
|
|
uart_tx_byte = byte;
|
|
|
|
}
|