From 657fdb84697bf5c4348de5a58ab0ea41f9bfeb7c Mon Sep 17 00:00:00 2001 From: Firmware Batman Date: Tue, 16 May 2017 17:01:29 -0700 Subject: [PATCH] add throughput test, switch 1338 to use UDP --- boardesp/proxy.c | 79 ++++++++++++++++++++++++---------------- lib/panda.py | 47 +++++++++++++++++------- tests/debug_console.py | 3 ++ tests/throughput_test.py | 59 ++++++++++++++++++++++++++++++ 4 files changed, 142 insertions(+), 46 deletions(-) create mode 100755 tests/throughput_test.py diff --git a/boardesp/proxy.c b/boardesp/proxy.c index 362748a2..b740b764 100644 --- a/boardesp/proxy.c +++ b/boardesp/proxy.c @@ -27,9 +27,9 @@ struct espconn tcp_conn; // TCP specific protocol structure. esp_tcp tcp_proto; -// interrupt communication on port 1338 +// interrupt communication on port 1338, UDP! struct espconn inter_conn; -esp_tcp inter_proto; +esp_udp inter_proto; uint32_t sendData[0x14] = {0}; uint32_t recvData[0x40] = {0}; @@ -113,16 +113,19 @@ void ICACHE_FLASH_ATTR tcp_connect_cb(void *arg) { espconn_regist_recvcb(conn, tcp_rx_cb); } -static volatile os_timer_t some_timer; -void ICACHE_FLASH_ATTR some_timerfunc(void *arg) { +// must be 0x44, because we can fit 4 more +uint8_t buf[0x44*0x10]; +int queue_send_len = -1; + +void ICACHE_FLASH_ATTR poll_can(void *arg) { uint8_t timerRecvData[0x44] = {0}; - uint8_t buf[0x44*0x10]; int i = 0; int j; while (i < 0x40) { int len = spi_comm("\x01\x00\x00\x00", 4, timerRecvData, 0x40); if (len == 0) break; + if (len > 0x40) { os_printf("SPI LENGTH ERROR!"); break; } // if it sends it, assume it's valid CAN for (j = 0; j < len; j += 0x10) { @@ -132,30 +135,27 @@ void ICACHE_FLASH_ATTR some_timerfunc(void *arg) { } if (i != 0) { - espconn_send(&inter_conn, buf, i*0x10); + int ret = espconn_sendto(&inter_conn, buf, i*0x10); + if (ret != 0) { + os_printf("send failed: %d\n", ret); + queue_send_len = i*0x10; + } else { + queue_send_len = -1; + } } } -volatile int timer_started = 0; - -void ICACHE_FLASH_ATTR inter_disc_cb(void *arg) { - if (timer_started) { - os_timer_disarm(&some_timer); - timer_started = 0; - } -} - -void ICACHE_FLASH_ATTR inter_connect_cb(void *arg) { - struct espconn *conn = (struct espconn *)arg; - espconn_set_opt(&inter_conn, ESPCONN_NODELAY); - espconn_regist_disconcb(conn, inter_disc_cb); - - // setup timer at 200hz - // TODO: disable when it runs out - if (!timer_started) { - os_timer_setfn(&some_timer, (os_timer_func_t *)some_timerfunc, NULL); - os_timer_arm(&some_timer, 5, 1); - timer_started = 1; +int timer_started = 0; +void ICACHE_FLASH_ATTR inter_recv_cb(void *arg, char *pusrdata, unsigned short length) { + os_printf("UDP recv\n"); + remot_info *premot = NULL; + if (espconn_get_connection_info(&inter_conn,&premot,0) == ESPCONN_OK) { + timer_started = 1; + inter_conn.proto.udp->remote_port = premot->remote_port; + inter_conn.proto.udp->remote_ip[0] = premot->remote_ip[0]; + inter_conn.proto.udp->remote_ip[1] = premot->remote_ip[1]; + inter_conn.proto.udp->remote_ip[2] = premot->remote_ip[2]; + inter_conn.proto.udp->remote_ip[3] = premot->remote_ip[3]; } } @@ -217,12 +217,16 @@ void ICACHE_FLASH_ATTR wifi_init() { // setup inter server inter_proto.local_port = 1338; - inter_conn.type = ESPCONN_TCP; - inter_conn.state = ESPCONN_NONE; - inter_conn.proto.tcp = &inter_proto; - espconn_regist_connectcb(&inter_conn, inter_connect_cb); - espconn_accept(&inter_conn); - espconn_regist_time(&inter_conn, 60, 0); // 60s timeout for all connections + const char udp_remote_ip[4] = {255, 255, 255, 255}; + os_memcpy(inter_proto.remote_ip, udp_remote_ip, 4); + inter_proto.remote_port = 1338; + + inter_conn.type = ESPCONN_UDP; + inter_conn.proto.udp = &inter_proto; + + espconn_regist_recvcb(&inter_conn, inter_recv_cb); + + espconn_create(&inter_conn); } #define LOOP_PRIO 2 @@ -284,10 +288,21 @@ void ICACHE_FLASH_ATTR user_init() // jump to OS system_os_task(loop, LOOP_PRIO, my_queue, QUEUE_SIZE); + system_os_post(LOOP_PRIO, 0, 0); } void ICACHE_FLASH_ATTR loop(os_event_t *events) { + if (timer_started) { + if (queue_send_len == -1) { + poll_can(NULL); + } else { + int ret = espconn_sendto(&inter_conn, buf, queue_send_len); + if (ret == 0) { + queue_send_len = -1; + } + } + } system_os_post(LOOP_PRIO, 0, 0); } diff --git a/lib/panda.py b/lib/panda.py index 50103676..9ef46aac 100644 --- a/lib/panda.py +++ b/lib/panda.py @@ -1,6 +1,5 @@ # python library to interface with panda import struct - import hashlib import socket import usb1 @@ -11,6 +10,38 @@ try: except: pass +def parse_can_buffer(dat): + ret = [] + for j in range(0, len(dat), 0x10): + ddat = dat[j:j+0x10] + f1, f2 = struct.unpack("II", ddat[0:8]) + extended = 4 + if f1 & extended: + address = f1 >> 3 + else: + address = f1 >> 21 + ret.append((address, f2>>16, ddat[8:8+(f2&0xF)], (f2>>4)&0xf)) + return ret + +class PandaWifiStreaming(object): + def __init__(self, ip="192.168.0.10", port=1338): + self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + self.sock.sendto("hello", (ip, port)) + self.sock.setblocking(0) + self.ip = ip + self.port = port + + def can_recv(self): + ret = [] + while 1: + try: + dat, addr = self.sock.recvfrom(0x200*0x10) + if addr == (self.ip, self.port): + ret += parse_can_buffer(dat) + except socket.error: + break + return ret + # stupid tunneling of USB over wifi and SPI class WifiHandle(object): def __init__(self, ip="192.168.0.10", port=1337): @@ -153,18 +184,6 @@ class Panda(object): self.can_send_many([[addr, None, dat, bus]]) def can_recv(self): - def __parse_can_buffer(dat): - ret = [] - for j in range(0, len(dat), 0x10): - ddat = dat[j:j+0x10] - f1, f2 = struct.unpack("II", ddat[0:8]) - extended = 4 - if f1 & extended: - address = f1 >> 3 - else: - address = f1 >> 21 - ret.append((address, f2>>16, ddat[8:8+(f2&0xF)], (f2>>4)&0xf)) - return ret dat = "" while 1: try: @@ -172,7 +191,7 @@ class Panda(object): break except (USBErrorIO, USBErrorOverflow): print "CAN: BAD RECV, RETRYING" - return __parse_can_buffer(dat) + return parse_can_buffer(dat) # ******************* serial ******************* diff --git a/tests/debug_console.py b/tests/debug_console.py index cfe3d8fd..0e9b4404 100755 --- a/tests/debug_console.py +++ b/tests/debug_console.py @@ -13,6 +13,9 @@ if __name__ == "__main__": port_number = int(os.getenv("PORT", 0)) serials = Panda.list() + if os.getenv("SERIAL"): + serials = filter(lambda x: x==os.getenv("SERIAL"), serials) + pandas = map(lambda x: Panda(x, False), serials) while 1: for i, panda in enumerate(pandas): diff --git a/tests/throughput_test.py b/tests/throughput_test.py new file mode 100755 index 00000000..76193189 --- /dev/null +++ b/tests/throughput_test.py @@ -0,0 +1,59 @@ +#!/usr/bin/env python +import os +import struct +import time +from panda.lib.panda import Panda, PandaWifiStreaming +from tqdm import tqdm + +# test throughput between USB and wifi + +if __name__ == "__main__": + print Panda.list() + p_out = Panda("108018800f51363038363036") + print p_out.get_serial() + #p_in = Panda("02001b000f51363038363036") + p_in = Panda("WIFI") + print p_in.get_serial() + + p_in = PandaWifiStreaming() + + #while 1: + # p_in.can_recv() + #exit(0) + + p_out.set_controls_allowed(True) + + set_out, set_in = set(), set() + + # drain + p_out.can_recv() + p_in.can_recv() + + BATCH_SIZE = 1 + for a in tqdm(range(0, 10000, BATCH_SIZE)): + for b in range(0, BATCH_SIZE): + msg = "\xaa"*4 + struct.pack("I", a+b) + if a%2 == 0: + p_out.can_send(0xaa, msg, 0) + + dat_out, dat_in = p_out.can_recv(), p_in.can_recv() + if len(dat_in) != 0: + print len(dat_in) + + num_out = [struct.unpack("I", i[4:])[0] for _, _, i, _ in dat_out] + num_in = [struct.unpack("I", i[4:])[0] for _, _, i, _ in dat_in] + + set_in.update(num_in) + set_out.update(num_out) + + # swag + print "waiting for packets" + time.sleep(1.0) + dat_in = p_in.can_recv() + num_in = [struct.unpack("I", i[4:])[0] for _, _, i, _ in dat_in] + set_in.update(num_in) + + if len(set_out - set_in): + print "MISSING %d" % len(set_out - set_in) + if len(set_out - set_in) < 100: + print map(hex, sorted(list(set_out - set_in)))