Last active
August 11, 2021 23:31
-
-
Save lorsi96/aaaa185ccbc849a53e3ac04697805e89 to your computer and use it in GitHub Desktop.
[Sistemas Operativos de Propósito General] TP II
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
/** | |
* @file main.c | |
* @author Lucas Orsi (lorsi@itba.edu.ar) | |
* @version 0.1 | |
* @date 2021-08-07 | |
* | |
* @copyright Copyright (c) 2021 | |
* | |
*/ | |
/* ****************************************************************************************************************** */ | |
/* Includes */ | |
/* ****************************************************************************************************************** */ | |
#include <stdio.h> | |
#include <sys/types.h> | |
#include <sys/socket.h> | |
#include <stdlib.h> | |
#include <unistd.h> | |
#include <errno.h> | |
#include <pthread.h> | |
#include <string.h> | |
#include <netinet/in.h> | |
#include <stdbool.h> | |
#include <arpa/inet.h> | |
#include <signal.h> | |
#include <netdb.h> | |
#include "SerialManager.h" | |
/* ****************************************************************************************************************** */ | |
/* Macros */ | |
/* ****************************************************************************************************************** */ | |
#define SOPG_ASSERT(exp, msg) \ | |
{ \ | |
if ((exp) <= -1) { \ | |
perror("[ERROR]" msg "\r\n"); \ | |
if (s) close(s); \ | |
if (u) serial_close(); \ | |
exit(1); \ | |
} \ | |
\ | |
} | |
#define S_LOOP_ASSERT(exp, msg) \ | |
{ \ | |
if ((exp) <= -1) { \ | |
if(!show_must_go_on) break; \ | |
perror("[ERROR]" msg "\r\n"); \ | |
if (s) close(s); \ | |
if (u) serial_close(); \ | |
exit(1); \ | |
} \ | |
\ | |
} | |
#define LOGD(format, ...) \ | |
DEBUG&& fprintf(stdout, "[DEBUG]: " format "\r\n", ##__VA_ARGS__); | |
/* ****************************************************************************************************************** */ | |
/* Constants */ | |
/* ****************************************************************************************************************** */ | |
#define ISERVICE_PORT 10000 | |
#define BUFFER_SIZE 128 | |
#define BACKLOG 10 | |
#define LOALHOST "127.0.0.1" | |
#define SW_MSG_SIZE 9 | |
#define EMPTY_CHAR 32 | |
#define UART_BPS 115200 | |
#define UART_USB1 1 | |
#define UART_SLEEP_US 3000 | |
#define UART_SOM '>' | |
#define DEBUG true | |
/* ****************************************************************************************************************** */ | |
/* Private Variables */ | |
/* ****************************************************************************************************************** */ | |
static bool show_must_go_on = true; | |
static int newfd; | |
static int s; | |
static int u; | |
pthread_mutex_t socket_writeable_lock = PTHREAD_MUTEX_INITIALIZER; | |
/* ****************************************************************************************************************** */ | |
/* Private Functions */ | |
/* ****************************************************************************************************************** */ | |
static inline void forward_msg_to_socket(char* buffer, size_t len) { | |
LOGD("UART is about to write to the Socket"); | |
pthread_mutex_lock(&socket_writeable_lock); | |
SOPG_ASSERT(write(newfd, buffer, len), "Error writing to Socket"); | |
pthread_mutex_unlock(&socket_writeable_lock); | |
LOGD("UART wrote to the Socket and unlocked it"); | |
} | |
static void* uart_thread(void* _) { | |
static const char MSG_LEN = 7; | |
static char uartbuff[BUFFER_SIZE] = {EMPTY_CHAR}; | |
static uint8_t sz; | |
for (;;) { | |
if (sz = serial_receive(uartbuff, BUFFER_SIZE)) { | |
LOGD("(UART)\tRead(%dby): %s", sz, uartbuff); | |
if (sz != SW_MSG_SIZE) { | |
perror("Ignorning invalid msg"); | |
continue; | |
} | |
forward_msg_to_socket(uartbuff, MSG_LEN); | |
} | |
usleep(UART_SLEEP_US); | |
} | |
} | |
static void signals_handler(int signal) { | |
show_must_go_on = false; | |
} | |
static void block_signals(bool block) { | |
sigset_t set; | |
sigemptyset(&set); | |
sigaddset(&set, SIGINT); | |
sigaddset(&set, SIGTERM); | |
SOPG_ASSERT(pthread_sigmask(block ? SIG_BLOCK : SIG_UNBLOCK, &set, NULL), | |
"Unable to block/unblock Signals"); | |
} | |
/* ****************************************************************************************************************** */ | |
/* Main */ | |
/* ****************************************************************************************************************** */ | |
int main() { | |
socklen_t addr_len; | |
struct sockaddr_in clientaddr; | |
struct sockaddr_in serveraddr; | |
pthread_t t1; | |
char buffer[BUFFER_SIZE]; | |
struct sigaction sa; | |
sa.sa_handler = signals_handler; | |
sa.sa_flags = 0; | |
sigemptyset(&sa.sa_mask); | |
SOPG_ASSERT(sigaction(SIGINT, &sa, NULL), "Failed at Configuring SIGINT handler"); | |
SOPG_ASSERT(sigaction(SIGTERM, &sa, NULL), "Failed at Configuring SIGTERM handler" ); | |
LOGD("Initializing UART /dev/ttyUSB%d", UART_USB1); | |
SOPG_ASSERT(u = serial_open(UART_USB1, UART_BPS), "Failed to init UART"); | |
LOGD("UART initialized"); | |
// Creamos socket | |
SOPG_ASSERT(s = socket(AF_INET, SOCK_STREAM, 0), "Failed to create Socket"); | |
bzero((char*)&serveraddr, sizeof(serveraddr)); | |
serveraddr.sin_family = AF_INET; | |
serveraddr.sin_port = htons(ISERVICE_PORT); | |
SOPG_ASSERT(inet_pton(AF_INET, LOALHOST, &(serveraddr.sin_addr)), | |
"Invalid server IP"); | |
// Abrimos puerto con bind() | |
if (bind(s, (struct sockaddr*)&serveraddr, sizeof(serveraddr)) == -1) { | |
close(s); | |
perror("listener: bind"); | |
return 1; | |
} | |
LOGD("Socket bound"); | |
SOPG_ASSERT(listen(s, BACKLOG), "Sockets listening error"); | |
LOGD("Socket Listening"); | |
// We lock the Socket Mutex until it's ready to be written -- a client is connected. | |
pthread_mutex_lock(&socket_writeable_lock); | |
LOGD("Socket Locked -- No one can write to it! (internally)"); | |
block_signals(/*block=*/true); | |
SOPG_ASSERT(pthread_create(&t1, NULL, uart_thread, NULL), | |
"Failed to create UART Thread"); | |
block_signals(/*block=*/false); | |
LOGD("UART listening to incoming serial packets"); | |
while (show_must_go_on) { | |
int n; | |
char ipClient[32]; | |
addr_len = sizeof(struct sockaddr_in); | |
S_LOOP_ASSERT(newfd = accept(s, (struct sockaddr*)&clientaddr, &addr_len), | |
"Accept Error"); | |
inet_ntop(AF_INET, &(clientaddr.sin_addr), ipClient, sizeof(ipClient)); | |
LOGD("Socket accepted a new client"); | |
// Now we allow other processes to write to our socket. | |
pthread_mutex_unlock(&socket_writeable_lock); | |
LOGD("Socket Unlocked -- UART Thread can write to the Socket now"); | |
while ((n = read(newfd, buffer, BUFFER_SIZE)) > 0) { | |
if(!show_must_go_on) break; | |
buffer[n] = '\0'; | |
LOGD("(Socket)Read(%dby): %s", n, buffer); | |
serial_send(buffer, n); | |
} | |
LOGD("Socket lost a client"); | |
// We block the socket until a new client is accepted. | |
pthread_mutex_lock(&socket_writeable_lock); | |
LOGD("Socket Locked -- There're no clients to send data to"); | |
S_LOOP_ASSERT(n, "Error reading message in Socket"); | |
} | |
LOGD("Terminating program"); | |
LOGD("Cancelling UART Thread"); | |
pthread_cancel(t1); | |
pthread_join(t1, NULL); | |
LOGD("Closing UART"); | |
serial_close(); | |
LOGD("Closing Socket"); | |
close(newfd); | |
close(s); | |
LOGD("That's all folks"); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment