Created
August 31, 2022 15:52
-
-
Save superna9999/fa31b8b3b42f84c83560679a5f4c5593 to your computer and use it in GitHub Desktop.
no comments
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <piccolo_config.h> | |
#include "termios.h" | |
#include "stdio.h" | |
#include "stdlib.h" | |
#include "string.h" | |
#include "fcntl.h" | |
#include "unistd.h" | |
#include "sys/signal.h" | |
#include "sys/socket.h" | |
#include "sys/types.h" | |
#include "netinet/in.h" | |
#include "errno.h" | |
#include "PSTN.h" | |
#include <sys/select.h> | |
#include "time.h" | |
#include "stdbool.h" | |
#include "unistd.h" | |
#include "sys/ioctl.h" | |
#include <sys/select.h> | |
#include "uart.h" | |
struct termios ttyset; | |
static bool uarts_initialised = false; | |
static UART_t uarts[UART_NUMBERS]; | |
static bool cb_in_progress; | |
static void UART1_transmitt(char *buffer_ptr, uint32_t size); | |
static void UART2_transmitt(char *buffer_ptr, uint32_t size); | |
static void UART3_transmitt(char *buffer_ptr, uint32_t size); | |
static void UART4_transmitt(char *buffer_ptr, uint32_t size); | |
static void UART5_transmitt(char *buffer_ptr, uint32_t size); | |
static void UARTUSB0_transmitt(char *buffer_ptr, uint32_t size); | |
static void UARTUSB1_transmitt(char *buffer_ptr, uint32_t size); | |
static void* UART1_worker(void *arg); | |
static void* UART2_worker(void *arg); | |
static void* UART3_worker(void *arg); | |
static void* UART4_worker(void *arg); | |
static void* UART5_worker(void *arg); | |
static void* UARTUSB0_worker(void *arg); | |
static void* UARTUSB1_worker(void *arg); | |
/* ttyO0 is reserved for the terminal */ | |
#if(SDK_VERSION == 314) | |
const char* UART_tty_devices[] = { "/dev/ttyO1", "/dev/ttyO2", "/dev/ttyO3", "/dev/ttyO4", "/dev/ttyO5", "/dev/ttyUSB0", "/dev/ttyUSB1" }; | |
#elif(SDK_VERSION == 404) | |
const char* UART_tty_devices[] = { "/dev/ttyS1", "/dev/ttyS2", "/dev/ttyS3", "/dev/ttyS4", "/dev/ttyS5", "/dev/ttyUSB0", "/dev/ttyUSB1" }; | |
#else | |
#error "SDK_VERSION not supported. Supported versions are 314 and 414" | |
#endif | |
////"/dev/ttyS1", "/dev/ttyS2", "/dev/ttyS3", "/dev/ttyS4", "/dev/ttyS5" | |
//const char* UART_tty_devices[] = { "/dev/ttyO1", "/dev/ttyO2", "/dev/ttyO3", "/dev/ttyO4", "/dev/ttyO5", "/dev/ttyUSB0", "/dev/ttyUSB1" }; | |
static uint32_t get_uart_bdr_mask(UART_baud_rate_t bdr) | |
{ | |
switch (bdr) { | |
case UART_BAUD_2400: | |
return B2400; | |
case UART_BAUD_4800: | |
return B4800; | |
case UART_BAUD_9600: | |
return B9600; | |
case UART_BAUD_19200: | |
return B19200; | |
case UART_BAUD_38400: | |
return B38400; | |
case UART_BAUD_57600: | |
return B57600; | |
case UART_BAUD_115200: | |
return B115200; | |
default: | |
return B9600; | |
} | |
} | |
/** | |
* Initialise selected UART | |
* @param[in] modem_id modem | |
* @return char array with device name | |
*/ | |
bool UART_open(UART_id_t id, UART_baud_rate_t bdr, UART_num_of_stop_bits_t stop_bits, UART_parity_t parity) | |
{ | |
int err; | |
char* uart_dev = UART_get_device(id); | |
if (uart_dev != NULL) { | |
uarts[id].fd = open(uart_dev, O_RDWR | O_NOCTTY); | |
if (uarts[id].fd < 0) { | |
return false; | |
} | |
} else { | |
return false; | |
} | |
bzero(&ttyset, sizeof(ttyset)); | |
err = cfsetispeed(&ttyset, get_uart_bdr_mask(bdr)); | |
err += cfsetospeed(&ttyset, get_uart_bdr_mask(bdr)); | |
ttyset.c_cflag = get_uart_bdr_mask(bdr) | /*CRTSCTS |*/CS8 | CLOCAL | CREAD; | |
if (stop_bits == UART_2STOP_BIT) { | |
ttyset.c_cflag |= CSTOPB; | |
} | |
if (parity == NO_PARITY) { | |
ttyset.c_cflag &= ~PARENB; | |
} else if (parity == EVEN_PARITY) { | |
ttyset.c_cflag |= PARENB; | |
ttyset.c_cflag &= ~PARODD; | |
} else if (parity == ODD_PARITY) { | |
ttyset.c_cflag |= (PARENB | PARODD); | |
} | |
ttyset.c_iflag = IGNPAR; | |
ttyset.c_oflag = 0; | |
/* set input mode (non-canonical, no echo,...) */ | |
ttyset.c_lflag &= ~ICANON; /* Set non-canonical mode */ | |
ttyset.c_cc[VTIME] = 100; /* Set timeout of 10.0 seconds */ | |
ttyset.c_lflag = 0; | |
ttyset.c_cc[VTIME] = 0; /* inter-character timer unused */ | |
ttyset.c_cc[VMIN] = 1; /* blocking read until 1 char received */ | |
// fcntl(uarts[id].fd, F_SETFL, 0); // causes read to block until new characters are present / | |
//// fcntl(uarts[id].fd, F_SETFL, FNDELAY); // remove this call as it causes read to return immediately / | |
// | |
// fcntl(uarts[id].fd, F_SETOWN, getpid()); | |
// fcntl(uarts[id].fd, F_SETFL, O_ASYNC); | |
err += tcflush(uarts[id].fd, TCIFLUSH); | |
err += tcsetattr(uarts[id].fd, TCSANOW, &ttyset); | |
if (err == 0) { | |
/* create thread for the UART */ | |
switch (id) { | |
case UART_1: | |
pthread_create(&(uarts[id].uart_thread_id), NULL, &UART1_worker, NULL); | |
break; | |
case UART_2: | |
pthread_create(&(uarts[id].uart_thread_id), NULL, &UART2_worker, NULL); | |
break; | |
case UART_3: | |
pthread_create(&(uarts[id].uart_thread_id), NULL, &UART3_worker, NULL); | |
break; | |
case UART_4: | |
pthread_create(&(uarts[id].uart_thread_id), NULL, &UART4_worker, NULL); | |
break; | |
case UART_5: | |
pthread_create(&(uarts[id].uart_thread_id), NULL, &UART5_worker, NULL); | |
break; | |
case UART_USB0: | |
pthread_create(&(uarts[id].uart_thread_id), NULL, &UARTUSB0_worker, NULL); | |
break; | |
case UART_USB1: | |
pthread_create(&(uarts[id].uart_thread_id), NULL, &UARTUSB1_worker, NULL); | |
break; | |
default: { | |
return false; | |
} | |
} | |
return true; | |
} else { | |
return false; | |
} | |
} | |
/* | |
* Returns true if received message satisfies receiving criteria | |
*/ | |
static bool UART_check_received(UART_id_t id, uint8_t received_byte) | |
{ | |
UART_receiver_t *uart_receiver = &uarts[id].receiver; | |
char last_char = uart_receiver->last_char_received; | |
uart_receiver->last_char_received = received_byte; | |
if (uart_receiver->receive_mode == UART_RX_MODE_BINARY && uart_receiver->expected_bytes > 0) { | |
if ((uart_receiver->data_ptr) >= uart_receiver->expected_bytes) { | |
return true; | |
} | |
} | |
if (uart_receiver->receive_mode == UART_RX_MODE_STRING) { | |
switch (uart_receiver->receive_string_delimiter) { | |
case UART_STRING_DELIMITER_CRLF: { | |
if (last_char == '\r' && received_byte == '\n') { | |
return true; | |
} | |
break; | |
} | |
case UART_STRING_DELIMITER_LF: { | |
if (received_byte == '\n') { | |
return true; | |
} | |
break; | |
} | |
case UART_STRING_DELIMITER_CR: { | |
if (received_byte == '\r') { | |
return true; | |
} | |
break; | |
} | |
} | |
} | |
return false; | |
} | |
/** | |
* Reset receiving pointer to start receiving from beggining of internal buffer | |
* @param[in] id UART id | |
*/ | |
void UART_reset_receiver(UART_id_t id) | |
{ | |
uarts[id].receiver.data_ptr = 0; | |
uarts[id].receiver.received_size = 0; | |
} | |
/* moves all elements from desired position to the beggining of array */ | |
static void move_buffer(uint8_t *buff, uint16_t size, uint16_t from) | |
{ | |
int i; | |
for (i = 0; i < size; i++) { | |
buff[i] = buff[i + from]; | |
} | |
} | |
/* general UART worker function */ | |
static void* UART_worker(UART_id_t id, void *arg) | |
{ | |
uint32_t bytes_avaiable; | |
uint16_t ptr; | |
uint16_t received_size; | |
UART_receiver_t *uart_receiver = &uarts[id].receiver; | |
bytes_avaiable = 0; | |
cb_in_progress = false; | |
while (1) { | |
ptr = uart_receiver->data_ptr; | |
bytes_avaiable = read(uarts[id].fd, &uart_receiver->data[uart_receiver->data_ptr], UART_RX_BUFFER_SIZE); | |
// printf("Bytes %d\n", bytes_avaiable); | |
if (ptr != uart_receiver->data_ptr) { /* pointer is changed during read blocking wait */ | |
move_buffer((uint8_t *) uart_receiver->data, bytes_avaiable, ptr); | |
} | |
uart_receiver->data_ptr += bytes_avaiable; | |
uart_receiver->received_size = uart_receiver->data_ptr; | |
if (UART_check_received(id, uart_receiver->data[uart_receiver->data_ptr - 1])) { | |
received_size = uart_receiver->data_ptr; | |
UART_reset_receiver(id); | |
if (uart_receiver->receive_cb != NULL && uart_receiver->receiver_cb_enabled) { | |
cb_in_progress = true; | |
uart_receiver->receive_cb((char*) uart_receiver->data, received_size, (void*) id); | |
cb_in_progress = false; | |
} | |
} | |
} | |
return arg; | |
} | |
/** | |
* Read directly if there are any bytes available, otherwise return 0 | |
* @param id | |
* @param buffer_ptr | |
* @return 0 if no bytes are available | |
*/ | |
static uint16_t UART_read_direct(UART_id_t id, char *buffer_ptr) | |
{ | |
int bytes_avail; | |
int tmp; | |
ioctl(uarts[id].fd, FIONREAD, &bytes_avail); | |
if (bytes_avail > 0) { | |
tmp = read(uarts[id].fd, buffer_ptr, UART_RX_BUFFER_SIZE); | |
return bytes_avail; | |
} else { | |
return 0; | |
} | |
} | |
uint16_t UART_get_received(UART_id_t id, char *buffer_ptr) | |
{ | |
if (cb_in_progress) { | |
return UART_read_direct(id, buffer_ptr); | |
} | |
memcpy(buffer_ptr, uarts[id].receiver.data, uarts[id].receiver.received_size); | |
return uarts[id].receiver.received_size; | |
} | |
/** | |
* Check if UART is enabled/present in the system | |
* @param[in] id UART id | |
* @return true if UART is enabled | |
*/ | |
bool UART_is_enabled(UART_id_t id) | |
{ | |
if (id == UART_1 && UART1_ENABLED) { | |
return true; | |
} | |
if (id == UART_2 && UART2_ENABLED) { | |
return true; | |
} | |
if (id == UART_3 && UART3_ENABLED) { | |
return true; | |
} | |
if (id == UART_4 && UART4_ENABLED) { | |
return true; | |
} | |
if (id == UART_5 && UART5_ENABLED) { | |
return true; | |
} | |
if (id == UART_USB0 && UARTUSB_ENABLED) { | |
return true; | |
} | |
if (id == UART_USB1 && UARTUSB_ENABLED) { | |
return true; | |
} | |
return false; | |
} | |
/** | |
* Initialise selected UART variables and states and function pointers | |
* @param[in] id UART which is about to be initialized | |
* @return true if UART is present and properly initialised | |
*/ | |
bool UART_init(UART_id_t id) | |
{ | |
if (!UART_is_enabled(id)) { | |
return false; | |
} | |
uarts[id].fd = (int) NULL; | |
uarts[id].receiver.receive_cb = NULL; | |
uarts[id].id = id; | |
switch (id) { | |
case UART_1: | |
uarts[id].transmit_cb = UART1_transmitt; | |
break; | |
case UART_2: | |
uarts[id].transmit_cb = UART2_transmitt; | |
break; | |
case UART_3: | |
uarts[id].transmit_cb = UART3_transmitt; | |
break; | |
case UART_4: | |
uarts[id].transmit_cb = UART4_transmitt; | |
break; | |
case UART_5: | |
uarts[id].transmit_cb = UART5_transmitt; | |
break; | |
case UART_USB0: | |
uarts[id].transmit_cb = UARTUSB0_transmitt; | |
break; | |
case UART_USB1: | |
uarts[id].transmit_cb = UARTUSB1_transmitt; | |
break; | |
} | |
return true; | |
} | |
/** | |
* Initialise all UARTs in system to default values and states | |
*/ | |
void UART_init_all() | |
{ | |
int i; | |
if (!uarts_initialised) { | |
for (i = UART_1; i <= UART_USB1; i++) { | |
UART_init(i); | |
uarts_initialised = true; | |
} | |
} | |
} | |
/** | |
* Initialise selected UART | |
* @param[in] modem_id modem | |
* @return char array with device name | |
*/ | |
char* UART_get_device(UART_id_t id) | |
{ | |
if (id <= UART_USB1) { | |
return (char*) UART_tty_devices[id]; | |
} else { | |
return NULL; | |
} | |
} | |
/** | |
* Wait for string to be received before invoking receiver callback | |
* @param[in] id UART id | |
* @param[in] lines number of text lines (terminated with delimiter) | |
* @param[in] delimiter defines how text lines delimitations shoud be handled | |
*/ | |
void UART_receive_strings(UART_id_t id, uint8_t lines, UART_receive_string_delimiter_t delimiter) | |
{ | |
uarts[id].receiver.expected_lines = lines; | |
uarts[id].receiver.receive_string_delimiter = delimiter; | |
uarts[id].receiver.receive_mode = UART_RX_MODE_STRING; | |
} | |
/** | |
* Wait for string to be received before invoking receiver callback | |
* @param[in] id UART id | |
* @param[in] expected_bytes bytes to receive before receiving callback invoking | |
*/ | |
void UART_receive_data(UART_id_t id, uint16_t expected_bytes) | |
{ | |
uarts[id].receiver.data_ptr = 0; | |
uarts[id].receiver.expected_bytes = expected_bytes; | |
uarts[id].receiver.receive_mode = UART_RX_MODE_BINARY; | |
} | |
/** | |
* Get UART receive mode | |
* @param[in] id UART id | |
* @return UART receive mode | |
*/ | |
UART_receive_mode_t UART_get_receive_mode(UART_id_t id) | |
{ | |
return uarts[id].receiver.receive_mode; | |
} | |
/*UNUSED*/ | |
//static void set_termios_rec_bytes(UART_id_t id, uint16_t expected_bytes) { | |
// | |
// tcflush(uarts[id].fd, TCIOFLUSH); | |
// tcgetattr(uarts[id].fd, &ttyset); | |
// ttyset.c_cc[VMIN] = expected_bytes; /* blocking read until 1 char received */ | |
// tcsetattr(uarts[id].fd, TCSANOW, &ttyset); | |
//} | |
/** | |
* Set callback function for receiver. Setting automatically enables callback if callback is not NULL | |
* @param[in] id UART id | |
* @param[in] receiver callback function | |
*/ | |
void UART_set_receive_cb(UART_id_t id, stream_receiver_cb_t cb_funct) | |
{ | |
uarts[id].receiver.receive_cb = cb_funct; | |
uarts[id].receiver.receiver_cb_enabled = cb_funct != NULL; | |
} | |
/** | |
* Set callback function for receiver. | |
* @param[in] id UART idasas | |
* @return pointer to receiver callback function | |
*/ | |
stream_receiver_cb_t UART_get_receive_cb(UART_id_t id) | |
{ | |
return uarts[id].receiver.receive_cb; | |
} | |
/** | |
* Enables/Disables UART receiver callback | |
* @param[in] id UART id | |
* @param[in] enable true to enable, false to disable | |
*/ | |
void UART_enable_receive_cb(UART_id_t id, bool enable) | |
{ | |
uarts[id].receiver.receiver_cb_enabled = enable; | |
} | |
/** | |
* Gets enabled state of selected UART receiver | |
* @param[in] id UART id | |
* @return true or false (enabled/disabled) | |
*/ | |
bool UART_is_receive_cb_enabled(UART_id_t id) | |
{ | |
return uarts[id].receiver.receiver_cb_enabled; | |
} | |
/** | |
* Transmits buffer on the UART | |
* @param[in] id UART id | |
* @param[in] buffer_ptr contains data to transmitt | |
* @param[in] size number of bytes for transmitting | |
*/ | |
void UART_transmitt(UART_id_t id, char *buffer_ptr, uint32_t size) | |
{ | |
FILE* f_ptr = (FILE*) uarts[id].fd; | |
if (f_ptr != NULL) { | |
write((int) f_ptr, buffer_ptr, size); | |
} | |
} | |
/* Transmitt wrappers */ | |
static void UART1_transmitt(char *buffer_ptr, uint32_t size) | |
{ | |
UART_transmitt(UART_1, buffer_ptr, size); | |
} | |
static void UART2_transmitt(char *buffer_ptr, uint32_t size) | |
{ | |
UART_transmitt(UART_2, buffer_ptr, size); | |
} | |
static void UART3_transmitt(char *buffer_ptr, uint32_t size) | |
{ | |
UART_transmitt(UART_3, buffer_ptr, size); | |
} | |
static void UART4_transmitt(char *buffer_ptr, uint32_t size) | |
{ | |
UART_transmitt(UART_4, buffer_ptr, size); | |
} | |
static void UART5_transmitt(char *buffer_ptr, uint32_t size) | |
{ | |
UART_transmitt(UART_5, buffer_ptr, size); | |
} | |
static void UARTUSB0_transmitt(char *buffer_ptr, uint32_t size) | |
{ | |
UART_transmitt(UART_USB0, buffer_ptr, size); | |
} | |
static void UARTUSB1_transmitt(char *buffer_ptr, uint32_t size) | |
{ | |
UART_transmitt(UART_USB1, buffer_ptr, size); | |
} | |
/** | |
* Gets transmitter funcition pointer for a UART | |
* @param[in] id UART id | |
* @return pointer to a transmitt function of an UART | |
*/ | |
stream_transmitter_cb_t UART_get_transmitter(UART_id_t id) | |
{ | |
return uarts[id].transmit_cb; | |
} | |
/* UART worker wrappers */ | |
static void* UART1_worker(void *arg) | |
{ | |
return UART_worker(UART_1, arg); | |
} | |
static void* UART2_worker(void *arg) | |
{ | |
return UART_worker(UART_2, arg); | |
} | |
static void* UART3_worker(void *arg) | |
{ | |
return UART_worker(UART_3, arg); | |
} | |
static void* UART4_worker(void *arg) | |
{ | |
return UART_worker(UART_4, arg); | |
} | |
static void* UART5_worker(void *arg) | |
{ | |
return UART_worker(UART_5, arg); | |
} | |
static void* UARTUSB0_worker(void *arg) | |
{ | |
return UART_worker(UART_USB0, arg); | |
} | |
static void* UARTUSB1_worker(void *arg) | |
{ | |
return UART_worker(UART_USB1, arg); | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment