AP_HAL_Linux: remove Qualcomm board support

This commit is contained in:
Francisco Ferreira 2018-05-11 13:26:52 +01:00 committed by Andrew Tridgell
parent 695d92ddbf
commit 5e821428a1
15 changed files with 0 additions and 1116 deletions

View File

@ -2,8 +2,6 @@
#include <AP_HAL/AP_HAL.h>
#if CONFIG_HAL_BOARD_SUBTYPE != HAL_BOARD_SUBTYPE_LINUX_QFLIGHT
#include <fcntl.h>
#include <stdio.h>
#include <sys/stat.h>
@ -244,5 +242,3 @@ fail_snprintf:
hal.console->printf("GPIO_Sysfs: Unable to export pin %u.\n", pin);
return false;
}
#endif

View File

@ -21,7 +21,6 @@
#include "OpticalFlow_Onboard.h"
#include "RCInput.h"
#include "RCInput_AioPRU.h"
#include "RCInput_DSM.h"
#include "RCInput_Navio2.h"
#include "RCInput_PRU.h"
#include "RCInput_RPI.h"
@ -153,8 +152,6 @@ static RCInput_ZYNQ rcinDriver;
static RCInput_UDP rcinDriver;
#elif CONFIG_HAL_BOARD_SUBTYPE == HAL_BOARD_SUBTYPE_LINUX_MINLURE
static RCInput_UART rcinDriver("/dev/ttyS5");
#elif CONFIG_HAL_BOARD_SUBTYPE == HAL_BOARD_SUBTYPE_LINUX_QFLIGHT
static RCInput_DSM rcinDriver;
#elif CONFIG_HAL_BOARD_SUBTYPE == HAL_BOARD_SUBTYPE_LINUX_DISCO
static RCInput_Multi rcinDriver{2, new RCInput_SBUS, new RCInput_115200("/dev/uart-sumd")};
#elif CONFIG_HAL_BOARD_SUBTYPE == HAL_BOARD_SUBTYPE_LINUX_AERO
@ -201,8 +198,6 @@ static RCOutput_PCA9685 rcoutDriver(i2c_mgr_instance.get_device(
/* UEFI with lpss set to PCI */
"pci0000:00/0000:00:18.6" },
PCA9685_PRIMARY_ADDRESS), false, 0, MINNOW_GPIO_S5_1);
#elif CONFIG_HAL_BOARD_SUBTYPE == HAL_BOARD_SUBTYPE_LINUX_QFLIGHT
static RCOutput_QFLIGHT rcoutDriver;
#elif CONFIG_HAL_BOARD_SUBTYPE == HAL_BOARD_SUBTYPE_LINUX_DISCO
static RCOutput_Disco rcoutDriver(i2c_mgr_instance.get_device(HAL_RCOUT_DISCO_BLDC_I2C_BUS, HAL_RCOUT_DISCO_BLDC_I2C_ADDR));
#elif CONFIG_HAL_BOARD_SUBTYPE == HAL_BOARD_SUBTYPE_LINUX_NAVIO2
@ -291,10 +286,6 @@ void HAL_Linux::run(int argc, char* const argv[], Callbacks* callbacks) const
{"uartD", true, 0, 'D'},
{"uartE", true, 0, 'E'},
{"uartF", true, 0, 'F'},
#if CONFIG_HAL_BOARD_SUBTYPE == HAL_BOARD_SUBTYPE_LINUX_QFLIGHT
{"dsm", true, 0, 'S'},
{"ESC", true, 0, 'e'},
#endif
{"log-directory", true, 0, 'l'},
{"terrain-directory", true, 0, 't'},
{"module-directory", true, 0, 'M'},
@ -328,14 +319,6 @@ void HAL_Linux::run(int argc, char* const argv[], Callbacks* callbacks) const
case 'F':
uartFDriver.set_device_path(gopt.optarg);
break;
#if CONFIG_HAL_BOARD_SUBTYPE == HAL_BOARD_SUBTYPE_LINUX_QFLIGHT
case 'e':
rcoutDriver.set_device_path(gopt.optarg);
break;
case 'S':
rcinDriver.set_device_path(gopt.optarg);
break;
#endif // CONFIG_HAL_BOARD_SUBTYPE
case 'l':
utilInstance.set_custom_log_directory(gopt.optarg);
break;

View File

