From 3a5fb92a375aed63d080658ddd728756b4ca7e7e Mon Sep 17 00:00:00 2001 From: We-unite <3205135446@qq.com> Date: Fri, 7 Jun 2024 14:00:49 +0800 Subject: initial commit --- .gitignore | 2 + serial.c | 260 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ server.cpp | 167 ++++++++++++++++++++++++++++++++++++++ testClient.c | 97 ++++++++++++++++++++++ 4 files changed, 526 insertions(+) create mode 100644 .gitignore create mode 100644 serial.c create mode 100644 server.cpp create mode 100644 testClient.c diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..367f77e --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +build/* +.vscode/* \ No newline at end of file diff --git a/serial.c b/serial.c new file mode 100644 index 0000000..43506ec --- /dev/null +++ b/serial.c @@ -0,0 +1,260 @@ +/* + * 在OpenHarmony系统下开发串口通信的应用与在Linux系统中类似, + * 但需要确保你的设备支持串口操作,并且有适当的驱动支持。 + * + * 以下是一个用C++编写的示例,展示如何在OpenHarmony中打开串口, + * 设置波特率为115200,并发送指定的16进制数。 + * - 打开串口:使用open()函数打开指定的串口设备。 + * - 配置串口:使用termios结构体配置串口参数如波特率、字符大小、奇偶校验等。 + * - 发送数据:使用write()函数将数据写入串口。 + * - 关闭串口:操作完成后,使用close()函数关闭串口。 + * 确保你的OpenHarmony设备有对应的串口设备文件/dev/ttyS1, + * 并且你的应用有足够的权限来访问这个设备。根据你的硬件和操作系统配置,设备文件的路径可能不同。 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define FULL_SPEED 1.0f // 全速前进的速度 +#define R 0.15f // 轮距的一半 + +typedef unsigned char byte; +int fd; +int port = 5001; +char portname[50] = "/dev/ttyUSB0"; // 串口设备名 +char clientIP[20] = ""; + +struct termios tty; +pthread_t udpSend, udpRecv; +const int MAX_BUFFER_SIZE = 1024; +struct sockaddr_in clientAddr; + +int whellInit() { + // 打开串口 + fd = open(portname, O_RDWR | O_NOCTTY | O_SYNC); + if (fd < 0) { + // C语言报error + fprintf(stderr, "Error opening %s: %s\n", portname, strerror(errno)); + return false; + } + + // 设置串口参数 + memset(&tty, 0, sizeof tty); + if (tcgetattr(fd, &tty) != 0) { + // cerr << "Error from tcgetattr: " << strerror(errno) << endl; + fprintf(stderr, "Error from tcgetattr: %s\n", strerror(errno)); + return false; + } + + cfsetospeed(&tty, B115200); // 设置输出波特率为115200 + cfsetispeed(&tty, B115200); // 设置输入波特率为115200 + + tty.c_cflag = (tty.c_cflag & ~CSIZE) | CS8; // 8-bit chars + tty.c_iflag &= ~IGNBRK; // ignore break signal + tty.c_lflag = 0; // no signaling chars, no echo, + // no canonical processing + tty.c_oflag = 0; // no remapping, no delays + tty.c_cc[VMIN] = 0; // read doesn't block + tty.c_cc[VTIME] = 5; // 0.5 seconds read timeout + + tty.c_iflag &= ~(IXON | IXOFF | IXANY); // shut off xon/xoff ctrl + tty.c_cflag |= (CLOCAL | CREAD); // ignore modem controls, + // enable reading + tty.c_cflag &= ~(PARENB | PARODD); // shut off parity + tty.c_cflag |= 0; + tty.c_cflag &= ~CSTOPB; + tty.c_cflag &= ~CRTSCTS; + + if (tcsetattr(fd, TCSANOW, &tty) != 0) { + // cerr << "Error from tcsetattr: " << strerror(errno) << endl; + fprintf(stderr, "Error from tcsetattr: %s\n", strerror(errno)); + return false; + } + return true; +} + +bool wheelSend(byte a, byte a_v, byte b, byte b_v) { + unsigned char data[7] = {0x53, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00}; + byte checksum = 0; + data[2] = a; + data[3] = a_v; + data[4] = b; + data[5] = b_v; + + for (int i = 0; i < 6; i++) { + checksum ^= data[i]; + } + data[6] = checksum; + + // 发送数据 + if (write(fd, data, 7) != 7) { + fprintf(stderr, "Failed to write to the serial port\n"); + return false; + } + + printf("Data %02X %02X %02X %02X %02X %02X %02X wheelSend successfully!\n", + data[0], data[1], data[2], data[3], data[4], data[5], data[6]); + return true; +} + +void speedControl(byte status, byte speed) { + switch (status) { + case 1: + wheelSend(0x01, speed, 0x01, speed); + break; + case 2: + wheelSend(0x02, speed, 0x01, speed); + break; + case 3: + wheelSend(0x01, speed, 0x02, speed); + break; + case 0: + default: + wheelSend(0x00, 0x00, 0x00, 0x00); + break; + } +} + +void udpSendThread() { + // 创建UDP套接字 + int sockfd = -1; + struct sockaddr_in serverAddr; + if ((sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) { + fprintf(stderr, "Error: Failed to create socket\n"); + return; + } + + memset((char *)&serverAddr, 0, sizeof(serverAddr)); + serverAddr.sin_family = AF_INET; // 设置地址族为IPv4 + serverAddr.sin_port = htons(port); // 设置端口号 + if (inet_aton(clientIP, &serverAddr.sin_addr) == 0) { + fprintf(stderr, "Error: Failed to convert IP address\n"); + close(sockfd); + return; + } + while (true) { + // 每秒向socket发送一次0x30 + byte a = 0x39; + // 发送消息 + sendto(sockfd, (const char *)&a, 1, 0, (struct sockaddr *)&serverAddr, + sizeof(serverAddr)); + printf("Send: Data %02X udpSend successfully!\n", a); + sleep(1); + } +} + +void udpRecvThread() { + int socketfd = -1; + char buffer[MAX_BUFFER_SIZE]; + struct sockaddr_in serverAddr; + socklen_t addrLen = sizeof(serverAddr); + int bytesReceived; + + // fd_set readfds; + // struct timeval tv; + int retval; + struct pollfd fds; + + if ((socketfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) { + fprintf(stderr, "Error: Failed to create socket\n"); + return; + } + memset((char *)&serverAddr, 0, sizeof(serverAddr)); + memset(buffer, 0, sizeof(buffer)); + serverAddr.sin_family = AF_INET; + serverAddr.sin_port = htons(port); + serverAddr.sin_addr.s_addr = htonl(INADDR_ANY); + + if (bind(socketfd, (struct sockaddr *)&serverAddr, sizeof(serverAddr)) == + -1) { + // cerr << "Error: Bind failed" << endl; + fprintf(stderr, "Error: Bind failed\n"); + close(socketfd); + return; + } + + bytesReceived = recvfrom(socketfd, buffer, MAX_BUFFER_SIZE, 0, + (struct sockaddr *)&clientAddr, &addrLen); + if (bytesReceived == -1) { + fprintf(stderr, "Error: Failed to receive data\n"); + close(socketfd); + return; + } + printf("Received start message from %s: %s\n", + inet_ntoa(clientAddr.sin_addr), buffer); + strcpy(clientIP, inet_ntoa(clientAddr.sin_addr)); + + if (pthread_create(&udpSend, NULL, udpSendThread, NULL) != 0) { + fprintf(stderr, "Error creating udpSend thread\n"); + close(socketfd); + return; + } + + fds.fd = socketfd; + fds.events = POLLIN; + + while (true) { + // /* Watch sock to see when it has input. */ + // FD_ZERO(&readfds); + // FD_SET(socketfd, &readfds); + // /* Wait up to three seconds. */ + // tv.tv_sec = 3; + // tv.tv_usec = 0; + + // retval = select(socketfd + 1, &readfds, NULL, NULL, &tv); + retval = poll(&fds, 1, 3000); + if (retval == -1) { + fprintf(stderr, "Error: select failed\n"); + break; + } else if (retval == 0) { + printf("No data within three seconds.\n"); + speedControl(0, 0); + // break; + } else { + bytesReceived = recvfrom(socketfd, buffer, MAX_BUFFER_SIZE, 0, + (struct sockaddr *)&clientAddr, &addrLen); + if (bytesReceived == -1) { + fprintf(stderr, "Error: Failed to receive data\n"); + continue; + } + printf("Received Message from %s: %2x %2x\n", + inet_ntoa(clientAddr.sin_addr), buffer[0], buffer[1]); + speedControl(buffer[0], buffer[1]); + } + } +} + +int main() { + // 关闭1号和2号文件描述符 + // close(1); + // close(2); + // // 打开serial.log文件,并将其复制到1号和2号文件描述符 + // open("serial.log", O_RDWR | O_CREAT, 0666); + // dup(1); + // dup(2); + + if (!whellInit()) { + goto err; + } + + if (pthread_create(&udpRecv, NULL, udpRecvThread, NULL) != 0) { + fprintf(stderr, "Error creating udpRecv thread\n"); + goto err; + } + pthread_join(udpRecv, NULL); + +err: + close(fd); + return 0; +} diff --git a/server.cpp b/server.cpp new file mode 100644 index 0000000..5e41eb8 --- /dev/null +++ b/server.cpp @@ -0,0 +1,167 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; + +enum robotState { // 机器人状态枚举 + beforeStart, + pending, + afterEnd, // 建好了图,接下来可选择重新建图或选终点开始路径 + startRoute, +}; + +enum runState { stop, go, left, right }; + +struct ReceiveDataStruct { + int robotId; + robotState state; + int x; + int y; + int r; +}; + +const int PORT = 5001; +const char *SERVER_IP = "0.0.0.0"; +const int MAX_BUFFER_SIZE = 1024; + +struct ReceiveData { + int values[4]; +}; + +bool newDataAvailable = false; +string CLIENT_IP = "127.0.0.1"; +struct sockaddr_in clientAddr; +ReceiveData receivedData = {{0, 1, 2, 3}}; + +// UDP发送线程函数 +void udpSenderThread() { + char values[100] = {0}; + struct sockaddr_in serverAddr; + int sockfd = -1; + + // 创建UDP套接字 + if ((sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) { + fprintf(stderr, "Error: Failed to create socket\n"); + return; + } + + memset((char *)&serverAddr, 0, sizeof(serverAddr)); + serverAddr.sin_family = AF_INET; + serverAddr.sin_port = htons(PORT); + if (inet_aton(CLIENT_IP.c_str(), &serverAddr.sin_addr) == 0) { + fprintf(stderr, "Error: Failed to convert IP address\n"); + close(sockfd); + return; + } + + while (true) { + this_thread::sleep_for(chrono::seconds(1)); // 每1秒发送一次 + + // 更新发送的消息 + memset(values, 0, 100); + for (int i = 0; i < 4; ++i) { + // values[i] = receivedData.values[i] + 1; + sprintf(values + strlen(values), "%d ", receivedData.values[i] + 1); + } + sprintf(values + strlen(values), "\n"); + printf("Sending message to %s: %s\n", CLIENT_IP.c_str(), values); + + // 发送消息 + sendto(sockfd, (const char *)values, sizeof(int) * 4, 0, + (struct sockaddr *)&serverAddr, sizeof(serverAddr)); + } + + close(sockfd); +} + +// 主线程接收UDP消息并打印 +void receiveAndPrintMessages() { + int sock; + struct sockaddr_in serverAddr; + socklen_t addrLen = sizeof(clientAddr); + char buffer[MAX_BUFFER_SIZE]; + ReceiveData receivedData; + int pos, bytesReceived; + + // 创建UDP套接字 + if ((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) { + fprintf(stderr, "Error: Failed to create socket\n"); + return; + } + + memset((char *)&serverAddr, 0, sizeof(serverAddr)); + memset(buffer, 0, sizeof(buffer)); + serverAddr.sin_family = AF_INET; + serverAddr.sin_port = htons(PORT); + serverAddr.sin_addr.s_addr = htonl(INADDR_ANY); + + // 绑定到端口 + if (::bind(sock, (struct sockaddr *)&serverAddr, sizeof(serverAddr)) == + -1) { + cerr << "Error: Bind failed" << endl; + close(sock); + return; + } + + bytesReceived = recvfrom(sock, buffer, MAX_BUFFER_SIZE, 0, + (struct sockaddr *)&clientAddr, &addrLen); + if (bytesReceived == -1) { + fprintf(stderr, "Error: Failed to receive data\n"); + return; + } + printf("Received Message from %s: %s\n", inet_ntoa(clientAddr.sin_addr), + buffer); + CLIENT_IP = inet_ntoa(clientAddr.sin_addr); + thread senderThread2(udpSenderThread); + while (true) { + // 接收消息 + bytesReceived = recvfrom(sock, buffer, MAX_BUFFER_SIZE, 0, + (struct sockaddr *)&clientAddr, &addrLen); + if (bytesReceived == -1) { + fprintf(stderr, "Error: Failed to receive data\n"); + continue; + } + + printf("Receive %d bytes from %s: \"%s\"\n", bytesReceived, + CLIENT_IP.c_str(), buffer); + pos = 0; + for (int i = 0; i < 4; ++i) { + receivedData.values[i] = atoi(strtok(buffer + pos, " ")); + // pos += log10(receivedData.values[i]) + 2; + // pos需要递增,否则会一直解析第一个数,要求能处理数据为0或负数的情况 + pos += strlen(strtok(buffer + pos, " ")) + 1; + } + newDataAvailable = true; + + // 打印消息 + // CLIENT_IP = inet_ntoa(clientAddr.sin_addr); + // cout << "Received Message from " << CLIENT_IP << ": "; + // printf("Received Message from %s: ", CLIENT_IP.c_str()); + // for (int i = 0; i < 4; ++i) { + // printf("%d ", receivedData.values[i]); + // } + printf("\n"); + } + + close(sock); + senderThread2.join(); +} + +int main() { + thread receiverThread(receiveAndPrintMessages); + receiverThread.join(); + + return 0; +} diff --git a/testClient.c b/testClient.c new file mode 100644 index 0000000..bbd2529 --- /dev/null +++ b/testClient.c @@ -0,0 +1,97 @@ +// 编写一段C程序,使用pthread创建两个线程 +// 发送线程将数据发送到127.0.0.1的5001端口,每0.5s一次 +// 接收线程接收127.0.0.1的5001端口的数据并打印 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +pthread_t udpSend, udpRecv; +pthread_mutex_t mutex; +int port = 5001; +char clientIP[20] = "127.0.0.1"; + +void udpSenderThread() { + struct sockaddr_in serverAddr; + int sockfd = -1; + + // 创建UDP套接字 + if ((sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) { + fprintf(stderr, "Error: Failed to create socket\n"); + return; + } + + memset((char *)&serverAddr, 0, sizeof(serverAddr)); + serverAddr.sin_family = AF_INET; + serverAddr.sin_port = htons(port); + serverAddr.sin_addr.s_addr = inet_addr(clientIP); + + while (1) { + char values[100] = {0}; + // strcpy(values, "Hello, world!"); + pthread_mutex_lock(&mutex); + printf("Input the data you want to send: "); + scanf("%s", values); + pthread_mutex_unlock(&mutex); + sendto(sockfd, values, strlen(values), 0, + (struct sockaddr *)&serverAddr, sizeof(serverAddr)); + // printf("Send: %s\n", values); + sleep(1); + } +} + +void udpReceiverThread() { + int sockfd = -1; + struct sockaddr_in serverAddr; + struct sockaddr_in clientAddr; + socklen_t clientAddrLen = sizeof(clientAddr); + char buffer[1024] = {0}; + + // 创建UDP套接字 + if ((sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) { + fprintf(stderr, "Error: Failed to create socket\n"); + return; + } + + memset((char *)&serverAddr, 0, sizeof(serverAddr)); + serverAddr.sin_family = AF_INET; + serverAddr.sin_port = htons(port - 1); + serverAddr.sin_addr.s_addr = htonl(INADDR_ANY); + + if (bind(sockfd, (struct sockaddr *)&serverAddr, sizeof(serverAddr)) == + -1) { + fprintf(stderr, "Error: Failed to bind socket\n"); + close(sockfd); + return; + } + + while (1) { + pthread_mutex_lock(&mutex); + int len = recvfrom(sockfd, buffer, 1024, 0, + (struct sockaddr *)&clientAddr, &clientAddrLen); + pthread_mutex_unlock(&mutex); + if (len == -1) { + fprintf(stderr, "Error: Failed to receive data\n"); + close(sockfd); + return; + } + buffer[len] = '\0'; + printf("Received: %s\n", buffer); + } +} + +int main() { + pthread_create(&udpSend, NULL, udpSenderThread, NULL); + // pthread_create(&udpRecv, NULL, udpReceiverThread, NULL); + pthread_join(udpSend, NULL); + // pthread_join(udpRecv, NULL); +} \ No newline at end of file -- cgit v1.2.3-70-g09d2