Add files via upload

pull/431/head
JohhnGoblin 2025-01-05 01:07:26 -06:00 committed by GitHub
parent e4b72f32eb
commit 7232a5f062
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
21 changed files with 498 additions and 0 deletions

Binary file not shown.

View File

@ -0,0 +1,416 @@
#include <getopt.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdbool.h>
#include <termios.h>
#include <assert.h>
#include <event2/event.h>
#include <event2/util.h>
#include <event2/buffer.h>
#include <event2/bufferevent.h>
#define MAX_MTU 9000
bool verbose = false;
const char *default_master = "/dev/ttyAMA0";
const int default_baudrate = 115200;
const char *defualt_out_addr = "127.0.0.1:14600";
const char *default_in_addr = "127.0.0.1:14601";
uint8_t ch_count = 0;
uint16_t ch[14];
struct bufferevent *serial_bev;
struct sockaddr_in sin_out = {
.sin_family = AF_INET,
};
int out_sock;
static void print_usage()
{
printf("Usage: mavfwd [OPTIONS]\n"
"Where:\n"
" --master Local MAVLink master port (%s by default)\n"
" --baudrate Serial port baudrate (%d by default)\n"
" --out Remote output port (%s by default)\n"
" --in Remote input port (%s by default)\n"
" --channels RC override channels to parse after first 4 and call /root/channels.sh $ch $val, default 0\n"
" --verbose display each packet, default not\n"
" --help Display this help\n",
default_master, default_baudrate, defualt_out_addr,
default_in_addr);
}
static speed_t speed_by_value(int baudrate)
{
switch (baudrate) {
case 9600:
return B9600;
case 19200:
return B19200;
case 38400:
return B38400;
case 57600:
return B57600;
case 115200:
return B115200;
case 230400:
return B230400;
case 460800:
return B460800;
case 500000:
return B500000;
case 921600:
return B921600;
case 1500000:
return B1500000;
default:
printf("Not implemented baudrate %d\n", baudrate);
exit(EXIT_FAILURE);
}
}
static bool parse_host_port(const char *s, struct in_addr *out_addr,
in_port_t *out_port)
{
char host_and_port[32] = { 0 };
strncpy(host_and_port, s, sizeof(host_and_port) - 1);
char *colon = strchr(host_and_port, ':');
if (NULL == colon) {
return -1;
}
*colon = '\0';
const char *host = host_and_port, *port_ptr = colon + 1;
const bool is_valid_addr = inet_aton(host, out_addr) != 0;
if (!is_valid_addr) {
printf("Cannot parse host `%s'.\n", host);
return false;
}
int port;
if (sscanf(port_ptr, "%d", &port) != 1) {
printf("Cannot parse port `%s'.\n", port_ptr);
return false;
}
*out_port = htons(port);
return true;
}
static void signal_cb(evutil_socket_t fd, short event, void *arg)
{
struct event_base *base = arg;
(void)event;
printf("%s signal received\n", strsignal(fd));
event_base_loopbreak(base);
}
static void dump_mavlink_packet(unsigned char *data, const char *direction)
{
uint8_t seq;
uint8_t sys_id;
uint8_t comp_id;
uint32_t msg_id;
if(data[0] == 0xFE) { //mavlink 1
seq = data[2];
sys_id = data[3];
comp_id = data[4];
msg_id = data[5];
} else { //mavlink 2
seq = data[4];
sys_id = data[5];
comp_id = data[6];
msg_id = data[7];
}
if (verbose) printf("%s %#02x sender %d/%d\t%d\t%d\n", direction, data[0], sys_id, comp_id, seq, msg_id);
uint16_t val;
//RC_CHANNELS ( #65 ) hook
if(msg_id == 65 && ch_count > 0) {
uint8_t offset = 18; //15 = 1ch;
for(uint8_t i=0; i < ch_count; i++) {
val = data[offset] | (data[offset+1] << 8);
if(ch[i] != val) {
ch[i] = val;
char buff[44];
sprintf(buff, "/root/channels.sh %d %d &", i+5, val);
system(buff);
if (verbose) printf("called /root/channels.sh %d %d\n", i+5, val);
}
offset = offset + 2;
} //for
} //msg_id
}
/* https://discuss.ardupilot.org/uploads/short-url/vS0JJd3BQfN9uF4DkY7bAeb6Svd.pdf
* 0. Message header, always 0xFE
* 1. Message length
* 2. Sequence number -- rolls around from 255 to 0 (0x4e, previous was 0x4d)
* 3. System ID - what system is sending this message
* 4. Component ID- what component of the system is sending the message
* 5. Message ID (e.g. 0 = heartbeat and many more! Dont be shy, you can add too..)
*/
static bool get_mavlink_packet(unsigned char *in_buffer, int buf_len,
int *packet_len)
{
if (buf_len < 6 /* header */) {
return false;
}
assert(in_buffer[0] == 0xFE || in_buffer[0] == 0xFD); //mavlink 1 or 2
uint8_t msg_len = in_buffer[1];
if (in_buffer[0] == 0xFE)
*packet_len = 6 /* header */ + msg_len + 2 /* crc */; //mavlink 1
else
*packet_len = 10 /* header */ + msg_len + 2 /* crc */; //mavlink 2
if (buf_len < *packet_len)
return false;
dump_mavlink_packet(in_buffer, ">>");
return true;
}
// Returns num bytes before first occurrence of 0xFE or full data length
static size_t until_first_fe(unsigned char *data, size_t len)
{
for (size_t i = 1; i < len; i++) {
if (data[i] == 0xFE || data[i] == 0xFD) {
return i;
}
}
return len;
}
static void serial_read_cb(struct bufferevent *bev, void *arg)
{
struct evbuffer *input = bufferevent_get_input(bev);
int packet_len, in_len;
struct event_base *base = arg;
while ((in_len = evbuffer_get_length(input))) {
unsigned char *data = evbuffer_pullup(input, in_len);
if (data == NULL) {
return;
}
// find first 0xFE and skip everything before it
if (*data != 0xFE && *data != 0xFD) {
int bad_len = until_first_fe(data, in_len);
if (verbose) printf(">> Skipping %d bytes of unknown data\n",
bad_len);
evbuffer_drain(input, bad_len);
continue;
}
if (!get_mavlink_packet(data, in_len, &packet_len))
return;
// TODO: check CRC correctness and skip bad packets
if (sendto(out_sock, data, packet_len, 0,
(struct sockaddr *)&sin_out,
sizeof(sin_out)) == -1) {
perror("sendto()");
event_base_loopbreak(base);
}
evbuffer_drain(input, packet_len);
}
}
static void serial_event_cb(struct bufferevent *bev, short events, void *arg)
{
(void)bev;
struct event_base *base = arg;
if (events & (BEV_EVENT_EOF | BEV_EVENT_ERROR | BEV_EVENT_TIMEOUT)) {
printf("Serial connection closed\n");
event_base_loopbreak(base);
}
}
static void in_read(evutil_socket_t sock, short event, void *arg)
{
(void)event;
unsigned char buf[MAX_MTU];
struct event_base *base = arg;
ssize_t nread;
nread = recvfrom(sock, &buf, sizeof(buf) - 1, 0, NULL, NULL);
if (nread == -1) {
perror("recvfrom()");
event_base_loopbreak(base);
}
assert(nread > 6);
dump_mavlink_packet(buf, "<<");
bufferevent_write(serial_bev, buf, nread);
}
static int handle_data(const char *port_name, int baudrate,
const char *out_addr, const char *in_addr)
{
struct event_base *base = NULL;
struct event *sig_int = NULL, *in_ev = NULL;
int ret = EXIT_SUCCESS;
int serial_fd = open(port_name, O_RDWR | O_NOCTTY);
if (serial_fd < 0) {
printf("Error while openning port %s: %s\n", port_name,
strerror(errno));
return EXIT_FAILURE;
};
evutil_make_socket_nonblocking(serial_fd);
struct termios options;
tcgetattr(serial_fd, &options);
cfsetspeed(&options, speed_by_value(baudrate));
options.c_cflag &= ~CSIZE; // Mask the character size bits
options.c_cflag |= CS8; // 8 bit data
options.c_cflag &= ~PARENB; // set parity to no
options.c_cflag &= ~PARODD; // set parity to no
options.c_cflag &= ~CSTOPB; // set one stop bit
options.c_cflag |= (CLOCAL | CREAD);
options.c_oflag &= ~OPOST;
options.c_lflag &= 0;
options.c_iflag &= 0; // disable software flow controll
options.c_oflag &= 0;
cfmakeraw(&options);
tcsetattr(serial_fd, TCSANOW, &options);
out_sock = socket(AF_INET, SOCK_DGRAM, 0);
int in_sock = socket(AF_INET, SOCK_DGRAM, 0);
struct sockaddr_in sin_in = {
.sin_family = AF_INET,
};
if (!parse_host_port(in_addr, (struct in_addr *)&sin_in.sin_addr.s_addr,
&sin_in.sin_port))
goto err;
if (!parse_host_port(out_addr,
(struct in_addr *)&sin_out.sin_addr.s_addr,
&sin_out.sin_port))
goto err;
if (bind(in_sock, (struct sockaddr *)&sin_in, sizeof(sin_in))) {
perror("bind()");
exit(EXIT_FAILURE);
}
printf("Listening on %s...\n", in_addr);
base = event_base_new();
sig_int = evsignal_new(base, SIGINT, signal_cb, base);
event_add(sig_int, NULL);
// it's recommended by libevent authors to ignore SIGPIPE
signal(SIGPIPE, SIG_IGN);
serial_bev = bufferevent_socket_new(base, serial_fd, 0);
bufferevent_setcb(serial_bev, serial_read_cb, NULL, serial_event_cb,
base);
bufferevent_enable(serial_bev, EV_READ);
in_ev = event_new(base, in_sock, EV_READ | EV_PERSIST, in_read, NULL);
event_add(in_ev, NULL);
event_base_dispatch(base);
err:
if (serial_fd >= 0)
close(serial_fd);
if (serial_bev)
bufferevent_free(serial_bev);
if (in_ev) {
event_del(in_ev);
event_free(in_ev);
}
if (sig_int)
event_free(sig_int);
if (base)
event_base_free(base);
libevent_global_shutdown();
return ret;
}
int main(int argc, char **argv)
{
const struct option long_options[] = {
{ "master", required_argument, NULL, 'm' },
{ "baudrate", required_argument, NULL, 'b' },
{ "out", required_argument, NULL, 'o' },
{ "in", required_argument, NULL, 'i' },
{ "channels", required_argument, NULL, 'c' },
{ "verbose", no_argument, NULL, 'v' },
{ "help", no_argument, NULL, 'h' },
{ NULL, 0, NULL, 0 }
};
const char *port_name = default_master;
int baudrate = default_baudrate;
const char *out_addr = defualt_out_addr;
const char *in_addr = default_in_addr;
int opt;
int long_index = 0;
while ((opt = getopt_long_only(argc, argv, "", long_options,
&long_index)) != -1) {
switch (opt) {
case 'm':
port_name = optarg;
break;
case 'b':
baudrate = atoi(optarg);
break;
case 'o':
out_addr = optarg;
break;
case 'i':
in_addr = optarg;
break;
case 'c':
ch_count = atoi(optarg);
if(ch_count == 0) printf("rc_channels_override monitoring disabled\n");
else printf("rc_channels_override monitoring %d channels after first 4\n", ch_count);
break;
case 'v':
verbose = true;
break;
case 'h':
default:
print_usage();
return EXIT_SUCCESS;
}
}
return handle_data(port_name, baudrate, out_addr, in_addr);
}