@ -1,73 +0,0 @@
/*
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/*
this is a driver for DSM input in the QFLIGHT board. It could be
extended to other boards in future by providing an open/read/write
abstraction
*/
#include <AP_HAL/AP_HAL.h>
#if CONFIG_HAL_BOARD_SUBTYPE == HAL_BOARD_SUBTYPE_LINUX_QFLIGHT
#include "RCInput_DSM.h"
#include <AP_HAL_Linux/qflight/qflight_util.h>
#include <AP_HAL_Linux/qflight/qflight_dsp.h>
#include <stdio.h>
extern const AP_HAL::HAL& hal;
using namespace Linux;
void RCInput_DSM::init()
{
}
void RCInput_DSM::set_device_path(const char *path)
{
device_path = path;
printf("Set DSM device path %s\n", path);
}
void RCInput_DSM::_timer_tick(void)
{
if (device_path == nullptr) {
return;
}
int ret;
/*
we defer the open to the timer tick to ensure all RPC calls are
made in the same thread
*/
if (fd == -1) {
ret = qflight_UART_open(device_path, &fd);
if (ret == 0) {
printf("Opened DSM input %s fd=%d\n", device_path, (int)fd);
fflush(stdout);
qflight_UART_set_baudrate(fd, 115200);
}
}
if (fd != -1) {
uint8_t bytes[16];
int32_t nread;
ret = qflight_UART_read(fd, bytes, sizeof(bytes), &nread);
if (ret == 0 && nread > 0) {
// printf("Read %u DSM bytes at %u\n", (unsigned)nread, AP_HAL::millis());
fflush(stdout);
add_dsm_input(bytes, nread);
}
}
}
#endif // CONFIG_HAL_BOARD_SUBTYPE

View File

@ -1,41 +0,0 @@
/*
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <AP_HAL/AP_HAL.h>
#if CONFIG_HAL_BOARD_SUBTYPE == HAL_BOARD_SUBTYPE_LINUX_QFLIGHT
#include "RCInput.h"
#include "RCInput_DSM.h"
namespace Linux {
class RCInput_DSM : public RCInput
{
public:
void init() override;
void _timer_tick(void) override;
void set_device_path(const char *path);
private:
const char *device_path;
int32_t fd = -1;
};
}
#endif // CONFIG_HAL_BOARD_SUBTYPE

View File

@ -1,198 +0,0 @@
/*
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/*
this is a driver for RC output in the QFLIGHT board. Output goes via
a UART with a CRC. See libraries/RC_Channel/examples/RC_UART for an
example of the other end of this protocol
*/
#include <AP_HAL/AP_HAL.h>
#include <RC_Channel/RC_Channel.h>
#if CONFIG_HAL_BOARD_SUBTYPE == HAL_BOARD_SUBTYPE_LINUX_QFLIGHT
#include "RCOutput_qflight.h"
#include <AP_HAL_Linux/qflight/qflight_util.h>
#include <AP_HAL_Linux/qflight/qflight_dsp.h>
#include <GCS_MAVLink/include/mavlink/v2.0/checksum.h>
#include <stdio.h>
extern const AP_HAL::HAL& hal;
using namespace Linux;
void RCOutput_QFLIGHT::init()
{
hal.scheduler->register_timer_process(FUNCTOR_BIND_MEMBER(&RCOutput_QFLIGHT::timer_update, void));
}
void RCOutput_QFLIGHT::set_device_path(const char *_device)
{
device = _device;
}
void RCOutput_QFLIGHT::set_freq(uint32_t chmask, uint16_t freq_hz)
{
// no support for changing frequency yet
}
uint16_t RCOutput_QFLIGHT::get_freq(uint8_t ch)
{
// return fixed fake value - no control of frequency over the UART
return 490;
}
void RCOutput_QFLIGHT::enable_ch(uint8_t ch)
{
if (ch >= channel_count) {
return;
}
enable_mask |= 1U<<ch;
}
void RCOutput_QFLIGHT::disable_ch(uint8_t ch)
{
if (ch >= channel_count) {
return;
}
enable_mask &= ~1U<<ch;
}
void RCOutput_QFLIGHT::write(uint8_t ch, uint16_t period_us)
{
if (ch >= channel_count) {
return;
}
period[ch] = period_us;
if (!corked) {
need_write = true;
}
}
uint16_t RCOutput_QFLIGHT::read(uint8_t ch)
{
if (ch >= channel_count) {
return 0;
}
return period[ch];
}
void RCOutput_QFLIGHT::read(uint16_t *period_us, uint8_t len)
{
for (int i = 0; i < len; i++) {
period_us[i] = read(i);
}
}
void RCOutput_QFLIGHT::timer_update(void)
{
/*
we defer the open to the time to ensure all RPC calls are made
from the same thread
*/
if (fd == -1 && device != nullptr) {
int ret = qflight_UART_open(device, &fd);
printf("Opened ESC UART %s ret=%d fd=%d\n",
device, ret, (int)fd);
if (fd != -1) {
qflight_UART_set_baudrate(fd, baudrate);
}
}
if (!need_write || fd == -1) {
return;
}
/*
this implements the PWM over UART prototocol.
*/
struct PACKED {
uint8_t magic = 0xF7;
uint16_t period[channel_count];
uint16_t crc;
} frame;
memcpy(frame.period, period, sizeof(period));
frame.crc = crc_calculate((uint8_t*)frame.period, channel_count*2);
int32_t nwritten;
qflight_UART_write(fd, (uint8_t *)&frame, sizeof(frame), &nwritten);
need_write = false;
check_rc_in();
}
/*
we accept RC input from the UART and treat it as RC overrides. This
is an lazy way to allow an RCOutput driver to do RCInput. See the
RC_UART example for the other end of this protocol
*/
void RCOutput_QFLIGHT::check_rc_in(void)
{
const uint8_t magic = 0xf6;
while (nrcin_bytes != sizeof(rcu.bytes)) {
int32_t nread;
if (qflight_UART_read(fd, rcu.bytes, sizeof(rcu.bytes)-nrcin_bytes, &nread) != 0 || nread <= 0) {
return;
}
nrcin_bytes += nread;
if (rcu.rcin.magic != magic) {
for (uint8_t i=1; i<nrcin_bytes; i++) {
if (rcu.bytes[i] == magic) {
memmove(&rcu.bytes[0], &rcu.bytes[i], nrcin_bytes-i);
nrcin_bytes = nrcin_bytes - i;
return;
}
}
nrcin_bytes = 0;
return;
}
}
if (nrcin_bytes == sizeof(rcu.bytes)) {
if (rcu.rcin.magic == 0xf6 &&
crc_calculate((uint8_t*)rcu.rcin.rcin, sizeof(rcu.rcin.rcin)) == rcu.rcin.crc) {
bool have_data = false;
for (uint8_t i=0; i<8; i++) {
if (rcu.rcin.rcin[i] != 0) {
have_data = true;
break;
}
}
if (have_data) {
// FIXME: This is an incredibly dirty hack as this probhibits the usage of
// overrides if an RC reciever is connected, as the next RC input will
// stomp over the GCS set overrides. This results in incredibly confusing,
// undocumented behaviour, that cannot be reported to the user.
for (uint8_t i = 0; i < 8; i++) {
RC_Channels::set_override(i, rcu.rcin.rcin[i]);
}
}
}
nrcin_bytes = 0;
}
}
void RCOutput_QFLIGHT::cork(void)
{
corked = true;
}
void RCOutput_QFLIGHT::push(void)
{
if (corked) {
corked = false;
need_write = true;
}
}
#endif // CONFIG_HAL_BOARD_SUBTYPE

