From 2ef8a327c6313373026bc45e81e67f26e9c27095 Mon Sep 17 00:00:00 2001 From: Peter Barker Date: Tue, 13 Jun 2017 16:34:02 +1000 Subject: [PATCH 01/32] Makefile: conform to gnu99 standards Several sticking points on using c99 standard, most notably cfnetspeed flags --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index e9c0c95..6b097e3 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ CC=gcc -CFLAGS=-Wall -g -Werror +CFLAGS=-Wall -g -Werror -std=gnu99 SRC = $(wildcard *.c) $(wildcard lib/*.c) $(wildcard linux/*.c) OBJ = $(SRC:%.c=%.o) From 3d68e8954374395eadf99034798de74e6ff76d3e Mon Sep 17 00:00:00 2001 From: Peter Barker Date: Wed, 14 Jun 2017 10:27:34 +1000 Subject: [PATCH 02/32] Add a .gitignore --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1c8938c --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +*.o +generated +web_server From 0fb539d434139c417e8249207ed9e6ab987e8d16 Mon Sep 17 00:00:00 2001 From: Peter Barker Date: Fri, 18 Aug 2017 14:02:44 +1000 Subject: [PATCH 03/32] files: index.html: adjust welcome message --- files/index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/files/index.html b/files/index.html index 968f313..aa3e555 100644 --- a/files/index.html +++ b/files/index.html @@ -15,7 +15,7 @@

ArduPilot Web Server

-Welcome to the ArduPilot Streaming GPS Drone

+Welcome to the ArduPilot Web Interface!

  • Filesystem access
  • From 514d219a62625f1af6b1500a759c0931f2e877ce Mon Sep 17 00:00:00 2001 From: Peter Barker Date: Wed, 21 Jun 2017 15:02:01 +1000 Subject: [PATCH 04/32] Use console_printf in place of fprintf --- web_server.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web_server.c b/web_server.c index c5c43ac..164071e 100644 --- a/web_server.c +++ b/web_server.c @@ -733,7 +733,7 @@ int main(int argc, char *argv[]) if (fc_udp_in_port !=-1 && serial_port != NULL) { // don't want to muck around with multiple mavlink channels - fprintf(stderr, "Only one of serial port and udp-in-port (-s and -u) can be supplied"); + console_printf("Only one of serial port and udp-in-port (-s and -u) can be supplied"); exit(1); } From 010f86ef540a7da540d4da6dd083a247f7e5cb82 Mon Sep 17 00:00:00 2001 From: Peter Barker Date: Wed, 14 Jun 2017 08:49:43 +1000 Subject: [PATCH 05/32] main: avoid calling mavlink_broadcast with bad fd --- web_server.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/web_server.c b/web_server.c index 164071e..cf7edfb 100644 --- a/web_server.c +++ b/web_server.c @@ -537,7 +537,9 @@ static void select_loop(int http_socket_fd, int udp_socket_fd) if (mavlink_parse_char(MAVLINK_COMM_FC, buf[i], &msg, &status)) { if (!mavlink_handle_msg(&msg)) { // forward to network connection as a udp broadcast packet - mavlink_broadcast(udp_socket_fd, &msg); + if (udp_socket_fd != -1) { + mavlink_broadcast(udp_socket_fd, &msg); + } } } } @@ -560,7 +562,9 @@ static void select_loop(int http_socket_fd, int udp_socket_fd) if (mavlink_parse_char(MAVLINK_COMM_FC, buf[i], &msg, &status)) { if (!mavlink_handle_msg(&msg)) { // forward to network connection as a udp broadcast packet - mavlink_broadcast(udp_socket_fd, &msg); + if (udp_socket_fd != -1) { + mavlink_broadcast(udp_socket_fd, &msg); + } } } } From 9efce7179b76ef23971a8c94b254fcac013bc3dd Mon Sep 17 00:00:00 2001 From: Peter Barker Date: Wed, 21 Jun 2017 09:57:17 +1000 Subject: [PATCH 06/32] web_server: Add UDP address:port output --- web_server.c | 105 ++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 103 insertions(+), 2 deletions(-) diff --git a/web_server.c b/web_server.c index cf7edfb..a77ee41 100644 --- a/web_server.c +++ b/web_server.c @@ -11,6 +11,7 @@ #ifdef SYSTEM_FREERTOS #include #else +#include #include #endif @@ -18,10 +19,14 @@ static pthread_mutex_t lock; static int serial_port_fd = -1; static int fc_udp_in_fd = -1; +static int udp_out_fd = -1; struct sockaddr_in fc_addr; socklen_t fc_addrlen; +struct sockaddr_in udp_out_addr; +socklen_t udp_out_addrlen; + #endif static int num_sockets_open; @@ -226,6 +231,21 @@ static void mavlink_broadcast(int fd, mavlink_message_t *msg) } #endif +/* + send a mavlink msg over WiFi to a single target + */ +static void mavlink_send_udp_out(mavlink_message_t *msg) +{ + if (udp_out_fd == -1) { + return; + } + uint8_t buf[300]; + uint16_t len = mavlink_msg_to_send_buffer(buf, msg); + if (len > 0) { + sendto(udp_out_fd, buf, len, 0, (struct sockaddr*)&udp_out_addr, sizeof(udp_out_addr)); + } +} + /* process input on a connection */ @@ -487,6 +507,13 @@ static void select_loop(int http_socket_fd, int udp_socket_fd) } } + if (udp_out_fd != -1) { + FD_SET(udp_out_fd, &fds); + if (udp_out_fd >= numfd) { + numfd = udp_out_fd+1; + } + } + tv.tv_sec = 1; tv.tv_usec = 0; @@ -524,6 +551,21 @@ static void select_loop(int http_socket_fd, int udp_socket_fd) } } + // check for incoming UDP packet from udp-out connection: + if (udp_out_fd != -1 && + FD_ISSET(udp_out_fd, &fds)) { + // we have data pending + uint8_t buf[1024]; + fc_addrlen = sizeof(fc_addr); + ssize_t nread = recvfrom(udp_out_fd, buf, sizeof(buf), MSG_DONTWAIT, (struct sockaddr*)&udp_out_addr, &udp_out_addrlen); + if (nread <= 0) { + /* printf("Read error from udp out connection\n"); */ + } else { + // send to flight controller + mavlink_fc_write(buf, nread); + } + } + if (fc_udp_in_fd != -1 && FD_ISSET(fc_udp_in_fd, &fds)) { // we have data pending @@ -540,6 +582,8 @@ static void select_loop(int http_socket_fd, int udp_socket_fd) if (udp_socket_fd != -1) { mavlink_broadcast(udp_socket_fd, &msg); } + // send to udp-out connection + mavlink_send_udp_out(&msg); } } } @@ -565,6 +609,8 @@ static void select_loop(int http_socket_fd, int udp_socket_fd) if (udp_socket_fd != -1) { mavlink_broadcast(udp_socket_fd, &msg); } + // send to udp-out connection + mavlink_send_udp_out(&msg); } } } @@ -692,6 +738,43 @@ static int udp_in_open(int port) return res; } +static int udp_out_open(const char *ip, const int port) +{ + int one=1; + + // prepare sending socket + struct sockaddr_in send_addr; + + memset(&send_addr,0,sizeof(send_addr)); + + send_addr.sin_port = 0; + send_addr.sin_family = AF_INET; + + int res = socket(AF_INET, SOCK_DGRAM, 0); + if (res == -1) { + return -1; + } + + setsockopt(res,SOL_SOCKET,SO_REUSEADDR,(char *)&one,sizeof(one)); + + if (bind(res, (struct sockaddr *)&send_addr, sizeof(send_addr)) < 0) { + return(-1); + } + + // prepare destination address + memset(&udp_out_addr,0x0,sizeof(udp_out_addr)); + udp_out_addr.sin_family = AF_INET; + if (inet_pton(AF_INET, ip, &udp_out_addr.sin_addr.s_addr) != 1) { + printf("Failed to convert IP address\n"); + exit(1); + } + udp_out_addr.sin_family = AF_INET; + udp_out_addr.sin_port = htons(port); + + return res; +} + + /* main program, start listening and answering queries */ int main(int argc, char *argv[]) { @@ -700,14 +783,15 @@ int main(int argc, char *argv[]) int opt; const char *serial_port = NULL; unsigned baudrate = 57600; - const char *usage = "Usage: web_server -p http_port -b baudrate -s serial_port -d debug_level -u -f fc_udp_in"; + const char *usage = "Usage: web_server -p http_port -b baudrate -s serial_port -d debug_level -u -f fc_udp_in -O udp-out-address:port"; bool do_udp_broadcast = 0; int fc_udp_in_port = -1; + const char *udp_out_arg = NULL; // e.g. 1.2.3.4:6543 // setup default allowed origin setup_origin(public_origin); - while ((opt=getopt(argc, argv, "p:s:b:hd:uf:")) != -1) { + while ((opt=getopt(argc, argv, "p:s:b:hd:uf:O:")) != -1) { switch (opt) { case 'p': http_port = atoi(optarg); @@ -727,6 +811,9 @@ int main(int argc, char *argv[]) case 'f': fc_udp_in_port = atoi(optarg); break; + case 'O': + udp_out_arg = optarg; + break; case 'h': default: printf("%s\n", usage); @@ -777,6 +864,20 @@ int main(int argc, char *argv[]) } } + if (udp_out_arg != NULL) { + char *colon = strchr(udp_out_arg, ':'); + if (colon == NULL) { + printf("udp-out address should be e.g. 1.2.3.4:6543\n"); + exit(1); + } + *colon = '\0'; + udp_out_fd = udp_out_open(udp_out_arg, atoi(colon+1)); + if (udp_out_fd == -1) { + printf("Failed to open UDP-out (%s:%u)\n", udp_out_arg, atoi(colon+1)); + exit(1); + } + } + select_loop(http_socket_fd, udp_socket_fd); return 0; From 61758fbb0e86589eb8e0dc3f10fd9b916780a627 Mon Sep 17 00:00:00 2001 From: Peter Barker Date: Wed, 21 Jun 2017 10:15:55 +1000 Subject: [PATCH 07/32] web_server: allow specification of IP address for TCP listen --- web_server.c | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/web_server.c b/web_server.c index a77ee41..a527835 100644 --- a/web_server.c +++ b/web_server.c @@ -650,7 +650,7 @@ static int mavlink_serial_open(const char *path, unsigned baudrate) /* open a TCP listening socket */ -static int tcp_open(unsigned port) +static int tcp_open(const char *ip, const unsigned port) { struct sockaddr_in sock; int listen_sock; @@ -659,6 +659,12 @@ static int tcp_open(unsigned port) memset((char *)&sock, 0, sizeof(sock)); sock.sin_port = htons(port); sock.sin_family = AF_INET; + if (ip != NULL) { + if (inet_pton(AF_INET, ip, &sock.sin_addr.s_addr) != 1) { + printf("Failed to convert IP address\n"); + exit(1); + } + } listen_sock = socket(AF_INET, SOCK_STREAM, 0); setsockopt(listen_sock, SOL_SOCKET,SO_REUSEADDR,(char *)&one,sizeof(one)); @@ -778,7 +784,6 @@ static int udp_out_open(const char *ip, const int port) /* main program, start listening and answering queries */ int main(int argc, char *argv[]) { - int http_port = -1; extern char *optarg; int opt; const char *serial_port = NULL; @@ -787,6 +792,7 @@ int main(int argc, char *argv[]) bool do_udp_broadcast = 0; int fc_udp_in_port = -1; const char *udp_out_arg = NULL; // e.g. 1.2.3.4:6543 + const char *http_port_arg = NULL; // e.g. 1.2.3.4:6543 or 6543 // setup default allowed origin setup_origin(public_origin); @@ -794,7 +800,7 @@ int main(int argc, char *argv[]) while ((opt=getopt(argc, argv, "p:s:b:hd:uf:O:")) != -1) { switch (opt) { case 'p': - http_port = atoi(optarg); + http_port_arg = optarg; break; case 's': serial_port = optarg; @@ -848,8 +854,16 @@ int main(int argc, char *argv[]) } int http_socket_fd = -1; - if (http_port != -1) { - http_socket_fd = tcp_open(http_port); + if (http_port_arg != NULL) { + char *colon = strchr(http_port_arg, ':'); + if (colon == NULL) { + // just a port number + http_socket_fd = tcp_open(NULL, atoi(http_port_arg)); + } else { + *colon = '\0'; + http_socket_fd = tcp_open(http_port_arg, atoi(colon+1)); + } + if (http_socket_fd == -1) { printf("Failed to open TCP socket\n"); exit(1); From a4086363d640170f30a9fb605292c0d3133c5afc Mon Sep 17 00:00:00 2001 From: Peter Barker Date: Wed, 21 Jun 2017 10:48:54 +1000 Subject: [PATCH 08/32] web_server: Make serial port read errors non-fatal --- web_server.c | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/web_server.c b/web_server.c index a527835..0bda4e2 100644 --- a/web_server.c +++ b/web_server.c @@ -596,21 +596,22 @@ static void select_loop(int http_socket_fd, int udp_socket_fd) uint8_t buf[200]; ssize_t nread = read(serial_port_fd, buf, sizeof(buf)); if (nread <= 0) { - printf("Read error from flight controller\n"); + printf("Read error from flight controller: %s\n", strerror(errno)); // we should re-open serial port - exit(1); - } - mavlink_message_t msg; - mavlink_status_t status; - for (uint16_t i=0; i Date: Wed, 21 Jun 2017 13:59:40 +1000 Subject: [PATCH 09/32] web_server: Increase debug on accept failure --- web_server.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/web_server.c b/web_server.c index 0bda4e2..11182fa 100644 --- a/web_server.c +++ b/web_server.c @@ -526,7 +526,10 @@ static void select_loop(int http_socket_fd, int udp_socket_fd) if (http_socket_fd != -1 && FD_ISSET(http_socket_fd, &fds)) { int fd = accept(http_socket_fd, NULL,0); - if (fd == -1) continue; + if (fd == -1) { + fprintf(stderr, "accept failed: %s\n", strerror(errno)); + continue; + }; // use a thread per connection. This allows for sending MAVLink messages // via mavlink_fc_send() from connections From abb5e29f216896ee93dfebb42f87c310a4b52959 Mon Sep 17 00:00:00 2001 From: Peter Barker Date: Wed, 21 Jun 2017 14:27:03 +1000 Subject: [PATCH 10/32] web_server: Move http accept into own function, add error checking --- web_server.c | 53 +++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 38 insertions(+), 15 deletions(-) diff --git a/web_server.c b/web_server.c index 11182fa..868a145 100644 --- a/web_server.c +++ b/web_server.c @@ -470,6 +470,43 @@ void web_server_task_process(void *pvParameters) vTaskDelete(NULL); } #else +void do_http_accept(const int sockfd) +{ + int fd = accept(sockfd, NULL,0); + if (fd == -1) { + console_printf("accept failed: %s\n", strerror(errno)); + goto BAD_ACCEPT; + }; + + // use a thread per connection. This allows for sending MAVLink messages + // via mavlink_fc_send() from connections + pthread_t thread_id; + pthread_attr_t thread_attr; + + int perrno; + if ((perrno = pthread_attr_init(&thread_attr)) != 0) { + console_printf("pthread_attr_init failed: %s\n", strerror(perrno)); + goto BAD_PTHREAD_INIT; + } + if ((perrno = pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED)) != 0) { + console_printf("pthread_attr_setdetachstate failed: %s\n", strerror(perrno)); + goto BAD_PTHREAD_SETDETEACHSTATE; + } + if ((perrno = pthread_create(&thread_id, &thread_attr, web_server_connection_process, (void*)(intptr_t)fd)) != 0) { + console_printf("pthread_create failed: %s\n", strerror(perrno)); + goto BAD_PTHREAD_CREATE; + } + pthread_attr_destroy(&thread_attr); + return; + +BAD_PTHREAD_CREATE: +BAD_PTHREAD_SETDETEACHSTATE: + pthread_attr_destroy(&thread_attr); +BAD_PTHREAD_INIT: + close(fd); +BAD_ACCEPT: + return; +} /* main select loop */ @@ -525,21 +562,7 @@ static void select_loop(int http_socket_fd, int udp_socket_fd) // check for new incoming tcp connection if (http_socket_fd != -1 && FD_ISSET(http_socket_fd, &fds)) { - int fd = accept(http_socket_fd, NULL,0); - if (fd == -1) { - fprintf(stderr, "accept failed: %s\n", strerror(errno)); - continue; - }; - - // use a thread per connection. This allows for sending MAVLink messages - // via mavlink_fc_send() from connections - pthread_t thread_id; - pthread_attr_t thread_attr; - - pthread_attr_init(&thread_attr); - pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED); - pthread_create(&thread_id, &thread_attr, web_server_connection_process, (void*)(intptr_t)fd); - pthread_attr_destroy(&thread_attr); + do_http_accept(http_socket_fd); } // check for incoming UDP packet (broadcast) From 67f1df08f264cd0c988e780ce505c4958d99fd78 Mon Sep 17 00:00:00 2001 From: Peter Barker Date: Thu, 31 Aug 2017 14:44:19 +1000 Subject: [PATCH 11/32] files: filesystem.html: option to start in a specific directory --- files/filesystem.html | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/files/filesystem.html b/files/filesystem.html index 1c43c26..96ecbee 100644 --- a/files/filesystem.html +++ b/files/filesystem.html @@ -37,6 +37,26 @@

    Index of /

    var current_directory = "/"; var file_list = []; + // from https://stackoverflow.com/questions/901115/how-can-i-get-query-string-values-in-javascript + function decode_params() { + var match; + var pl = /\+/g; // Regex for replacing addition symbol with a space + var search = /([^&=]+)=?([^&]*)/g; + var decode = function (s) { return decodeURIComponent(s.replace(pl, " ")); }; + var query = window.location.search.substring(1); + + urlParams = {}; + while (match = search.exec(query)) { + urlParams[decode(match[1])] = decode(match[2]); + } + return urlParams + } + + params = decode_params() + if (params["start_directory"]) { + current_directory = params["start_directory"] + } + function fill_directory(json) { var table = document.getElementById("directory_table"); From 1631374cc14a2a95d57ef5d1b7b4f5a479a96d08 Mon Sep 17 00:00:00 2001 From: Peter Barker Date: Thu, 7 Sep 2017 16:21:19 +1000 Subject: [PATCH 12/32] linux: use clock_gettime to reliably get boot time --- linux/util_linux.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/linux/util_linux.c b/linux/util_linux.c index 4f3e4b1..b1a3c95 100644 --- a/linux/util_linux.c +++ b/linux/util_linux.c @@ -39,13 +39,11 @@ long long get_sys_seconds_boot() // get number of milliseconds since boot uint32_t get_time_boot_ms() { - if (!system_time.initialised) { - gettimeofday(&system_time.tv,NULL); - system_time.initialised = true; - } - struct timeval tv; - gettimeofday(&tv,NULL); - return (tv.tv_sec - system_time.tv.tv_sec) * 1000U + (tv.tv_usec - system_time.tv.tv_usec) / 1000U; + struct timespec elapsed_from_boot; + + clock_gettime(CLOCK_BOOTTIME, &elapsed_from_boot); + + return elapsed_from_boot.tv_sec*1000 + elapsed_from_boot.tv_nsec/1000000; } void mdelay(uint32_t ms) From 34a7fb3f2cd9f588001450e759ed6ba7dc00a1a4 Mon Sep 17 00:00:00 2001 From: Peter Barker Date: Wed, 14 Jun 2017 20:47:41 +1000 Subject: [PATCH 13/32] linux: invoke shutdown(1) for __reboot --- linux/util_linux.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/linux/util_linux.c b/linux/util_linux.c index b1a3c95..80ca87f 100644 --- a/linux/util_linux.c +++ b/linux/util_linux.c @@ -68,6 +68,8 @@ void __reboot(void) #if __APPLE__ printf("reboot OSX implemented, but disabled for now.\n"); //reboot(0); + #elif __linux__ + system("/sbin/shutdown -t now -r"); #else printf("reboot not implemented\n"); #endif From 2e1dfb2704d2320cc381cc23ad37ed60b25785ee Mon Sep 17 00:00:00 2001 From: Peter Barker Date: Wed, 14 Jun 2017 10:26:47 +1000 Subject: [PATCH 14/32] posix: add disk_info function --- Makefile | 2 +- functions.c | 7 +++++++ posix/functions.c | 42 ++++++++++++++++++++++++++++++++++++++++++ posix/functions.h | 8 ++++++++ 4 files changed, 58 insertions(+), 1 deletion(-) create mode 100644 posix/functions.c create mode 100644 posix/functions.h diff --git a/Makefile b/Makefile index 6b097e3..310be85 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ CC=gcc CFLAGS=-Wall -g -Werror -std=gnu99 -SRC = $(wildcard *.c) $(wildcard lib/*.c) $(wildcard linux/*.c) +SRC = $(wildcard *.c) $(wildcard lib/*.c) $(wildcard linux/*.c) $(wildcard posix/*.c) OBJ = $(SRC:%.c=%.o) LIBS = -ltalloc -lpthread diff --git a/functions.c b/functions.c index deb718e..7ce071f 100644 --- a/functions.c +++ b/functions.c @@ -9,6 +9,10 @@ #include "mavlink_core.h" #include "cgi.h" +#ifdef _POSIX_VERSION +#include "posix/functions.h" +#endif + #ifdef SYSTEM_FREERTOS #include "../mavlink_wifi.h" #include "video_main.h" @@ -1027,6 +1031,9 @@ void functions_init(struct template_state *tmpl) tmpl->put(tmpl, "nvram_set_value", "", nvram_set_value); tmpl->put(tmpl, "get_ssid", "", get_ssid); #endif // SYSTEM_FREERTOS +#ifdef _POSIX_VERSION + posix_functions_init(tmpl); +#endif tmpl->put(tmpl, "format_storage", "", format_storage); tmpl->put(tmpl, "factory_reset", "", factory_reset); tmpl->put(tmpl, "reboot_companion", "", reboot_companion); diff --git a/posix/functions.c b/posix/functions.c new file mode 100644 index 0000000..f862a51 --- /dev/null +++ b/posix/functions.c @@ -0,0 +1,42 @@ +#include "../includes.h" +#include "../template.h" +#include "functions.h" + +#include + +static void sock_send_diskinfo(struct sock_buf *sock, const char *label, unsigned serial, unsigned total_clusters, unsigned free_clusters, unsigned cluster_size) +{ + sock_printf(sock, + "{" + "\"label\" : \"%s\", " + "\"serial\" : %u, " + "\"total_clusters\" : %u, " + "\"free_clusters\" : %u, " + "\"cluster_size\" : %u" + "}", + label, serial, total_clusters, free_clusters, cluster_size*512); +} + +static void disk_info(struct template_state *tmpl, const char *name, const char *value, int argc, char **argv) +{ + unsigned long free_clusters = 0, total_clusters = 0, cluster_size = 0; + const char label[] = "/"; + + /* Get volume information and free clusters of root filesystem */ + struct statvfs buf; + if (statvfs("/", &buf) != -1) { + total_clusters = buf.f_blocks; + free_clusters = buf.f_bfree; + cluster_size = buf.f_bsize / 512; + } + + const unsigned serial = 0; + + sock_send_diskinfo(tmpl->sock, label, serial, total_clusters, free_clusters, cluster_size); +} + + +void posix_functions_init(struct template_state *tmpl) +{ + tmpl->put(tmpl, "disk_info", "", disk_info); +} diff --git a/posix/functions.h b/posix/functions.h new file mode 100644 index 0000000..bb7d28c --- /dev/null +++ b/posix/functions.h @@ -0,0 +1,8 @@ +/* + provide server side functions in C + */ + +#include "../template.h" +#include "../includes.h" + +void posix_functions_init(struct template_state *tmpl); From de8842e27cf4d023a8f9e1101890a7104f728cff Mon Sep 17 00:00:00 2001 From: Peter Barker Date: Wed, 14 Jun 2017 11:38:49 +1000 Subject: [PATCH 15/32] posix: add file_listdir --- posix/functions.c | 70 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) diff --git a/posix/functions.c b/posix/functions.c index f862a51..07b000e 100644 --- a/posix/functions.c +++ b/posix/functions.c @@ -4,6 +4,9 @@ #include +#include +#include + static void sock_send_diskinfo(struct sock_buf *sock, const char *label, unsigned serial, unsigned total_clusters, unsigned free_clusters, unsigned cluster_size) { sock_printf(sock, @@ -36,7 +39,74 @@ static void disk_info(struct template_state *tmpl, const char *name, const char } +static void sock_send_dirent(struct sock_buf *sock, bool first, int type, const char *name, unsigned year, unsigned month, unsigned day, unsigned hour, unsigned minute, unsigned second, unsigned size) +{ + if (!first) { + sock_printf(sock, "%s", ",\n"); + } + sock_printf(sock, "{" + "\"type\" : %u, " + "\"name\" : \"%s\", " + "\"date\" : \"%04u-%02u-%02u %02u:%02u:%02u\", " + "\"size\" : %u " + "}", + type, name, year, month, day, hour, minute, second, size); +} + +static void file_listdir(struct template_state *tmpl, const char *name, const char *value, int argc, char **argv) +{ + if (argc < 1) { + return; + } + const char *dirpath = argv[0]; + + DIR *dh = opendir(dirpath); + if (dh == NULL) { + console_printf("Failed to open directory %s\n", dirpath); + return; + } + + sock_printf(tmpl->sock, "[ "); + + bool first = true; + struct dirent *result; + while ((result = readdir(dh)) != NULL) { + if (strcmp(result->d_name, ".") == 0) { + continue; + } + + struct stat buf; + char filepath[PATH_MAX] = {}; + snprintf(filepath, sizeof(filepath), "%s/%s", dirpath, result->d_name); + if (stat(filepath, &buf) == -1) { + continue; + } + + struct tm t; + if (localtime_r(&buf.st_mtim.tv_sec, &t) == NULL) { + continue; + } + + sock_send_dirent(tmpl->sock, + first, + (result->d_type==DT_DIR) ? 1 :0, + result->d_name, + t.tm_year+1900, + t.tm_mon+1, + t.tm_mday, + t.tm_hour, + t.tm_min, + t.tm_sec, + buf.st_size); + first = false; + } + sock_printf(tmpl->sock, "]"); + closedir(dh); +} + + void posix_functions_init(struct template_state *tmpl) { + tmpl->put(tmpl, "file_listdir", "", file_listdir); tmpl->put(tmpl, "disk_info", "", disk_info); } From dcfc332a1faee99ad787e4bdb0665c3fcdd064ed Mon Sep 17 00:00:00 2001 From: Peter Barker Date: Fri, 1 Sep 2017 13:55:29 +1000 Subject: [PATCH 16/32] posix: download_filesystem support --- cgi.c | 8 ++++--- posix/functions.c | 54 +++++++++++++++++++++++++++++++++++++++++++++-- posix/functions.h | 1 + 3 files changed, 58 insertions(+), 5 deletions(-) diff --git a/cgi.c b/cgi.c index 9d3b079..daf5652 100644 --- a/cgi.c +++ b/cgi.c @@ -21,6 +21,10 @@ #include "includes.h" #include +#ifdef _POSIX_VERSION +#include "posix/functions.h" +#endif + #define CONTENT_DISPOSITION "Content-Disposition:" #define CONTENT_TYPE "Content-Type:" #define MULTIPART_FORM_DATA "multipart/form-data" @@ -589,13 +593,11 @@ static void download(struct cgi_state *cgi, const char *path) mtype = get_mime_type(path); -#ifdef SYSTEM_FREERTOS if (strncmp(path, "fs/", 3) == 0) { download_filesystem(cgi, path); return; } -#endif - + size_t size = 0; const char *contents = get_embedded_file(path, &size); if (!contents) { diff --git a/posix/functions.c b/posix/functions.c index 07b000e..84a4875 100644 --- a/posix/functions.c +++ b/posix/functions.c @@ -2,10 +2,15 @@ #include "../template.h" #include "functions.h" +#include +#include +#include +#include #include - #include -#include +#include +#include + static void sock_send_diskinfo(struct sock_buf *sock, const char *label, unsigned serial, unsigned total_clusters, unsigned free_clusters, unsigned cluster_size) { @@ -104,6 +109,51 @@ static void file_listdir(struct template_state *tmpl, const char *name, const ch closedir(dh); } +void download_filesystem(struct cgi_state *cgi, const char *fs_path) +{ + const char *path = fs_path+2; + + struct stat stats; + if (stat(path, &stats) == -1) { + cgi->http_error(cgi, "404 Bad File", "", "file not found"); + return; + } + + cgi->content_length = stats.st_size; + const int fd = open(path, O_RDONLY); + if(fd == -1) { + cgi->http_error(cgi, "500 Open failed", "", strerror(errno)); + return; + } + cgi->http_header(cgi, fs_path); + char buf[2048]; + do { + const ssize_t read_count = read(fd, buf, sizeof(buf)); + if (read_count == -1) { + console_printf("Read failure: %s", strerror(errno)); + return; + } + if (read_count == 0) { + // EOF + break; + } + ssize_t to_write = read_count; + while (to_write > 0) { + ssize_t write_count = sock_write(cgi->sock, buf, to_write); + if (write_count == 0) { + console_printf("EOF on write?!"); + return; + } + if (write_count == -1) { + console_printf("Error on write: %s", strerror(errno)); + return; + } + to_write -= write_count; + } + } while (1); + + close(fd); +} void posix_functions_init(struct template_state *tmpl) { diff --git a/posix/functions.h b/posix/functions.h index bb7d28c..38b4240 100644 --- a/posix/functions.h +++ b/posix/functions.h @@ -6,3 +6,4 @@ #include "../includes.h" void posix_functions_init(struct template_state *tmpl); +void download_filesystem(struct cgi_state *cgi, const char *fs_path); From 2cadb19112e1674036789007195c084edb5c54fc Mon Sep 17 00:00:00 2001 From: Peter Barker Date: Thu, 22 Jun 2017 16:02:21 +1000 Subject: [PATCH 17/32] linux: Get system information statistics working --- functions.c | 13 ++++++++----- linux/util_linux.c | 7 +++++++ linux/util_linux.h | 5 +++++ web_server.c | 20 +++++++++++++++++++- 4 files changed, 39 insertions(+), 6 deletions(-) diff --git a/functions.c b/functions.c index 7ce071f..c2135a6 100644 --- a/functions.c +++ b/functions.c @@ -24,6 +24,7 @@ #include "files/version.h" #include #include +#endif /* get uptime in seconds @@ -36,6 +37,7 @@ static void uptime(struct template_state *tmpl, const char *name, const char *va /* get FC mavlink packet count */ +unsigned mavlink_fc_pkt_count(); static void fc_mavlink_count(struct template_state *tmpl, const char *name, const char *value, int argc, char **argv) { sock_printf(tmpl->sock, "%u", mavlink_fc_pkt_count()); @@ -44,6 +46,8 @@ static void fc_mavlink_count(struct template_state *tmpl, const char *name, cons /* get FC mavlink baudrate */ +int uart2_get_baudrate(); + static void fc_mavlink_baudrate(struct template_state *tmpl, const char *name, const char *value, int argc, char **argv) { sock_printf(tmpl->sock, "%u", uart2_get_baudrate()); @@ -57,7 +61,6 @@ static void mem_free(struct template_state *tmpl, const char *name, const char * int mem_type = argc>0?atoi(argv[0]):1; sock_printf(tmpl->sock, "%u", xPortGetFreeHeapSize(mem_type)); } -#endif /* get upload progress @@ -1007,8 +1010,6 @@ static void nvram_set_value(struct template_state *tmpl, const char *name, const void functions_init(struct template_state *tmpl) { #ifdef SYSTEM_FREERTOS - tmpl->put(tmpl, "uptime", "", uptime); - tmpl->put(tmpl, "mem_free", "", mem_free); tmpl->put(tmpl, "snapshot", "", snapshot); tmpl->put(tmpl, "mjpgvideo", "", mjpg_video); tmpl->put(tmpl, "take_picture", "", take_picture); @@ -1022,8 +1023,6 @@ void functions_init(struct template_state *tmpl) tmpl->put(tmpl, "file_listdir", "", file_listdir); tmpl->put(tmpl, "disk_info", "", disk_info); tmpl->put(tmpl, "set_time_utc", "", set_time_utc); - tmpl->put(tmpl, "fc_mavlink_count", "", fc_mavlink_count); - tmpl->put(tmpl, "fc_mavlink_baudrate", "", fc_mavlink_baudrate); tmpl->put(tmpl, "mga_status", "", mga_status); tmpl->put(tmpl, "mga_upload", "", mga_upload); tmpl->put(tmpl, "nvram_pack_list", "", nvram_pack_list); @@ -1034,6 +1033,10 @@ void functions_init(struct template_state *tmpl) #ifdef _POSIX_VERSION posix_functions_init(tmpl); #endif + tmpl->put(tmpl, "uptime", "", uptime); + tmpl->put(tmpl, "mem_free", "", mem_free); + tmpl->put(tmpl, "fc_mavlink_count", "", fc_mavlink_count); + tmpl->put(tmpl, "fc_mavlink_baudrate", "", fc_mavlink_baudrate); tmpl->put(tmpl, "format_storage", "", format_storage); tmpl->put(tmpl, "factory_reset", "", factory_reset); tmpl->put(tmpl, "reboot_companion", "", reboot_companion); diff --git a/linux/util_linux.c b/linux/util_linux.c index 80ca87f..17b7fea 100644 --- a/linux/util_linux.c +++ b/linux/util_linux.c @@ -97,3 +97,10 @@ void *print_printf(void *ctx, const char *fmt, ...) va_end(ap); return ret; } + + + +unsigned xPortGetFreeHeapSize() +{ + return 0; +} diff --git a/linux/util_linux.h b/linux/util_linux.h index 35577d1..90ec2fd 100644 --- a/linux/util_linux.h +++ b/linux/util_linux.h @@ -25,3 +25,8 @@ void __reboot(void); // __ so we don't call the os version of this by mistake. char *print_vprintf(void *ctx, const char *fmt, va_list ap); void *print_printf(void *ctx, const char *fmt, ...); + + + +unsigned mavlink_fc_pkt_count(); +unsigned xPortGetFreeHeapSize(); diff --git a/web_server.c b/web_server.c index 868a145..7878108 100644 --- a/web_server.c +++ b/web_server.c @@ -27,6 +27,12 @@ socklen_t fc_addrlen; struct sockaddr_in udp_out_addr; socklen_t udp_out_addrlen; +unsigned baudrate = 57600; + +struct { + uint64_t packet_count_from_fc; +} stats; + #endif static int num_sockets_open; @@ -507,6 +513,17 @@ void do_http_accept(const int sockfd) BAD_ACCEPT: return; } + +int uart2_get_baudrate() +{ + return baudrate; +} + +unsigned mavlink_fc_pkt_count() +{ + return stats.packet_count_from_fc; +} + /* main select loop */ @@ -603,6 +620,7 @@ static void select_loop(int http_socket_fd, int udp_socket_fd) mavlink_status_t status; for (uint16_t i=0; i Date: Thu, 28 Sep 2017 20:51:48 +1000 Subject: [PATCH 18/32] web_server: catch SIGPIPE --- web_server.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/web_server.c b/web_server.c index 7878108..fac1242 100644 --- a/web_server.c +++ b/web_server.c @@ -351,6 +351,11 @@ static void setup_origin(const char *origin) #endif } +void sig_pipe_handler(int signum) +{ + web_debug(3, "Caught signal SIGPIPE %d\n",signum); +} + /* task for web_server */ @@ -879,6 +884,14 @@ int main(int argc, char *argv[]) exit(1); } + // summarily ignore SIGPIPE; without this, if a download is + // interrupted sock_write's write() call will kill the process + // with SIGPIPE + web_debug(4, "Ignoring sig pipe\n"); + if (signal(SIGPIPE, sig_pipe_handler) == SIG_ERR) { + console_printf("Failed to ignore SIGPIPE: %m\n"); + } + pthread_mutex_init(&lock, NULL); if (serial_port) { From f4b8aab3afb7d592013805c39bd85d9c86840188 Mon Sep 17 00:00:00 2001 From: Peter Barker Date: Thu, 5 Oct 2017 17:07:32 +1100 Subject: [PATCH 19/32] filesystem.html: sort by filename --- files/filesystem.html | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/files/filesystem.html b/files/filesystem.html index 96ecbee..92946f3 100644 --- a/files/filesystem.html +++ b/files/filesystem.html @@ -57,6 +57,17 @@

    Index of /

    current_directory = params["start_directory"] } + function find_insertion_point(table, name) { + // offset 1 is the table header + for (var i=1; i name) { + return i; + } + } + return 1; + } + function fill_directory(json) { var table = document.getElementById("directory_table"); @@ -92,11 +103,12 @@

    Index of /

    var total_size = 0; for (var i=0; i Date: Thu, 2 Aug 2018 20:29:41 +0530 Subject: [PATCH 20/32] Added copy URL button --- files/apsync/video.html | 222 ++++++++++++++++++++++++++++++++++++++++ files/index.html | 1 + files/js/config.js | 2 +- files/js/mavlink.js | 15 ++- functions.c | 77 ++++++++++++++ rtsp_ipc.c | 139 +++++++++++++++++++++++++ rtsp_ipc.h | 18 ++++ web_server.c | 27 ++++- 8 files changed, 492 insertions(+), 9 deletions(-) create mode 100644 files/apsync/video.html create mode 100644 rtsp_ipc.c create mode 100644 rtsp_ipc.h diff --git a/files/apsync/video.html b/files/apsync/video.html new file mode 100644 index 0000000..2caab77 --- /dev/null +++ b/files/apsync/video.html @@ -0,0 +1,222 @@ + + + + ArduPilot + + + + + + + + +

    ArduPilot

    +

    Video Streaming

    +
    +

    Network Interface:

    +
    +
    + + +
    DeviceCamera NameRTSP URLCopy URLQuality ⓘRecord ⓘApply
    +

    +
    + + \ No newline at end of file diff --git a/files/index.html b/files/index.html index 6e9757d..1ccedb1 100644 --- a/files/index.html +++ b/files/index.html @@ -24,6 +24,7 @@

    ArduPilot Web Server

  • System Status
  • Calibration
  • Flight Parameters
  • +
  • Video Streaming
diff --git a/files/js/config.js b/files/js/config.js index 2e50568..5fb8abd 100644 --- a/files/js/config.js +++ b/files/js/config.js @@ -1,4 +1,4 @@ -var drone_url = "http://192.168.99.1"; +var drone_url = "http://127.0.0.1"; /* URL for Ublox MGA data */ var mga_data_url = "http://gps.tridgell.net/data/mga-offline.ubx"; diff --git a/files/js/mavlink.js b/files/js/mavlink.js index 9e47cee..52d5417 100644 --- a/files/js/mavlink.js +++ b/files/js/mavlink.js @@ -113,7 +113,8 @@ function fill_sr_parameters(plist) { /* fill in all divs of form MAVLINK:MSGNAME:field at refresh_ms() rate */ -function fill_mavlink_ids(options={}) { +function fill_mavlink_ids(options) { + options = options || {} function again() { setTimeout(function() { fill_mavlink_ids(options); }, refresh_ms()); } @@ -266,7 +267,8 @@ function page_fill_json_html(json) { /* send a command function */ -function command_send(command, options={}) { +function command_send(command, options) { + options = options || {} var args = Array.prototype.slice.call(arguments); var xhr = createCORSRequest("POST", drone_url + "/ajax/command.json"); var form = new FormData(); @@ -395,7 +397,8 @@ function ajax_get_callback_binary(url, callback) { /* poll a URL, calling a callback */ -function ajax_poll(url, callback, refresh_ms=1000) { +function ajax_poll(url, callback, refresh_ms) { + refresh_ms = refresh_ms || 1000 function again() { setTimeout(function() { ajax_poll(url, callback, refresh_ms); }, refresh_ms); } @@ -419,7 +422,8 @@ function ajax_poll(url, callback, refresh_ms=1000) { /* poll a json file and fill document IDs at the given rate */ -function ajax_json_poll(url, callback, refresh_ms=1000) { +function ajax_json_poll(url, callback, refresh_ms) { + refresh_ms = refresh_ms || 1000 function do_callback(responseText) { try { var json = JSON.parse(responseText); @@ -436,7 +440,8 @@ function ajax_json_poll(url, callback, refresh_ms=1000) { /* poll a json file and fill document IDs at the given rate */ -function ajax_json_poll_fill(url, refresh_ms=1000) { +function ajax_json_poll_fill(url, refresh_ms) { + refresh_ms = refresh_ms || 1000 function callback(json) { page_fill_json_html(json); return true; diff --git a/functions.c b/functions.c index ad2ec8e..0c5987e 100644 --- a/functions.c +++ b/functions.c @@ -8,6 +8,7 @@ #include "mavlink_json.h" #include "mavlink_core.h" #include "cgi.h" +#include "rtsp_ipc.h" #ifdef _POSIX_VERSION #include "posix/functions.h" @@ -755,6 +756,77 @@ static void get_param(struct template_state *tmpl, const char *name, const char } } +/* + gets the list of avaialble cameras from the RTSP stream server over a local socket + */ +static void get_camera_details(struct template_state *tmpl, const char *name, const char *value, int argc, char **argv) +{ + char msg[IPC_BUFFER_SIZE]; + char result[IPC_BUFFER_SIZE]; + get_server_response(GET_DEVICE_PROPS, msg, NULL); + if (strlen(msg)) { + process_server_response(msg, result); + sock_printf(tmpl->sock, "%s", result); + } else { + sock_printf(tmpl->sock, "%s", "ERROR"); + } +} + +/* + find the list of available network interfaces for starting the RTSP stream server + */ +static void get_interfaces(struct template_state *tmpl, const char *name, const char *value, int argc, char **argv) +{ + char interfaces_list[IPC_BUFFER_SIZE]; + get_interfaces_list(interfaces_list); + sock_printf(tmpl->sock, "%s", interfaces_list); +} + +/* + sets the properties of a camera through IPC with the RTSP stream server + */ +static void set_device_quality(struct template_state *tmpl, const char *name, const char *value, int argc, char **argv) +{ + if (argc) { + if (send_server_message(argv[0])) { + printf("Error in setting camera properties\n"); + } + } +} + +static pid_t stream_server_pid = -1; + +/* + forks to create a new process for the RTSP stream + */ +static void start_rtsp_server(struct template_state *tmpl, const char *name, const char *value, int argc, char **argv) +{ + if (stream_server_pid == -1) { + stream_server_pid = fork(); + if (stream_server_pid < 0) { + printf("Fork failed\n"); + } else if (stream_server_pid == 0) { + if (execlp("stream_server", "stream_server", argv[0], NULL)==-1) { + printf("Error in launching the stream server\n"); + } + } + } else { + printf("Stream server running with PID: %d\n", stream_server_pid); + } +} + +static void stop_rtsp_server(struct template_state *tmpl, const char *name, const char *value, int argc, char **argv) +{ + if (stream_server_pid != -1) { + if(!kill(stream_server_pid, SIGTERM)) { + stream_server_pid = -1; + printf("Stream server successfully killed\n"); + } else { + printf("Could not kill the stream server\n"); + } + } +} + /* get parameter list */ @@ -1061,4 +1133,9 @@ void functions_init(struct template_state *tmpl) tmpl->put(tmpl, "process_content", "", process_content); tmpl->put(tmpl, "get_param", "", get_param); tmpl->put(tmpl, "get_param_list", "", get_param_list); + tmpl->put(tmpl, "get_camera_details", "", get_camera_details); + tmpl->put(tmpl, "set_device_quality", "", set_device_quality); + tmpl->put(tmpl, "start_rtsp_server", "", start_rtsp_server); + tmpl->put(tmpl, "stop_rtsp_server", "", stop_rtsp_server); + tmpl->put(tmpl, "get_interfaces", "", get_interfaces); } diff --git a/rtsp_ipc.c b/rtsp_ipc.c new file mode 100644 index 0000000..811530e --- /dev/null +++ b/rtsp_ipc.c @@ -0,0 +1,139 @@ +#include "includes.h" +#include "rtsp_ipc.h" +#include +#include +#include +#include +#include +#include +#include +#include + +const char SOCKET_PATH[80] = "/tmp/rtsp_server.sock"; + +const char* RTSP_MESSAGE_HEADER[] = { + "GDP", "SDP" +}; + +int send_server_message(char* msg) +{ + struct sockaddr_un addr; + int fd; + + if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) { + printf("Unable to create stream server socket\n"); + return -1; + } + + memset(&addr, 0, sizeof(addr)); + addr.sun_family = AF_UNIX; + strcpy(addr.sun_path, SOCKET_PATH); + + if (connect(fd, (struct sockaddr*)&addr, sizeof(addr)) == -1) { + printf("Unable to connect to the stream server\n"); + return -1; + } else { + write(fd, msg, strlen(msg)); + close(fd); + } + return 0; +} + +void get_server_response(RTSP_MESSAGE_TYPE type, char* reply, char* args) +{ + struct sockaddr_un addr; + int fd; + + if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) { + printf("Unable to create stream server socket\n"); + reply[0] = '\0'; + return; + } + + memset(&addr, 0, sizeof(addr)); + addr.sun_family = AF_UNIX; + strcpy(addr.sun_path, SOCKET_PATH); + + if (connect(fd, (struct sockaddr*)&addr, sizeof(addr)) == -1) { + reply[0] = '\0'; + printf("Unable to connect to the stream server\n"); + } else { + switch(type) { + case GET_DEVICE_PROPS: + write(fd, "GDP", 4); + break; + default: + printf("Malformed message from stream server\n"); + } + + char read_buffer[IPC_BUFFER_SIZE]; + read_buffer[0] = '\0'; + int bytes_read = recv(fd, read_buffer, sizeof(read_buffer), 0); + read_buffer[bytes_read] = '\0'; + if (bytes_read != -1) { + strcpy(reply, read_buffer); + } + } + close(fd); +} + +RTSP_MESSAGE_TYPE get_message_type(char* header) +{ + for (int i = 0; i < RTSP_MESSAGE_TYPE_COUNT; i++) { + if (!strcmp(header, RTSP_MESSAGE_HEADER[i])) { + return i; + } + } + return ERROR; +} + +void process_server_response(char* reply, char* result) +{ + char* p = strtok(reply, "$"); + + char* msg_header = strdup(p); + RTSP_MESSAGE_TYPE message_type; + message_type = get_message_type(msg_header); + + p = strtok(NULL, "$"); + + switch (message_type) { + case GET_DEVICE_PROPS: + ; + strcpy(result, p); + break; + default: + printf("Malformed message from stream server\n"); + } +} + +// Gets list of available network interfaces for starting the RTSP stream server +void get_interfaces_list(char* interface_list) +{ + struct ifaddrs *ifaddr, *ifa; + char host[NI_MAXHOST]; + + if (getifaddrs(&ifaddr) == -1) { + printf("Could not get IPs"); + } + interface_list[0] = '\0'; + sprintf(interface_list, "{\"interfaces\": ["); + int i = 0; + for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) { + if (ifa->ifa_addr == NULL) { + continue; + } + getnameinfo(ifa->ifa_addr,sizeof(struct sockaddr_in), host, NI_MAXHOST, + NULL, 0, NI_NUMERICHOST); + if (ifa->ifa_addr->sa_family==AF_INET) { + if (i == 0) { + sprintf(interface_list, "%s\"%s\"", interface_list, ifa->ifa_name); + } else { + sprintf(interface_list, "%s,\"%s\"", interface_list, ifa->ifa_name); + } + i++; + } + } + sprintf(interface_list, "%s]}", interface_list); + freeifaddrs(ifaddr); +} diff --git a/rtsp_ipc.h b/rtsp_ipc.h new file mode 100644 index 0000000..a87598c --- /dev/null +++ b/rtsp_ipc.h @@ -0,0 +1,18 @@ +#ifndef RTSP_IPC_H +#define RTSP_IPC_H + +static const unsigned int IPC_BUFFER_SIZE = 10000; + +typedef enum RTSP_MESSAGE_TYPE {GET_DEVICE_PROPS, + SET_DEVICE_PROPS, + ERROR, + RTSP_MESSAGE_TYPE_COUNT} + RTSP_MESSAGE_TYPE; + +void get_server_response(RTSP_MESSAGE_TYPE type, char* reply, char* args); +int send_server_message(char* msg); +void process_server_response(char* reply, char* result); +void get_interfaces_list(char* interface_list); +RTSP_MESSAGE_TYPE get_message_type(char* header); + +#endif diff --git a/web_server.c b/web_server.c index 78fa5c2..0c977c3 100644 --- a/web_server.c +++ b/web_server.c @@ -13,6 +13,9 @@ #else #include #include +#include +#include +#include #endif #ifndef SYSTEM_FREERTOS @@ -273,9 +276,27 @@ static void connection_process(struct connection_state *c) */ static bool check_origin(const char *origin) { - if (strcmp(origin, "http://10.0.1.128") == 0) { - // always accept - return true; + struct ifaddrs *ifaddr, *ifa; + char host[NI_MAXHOST]; + + if (getifaddrs(&ifaddr) == -1) { + printf("Could not get IPs"); + } + + // check for matching IPs on all interfaces of the device + for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) { + if (ifa->ifa_addr == NULL) { + continue; + } + getnameinfo(ifa->ifa_addr,sizeof(struct sockaddr_in), host, NI_MAXHOST, + NULL, 0, NI_NUMERICHOST); + if (ifa->ifa_addr->sa_family==AF_INET) { + char host_string[20] = "http://"; + strcat(host_string, host); + if (strcmp(origin, host_string) == 0) { + return true; + } + } } #ifdef SYSTEM_FREERTOS From feaa8800dd0ff6f189170f9009ec1740bf670b7c Mon Sep 17 00:00:00 2001 From: arnav dhamija Date: Tue, 7 Aug 2018 12:59:13 +0530 Subject: [PATCH 21/32] Fixed layout bug --- files/apsync/video.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/files/apsync/video.html b/files/apsync/video.html index 2caab77..4bd1e8e 100644 --- a/files/apsync/video.html +++ b/files/apsync/video.html @@ -152,7 +152,7 @@

Video Streaming

var form_quality = "form_quality" + i; var quality_select_box = "quality_select_box"+i; - var set_quality_button = "set_quality_button"+i;copy_clipboard + var set_quality_button = "set_quality_button"+i; var record_video_checkbox = "record"+i; var current_quality = rowdata.current_quality; From b0d8471415f0b698598a631e85e741012998d69a Mon Sep 17 00:00:00 2001 From: arnav dhamija Date: Wed, 8 Aug 2018 14:51:42 +0530 Subject: [PATCH 22/32] Changed SIG for killing the stream server --- functions.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/functions.c b/functions.c index 0c5987e..8163877 100644 --- a/functions.c +++ b/functions.c @@ -818,7 +818,7 @@ static void start_rtsp_server(struct template_state *tmpl, const char *name, con static void stop_rtsp_server(struct template_state *tmpl, const char *name, const char *value, int argc, char **argv) { if (stream_server_pid != -1) { - if(!kill(stream_server_pid, SIGTERM)) { + if(!kill(stream_server_pid, SIGINT)) { stream_server_pid = -1; printf("Stream server successfully killed\n"); } else { From cd4289cb3a1ba6ef4021732f4c19e60f512e3c1f Mon Sep 17 00:00:00 2001 From: arnav dhamija Date: Wed, 8 Aug 2018 15:19:39 +0530 Subject: [PATCH 23/32] Fixed segfault bug --- functions.c | 1 + rtsp_ipc.c | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/functions.c b/functions.c index 8163877..b373995 100644 --- a/functions.c +++ b/functions.c @@ -763,6 +763,7 @@ static void get_camera_details(struct template_state *tmpl, const char *name, co { char msg[IPC_BUFFER_SIZE]; char result[IPC_BUFFER_SIZE]; + msg[0] = '\0'; get_server_response(GET_DEVICE_PROPS, msg, NULL); if (strlen(msg)) { process_server_response(msg, result); diff --git a/rtsp_ipc.c b/rtsp_ipc.c index 811530e..d3f568a 100644 --- a/rtsp_ipc.c +++ b/rtsp_ipc.c @@ -96,11 +96,14 @@ void process_server_response(char* reply, char* result) message_type = get_message_type(msg_header); p = strtok(NULL, "$"); + result[0] = '\0'; switch (message_type) { case GET_DEVICE_PROPS: ; - strcpy(result, p); + if (result) { + strcpy(result, p); + } break; default: printf("Malformed message from stream server\n"); From bad39aebeb233c080498524c22de7ade80fdfbf0 Mon Sep 17 00:00:00 2001 From: arnav dhamija Date: Tue, 18 Sep 2018 15:00:45 +0530 Subject: [PATCH 24/32] Changed location of stream server binary --- functions.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/functions.c b/functions.c index b373995..9ca878a 100644 --- a/functions.c +++ b/functions.c @@ -807,7 +807,11 @@ static void start_rtsp_server(struct template_state *tmpl, const char *name, con if (stream_server_pid < 0) { printf("Fork failed\n"); } else if (stream_server_pid == 0) { - if (execlp("stream_server", "stream_server", argv[0], NULL)==-1) { + char* home_dir; + char stream_server_path[256]; + home_dir = getenv("HOME"); + sprintf(stream_server_path, "%s/apsync/start_apstreamline/bin/stream_server", home_dir); + if (execl(stream_server_path, "stream_server", argv[0], NULL)==-1) { printf("Error in launching the stream server\n"); } } From 2374b8fb9383794565ea2ba542866a6ed33b2e6d Mon Sep 17 00:00:00 2001 From: arnav dhamija Date: Tue, 18 Sep 2018 18:23:33 +0530 Subject: [PATCH 25/32] Changed stream_server executable path --- functions.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/functions.c b/functions.c index 9ca878a..69ba4e9 100644 --- a/functions.c +++ b/functions.c @@ -810,7 +810,8 @@ static void start_rtsp_server(struct template_state *tmpl, const char *name, con char* home_dir; char stream_server_path[256]; home_dir = getenv("HOME"); - sprintf(stream_server_path, "%s/apsync/start_apstreamline/bin/stream_server", home_dir); + sprintf(stream_server_path, "%s/start_apstreamline/bin/stream_server", home_dir); + printf("%s", stream_server_path); if (execl(stream_server_path, "stream_server", argv[0], NULL)==-1) { printf("Error in launching the stream server\n"); } From 9ce1ff167c70d0268a77ac45783305b0cf2e2c56 Mon Sep 17 00:00:00 2001 From: Peter Barker Date: Thu, 14 Mar 2019 16:10:40 +1100 Subject: [PATCH 26/32] mavlink: update to ardupilot master --- modules/mavlink | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/mavlink b/modules/mavlink index 27e40d1..789a6d1 160000 --- a/modules/mavlink +++ b/modules/mavlink @@ -1 +1 @@ -Subproject commit 27e40d19654ca39818e6f63728f999afae679710 +Subproject commit 789a6d17fb33a1b95935313fd34116df6e62c485 From 80d1085777690d17090cbcbef83c2b740b39e2ed Mon Sep 17 00:00:00 2001 From: Peter Barker Date: Thu, 14 Mar 2019 16:11:01 +1100 Subject: [PATCH 27/32] Makefile: use mavgen shipped with mavlink's pymavlink --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 310be85..6c56a16 100644 --- a/Makefile +++ b/Makefile @@ -12,7 +12,7 @@ all: files/embedded.c mavlink web_server mavlink: generated/mavlink/ardupilotmega/mavlink.h generated/mavlink/ardupilotmega/mavlink.h: - mavgen.py --lang C modules/mavlink/message_definitions/v1.0/ardupilotmega.xml -o generated/mavlink --wire-protocol=2.0 + modules/mavlink/pymavlink/tools/mavgen.py --lang C modules/mavlink/message_definitions/v1.0/ardupilotmega.xml -o generated/mavlink --wire-protocol=2.0 web_server: $(OBJ) files/embedded.c $(CC) -o web_server $(OBJ) $(LIBS) From e801235715841e1740b565cb3b9236e57031b391 Mon Sep 17 00:00:00 2001 From: arnav dhamija Date: Sun, 31 Mar 2019 10:38:54 +0800 Subject: [PATCH 28/32] Fixed CORS requests from Chrome/Safari --- web_server.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/web_server.c b/web_server.c index f5fe9d8..54a2568 100644 --- a/web_server.c +++ b/web_server.c @@ -291,9 +291,7 @@ static bool check_origin(const char *origin) getnameinfo(ifa->ifa_addr,sizeof(struct sockaddr_in), host, NI_MAXHOST, NULL, 0, NI_NUMERICHOST); if (ifa->ifa_addr->sa_family==AF_INET) { - char host_string[20] = "http://"; - strcat(host_string, host); - if (strcmp(origin, host_string) == 0) { + if (strstr(origin, host) != NULL) { return true; } } From 11a48e52e97346b643c4419a60f0b374d5753234 Mon Sep 17 00:00:00 2001 From: arnav dhamija Date: Mon, 1 Apr 2019 13:50:39 +0800 Subject: [PATCH 29/32] Disabled the file recorder --- files/apsync/video.html | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) diff --git a/files/apsync/video.html b/files/apsync/video.html index 4bd1e8e..3683c84 100644 --- a/files/apsync/video.html +++ b/files/apsync/video.html @@ -17,7 +17,7 @@

Video Streaming

- +
DeviceCamera NameRTSP URLCopy URLQuality ⓘRecord ⓘApply
DeviceCamera NameRTSP URLCopy URLQuality ⓘApply

@@ -164,12 +164,7 @@

Video Streaming

} else { row.insertCell(4).innerHTML = ''; } - if (rowdata.camtype != 2) { - row.insertCell(5).innerHTML = ''; - } else { - row.insertCell(5).innerHTML = ''; - } - row.insertCell(6).innerHTML = ''; + row.insertCell(5).innerHTML = ''; var select = document.getElementById(quality_select_box); select.options[select.options.length] = new Option("Auto", AUTO_PRESET); @@ -196,13 +191,7 @@

Video Streaming

var device_name = document.getElementById("device" + button.value).innerHTML; var qual_setting = quality_select_box.value; - var record_val; - - if (record_video_checkbox.checked == true) { - record_val = 1; - } else { - record_val = 0; - } + var record_val = 0; var sdp_string = "SDP$" + device_name + " " + qual_setting + " " + record_val; command_send("set_device_quality(" + sdp_string + ")", {"onload" : after_sdp}); From e4b0b543ee0d3323634ab97067a05780952e644f Mon Sep 17 00:00:00 2001 From: arnav dhamija Date: Mon, 1 Apr 2019 13:53:37 +0800 Subject: [PATCH 30/32] Re-enabled quality for UVC cameras --- files/apsync/video.html | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/files/apsync/video.html b/files/apsync/video.html index 3683c84..f291119 100644 --- a/files/apsync/video.html +++ b/files/apsync/video.html @@ -158,12 +158,7 @@

Video Streaming

var current_quality = rowdata.current_quality; var curr_recording = rowdata.recording; - // H.264 cams don't do file recording properly, so let's disable it for now - if (rowdata.camtype != 1) { - row.insertCell(4).innerHTML = ''; - } else { - row.insertCell(4).innerHTML = ''; - } + row.insertCell(4).innerHTML = ''; row.insertCell(5).innerHTML = ''; var select = document.getElementById(quality_select_box); From 2b4dcf1fa849f4c8312623fd197ae8bab80ed941 Mon Sep 17 00:00:00 2001 From: arnav dhamija Date: Tue, 21 May 2019 11:42:48 +0530 Subject: [PATCH 31/32] Removed file recording checkbox --- files/apsync/video.html | 1 - 1 file changed, 1 deletion(-) diff --git a/files/apsync/video.html b/files/apsync/video.html index f291119..6386f8e 100644 --- a/files/apsync/video.html +++ b/files/apsync/video.html @@ -172,7 +172,6 @@

Video Streaming

} } document.getElementById(quality_select_box).value = current_quality; - document.getElementById(record_video_checkbox).checked = curr_recording; } } } From b8203158a37ecec99f4e873777095a9013364804 Mon Sep 17 00:00:00 2001 From: arnav dhamija Date: Wed, 31 Jul 2019 17:13:47 +0530 Subject: [PATCH 32/32] Changed path of stream_server executable for APStreamline --- functions.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/functions.c b/functions.c index 7e8d38f..5b54809 100644 --- a/functions.c +++ b/functions.c @@ -811,12 +811,7 @@ static void start_rtsp_server(struct template_state *tmpl, const char *name, con if (stream_server_pid < 0) { printf("Fork failed\n"); } else if (stream_server_pid == 0) { - char* home_dir; - char stream_server_path[256]; - home_dir = getenv("HOME"); - sprintf(stream_server_path, "%s/start_apstreamline/bin/stream_server", home_dir); - printf("%s", stream_server_path); - if (execl(stream_server_path, "stream_server", argv[0], NULL)==-1) { + if (execlp("stream_server", "stream_server", argv[0], NULL)==-1) { printf("Error in launching the stream server\n"); } }