9 changed files with 415 additions and 0 deletions
-
5.clang-format
-
0.gitignore
-
5.vscode/settings.json
-
1build.sh
-
204net_uart.cpp
-
0release/v1.0/aarch64/.mark
-
BINrelease/v1.0/aarch64/net_tty.out
-
172uart.cpp
-
28uart.hpp
@ -0,0 +1,5 @@ |
|||
# Defines the Chromium style for automatic reformatting. |
|||
# http://clang.llvm.org/docs/ClangFormatStyleOptions.html |
|||
Language: Cpp |
|||
BasedOnStyle: Google |
|||
ColumnLimit: 300 |
@ -0,0 +1,5 @@ |
|||
{ |
|||
"files.associations": { |
|||
"string_view": "cpp" |
|||
} |
|||
} |
@ -0,0 +1 @@ |
|||
aarch64-linux-gnu-g++ net_uart.cpp uart.cpp -o net_tty.out -lpthread |
@ -0,0 +1,204 @@ |
|||
|
|||
#include <fcntl.h>
|
|||
#include <stdint.h>
|
|||
#include <stdio.h>
|
|||
#include <stdlib.h>
|
|||
#include <string.h>
|
|||
#include <termios.h>
|
|||
#include <unistd.h>
|
|||
//
|
|||
#include <arpa/inet.h>
|
|||
#include <netinet/in.h>
|
|||
#include <sys/socket.h>
|
|||
#include <sys/types.h>
|
|||
//
|
|||
#include <map>
|
|||
#include <set>
|
|||
#include <string>
|
|||
|
|||
#include "uart.hpp"
|
|||
using namespace std; |
|||
#define BACK_LOG 10
|
|||
#define MAX_RECV_SIZE 235
|
|||
|
|||
typedef struct { |
|||
int fd; |
|||
struct sockaddr_in client; |
|||
} tcpclient_t; |
|||
map<string, uint32_t> g_baundmap = { |
|||
{"0", 0000000}, {"50", 0000001}, {"75", 0000002}, {"110", 0000003}, //
|
|||
{"134", 0000004}, {"150", 0000005}, {"200", 0000006}, {"300", 0000007}, //
|
|||
{"600", 0000010}, {"1200", 0000011}, {"1800", 0000012}, {"2400", 0000013}, //
|
|||
{"4800", 0000014}, {"9600", 0000015}, {"19200", 0000016}, {"38400", 0000017}, //
|
|||
{"57600", 0010001}, {"115200", 0010002}, {"230400", 0010003}, {"460800", 0010004}, //
|
|||
{"500000", 0010005}, {"576000", 0010006}, {"921600", 0010007}, {"1000000", 0010010}, //
|
|||
{"1152000", 0010011}, {"1500000", 0010012}, {"2000000", 0010013}, {"2500000", 0010014}, //
|
|||
{"3000000", 0010015}, {"3500000", 0010016}, {"4000000", 0010017}, |
|||
}; |
|||
UartDevice g_uart_device = {0}; |
|||
set<int> g_remote_client_fds; |
|||
|
|||
int safe_write(int fd, char *buff, size_t len) { |
|||
int hassend = 0; |
|||
while (true) { |
|||
int send_this_time = write(fd, buff + hassend, len - hassend); |
|||
if (send_this_time == 0) { |
|||
continue; |
|||
} |
|||
if (send_this_time < 0) { |
|||
return send_this_time; |
|||
} |
|||
|
|||
hassend += send_this_time; |
|||
if (hassend == len) { |
|||
break; |
|||
} |
|||
} |
|||
return len; |
|||
} |
|||
|
|||
void printf_buf(char *rx, ssize_t size) { |
|||
for (int i = 0; i < size; i++) { |
|||
printf("0x%02x,", rx[i]); |
|||
} |
|||
printf("\n"); |
|||
} |
|||
|
|||
void *netclient_thread(void *arg) { |
|||
tcpclient_t *client = (tcpclient_t *)arg; |
|||
// while循环监听数据,接收到数据转发给串口
|
|||
char buff[4096]; |
|||
int n = 0; |
|||
while ((n = read(client->fd, buff, 4096)) >= 0) { |
|||
printf("net->uart: %d\n", n); |
|||
printf_buf(buff, n); |
|||
uartSend(&g_uart_device, buff, n); |
|||
} |
|||
printf("socket %d is closed by client-end\n", client->fd); |
|||
close(client->fd); |
|||
g_remote_client_fds.erase(client->fd); |
|||
|
|||
free(client); |
|||
pthread_detach(pthread_self()); |
|||
return NULL; |
|||
} |
|||
|
|||
void *uart_rx_thread(void *arg) { |
|||
char buff[4096]; |
|||
while (true) { |
|||
int ret = uartReceive(&g_uart_device, buff, 1024); // send the received text over UART
|
|||
if (ret < 0) { |
|||
printf("uartReceive fail\n"); |
|||
exit(-1); |
|||
} |
|||
|
|||
//
|
|||
if (ret > 0) { |
|||
printf("net<-uart: %d\n", ret); |
|||
printf_buf(buff, ret); |
|||
for (auto &clientfd : g_remote_client_fds) { |
|||
safe_write(clientfd, buff, ret); |
|||
} |
|||
} |
|||
//
|
|||
} |
|||
return NULL; |
|||
} |
|||
|
|||
int start_tcp_server(int port) { |
|||
int listenfd, connectfd; |
|||
struct sockaddr_in server; |
|||
struct sockaddr_in client; |
|||
pid_t childpid; |
|||
socklen_t addrlen; |
|||
listenfd = socket(AF_INET, SOCK_STREAM, 0); |
|||
if (listenfd == -1) { |
|||
perror("socker created failed"); |
|||
exit(0); |
|||
} |
|||
int option; |
|||
option = SO_REUSEADDR; |
|||
setsockopt(listenfd, SOL_SOCKET, option, &option, sizeof(option)); |
|||
bzero(&server, sizeof(server)); |
|||
server.sin_family = AF_INET; |
|||
server.sin_port = htons(port); |
|||
server.sin_addr.s_addr = htonl(INADDR_ANY); |
|||
printf("bind......\n"); |
|||
if (bind(listenfd, (struct sockaddr *)&server, sizeof(server)) == -1) { |
|||
perror("Bind error!"); |
|||
exit(1); |
|||
} |
|||
printf("listen......\n"); |
|||
if (listen(listenfd, BACK_LOG) == -1) { |
|||
perror("listend error"); |
|||
exit(1); |
|||
} |
|||
printf("waiting for clinet's request.....\n"); |
|||
while (1) { |
|||
int n; |
|||
addrlen = sizeof(client); |
|||
connectfd = accept(listenfd, (struct sockaddr *)&client, &addrlen); |
|||
if (connectfd == -1) { |
|||
perror("accept error"); |
|||
sleep(1); |
|||
continue; |
|||
} |
|||
|
|||
printf("%s connect to me,connectfd == %d\n", inet_ntoa(client.sin_addr), connectfd); |
|||
g_remote_client_fds.insert(connectfd); |
|||
|
|||
pthread_t pthread; |
|||
tcpclient_t *client = (tcpclient_t *)malloc(sizeof(tcpclient_t)); |
|||
if (client == NULL) { |
|||
perror("malloc fail"); |
|||
exit(-1); |
|||
} |
|||
client->fd = connectfd; |
|||
memcpy(&client->client, &client, sizeof(client->client)); |
|||
pthread_create(&pthread, NULL, netclient_thread, (void *)client); |
|||
} |
|||
return 0; |
|||
} |
|||
|
|||
int openuart(struct UartDevice *device, const char *devname, int rate) { |
|||
device->name = (char *)devname; |
|||
device->rate = rate; |
|||
|
|||
printf("UART open %s\n", device->name); |
|||
return uartStart(device, 0); |
|||
} |
|||
int main(int argc, char const *argv[]) { |
|||
/* code */ |
|||
//"net_uart /dev/ttyUSB0 115200 port"
|
|||
|
|||
if (argc != 4) { |
|||
printf("Usage: %s /dev/ttyUSB0 115200 port\n", argv[0]); |
|||
return -1; |
|||
} |
|||
printf("device name:%s\n", argv[1]); |
|||
printf("baundrate :%s\n", argv[2]); |
|||
printf("port :%s\n", argv[3]); |
|||
|
|||
auto baundrate_find_result = g_baundmap.find(argv[2]); |
|||
if (baundrate_find_result == g_baundmap.end()) { |
|||
printf("unsupport baundrate\n"); |
|||
return -1; |
|||
// baundrate_find_result.
|
|||
}; |
|||
|
|||
/**
|
|||
* 打开串口 |
|||
*/ |
|||
int rc = openuart(&g_uart_device, argv[1], baundrate_find_result->second); |
|||
if (rc) { |
|||
perror("open uart fail"); |
|||
exit(-1); |
|||
} |
|||
|
|||
pthread_t uart_rx_thread; |
|||
pthread_create(&uart_rx_thread, NULL, netclient_thread, NULL); |
|||
|
|||
start_tcp_server(atoi(argv[3])); |
|||
|
|||
return 0; |
|||
} |
@ -0,0 +1,172 @@ |
|||
|
|||
/*
|
|||
* uart.c |
|||
* |
|||
* Created on: Aug 5, 2019 |
|||
* Author: Cristian Fatu |
|||
* Implements basic UART functionality, over Uart Lite linux driver, using termios. |
|||
* After booting linux, a device like "/dev/ttyUL1" must be present. |
|||
* These functions work in both canonic and not canonic modes. |
|||
* In the canonic communication mode, the received chars can be retrieved by read only after \n is detected. |
|||
* In the non canonic communication mode, the received chars can be retrieved by read as they are received. |
|||
*/ |
|||
#include "uart.hpp"
|
|||
|
|||
#include <fcntl.h>
|
|||
#include <stdio.h>
|
|||
#include <stdlib.h>
|
|||
#include <string.h>
|
|||
#include <termios.h>
|
|||
/*
|
|||
Parameters: |
|||
struct UartDevice* dev - pointer to the UartDevice struct |
|||
unsigned char canonic - communication mode |
|||
1 - canonic communication (chars are only received after \n is detected). |
|||
0 - non canonic communication (chars are received as they arrive over UART). |
|||
Return value: |
|||
UART_FAILURE -1 failure |
|||
UART_SUCCESS 0 success |
|||
Description: |
|||
Initializes the UART device. |
|||
When calling the function, the device name (usually "/dev/ttyUL1") must be filled in dev->name and the baud rate must be filled in dev->rate. |
|||
The canonic function parameter indicates communication mode (canonic or not). |
|||
In the canonic communication mode, the received chars can be retrieved by read only after \n is detected. |
|||
In the non canonic communication mode, the received chars can be retrieved by read as they are received, as the non canonic mode is configured with no wait. |
|||
*/ |
|||
int uartStart(struct UartDevice* dev, unsigned char canonic) { |
|||
struct termios* tty; |
|||
int fd; |
|||
int rc; |
|||
|
|||
fd = open(dev->name, O_RDWR | O_NOCTTY); |
|||
if (fd < 0) { |
|||
printf("%s: failed to open file descriptor for file %s\r\n", __func__, dev->name); |
|||
return UART_FAILURE; |
|||
} |
|||
|
|||
tty = (struct termios*)calloc(1, sizeof(*dev->tty)); |
|||
if (!tty) { |
|||
printf("%s: failed to allocate tty instance\r\n", __func__); |
|||
return UART_FAILURE; |
|||
} |
|||
// memset(tty, 0, sizeof(struct termios));
|
|||
|
|||
/*
|
|||
BAUDRATE: Set bps rate. You could also use cfsetispeed and cfsetospeed. |
|||
CRTSCTS : output hardware flow control (only used if the cable has |
|||
all necessary lines. See sect. 7 of Serial-HOWTO) |
|||
CS8 : 8n1 (8bit,no parity,1 stopbit) |
|||
CLOCAL : local connection, no modem contol |
|||
CREAD : enable receiving characters |
|||
*/ |
|||
// tty->c_cflag = dev->rate | CRTSCTS | CS8 | CLOCAL | CREAD;
|
|||
tty->c_cflag = dev->rate | CS8 | CLOCAL | CREAD; |
|||
if (canonic) { |
|||
// canonic
|
|||
/*
|
|||
IGNPAR : ignore bytes with parity errors |
|||
ICRNL : map CR to NL (otherwise a CR input on the other computer |
|||
will not terminate input) |
|||
otherwise make device raw (no other input processing) |
|||
*/ |
|||
tty->c_iflag = IGNPAR | ICRNL; |
|||
/*
|
|||
ICANON : enable canonical input |
|||
disable all echo functionality, and don't send signals to calling program |
|||
*/ |
|||
tty->c_lflag = ICANON; |
|||
} else { |
|||
// not canonic
|
|||
/*
|
|||
IGNPAR : ignore bytes with parity errorsc_cc[VTIME] |
|||
*/ |
|||
tty->c_iflag = IGNPAR; |
|||
/* set input mode (non-canonical, no echo,...) */ |
|||
tty->c_lflag = 0; |
|||
/* Do not wait for data */ |
|||
tty->c_cc[VTIME] = 0; /* inter-character timer unused */ |
|||
tty->c_cc[VMIN] = 0; /* blocking read until 5 chars received */ |
|||
} |
|||
|
|||
/*
|
|||
Raw output. |
|||
*/ |
|||
tty->c_oflag = 0; |
|||
|
|||
/* Flush port */ |
|||
tcflush(fd, TCIFLUSH); |
|||
|
|||
/* Apply attributes */ |
|||
rc = tcsetattr(fd, TCSANOW, tty); |
|||
if (rc) { |
|||
printf("%s: failed to set TCSANOW attr\r\n", __func__); |
|||
return UART_FAILURE; |
|||
} |
|||
|
|||
dev->fd = fd; |
|||
dev->tty = tty; |
|||
|
|||
return UART_SUCCESS; |
|||
} |
|||
|
|||
/*
|
|||
Parameters: |
|||
struct UartDevice* dev - pointer to the UartDevice struct |
|||
char *data - pointer to the array of chars to be sent over UART |
|||
int size |
|||
positive value - number of chars to be sent over UART |
|||
-1 - indicates that all the chars until string terminator \0 will be sent |
|||
Return value: |
|||
number of chars sent over UART |
|||
Description: |
|||
This function sends a number of chars over UART. |
|||
If the size function parameter is -1 then all the characters until string terminator \0 will be sent. |
|||
*/ |
|||
int uartSend(struct UartDevice* dev, char* data, int size) { |
|||
int sent = 0; |
|||
if (size == -1) { |
|||
size = strlen(data); |
|||
} |
|||
sent = write(dev->fd, data, size); |
|||
|
|||
#ifdef DEBUG
|
|||
printf("%s: sent %d characters\r\n", __func__, sent); |
|||
#endif
|
|||
return sent; |
|||
} |
|||
|
|||
/*
|
|||
Parameters: |
|||
struct UartDevice* dev - pointer to the UartDevice struct |
|||
char *data - pointer to the array of chars to hold the cars revceived over UART |
|||
int size_max - the maximum number of characters to be received |
|||
Return value: |
|||
number of chars received over UART |
|||
Description: |
|||
This function receives characters over UART. |
|||
In the canonic communication mode, the received chars will be retrieved by read only after \n is detected. |
|||
In the non canonic communication mode, the received chars will be retrieved by read as they are received, as the non canonic mode is configured with no wait. |
|||
*/ |
|||
int uartReceive(struct UartDevice* dev, char* data, int size_max) { |
|||
int received = 0; |
|||
|
|||
#ifdef DEBUG
|
|||
// printf("%s: receiving characters %d\r\n", __func__, size_max);
|
|||
#endif
|
|||
received = read(dev->fd, data, size_max - 1); |
|||
data[received] = '\0'; |
|||
|
|||
#ifdef DEBUG
|
|||
// if(received > 0)
|
|||
// printf("%s: received %d characters\r\n", __func__, received);
|
|||
// else
|
|||
// printf("%s: r%d/%d\r\n", __func__, received, size_max);
|
|||
#endif
|
|||
return received; |
|||
} |
|||
|
|||
int uartStop(struct UartDevice* dev) { |
|||
free(dev->tty); |
|||
|
|||
return UART_SUCCESS; |
|||
} |
@ -0,0 +1,28 @@ |
|||
/*
|
|||
* uart.h |
|||
* |
|||
* Created on: Aug 5, 2019 |
|||
* Author: cristian |
|||
*/ |
|||
|
|||
#include <termios.h>
|
|||
#include <unistd.h>
|
|||
#ifndef SRC_UART_H_
|
|||
#define SRC_UART_H_
|
|||
#define UART_FAILURE -1
|
|||
#define UART_SUCCESS 0
|
|||
// #define DEBUG
|
|||
struct UartDevice { |
|||
char* name; |
|||
int rate; |
|||
|
|||
int fd; |
|||
struct termios* tty; |
|||
}; |
|||
|
|||
int uartStart(struct UartDevice* dev, unsigned char canonic); |
|||
int uartSend(struct UartDevice* dev, char* data, int size); |
|||
int uartReceive(struct UartDevice* dev, char* data, int size_max); |
|||
int uartStop(struct UartDevice* dev); |
|||
|
|||
#endif /* SRC_UART_H_ */
|
Write
Preview
Loading…
Cancel
Save
Reference in new issue