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.
		
		
		
		
			
				
					692 lines
				
				19 KiB
			
		
		
			
		
	
	
					692 lines
				
				19 KiB
			| 
											8 years ago
										 | #include "config.h"
 | ||
|  | #include "obj/gitversion.h"
 | ||
|  | 
 | ||
|  | // ********************* includes *********************
 | ||
|  | 
 | ||
|  | #include "libc.h"
 | ||
|  | #include "safety.h"
 | ||
|  | #include "provision.h"
 | ||
|  | 
 | ||
|  | #include "drivers/drivers.h"
 | ||
|  | 
 | ||
|  | #include "drivers/llgpio.h"
 | ||
|  | #include "gpio.h"
 | ||
|  | 
 | ||
|  | #include "drivers/uart.h"
 | ||
|  | #include "drivers/adc.h"
 | ||
|  | #include "drivers/usb.h"
 | ||
| 
											7 years ago
										 | #include "drivers/gmlan_alt.h"
 | ||
| 
											8 years ago
										 | #include "drivers/can.h"
 | ||
|  | #include "drivers/spi.h"
 | ||
|  | #include "drivers/timer.h"
 | ||
|  | 
 | ||
|  | 
 | ||
|  | // ***************************** fan *****************************
 | ||
|  | 
 | ||
|  | void fan_init() {
 | ||
|  |   // timer for fan PWM
 | ||
|  |   TIM3->CCMR2 = TIM_CCMR2_OC3M_2 | TIM_CCMR2_OC3M_1;
 | ||
|  |   TIM3->CCER = TIM_CCER_CC3E;
 | ||
|  |   timer_init(TIM3, 10);
 | ||
|  | }
 | ||
|  | 
 | ||
|  | void fan_set_speed(int fan_speed) {
 | ||
|  |   TIM3->CCR3 = fan_speed;
 | ||
|  | }
 | ||
|  | 
 | ||
|  | // ********************* serial debugging *********************
 | ||
|  | 
 | ||
|  | void debug_ring_callback(uart_ring *ring) {
 | ||
|  |   char rcv;
 | ||
|  |   while (getc(ring, &rcv)) {
 | ||
|  |     putc(ring, rcv);
 | ||
|  | 
 | ||
|  |     // jump to DFU flash
 | ||
|  |     if (rcv == 'z') {
 | ||
|  |       enter_bootloader_mode = ENTER_BOOTLOADER_MAGIC;
 | ||
|  |       NVIC_SystemReset();
 | ||
|  |     }
 | ||
|  | 
 | ||
|  |     // normal reset
 | ||
|  |     if (rcv == 'x') {
 | ||
|  |       NVIC_SystemReset();
 | ||
|  |     }
 | ||
|  | 
 | ||
|  |     // enable CDP mode
 | ||
|  |     if (rcv == 'C') {
 | ||
|  |       puts("switching USB to CDP mode\n");
 | ||
|  |       set_usb_power_mode(USB_POWER_CDP);
 | ||
|  |     }
 | ||
|  |     if (rcv == 'c') {
 | ||
|  |       puts("switching USB to client mode\n");
 | ||
|  |       set_usb_power_mode(USB_POWER_CLIENT);
 | ||
|  |     }
 | ||
|  |     if (rcv == 'D') {
 | ||
|  |       puts("switching USB to DCP mode\n");
 | ||
|  |       set_usb_power_mode(USB_POWER_DCP);
 | ||
|  |     }
 | ||
|  |   }
 | ||
|  | }
 | ||
|  | 
 | ||
|  | // ***************************** USB port *****************************
 | ||
|  | 
 | ||
