Skip to content

Commit e9d54b0

Browse files
committed
add caching and fix start memset
1 parent 9cb97d9 commit e9d54b0

File tree

4 files changed

+158
-57
lines changed

4 files changed

+158
-57
lines changed

msp.c

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,19 @@
33
#include <stdio.h>
44
#include "msp.h"
55

6-
msp_error_e construct_msp_command(uint8_t message_buffer[], uint8_t command, uint8_t payload[], uint8_t size) {
6+
void msp_data_from_msg(uint8_t message_buffer[], msp_msg_t *msg) {
7+
construct_msp_command(message_buffer, msg->cmd, msg->payload, msg->size, msg->direction);
8+
}
9+
10+
msp_error_e construct_msp_command(uint8_t message_buffer[], uint8_t command, uint8_t payload[], uint8_t size, msp_direction_e direction) {
711
uint8_t checksum;
812
message_buffer[0] = '$'; // Header
913
message_buffer[1] = 'M'; // MSP V1
10-
message_buffer[2] = '<'; // Command Direction
14+
if (direction == MSP_OUTBOUND) {
15+
message_buffer[2] = '<';
16+
} else {
17+
message_buffer[2] = '>';
18+
}
1119
message_buffer[3] = size; // Payload Size
1220
checksum = size;
1321
message_buffer[4] = command; // Command

msp.h

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,16 @@
11
#include <stdint.h>
22

3+
#define MSP_CMD_FC_VERSION 3
4+
#define MSP_CMD_NAME 10
5+
#define MSP_CMD_FILTER_CONFIG 92
6+
#define MSP_CMD_PID_ADVANCED 94
37
#define MSP_CMD_STATUS 101
8+
#define MSP_CMD_RC 105
9+
#define MSP_CMD_ANALOG 110
10+
#define MSP_CMD_RC_TUNING 111
11+
#define MSP_CMD_PID 112
412
#define MSP_CMD_BATTERY_STATE 130
13+
#define MSP_CMD_STATUS_EX 150
514
#define MSP_CMD_DISPLAYPORT 182
615

716
typedef enum {
@@ -42,5 +51,6 @@ typedef struct msp_state_s {
4251
msp_msg_t message;
4352
} msp_state_t;
4453

45-
msp_error_e construct_msp_command(uint8_t message_buffer[], uint8_t command, uint8_t payload[], uint8_t size);
54+
uint16_t msp_data_from_msg(uint8_t message_buffer[], msp_msg_t *msg);
55+
msp_error_e construct_msp_command(uint8_t message_buffer[], uint8_t command, uint8_t payload[], uint8_t size, msp_direction_e direction);
4656
msp_error_e msp_process_data(msp_state_t *msp_state, uint8_t dat);

msp_displayport_mux.c

Lines changed: 135 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -17,51 +17,132 @@
1717
#define DEBUG_PRINT(fmt, args...)
1818
#endif
1919

20-
uint8_t frame_buffer[4196]; // buffer a whole frame of MSP commands until we get a draw command
21-
uint8_t message_buffer[256]; // only needs to be the maximum size of an MSP packet, we only care to fwd MSP
22-
uint8_t cursor = 0;
23-
uint32_t fb_cursor = 0;
20+
typedef struct msp_cache_entry_s {
21+
struct timespec time;
22+
msp_msg_t message;
23+
} msp_cache_entry_t;
24+
25+
static msp_cache_entry_t *msp_message_cache[256]; // make a slot for all possible messages
26+
27+
static uint8_t frame_buffer[4196]; // buffer a whole frame of MSP commands until we get a draw command
28+
static uint32_t fb_cursor = 0;
29+
30+
static uint8_t rx_message_buffer[256]; // only needs to be the maximum size of an MSP packet, we only care to fwd MSP
31+
static uint8_t rx_cursor = 0;
32+
33+
static uint8_t tx_message_buffer[256];
34+
static uint8_t tx_cursor = 0;
2435

2536
int pty_fd;
2637
int serial_fd;
2738
int socket_fd;
2839

2940
static volatile sig_atomic_t quit = 0;
41+
static uint8_t serial_passthrough = 1;
3042

3143
static void sig_handler(int _)
3244
{
3345
quit = 1;
3446
}
3547

36-
static void msp_callback(msp_msg_t *msp_message)
37-
{
38-
DEBUG_PRINT("MSP cmd %d with data len %d \n", msp_message->cmd, msp_message->size);
48+
static uint8_t cache_msp_message(msp_msg_t *msp_message) {
49+
// 0 -> cache overwritten
50+
// 1 -> freshly cached
51+
uint8_t retval = 0;
52+
msp_cache_entry_t *cache_message = msp_message_cache[msp_message->cmd];
53+
if (cache_message == NULL) {
54+
DEBUG_PRINT("no entry for msg %d, allocating\n", msp_message->cmd);
55+
cache_message = calloc(1, sizeof(msp_cache_entry_t));
56+
msp_message_cache[msp_message->cmd] = cache_message;
57+
retval = 1;
58+
}
59+
memcpy(&cache_message->message, msp_message, sizeof(msp_message));
60+
clock_gettime(CLOCK_MONOTONIC, &cache_message->time);
61+
return retval;
62+
}
3963

40-
// Process a received MSP message and decide whether to send it to the PTY (DJI) or UDP port (MSP-OSD on Goggles)
64+
static int16_t msp_msg_from_cache(uint8_t msg_buffer[], uint8_t cmd_id) {
65+
// returns size of message or -1
66+
msp_cache_entry_t *cache_message = msp_message_cache[cmd_id];
67+
if (cache_message == NULL) {
68+
// cache missed, return -1 to trigger a serial send
69+
return -1;
70+
} else {
71+
// cache hit, let's see if it's too old
72+
// messages we care to expire after second boundary
73+
if(cmd_id == MSP_CMD_ANALOG
74+
|| cmd_id == MSP_CMD_STATUS
75+
|| cmd_id == MSP_CMD_BATTERY_STATE) {
76+
struct timespec now;
77+
clock_gettime(CLOCK_MONOTONIC, &now);
78+
if(now.tv_sec > cache_message->time.tv_sec) {
79+
// message is too old, invalidate cache and force a resend
80+
free(cache_message);
81+
msp_message_cache[cmd_id] = 0;
82+
return -1;
83+
}
84+
}
85+
return msp_data_from_msg(msg_buffer, &cache_message->message);
86+
}
87+
}
88+
89+
static void rx_msp_callback(msp_msg_t *msp_message)
90+
{
91+
// Process a received MSP message from FC and decide whether to send it to the PTY (DJI) or UDP port (MSP-OSD on Goggles)
92+
DEBUG_PRINT("FC->AU MSP msg %d with data len %d \n", msp_message->cmd, msp_message->size);
4193
if(msp_message->cmd == MSP_CMD_DISPLAYPORT) {
94+
// This was an MSP DisplayPort message, so buffer it until we get a whole frame.
4295
if(fb_cursor > sizeof(frame_buffer)) {
4396
printf("Exhausted frame buffer!\n");
4497
}
45-
memcpy(&frame_buffer[fb_cursor], message_buffer, cursor);
46-
fb_cursor += cursor;
47-
cursor = 0;
48-
if(msp_message->payload[0] == 4) { // Draw command
98+
memcpy(&frame_buffer[fb_cursor], rx_message_buffer, rx_cursor);
99+
fb_cursor += rx_cursor;
100+
rx_cursor = 0;
101+
if(msp_message->payload[0] == 4) {
102+
// Once we have a whole frame of data, send it to the goggles.
49103
write(socket_fd, frame_buffer, fb_cursor);
50104
DEBUG_PRINT("DRAW! wrote %d bytes\n", fb_cursor);
51105
fb_cursor = 0;
52106
}
53107
} else {
54-
write(pty_fd, message_buffer, cursor);
55-
cursor = 0;
108+
// This isn't an MSP DisplayPort message, so send it to either DJI directly or to the cache.
109+
if(serial_passthrough) {
110+
// Serial passthrough is on, so send it straight to DJI.
111+
write(pty_fd, rx_message_buffer, rx_cursor);
112+
} else {
113+
// Serial passthrough is off, so cache the response we got.
114+
if(cache_msp_message(msp_message)) {
115+
// 1 -> cache miss, so this message expired or hasn't been seen. this means DJI is waiting for it, so send it over
116+
write(pty_fd, rx_message_buffer, rx_cursor);
117+
}
118+
}
119+
rx_cursor = 0;
120+
}
121+
}
122+
123+
static void tx_msp_callback(msp_msg_t *msp_message)
124+
{
125+
// We got a valid message from DJI asking for something. See if there's a response in the cache or not.
126+
// We can only get here if serial passthrough is off and caching is on, so no need to check again.
127+
DEBUG_PRINT("DJI->FC MSP msg %d with data len %d \n", msp_message->cmd, msp_message->size);
128+
uint8_t send_buffer[256];
129+
uint16_t size;
130+
if(0 < (size = msp_msg_from_cache(send_buffer, msp_message->cmd))) {
131+
// cache hit, so write the cached message straight back to DJI
132+
DEBUG_PRINT("DJI->FC MSP CACHE HIT %d with data len %d \n", msp_message->cmd, size);
133+
write(pty_fd, send_buffer, size);
134+
} else {
135+
// cache miss, so write the DJI request to serial and wait for the FC to come back.
136+
DEBUG_PRINT("DJI->FC MSP CACHE MISS %d\n",msp_message->cmd);
137+
write(serial_fd, tx_message_buffer, tx_cursor);
56138
}
139+
tx_cursor = 0;
57140
}
58141

59142
int main(int argc, char *argv[]) {
60143
int opt;
61144
uint8_t fast_serial = 0;
62-
uint8_t serial_passthrough = 1;
63-
uint8_t poll_manually = 0;
64-
uint8_t msg_flip = 0;
145+
uint8_t msp_command_number = 0;
65146
while((opt = getopt(argc, argv, "fsp")) != -1){
66147
switch(opt){
67148
case 'f':
@@ -70,11 +151,7 @@ int main(int argc, char *argv[]) {
70151
break;
71152
case 's':
72153
serial_passthrough = 0;
73-
printf("Disabling serial passthrough, enabling filtering\n");
74-
break;
75-
case 'p':
76-
poll_manually = 1;
77-
printf("Enabling manual MSP polling every 500ms\n");
154+
printf("Disabling serial passthrough, enabling caching\n");
78155
break;
79156
case '?':
80157
printf("unknown option: %c\n", optopt);
@@ -83,7 +160,7 @@ int main(int argc, char *argv[]) {
83160
}
84161

85162
if((argc - optind) < 2) {
86-
printf("usage: msp_displayport_mux [-f] [-s] [-p] ipaddr serial_port [pty_target]\n-s : enable serial filtering\n-f : 230400 baud serial\n-p: enable manual polling\n");
163+
printf("usage: msp_displayport_mux [-f] [-s] [-p] ipaddr serial_port [pty_target]\n-s : enable serial caching\n-f : 230400 baud serial\n");
87164
return 0;
88165
}
89166

@@ -92,8 +169,10 @@ int main(int argc, char *argv[]) {
92169
signal(SIGINT, sig_handler);
93170
struct pollfd poll_fds[2];
94171
const char *pty_name_ptr;
95-
msp_state_t *msp_state = calloc(1, sizeof(msp_state_t));
96-
msp_state->cb = &msp_callback;
172+
msp_state_t *rx_msp_state = calloc(1, sizeof(msp_state_t));
173+
msp_state_t *tx_msp_state = calloc(1, sizeof(msp_state_t));
174+
rx_msp_state->cb = &rx_msp_callback;
175+
tx_msp_state->cb = &tx_msp_callback;
97176
serial_fd = open_serial_port(serial_port, fast_serial ? B230400 : B115200);
98177
if (serial_fd <= 0) {
99178
printf("Failed to open serial port!\n");
@@ -115,47 +194,49 @@ int main(int argc, char *argv[]) {
115194
poll_fds[1].fd = pty_fd;
116195
poll_fds[0].events = POLLIN;
117196
poll_fds[1].events = POLLIN;
197+
118198
poll(poll_fds, 2, 250);
119-
// We got serial data, process it as MSP data.
199+
// We got inbound serial data, process it as MSP data.
120200
if (0 < (serial_data_size = read(serial_fd, serial_data, sizeof(serial_data)))) {
121201
DEBUG_PRINT("RECEIVED data! length %d\n", serial_data_size);
122202
for (ssize_t i = 0; i < serial_data_size; i++) {
123-
if(msp_process_data(msp_state, serial_data[i]) == 0) {
124-
// 0 -> MSP data was valid, so buffer it to forward on later
125-
message_buffer[cursor] = serial_data[i];
126-
cursor++;
203+
if(msp_process_data(rx_msp_state, serial_data[i]) == 0) {
204+
// 0 -> MSP data was valid, so buffer it to forward on to either goggles or DJI later
205+
rx_message_buffer[rx_cursor] = serial_data[i];
206+
rx_cursor++;
127207
} else {
128-
cursor = 0;
208+
rx_cursor = 0;
129209
}
130210
}
131211
}
132-
133-
// If serial passthrough is enabled, send the message through verbatim.
134-
if(0 < (serial_data_size = read(pty_fd, serial_data, sizeof(serial_data))) && serial_passthrough) {
135-
DEBUG_PRINT("SEND data! length %d\n", serial_data_size);
136-
for (ssize_t i= 0; i < serial_data_size; i++) {
137-
DEBUG_PRINT("%02X ", serial_data[i]);
138-
}
139-
DEBUG_PRINT("\n");
140-
write(serial_fd, &serial_data, serial_data_size);
141-
}
142-
143-
// If manual MSP polling is enabled, poll only for a few messages: arming status and battery voltage
144-
clock_gettime(CLOCK_MONOTONIC, &now);
145-
if(poll_manually && (now.tv_sec > last.tv_sec || now.tv_nsec > (last.tv_nsec + 50000000000))) {
146-
construct_msp_command(&serial_data, msg_flip ? MSP_CMD_STATUS : MSP_CMD_BATTERY_STATE, 0, 0);
147-
msg_flip = !msg_flip;
148-
DEBUG_PRINT("Polling: ");
149-
for(ssize_t i = 0; i < 6; i++) {
150-
DEBUG_PRINT("%02X ", serial_data[i]);
212+
// We got data from DJI (the pty), so see what to do next:
213+
if(0 < (serial_data_size = read(pty_fd, serial_data, sizeof(serial_data)))) {
214+
if (serial_passthrough) {
215+
// If serial passthrough is enabled, send the message through verbatim.
216+
DEBUG_PRINT("SEND data! length %d\n", serial_data_size);
217+
for (ssize_t i= 0; i < serial_data_size; i++) {
218+
DEBUG_PRINT("%02X ", serial_data[i]);
219+
}
220+
DEBUG_PRINT("\n");
221+
write(serial_fd, &serial_data, serial_data_size);
222+
} else {
223+
// Otherwise, queue it up for processing by the MSP layer.
224+
DEBUG_PRINT("SEND data to MSP buffer! length %d\n", serial_data_size);
225+
for (ssize_t i = 0; i < serial_data_size; i++) {
226+
if(msp_process_data(tx_msp_state, serial_data[i]) == 0) {
227+
// 0 -> MSP data was valid, so buffer it to forward on later
228+
tx_message_buffer[tx_cursor] = serial_data[i];
229+
tx_cursor++;
230+
} else {
231+
tx_cursor = 0;
232+
}
233+
}
151234
}
152-
DEBUG_PRINT("\n");
153-
write(serial_fd, &serial_data, 6);
154235
}
155-
last = now;
156236
}
157237
close(serial_fd);
158238
close(pty_fd);
159239
close(socket_fd);
160-
free(msp_state);
240+
free(rx_msp_state);
241+
free(tx_msp_state);
161242
}

osd_dji_udp.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,8 @@ int main(int argc, char *argv[])
203203
socklen_t src_addr_len=sizeof(src_addr);
204204
struct input_event ev;
205205
struct timespec button_start, display_start, now;
206+
memset(&display_start, 0, sizeof(display_start));
207+
memset(&button_start, 0, sizeof(button_start));
206208

207209
enum display_mode_s {
208210
DISPLAY_DISABLED = 0,

0 commit comments

Comments
 (0)