aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWe-unite <3205135446@qq.com>2024-06-11 19:05:45 +0800
committerWe-unite <3205135446@qq.com>2024-06-11 19:41:27 +0800
commitd746146529490663993e489de21d0c15e2d234ad (patch)
treea2ef7f295702323210a9e33daf525a9a3ffefb27
parent3a5fb92a375aed63d080658ddd728756b4ca7e7e (diff)
downloadWheelCtrl-d746146529490663993e489de21d0c15e2d234ad.tar.gz
WheelCtrl-d746146529490663993e489de21d0c15e2d234ad.zip
Add udp2lcm server && datastructure to wheel ctrl
-rw-r--r--path/path_ctrl.lcm5
-rw-r--r--path/path_ctrl_t.c241
-rw-r--r--path/path_ctrl_t.h143
-rw-r--r--serial.c196
-rw-r--r--server.cpp167
-rw-r--r--testClient.c97
-rw-r--r--udp2lcm.c184
7 files changed, 602 insertions, 431 deletions
diff --git a/path/path_ctrl.lcm b/path/path_ctrl.lcm
new file mode 100644
index 0000000..502e342
--- /dev/null
+++ b/path/path_ctrl.lcm
@@ -0,0 +1,5 @@
1struct path_ctrl_t
2{
3 int8_t cmd;
4 int8_t speed;
5}
diff --git a/path/path_ctrl_t.c b/path/path_ctrl_t.c
new file mode 100644
index 0000000..2298a56
--- /dev/null
+++ b/path/path_ctrl_t.c
@@ -0,0 +1,241 @@
1// THIS IS AN AUTOMATICALLY GENERATED FILE. DO NOT MODIFY
2// BY HAND!!
3//
4// Generated by lcm-gen
5
6#include <string.h>
7#include "path_ctrl_t.h"
8
9static int __path_ctrl_t_hash_computed;
10static uint64_t __path_ctrl_t_hash;
11
12uint64_t __path_ctrl_t_hash_recursive(const __lcm_hash_ptr *p)
13{
14 const __lcm_hash_ptr *fp;
15 for (fp = p; fp != NULL; fp = fp->parent)
16 if (fp->v == __path_ctrl_t_get_hash)
17 return 0;
18
19 __lcm_hash_ptr cp;
20 cp.parent = p;
21 cp.v = (void*)__path_ctrl_t_get_hash;
22 (void) cp;
23
24 uint64_t hash = (uint64_t)0x5cf946463c463b9eLL
25 + __int8_t_hash_recursive(&cp)
26 + __int8_t_hash_recursive(&cp)
27 ;
28
29 return (hash<<1) + ((hash>>63)&1);
30}
31
32int64_t __path_ctrl_t_get_hash(void)
33{
34 if (!__path_ctrl_t_hash_computed) {
35 __path_ctrl_t_hash = (int64_t)__path_ctrl_t_hash_recursive(NULL);
36 __path_ctrl_t_hash_computed = 1;
37 }
38
39 return __path_ctrl_t_hash;
40}
41
42int __path_ctrl_t_encode_array(void *buf, int offset, int maxlen, const path_ctrl_t *p, int elements)
43{
44 int pos = 0, element;
45 int thislen;
46
47 for (element = 0; element < elements; element++) {
48
49 thislen = __int8_t_encode_array(buf, offset + pos, maxlen - pos, &(p[element].cmd), 1);
50 if (thislen < 0) return thislen; else pos += thislen;
51
52 thislen = __int8_t_encode_array(buf, offset + pos, maxlen - pos, &(p[element].speed), 1);
53 if (thislen < 0) return thislen; else pos += thislen;
54
55 }
56 return pos;
57}
58
59int path_ctrl_t_encode(void *buf, int offset, int maxlen, const path_ctrl_t *p)
60{
61 int pos = 0, thislen;
62 int64_t hash = __path_ctrl_t_get_hash();
63
64 thislen = __int64_t_encode_array(buf, offset + pos, maxlen - pos, &hash, 1);
65 if (thislen < 0) return thislen; else pos += thislen;
66
67 thislen = __path_ctrl_t_encode_array(buf, offset + pos, maxlen - pos, p, 1);
68 if (thislen < 0) return thislen; else pos += thislen;
69
70 return pos;
71}
72
73int __path_ctrl_t_encoded_array_size(const path_ctrl_t *p, int elements)
74{
75 int size = 0, element;
76 for (element = 0; element < elements; element++) {
77
78 size += __int8_t_encoded_array_size(&(p[element].cmd), 1);
79
80 size += __int8_t_encoded_array_size(&(p[element].speed), 1);
81
82 }
83 return size;
84}
85
86int path_ctrl_t_encoded_size(const path_ctrl_t *p)
87{
88 return 8 + __path_ctrl_t_encoded_array_size(p, 1);
89}
90
91int __path_ctrl_t_decode_array(const void *buf, int offset, int maxlen, path_ctrl_t *p, int elements)
92{
93 int pos = 0, thislen, element;
94
95 for (element = 0; element < elements; element++) {
96
97 thislen = __int8_t_decode_array(buf, offset + pos, maxlen - pos, &(p[element].cmd), 1);
98 if (thislen < 0) return thislen; else pos += thislen;
99
100 thislen = __int8_t_decode_array(buf, offset + pos, maxlen - pos, &(p[element].speed), 1);
101 if (thislen < 0) return thislen; else pos += thislen;
102
103 }
104 return pos;
105}
106
107int __path_ctrl_t_decode_array_cleanup(path_ctrl_t *p, int elements)
108{
109 int element;
110 for (element = 0; element < elements; element++) {
111
112 __int8_t_decode_array_cleanup(&(p[element].cmd), 1);
113
114 __int8_t_decode_array_cleanup(&(p[element].speed), 1);
115
116 }
117 return 0;
118}
119
120int path_ctrl_t_decode(const void *buf, int offset, int maxlen, path_ctrl_t *p)
121{
122 int pos = 0, thislen;
123 int64_t hash = __path_ctrl_t_get_hash();
124
125 int64_t this_hash;
126 thislen = __int64_t_decode_array(buf, offset + pos, maxlen - pos, &this_hash, 1);
127 if (thislen < 0) return thislen; else pos += thislen;
128 if (this_hash != hash) return -1;
129
130 thislen = __path_ctrl_t_decode_array(buf, offset + pos, maxlen - pos, p, 1);
131 if (thislen < 0) return thislen; else pos += thislen;
132
133 return pos;
134}
135
136int path_ctrl_t_decode_cleanup(path_ctrl_t *p)
137{
138 return __path_ctrl_t_decode_array_cleanup(p, 1);
139}
140
141int __path_ctrl_t_clone_array(const path_ctrl_t *p, path_ctrl_t *q, int elements)
142{
143 int element;
144 for (element = 0; element < elements; element++) {
145
146 __int8_t_clone_array(&(p[element].cmd), &(q[element].cmd), 1);
147
148 __int8_t_clone_array(&(p[element].speed), &(q[element].speed), 1);
149
150 }
151 return 0;
152}
153
154path_ctrl_t *path_ctrl_t_copy(const path_ctrl_t *p)
155{
156 path_ctrl_t *q = (path_ctrl_t*) malloc(sizeof(path_ctrl_t));
157 __path_ctrl_t_clone_array(p, q, 1);
158 return q;
159}
160
161void path_ctrl_t_destroy(path_ctrl_t *p)
162{
163 __path_ctrl_t_decode_array_cleanup(p, 1);
164 free(p);
165}
166
167int path_ctrl_t_publish(lcm_t *lc, const char *channel, const path_ctrl_t *p)
168{
169 int max_data_size = path_ctrl_t_encoded_size (p);
170 uint8_t *buf = (uint8_t*) malloc (max_data_size);
171 if (!buf) return -1;
172 int data_size = path_ctrl_t_encode (buf, 0, max_data_size, p);
173 if (data_size < 0) {
174 free (buf);
175 return data_size;
176 }
177 int status = lcm_publish (lc, channel, buf, data_size);
178 free (buf);
179 return status;
180}
181
182struct _path_ctrl_t_subscription_t {
183 path_ctrl_t_handler_t user_handler;
184 void *userdata;
185 lcm_subscription_t *lc_h;
186};
187static
188void path_ctrl_t_handler_stub (const lcm_recv_buf_t *rbuf,
189 const char *channel, void *userdata)
190{
191 int status;
192 path_ctrl_t p;
193 memset(&p, 0, sizeof(path_ctrl_t));
194 status = path_ctrl_t_decode (rbuf->data, 0, rbuf->data_size, &p);
195 if (status < 0) {
196 fprintf (stderr, "error %d decoding path_ctrl_t!!!\n", status);
197 return;
198 }
199
200 path_ctrl_t_subscription_t *h = (path_ctrl_t_subscription_t*) userdata;
201 h->user_handler (rbuf, channel, &p, h->userdata);
202
203 path_ctrl_t_decode_cleanup (&p);
204}
205
206path_ctrl_t_subscription_t* path_ctrl_t_subscribe (lcm_t *lcm,
207 const char *channel,
208 path_ctrl_t_handler_t f, void *userdata)
209{
210 path_ctrl_t_subscription_t *n = (path_ctrl_t_subscription_t*)
211 malloc(sizeof(path_ctrl_t_subscription_t));
212 n->user_handler = f;
213 n->userdata = userdata;
214 n->lc_h = lcm_subscribe (lcm, channel,
215 path_ctrl_t_handler_stub, n);
216 if (n->lc_h == NULL) {
217 fprintf (stderr,"couldn't reg path_ctrl_t LCM handler!\n");
218 free (n);
219 return NULL;
220 }
221 return n;
222}
223
224int path_ctrl_t_subscription_set_queue_capacity (path_ctrl_t_subscription_t* subs,
225 int num_messages)
226{
227 return lcm_subscription_set_queue_capacity (subs->lc_h, num_messages);
228}
229
230int path_ctrl_t_unsubscribe(lcm_t *lcm, path_ctrl_t_subscription_t* hid)
231{
232 int status = lcm_unsubscribe (lcm, hid->lc_h);
233 if (0 != status) {
234 fprintf(stderr,
235 "couldn't unsubscribe path_ctrl_t_handler %p!\n", hid);
236 return -1;
237 }
238 free (hid);
239 return 0;
240}
241
diff --git a/path/path_ctrl_t.h b/path/path_ctrl_t.h
new file mode 100644
index 0000000..3e629eb
--- /dev/null
+++ b/path/path_ctrl_t.h
@@ -0,0 +1,143 @@
1// THIS IS AN AUTOMATICALLY GENERATED FILE. DO NOT MODIFY
2// BY HAND!!
3//
4// Generated by lcm-gen
5
6#include <stdint.h>
7#include <stdlib.h>
8#include <lcm/lcm_coretypes.h>
9#include <lcm/lcm.h>
10
11#ifndef _path_ctrl_t_h
12#define _path_ctrl_t_h
13
14#ifdef __cplusplus
15extern "C" {
16#endif
17
18typedef struct _path_ctrl_t path_ctrl_t;
19struct _path_ctrl_t
20{
21 int8_t cmd;
22 int8_t speed;
23};
24
25/**
26 * Create a deep copy of a path_ctrl_t.
27 * When no longer needed, destroy it with path_ctrl_t_destroy()
28 */
29path_ctrl_t* path_ctrl_t_copy(const path_ctrl_t* to_copy);
30
31/**
32 * Destroy an instance of path_ctrl_t created by path_ctrl_t_copy()
33 */
34void path_ctrl_t_destroy(path_ctrl_t* to_destroy);
35
36/**
37 * Identifies a single subscription. This is an opaque data type.
38 */
39typedef struct _path_ctrl_t_subscription_t path_ctrl_t_subscription_t;
40
41/**
42 * Prototype for a callback function invoked when a message of type
43 * path_ctrl_t is received.
44 */
45typedef void(*path_ctrl_t_handler_t)(const lcm_recv_buf_t *rbuf,
46 const char *channel, const path_ctrl_t *msg, void *userdata);
47
48/**
49 * Publish a message of type path_ctrl_t using LCM.
50 *
51 * @param lcm The LCM instance to publish with.
52 * @param channel The channel to publish on.
53 * @param msg The message to publish.
54 * @return 0 on success, <0 on error. Success means LCM has transferred
55 * responsibility of the message data to the OS.
56 */
57int path_ctrl_t_publish(lcm_t *lcm, const char *channel, const path_ctrl_t *msg);
58
59/**
60 * Subscribe to messages of type path_ctrl_t using LCM.
61 *
62 * @param lcm The LCM instance to subscribe with.
63 * @param channel The channel to subscribe to.
64 * @param handler The callback function invoked by LCM when a message is received.
65 * This function is invoked by LCM during calls to lcm_handle() and
66 * lcm_handle_timeout().
67 * @param userdata An opaque pointer passed to @p handler when it is invoked.
68 * @return 0 on success, <0 if an error occured
69 */
70path_ctrl_t_subscription_t* path_ctrl_t_subscribe(lcm_t *lcm, const char *channel, path_ctrl_t_handler_t handler, void *userdata);
71
72/**
73 * Removes and destroys a subscription created by path_ctrl_t_subscribe()
74 */
75int path_ctrl_t_unsubscribe(lcm_t *lcm, path_ctrl_t_subscription_t* hid);
76
77/**
78 * Sets the queue capacity for a subscription.
79 * Some LCM providers (e.g., the default multicast provider) are implemented
80 * using a background receive thread that constantly revceives messages from
81 * the network. As these messages are received, they are buffered on
82 * per-subscription queues until dispatched by lcm_handle(). This function
83 * how many messages are queued before dropping messages.
84 *
85 * @param subs the subscription to modify.
86 * @param num_messages The maximum number of messages to queue
87 * on the subscription.
88 * @return 0 on success, <0 if an error occured
89 */
90int path_ctrl_t_subscription_set_queue_capacity(path_ctrl_t_subscription_t* subs,
91 int num_messages);
92
93/**
94 * Encode a message of type path_ctrl_t into binary form.
95 *
96 * @param buf The output buffer.
97 * @param offset Encoding starts at this byte offset into @p buf.
98 * @param maxlen Maximum number of bytes to write. This should generally
99 * be equal to path_ctrl_t_encoded_size().
100 * @param msg The message to encode.
101 * @return The number of bytes encoded, or <0 if an error occured.
102 */
103int path_ctrl_t_encode(void *buf, int offset, int maxlen, const path_ctrl_t *p);
104
105/**
106 * Decode a message of type path_ctrl_t from binary form.
107 * When decoding messages containing strings or variable-length arrays, this
108 * function may allocate memory. When finished with the decoded message,
109 * release allocated resources with path_ctrl_t_decode_cleanup().
110 *
111 * @param buf The buffer containing the encoded message
112 * @param offset The byte offset into @p buf where the encoded message starts.
113 * @param maxlen The maximum number of bytes to read while decoding.
114 * @param msg Output parameter where the decoded message is stored
115 * @return The number of bytes decoded, or <0 if an error occured.
116 */
117int path_ctrl_t_decode(const void *buf, int offset, int maxlen, path_ctrl_t *msg);
118
119/**
120 * Release resources allocated by path_ctrl_t_decode()
121 * @return 0
122 */
123int path_ctrl_t_decode_cleanup(path_ctrl_t *p);
124
125/**
126 * Check how many bytes are required to encode a message of type path_ctrl_t
127 */
128int path_ctrl_t_encoded_size(const path_ctrl_t *p);
129
130// LCM support functions. Users should not call these
131int64_t __path_ctrl_t_get_hash(void);
132uint64_t __path_ctrl_t_hash_recursive(const __lcm_hash_ptr *p);
133int __path_ctrl_t_encode_array(void *buf, int offset, int maxlen, const path_ctrl_t *p, int elements);
134int __path_ctrl_t_decode_array(const void *buf, int offset, int maxlen, path_ctrl_t *p, int elements);
135int __path_ctrl_t_decode_array_cleanup(path_ctrl_t *p, int elements);
136int __path_ctrl_t_encoded_array_size(const path_ctrl_t *p, int elements);
137int __path_ctrl_t_clone_array(const path_ctrl_t *p, path_ctrl_t *q, int elements);
138
139#ifdef __cplusplus
140}
141#endif
142
143#endif
diff --git a/serial.c b/serial.c
index 43506ec..6251675 100644
--- a/serial.c
+++ b/serial.c
@@ -1,50 +1,46 @@
1/* 1#include "path/path_ctrl_t.h"
2 * 在OpenHarmony系统下开发串口通信的应用与在Linux系统中类似,
3 * 但需要确保你的设备支持串口操作,并且有适当的驱动支持。
4 *
5 * 以下是一个用C++编写的示例,展示如何在OpenHarmony中打开串口,
6 * 设置波特率为115200,并发送指定的16进制数。
7 * - 打开串口:使用open()函数打开指定的串口设备。
8 * - 配置串口:使用termios结构体配置串口参数如波特率、字符大小、奇偶校验等。
9 * - 发送数据:使用write()函数将数据写入串口。
10 * - 关闭串口:操作完成后,使用close()函数关闭串口。
11 * 确保你的OpenHarmony设备有对应的串口设备文件/dev/ttyS1,
12 * 并且你的应用有足够的权限来访问这个设备。根据你的硬件和操作系统配置,设备文件的路径可能不同。
13 */
14
15#include <arpa/inet.h>
16#include <errno.h> 2#include <errno.h>
17#include <fcntl.h> 3#include <fcntl.h>
18#include <netinet/in.h>
19#include <poll.h>
20#include <pthread.h>
21#include <stdbool.h> 4#include <stdbool.h>
22#include <stdio.h> 5#include <stdio.h>
23#include <stdlib.h> 6#include <stdlib.h>
24#include <string.h> 7#include <string.h>
25#include <sys/socket.h>
26#include <termios.h> 8#include <termios.h>
27#include <unistd.h> 9#include <unistd.h>
28 10
29#define FULL_SPEED 1.0f // 全速前进的速度
30#define R 0.15f // 轮距的一半
31
32typedef unsigned char byte; 11typedef unsigned char byte;
33int fd; 12#define MAX_BUFFER_SIZE 1024
34int port = 5001; 13
14int fd; // 轮子的串口文件描述符
35char portname[50] = "/dev/ttyUSB0"; // 串口设备名 15char portname[50] = "/dev/ttyUSB0"; // 串口设备名
36char clientIP[20] = ""; 16char clientIP[20] = "";
37
38struct termios tty; 17struct termios tty;
39pthread_t udpSend, udpRecv;
40const int MAX_BUFFER_SIZE = 1024;
41struct sockaddr_in clientAddr;
42 18
43int whellInit() { 19bool whellInit();
20bool wheelSend(byte a, byte a_v, byte b, byte b_v);
21void speedControl(byte status, byte speed);
22void parseCmd(const path_ctrl_t *msg, void *user);
23
24int main() {
25 if (!whellInit()) {
26 goto err;
27 }
28 lcm *path_lcm = lcm_create(NULL);
29 if (!path_lcm) {
30 fprintf(stderr, "Failed to create LCM\n");
31 goto err;
32 }
33 path_ctrl_t_subscribe(path_lcm, "PATH_CTRL", parseCmd);
34
35err:
36 close(fd);
37 return 0;
38}
39
40bool whellInit() {
44 // 打开串口 41 // 打开串口
45 fd = open(portname, O_RDWR | O_NOCTTY | O_SYNC); 42 fd = open(portname, O_RDWR | O_NOCTTY | O_SYNC);
46 if (fd < 0) { 43 if (fd < 0) {
47 // C语言报error
48 fprintf(stderr, "Error opening %s: %s\n", portname, strerror(errno)); 44 fprintf(stderr, "Error opening %s: %s\n", portname, strerror(errno));
49 return false; 45 return false;
50 } 46 }
@@ -52,7 +48,6 @@ int whellInit() {
52 // 设置串口参数 48 // 设置串口参数
53 memset(&tty, 0, sizeof tty); 49 memset(&tty, 0, sizeof tty);
54 if (tcgetattr(fd, &tty) != 0) { 50 if (tcgetattr(fd, &tty) != 0) {
55 // cerr << "Error from tcgetattr: " << strerror(errno) << endl;
56 fprintf(stderr, "Error from tcgetattr: %s\n", strerror(errno)); 51 fprintf(stderr, "Error from tcgetattr: %s\n", strerror(errno));
57 return false; 52 return false;
58 } 53 }
@@ -77,7 +72,6 @@ int whellInit() {
77 tty.c_cflag &= ~CRTSCTS; 72 tty.c_cflag &= ~CRTSCTS;
78 73
79 if (tcsetattr(fd, TCSANOW, &tty) != 0) { 74 if (tcsetattr(fd, TCSANOW, &tty) != 0) {
80 // cerr << "Error from tcsetattr: " << strerror(errno) << endl;
81 fprintf(stderr, "Error from tcsetattr: %s\n", strerror(errno)); 75 fprintf(stderr, "Error from tcsetattr: %s\n", strerror(errno));
82 return false; 76 return false;
83 } 77 }
@@ -108,7 +102,8 @@ bool wheelSend(byte a, byte a_v, byte b, byte b_v) {
108 return true; 102 return true;
109} 103}
110 104
111void speedControl(byte status, byte speed) { 105void parseCmd(const path_ctrl_t *msg, void *user) {
106 byte status = msg->cmd, speed = msg->speed;
112 switch (status) { 107 switch (status) {
113 case 1: 108 case 1:
114 wheelSend(0x01, speed, 0x01, speed); 109 wheelSend(0x01, speed, 0x01, speed);
@@ -124,137 +119,4 @@ void speedControl(byte status, byte speed) {
124 wheelSend(0x00, 0x00, 0x00, 0x00); 119 wheelSend(0x00, 0x00, 0x00, 0x00);
125 break; 120 break;
126 } 121 }
127} 122} \ No newline at end of file
128
129void udpSendThread() {
130 // 创建UDP套接字
131 int sockfd = -1;
132 struct sockaddr_in serverAddr;
133 if ((sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) {
134 fprintf(stderr, "Error: Failed to create socket\n");
135 return;
136 }
137
138 memset((char *)&serverAddr, 0, sizeof(serverAddr));
139 serverAddr.sin_family = AF_INET; // 设置地址族为IPv4
140 serverAddr.sin_port = htons(port); // 设置端口号
141 if (inet_aton(clientIP, &serverAddr.sin_addr) == 0) {
142 fprintf(stderr, "Error: Failed to convert IP address\n");
143 close(sockfd);
144 return;
145 }
146 while (true) {
147 // 每秒向socket发送一次0x30
148 byte a = 0x39;
149 // 发送消息
150 sendto(sockfd, (const char *)&a, 1, 0, (struct sockaddr *)&serverAddr,
151 sizeof(serverAddr));
152 printf("Send: Data %02X udpSend successfully!\n", a);
153 sleep(1);
154 }
155}
156
157void udpRecvThread() {
158 int socketfd = -1;
159 char buffer[MAX_BUFFER_SIZE];
160 struct sockaddr_in serverAddr;
161 socklen_t addrLen = sizeof(serverAddr);
162 int bytesReceived;
163
164 // fd_set readfds;
165 // struct timeval tv;
166 int retval;
167 struct pollfd fds;
168
169 if ((socketfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) {
170 fprintf(stderr, "Error: Failed to create socket\n");
171 return;
172 }
173 memset((char *)&serverAddr, 0, sizeof(serverAddr));
174 memset(buffer, 0, sizeof(buffer));
175 serverAddr.sin_family = AF_INET;
176 serverAddr.sin_port = htons(port);
177 serverAddr.sin_addr.s_addr = htonl(INADDR_ANY);
178
179 if (bind(socketfd, (struct sockaddr *)&serverAddr, sizeof(serverAddr)) ==
180 -1) {
181 // cerr << "Error: Bind failed" << endl;
182 fprintf(stderr, "Error: Bind failed\n");
183 close(socketfd);
184 return;
185 }
186
187 bytesReceived = recvfrom(socketfd, buffer, MAX_BUFFER_SIZE, 0,
188 (struct sockaddr *)&clientAddr, &addrLen);
189 if (bytesReceived == -1) {
190 fprintf(stderr, "Error: Failed to receive data\n");
191 close(socketfd);
192 return;
193 }
194 printf("Received start message from %s: %s\n",
195 inet_ntoa(clientAddr.sin_addr), buffer);
196 strcpy(clientIP, inet_ntoa(clientAddr.sin_addr));
197
198 if (pthread_create(&udpSend, NULL, udpSendThread, NULL) != 0) {
199 fprintf(stderr, "Error creating udpSend thread\n");
200 close(socketfd);
201 return;
202 }
203
204 fds.fd = socketfd;
205 fds.events = POLLIN;
206
207 while (true) {
208 // /* Watch sock to see when it has input. */
209 // FD_ZERO(&readfds);
210 // FD_SET(socketfd, &readfds);
211 // /* Wait up to three seconds. */
212 // tv.tv_sec = 3;
213 // tv.tv_usec = 0;
214
215 // retval = select(socketfd + 1, &readfds, NULL, NULL, &tv);
216 retval = poll(&fds, 1, 3000);
217 if (retval == -1) {
218 fprintf(stderr, "Error: select failed\n");
219 break;
220 } else if (retval == 0) {
221 printf("No data within three seconds.\n");
222 speedControl(0, 0);
223 // break;
224 } else {
225 bytesReceived = recvfrom(socketfd, buffer, MAX_BUFFER_SIZE, 0,
226 (struct sockaddr *)&clientAddr, &addrLen);
227 if (bytesReceived == -1) {
228 fprintf(stderr, "Error: Failed to receive data\n");
229 continue;
230 }
231 printf("Received Message from %s: %2x %2x\n",
232 inet_ntoa(clientAddr.sin_addr), buffer[0], buffer[1]);
233 speedControl(buffer[0], buffer[1]);
234 }
235 }
236}
237
238int main() {
239 // 关闭1号和2号文件描述符
240 // close(1);
241 // close(2);
242 // // 打开serial.log文件,并将其复制到1号和2号文件描述符
243 // open("serial.log", O_RDWR | O_CREAT, 0666);
244 // dup(1);
245 // dup(2);
246
247 if (!whellInit()) {
248 goto err;
249 }
250
251 if (pthread_create(&udpRecv, NULL, udpRecvThread, NULL) != 0) {
252 fprintf(stderr, "Error creating udpRecv thread\n");
253 goto err;
254 }
255 pthread_join(udpRecv, NULL);
256
257err:
258 close(fd);
259 return 0;
260}
diff --git a/server.cpp b/server.cpp
deleted file mode 100644
index 5e41eb8..0000000
--- a/server.cpp
+++ /dev/null
@@ -1,167 +0,0 @@
1#include <arpa/inet.h>
2#include <chrono>
3#include <cmath>
4#include <condition_variable>
5#include <cstring>
6#include <iostream>
7#include <mutex>
8#include <netinet/in.h>
9#include <sstream>
10#include <string.h>
11#include <string>
12#include <sys/socket.h>
13#include <thread>
14#include <unistd.h>
15
16using namespace std;
17
18enum robotState { // 机器人状态枚举
19 beforeStart,
20 pending,
21 afterEnd, // 建好了图,接下来可选择重新建图或选终点开始路径
22 startRoute,
23};
24
25enum runState { stop, go, left, right };
26
27struct ReceiveDataStruct {
28 int robotId;
29 robotState state;
30 int x;
31 int y;
32 int r;
33};
34
35const int PORT = 5001;
36const char *SERVER_IP = "0.0.0.0";
37const int MAX_BUFFER_SIZE = 1024;
38
39struct ReceiveData {
40 int values[4];
41};
42
43bool newDataAvailable = false;
44string CLIENT_IP = "127.0.0.1";
45struct sockaddr_in clientAddr;
46ReceiveData receivedData = {{0, 1, 2, 3}};
47
48// UDP发送线程函数
49void udpSenderThread() {
50 char values[100] = {0};
51 struct sockaddr_in serverAddr;
52 int sockfd = -1;
53
54 // 创建UDP套接字
55 if ((sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) {
56 fprintf(stderr, "Error: Failed to create socket\n");
57 return;
58 }
59
60 memset((char *)&serverAddr, 0, sizeof(serverAddr));
61 serverAddr.sin_family = AF_INET;
62 serverAddr.sin_port = htons(PORT);
63 if (inet_aton(CLIENT_IP.c_str(), &serverAddr.sin_addr) == 0) {
64 fprintf(stderr, "Error: Failed to convert IP address\n");
65 close(sockfd);
66 return;
67 }
68
69 while (true) {
70 this_thread::sleep_for(chrono::seconds(1)); // 每1秒发送一次
71
72 // 更新发送的消息
73 memset(values, 0, 100);
74 for (int i = 0; i < 4; ++i) {
75 // values[i] = receivedData.values[i] + 1;
76 sprintf(values + strlen(values), "%d ", receivedData.values[i] + 1);
77 }
78 sprintf(values + strlen(values), "\n");
79 printf("Sending message to %s: %s\n", CLIENT_IP.c_str(), values);
80
81 // 发送消息
82 sendto(sockfd, (const char *)values, sizeof(int) * 4, 0,
83 (struct sockaddr *)&serverAddr, sizeof(serverAddr));
84 }
85
86 close(sockfd);
87}
88
89// 主线程接收UDP消息并打印
90void receiveAndPrintMessages() {
91 int sock;
92 struct sockaddr_in serverAddr;
93 socklen_t addrLen = sizeof(clientAddr);
94 char buffer[MAX_BUFFER_SIZE];
95 ReceiveData receivedData;
96 int pos, bytesReceived;
97
98 // 创建UDP套接字
99 if ((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) {
100 fprintf(stderr, "Error: Failed to create socket\n");
101 return;
102 }
103
104 memset((char *)&serverAddr, 0, sizeof(serverAddr));
105 memset(buffer, 0, sizeof(buffer));
106 serverAddr.sin_family = AF_INET;
107 serverAddr.sin_port = htons(PORT);
108 serverAddr.sin_addr.s_addr = htonl(INADDR_ANY);
109
110 // 绑定到端口
111 if (::bind(sock, (struct sockaddr *)&serverAddr, sizeof(serverAddr)) ==
112 -1) {
113 cerr << "Error: Bind failed" << endl;
114 close(sock);
115 return;
116 }
117
118 bytesReceived = recvfrom(sock, buffer, MAX_BUFFER_SIZE, 0,
119 (struct sockaddr *)&clientAddr, &addrLen);
120 if (bytesReceived == -1) {
121 fprintf(stderr, "Error: Failed to receive data\n");
122 return;
123 }
124 printf("Received Message from %s: %s\n", inet_ntoa(clientAddr.sin_addr),
125 buffer);
126 CLIENT_IP = inet_ntoa(clientAddr.sin_addr);
127 thread senderThread2(udpSenderThread);
128 while (true) {
129 // 接收消息
130 bytesReceived = recvfrom(sock, buffer, MAX_BUFFER_SIZE, 0,
131 (struct sockaddr *)&clientAddr, &addrLen);
132 if (bytesReceived == -1) {
133 fprintf(stderr, "Error: Failed to receive data\n");
134 continue;
135 }
136
137 printf("Receive %d bytes from %s: \"%s\"\n", bytesReceived,
138 CLIENT_IP.c_str(), buffer);
139 pos = 0;
140 for (int i = 0; i < 4; ++i) {
141 receivedData.values[i] = atoi(strtok(buffer + pos, " "));
142 // pos += log10(receivedData.values[i]) + 2;
143 // pos需要递增,否则会一直解析第一个数,要求能处理数据为0或负数的情况
144 pos += strlen(strtok(buffer + pos, " ")) + 1;
145 }
146 newDataAvailable = true;
147
148 // 打印消息
149 // CLIENT_IP = inet_ntoa(clientAddr.sin_addr);
150 // cout << "Received Message from " << CLIENT_IP << ": ";
151 // printf("Received Message from %s: ", CLIENT_IP.c_str());
152 // for (int i = 0; i < 4; ++i) {
153 // printf("%d ", receivedData.values[i]);
154 // }
155 printf("\n");
156 }
157
158 close(sock);
159 senderThread2.join();
160}
161
162int main() {
163 thread receiverThread(receiveAndPrintMessages);
164 receiverThread.join();
165
166 return 0;
167}
diff --git a/testClient.c b/testClient.c
deleted file mode 100644
index bbd2529..0000000
--- a/testClient.c
+++ /dev/null
@@ -1,97 +0,0 @@
1// 编写一段C程序,使用pthread创建两个线程
2// 发送线程将数据发送到127.0.0.1的5001端口,每0.5s一次
3// 接收线程接收127.0.0.1的5001端口的数据并打印
4
5#include <arpa/inet.h>
6#include <errno.h>
7#include <fcntl.h>
8#include <netinet/in.h>
9#include <pthread.h>
10#include <stdbool.h>
11#include <stdio.h>
12#include <stdlib.h>
13#include <string.h>
14#include <sys/socket.h>
15#include <termios.h>
16#include <unistd.h>
17
18pthread_t udpSend, udpRecv;
19pthread_mutex_t mutex;
20int port = 5001;
21char clientIP[20] = "127.0.0.1";
22
23void udpSenderThread() {
24 struct sockaddr_in serverAddr;
25 int sockfd = -1;
26
27 // 创建UDP套接字
28 if ((sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) {
29 fprintf(stderr, "Error: Failed to create socket\n");
30 return;
31 }
32
33 memset((char *)&serverAddr, 0, sizeof(serverAddr));
34 serverAddr.sin_family = AF_INET;
35 serverAddr.sin_port = htons(port);
36 serverAddr.sin_addr.s_addr = inet_addr(clientIP);
37
38 while (1) {
39 char values[100] = {0};
40 // strcpy(values, "Hello, world!");
41 pthread_mutex_lock(&mutex);
42 printf("Input the data you want to send: ");
43 scanf("%s", values);
44 pthread_mutex_unlock(&mutex);
45 sendto(sockfd, values, strlen(values), 0,
46 (struct sockaddr *)&serverAddr, sizeof(serverAddr));
47 // printf("Send: %s\n", values);
48 sleep(1);
49 }
50}
51
52void udpReceiverThread() {
53 int sockfd = -1;
54 struct sockaddr_in serverAddr;
55 struct sockaddr_in clientAddr;
56 socklen_t clientAddrLen = sizeof(clientAddr);
57 char buffer[1024] = {0};
58
59 // 创建UDP套接字
60 if ((sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) {
61 fprintf(stderr, "Error: Failed to create socket\n");
62 return;
63 }
64
65 memset((char *)&serverAddr, 0, sizeof(serverAddr));
66 serverAddr.sin_family = AF_INET;
67 serverAddr.sin_port = htons(port - 1);
68 serverAddr.sin_addr.s_addr = htonl(INADDR_ANY);
69
70 if (bind(sockfd, (struct sockaddr *)&serverAddr, sizeof(serverAddr)) ==
71 -1) {
72 fprintf(stderr, "Error: Failed to bind socket\n");
73 close(sockfd);
74 return;
75 }
76
77 while (1) {
78 pthread_mutex_lock(&mutex);
79 int len = recvfrom(sockfd, buffer, 1024, 0,
80 (struct sockaddr *)&clientAddr, &clientAddrLen);
81 pthread_mutex_unlock(&mutex);
82 if (len == -1) {
83 fprintf(stderr, "Error: Failed to receive data\n");
84 close(sockfd);
85 return;
86 }
87 buffer[len] = '\0';
88 printf("Received: %s\n", buffer);
89 }
90}
91
92int main() {
93 pthread_create(&udpSend, NULL, udpSenderThread, NULL);
94 // pthread_create(&udpRecv, NULL, udpReceiverThread, NULL);
95 pthread_join(udpSend, NULL);
96 // pthread_join(udpRecv, NULL);
97} \ No newline at end of file
diff --git a/udp2lcm.c b/udp2lcm.c
new file mode 100644
index 0000000..ec8aee8
--- /dev/null
+++ b/udp2lcm.c
@@ -0,0 +1,184 @@
1// Encoded in UTF-8
2
3/*
4 * struct path_ctrl_t
5 * {
6 * int8_t cmd;
7 * int8_t speed;
8 * }
9 * 这是与轮控模块通信的数据结构,speed为0-100表示速度
10 * cmd为0停,1前,2左,3右
11 */
12#include "path/path_ctrl_t.h"
13#include <stdio.h>
14#include <stdlib.h>
15#include <string.h>
16
17#define MAX_BUFFER_SIZE 1024
18#define PORT 5001
19
20pthread_t udpRecv, udpSend;
21int8_t heartBeat[9] = {0}; // 用于存储需要发送的心跳信息
22// clientIP用于存储手机端IP地址,仅在第一次接收消息后修改
23// 本身就是inet_ntoa(clientAddr.sin_addr),二者内容完全一致
24struct sockaddr_in clientAddr;
25char clientIP[20] = "";
26lcm_t *path_ctrl_lcm;
27
28bool LCMInit();
29void udpSendHandler();
30void udpRecvHandler();
31void parseCmd(const char *buffer, int bytesReceived);
32
33int main() {
34 if (!LCMInit()) {
35 fprintf(stderr, "Error: Failed to initialize LCM\n");
36 return -1;
37 }
38 // 开启udp接收线程
39 pthread_create(&udpRecv, NULL, udpRecvHandler, NULL);
40 return 0;
41}
42
43bool LCMInit() {
44 // TODO: 在这里同意初始化各个LCM变量
45 // ATTENTION:
46 // 是否在这里订阅各个通道、各个通道需要在什么地方订阅,需要慎重考虑
47 if ((path_ctrl_lcm = lcm_create(NULL)) == NULL) {
48 fprintf(stderr, "Error: Failed to create Path Ctrl LCM\n");
49 return false;
50 }
51
52 return true;
53}
54
55void udpRecvHandler() {
56 int socketfd = -1;
57 char buffer[MAX_BUFFER_SIZE];
58 struct sockaddr_in serverAddr;
59 socklen_t addrLen = sizeof(serverAddr);
60 int bytesReceived;
61
62 int retval;
63 struct pollfd fds;
64
65 if ((socketfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) {
66 fprintf(stderr, "Error: Failed to create socket\n");
67 return;
68 }
69 memset((char *)&serverAddr, 0, sizeof(serverAddr));
70 memset(buffer, 0, sizeof(buffer));
71 serverAddr.sin_family = AF_INET;
72 serverAddr.sin_port = htons(port);
73 serverAddr.sin_addr.s_addr = htonl(INADDR_ANY);
74
75 if (bind(socketfd, (struct sockaddr *)&serverAddr, sizeof(serverAddr)) ==
76 -1) {
77 fprintf(stderr, "Error: Bind failed\n");
78 close(socketfd);
79 return;
80 }
81
82 bytesReceived = recvfrom(socketfd, buffer, MAX_BUFFER_SIZE, 0,
83 (struct sockaddr *)&clientAddr, &addrLen);
84 if (bytesReceived == -1) {
85 fprintf(stderr, "Error: Failed to receive data\n");
86 close(socketfd);
87 return;
88 }
89 printf("Start message from %s: %s\n", inet_ntoa(clientAddr.sin_addr),
90 buffer);
91 strcpy(clientIP, inet_ntoa(clientAddr.sin_addr));
92
93 // 在接收到第一条消息之后,开启udp发送线程,用于发送心跳信息
94 if (pthread_create(&udpSend, NULL, udpSendHandler, NULL) != 0) {
95 fprintf(stderr, "Error creating udpSend thread\n");
96 close(socketfd);
97 exit(-1);
98 }
99
100 fds.fd = socketfd;
101 fds.events = POLLIN;
102
103 while (true) {
104 retval = poll(&fds, 1, 3000);
105 if (retval == -1) {
106 fprintf(stderr, "Error: select failed\n");
107 break;
108 } else if (retval == 0) {
109 printf("No data within three seconds.\n");
110 speedControl(0, 0);
111 } else {
112 bytesReceived = recvfrom(socketfd, buffer, MAX_BUFFER_SIZE, 0,
113 (struct sockaddr *)&clientAddr, &addrLen);
114 if (bytesReceived == -1) {
115 fprintf(stderr, "Error: Failed to receive data\n");
116 continue;
117 }
118 printf("Massage from client %s: ", clientIP);
119 for (int i = 0; i < bytesReceived; i++) {
120 printf("%02x ", buffer[i]);
121 }
122 printf("\n");
123 parseCmd(buffer, bytesReceived);
124 }
125 }
126}
127
128void udpSendHandler() {
129 // 创建UDP套接字
130 int sockfd = -1;
131 struct sockaddr_in serverAddr;
132 if ((sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) {
133 fprintf(stderr, "Error: Failed to create socket\n");
134 return;
135 }
136
137 memset((char *)&serverAddr, 0, sizeof(serverAddr));
138 serverAddr.sin_family = AF_INET; // 设置地址族为IPv4
139 serverAddr.sin_port = htons(port); // 设置端口号
140 if (inet_aton(clientIP, &serverAddr.sin_addr) == 0) {
141 fprintf(stderr, "Error: Failed to convert IP address\n");
142 close(sockfd);
143 return;
144 }
145
146 while (true) {
147 sendto(sockfd, (const char *)heartBeat, 9, 0,
148 (struct sockaddr *)&serverAddr, sizeof(serverAddr));
149 printf("Send: Data %02x udpSend successfully!\n", a);
150 sleep(1);
151 }
152}
153
154void parseCmd(const char *buffer, int bytesReceived) {
155 // TODO: 完成本函数的内容
156 if (buffer == NULL || strlen(buffer) != 9) {
157 fprintf(stderr, "Error: Invalid message\n");
158 return;
159 }
160
161 if (buffer[0] == 0) {
162 // 手机端用来与udp2lcm服务器建立连接的初始化消息
163 fprintf(stderr, "Why Init cmd here?\n");
164 } else if (buffer[0] == 1) {
165 // 建图过程中,手机端遥控小车进行移动,命令下发至轮控模块
166 path_ctrl_t path;
167 path.cmd = buffer[1];
168 path.speed = buffer[2];
169 path_ctrl_t_publish(path_ctrl_lcm, "wheel_ctrl", &path);
170 } else if (buffer[0] == 2) {
171 /*
172 * 结束建图,主要有以下几个任务:
173 * - 向轮控模块发送停止命令
174 * - 通知算法模块结束建图(FIXME: 是否接受算法模块的回应?)
175 * - 拉起http服务器进程
176 * - 向手机端通知建图完成
177 * -
178 * 开始通过lcm接受算法给出的实时坐标,存储至heartBeat数组中(对应格式)
179 */
180 } else if (buffer[0] == 3) {
181 // 手机发来的终点坐标,转发给算法模块
182 ;
183 }
184} \ No newline at end of file