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.
488 lines
16 KiB
488 lines
16 KiB
/* |
|
(c) 2017 night_ghost@ykoctpa.ru |
|
|
|
*/ |
|
|
|
#pragma GCC optimize ("O2") |
|
|
|
#include <AP_HAL/AP_HAL.h> |
|
|
|
#if CONFIG_HAL_BOARD == HAL_BOARD_F4LIGHT |
|
#include <assert.h> |
|
#include <AP_HAL_F4Light/AP_HAL_F4Light.h> |
|
#include "AP_HAL_F4Light_Namespace.h" |
|
#include "AP_HAL_F4Light_Private.h" |
|
#include "HAL_F4Light_Class.h" |
|
#include "RCInput.h" |
|
#include "Util.h" |
|
|
|
#include <AP_Param_Helper/AP_Param_Helper.h> |
|
|
|
#include "UART_PPM.h" |
|
|
|
#if defined(USE_SOFTSERIAL) |
|
#include "UART_SoftDriver.h" |
|
#endif |
|
|
|
|
|
|
|
#if defined(BOARD_SDCARD_NAME) || defined(BOARD_DATAFLASH_FATFS) |
|
#include "sd/SD.h" |
|
#endif |
|
|
|
#if defined(BOARD_OSD_CS_PIN) |
|
#include "UART_OSD.h" |
|
#endif |
|
|
|
#if defined(USB_MASSSTORAGE) |
|
#include "massstorage/mass_storage.h" |
|
#endif |
|
|
|
using namespace F4Light; |
|
|
|
|
|
static F4Light::I2CDeviceManager i2c_mgr_instance; |
|
|
|
// XXX make sure these are assigned correctly |
|
static USBDriver USB_Driver(1); // ACM |
|
static UARTDriver uart1Driver(_USART1); // main port |
|
|
|
#if defined(BOARD_USART6_RX_PIN) && defined(BOARD_USART6_TX_PIN) |
|
static UARTDriver uart6Driver(_USART6); // pin 7&8(REVO)/5&6(RevoMini) of input port |
|
#endif |
|
|
|
|
|
#ifdef BOARD_HAS_UART3 |
|
static UARTDriver uart3Driver(_USART3); // flexi port |
|
// static SerialDriver IN_CCM softDriver(BOARD_SOFTSERIAL_TX, BOARD_SOFTSERIAL_RX, false); // pin 7&8 of input port |
|
#endif |
|
|
|
#if defined(BOARD_SOFT_UART3) || defined(USE_SOFTSERIAL) |
|
static SerialDriver IN_CCM softDriver(BOARD_SOFTSERIAL_TX, BOARD_SOFTSERIAL_RX, false); |
|
#endif |
|
|
|
|
|
#ifdef BOARD_OSD_CS_PIN |
|
static UART_OSD uartOSDdriver; |
|
#endif |
|
|
|
#if defined(BOARD_USART4_RX_PIN) && defined( BOARD_USART4_TX_PIN) |
|
static UARTDriver uart4Driver(_UART4); // pin 5&6 of servo port |
|
#endif |
|
|
|
#if defined(BOARD_USART5_RX_PIN) && defined( BOARD_USART5_TX_PIN) |
|
static UARTDriver uart5Driver(_UART5); |
|
#endif |
|
|
|
static UART_PPM uartPPM2(1); // PPM2 input |
|
static UART_PPM uartPPM1(0); // PPM1 input |
|
|
|
|
|
|
|
// only for DSM satellite, served in rc_input |
|
//static UARTDriver uart5Driver(_UART5,0); // D26/PD2 6 EXTI_RFM22B / UART5_RX input-only UART for DSM satellite |
|
|
|
/* |
|
input port pinout |
|
1 2 3 4 5 6 7 8 |
|
pin b14 b15 c6 c7 c8 c9 |
|
gnd vcc PPM buzz 6_tx 6_rx Sscl Ssda |
|
USE_SOFTSERIAL -> S_tx S_rx |
|
servos -> srv7 srv8 srv9 srv10 srv11 srv12 |
|
*/ |
|
|
|
|
|
/* OPLINK AIR port pinout |
|
1 2 3 4 5 6 7 |
|
|
|
gnd +5 26 103 |
|
rx pow |
|
*/ |
|
|
|
static F4Light::SPIDeviceManager spiDeviceManager; |
|
static AnalogIn analogIn IN_CCM; |
|
static Storage storageDriver; |
|
static GPIO gpioDriver; |
|
static RCInput rcinDriver; |
|
static RCOutput rcoutDriver; |
|
static Scheduler schedulerInstance; |
|
static Util utilInstance; |
|
|
|
HAL_state HAL_F4Light::state; |
|
|
|
//const AP_HAL::UARTDriver** HAL_F4Light::uarts[] = { &uartA, &uartB, &uartC, &uartD, &uartE, &uartF }; |
|
|
|
/* |
|
AP_HAL::UARTDriver* _uartA, // console |
|
AP_HAL::UARTDriver* _uartB, // 1st GPS |
|
AP_HAL::UARTDriver* _uartC, // telem1 |
|
AP_HAL::UARTDriver* _uartD, // telem2 |
|
AP_HAL::UARTDriver* _uartE, // 2nd GPS |
|
AP_HAL::UARTDriver* _uartF, // extra1 |
|
|
|
|
|
AP_SerialManager.cpp line 159 |
|
// initialise pointers to serial ports |
|
state[1].uart = hal.uartC; // serial1, uartC, normally telem1 |
|
state[2].uart = hal.uartD; // serial2, uartD, normally telem2 |
|
state[3].uart = hal.uartB; // serial3, uartB, normally 1st GPS |
|
state[4].uart = hal.uartE; // serial4, uartE, normally 2nd GPS |
|
state[5].uart = hal.uartF; // serial5 |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
HAL_F4Light::HAL_F4Light() : |
|
AP_HAL::HAL( |
|
&USB_Driver, // uartA - USB console - Serial0 |
|
|
|
#if BOARD_UARTS_LAYOUT == 1 // Revolution |
|
|
|
&uart6Driver, // uartB - pin 7&8(REVO)/5&6(RevoMini) of input port - for GPS - Serial3 |
|
&uart1Driver, // uartC - main port - for telemetry - Serial1 |
|
&uart3Driver, // uartD - flexi port - Serial2 |
|
&uart4Driver, // uartE - PWM pins 5&6 - Serial4 |
|
&softDriver, // uartF - soft UART on pins 7&8 - Serial5 |
|
|
|
#elif BOARD_UARTS_LAYOUT == 2 // Airbot |
|
|
|
&uart6Driver, // uartB - pin 7&8(REVO)/5&6(RevoMini) of input port - for GPS - Serial3 |
|
&uart1Driver, // uartC - main port - for telemetry - Serial1 |
|
&uart4Driver, // uartD - PWM pins 5&6 - Serial2 |
|
&uartPPM2, // uartE - input data from PPM2 pin - Serial4 |
|
&uartPPM1, // uartF - input data from PPM1 pin - Serial5 |
|
|
|
#elif BOARD_UARTS_LAYOUT == 3 // AirbotV2 |
|
|
|
&uart6Driver, // uartB - pin 7&8(REVO)/5&6(RevoMini) of input port - for GPS - Serial3 |
|
&uart1Driver, // uartC - main port - for telemetry - Serial1 |
|
&uartOSDdriver, // uartD - OSD emulated UART - Serial2 |
|
&uart4Driver, // uartE - PWM pins 5&6 - Serial4 |
|
&uartPPM2, // uartF - input data from PPM2 pin - Serial5 |
|
|
|
#elif BOARD_UARTS_LAYOUT == 4 // MiniOSD |
|
|
|
&uart6Driver, // uartB - pin 7&8(REVO)/5&6(RevoMini) of input port - for GPS - Serial3 |
|
&uart1Driver, // uartC - main port - for telemetry - Serial1 |
|
NULL, |
|
NULL, |
|
NULL, |
|
|
|
#elif BOARD_UARTS_LAYOUT == 5 // MicroOSD |
|
|
|
&uart6Driver, // uartB - pin 7&8(REVO)/5&6(RevoMini) of input port - for GPS - Serial3 |
|
&uart1Driver, // uartC - main port - for telemetry - Serial1 |
|
NULL, |
|
NULL, |
|
NULL, |
|
|
|
#elif BOARD_UARTS_LAYOUT == 6 // MatekF405_CTR |
|
|
|
&uart4Driver, // uartB - UART4 for GPS - Serial3 |
|
&uart1Driver, // uartC - UART1 for telemetry - Serial1 |
|
&uartOSDdriver, // uartD - OSD emulated UART - Serial2 |
|
&uart3Driver, // uartE - UART3 - Serial4 |
|
&uart5Driver, // uartF - UART5 - Serial5 |
|
|
|
#elif BOARD_UARTS_LAYOUT == 7 // Cl_Racing F4 |
|
|
|
&uart6Driver, // uartB - pin 7&8(REVO)/5&6(RevoMini) of input port - for GPS - Serial3 |
|
&uart1Driver, // uartC - main port - for telemetry - Serial1 |
|
&uartOSDdriver, // uartD - OSD emulated UART - Serial2 |
|
&uartPPM1, // uartE - input data from PPM1 pin - Serial4 |
|
NULL, // no uartF |
|
|
|
#else |
|
#error no BOARD_UARTS_LAYOUT! |
|
#endif |
|
|
|
&i2c_mgr_instance, // I2C |
|
&spiDeviceManager, // spi |
|
&analogIn, // analogin |
|
&storageDriver, // storage |
|
&HAL_CONSOLE, // console via radio or USB on per-board basis |
|
&gpioDriver, // gpio |
|
&rcinDriver, // rcinput |
|
&rcoutDriver, // rcoutput |
|
&schedulerInstance, // scheduler |
|
&utilInstance, // util |
|
nullptr, // no onboard optical flow |
|
nullptr // no CAN |
|
) |
|
|
|
// 0 1 2 3 4 5 |
|
// USB Main Flexi/OSD Uart4 UART6 Soft/Uart4 |
|
, uarts{ &uartA, &uartC, &uartD, &uartE, &uartB, &uartF } |
|
|
|
{ |
|
|
|
uint32_t sig = board_get_rtc_register(RTC_CONSOLE_REG); |
|
if( (sig & ~CONSOLE_PORT_MASK) == CONSOLE_PORT_SIGNATURE) { |
|
AP_HAL::UARTDriver** up = uarts[sig & CONSOLE_PORT_MASK]; |
|
if(up){ |
|
console = *up; |
|
} |
|
} |
|
} |
|
|
|
extern const AP_HAL::HAL& hal; |
|
|
|
|
|
void HAL_F4Light::run(int argc,char* const argv[], Callbacks* callbacks) const |
|
{ |
|
assert(callbacks); |
|
|
|
/* initialize all drivers and private members here. |
|
* up to the programmer to do this in the correct order. |
|
* Scheduler should likely come first. */ |
|
|
|
scheduler->init(); |
|
|
|
uint32_t start_t = AP_HAL::millis(); |
|
|
|
gpio->init(); |
|
|
|
rcout->init(); |
|
|
|
usart_disable_all(); |
|
|
|
{ |
|
#if defined(USB_MASSSTORAGE) |
|
uint32_t sig = board_get_rtc_register(RTC_MASS_STORAGE_REG); |
|
if( sig == MASS_STORAGE_SIGNATURE) { |
|
board_set_rtc_register(0, RTC_MASS_STORAGE_REG); |
|
|
|
#if defined(BOARD_SDCARD_NAME) && defined(BOARD_SDCARD_CS_PIN) |
|
SD.begin(F4Light::SPIDeviceManager::_get_device(BOARD_SDCARD_NAME)); |
|
#elif defined(BOARD_DATAFLASH_FATFS) |
|
SD.begin(F4Light::SPIDeviceManager::_get_device(HAL_DATAFLASH_NAME)); |
|
#endif |
|
state.sd_busy=true; |
|
massstorage.setup(); // init USB as mass-storage |
|
} |
|
else |
|
#endif |
|
{ |
|
extern void usb_init(); // init as VCP |
|
usb_init(); // moved from boards.cpp |
|
|
|
uartA->begin(115200); // uartA is the USB serial port used for the console, so lets make sure it is initialized at boot |
|
} |
|
} |
|
|
|
|
|
if(console != uartA) { |
|
console->begin(57600); // init telemetry port as console |
|
} |
|
|
|
|
|
rcin->init(); |
|
|
|
storage->init(); // Uses EEPROM.*, flash_stm* reworked |
|
analogin->init(); |
|
|
|
printf("\nHAL startup at %ldms\n", start_t); |
|
|
|
if(!state.sd_busy) { |
|
|
|
|
|
#if defined(BOARD_SDCARD_NAME) && defined(BOARD_SDCARD_CS_PIN) |
|
printf("\nEnabling SD at %ldms\n", AP_HAL::millis()); |
|
SD.begin(F4Light::SPIDeviceManager::_get_device(BOARD_SDCARD_NAME)); |
|
#elif defined(BOARD_DATAFLASH_FATFS) |
|
printf("\nEnabling DataFlash as SD at %ldms\n", AP_HAL::millis()); |
|
SD.begin(F4Light::SPIDeviceManager::_get_device(HAL_DATAFLASH_NAME)); |
|
#endif |
|
|
|
#if defined(BOARD_OSD_NAME) |
|
uartOSDdriver.begin(57600); // init OSD after SD but before call to lateInit(), but only if not in USB_STORAGE |
|
#endif |
|
|
|
} |
|
|
|
|
|
printf("\nHAL init done at %ldms\n", AP_HAL::millis()); |
|
|
|
callbacks->setup(); |
|
|
|
#if 0 //[ here is too late :( so we need a small hack and call lateInit from Scheduler::register_delay_callback |
|
// which called when parameters already initialized |
|
|
|
lateInit(); |
|
#endif //] |
|
|
|
|
|
scheduler->system_initialized(); // clear bootloader flag |
|
|
|
Scheduler::start_stats_task(); |
|
|
|
printf("\nLoop started at %ldms\n", AP_HAL::millis()); |
|
|
|
|
|
// main application loop hosted here! |
|
for (;;) { |
|
callbacks->loop(); |
|
// ((F4Light::Scheduler *)scheduler)->loop(); // to execute stats in main loop |
|
// ((F4Light::RCInput *)rcin)->loop(); // to execute debug in main loop |
|
} |
|
} |
|
|
|
|
|
static bool lateInitDone=false; |
|
|
|
void HAL_F4Light::lateInit() { |
|
|
|
if(lateInitDone) return; |
|
|
|
lateInitDone=true; |
|
|
|
{ |
|
uint32_t sig = board_get_rtc_register(RTC_CONSOLE_REG); |
|
uint8_t port = hal_param_helper->_console_uart; |
|
|
|
if(port < sizeof(uarts)/sizeof(AP_HAL::UARTDriver**) ){ |
|
|
|
if( (sig & ~CONSOLE_PORT_MASK) == CONSOLE_PORT_SIGNATURE) { |
|
if(port != (sig & CONSOLE_PORT_MASK)) { // wrong console - reboot needed |
|
board_set_rtc_register(CONSOLE_PORT_SIGNATURE | (port & CONSOLE_PORT_MASK), RTC_CONSOLE_REG); |
|
board_set_rtc_register(FORCE_APP_RTC_SIGNATURE, RTC_SIGNATURE_REG); // force bootloader to not wait |
|
Scheduler::_reboot(false); |
|
} |
|
} else { // no signature - set and check console |
|
board_set_rtc_register(CONSOLE_PORT_SIGNATURE | (port & CONSOLE_PORT_MASK), RTC_CONSOLE_REG); |
|
|
|
AP_HAL::UARTDriver** up = uarts[port]; |
|
if(up && *up != console) { |
|
board_set_rtc_register(FORCE_APP_RTC_SIGNATURE, RTC_SIGNATURE_REG); // force bootloader to not wait |
|
Scheduler::_reboot(false); |
|
} |
|
} |
|
} |
|
} |
|
{ |
|
uint32_t g = board_get_rtc_register(RTC_OV_GUARD_REG); |
|
uint32_t sig = board_get_rtc_register(RTC_OVERCLOCK_REG); |
|
uint8_t oc = hal_param_helper->_overclock; |
|
|
|
if(g==OV_GUARD_FAIL_SIGNATURE) { |
|
if(oc==0) { |
|
board_set_rtc_register(OVERCLOCK_SIGNATURE | oc, RTC_OVERCLOCK_REG); // set default clock |
|
board_set_rtc_register(0, RTC_OV_GUARD_REG); // and reset failure |
|
} else printf("\noverclocking failed!\n"); |
|
} else { |
|
|
|
if((sig & ~OVERCLOCK_SIG_MASK ) == OVERCLOCK_SIGNATURE ) { // if correct signature |
|
board_set_rtc_register(OVERCLOCK_SIGNATURE | oc, RTC_OVERCLOCK_REG); // set required clock in any case |
|
if((sig & OVERCLOCK_SIG_MASK) != oc) { // if wrong clock |
|
board_set_rtc_register(FORCE_APP_RTC_SIGNATURE, RTC_SIGNATURE_REG); // force bootloader to not wait |
|
Scheduler::_reboot(false); // then reboot required |
|
} |
|
} else { // no signature, write only if needed |
|
if(oc) board_set_rtc_register(OVERCLOCK_SIGNATURE | oc, RTC_OVERCLOCK_REG); // set required clock |
|
} |
|
} |
|
} |
|
|
|
{ // one-time connection to COM-port |
|
uint8_t conn = hal_param_helper->_connect_com; |
|
if(conn) { |
|
hal_param_helper->_connect_com = 0; |
|
hal_param_helper->_connect_com.save(); |
|
|
|
if(conn < sizeof(uarts)/sizeof(AP_HAL::UARTDriver**) ){ |
|
AP_HAL::UARTDriver** up = uarts[conn]; |
|
if(up && *up){ |
|
connect_uart(uartA,*up, NULL); |
|
} |
|
} else printf("\nWrong HAL_CONNECT_COM selected!"); |
|
|
|
} |
|
} |
|
|
|
#if defined(USB_MASSSTORAGE) |
|
if(!state.sd_busy){ |
|
uint8_t conn=hal_param_helper->_usb_storage; |
|
|
|
if(conn){ |
|
hal_param_helper->_usb_storage=0; |
|
hal_param_helper->_usb_storage.save(); |
|
|
|
board_set_rtc_register(MASS_STORAGE_SIGNATURE, RTC_MASS_STORAGE_REG); |
|
board_set_rtc_register(FORCE_APP_RTC_SIGNATURE, RTC_SIGNATURE_REG); // force bootloader to not wait |
|
Scheduler::_reboot(false); |
|
} |
|
} |
|
#endif |
|
|
|
#ifdef USE_SERIAL_4WAY_BLHELI_INTERFACE |
|
{ // one-time connection to ESC |
|
uint8_t conn = hal_param_helper->_connect_esc; |
|
|
|
if(conn){ |
|
hal_param_helper->_connect_esc = 0; |
|
hal_param_helper->_connect_esc.save(); |
|
|
|
conn-=1; |
|
|
|
if(conn < sizeof(uarts)/sizeof(AP_HAL::UARTDriver**) ){ |
|
AP_HAL::UARTDriver** up = uarts[conn]; |
|
if(up && *up){ |
|
RCOutput::do_4way_if(*up); |
|
} |
|
} else printf("\nWrong HAL_CONNECT_ESC selected!"); |
|
} |
|
} |
|
#endif |
|
|
|
RCOutput::lateInit(); // 2nd stage - now with loaded parameters |
|
|
|
// all another parameter-dependent inits |
|
|
|
#ifdef BOARD_I2C_FLEXI |
|
if(hal_param_helper->_flexi_i2c) { |
|
uart3Driver.end(); |
|
uart3Driver.disable(); // uses Flexi port occupied by I2C |
|
printf("\nUART3 disabled by I2C2\n"); |
|
} |
|
#endif |
|
I2CDevice::lateInit(); |
|
|
|
Storage::late_init(hal_param_helper->_eeprom_deferred); |
|
|
|
uint8_t flags=0; |
|
|
|
if(hal_param_helper->_rc_fs) flags |= BOARD_RC_FAILSAFE; |
|
|
|
RCInput::late_init(flags); |
|
} |
|
|
|
// 57600 gives ~6500 chars per second or 6 chars per ms |
|
void HAL_F4Light::connect_uart(AP_HAL::UARTDriver* uartL,AP_HAL::UARTDriver* uartR, AP_HAL::Proc proc){ |
|
while(1){ |
|
bool got=false; |
|
if(uartL->available() && uartR->txspace()) { uartR->write(uartL->read()); got=true; } |
|
if(uartR->available() && uartL->txspace()) { uartL->write(uartR->read()); got=true; } |
|
if(proc) proc(); |
|
if(!got) Scheduler::yield(100); // give a chance to other threads |
|
if(state.disconnect) break; // if USB disconnected |
|
} |
|
} |
|
|
|
static const HAL_F4Light hal_revo; |
|
|
|
const AP_HAL::HAL& AP_HAL::get_HAL() { |
|
return hal_revo; |
|
} |
|
|
|
|
|
extern "C" void usb_mass_mal_USBdisconnect(); |
|
|
|
void usb_mass_mal_USBdisconnect(){ |
|
HAL_F4Light::state.sd_busy=false; |
|
HAL_F4Light::state.disconnect=true; |
|
} |
|
|
|
#endif
|
|
|