|  | int get_health_pkt(void *dat) {
 | ||
|  |   struct __attribute__((packed)) {
 | ||
|  |     uint32_t voltage;
 | ||
|  |     uint32_t current;
 | ||
|  |     uint8_t started;
 | ||
|  |     uint8_t controls_allowed;
 | ||
|  |     uint8_t gas_interceptor_detected;
 | ||
|  |     uint8_t started_signal_detected;
 | ||
|  |     uint8_t started_alt;
 | ||
|  |   } *health = dat;
 | ||
|  | 
 | ||
|  |   //Voltage will be measured in mv. 5000 = 5V
 | ||
|  |   uint32_t voltage = adc_get(ADCCHAN_VOLTAGE);
 | ||
|  |   if (revision == PANDA_REV_AB) {
 | ||
|  |     //REVB has a 100, 27 (27/127) voltage divider
 | ||
|  |     //Here is the calculation for the scale
 | ||
|  |     //ADCV = VIN_S * (27/127) * (4095/3.3)
 | ||
|  |     //RETVAL = ADCV * s = VIN_S*1000
 | ||
|  |     //s = 1000/((4095/3.3)*(27/127)) = 3.79053046
 | ||
|  | 
 | ||
|  |     //Avoid needing floating point math
 | ||
|  |     health->voltage = (voltage * 3791) / 1000;
 | ||
|  |   } else {
 | ||
|  |     //REVC has a 10, 1 (1/11) voltage divider
 | ||
|  |     //Here is the calculation for the scale (s)
 | ||
|  |     //ADCV = VIN_S * (1/11) * (4095/3.3)
 | ||
|  |     //RETVAL = ADCV * s = VIN_S*1000
 | ||
|  |     //s = 1000/((4095/3.3)*(1/11)) = 8.8623046875
 | ||
|  | 
 | ||
|  |     //Avoid needing floating point math
 | ||
|  |     health->voltage = (voltage * 8862) / 1000;
 | ||
|  |   }
 | ||
|  | 
 | ||
|  | #ifdef PANDA
 | ||
|  |   health->current = adc_get(ADCCHAN_CURRENT);
 | ||
| 
											8 years ago
										 |   int safety_ignition = safety_ignition_hook();
 | ||
|  |   if (safety_ignition < 0) {
 | ||
|  |     //Use the GPIO pin to determine ignition
 | ||
|  |     health->started = (GPIOA->IDR & (1 << 1)) == 0;
 | ||
|  |   } else {
 | ||
|  |     //Current safety hooks want to determine ignition (ex: GM)
 | ||
|  |     health->started = safety_ignition;
 | ||
|  |   }
 | ||
| 
											8 years ago
										 | #else
 | ||
|  |   health->current = 0;
 | ||
|  |   health->started = (GPIOC->IDR & (1 << 13)) != 0;
 | ||
|  | #endif
 | ||
|  | 
 | ||
|  |   health->controls_allowed = controls_allowed;
 | ||
|  |   health->gas_interceptor_detected = gas_interceptor_detected;
 | ||
|  | 
 | ||
|  |   // DEPRECATED
 | ||
|  |   health->started_alt = 0;
 | ||
|  |   health->started_signal_detected = 0;
 | ||
|  | 
 | ||
|  |   return sizeof(*health);
 | ||
|  | }
 | ||
|  | 
 | ||
|  | int usb_cb_ep1_in(uint8_t *usbdata, int len, int hardwired) {
 | ||
|  |   CAN_FIFOMailBox_TypeDef *reply = (CAN_FIFOMailBox_TypeDef *)usbdata;
 | ||
|  |   int ilen = 0;
 | ||
|  |   while (ilen < min(len/0x10, 4) && can_pop(&can_rx_q, &reply[ilen])) ilen++;
 | ||
|  |   return ilen*0x10;
 | ||
|  | }
 | ||
|  | 
 | ||
|  | // send on serial, first byte to select the ring
 | ||
|  | void usb_cb_ep2_out(uint8_t *usbdata, int len, int hardwired) {
 | ||
|  |   if (len == 0) return;
 | ||
|  |   uart_ring *ur = get_ring_by_number(usbdata[0]);
 | ||
|  |   if (!ur) return;
 | ||
|  |   if ((usbdata[0] < 2) || safety_tx_lin_hook(usbdata[0]-2, usbdata+1, len-1)) {
 | ||
|  |     for (int i = 1; i < len; i++) while (!putc(ur, usbdata[i]));
 | ||
|  |   }
 | ||
|  | }
 | ||
|  | 
 | ||
|  | // send on CAN
 | ||
|  | void usb_cb_ep3_out(uint8_t *usbdata, int len, int hardwired) {
 | ||
|  |   int dpkt = 0;
 | ||
|  |   for (dpkt = 0; dpkt < len; dpkt += 0x10) {
 | ||
|  |     uint32_t *tf = (uint32_t*)(&usbdata[dpkt]);
 | ||
|  | 
 | ||
|  |     // make a copy
 | ||
|  |     CAN_FIFOMailBox_TypeDef to_push;
 | ||
|  |     to_push.RDHR = tf[3];
 | ||
|  |     to_push.RDLR = tf[2];
 | ||
|  |     to_push.RDTR = tf[1];
 | ||
|  |     to_push.RIR = tf[0];
 | ||
|  | 
 | ||
|  |     uint8_t bus_number = (to_push.RDTR >> 4) & CAN_BUS_NUM_MASK;
 | ||
|  |     can_send(&to_push, bus_number);
 | ||
|  |   }
 | ||
|  | }
 | ||
|  | 
 | ||
|  | int is_enumerated = 0;
 | ||
|  | 
 | ||
|  | void usb_cb_enumeration_complete() {
 | ||
|  |   puts("USB enumeration complete\n");
 | ||
|  |   is_enumerated = 1;
 | ||
|  | }
 | ||
|  | 
 | ||