View File

@ -1,54 +0,0 @@
#pragma once
#include <AP_HAL/AP_HAL.h>
#include "AP_HAL_Linux.h"
#if CONFIG_HAL_BOARD_SUBTYPE == HAL_BOARD_SUBTYPE_LINUX_QFLIGHT
namespace Linux {
class RCOutput_QFLIGHT : public AP_HAL::RCOutput {
public:
void init();
void set_freq(uint32_t chmask, uint16_t freq_hz);
uint16_t get_freq(uint8_t ch);
void enable_ch(uint8_t ch);
void disable_ch(uint8_t ch);
void write(uint8_t ch, uint16_t period_us);
uint16_t read(uint8_t ch);
void read(uint16_t *period_us, uint8_t len);
void set_device_path(const char *device);
void cork(void) override;
void push(void) override;
private:
const char *device = nullptr;
const uint32_t baudrate = 115200;
static const uint8_t channel_count = 4;
int32_t fd = -1;
uint16_t enable_mask;
uint16_t period[channel_count];
volatile bool need_write;
void timer_update(void);
void check_rc_in(void);
uint32_t last_read_check_ms;
struct PACKED rcin_frame {
uint8_t magic;
uint16_t rcin[8];
uint16_t crc;
};
union {
struct rcin_frame rcin;
uint8_t bytes[19];
} rcu;
uint8_t nrcin_bytes;
bool corked;
};
}
#endif // CONFIG_HAL_BOARD_SUBTYPE

View File

