From 8cede72a8cd3b8a3d21938216f855f755d894e9a Mon Sep 17 00:00:00 2001 From: zhaohe <1013909206@qq.com> Date: Wed, 29 Dec 2021 15:47:09 +0800 Subject: [PATCH] first commit --- .clang-format | 5 + .gitignore | 0 .vscode/settings.json | 5 + build.sh | 1 + net_uart.cpp | 204 +++++++++++++++++++++++++++++++++++++++ release/v1.0/aarch64/.mark | 0 release/v1.0/aarch64/net_tty.out | Bin 0 -> 77456 bytes uart.cpp | 172 +++++++++++++++++++++++++++++++++ uart.hpp | 28 ++++++ 9 files changed, 415 insertions(+) create mode 100644 .clang-format create mode 100644 .gitignore create mode 100644 .vscode/settings.json create mode 100755 build.sh create mode 100644 net_uart.cpp create mode 100644 release/v1.0/aarch64/.mark create mode 100755 release/v1.0/aarch64/net_tty.out create mode 100644 uart.cpp create mode 100644 uart.hpp diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..8587fbe --- /dev/null +++ b/.clang-format @@ -0,0 +1,5 @@ +# Defines the Chromium style for automatic reformatting. +# http://clang.llvm.org/docs/ClangFormatStyleOptions.html +Language: Cpp +BasedOnStyle: Google +ColumnLimit: 300 \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e69de29 diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..a478c1f --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,5 @@ +{ + "files.associations": { + "string_view": "cpp" + } +} \ No newline at end of file diff --git a/build.sh b/build.sh new file mode 100755 index 0000000..cc8c952 --- /dev/null +++ b/build.sh @@ -0,0 +1 @@ +aarch64-linux-gnu-g++ net_uart.cpp uart.cpp -o net_tty.out -lpthread \ No newline at end of file diff --git a/net_uart.cpp b/net_uart.cpp new file mode 100644 index 0000000..7079c46 --- /dev/null +++ b/net_uart.cpp @@ -0,0 +1,204 @@ + +#include +#include +#include +#include +#include +#include +#include +// +#include +#include +#include +#include +// +#include +#include +#include + +#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 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 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; +} diff --git a/release/v1.0/aarch64/.mark b/release/v1.0/aarch64/.mark new file mode 100644 index 0000000..e69de29 diff --git a/release/v1.0/aarch64/net_tty.out b/release/v1.0/aarch64/net_tty.out new file mode 100755 index 0000000000000000000000000000000000000000..1c016791ad8a1f8874fa12f75439007b6edd976c GIT binary patch literal 77456 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 II3Csi2c5<9^8f$< literal 0 HcmV?d00001 diff --git a/uart.cpp b/uart.cpp new file mode 100644 index 0000000..5df30b4 --- /dev/null +++ b/uart.cpp @@ -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 +#include +#include +#include +#include +/* +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; +} \ No newline at end of file diff --git a/uart.hpp b/uart.hpp new file mode 100644 index 0000000..66de474 --- /dev/null +++ b/uart.hpp @@ -0,0 +1,28 @@ +/* + * uart.h + * + * Created on: Aug 5, 2019 + * Author: cristian + */ + +#include +#include +#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_ */ \ No newline at end of file