final
This commit is contained in:
commit
e9e8a5cc1e
8
.gitignore
vendored
Normal file
8
.gitignore
vendored
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
server
|
||||||
|
server.exe
|
||||||
|
client
|
||||||
|
client.exe
|
||||||
|
demo
|
||||||
|
demo.exe
|
||||||
|
logy.txt
|
||||||
|
auto-logy.txt
|
40
README.md
Normal file
40
README.md
Normal file
@ -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)
|
||||||
|
|
7
autostart.sh
Normal file
7
autostart.sh
Normal file
@ -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
|
316
client.c
Normal file
316
client.c
Normal file
@ -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 <winsock2.h>
|
||||||
|
#else
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <netdb.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#endif
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
/* 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 <Server IP> <Server Port>\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;
|
||||||
|
}
|
13
commands.txt
Normal file
13
commands.txt
Normal file
@ -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
|
26
config.txt
Normal file
26
config.txt
Normal file
@ -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
|
126
demo.c
Normal file
126
demo.c
Normal file
@ -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 <winsock2.h>
|
||||||
|
#else
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <netdb.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#endif
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
/* 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;
|
||||||
|
}
|
879
rs232.c
Normal file
879
rs232.c
Normal file
@ -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 <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
***************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/* 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<RS232_PORTNR; i++)
|
||||||
|
{
|
||||||
|
if(!strcmp(comports[i], str))
|
||||||
|
{
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1; /* device not found */
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
85
rs232.h
Normal file
85
rs232.h
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
/*
|
||||||
|
***************************************************************************
|
||||||
|
*
|
||||||
|
* 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
***************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* 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 <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(__linux__) || defined(__FreeBSD__)
|
||||||
|
|
||||||
|
#include <termios.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <sys/file.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
#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
|
||||||
|
|
||||||
|
|
542
server.c
Normal file
542
server.c
Normal file
@ -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 <winsock2.h>
|
||||||
|
#else
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <netdb.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#endif
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <time.h>
|
||||||
|
#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 <Server Port>\n", argv[0]);
|
||||||
|
fprintf(stderr, "- %s <Server Port> <Config file>\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;
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user