openpilot is an open source driver assistance system. openpilot performs the functions of Automated Lane Centering and Adaptive Cruise Control for over 200 supported car makes and models.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

370 lines
9.6 KiB

#include "ets_sys.h"
#include "osapi.h"
#include "gpio.h"
#include "os_type.h"
#include "user_interface.h"
#include "espconn.h"
#include "driver/spi_interface.h"
#include "driver/uart.h"
#include "crypto/sha.h"
#define min(a,b) \
({ __typeof__ (a) _a = (a); \
__typeof__ (b) _b = (b); \
_a < _b ? _a : _b; })
#define max(a,b) \
({ __typeof__ (a) _a = (a); \
__typeof__ (b) _b = (b); \
_a > _b ? _a : _b; })
char ssid[32];
char password[] = "testing123";
int wifi_secure_mode = 0;
static const int pin = 2;
// Structure holding the TCP connection information.
struct espconn tcp_conn;
// TCP specific protocol structure.
esp_tcp tcp_proto;
// interrupt communication on port 1338, UDP!
struct espconn inter_conn;
esp_udp inter_proto;
uint32_t sendData[0x14] = {0};
uint32_t recvData[0x40] = {0};
static int ICACHE_FLASH_ATTR __spi_comm(char *dat, int len, uint32_t *recvData, int recvDataLen) {
unsigned int length = 0;
SpiData spiData;
spiData.cmd = 2;
spiData.cmdLen = 0;
spiData.addr = NULL;
spiData.addrLen = 0;
// float boot pin
gpio_output_set(0, 0, 0, (1 << 4));
// manual CS pin
gpio_output_set(0, (1 << 5), 0, 0);
memset(sendData, 0xCC, 0x14);
// wait for ST to respond to CS interrupt
os_delay_us(50);
// send request
memcpy(((void*)sendData), dat, len);
spiData.data = sendData;
spiData.dataLen = 0x14;
SPIMasterSendData(SpiNum_HSPI, &spiData);
#define SPI_TIMEOUT 50000
// give the ST time to be ready, up to 500ms
int i;
for (i = 0; (gpio_input_get() & (1 << 4)) && i < SPI_TIMEOUT; i++) {
os_delay_us(10);
system_soft_wdt_feed();
}
// TODO: handle this better
if (i == SPI_TIMEOUT) {
os_printf("ERROR: SPI receive failed\n");
goto fail;
}
// blank out recvData
memset(recvData, 0x00, 0x44);
// receive the length
spiData.data = recvData;
spiData.dataLen = 4;
if(SPIMasterRecvData(SpiNum_HSPI, &spiData) == -1) {
// TODO: Handle gracefully. Maybe fail if len read fails?
os_printf("SPI: Failed to recv length\n");
goto fail;
}
length = recvData[0];
if (length > 0x40) {
os_printf("SPI: BAD LENGTH RECEIVED %x\n", length);
length = 0;
goto fail;
}
// got response, 0x40 works, 0x44 does not
spiData.data = recvData+1;
spiData.dataLen = (length+3)&(~3); // recvDataLen;
if(SPIMasterRecvData(SpiNum_HSPI, &spiData) == -1) {
// TODO: Handle gracefully. Maybe retry if payload failed.
os_printf("SPI: Failed to recv payload\n");
length = 0;
goto fail;
}
fail:
// clear CS
gpio_output_set((1 << 5), 0, 0, 0);
// set boot pin back
gpio_output_set((1 << 4), 0, (1 << 4), 0);
return length;
}
int ICACHE_FLASH_ATTR spi_comm(char *dat, int len, uint32_t *recvData, int recvDataLen) {
// blink the led during SPI comm
if (GPIO_REG_READ(GPIO_OUT_ADDRESS) & (1 << pin)) {
// set gpio low
gpio_output_set(0, (1 << pin), 0, 0);
} else {
// set gpio high
gpio_output_set((1 << pin), 0, 0, 0);
}
return __spi_comm(dat, len, recvData, recvDataLen);
}
static void ICACHE_FLASH_ATTR tcp_rx_cb(void *arg, char *data, uint16_t len) {
// nothing too big
if (len > 0x14) return;
// do the SPI comm
spi_comm(data, len, recvData, 0x40);
espconn_send(&tcp_conn, recvData, 0x44);
}
void ICACHE_FLASH_ATTR tcp_connect_cb(void *arg) {
struct espconn *conn = (struct espconn *)arg;
espconn_set_opt(&tcp_conn, ESPCONN_NODELAY);
espconn_regist_recvcb(conn, tcp_rx_cb);
}
// 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};
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) {
memcpy(buf + i*0x10, (timerRecvData+4)+j, 0x10);
i++;
}
}
if (i != 0) {
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;
}
}
}
int udp_countdown = 0;
static volatile os_timer_t udp_callback;
void ICACHE_FLASH_ATTR udp_callback_func(void *arg) {
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;
}
}
if (udp_countdown > 0) {
os_timer_arm(&udp_callback, 5, 0);
udp_countdown--;
} else {
os_printf("UDP timeout\n");
}
}
void ICACHE_FLASH_ATTR inter_recv_cb(void *arg, char *pusrdata, unsigned short length) {
remot_info *premot = NULL;
if (espconn_get_connection_info(&inter_conn,&premot,0) == ESPCONN_OK) {
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];
if (udp_countdown == 0) {
os_printf("UDP recv\n");
udp_countdown = 200*5;
// start 5 second timer
os_timer_disarm(&udp_callback);
os_timer_setfn(&udp_callback, (os_timer_func_t *)udp_callback_func, NULL);
os_timer_arm(&udp_callback, 5, 0);
} else {
udp_countdown = 200*5;
}
}
}
void ICACHE_FLASH_ATTR wifi_configure(int secure) {
wifi_secure_mode = secure;
// start wifi AP
wifi_set_opmode(SOFTAP_MODE);
struct softap_config config = {0};
wifi_softap_get_config(&config);
strcpy(config.ssid, ssid);
if (wifi_secure_mode == 0) strcat(config.ssid, "-pair");
strcpy(config.password, password);
config.ssid_len = strlen(config.ssid);
config.authmode = wifi_secure_mode ? AUTH_WPA2_PSK : AUTH_OPEN;
config.beacon_interval = 100;
config.max_connection = 4;
wifi_softap_set_config(&config);
if (wifi_secure_mode) {
// setup tcp server
tcp_proto.local_port = 1337;
tcp_conn.type = ESPCONN_TCP;
tcp_conn.state = ESPCONN_NONE;
tcp_conn.proto.tcp = &tcp_proto;
espconn_regist_connectcb(&tcp_conn, tcp_connect_cb);
espconn_accept(&tcp_conn);
espconn_regist_time(&tcp_conn, 60, 0); // 60s timeout for all connections
// setup inter server
inter_proto.local_port = 1338;
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);
}
}
void ICACHE_FLASH_ATTR wifi_init() {
// default ssid and password
memset(ssid, 0, 32);
os_sprintf(ssid, "panda-%08x-BROKEN", system_get_chip_id());
// fetch secure ssid and password
// update, try 20 times, for 1 second
for (int i = 0; i < 20; i++) {
uint8_t digest[SHA_DIGEST_SIZE];
char resp[0x20];
__spi_comm("\x00\x00\x00\x00\x40\xD0\x00\x00\x00\x00\x20\x00", 0xC, recvData, 0x40);
memcpy(resp, recvData+1, 0x20);
SHA_hash(resp, 0x1C, digest);
if (memcmp(digest, resp+0x1C, 4) == 0) {
// OTP is valid
memcpy(ssid+6, resp, 0x10);
memcpy(password, resp+0x10, 10);
break;
}
os_delay_us(50000);
}
// set IP
wifi_softap_dhcps_stop(); //stop DHCP before setting static IP
struct ip_info ip_config;
IP4_ADDR(&ip_config.ip, 192, 168, 0, 10);
IP4_ADDR(&ip_config.gw, 0, 0, 0, 0);
IP4_ADDR(&ip_config.netmask, 255, 255, 255, 0);
wifi_set_ip_info(SOFTAP_IF, &ip_config);
int stupid_gateway = 0;
wifi_softap_set_dhcps_offer_option(OFFER_ROUTER, &stupid_gateway);
wifi_softap_dhcps_start();
wifi_configure(0);
}
#define LOOP_PRIO 2
#define QUEUE_SIZE 1
static os_event_t my_queue[QUEUE_SIZE];
void loop();
void ICACHE_FLASH_ATTR web_init();
void ICACHE_FLASH_ATTR elm327_init();
void ICACHE_FLASH_ATTR user_init() {
// init gpio subsystem
gpio_init();
// configure UART TXD to be GPIO1, set as output
PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0TXD_U, FUNC_GPIO1);
gpio_output_set(0, 0, (1 << pin), 0);
// configure SPI
SpiAttr hSpiAttr;
hSpiAttr.bitOrder = SpiBitOrder_MSBFirst;
hSpiAttr.speed = SpiSpeed_10MHz;
hSpiAttr.mode = SpiMode_Master;
hSpiAttr.subMode = SpiSubMode_0;
// TODO: is one of these CS?
WRITE_PERI_REG(PERIPHS_IO_MUX, 0x105);
PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDI_U, 2); // configure io to spi mode
PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTCK_U, 2); // configure io to spi mode
PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTMS_U, 2); // configure io to spi mode
PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDO_U, 2); // configure io to spi mode
SPIInit(SpiNum_HSPI, &hSpiAttr);
//SPICsPinSelect(SpiNum_HSPI, SpiPinCS_1);
// configure UART TXD to be GPIO1, set as output
PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO5_U, FUNC_GPIO5);
gpio_output_set(0, 0, (1 << 5), 0);
gpio_output_set((1 << 5), 0, 0, 0);
// uart init
uart_init(BIT_RATE_115200, BIT_RATE_115200);
// led init
PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO2_U, FUNC_GPIO2);
gpio_output_set(0, (1 << pin), (1 << pin), 0);
os_printf("hello\n");
// needs SPI
wifi_init();
// support ota upgrades
elm327_init();
web_init();
// set gpio high, so LED is off by default
for (int i = 0; i < 5; i++) {
gpio_output_set(0, (1 << pin), 0, 0);
os_delay_us(50000);
gpio_output_set((1 << pin), 0, 0, 0);
os_delay_us(50000);
}
// 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) {
system_os_post(LOOP_PRIO, 0, 0);
}