// ********************* Includes ********************* #include "board/config.h" #include "board/safety.h" #include "board/drivers/pwm.h" #include "board/drivers/usb.h" #include "board/early_init.h" #include "board/provision.h" #include "board/health.h" #include "jungle_health.h" #include "board/drivers/can_common.h" #ifdef STM32H7 #include "board/drivers/fdcan.h" #else #include "board/drivers/bxcan.h" #endif #include "board/obj/gitversion.h" #include "board/can_comms.h" #include "main_comms.h" // ********************* Serial debugging ********************* void debug_ring_callback(uart_ring *ring) { char rcv; while (get_char(ring, &rcv)) { (void)injectc(ring, rcv); } } // ***************************** main code ***************************** // cppcheck-suppress unusedFunction ; used in headers not included in cppcheck void __initialize_hardware_early(void) { early_initialization(); } void __attribute__ ((noinline)) enable_fpu(void) { // enable the FPU SCB->CPACR |= ((3UL << (10U * 2U)) | (3UL << (11U * 2U))); } // called at 8Hz uint32_t loop_counter = 0U; uint16_t button_press_cnt = 0U; void tick_handler(void) { if (TICK_TIMER->SR != 0) { if (generated_can_traffic) { for (int i = 0; i < 3; i++) { if (can_health[i].transmit_error_cnt >= 128) { (void)llcan_init(CANIF_FROM_CAN_NUM(i)); } } } // tick drivers at 8Hz usb_tick(); // decimated to 1Hz if ((loop_counter % 8) == 0U) { #ifdef DEBUG print("** blink "); print("rx:"); puth4(can_rx_q.r_ptr); print("-"); puth4(can_rx_q.w_ptr); print(" "); print("tx1:"); puth4(can_tx1_q.r_ptr); print("-"); puth4(can_tx1_q.w_ptr); print(" "); print("tx2:"); puth4(can_tx2_q.r_ptr); print("-"); puth4(can_tx2_q.w_ptr); print(" "); print("tx3:"); puth4(can_tx3_q.r_ptr); print("-"); puth4(can_tx3_q.w_ptr); print("\n"); #endif current_board->board_tick(); // check registers check_registers(); // turn off the blue LED, turned on by CAN current_board->set_led(LED_BLUE, false); // Blink and OBD CAN #ifdef FINAL_PROVISIONING current_board->set_can_mode(can_mode == CAN_MODE_NORMAL ? CAN_MODE_OBD_CAN2 : CAN_MODE_NORMAL); #endif // on to the next one uptime_cnt += 1U; } current_board->set_led(LED_GREEN, green_led_enabled); // Check on button bool current_button_status = current_board->get_button(); if (current_button_status && button_press_cnt == 10) { current_board->set_panda_power(!panda_power); } #ifdef FINAL_PROVISIONING // Ignition blinking uint8_t ignition_bitmask = 0U; for (uint8_t i = 0U; i < 6U; i++) { ignition_bitmask |= ((loop_counter % 12U) < ((uint32_t) i + 2U)) << i; } current_board->set_individual_ignition(ignition_bitmask); // SBU voltage reporting if (current_board->has_sbu_sense) { for (uint8_t i = 0U; i < 6U; i++) { CANPacket_t pkt = { 0 }; pkt.data_len_code = 8U; pkt.addr = 0x100U + i; *(uint16_t *) &pkt.data[0] = current_board->get_sbu_mV(i + 1U, SBU1); *(uint16_t *) &pkt.data[2] = current_board->get_sbu_mV(i + 1U, SBU2); pkt.data[4] = (ignition_bitmask >> i) & 1U; can_set_checksum(&pkt); can_send(&pkt, 0U, false); } } #else // toggle ignition on button press static bool prev_button_status = false; if (!current_button_status && prev_button_status && button_press_cnt < 10){ current_board->set_ignition(!ignition); } prev_button_status = current_button_status; #endif button_press_cnt = current_button_status ? button_press_cnt + 1 : 0; loop_counter++; } TICK_TIMER->SR = 0; } int main(void) { // Init interrupt table init_interrupts(true); // shouldn't have interrupts here, but just in case disable_interrupts(); // init early devices clock_init(); peripherals_init(); detect_board_type(); // red+green leds enabled until succesful USB init, as a debug indicator current_board->set_led(LED_RED, true); current_board->set_led(LED_GREEN, true); // print hello print("\n\n\n************************ MAIN START ************************\n"); // check for non-supported board types if (hw_type == HW_TYPE_UNKNOWN) { print("Unsupported board type\n"); while (1) { /* hang */ } } print("Config:\n"); print(" Board type: 0x"); puth(hw_type); print("\n"); // init board current_board->init(); // we have an FPU, let's use it! enable_fpu(); microsecond_timer_init(); // 8Hz timer REGISTER_INTERRUPT(TICK_TIMER_IRQ, tick_handler, 10U, FAULT_INTERRUPT_RATE_TICK) tick_timer_init(); #ifdef DEBUG print("DEBUG ENABLED\n"); #endif // enable USB (right before interrupts or enum can fail!) usb_init(); current_board->set_led(LED_RED, false); current_board->set_led(LED_GREEN, false); print("**** INTERRUPTS ON ****\n"); enable_interrupts(); can_silent = ALL_CAN_LIVE; set_safety_hooks(SAFETY_ALLOUTPUT, 0U); can_init_all(); current_board->set_harness_orientation(HARNESS_ORIENTATION_1); #ifdef FINAL_PROVISIONING print("---- FINAL PROVISIONING BUILD ---- \n"); can_set_forwarding(0, 2); can_set_forwarding(1, 2); #endif // LED should keep on blinking all the time uint32_t cnt = 0; for (cnt=0;;cnt++) { if (generated_can_traffic) { // fill up all the queues can_ring *qs[] = {&can_tx1_q, &can_tx2_q, &can_tx3_q}; for (int j = 0; j < 3; j++) { for (uint16_t n = 0U; n < can_slots_empty(qs[j]); n++) { uint16_t i = cnt % 100U; CANPacket_t to_send; to_send.returned = 0U; to_send.rejected = 0U; to_send.extended = 0U; to_send.addr = 0x200U + i; to_send.bus = i % 3U; to_send.data_len_code = i % 8U; (void)memcpy(to_send.data, "\xff\xff\xff\xff\xff\xff\xff\xff", dlc_to_len[to_send.data_len_code]); can_set_checksum(&to_send); can_send(&to_send, to_send.bus, true); } } delay(1000); continue; } // useful for debugging, fade breaks = panda is overloaded for (uint32_t fade = 0U; fade < MAX_LED_FADE; fade += 1U) { current_board->set_led(LED_RED, true); delay(fade >> 4); current_board->set_led(LED_RED, false); delay((MAX_LED_FADE - fade) >> 4); } for (uint32_t fade = MAX_LED_FADE; fade > 0U; fade -= 1U) { current_board->set_led(LED_RED, true); delay(fade >> 4); current_board->set_led(LED_RED, false); delay((MAX_LED_FADE - fade) >> 4); } } return 0; }