|  | int usb_cb_control_msg(USB_Setup_TypeDef *setup, uint8_t *resp, int hardwired) {
 | ||
|  |   int resp_len = 0;
 | ||
|  |   uart_ring *ur = NULL;
 | ||
|  |   int i;
 | ||
|  |   switch (setup->b.bRequest) {
 | ||
|  |     // **** 0xc0: get CAN debug info
 | ||
|  |     case 0xc0:
 | ||
|  |       puts("can tx: "); puth(can_tx_cnt);
 | ||
|  |       puts(" txd: "); puth(can_txd_cnt);
 | ||
|  |       puts(" rx: "); puth(can_rx_cnt);
 | ||
|  |       puts(" err: "); puth(can_err_cnt);
 | ||
|  |       puts("\n");
 | ||
|  |       break;
 | ||
| 
											8 years ago
										 |     // **** 0xc1: is grey panda
 | ||
|  |     case 0xc1:
 | ||
|  |       resp[0] = is_grey_panda;
 | ||
|  |       resp_len = 1;
 | ||
|  |       break;
 | ||
| 
											8 years ago
										 |     // **** 0xd0: fetch serial number
 | ||
|  |     case 0xd0:
 | ||
|  |       #ifdef PANDA
 | ||
|  |         // addresses are OTP
 | ||
|  |         if (setup->b.wValue.w == 1) {
 | ||
|  |           memcpy(resp, (void *)0x1fff79c0, 0x10);
 | ||
|  |           resp_len = 0x10;
 | ||
|  |         } else {
 | ||
|  |           get_provision_chunk(resp);
 | ||
|  |           resp_len = PROVISION_CHUNK_LEN;
 | ||
|  |         }
 | ||
|  |       #endif
 | ||
|  |       break;
 | ||
|  |     // **** 0xd1: enter bootloader mode
 | ||
|  |     case 0xd1:
 | ||
|  |       // this allows reflashing of the bootstub
 | ||
|  |       // so it's blocked over wifi
 | ||
|  |       switch (setup->b.wValue.w) {
 | ||
|  |         case 0:
 | ||
|  |           if (hardwired) {
 | ||
|  |             puts("-> entering bootloader\n");
 | ||
|  |             enter_bootloader_mode = ENTER_BOOTLOADER_MAGIC;
 | ||
|  |             NVIC_SystemReset();
 | ||
|  |           }
 | ||
|  |           break;
 | ||
|  |         case 1:
 | ||
|  |           puts("-> entering softloader\n");
 | ||
|  |           enter_bootloader_mode = ENTER_SOFTLOADER_MAGIC;
 | ||
|  |           NVIC_SystemReset();
 | ||
|  |           break;
 | ||
|  |       }
 | ||
|  |       break;
 | ||
|  |     // **** 0xd2: get health packet
 | ||
|  |     case 0xd2:
 | ||
|  |       resp_len = get_health_pkt(resp);
 | ||
|  |       break;
 | ||
|  |     // **** 0xd3: set fan speed
 | ||
|  |     case 0xd3:
 | ||
|  |       fan_set_speed(setup->b.wValue.w);
 | ||
|  |       break;
 | ||
|  |     // **** 0xd6: get version
 | ||
|  |     case 0xd6:
 | ||
|  |       COMPILE_TIME_ASSERT(sizeof(gitversion) <= MAX_RESP_LEN)
 | ||
|  |       memcpy(resp, gitversion, sizeof(gitversion));
 | ||
|  |       resp_len = sizeof(gitversion)-1;
 | ||
|  |       break;
 | ||
|  |     // **** 0xd8: reset ST
 | ||
|  |     case 0xd8:
 | ||
|  |       NVIC_SystemReset();
 | ||
|  |       break;
 | ||
|  |     // **** 0xd9: set ESP power
 | ||
|  |     case 0xd9:
 | ||
|  |       if (setup->b.wValue.w == 1) {
 | ||
|  |         set_esp_mode(ESP_ENABLED);
 | ||
| 
											8 years ago
										 |       } else if (setup->b.wValue.w == 2) {
 | ||
|  |         set_esp_mode(ESP_BOOTMODE);
 | ||
| 
											8 years ago
										 |       } else {
 | ||
|  |         set_esp_mode(ESP_DISABLED);
 | ||
|  |       }
 | ||
|  |       break;
 | ||
|  |     // **** 0xda: reset ESP, with optional boot mode
 | ||
|  |     case 0xda:
 | ||
|  |       set_esp_mode(ESP_DISABLED);
 | ||
|  |       delay(1000000);
 | ||
|  |       if (setup->b.wValue.w == 1) {
 | ||
|  |         set_esp_mode(ESP_BOOTMODE);
 | ||
|  |       } else {
 | ||
|  |         set_esp_mode(ESP_ENABLED);
 | ||
|  |       }
 | ||
|  |       delay(1000000);
 | ||
|  |       set_esp_mode(ESP_ENABLED);
 | ||
|  |       break;
 | ||
|  |     // **** 0xdb: set GMLAN multiplexing mode
 | ||
|  |     case 0xdb:
 | ||
|  |       #ifdef PANDA
 | ||
|  |         if (setup->b.wValue.w == 1) {
 | ||
|  |           // GMLAN ON
 | ||
|  |           if (setup->b.wIndex.w == 1) {
 | ||
|  |             can_set_gmlan(1);
 | ||
|  |           } else if (setup->b.wIndex.w == 2) {
 | ||
|  |             // might be ignored on rev b panda
 | ||
|  |             can_set_gmlan(2);
 | ||
|  |           }
 | ||
|  |         } else {
 | ||
|  |           can_set_gmlan(-1);
 | ||
|  |         }
 | ||
|  |       #endif
 | ||
|  |       break;
 | ||
|  |     // **** 0xdc: set safety mode
 | ||
|  |     case 0xdc:
 | ||
|  |       // this is the only way to leave silent mode
 | ||
|  |       // and it's blocked over WiFi
 | ||
|  |       // Allow ELM security mode to be set over wifi.
 | ||
|  |       if (hardwired || setup->b.wValue.w == SAFETY_NOOUTPUT || setup->b.wValue.w == SAFETY_ELM327) {
 | ||
| 
											8 years ago
										 |         safety_set_mode(setup->b.wValue.w, (int16_t)setup->b.wIndex.w);
 | ||
| 
											8 years ago
										 |         switch (setup->b.wValue.w) {
 | ||
|  |           case SAFETY_NOOUTPUT:
 | ||
|  |             can_silent = ALL_CAN_SILENT;
 | ||
|  |             break;
 | ||
|  |           case SAFETY_ELM327:
 | ||
|  |             can_silent = ALL_CAN_BUT_MAIN_SILENT;
 | ||
| 
											8 years ago
										 |             can_autobaud_enabled[0] = false;
 | ||
| 
											8 years ago
										 |             break;
 | ||
|  |           default:
 | ||
|  |             can_silent = ALL_CAN_LIVE;
 | ||
| 
											8 years ago
										 |             can_autobaud_enabled[0] = false;
 | ||
|  |             can_autobaud_enabled[1] = false;
 | ||
|  |             #ifdef PANDA
 | ||
|  |               can_autobaud_enabled[2] = false;
 | ||
|  |             #endif
 | ||
| 
											8 years ago
										 |             break;
 | ||
|  |         }
 | ||
|  |         can_init_all();
 | ||
|  |       }
 | ||
|  |       break;
 | ||
|  |     // **** 0xdd: enable can forwarding
 | ||
|  |     case 0xdd:
 | ||
|  |       // wValue = Can Bus Num to forward from
 | ||
|  |       // wIndex = Can Bus Num to forward to
 | ||
|  |       if (setup->b.wValue.w < BUS_MAX && setup->b.wIndex.w < BUS_MAX &&
 | ||
|  |           setup->b.wValue.w != setup->b.wIndex.w) { // set forwarding
 | ||
|  |         can_set_forwarding(setup->b.wValue.w, setup->b.wIndex.w & CAN_BUS_NUM_MASK);
 | ||
|  |       } else if(setup->b.wValue.w < BUS_MAX && setup->b.wIndex.w == 0xFF){ //Clear Forwarding
 | ||
|  |         can_set_forwarding(setup->b.wValue.w, -1);
 | ||
|  |       }
 | ||
|  |       break;
 | ||
|  |     // **** 0xde: set can bitrate
 | ||
|  |     case 0xde:
 | ||
|  |       if (setup->b.wValue.w < BUS_MAX) {
 | ||
| 
											8 years ago
										 |         can_autobaud_enabled[setup->b.wValue.w] = false;
 | ||
| 
											8 years ago
										 |         can_speed[setup->b.wValue.w] = setup->b.wIndex.w;
 | ||
|  |         can_init(CAN_NUM_FROM_BUS_NUM(setup->b.wValue.w));
 | ||
|  |       }
 | ||
|  |       break;
 | ||
|  |     // **** 0xe0: uart read
 | ||
|  |     case 0xe0:
 | ||
|  |       ur = get_ring_by_number(setup->b.wValue.w);
 | ||
|  |       if (!ur) break;
 | ||
| 
											8 years ago
										 |       if (ur == &esp_ring) uart_dma_drain();
 | ||
| 
											8 years ago
										 |       // read
 | ||
|  |       while ((resp_len < min(setup->b.wLength.w, MAX_RESP_LEN)) &&
 | ||
|  |                          getc(ur, (char*)&resp[resp_len])) {
 | ||
|  |         ++resp_len;
 | ||
|  |       }
 | ||
|  |       break;
 | ||
|  |     // **** 0xe1: uart set baud rate
 | ||
|  |     case 0xe1:
 | ||
|  |       ur = get_ring_by_number(setup->b.wValue.w);
 | ||
|  |       if (!ur) break;
 | ||
|  |       uart_set_baud(ur->uart, setup->b.wIndex.w);
 | ||
|  |       break;
 | ||
|  |     // **** 0xe2: uart set parity
 | ||
|  |     case 0xe2:
 | ||
|  |       ur = get_ring_by_number(setup->b.wValue.w);
 | ||
|  |       if (!ur) break;
 | ||
|  |       switch (setup->b.wIndex.w) {
 | ||
|  |         case 0:
 | ||
|  |           // disable parity, 8-bit
 | ||
|  |           ur->uart->CR1 &= ~(USART_CR1_PCE | USART_CR1_M);
 | ||
|  |           break;
 | ||
|  |         case 1:
 | ||
|  |           // even parity, 9-bit
 | ||
|  |           ur->uart->CR1 &= ~USART_CR1_PS;
 | ||
|  |           ur->uart->CR1 |= USART_CR1_PCE | USART_CR1_M;
 | ||
|  |           break;
 | ||
|  |         case 2:
 | ||
|  |           // odd parity, 9-bit
 | ||
|  |           ur->uart->CR1 |= USART_CR1_PS;
 | ||
|  |           ur->uart->CR1 |= USART_CR1_PCE | USART_CR1_M;
 | ||
|  |           break;
 | ||
|  |         default:
 | ||
|  |           break;
 | ||
|  |       }
 | ||
|  |       break;
 | ||
|  |     // **** 0xe4: uart set baud rate extended
 | ||
|  |     case 0xe4:
 | ||
|  |       ur = get_ring_by_number(setup->b.wValue.w);
 | ||
|  |       if (!ur) break;
 | ||
|  |       uart_set_baud(ur->uart, (int)setup->b.wIndex.w*300);
 | ||
|  |       break;
 | ||
|  |     // **** 0xe5: set CAN loopback (for testing)
 | ||
|  |     case 0xe5:
 | ||
|  |       can_loopback = (setup->b.wValue.w > 0);
 | ||
|  |       can_init_all();
 | ||
|  |       break;
 | ||
|  |     // **** 0xe6: set USB power
 | ||
|  |     case 0xe6:
 | ||
|  |       if (revision == PANDA_REV_C) {
 | ||
|  |         if (setup->b.wValue.w == 1) {
 | ||
|  |           puts("user setting CDP mode\n");
 | ||
|  |           set_usb_power_mode(USB_POWER_CDP);
 | ||
|  |         } else if (setup->b.wValue.w == 2) {
 | ||
|  |           puts("user setting DCP mode\n");
 | ||
|  |           set_usb_power_mode(USB_POWER_DCP);
 | ||
|  |         } else {
 | ||
|  |           puts("user setting CLIENT mode\n");
 | ||
|  |           set_usb_power_mode(USB_POWER_CLIENT);
 | ||
|  |         }
 | ||
|  |       }
 | ||
|  |       break;
 | ||
|  |     // **** 0xf0: do k-line wValue pulse on uart2 for Acura
 | ||
|  |     case 0xf0:
 | ||
|  |       if (setup->b.wValue.w == 1) {
 | ||
|  |         GPIOC->ODR &= ~(1 << 10);
 | ||
|  |         GPIOC->MODER &= ~GPIO_MODER_MODER10_1;
 | ||
|  |         GPIOC->MODER |= GPIO_MODER_MODER10_0;
 | ||
|  |       } else {
 | ||
|  |         GPIOC->ODR &= ~(1 << 12);
 | ||
|  |         GPIOC->MODER &= ~GPIO_MODER_MODER12_1;
 | ||
|  |         GPIOC->MODER |= GPIO_MODER_MODER12_0;
 | ||
|  |       }
 | ||
|  | 
 | ||
|  |       for (i = 0; i < 80; i++) {
 | ||
|  |         delay(8000);
 | ||
|  |         if (setup->b.wValue.w == 1) {
 | ||
|  |           GPIOC->ODR |= (1 << 10);
 | ||
|  |           GPIOC->ODR &= ~(1 << 10);
 | ||
|  |         } else {
 | ||
|  |           GPIOC->ODR |= (1 << 12);
 | ||
|  |           GPIOC->ODR &= ~(1 << 12);
 | ||
|  |         }
 | ||
|  |       }
 | ||
|  | 
 | ||
|  |       if (setup->b.wValue.w == 1) {
 | ||
|  |         GPIOC->MODER &= ~GPIO_MODER_MODER10_0;
 | ||
|  |         GPIOC->MODER |= GPIO_MODER_MODER10_1;
 | ||
|  |       } else {
 | ||
|  |         GPIOC->MODER &= ~GPIO_MODER_MODER12_0;
 | ||
|  |         GPIOC->MODER |= GPIO_MODER_MODER12_1;
 | ||
|  |       }
 | ||
|  | 
 | ||
|  |       delay(140 * 9000);
 | ||
|  |       break;
 | ||
|  |     // **** 0xf1: Clear CAN ring buffer.
 | ||
|  |     case 0xf1:
 | ||
|  |       if (setup->b.wValue.w == 0xFFFF) {
 | ||
|  |         puts("Clearing CAN Rx queue\n");
 | ||
|  |         can_clear(&can_rx_q);
 | ||
|  |       } else if (setup->b.wValue.w < BUS_MAX) {
 | ||
|  |         puts("Clearing CAN Tx queue\n");
 | ||
|  |         can_clear(can_queues[setup->b.wValue.w]);
 | ||
|  |       }
 | ||
|  |       break;
 | ||
|  |     // **** 0xf2: Clear UART ring buffer.
 | ||
|  |     case 0xf2:
 | ||
|  |       {
 | ||
|  |         uart_ring * rb = get_ring_by_number(setup->b.wValue.w);
 | ||
|  |         if (rb) {
 | ||
|  |           puts("Clearing UART queue.\n");
 | ||
|  |           clear_uart_buff(rb);
 | ||
|  |         }
 | ||
|  |         break;
 | ||
|  |       }
 | ||
|  |     default:
 | ||
|  |       puts("NO HANDLER ");
 | ||
|  |       puth(setup->b.bRequest);
 | ||
|  |       puts("\n");
 | ||
|  |       break;
 | ||
|  |   }
 | ||
|  |   return resp_len;
 | ||
|  | }
 | ||
|  | 
 | ||
|  | #ifdef PANDA
 | ||
|  | int spi_cb_rx(uint8_t *data, int len, uint8_t *data_out) {
 | ||
|  |   // data[0]  = endpoint
 | ||
|  |   // data[2]  = length
 | ||
|  |   // data[4:] = data
 | ||
|  | 
 | ||
|  |   int resp_len = 0;
 | ||
|  |   switch (data[0]) {
 | ||
|  |     case 0:
 | ||
|  |       // control transfer
 | ||
|  |       resp_len = usb_cb_control_msg((USB_Setup_TypeDef *)(data+4), data_out, 0);
 | ||
|  |       break;
 | ||
|  |     case 1:
 | ||
|  |       // ep 1, read
 | ||
|  |       resp_len = usb_cb_ep1_in(data_out, 0x40, 0);
 | ||
|  |       break;
 | ||
|  |     case 2:
 | ||
|  |       // ep 2, send serial
 | ||
|  |       usb_cb_ep2_out(data+4, data[2], 0);
 | ||
|  |       break;
 | ||
|  |     case 3:
 | ||
|  |       // ep 3, send CAN
 | ||
|  |       usb_cb_ep3_out(data+4, data[2], 0);
 | ||
|  |       break;
 | ||
|  |   }
 | ||
|  |   return resp_len;
 | ||
|  | }
 | ||
|  | 
 | ||
|  | #else
 | ||
|  | 
 | ||
|  | int spi_cb_rx(uint8_t *data, int len, uint8_t *data_out) { return 0; };
 | ||
|  | 
 | ||
|  | #endif
 | ||
|  | 
 | ||
|  | 
 | ||
|  | // ***************************** main code *****************************
 | ||
|  | 
 | ||
|  | void __initialize_hardware_early() {
 | ||
|  |   early();
 | ||
|  | }
 | ||
|  | 
 | ||
| 
											8 years ago
										 | void __attribute__ ((noinline)) enable_fpu() {
 | ||
|  |   // enable the FPU
 | ||
|  |   SCB->CPACR |= ((3UL << 10*2) | (3UL << 11*2));
 | ||
|  | }
 | ||
|  | 
 | ||
| 
											8 years ago
										 | int main() {
 | ||
|  |   // shouldn't have interrupts here, but just in case
 | ||
|  |   __disable_irq();
 | ||
|  | 
 | ||
|  |   // init early devices
 | ||
|  |   clock_init();
 | ||
|  |   periph_init();
 | ||
|  |   detect();
 | ||
|  | 
 | ||
|  |   // print hello
 | ||
|  |   puts("\n\n\n************************ MAIN START ************************\n");
 | ||
|  | 
 | ||
|  |   // detect the revision and init the GPIOs
 | ||
|  |   puts("config:\n");
 | ||
|  |   #ifdef PANDA
 | ||
|  |     puts(revision == PANDA_REV_C ? "  panda rev c\n" : "  panda rev a or b\n");
 | ||
|  |   #else
 | ||
|  |     puts("  legacy\n");
 | ||
|  |   #endif
 | ||
|  |   puts(has_external_debug_serial ? "  real serial\n" : "  USB serial\n");
 | ||
|  |   puts(is_giant_panda ? "  GIANTpanda detected\n" : "  not GIANTpanda\n");
 | ||
| 
											8 years ago
										 |   puts(is_grey_panda ? "  gray panda detected!\n" : "  white panda\n");
 | ||
| 
											8 years ago
										 |   puts(is_entering_bootmode ? "  ESP wants bootmode\n" : "  no bootmode\n");
 | ||
|  |   gpio_init();
 | ||
|  | 
 | ||
| 
											8 years ago
										 | #ifdef PANDA
 | ||
|  |   // panda has an FPU, let's use it!
 | ||
|  |   enable_fpu();
 | ||
|  | #endif
 | ||
|  | 
 | ||
| 
											8 years ago
										 |   // enable main uart if it's connected
 | ||
|  |   if (has_external_debug_serial) {
 | ||
|  |     // WEIRDNESS: without this gate around the UART, it would "crash", but only if the ESP is enabled
 | ||
|  |     // assuming it's because the lines were left floating and spurious noise was on them
 | ||
|  |     uart_init(USART2, 115200);
 | ||
|  |   }
 | ||
|  | 
 | ||
|  | #ifdef PANDA
 | ||
| 
											8 years ago
										 |   if (is_grey_panda) {
 | ||
|  |     uart_init(USART1, 9600);
 | ||
|  |   } else {
 | ||
|  |     // enable ESP uart
 | ||
|  |     uart_init(USART1, 115200);
 | ||
|  |   }
 | ||
| 
											8 years ago
										 |   // enable LIN
 | ||
|  |   uart_init(UART5, 10400);
 | ||
|  |   UART5->CR2 |= USART_CR2_LINEN;
 | ||
|  |   uart_init(USART3, 10400);
 | ||
|  |   USART3->CR2 |= USART_CR2_LINEN;
 | ||
|  | #endif
 | ||
|  | 
 | ||
|  |   // init microsecond system timer
 | ||
|  |   // increments 1000000 times per second
 | ||
|  |   // generate an update to set the prescaler
 | ||
|  |   TIM2->PSC = 48-1;
 | ||
|  |   TIM2->CR1 = TIM_CR1_CEN;
 | ||
|  |   TIM2->EGR = TIM_EGR_UG;
 | ||
|  |   // use TIM2->CNT to read
 | ||
|  | 
 | ||
|  |   // enable USB
 | ||
|  |   usb_init();
 | ||
|  | 
 | ||
|  |   // default to silent mode to prevent issues with Ford
 | ||
| 
											7 years ago
										 |   // hardcode a specific safety mode if you want to force the panda to be in a specific mode
 | ||
| 
											8 years ago
										 |   safety_set_mode(SAFETY_NOOUTPUT, 0);
 | ||
| 
											8 years ago
										 |   can_silent = ALL_CAN_SILENT;
 | ||
|  |   can_init_all();
 | ||
|  | 
 | ||
|  |   adc_init();
 | ||
|  | 
 | ||
|  | #ifdef PANDA
 | ||
|  |   spi_init();
 | ||
|  | #endif
 | ||
|  | 
 | ||
|  |   // set PWM
 | ||
|  |   fan_init();
 | ||
|  |   fan_set_speed(0);
 | ||
|  | 
 | ||
|  |   puts("**** INTERRUPTS ON ****\n");
 | ||
|  | 
 | ||
|  |   __enable_irq();
 | ||
|  | 
 | ||
| 
											8 years ago
										 |   // if the error interrupt is enabled to quickly when the CAN bus is active
 | ||
|  |   // something bad happens and you can't connect to the device over USB
 | ||
|  |   delay(10000000);
 | ||
|  |   CAN1->IER |= CAN_IER_ERRIE | CAN_IER_LECIE;
 | ||
|  | 
 | ||
| 
											8 years ago
										 |   // LED should keep on blinking all the time
 | ||
|  |   uint64_t cnt = 0;
 | ||
|  | 
 | ||
|  |   #ifdef PANDA
 | ||
|  |     uint64_t marker = 0;
 | ||
|  |     #define CURRENT_THRESHOLD 0xF00
 | ||
|  |     #define CLICKS 8
 | ||
| 
											7 years ago
										 |     // Enough clicks to ensure that enumeration happened. Should be longer than bootup time of the device connected to EON
 | ||
|  |     #define CLICKS_BOOTUP 30
 | ||
| 
											8 years ago
										 |   #endif
 | ||
|  | 
 | ||
|  |   for (cnt=0;;cnt++) {
 | ||
|  |     can_live = pending_can_live;
 | ||
|  | 
 | ||
| 
											8 years ago
										 |     //puth(usart1_dma); puts(" "); puth(DMA2_Stream5->M0AR); puts(" "); puth(DMA2_Stream5->NDTR); puts("\n");
 | ||
|  | 
 | ||
| 
											8 years ago
										 |     #ifdef PANDA
 | ||
|  |       int current = adc_get(ADCCHAN_CURRENT);
 | ||
|  | 
 | ||
|  |       switch (usb_power_mode) {
 | ||
|  |         case USB_POWER_CLIENT:
 | ||
|  |           if ((cnt-marker) >= CLICKS) {
 | ||
|  |             if (!is_enumerated) {
 | ||
|  |               puts("USBP: didn't enumerate, switching to CDP mode\n");
 | ||
|  |               // switch to CDP
 | ||
|  |               set_usb_power_mode(USB_POWER_CDP);
 | ||
|  |               marker = cnt;
 | ||
|  |             }
 | ||
|  |           }
 | ||
|  |           // keep resetting the timer if it's enumerated
 | ||
|  |           if (is_enumerated) {
 | ||
|  |             marker = cnt;
 | ||
|  |           }
 | ||
|  |           break;
 | ||
|  |         case USB_POWER_CDP:
 | ||
| 
											7 years ago
										 |           // been CLICKS_BOOTUP clicks since we switched to CDP
 | ||
|  |           if ((cnt-marker) >= CLICKS_BOOTUP ) {
 | ||
| 
											8 years ago
										 |             // measure current draw, if positive and no enumeration, switch to DCP
 | ||
|  |             if (!is_enumerated && current < CURRENT_THRESHOLD) {
 | ||
|  |               puts("USBP: no enumeration with current draw, switching to DCP mode\n");
 | ||
|  |               set_usb_power_mode(USB_POWER_DCP);
 | ||
|  |               marker = cnt;
 | ||
|  |             }
 | ||
|  |           }
 | ||
|  |           // keep resetting the timer if there's no current draw in CDP
 | ||
|  |           if (current >= CURRENT_THRESHOLD) {
 | ||
|  |             marker = cnt;
 | ||
|  |           }
 | ||
|  |           break;
 | ||
|  |         case USB_POWER_DCP:
 | ||
|  |           // been at least CLICKS clicks since we switched to DCP
 | ||
|  |           if ((cnt-marker) >= CLICKS) {
 | ||
|  |             // if no current draw, switch back to CDP
 | ||
|  |             if (current >= CURRENT_THRESHOLD) {
 | ||
|  |               puts("USBP: no current draw, switching back to CDP mode\n");
 | ||
|  |               set_usb_power_mode(USB_POWER_CDP);
 | ||
|  |               marker = cnt;
 | ||
|  |             }
 | ||
|  |           }
 | ||
|  |           // keep resetting the timer if there's current draw in DCP
 | ||
|  |           if (current < CURRENT_THRESHOLD) {
 | ||
|  |             marker = cnt;
 | ||
|  |           }
 | ||
|  |           break;
 | ||
|  |       }
 | ||
|  | 
 | ||
|  |       // ~0x9a = 500 ma
 | ||
|  |       /*puth(current);
 | ||
|  |       puts("\n");*/
 | ||
|  |     #endif
 | ||
|  | 
 | ||
|  |     // reset this every 16th pass
 | ||
|  |     if ((cnt&0xF) == 0) pending_can_live = 0;
 | ||
|  | 
 | ||
|  |     #ifdef DEBUG
 | ||
|  |       puts("** blink ");
 | ||
|  |       puth(can_rx_q.r_ptr); puts(" "); puth(can_rx_q.w_ptr); puts("  ");
 | ||
|  |       puth(can_tx1_q.r_ptr); puts(" "); puth(can_tx1_q.w_ptr); puts("  ");
 | ||
|  |       puth(can_tx2_q.r_ptr); puts(" "); puth(can_tx2_q.w_ptr); puts("\n");
 | ||
|  |     #endif
 | ||
|  | 
 | ||
|  |     // set green LED to be controls allowed
 | ||
|  |     set_led(LED_GREEN, controls_allowed);
 | ||
|  | 
 | ||
|  |     // blink the red LED
 | ||
|  |     int div_mode = ((usb_power_mode == USB_POWER_DCP) ? 4 : 1);
 | ||
|  | 
 | ||
|  |     for (int div_mode_loop = 0; div_mode_loop < div_mode; div_mode_loop++) {
 | ||
|  |       for (int fade = 0; fade < 1024; fade += 8) {
 | ||
|  |         for (int i = 0; i < 128/div_mode; i++) {
 | ||
|  |           set_led(LED_RED, 0);
 | ||
|  |           if (fade < 512) { delay(512-fade); } else { delay(fade-512); }
 | ||
|  |           set_led(LED_RED, 1);
 | ||
|  |           if (fade < 512) { delay(fade); } else { delay(1024-fade); }
 | ||
|  |         }
 | ||
|  |       }
 | ||
|  |     }
 | ||
|  | 
 | ||
|  |     // turn off the blue LED, turned on by CAN
 | ||
|  |     #ifdef PANDA
 | ||
|  |       set_led(LED_BLUE, 0);
 | ||
|  |     #endif
 | ||
|  |   }
 | ||
|  | 
 | ||
|  |   return 0;
 | ||
|  | }
 |