@ -18,13 +18,6 @@
#include "UARTDriver.h"
#include "Util.h"
#if CONFIG_HAL_BOARD_SUBTYPE == HAL_BOARD_SUBTYPE_LINUX_QFLIGHT
#include <rpcmem.h>
#include <AP_HAL_Linux/qflight/qflight_util.h>
#include <AP_HAL_Linux/qflight/qflight_dsp.h>
#include <AP_HAL_Linux/qflight/qflight_buffer.h>
#endif
#if HAL_WITH_UAVCAN
#include "CAN.h"
#endif
@ -257,16 +250,6 @@ void Scheduler::_timer_task()
_in_timer_proc = false;
#if HAL_LINUX_UARTS_ON_TIMER_THREAD
/*
some boards require that UART calls happen on the same
thread as other calls of the same time. This impacts the
QFLIGHT calls where UART output is an RPC call to the DSPs
*/
_run_uarts();
RCInput::from(hal.rcin)->_timer_tick();
#endif
#if HAL_WITH_UAVCAN
#if CONFIG_HAL_BOARD == HAL_BOARD_LINUX
for (i = 0; i < MAX_NUMBER_OF_CAN_INTERFACES; i++) {
@ -310,16 +293,12 @@ void Scheduler::_run_uarts()
void Scheduler::_rcin_task()
{
#if !HAL_LINUX_UARTS_ON_TIMER_THREAD
RCInput::from(hal.rcin)->_timer_tick();
#endif
}
void Scheduler::_uart_task()
{
#if !HAL_LINUX_UARTS_ON_TIMER_THREAD
_run_uarts();
#endif
}
void Scheduler::_tonealarm_task()
@ -376,14 +355,6 @@ void Scheduler::stop_clock(uint64_t time_usec)
bool Scheduler::SchedulerThread::_run()
{
#if CONFIG_HAL_BOARD_SUBTYPE == HAL_BOARD_SUBTYPE_LINUX_QFLIGHT
if (_sched._timer_thread.is_current_thread()) {
/* make rpcmem initialization on timer thread */
printf("Initialising rpcmem\n");
rpcmem_init();
}
#endif
_sched._wait_all_threads();
return PeriodicThread::_run();

View File

@ -22,7 +22,6 @@
#include "ConsoleDevice.h"
#include "TCPServerDevice.h"
#include "UARTDevice.h"
#include "UARTQFlight.h"
#include "UDPDevice.h"
#include <GCS_MAVLink/GCS.h>
@ -129,10 +128,6 @@ AP_HAL::OwnPtr<SerialDevice> UARTDriver::_parseDevicePath(const char *arg)
if (stat(arg, &st) == 0 && S_ISCHR(st.st_mode)) {
return AP_HAL::OwnPtr<SerialDevice>(new UARTDevice(arg));
#if CONFIG_HAL_BOARD_SUBTYPE == HAL_BOARD_SUBTYPE_LINUX_QFLIGHT
} else if (strncmp(arg, "qflight:", 8) == 0) {
return AP_HAL::OwnPtr<SerialDevice>(new QFLIGHTDevice(device_path));
#endif
} else if (strncmp(arg, "tcp:", 4) != 0 &&
strncmp(arg, "udp:", 4) != 0 &&
strncmp(arg, "udpin:", 6)) {

View File

@ -1,103 +0,0 @@
/*
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/*
This is a UART driver for the QFLIGHT port. Actual UART output
happens via RPC calls. See the qflight/ subdirectory for details
*/
#include <AP_HAL/AP_HAL.h>
#if CONFIG_HAL_BOARD_SUBTYPE == HAL_BOARD_SUBTYPE_LINUX_QFLIGHT
#include <stdio.h>
#include <unistd.h>
#include "UARTQFlight.h"
#include <AP_HAL_Linux/qflight/qflight_util.h>
#include <AP_HAL_Linux/qflight/qflight_dsp.h>
#include <stdio.h>
QFLIGHTDevice::QFLIGHTDevice(const char *_device_path)
{
device_path = _device_path;
if (strncmp(device_path, "qflight:", 8) == 0) {
device_path += 8;
}
}
QFLIGHTDevice::~QFLIGHTDevice()
{
close();
}
bool QFLIGHTDevice::close()
{
if (fd != -1) {
if (qflight_UART_close(fd) != 0) {
return false;
}
}
fd = -1;
return true;
}
bool QFLIGHTDevice::open()
{
int ret = qflight_UART_open(device_path, &fd);
if (ret != 0 || fd == -1) {
printf("Failed to open UART device %s ret=%d fd=%d\n",
device_path, ret, (int)fd);
return false;
}
printf("opened QFLIGHT UART device %s ret=%d fd=%d\n",
device_path, ret, (int)fd);
return true;
}
ssize_t QFLIGHTDevice::read(uint8_t *buf, uint16_t n)
{
int32_t nread = 0;
int ret = qflight_UART_read(fd, buf, n, &nread);
if (ret != 0) {
return 0;
}
return nread;
}
ssize_t QFLIGHTDevice::write(const uint8_t *buf, uint16_t n)
{
int32_t nwritten = 0;
int ret = qflight_UART_write(fd, buf, n, &nwritten);
if (ret != 0) {
return 0;
}
return nwritten;
}
void QFLIGHTDevice::set_blocking(bool blocking)
{
// no implementation yet
}
void QFLIGHTDevice::set_speed(uint32_t baudrate)
{
qflight_UART_set_baudrate(fd, baudrate);
}
#endif // CONFIG_HAL_BOARD_SUBTYPE

View File

@ -1,25 +0,0 @@
#pragma once
#include <AP_HAL/AP_HAL.h>
#include "SerialDevice.h"
#if CONFIG_HAL_BOARD_SUBTYPE == HAL_BOARD_SUBTYPE_LINUX_QFLIGHT
class QFLIGHTDevice: public SerialDevice {
public:
QFLIGHTDevice(const char *device_path);
virtual ~QFLIGHTDevice();
virtual bool open() override;
virtual bool close() override;
virtual ssize_t write(const uint8_t *buf, uint16_t n) override;
virtual ssize_t read(uint8_t *buf, uint16_t n) override;
virtual void set_blocking(bool blocking) override;
virtual void set_speed(uint32_t speed) override;
private:
int32_t fd = -1;
const char *device_path;
};
#endif

View File

@ -1,118 +0,0 @@
# ArduPilot on Qualcomm Flight
This is a port of ArduPilot to the Qualcomm Flight development board:
http://shop.intrinsyc.com/products/snapdragon-flight-dev-kit
This board is interesting because it is small but offers a lot of CPU
power and two on-board cameras.
The board has 4 'Krait' ARM cores which run Linux (by default Ubuntu
14.04 Trusty), plus 3 'Hexagon' DSP cores which run the QURT RTOS.
There are two ports of ArduPilot to this board. One is called
'HAL_QURT' and runs primarily on the DSPs, with just a small shim on
the ARM cores. The other is a HAL_Linux subtype called 'QFLIGHT' which
runs mostly on the ARM cores, with just sensor and UARTs on the DSPs.
This is the readme for the QFLIGHT port. See the AP_HAL_QURT directory
for information on the QURT port.
# Building ArduPilot for 'QFLIGHT'
Due to some rather unusual licensing terms from Intrinsyc we cannot
distribute binaries of ArduPilot (or any program built with the
Qualcomm libraries). So you will have to build the firmware yourself.
To build ArduPilot you will need 3 library packages from
Intrinsyc. They are:
* the HEXAGON_Tools package, tested with version 7.2.11
* the Hexagon_SDK packet, version 2.0
* the HexagonFCAddon package, tested with Flight_BSP_1.1_ES3_003.2
These packages should all be unpacked in a $HOME/Qualcomm directory.
To build APM:Copter you then do:
```
cd ArduCopter
make qflight -j4
```
you can then upload the firmware to your board by joining to the WiFi
network of the board and doing this
```
make qflight_send FLIGHT_BOARD=myboard
```
where "myboard" is the hostname or IP address of your board.
This will install two files:
```
/root/ArduCopter.elf
/usr/share/data/adsp/libqflight_skel.so
```
To start ArduPilot just run the elf file as root on the flight
board. You can control UART output with command line options. A
typical startup command would be:
```
/root/ArduCopter.elf -A udp:192.168.1.255:14550:bcast -e /dev/tty-3 -B qflight:/dev/tty-2 --dsm /dev/tty-4
```
That will start ArduPilot with telemetry over UDP on port 14550, GPS
on tty-2 on the DSPs, Skektrum satellite RC input on tty-4 and
ESC output on tty-3.
Then you can open your favourite MAVLink compatible GCS and connect
with UDP.
# Logging
Logs will appear in /var/APM/logs as usual for Linux ArduPilot
ports. You can download logs over MAVLink or transfer over WiFi.
# UART connections
The Qualcomm Flight board has 4 DF13 6 pin UART connectors. Be careful
though as they do not have the same pinout as the same connectors on a
Pixhawk.
The pinout of them all is:
* pin1: power
* pin2: TX
* pin3: RX
* pin5: GND
3 of the 4 ports provide 3.3V power on pin1, while the 4th port
provides 5V power. Note that pin6 is not ground, unlike on a Pixhawk.
The 4 ports are called /dev/tty-1, /dev/tty-2, /dev/tty-3 and
/dev/tty-4. The first port is the one closest to the USB3
connector. The ports proceed counter-clockwise from there. So tty-2 is
the one closest to the power connector.
Only tty-2 provides 5V power. The others provide 3.3V power. You will
need to check whether your GPS can be powered off 3.3V.
# ESC PWM Output
To get signals to ESCs or servos you need to use a UART. The default
setup is to send 4 PWM signals as serial data on /dev/tty-3. This is
designed to work with this firmware for any ArduPilot compatible
board:
https://github.com/tridge/ardupilot/tree/hal-qurt/libraries/RC_Channel/examples/RC_UART
that firmware will read the UART serial stream and output to the PWM
output of the board you use. For example, you could use a Pixracer or
Pixhawk board. This is an interim solution until Qualcomm/Intrinsyc
release an ESC add-on control board for the Qualcomm Flight.
Note that you can also use RC input from that attached board, allowing
you to use any ArduPilot compatible RC receiver.

View File

@ -1,393 +0,0 @@
/*
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/*
This is an implementation of all of the code for the QFLIGHT board
that runs on the DSPs. See qflight_dsp.idl for the interface
definition for the RPC calls
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include "qflight_dsp.h"
extern "C" {
#include "bmp280_api.h"
#include "mpu9x50.h"
}
#include <types.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdint.h>
#include <stdarg.h>
#include <sys/timespec.h>
#include <errno.h>
#include <string.h>
#include <time.h>
#include <dspal_time.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <dirent.h>
#include <stdlib.h>
#include <dev_fs_lib_serial.h>
#include "qflight_buffer.h"
#include <AP_HAL/utility/RingBuffer.h>
const float GRAVITY_MSS = 9.80665;
const float ACCEL_SCALE_1G = GRAVITY_MSS / 2048.0;
const float GYRO_SCALE = 0.0174532 / 16.4;
const float RAD_TO_DEG = 57.295779513082320876798154814105;
static ObjectBuffer<DSPBuffer::IMU::BUF> imu_buffer(30);
static ObjectBuffer<DSPBuffer::MAG::BUF> mag_buffer(10);
static ObjectBuffer<DSPBuffer::BARO::BUF> baro_buffer(10);
static bool mpu9250_started;
static uint32_t bmp280_handle;
static uint32_t baro_counter;
/*
read buffering for UARTs
*/
static const uint8_t max_uarts = 8;
static uint8_t num_open_uarts;
static struct uartbuf {
int fd;
ByteBuffer *readbuffer;
} uarts[max_uarts];
extern "C" {
void HAP_debug(const char *msg, int level, const char *filename, int line);
}
void HAP_printf(const char *file, int line, const char *format, ...)
{
va_list ap;
char buf[300];
va_start(ap, format);
vsnprintf(buf, sizeof(buf), format, ap);
va_end(ap);
HAP_debug(buf, 0, file, line);
}
void HAP_printf(const char *file, int line, const char *format, ...);
#define HAP_PRINTF(...) HAP_printf(__FILE__, __LINE__, __VA_ARGS__)
static int init_barometer(void)
{
int ret = bmp280_open("/dev/i2c-2", &bmp280_handle);
HAP_PRINTF("**** bmp280: ret=%d handle=0x%x\n", ret, (unsigned)bmp280_handle);
return ret;
}
static int init_mpu9250(void)
{
struct mpu9x50_config config;
config.gyro_lpf = MPU9X50_GYRO_LPF_184HZ;
config.acc_lpf = MPU9X50_ACC_LPF_184HZ;
config.gyro_fsr = MPU9X50_GYRO_FSR_2000DPS;
config.acc_fsr = MPU9X50_ACC_FSR_16G;
config.gyro_sample_rate = MPU9x50_SAMPLE_RATE_1000HZ;
config.compass_enabled = true;
config.compass_sample_rate = MPU9x50_COMPASS_SAMPLE_RATE_100HZ;
config.spi_dev_path = "/dev/spi-1";
int ret;
ret = mpu9x50_validate_configuration(&config);
HAP_PRINTF("***** mpu9250 validate ret=%d\n", ret);
if (ret != 0) {
return ret;
}
ret = mpu9x50_initialize(&config);
HAP_PRINTF("***** mpu9250 initialise ret=%d\n", ret);
mpu9250_started = true;
return ret;
}
/*
thread gathering sensor data from mpu9250
*/
static void *mpu_data_ready(void *ctx)
{
struct mpu9x50_data data;
memset(&data, 0, sizeof(data));
int ret = mpu9x50_get_data(&data);
if (ret != 0) {
return nullptr;
}
DSPBuffer::IMU::BUF b;
b.timestamp = data.timestamp;
b.accel[0] = data.accel_raw[0]*ACCEL_SCALE_1G;
b.accel[1] = data.accel_raw[1]*ACCEL_SCALE_1G;
b.accel[2] = data.accel_raw[2]*ACCEL_SCALE_1G;
b.gyro[0] = data.gyro_raw[0]*GYRO_SCALE;
b.gyro[1] = data.gyro_raw[1]*GYRO_SCALE;
b.gyro[2] = data.gyro_raw[2]*GYRO_SCALE;
imu_buffer.push(b);
if (data.mag_data_ready) {
DSPBuffer::MAG::BUF m;
m.mag_raw[0] = data.mag_raw[0];
m.mag_raw[1] = data.mag_raw[1];
m.mag_raw[2] = data.mag_raw[2];
m.timestamp = data.timestamp;
mag_buffer.push(m);
}
if (bmp280_handle != 0 && baro_counter++ % 10 == 0) {
struct bmp280_sensor_data data;
memset(&data, 0, sizeof(data));
int ret = bmp280_get_sensor_data(bmp280_handle, &data, false);
if (ret == 0) {
DSPBuffer::BARO::BUF b;
b.pressure_pa = data.pressure_in_pa;
b.temperature_C = data.temperature_in_c;
b.timestamp = data.last_read_time_in_usecs;
baro_buffer.push(b);
}
}
return nullptr;
}
static void mpu9250_startup(void)
{
if (!mpu9250_started) {
if (init_mpu9250() != 0) {
return;
}
mpu9x50_register_interrupt(65, mpu_data_ready, nullptr);
}
}
/*
get any available IMU data
*/
int qflight_get_imu_data(uint8_t *buf, int len)
{
DSPBuffer::IMU &imu = *(DSPBuffer::IMU *)buf;
if (len != sizeof(imu)) {
HAP_PRINTF("incorrect size for imu data %d should be %d\n",
len, sizeof(imu));
return 1;
}
mpu9250_startup();
imu.num_samples = 0;
while (imu.num_samples < imu.max_samples &&
imu_buffer.pop(imu.buf[imu.num_samples])) {
imu.num_samples++;
}
return 0;
}
/*
get any available mag data
*/
int qflight_get_mag_data(uint8_t *buf, int len)
{
DSPBuffer::MAG &mag = *(DSPBuffer::MAG *)buf;
if (len != sizeof(mag)) {
HAP_PRINTF("incorrect size for mag data %d should be %d\n",
len, sizeof(mag));
return 1;
}
mpu9250_startup();
mag.num_samples = 0;
while (mag.num_samples < mag.max_samples &&
mag_buffer.pop(mag.buf[mag.num_samples])) {
mag.num_samples++;
}
return 0;
}
/*
get any available baro data
*/
int qflight_get_baro_data(uint8_t *buf, int len)
{
DSPBuffer::BARO &baro = *(DSPBuffer::BARO *)buf;
if (len != sizeof(baro)) {
HAP_PRINTF("incorrect size for baro data %d should be %d\n",
len, sizeof(baro));
return 1;
}
mpu9250_startup();
if (bmp280_handle == 0) {
if (init_barometer() != 0) {
return 1;
}
}
baro.num_samples = 0;
while (baro.num_samples < baro.max_samples &&
baro_buffer.pop(baro.buf[baro.num_samples])) {
baro.num_samples++;
}
return 0;
}
extern "C" {
static void read_callback_trampoline(void *, char *, size_t );
}
static void read_callback_trampoline(void *ctx, char *buf, size_t size)
{
if (size > 0) {
((ByteBuffer *)ctx)->write((const uint8_t *)buf, size);
}
}
/*
open a UART
*/
int qflight_UART_open(const char *device, int32_t *_fd)
{
if (num_open_uarts == max_uarts) {
return -1;
}
struct uartbuf &b = uarts[num_open_uarts];
int fd = open(device, O_RDWR | O_NONBLOCK|O_CLOEXEC);
if (fd == -1) {
return -1;
}
b.fd = fd;
b.readbuffer = new ByteBuffer(16384);
struct dspal_serial_open_options options;
options.bit_rate = DSPAL_SIO_BITRATE_57600;
options.tx_flow = DSPAL_SIO_FCTL_OFF;
options.rx_flow = DSPAL_SIO_FCTL_OFF;
options.rx_data_callback = nullptr;
options.tx_data_callback = nullptr;
options.is_tx_data_synchronous = false;
int ret = ioctl(fd, SERIAL_IOCTL_OPEN_OPTIONS, (void *)&options);
if (ret != 0) {
HAP_PRINTF("Failed to setup UART flow control options");
}
struct dspal_serial_ioctl_receive_data_callback callback {};
callback.context = b.readbuffer;
callback.rx_data_callback_func_ptr = read_callback_trampoline;
ret = ioctl(fd, SERIAL_IOCTL_SET_RECEIVE_DATA_CALLBACK, (void *)&callback);
if (ret != 0) {
HAP_PRINTF("Failed to setup UART read trampoline");
delete b.readbuffer;
close(fd);
return -1;
}
HAP_PRINTF("UART open %s fd=%d num_open=%u",
device, fd, num_open_uarts);
num_open_uarts++;
*_fd = fd;
return 0;
}
/*
close a UART
*/
int qflight_UART_close(int32_t fd)
{
uint8_t i;
for (i=0; i<num_open_uarts; i++) {
if (fd == uarts[i].fd) break;
}
if (i == num_open_uarts) {
return -1;
}
close(fd);
delete uarts[i].readbuffer;
if (i < num_open_uarts-1) {
memmove(&uarts[i], &uarts[i+1], ((num_open_uarts-1)-i)*sizeof(uarts[0]));
}
num_open_uarts--;
return 0;
}
/*
read from a UART
*/
int qflight_UART_read(int32_t fd, uint8_t *buf, int size, int32_t *nread)
{
uint8_t i;
for (i=0; i<num_open_uarts; i++) {
if (fd == uarts[i].fd) break;
}
if (i == num_open_uarts) {
return -1;
}
*nread = uarts[i].readbuffer->read(buf, size);
return 0;
}
/*
write to a UART
*/
int qflight_UART_write(int32_t fd, const uint8_t *buf, int size, int32_t *nwritten)
{
*nwritten = write(fd, buf, size);
return 0;
}
static const struct {
uint32_t baudrate;
enum DSPAL_SERIAL_BITRATES arg;
} baudrate_table[] = {
{ 9600, DSPAL_SIO_BITRATE_9600 },
{ 14400, DSPAL_SIO_BITRATE_14400 },
{ 19200, DSPAL_SIO_BITRATE_19200 },
{ 38400, DSPAL_SIO_BITRATE_38400 },
{ 57600, DSPAL_SIO_BITRATE_57600 },
{ 76800, DSPAL_SIO_BITRATE_76800 },
{ 115200, DSPAL_SIO_BITRATE_115200 },
{ 230400, DSPAL_SIO_BITRATE_230400 },
{ 250000, DSPAL_SIO_BITRATE_250000 },
{ 460800, DSPAL_SIO_BITRATE_460800 },
{ 921600, DSPAL_SIO_BITRATE_921600 },
{ 2000000, DSPAL_SIO_BITRATE_2000000 },
};
/*
set UART baudrate
*/
int qflight_UART_set_baudrate(int32_t fd, uint32_t baudrate)
{
for (uint8_t i=0; i<sizeof(baudrate_table)/sizeof(baudrate_table[0]); i++) {
if (baudrate <= baudrate_table[i].baudrate) {
struct dspal_serial_ioctl_data_rate rate {};
rate.bit_rate = baudrate_table[i].arg;
int ret = ioctl(fd, SERIAL_IOCTL_SET_DATA_RATE, (void *)&rate);
HAP_PRINTF("set_rate -> %d\n", ret);
return 0;
}
}
return -1;
}

View File

@ -1,38 +0,0 @@
#pragma once
/*
shared memory structures for sensor data and peripheral control on Qualcomm flight board
*/
struct DSPBuffer {
// IMU data
struct IMU {
static const uint32_t max_samples = 10;
uint32_t num_samples;
struct BUF {
uint64_t timestamp;
float accel[3];
float gyro[3];
} buf[max_samples];
} imu;
// MAG data
struct MAG {
static const uint64_t max_samples = 10;
uint32_t num_samples;
struct BUF {
uint64_t timestamp;
int16_t mag_raw[3];
} buf[max_samples];
} mag;
// baro data
struct BARO {
static const uint32_t max_samples = 10;
uint32_t num_samples;
struct BUF {
uint64_t timestamp;
float pressure_pa;
float temperature_C;
} buf[max_samples];
} baro;
};

View File

@ -1,15 +0,0 @@
#include "AEEStdDef.idl"
interface qflight {
// sensor calls
long get_imu_data(rout sequence<uint8> outdata);
long get_mag_data(rout sequence<uint8> outdata);
long get_baro_data(rout sequence<uint8> outdata);
// UART control
long UART_open(in string device, rout int32 fd);
long UART_set_baudrate(in int32 fd, in uint32 baudrate);
long UART_read(in int32 fd, rout sequence<uint8> buf, rout int32 nread);
long UART_write(in int32 fd, in sequence<uint8> buf, rout int32 nwritten);
long UART_close(in int32 fd);
};

View File

@ -1,3 +0,0 @@
#include <rpcmem.h>
#define QFLIGHT_RPC_ALLOCATE(type) (type *)rpcmem_alloc_def(sizeof(type))