View File

@ -0,0 +1,13 @@
### Зачем нужен mavfwd
`mavfwd` в первую очередь необходим для связи телеметрийного потока wifibroadcast,
разделенного на входящий и исходящий на разных udp-портах, с uart камеры, который
подключен к uart полетного контроллера UAV, настроенного на обмен телеметрией.
Поддерживается mavlink 1 и 2 версий. Подробности о параметрах доступны по `mavfwd --help`.
Во вторую очередь, mavfwd способен мониторить передаваемые в mavlink-пакете [RC_CHANNELS #65](https://mavlink.io/en/messages/common.html#RC_CHANNELS)
значения каналов с 4-го и выше, указанное в параметре --channels числом. По изменению значений каналов вызывается bash-скрипт /root/channels.sh,
передавая ему параметрами номер канала и его значение. Это нужно, чтобы организовать какое-то управление хост-системой (камерой), например ее перезагрузку
или настройку каких-то параметров стримера. В приложенном примере производятся:
* переключение разрешений 1080p / 720p;
* включение и отключение ircut камеры;
* пороговое изменение яркости, три режима, для подбора нужного под текущие условия освещённости (яркий день, обычный день, ночь).

View File

@ -0,0 +1,13 @@
### Why you need mavfwd
`mavfwd` is primarily necessary for the connection of the telemetry stream wifibroadcast,
divided into incoming and outgoing on different udp ports, from a uart camera, which
connected to the uart flight controller UAV, configured to exchange telemetry.
maxlink 1 and 2 versions are supported. Details of the parameters are available for `mavfwd --help`.
In the second place, mavfwd is able to monitor transmitted in the mavlink-pack [RC_CHANNELS #65](htts://mavlink.io/en/messages/common.html#RC_CHANNELS)
the channel value with 4 and above, specified in the --channels number parameter. By changing the values of the channels, the bash-script /root/channels.sh is called,
passing the channel number and its value. This is necessary to organize some kind of control of the host system (camera), for example, its reboot
or setting up some streamer parameters. The attached example makes:
* 180p / 720p resolution switching;
* Turning on and off the ircut camera;
* threshold change of brightness, three modes, for selecting the necessary under current conditions of illumination (strong day, ordinary day, night).

Binary file not shown.

After

Width:  |  Height:  |  Size: 153 KiB

View File

@ -0,0 +1,27 @@
text,type,typeId,Description
,Rectangle,creately.basic.rectangle,
GROUND (NVR),Text,creately.basic.text,
WIFI,WiFi,creately.material-icons.wifi_twotone_2,
rtl8812au,Rectangle,creately.basic.rectangle,
wifi adapter driver in monitor mode,Rectangle,creately.basic.rectangle,
wfb-rx,Rectangle,creately.basic.rectangle,
LAN / WLAN or usb network,Ellipse,creately.basic.ellipse,
,Rectangle,creately.basic.rectangle,
PC or Pocket,Text,creately.basic.text,
GS telemetry program,Computer,creately.material-icons.computer_twotone_2,
udp:14551,Text,creately.basic.text,
udp:14550,Text,creately.basic.text,
,Rectangle,creately.basic.rectangle,
CAM,Text,creately.basic.text,
mavfwd,Rectangle,creately.basic.rectangle,
wfb-tx,Rectangle,creately.basic.rectangle,
wfb-rx,Rectangle,creately.basic.rectangle,
udp:14550,Text,creately.basic.text,
udp:14551,Text,creately.basic.text,
FC > cam uart,Rectangle,creately.basic.rectangle,
wifi adapter driver in monitor mode,Rectangle,creately.basic.rectangle,
rtl8812au,Rectangle,creately.basic.rectangle,
WIFI,WiFi,creately.material-icons.wifi_twotone_2,
wfb-rx,Rectangle,creately.basic.rectangle,
mavlink-routerd,Rectangle,creately.basic.rectangle,
udp:14550,Text,creately.basic.text,
1 text type typeId Description
2 Rectangle creately.basic.rectangle
3 GROUND (NVR) Text creately.basic.text
4 WIFI WiFi creately.material-icons.wifi_twotone_2
5 rtl8812au Rectangle creately.basic.rectangle
6 wifi adapter driver in monitor mode Rectangle creately.basic.rectangle
7 wfb-rx Rectangle creately.basic.rectangle
8 LAN / WLAN or usb network Ellipse creately.basic.ellipse
9 Rectangle creately.basic.rectangle
10 PC or Pocket Text creately.basic.text
11 GS telemetry program Computer creately.material-icons.computer_twotone_2
12 udp:14551 Text creately.basic.text
13 udp:14550 Text creately.basic.text
14 Rectangle creately.basic.rectangle
15 CAM Text creately.basic.text
16 mavfwd Rectangle creately.basic.rectangle
17 wfb-tx Rectangle creately.basic.rectangle
18 wfb-rx Rectangle creately.basic.rectangle
19 udp:14550 Text creately.basic.text
20 udp:14551 Text creately.basic.text
21 FC > cam uart Rectangle creately.basic.rectangle
22 wifi adapter driver in monitor mode Rectangle creately.basic.rectangle
23 rtl8812au Rectangle creately.basic.rectangle
24 WIFI WiFi creately.material-icons.wifi_twotone_2
25 wfb-rx Rectangle creately.basic.rectangle
26 mavlink-routerd Rectangle creately.basic.rectangle
27 udp:14550 Text creately.basic.text

View File

@ -0,0 +1,29 @@
text,type,typeId,Description
,Rectangle,creately.basic.rectangle,
sensor,Rectangle,creately.basic.rectangle,
CAM,Text,creately.basic.text,
majestic or vencoder,Rectangle,creately.basic.rectangle,
wfb-tx,Rectangle,creately.basic.rectangle,
wifi adapter driver in monitor mode,Rectangle,creately.basic.rectangle,
isp,Text,creately.basic.text,
rtp:5600,Text,creately.basic.text,
rtl8812au,Rectangle,creately.basic.rectangle,
WIFI,WiFi,creately.material-icons.wifi_twotone_2,
,Rectangle,creately.basic.rectangle,
GROUND (NVR),Text,creately.basic.text,
WIFI,WiFi,creately.material-icons.wifi_twotone_2,
rtl8812au,Rectangle,creately.basic.rectangle,
wifi adapter driver in monitor mode,Rectangle,creately.basic.rectangle,
wfb-rx,Rectangle,creately.basic.rectangle,
LAN / WLAN or usb network,Ellipse,creately.basic.ellipse,
,Rectangle,creately.basic.rectangle,
PC or Pocket,Text,creately.basic.text,
videoplayer or GS program,Computer,creately.material-icons.computer_twotone_2,
,To Right Arrow,creately.arrows.torightarrow,
,To Right Arrow,creately.arrows.torightarrow,
rtp:5600,Text,creately.basic.text,
rtp:5600,Text,creately.basic.text,
wfb-rx,Rectangle,creately.basic.rectangle,
vdecoder,Rectangle,creately.basic.rectangle,
HDMI,Rectangle,creately.basic.rectangle,
udp:5000,Text,creately.basic.text,
1 text type typeId Description
2 Rectangle creately.basic.rectangle
3 sensor Rectangle creately.basic.rectangle
4 CAM Text creately.basic.text
5 majestic or vencoder Rectangle creately.basic.rectangle
6 wfb-tx Rectangle creately.basic.rectangle
7 wifi adapter driver in monitor mode Rectangle creately.basic.rectangle
8 isp Text creately.basic.text
9 rtp:5600 Text creately.basic.text
10 rtl8812au Rectangle creately.basic.rectangle
11 WIFI WiFi creately.material-icons.wifi_twotone_2
12 Rectangle creately.basic.rectangle
13 GROUND (NVR) Text creately.basic.text
14 WIFI WiFi creately.material-icons.wifi_twotone_2
15 rtl8812au Rectangle creately.basic.rectangle
16 wifi adapter driver in monitor mode Rectangle creately.basic.rectangle
17 wfb-rx Rectangle creately.basic.rectangle
18 LAN / WLAN or usb network Ellipse creately.basic.ellipse
19 Rectangle creately.basic.rectangle
20 PC or Pocket Text creately.basic.text
21 videoplayer or GS program Computer creately.material-icons.computer_twotone_2
22 To Right Arrow creately.arrows.torightarrow
23 To Right Arrow creately.arrows.torightarrow
24 rtp:5600 Text creately.basic.text
25 rtp:5600 Text creately.basic.text
26 wfb-rx Rectangle creately.basic.rectangle
27 vdecoder Rectangle creately.basic.rectangle
28 HDMI Rectangle creately.basic.rectangle
29 udp:5000 Text creately.basic.text

Binary file not shown.

After

Width:  |  Height:  |  Size: 755 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 333 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 451 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 323 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 490 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 122 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 135 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB