commit e9e8a5cc1eb1212272288b14035aa4e5a4641cd1 Author: Jozef Šimko Date: Fri May 20 12:25:09 2022 +0200 final diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..9706db3 --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ +server +server.exe +client +client.exe +demo +demo.exe +logy.txt +auto-logy.txt diff --git a/README.md b/README.md new file mode 100644 index 0000000..be2a91e --- /dev/null +++ b/README.md @@ -0,0 +1,40 @@ +# TestBP + +## About +This repository contains source codes for client-server network application capable to communicate with distance laser sensor DLS-C 15 via RS-232 interface, which was implemented as a part of bachelor thesis. + +## Author +Author: Jozef Simko + +School year: 3., Bachelor study, 2021/22 + +Study program: Computer Networks + +Organization: Technical University of Kosice (TUKE), Faculty of Electrical Engineering and Informatics (FEI) + +## Building +Implemented and tested on: +| Platform | OS | compiler | +|-----------------|---------------------------|-------------------------------------------------| +| Linux | Ubuntu 20.04.1 WLS2 | gcc version 9.3.0 (Ubuntu 9.3.0-10ubuntu2) | +| Windows | Windows 10.0.19043 | gcc version 11.2.0 (MinGW-W64 x86_64-posix-seh) | +| Raspberry Pi | Linux raspberrypi 5.10.17 | gcc version 8.3.0 (Raspbian 8.3.0-6+rpi1) | + +### LINUX + + +### WINDOWS + + +## Launch +### Server +Program *serveru* je po kompilácii možné spustiť v 2 režimoch: +* manuálny režim (./server port) +* automatický režim (./server port config_file) + +### Client +### Demo + +## References +[WinLibs GCC](https://winlibs.com) + diff --git a/autostart.sh b/autostart.sh new file mode 100644 index 0000000..4cdda66 --- /dev/null +++ b/autostart.sh @@ -0,0 +1,7 @@ +#!/bin/bash + +PORT=32500 +server_path="/home/pi/Desktop/TestBP/server" +cfg_path="/home/pi/Desktop/TestBP/config.txt" + +$server_path $PORT $cfg_path diff --git a/client.c b/client.c new file mode 100644 index 0000000..0ff3134 --- /dev/null +++ b/client.c @@ -0,0 +1,316 @@ +/* +Author: Jozef Simko +School year: 3., Bachelor study, 2021/22 +Study program: Computer Networks +Organization: Technical University of Kosice (TUKE), Faculty of Electrical Engineering and Informatics (FEI), + +Compiler: Winlibs GCC -- MinGW-W64 x86_64-posix-seh version 11.2.0, built by Brecht Sanders (OS Win) + -- gcc version 9.3.0 (OS Linux) + +compile: WIN -- gcc client.c -Wall -Wextra -lwsock32 -o client + LINUX -- gcc server.c -Wall -Wextra -o server +version: 1.2 , 17.5.2021 +Usage: Program can communicate with second program (server) using sockets. + It works in active or passive mode according to settings of server. +*/ + +#ifdef _WIN32 +#define WIN32_LEAN_AND_MEAN +#include +#else +#include +#include +#include +#include +#include +#endif +#include +#include +#include +#include + +/* Defines lenght of user input and output send to server +Should not be less than longest user command in commands.txt file */ +#define MESSAGE_SIZE 16 + +/* Defines lenght of buffer for server's messages +It's better to use higher values, it's helpful in case of hardware/network overload */ +#define REPLY_MSG_SIZE 2048 + +/* Defines exact amount of user commands in commands.txt file and works as safety feature +Should not be less than number of lines in commands.txt file */ +#define CMD_BUF_SIZE 13 + +/* Defines lenght of buffer used to read line from commands.txt file +Should not be less than the longest line in file commands.txt */ +#define LINE_SIZE 256 + +/*########################################### + DEFINED FUNCTIONS +#############################################*/ + +/* +Writes input to log file with time stamp +*/ +void write_log(FILE *log, char *mess){ + time_t rawtime; + struct tm * timeinfo; + + time(&rawtime); + timeinfo = localtime(&rawtime); + + mess[strcspn(mess, "\r")] = 0; + + fprintf (log, "%02d/%02d/%d - %02d:%02d:%02d: %s\n", timeinfo->tm_mday, timeinfo->tm_mon+1, timeinfo->tm_year+1900, + timeinfo->tm_hour, timeinfo->tm_min, timeinfo->tm_sec, mess); + return; +} + +/* +Closes socket (with dependency on used OS) +*/ +void cleanUP(int sock){ +#ifdef WIN32 + closesocket(sock); + WSACleanup(); +#else + close(sock); +#endif + return; +} + +/* +Frees allocated memory of pointer to array of chars +*/ +void freeCMD(char *commands[], char *ls_commands[], char *description[], int i){ + for(int f=0; f < i; f++){ + free(commands[f]); + free(ls_commands[f]); + free(description[f]); + } + return; +} + +/* ######################################### */ + +int main(int argc , char *argv[]){ + + if (argc != 3){ + fprintf(stderr, "Usage:\n"); + fprintf(stderr, "- %s \n", argv[0]); + return 1; + } + + int sock; + struct sockaddr_in server; + char message[MESSAGE_SIZE]; + char server_reply[REPLY_MSG_SIZE]; + +#ifdef WIN32 + WSADATA wsaData; + int iResult = WSAStartup(MAKEWORD(2, 2), &wsaData); + if (iResult != 0){ + printf("WSASturtup() failed %d\n", iResult); + return 1; + } +#endif + + // Create socket + if ((sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0){ + printf("socket() failed\n"); + cleanUP(sock); + return 1; + } + + memset(&server, 0, sizeof(server)); + server.sin_family = AF_INET; + server.sin_addr.s_addr = inet_addr(argv[1]); + server.sin_port = htons(atoi(argv[2])); + + // Connect to remote server + if (connect(sock, (struct sockaddr *) &server, sizeof(server)) != 0){ + printf("Cannot connect to server - please check IP, port and status of server before trying again!\n"); + cleanUP(sock); + return 1; + } + + memset(server_reply, 0, REPLY_MSG_SIZE); + + if(recv(sock, server_reply, 2, 0) <= 0){ + printf("Connection interrupted! Check server status!\n"); + cleanUP(sock); + return 1; + } + + // Check server's mode + int automatic = 0; + if(strcmp(server_reply, "0") == 0){ + printf("Connected - manual mode.\n"); + } + else{ + printf("Connected - automatic mode.\n"); + automatic = 1; + } + + char *commands[CMD_BUF_SIZE]; + char *ls_commands[CMD_BUF_SIZE]; + char *description[CMD_BUF_SIZE]; + int i = 0; + + if(automatic == 0){ + + // Load user commands + FILE *fptr; + if ((fptr = fopen("commands.txt", "r")) == NULL) { + printf("Cannot open/create log file!\n"); + cleanUP(sock); + return 1; + } + char line[LINE_SIZE]; + memset(line, 0, LINE_SIZE); + while(fgets(line, sizeof(line), fptr) != NULL) { + char *rest = line; + char *cmd = strtok_r(line, ":", &rest); + char *ls_cmd = strtok_r(rest, ":", &rest); + char *des = strtok_r(rest, ":", &rest); + commands[i] = (char *)calloc(strlen(cmd)+2, sizeof(char)); + strcpy(commands[i], cmd); + + ls_commands[i] = (char *)calloc(strlen(ls_cmd)+2, sizeof(char)); + strcpy(ls_commands[i], ls_cmd); + + description[i] = (char *)calloc(strlen(des)+2, sizeof(char)); + strcpy(description[i], des); + i++; + } + fclose(fptr); + puts("Commands loaded. Type 'show' or 'show info' to see more. Use 'close' for client shutdown."); + } + + FILE *logs; + + // Communication with server + while(1){ + memset(server_reply, 0, REPLY_MSG_SIZE); + + if(automatic == 0){ + logs = fopen("logy.txt", "a"); + + if(logs == NULL){ + printf("Cannot open/create log file!\n"); + cleanUP(sock); + return 1; + } + + // Wait for, read and compare user input + char message_lsm[MESSAGE_SIZE]; + memset(message_lsm, 0, MESSAGE_SIZE); + + printf(">> Enter command: "); + + memset(message, 0, MESSAGE_SIZE); + char* r = fgets(message, MESSAGE_SIZE, stdin); + if (r == NULL){ + printf("Input failed.\n"); + break; + } + + if(strcmp(message, "\n") == 0){ + continue; + } + + message[strcspn(message, "\n")] = 0; + + if(strcmp(message, "close") == 0){ + break; + } + + if(strcmp(message, "show") == 0){ + for(int cmd = 0; cmd < i; cmd++){ + printf("%s\n", commands[cmd]); + } + printf("\n"); + continue; + } + else if(strcmp(message, "show info") == 0){ + for(int cmds = 0; cmds < i; cmds++){ + printf("%s - %s", commands[cmds], description[cmds]); + } + printf("\n"); + continue; + } + else{ + int check = 0; + for(int y=0; y < i; y++){ + if(strcmp(message, commands[y]) == 0){ + strcpy(message_lsm, ls_commands[y]); + write_log(logs, message_lsm); + check = 1; + fclose(logs); + } + } + if(check == 0){ + printf("Invalid input. Try commands 'show' or 'show info' to check all avaible commands.\n"); + continue; + } + } + + // Send data + if(send(sock, message_lsm, strlen(message_lsm), 0) < (ssize_t)strlen(message_lsm)){ + printf("send() failed"); + cleanUP(sock); + freeCMD(commands, ls_commands, description, i); + return 1; + } + + + } + + // Receive a reply from the server + if(recv(sock, server_reply, REPLY_MSG_SIZE, 0) <= 0){ + printf("Server crashed or disconnected!\n"); + cleanUP(sock); + if(automatic == 0){ + freeCMD(commands, ls_commands, description, i); + } + return 0; + } + + // Write received data to logs and to terminal + if(automatic == 0){ + logs = fopen("logy.txt", "a"); + + if(logs == NULL){ + printf("Cannot create/write to log file!\n"); + cleanUP(sock); + return 1; + } + + puts("Server reply: "); + write_log(logs, server_reply); + printf("%s\n", server_reply); + printf("\n"); + fprintf(logs, "\n"); + fclose(logs); + } + else{ + // Char % indicates end of measurement + if(strcmp(server_reply, "%") == 0){ + break; + } + logs = fopen("auto-logy.txt", "a"); + if(logs == NULL){ + printf("Cannot open auto-log file!\n"); + cleanUP(sock); + return 1; + } + + fprintf(logs, "%s", server_reply); + printf("%s", server_reply); + fclose(logs); + } + } + + cleanUP(sock); + return 0; +} diff --git a/commands.txt b/commands.txt new file mode 100644 index 0000000..3096a42 --- /dev/null +++ b/commands.txt @@ -0,0 +1,13 @@ +measure:sNg:triggers simple measurement of distance +buffer measure:sNf+0:triggers continuous measurements of the distance as fast as possible with internal buffering in the device until 'stop' command +read:sNq:reads the latest measurement from continuous measurement (buffer measure) +stop:sNc:stops the current execution and resets the status LEDs +single signal:sNm+0:returns signal strength after single measurement +temperature:sNt:triggers measurement of the temperature inside the sensor +laser on:sNo:switches the laser ON +laser off:sNp:switches the laser OFF +version:sNsv:retrieves the software version +serial:sNsn:setrieves the serial number +type:dt:returns the device type +info:dg:returns the device type, generation and current communication settings +configuration:sNuc:returns characteristic configuration diff --git a/config.txt b/config.txt new file mode 100644 index 0000000..57ec92c --- /dev/null +++ b/config.txt @@ -0,0 +1,26 @@ +################## Config pre server ################### +######################################################## + +# COM port +comport=16 + +# COM port characteristics +baud=115200 +bits=8 +# parita bud N - 0 alebo E - 2 +parity=1 +stopbit=1 + +# Rychlost merania(v ms), pocet ignorovanych errorov a pocet merani +measure rate=0 +maxErrors=5 +#samples=15 + +# Jednotky merania - zaklad v ms, 10 - mm, 100 - cm +units=10 + +# Moznost zapnut user auto-start s nastavenim prikazov ako sNuof, sNuga + +sNuH=0 + +cmd=sNuof+xx diff --git a/demo.c b/demo.c new file mode 100644 index 0000000..89f9f26 --- /dev/null +++ b/demo.c @@ -0,0 +1,126 @@ +/* +Author: Jozef Simko +School year: 3., Bachelor study, 2021/22 +Study program: Computer Networks +Organization: Technical University of Kosice (TUKE), Faculty of Electrical Engineering and Informatics (FEI), +Compiler: Winlibs GCC -- MinGW-W64 x86_64-posix-seh version 11.2.0, built by Brecht Sanders (OS Win) + -- gcc version 9.3.0 (OS Linux) +compile: WIN -- gcc client.c -Wall -Wextra -lwsock32 -o client + LINUX -- gcc server.c -Wall -Wextra -o server +version: 1.2 , 15.5.2021 +Usage: This demo demonstrates simple way of using Socket API and loading measurements from our server. + Results are compared with MAX and MIN value - be careful on used units. + +*/ + +#ifdef _WIN32 +#define WIN32_LEAN_AND_MEAN +#include +#else +#include +#include +#include +#include +#include +#endif +#include +#include +#include + +/* Defines lenght of buffer for server's messages +It's better to use higher values, it's helpful in case of hardware/network overload */ +#define REPLY_MSG_SIZE 2048 + +/* Defines public or local IP address of server in decimal form */ +#define IP_ADDRESS "192.168.0.101" + +/* Defines port used by server */ +#define PORT 32500 + +/* MAX & MIN values are used to compare measurement result +Values should be adjusted to the used units (check server config file) */ +#define MAX_VALUE 1265 +#define MIN_VALUE 1200 + +/* +Closes socket (with dependency on used OS) +*/ +void cleanUP(int sock){ +#ifdef WIN32 + closesocket(sock); + WSACleanup(); +#else + close(sock); +#endif + return; +} + +/* ====================================================== */ + +int main(){ + int sock; + struct sockaddr_in server; + char server_reply[REPLY_MSG_SIZE]; + +#ifdef WIN32 + WSADATA wsaData; + int iResult = WSAStartup(MAKEWORD(2, 2), &wsaData); + if (iResult != 0){ + printf("WSASturtup() failed %d\n", iResult); + return 1; + } +#endif + + if ((sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0){ + printf("socket() failed\n"); + cleanUP(sock); + return 1; + } + + memset(&server, 0, sizeof(server)); + server.sin_family = AF_INET; + server.sin_addr.s_addr = inet_addr(IP_ADDRESS); + server.sin_port = htons(PORT); + + if (connect(sock, (struct sockaddr *) &server, sizeof(server)) != 0){ + printf("Cannot connect to server - check IP, port and server status!\n"); + cleanUP(sock); + return 1; + } + + if(recv(sock, server_reply, 2, 0) <= 0){ + printf("Connection interrupted! Check server status!\n"); + cleanUP(sock); + return 1; + } + + while(1){ + memset(server_reply, 0, REPLY_MSG_SIZE); + + if(recv(sock, server_reply, REPLY_MSG_SIZE, 0) <= 0){ + printf("Server crushed or disconnected!\n"); + cleanUP(sock); + return 1; + } + + if(strcmp(server_reply, "%") == 0){ + break; + } + + char *rest = server_reply; + for(int i = 0; i < 3; i++){ + strtok_r(rest, ":", &rest); + } + double result = strtof(rest, NULL); + + if(result > MAX_VALUE){ + printf("Distance out of range - too great (%0.2f)\n", result); + } + if(result < MIN_VALUE){ + printf("Distance out of range - too low (%0.2f)\n", result); + } + } + + cleanUP(sock); + return 0; +} diff --git a/rs232.c b/rs232.c new file mode 100644 index 0000000..3a08ce7 --- /dev/null +++ b/rs232.c @@ -0,0 +1,879 @@ +/* +*************************************************************************** +* +* Author: Teunis van Beelen +* +* Copyright (C) 2005 - 2021 Teunis van Beelen +* +* Email: teuniz@protonmail.com +* +*************************************************************************** +* +* 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. +* +* 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 . +* +*************************************************************************** +*/ + + +/* Last revision: February 9, 2021 */ +/* For more info and how to use this library, visit: http://www.teuniz.net/RS-232/ */ + + +#include "rs232.h" + + +#if defined(__linux__) || defined(__FreeBSD__) /* Linux & FreeBSD */ + +#define RS232_PORTNR 38 + + +int Cport[RS232_PORTNR], + error; + +struct termios new_port_settings, + old_port_settings[RS232_PORTNR]; + +const char *comports[RS232_PORTNR]={"/dev/ttyS0","/dev/ttyS1","/dev/ttyS2","/dev/ttyS3","/dev/ttyS4","/dev/ttyS5", + "/dev/ttyS6","/dev/ttyS7","/dev/ttyS8","/dev/ttyS9","/dev/ttyS10","/dev/ttyS11", + "/dev/ttyS12","/dev/ttyS13","/dev/ttyS14","/dev/ttyS15","/dev/ttyUSB0", + "/dev/ttyUSB1","/dev/ttyUSB2","/dev/ttyUSB3","/dev/ttyUSB4","/dev/ttyUSB5", + "/dev/ttyAMA0","/dev/ttyAMA1","/dev/ttyACM0","/dev/ttyACM1", + "/dev/rfcomm0","/dev/rfcomm1","/dev/ircomm0","/dev/ircomm1", + "/dev/cuau0","/dev/cuau1","/dev/cuau2","/dev/cuau3", + "/dev/cuaU0","/dev/cuaU1","/dev/cuaU2","/dev/cuaU3"}; + +int RS232_OpenComport(int comport_number, int baudrate, const char *mode, int flowctrl) +{ + int baudr, + status; + + if((comport_number>=RS232_PORTNR)||(comport_number<0)) + { + printf("illegal comport number\n"); + return(1); + } + + switch(baudrate) + { + case 50 : baudr = B50; + break; + case 75 : baudr = B75; + break; + case 110 : baudr = B110; + break; + case 134 : baudr = B134; + break; + case 150 : baudr = B150; + break; + case 200 : baudr = B200; + break; + case 300 : baudr = B300; + break; + case 600 : baudr = B600; + break; + case 1200 : baudr = B1200; + break; + case 1800 : baudr = B1800; + break; + case 2400 : baudr = B2400; + break; + case 4800 : baudr = B4800; + break; + case 9600 : baudr = B9600; + break; + case 19200 : baudr = B19200; + break; + case 38400 : baudr = B38400; + break; + case 57600 : baudr = B57600; + break; + case 115200 : baudr = B115200; + break; + case 230400 : baudr = B230400; + break; + case 460800 : baudr = B460800; + break; +#if defined(__linux__) + case 500000 : baudr = B500000; + break; + case 576000 : baudr = B576000; + break; + case 921600 : baudr = B921600; + break; + case 1000000 : baudr = B1000000; + break; + case 1152000 : baudr = B1152000; + break; + case 1500000 : baudr = B1500000; + break; + case 2000000 : baudr = B2000000; + break; + case 2500000 : baudr = B2500000; + break; + case 3000000 : baudr = B3000000; + break; + case 3500000 : baudr = B3500000; + break; + case 4000000 : baudr = B4000000; + break; +#endif + default : printf("invalid baudrate\n"); + return(1); + break; + } + + int cbits=CS8, + cpar=0, + ipar=IGNPAR, + bstop=0; + + if(strlen(mode) != 3) + { + printf("invalid mode \"%s\"\n", mode); + return(1); + } + + switch(mode[0]) + { + case '8': cbits = CS8; + break; + case '7': cbits = CS7; + break; + case '6': cbits = CS6; + break; + case '5': cbits = CS5; + break; + default : printf("invalid number of data-bits '%c'\n", mode[0]); + return(1); + break; + } + + switch(mode[1]) + { + case 'N': + case 'n': cpar = 0; + ipar = IGNPAR; + break; + case 'E': + case 'e': cpar = PARENB; + ipar = INPCK; + break; + case 'O': + case 'o': cpar = (PARENB | PARODD); + ipar = INPCK; + break; + default : printf("invalid parity '%c'\n", mode[1]); + return(1); + break; + } + + switch(mode[2]) + { + case '1': bstop = 0; + break; + case '2': bstop = CSTOPB; + break; + default : printf("invalid number of stop bits '%c'\n", mode[2]); + return(1); + break; + } + +/* +http://pubs.opengroup.org/onlinepubs/7908799/xsh/termios.h.html + +http://man7.org/linux/man-pages/man3/termios.3.html +*/ + + Cport[comport_number] = open(comports[comport_number], O_RDWR | O_NOCTTY | O_NDELAY); + if(Cport[comport_number]==-1) + { + perror("unable to open comport "); + return(1); + } + + /* lock access so that another process can't also use the port */ + if(flock(Cport[comport_number], LOCK_EX | LOCK_NB) != 0) + { + close(Cport[comport_number]); + perror("Another process has locked the comport."); + return(1); + } + + error = tcgetattr(Cport[comport_number], old_port_settings + comport_number); + if(error==-1) + { + close(Cport[comport_number]); + flock(Cport[comport_number], LOCK_UN); /* free the port so that others can use it. */ + perror("unable to read portsettings "); + return(1); + } + memset(&new_port_settings, 0, sizeof(new_port_settings)); /* clear the new struct */ + + new_port_settings.c_cflag = cbits | cpar | bstop | CLOCAL | CREAD; + if(flowctrl) + { + new_port_settings.c_cflag |= CRTSCTS; + } + new_port_settings.c_iflag = ipar; + new_port_settings.c_oflag = 0; + new_port_settings.c_lflag = 0; + new_port_settings.c_cc[VMIN] = 0; /* block untill n bytes are received */ + new_port_settings.c_cc[VTIME] = 0; /* block untill a timer expires (n * 100 mSec.) */ + + cfsetispeed(&new_port_settings, baudr); + cfsetospeed(&new_port_settings, baudr); + + error = tcsetattr(Cport[comport_number], TCSANOW, &new_port_settings); + if(error==-1) + { + tcsetattr(Cport[comport_number], TCSANOW, old_port_settings + comport_number); + close(Cport[comport_number]); + flock(Cport[comport_number], LOCK_UN); /* free the port so that others can use it. */ + perror("unable to adjust portsettings "); + return(1); + } + +/* http://man7.org/linux/man-pages/man4/tty_ioctl.4.html */ + + if(ioctl(Cport[comport_number], TIOCMGET, &status) == -1) + { + tcsetattr(Cport[comport_number], TCSANOW, old_port_settings + comport_number); + flock(Cport[comport_number], LOCK_UN); /* free the port so that others can use it. */ + perror("unable to get portstatus"); + return(1); + } + + status |= TIOCM_DTR; /* turn on DTR */ + status |= TIOCM_RTS; /* turn on RTS */ + + if(ioctl(Cport[comport_number], TIOCMSET, &status) == -1) + { + tcsetattr(Cport[comport_number], TCSANOW, old_port_settings + comport_number); + flock(Cport[comport_number], LOCK_UN); /* free the port so that others can use it. */ + perror("unable to set portstatus"); + return(1); + } + + return(0); +} + + +int RS232_PollComport(int comport_number, unsigned char *buf, int size) +{ + int n; + + n = read(Cport[comport_number], buf, size); + + if(n < 0) + { + if(errno == EAGAIN) return 0; + } + + return(n); +} + + +int RS232_SendByte(int comport_number, unsigned char byte) +{ + int n = write(Cport[comport_number], &byte, 1); + if(n < 0) + { + if(errno == EAGAIN) + { + return 0; + } + else + { + return 1; + } + } + + return(0); +} + + +int RS232_SendBuf(int comport_number, unsigned char *buf, int size) +{ + int n = write(Cport[comport_number], buf, size); + if(n < 0) + { + if(errno == EAGAIN) + { + return 0; + } + else + { + return -1; + } + } + + return(n); +} + + +void RS232_CloseComport(int comport_number) +{ + int status; + + if(ioctl(Cport[comport_number], TIOCMGET, &status) == -1) + { + perror("unable to get portstatus"); + } + + status &= ~TIOCM_DTR; /* turn off DTR */ + status &= ~TIOCM_RTS; /* turn off RTS */ + + if(ioctl(Cport[comport_number], TIOCMSET, &status) == -1) + { + perror("unable to set portstatus"); + } + + tcsetattr(Cport[comport_number], TCSANOW, old_port_settings + comport_number); + close(Cport[comport_number]); + + flock(Cport[comport_number], LOCK_UN); /* free the port so that others can use it. */ +} + +/* +Constant Description +TIOCM_LE DSR (data set ready/line enable) +TIOCM_DTR DTR (data terminal ready) +TIOCM_RTS RTS (request to send) +TIOCM_ST Secondary TXD (transmit) +TIOCM_SR Secondary RXD (receive) +TIOCM_CTS CTS (clear to send) +TIOCM_CAR DCD (data carrier detect) +TIOCM_CD see TIOCM_CAR +TIOCM_RNG RNG (ring) +TIOCM_RI see TIOCM_RNG +TIOCM_DSR DSR (data set ready) + +http://man7.org/linux/man-pages/man4/tty_ioctl.4.html +*/ + +int RS232_IsDCDEnabled(int comport_number) +{ + int status; + + ioctl(Cport[comport_number], TIOCMGET, &status); + + if(status&TIOCM_CAR) return(1); + else return(0); +} + + +int RS232_IsRINGEnabled(int comport_number) +{ + int status; + + ioctl(Cport[comport_number], TIOCMGET, &status); + + if(status&TIOCM_RNG) return(1); + else return(0); +} + + +int RS232_IsCTSEnabled(int comport_number) +{ + int status; + + ioctl(Cport[comport_number], TIOCMGET, &status); + + if(status&TIOCM_CTS) return(1); + else return(0); +} + + +int RS232_IsDSREnabled(int comport_number) +{ + int status; + + ioctl(Cport[comport_number], TIOCMGET, &status); + + if(status&TIOCM_DSR) return(1); + else return(0); +} + + +void RS232_enableDTR(int comport_number) +{ + int status; + + if(ioctl(Cport[comport_number], TIOCMGET, &status) == -1) + { + perror("unable to get portstatus"); + } + + status |= TIOCM_DTR; /* turn on DTR */ + + if(ioctl(Cport[comport_number], TIOCMSET, &status) == -1) + { + perror("unable to set portstatus"); + } +} + + +void RS232_disableDTR(int comport_number) +{ + int status; + + if(ioctl(Cport[comport_number], TIOCMGET, &status) == -1) + { + perror("unable to get portstatus"); + } + + status &= ~TIOCM_DTR; /* turn off DTR */ + + if(ioctl(Cport[comport_number], TIOCMSET, &status) == -1) + { + perror("unable to set portstatus"); + } +} + + +void RS232_enableRTS(int comport_number) +{ + int status; + + if(ioctl(Cport[comport_number], TIOCMGET, &status) == -1) + { + perror("unable to get portstatus"); + } + + status |= TIOCM_RTS; /* turn on RTS */ + + if(ioctl(Cport[comport_number], TIOCMSET, &status) == -1) + { + perror("unable to set portstatus"); + } +} + + +void RS232_disableRTS(int comport_number) +{ + int status; + + if(ioctl(Cport[comport_number], TIOCMGET, &status) == -1) + { + perror("unable to get portstatus"); + } + + status &= ~TIOCM_RTS; /* turn off RTS */ + + if(ioctl(Cport[comport_number], TIOCMSET, &status) == -1) + { + perror("unable to set portstatus"); + } +} + + +void RS232_flushRX(int comport_number) +{ + tcflush(Cport[comport_number], TCIFLUSH); +} + + +void RS232_flushTX(int comport_number) +{ + tcflush(Cport[comport_number], TCOFLUSH); +} + + +void RS232_flushRXTX(int comport_number) +{ + tcflush(Cport[comport_number], TCIOFLUSH); +} + + +#else /* windows */ + +#define RS232_PORTNR 32 + +HANDLE Cport[RS232_PORTNR]; + + +const char *comports[RS232_PORTNR]={"\\\\.\\COM1", "\\\\.\\COM2", "\\\\.\\COM3", "\\\\.\\COM4", + "\\\\.\\COM5", "\\\\.\\COM6", "\\\\.\\COM7", "\\\\.\\COM8", + "\\\\.\\COM9", "\\\\.\\COM10", "\\\\.\\COM11", "\\\\.\\COM12", + "\\\\.\\COM13", "\\\\.\\COM14", "\\\\.\\COM15", "\\\\.\\COM16", + "\\\\.\\COM17", "\\\\.\\COM18", "\\\\.\\COM19", "\\\\.\\COM20", + "\\\\.\\COM21", "\\\\.\\COM22", "\\\\.\\COM23", "\\\\.\\COM24", + "\\\\.\\COM25", "\\\\.\\COM26", "\\\\.\\COM27", "\\\\.\\COM28", + "\\\\.\\COM29", "\\\\.\\COM30", "\\\\.\\COM31", "\\\\.\\COM32"}; + +char mode_str[128]; + + +int RS232_OpenComport(int comport_number, int baudrate, const char *mode, int flowctrl) +{ + if((comport_number>=RS232_PORTNR)||(comport_number<0)) + { + printf("illegal comport number\n"); + return(1); + } + + switch(baudrate) + { + case 110 : strcpy(mode_str, "baud=110"); + break; + case 300 : strcpy(mode_str, "baud=300"); + break; + case 600 : strcpy(mode_str, "baud=600"); + break; + case 1200 : strcpy(mode_str, "baud=1200"); + break; + case 2400 : strcpy(mode_str, "baud=2400"); + break; + case 4800 : strcpy(mode_str, "baud=4800"); + break; + case 9600 : strcpy(mode_str, "baud=9600"); + break; + case 19200 : strcpy(mode_str, "baud=19200"); + break; + case 38400 : strcpy(mode_str, "baud=38400"); + break; + case 57600 : strcpy(mode_str, "baud=57600"); + break; + case 115200 : strcpy(mode_str, "baud=115200"); + break; + case 128000 : strcpy(mode_str, "baud=128000"); + break; + case 256000 : strcpy(mode_str, "baud=256000"); + break; + case 500000 : strcpy(mode_str, "baud=500000"); + break; + case 921600 : strcpy(mode_str, "baud=921600"); + break; + case 1000000 : strcpy(mode_str, "baud=1000000"); + break; + case 1500000 : strcpy(mode_str, "baud=1500000"); + break; + case 2000000 : strcpy(mode_str, "baud=2000000"); + break; + case 3000000 : strcpy(mode_str, "baud=3000000"); + break; + default : printf("invalid baudrate\n"); + return(1); + break; + } + + if(strlen(mode) != 3) + { + printf("invalid mode \"%s\"\n", mode); + return(1); + } + + switch(mode[0]) + { + case '8': strcat(mode_str, " data=8"); + break; + case '7': strcat(mode_str, " data=7"); + break; + case '6': strcat(mode_str, " data=6"); + break; + case '5': strcat(mode_str, " data=5"); + break; + default : printf("invalid number of data-bits '%c'\n", mode[0]); + return(1); + break; + } + + switch(mode[1]) + { + case 'N': + case 'n': strcat(mode_str, " parity=n"); + break; + case 'E': + case 'e': strcat(mode_str, " parity=e"); + break; + case 'O': + case 'o': strcat(mode_str, " parity=o"); + break; + default : printf("invalid parity '%c'\n", mode[1]); + return(1); + break; + } + + switch(mode[2]) + { + case '1': strcat(mode_str, " stop=1"); + break; + case '2': strcat(mode_str, " stop=2"); + break; + default : printf("invalid number of stop bits '%c'\n", mode[2]); + return(1); + break; + } + + if(flowctrl) + { + strcat(mode_str, " xon=off to=off odsr=off dtr=on rts=off"); + } + else + { + strcat(mode_str, " xon=off to=off odsr=off dtr=on rts=on"); + } + +/* +http://msdn.microsoft.com/en-us/library/windows/desktop/aa363145%28v=vs.85%29.aspx + +http://technet.microsoft.com/en-us/library/cc732236.aspx + +https://docs.microsoft.com/en-us/windows/desktop/api/winbase/ns-winbase-_dcb +*/ + + Cport[comport_number] = CreateFileA(comports[comport_number], + GENERIC_READ|GENERIC_WRITE, + 0, /* no share */ + NULL, /* no security */ + OPEN_EXISTING, + 0, /* no threads */ + NULL); /* no templates */ + + if(Cport[comport_number]==INVALID_HANDLE_VALUE) + { + printf("unable to open comport\n"); + return(1); + } + + DCB port_settings; + memset(&port_settings, 0, sizeof(port_settings)); /* clear the new struct */ + port_settings.DCBlength = sizeof(port_settings); + + if(!BuildCommDCBA(mode_str, &port_settings)) + { + printf("unable to set comport dcb settings\n"); + CloseHandle(Cport[comport_number]); + return(1); + } + + if(flowctrl) + { + port_settings.fOutxCtsFlow = TRUE; + port_settings.fRtsControl = RTS_CONTROL_HANDSHAKE; + } + + if(!SetCommState(Cport[comport_number], &port_settings)) + { + printf("unable to set comport cfg settings\n"); + CloseHandle(Cport[comport_number]); + return(1); + } + + COMMTIMEOUTS Cptimeouts; + + Cptimeouts.ReadIntervalTimeout = MAXDWORD; + Cptimeouts.ReadTotalTimeoutMultiplier = 0; + Cptimeouts.ReadTotalTimeoutConstant = 0; + Cptimeouts.WriteTotalTimeoutMultiplier = 0; + Cptimeouts.WriteTotalTimeoutConstant = 0; + + if(!SetCommTimeouts(Cport[comport_number], &Cptimeouts)) + { + printf("unable to set comport time-out settings\n"); + CloseHandle(Cport[comport_number]); + return(1); + } + + return(0); +} + + +int RS232_PollComport(int comport_number, unsigned char *buf, int size) +{ + int n; + +/* added the void pointer cast, otherwise gcc will complain about */ +/* "warning: dereferencing type-punned pointer will break strict aliasing rules" */ + + if(!ReadFile(Cport[comport_number], buf, size, (LPDWORD)((void *)&n), NULL)) + { + return -1; + } + + return(n); +} + + +int RS232_SendByte(int comport_number, unsigned char byte) +{ + int n; + + if(!WriteFile(Cport[comport_number], &byte, 1, (LPDWORD)((void *)&n), NULL)) + { + return(1); + } + + if(n<0) return(1); + + return(0); +} + + +int RS232_SendBuf(int comport_number, unsigned char *buf, int size) +{ + int n; + + if(WriteFile(Cport[comport_number], buf, size, (LPDWORD)((void *)&n), NULL)) + { + return(n); + } + + return(-1); +} + + +void RS232_CloseComport(int comport_number) +{ + CloseHandle(Cport[comport_number]); +} + +/* +http://msdn.microsoft.com/en-us/library/windows/desktop/aa363258%28v=vs.85%29.aspx +*/ + +int RS232_IsDCDEnabled(int comport_number) +{ + int status; + + GetCommModemStatus(Cport[comport_number], (LPDWORD)((void *)&status)); + + if(status&MS_RLSD_ON) return(1); + else return(0); +} + + +int RS232_IsRINGEnabled(int comport_number) +{ + int status; + + GetCommModemStatus(Cport[comport_number], (LPDWORD)((void *)&status)); + + if(status&MS_RING_ON) return(1); + else return(0); +} + + +int RS232_IsCTSEnabled(int comport_number) +{ + int status; + + GetCommModemStatus(Cport[comport_number], (LPDWORD)((void *)&status)); + + if(status&MS_CTS_ON) return(1); + else return(0); +} + + +int RS232_IsDSREnabled(int comport_number) +{ + int status; + + GetCommModemStatus(Cport[comport_number], (LPDWORD)((void *)&status)); + + if(status&MS_DSR_ON) return(1); + else return(0); +} + + +void RS232_enableDTR(int comport_number) +{ + EscapeCommFunction(Cport[comport_number], SETDTR); +} + + +void RS232_disableDTR(int comport_number) +{ + EscapeCommFunction(Cport[comport_number], CLRDTR); +} + + +void RS232_enableRTS(int comport_number) +{ + EscapeCommFunction(Cport[comport_number], SETRTS); +} + + +void RS232_disableRTS(int comport_number) +{ + EscapeCommFunction(Cport[comport_number], CLRRTS); +} + +/* +https://msdn.microsoft.com/en-us/library/windows/desktop/aa363428%28v=vs.85%29.aspx +*/ + +void RS232_flushRX(int comport_number) +{ + PurgeComm(Cport[comport_number], PURGE_RXCLEAR | PURGE_RXABORT); +} + + +void RS232_flushTX(int comport_number) +{ + PurgeComm(Cport[comport_number], PURGE_TXCLEAR | PURGE_TXABORT); +} + + +void RS232_flushRXTX(int comport_number) +{ + PurgeComm(Cport[comport_number], PURGE_RXCLEAR | PURGE_RXABORT); + PurgeComm(Cport[comport_number], PURGE_TXCLEAR | PURGE_TXABORT); +} + + +#endif + + +void RS232_cputs(int comport_number, const char *text) /* sends a string to serial port */ +{ + while(*text != 0) RS232_SendByte(comport_number, *(text++)); +} + + +/* return index in comports matching to device name or -1 if not found */ +int RS232_GetPortnr(const char *devname) +{ + int i; + + char str[32]; + +#if defined(__linux__) || defined(__FreeBSD__) /* Linux & FreeBSD */ + strcpy(str, "/dev/"); +#else /* windows */ + strcpy(str, "\\\\.\\"); +#endif + strncat(str, devname, 16); + str[31] = 0; + + for(i=0; i. +* +*************************************************************************** +*/ + +/* For more info and how to use this library, visit: http://www.teuniz.net/RS-232/ */ + + +#ifndef rs232_INCLUDED +#define rs232_INCLUDED + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + + + +#if defined(__linux__) || defined(__FreeBSD__) + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#else + +#include + +#endif + +int RS232_OpenComport(int, int, const char *, int); +int RS232_PollComport(int, unsigned char *, int); +int RS232_SendByte(int, unsigned char); +int RS232_SendBuf(int, unsigned char *, int); +void RS232_CloseComport(int); +void RS232_cputs(int, const char *); +int RS232_IsDCDEnabled(int); +int RS232_IsRINGEnabled(int); +int RS232_IsCTSEnabled(int); +int RS232_IsDSREnabled(int); +void RS232_enableDTR(int); +void RS232_disableDTR(int); +void RS232_enableRTS(int); +void RS232_disableRTS(int); +void RS232_flushRX(int); +void RS232_flushTX(int); +void RS232_flushRXTX(int); +int RS232_GetPortnr(const char *); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif + + diff --git a/server.c b/server.c new file mode 100644 index 0000000..2761e7f --- /dev/null +++ b/server.c @@ -0,0 +1,542 @@ +/* +Author: Jozef Simko +School year: 3., Bachelor study, 2021/22 +Study program: Computer Networks +Organization: Technical University of Kosice (TUKE), Faculty of Electrical Engineering and Informatics (FEI), + +Compiler: Winlibs GCC -- MinGW-W64 x86_64-posix-seh version 11.2.0, built by Brecht Sanders (OS Win) + -- gcc version 9.3.0 (OS Linux) + +compile: WIN -- gcc server.c RS232.c -Wall -Wextra -lwsock32 -o server + LINUX -- gcc server.c RS232.c -Wall -Wextra -o server +version: 1.3 , 17.5.2021 +Usage: Program communicates with both second program (client) using sockets and lasermeter using RS232 COM port communication. + It works in active or passive mode according input parameters. +*/ + +#ifdef _WIN32 +#define WIN32_LEAN_AND_MEAN +#include +#else +#include +#include +#include +#include +#include +#endif +#include +#include +#include +#include +#include "rs232.h" + +/* Defines lenght of various buffers: +- buffer for message from client +- buffer for reading lines from config file +- buffer for output line which is send to client +Should not be less then 30 */ +#define MESSAGE_SIZE 32 + +/* Pre-defined COM port number from RS-232 library documentation table according to used OS +Documentation - https://www.teuniz.net/RS-232/ */ +#define COM_PORT 16 + +/* COM port baudrate number from RS-232 library - https://www.teuniz.net/RS-232/ */ +#define COM_BAUD 115200 + +/* Pre-defined COM port mode from RS-232 library - https://www.teuniz.net/RS-232/ +first number represents databits, letter defines parity and last number is for stopbits */ +#define COM_MODE "8N1" + +/* Defines lenght of buffer for data from lasermeter +It's better to use higher values, it's helpful in case of hardware/RS-232 overload */ +#define COM_BUFFER 4096 + +/* Definition of struct used in main() */ +struct var { + char *name; + int value; +}; + + +/*########################################### + DEFINED FUNCTIONS +#############################################*/ + +/* +Waits exact number of seconds (with dependency on used OS) +*/ +void wait(int sec){ +#ifdef _WIN32 + Sleep(sec*1000); +#else + sleep(sec); +#endif + return; +} + +/* +Returns lasermeter device ID from return value of command "dg" +*/ +char getID(int cport_nr){ + char dg[] = "dg\r\n"; + RS232_cputs(cport_nr, dg); + wait(1); + + unsigned char buf[MESSAGE_SIZE]; + + if(RS232_PollComport(cport_nr, buf, MESSAGE_SIZE) <= 0){ + return 'x'; + } + return buf[1]; +} + +/* +Loads variables from config.txt file to defined struction +Returns pointer on arrays of chars which contain commands from config variables cmd= +*/ +char** setVars(struct var *vars, FILE *cfg){ + char line[MESSAGE_SIZE]; + memset(line, 0, MESSAGE_SIZE); + char **cmds = NULL; + cmds = malloc(sizeof(char *)); + int cmdID = 0; + + while(fgets(line, sizeof(line), cfg) != NULL) { + if(line[0] == '#' || line[0] == '\n'){ + continue; + } + char *second; + char *first = strtok_r(line, "=", &second); + + if(strcmp(first, "cmd") == 0){ + cmds = realloc(cmds, (cmdID+1)*sizeof(char *)); + cmds[cmdID] = malloc(sizeof(char)); + second[strcspn(second, "\n")] = 0; + strcpy(cmds[cmdID], second); + cmdID++; + continue; + } + + for(int i=0; vars[i].name; i++){ + if(strcmp(vars[i].name, first) == 0){ + vars[i].value = atoi(second); + } + } + } + cmds = realloc(cmds, (cmdID+1)*sizeof(char *)); + cmds[cmdID] = NULL; + return cmds; +} + +/* +Frees allocated memory of pointer to arrays of chars +*/ +void freeCMDS(char **cmds){ + int i=0; + while(cmds[i] != NULL){ + free(cmds[i]); + i++; + } + free(cmds); +} + +/* +Returns value of variable defined in struction +*/ +int getVar(struct var *vars, char *var){ + for(int i=0; vars[i].name; i++){ + if(strcmp(vars[i].name, var) == 0){ + return vars[i].value; + } + } + return -1; +} + +/* +Changes "raw" command to usable command for lasermeter +*/ +char *makeCMD(char *string, char deviceID){ + int n = strlen(string) + 2; + char *ptr = (char *)calloc(n, sizeof(char)); + + strcpy(ptr, string); + ptr[n-2] = '\r'; + ptr[n-1] = '\n'; + if(ptr[1] == 'N'){ + ptr[1] = deviceID; + } + return ptr; +} + +/* +Closes socket (with dependency on used OS) +*/ +void cleanUP(int sock){ +#ifdef WIN32 + closesocket(sock); + WSACleanup(); +#else + close(sock); +#endif + return; +} + +/* ######################################### */ + +int main(int argc , char *argv[]){ + +#ifdef WIN32 + WSADATA wsaData; + int iResult = WSAStartup(MAKEWORD(2 ,2), &wsaData); + if (iResult != 0){ + printf("WSASturtup() failed\n"); + return 0; + } +#endif + + int sock; + int client_sock; + int read_size; + struct sockaddr_in server; + struct sockaddr_in client; + char client_message[MESSAGE_SIZE]; + + memset(client_message, 0, MESSAGE_SIZE); + + if (argc < 2 || argc > 3){ + fprintf(stderr, "Usage:\n"); + fprintf(stderr, "- %s \n", argv[0]); + fprintf(stderr, "- %s \n", argv[0]); + return 1; + } + + // Decide to use manual or automatic mode + int automatic = 0; + if(argc == 3){ + automatic = 1; + } + + // Create socket + if ((sock = socket(PF_INET , SOCK_STREAM , IPPROTO_TCP)) < 0){ + printf("socket() failed\n"); + cleanUP(sock); + return 1; + } + + // Prepare the sockaddr_in structure + memset(&server, 0, sizeof(server)); + server.sin_family = AF_INET; + server.sin_addr.s_addr = htonl(INADDR_ANY); + server.sin_port = htons(atoi(argv[1])); + + // Bind + if (bind(sock,(struct sockaddr *) &server, sizeof(server)) != 0){ + printf("bind() failed\n"); + cleanUP(sock); + return 1; + } + + // Define basic vars struct + struct var vars[] = { + {"comport", 1}, + {"baud", 9600}, + {"bits", 8}, + {"parity", 0}, + {"stopbit", 1}, + {"measure rate", 0}, + {"maxErrors", 5}, + {"samples", -1}, + {"units", 1}, + {"sNuH", 0}, + {NULL, 0} + }; + + FILE *cfg; + char **cmds = NULL; + + // Open config and change variables in struct vars + if(automatic == 1){ + if ((cfg = fopen(argv[2], "r")) == NULL) { + printf("Error! Config file cannot be opened.\n"); + cleanUP(sock); + return 1; + } + cmds = setVars(vars, cfg); + fclose(cfg); + } + + int cport_nr = COM_PORT; + int bdrate = COM_BAUD; + unsigned char buf[COM_BUFFER]; + char mode[] = COM_MODE; + + // Load variables from struct vars + if(automatic == 1){ + cport_nr = getVar(vars, "comport"); + bdrate = getVar(vars, "baud"); + mode[0] = getVar(vars, "bits") + '0'; + if(getVar(vars, "parity") == 2){mode[1] = 'E';} + mode[2] = getVar(vars, "stopbit") + '0'; + } + + if(RS232_OpenComport(cport_nr, bdrate, mode, 0)){ + printf("Cannot open comport. Server is shutting down.\n"); + cleanUP(sock); + return 1; + } + + for(;;){ + // Listen + if(listen(sock, 1) != 0){ + printf("listen() failed\n"); + cleanUP(sock); + return 1; + } + + puts("Waiting for incoming connections..."); + + // Accept connection from an incoming client + + #ifdef WIN32 + int c = sizeof(server); + client_sock = accept(sock, (struct sockaddr *) &client, &c); + #else + socklen_t c = sizeof(server); + client_sock = accept(sock, (struct sockaddr *) &client, &c); + #endif + if (client_sock < 0){ + printf("accept() failed"); + cleanUP(sock); + return 1; + } + + printf("Connection of client %s accepted\n", inet_ntoa(client.sin_addr)); + + // Send info about mode to client + char init[2] = "0"; + if(automatic == 1){ + init[0] = '1'; + } + send(client_sock, init, strlen(init), 0); + + // Laser sensor start sequence + char deviceID = getID(cport_nr); + if(deviceID == 'x'){ + printf("COM port opened, lasermeter not connected! Check your device!\n"); + cleanUP(sock); + return 1; + } + + char mode[]="sNc\r\n"; + mode[1] = deviceID; + RS232_cputs(cport_nr, mode); + wait(1); + RS232_PollComport(cport_nr, buf, COM_BUFFER); + + // Automatic mode + if(automatic == 1){ + // Load measure rate + char *mode; + int rate = getVar(vars, "measure rate"); + int nDigits = 1; + if(rate != 0){ + int n = rate; + while(n!=0){ + n=n/10; + nDigits++; + } + nDigits -= 1; + } + // User measurement mode + if(getVar(vars, "sNuH") == 1){ + + // Send commands from config (**cmds) + int cmd = 0; + while(cmds[cmd] != NULL){ + char *ptr = makeCMD(cmds[cmd], deviceID); + RS232_cputs(cport_nr, ptr); + cmd++; + free(ptr); + } + + freeCMDS(cmds); + + mode = malloc((5+nDigits+1) * sizeof(char)); + snprintf(mode, 5+nDigits+1, "sNuh+%d", rate); + } + // Basic measurement mode + else{ + mode = malloc((4+nDigits+1) * sizeof(char)); + snprintf(mode, 4+nDigits+1, "sNh+%d", rate); + } + + mode = makeCMD(mode, deviceID); + + RS232_cputs(cport_nr, mode); + free(mode); + + wait(1); + + char *errors = malloc(sizeof(char)); + int errCount = 0; + int errInRow = 0; + int maxErrors = getVar(vars, "maxErrors"); + int samples = getVar(vars, "samples"); + int measureSamples = 0; + int e = 0; + + while(1){ + if(errInRow >= maxErrors){ + break; + } + + if(samples > -1 && samples == measureSamples){ + break; + } + + if(e == 1){ + break; + } + + memset(buf, 0, COM_BUFFER); + RS232_PollComport(cport_nr, buf, COM_BUFFER); + + time_t rawtime; + struct tm *timeinfo; + time(&rawtime); + timeinfo = localtime(&rawtime); + + char *rest = (char *) buf; + char *first = NULL; + printf("%s", buf); + + // Split and handle data + while((first = strtok_r(rest, "\r\n", &rest))){ + // Check and handle error + char *err = NULL; + strtok_r(first, "@", &err); + if(strlen(err) > 0){ + errCount++; + errInRow++; + errors = (char *) realloc(errors, (errCount)*6*sizeof(char)+1); + strcat(errors, err); + strcat(errors, "\r\n"); + if(errInRow >= maxErrors){ + char warning[]="Too many errors! Please check your device!\n"; + printf("%s", warning); + printf("%s", errors); + send(client_sock, warning, strlen(warning), 0); + break; + } + } + // Handle other values + else{ + int res = 0; + + if((res = atoi(first)) > 0){ + res = atoi(first); + } + else{ + char *numbers = NULL; + strtok_r(first, "+", &numbers); + res = atoi(numbers); + } + + + if(res == 0){ + continue; + } + + int units = getVar(vars, "units"); + + double resd = res * (1/(double)units); + char output[MESSAGE_SIZE]; + memset(output, 0, MESSAGE_SIZE); + + snprintf(output, MESSAGE_SIZE, "%02d/%02d/%d - %02d:%02d:%02d: %0.2f\n", timeinfo->tm_mday, timeinfo->tm_mon+1, timeinfo->tm_year+1900, + timeinfo->tm_hour, timeinfo->tm_min, timeinfo->tm_sec, resd); + + errInRow = 0; + measureSamples++; + + // Check availability of client + #ifdef WIN32 + int iResult = send(client_sock, output, strlen(output), 0); + if(iResult == WSAETIMEDOUT){ + printf("Client disconnected!\n"); + e = 1; + break; + } + + #else + send(client_sock, output, strlen(output), MSG_NOSIGNAL); + if(errno == EPIPE){ + printf("Client disconnected!\n"); + e = 1; + break; + } + #endif + + if(samples > -1 && samples == measureSamples){ + break; + } + } + } + + } + // Automatic mode end sequence + wait(1); + char stop[] = "sNc\r\n"; + stop[1] = deviceID; + RS232_cputs(cport_nr, stop); + + memset(buf, 0, COM_BUFFER); + + if(e == 0){ + char end[] = "%"; + send(client_sock, end, 1, 0); + } + + wait(1); + printf("End of measuring, shutting down server.\n"); + break; + } + + // Manual mode + else{ + // Receive a message from client + while ((read_size = recv(client_sock, client_message, MESSAGE_SIZE, 0)) > 0 ){ + memset(buf, 0, COM_BUFFER); + + char *ptr = makeCMD(client_message, deviceID); + RS232_cputs(cport_nr, ptr); + + int checkCOM = 0; + while(RS232_PollComport(cport_nr, buf, COM_BUFFER) <= 0){ + wait(1); + if(checkCOM == 5){ + char info[] = "No response from COM port, check your device and all cables!\n"; + send(client_sock, info, strlen(info), 0); + printf("Empty COM-PORT buffer!\n"); + cleanUP(sock); + return 1; + } + checkCOM++; + } + + // Send received data back to client + send(client_sock, (char*) buf, strlen((char *)buf), 0); + memset(client_message, 0, MESSAGE_SIZE); + free(ptr); + } + + if(read_size <= 0){ + puts("Client disconnected.\n"); + } + } + } + + cleanUP(sock); + return 0; +}