|
|
|
@ -49,7 +49,8 @@
@@ -49,7 +49,8 @@
|
|
|
|
|
#include <px4_platform_common/px4_config.h> |
|
|
|
|
#include <px4_platform_common/defines.h> |
|
|
|
|
#include <px4_platform_common/getopt.h> |
|
|
|
|
#include <px4_platform_common/px4_work_queue/ScheduledWorkItem.hpp> |
|
|
|
|
#include <px4_platform_common/i2c_spi_buses.h> |
|
|
|
|
#include <px4_platform_common/module.h> |
|
|
|
|
#include <uORB/PublicationMulti.hpp> |
|
|
|
|
#include <uORB/topics/distance_sensor.h> |
|
|
|
|
#include <uORB/topics/optical_flow.h> |
|
|
|
@ -75,23 +76,28 @@
@@ -75,23 +76,28 @@
|
|
|
|
|
|
|
|
|
|
#include "i2c_frame.h" |
|
|
|
|
|
|
|
|
|
class PX4FLOW: public device::I2C, public px4::ScheduledWorkItem |
|
|
|
|
class PX4FLOW: public device::I2C, public I2CSPIDriver<PX4FLOW> |
|
|
|
|
{ |
|
|
|
|
public: |
|
|
|
|
PX4FLOW(int bus, int address = I2C_FLOW_ADDRESS_DEFAULT, enum Rotation rotation = (enum Rotation)0, |
|
|
|
|
int conversion_interval = PX4FLOW_CONVERSION_INTERVAL_DEFAULT, |
|
|
|
|
uint8_t sonar_rotation = distance_sensor_s::ROTATION_DOWNWARD_FACING); |
|
|
|
|
PX4FLOW(I2CSPIBusOption bus_option, int bus, int address, uint8_t sonar_rotation, int bus_frequency, |
|
|
|
|
int conversion_interval = PX4FLOW_CONVERSION_INTERVAL_DEFAULT, enum Rotation rotation = ROTATION_NONE); |
|
|
|
|
virtual ~PX4FLOW(); |
|
|
|
|
|
|
|
|
|
virtual int init(); |
|
|
|
|
static I2CSPIDriverBase *instantiate(const BusCLIArguments &cli, const BusInstanceIterator &iterator, |
|
|
|
|
int runtime_instance); |
|
|
|
|
static void print_usage(); |
|
|
|
|
|
|
|
|
|
int init() override; |
|
|
|
|
|
|
|
|
|
void print_status(); |
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Diagnostics - print some basic information about the driver. |
|
|
|
|
* Perform a poll cycle; collect from the previous measurement |
|
|
|
|
* and start a new one. |
|
|
|
|
*/ |
|
|
|
|
void print_info(); |
|
|
|
|
|
|
|
|
|
void RunImpl(); |
|
|
|
|
protected: |
|
|
|
|
virtual int probe(); |
|
|
|
|
int probe() override; |
|
|
|
|
|
|
|
|
|
private: |
|
|
|
|
|
|
|
|
@ -132,30 +138,17 @@ private:
@@ -132,30 +138,17 @@ private:
|
|
|
|
|
*/ |
|
|
|
|
void start(); |
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Stop the automatic measurement state machine. |
|
|
|
|
*/ |
|
|
|
|
void stop(); |
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Perform a poll cycle; collect from the previous measurement |
|
|
|
|
* and start a new one. |
|
|
|
|
*/ |
|
|
|
|
void Run() override; |
|
|
|
|
|
|
|
|
|
int measure(); |
|
|
|
|
int collect(); |
|
|
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Driver 'main' command. |
|
|
|
|
*/ |
|
|
|
|
extern "C" __EXPORT int px4flow_main(int argc, char *argv[]); |
|
|
|
|
|
|
|
|
|
PX4FLOW::PX4FLOW(int bus, int address, enum Rotation rotation, int conversion_interval, uint8_t sonar_rotation) : |
|
|
|
|
I2C("PX4FLOW", PX4FLOW0_DEVICE_PATH, bus, address, PX4FLOW_I2C_MAX_BUS_SPEED), /* 100-400 KHz */ |
|
|
|
|
ScheduledWorkItem(MODULE_NAME, px4::device_bus_to_wq(get_device_id())), |
|
|
|
|
PX4FLOW::PX4FLOW(I2CSPIBusOption bus_option, int bus, int address, uint8_t sonar_rotation, int bus_frequency, |
|
|
|
|
int conversion_interval, enum Rotation rotation) : |
|
|
|
|
I2C("PX4FLOW", PX4FLOW0_DEVICE_PATH, bus, address, bus_frequency), |
|
|
|
|
I2CSPIDriver(MODULE_NAME, px4::device_bus_to_wq(get_device_id()), bus_option, bus, address), |
|
|
|
|
_sonar_rotation(sonar_rotation), |
|
|
|
|
_sample_perf(perf_alloc(PC_ELAPSED, "px4f_read")), |
|
|
|
|
_comms_errors(perf_alloc(PC_COUNT, "px4f_com_err")), |
|
|
|
@ -165,9 +158,6 @@ PX4FLOW::PX4FLOW(int bus, int address, enum Rotation rotation, int conversion_in
@@ -165,9 +158,6 @@ PX4FLOW::PX4FLOW(int bus, int address, enum Rotation rotation, int conversion_in
|
|
|
|
|
|
|
|
|
|
PX4FLOW::~PX4FLOW() |
|
|
|
|
{ |
|
|
|
|
/* make sure we are truly inactive */ |
|
|
|
|
stop(); |
|
|
|
|
|
|
|
|
|
perf_free(_sample_perf); |
|
|
|
|
perf_free(_comms_errors); |
|
|
|
|
} |
|
|
|
@ -361,13 +351,7 @@ PX4FLOW::start()
@@ -361,13 +351,7 @@ PX4FLOW::start()
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void |
|
|
|
|
PX4FLOW::stop() |
|
|
|
|
{ |
|
|
|
|
ScheduleClear(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void |
|
|
|
|
PX4FLOW::Run() |
|
|
|
|
PX4FLOW::RunImpl() |
|
|
|
|
{ |
|
|
|
|
if (OK != measure()) { |
|
|
|
|
DEVICE_DEBUG("measure error"); |
|
|
|
@ -385,257 +369,82 @@ PX4FLOW::Run()
@@ -385,257 +369,82 @@ PX4FLOW::Run()
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void |
|
|
|
|
PX4FLOW::print_info() |
|
|
|
|
PX4FLOW::print_status() |
|
|
|
|
{ |
|
|
|
|
I2CSPIDriverBase::print_status(); |
|
|
|
|
perf_print_counter(_sample_perf); |
|
|
|
|
perf_print_counter(_comms_errors); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Local functions in support of the shell command. |
|
|
|
|
*/ |
|
|
|
|
namespace px4flow |
|
|
|
|
void |
|
|
|
|
PX4FLOW::print_usage() |
|
|
|
|
{ |
|
|
|
|
PRINT_MODULE_USAGE_NAME("px4flow", "driver"); |
|
|
|
|
PRINT_MODULE_USAGE_COMMAND("start"); |
|
|
|
|
PRINT_MODULE_USAGE_PARAMS_I2C_SPI_DRIVER(true, false); |
|
|
|
|
PRINT_MODULE_USAGE_PARAMS_I2C_ADDRESS(0x42); |
|
|
|
|
PRINT_MODULE_USAGE_PARAM_INT('R', 25, 0, 35, "Rotation (default=downwards)", true); |
|
|
|
|
PRINT_MODULE_USAGE_DEFAULT_COMMANDS(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
PX4FLOW *g_dev = nullptr; |
|
|
|
|
bool start_in_progress = false; |
|
|
|
|
|
|
|
|
|
const int START_RETRY_COUNT = 5; |
|
|
|
|
const int START_RETRY_TIMEOUT = 1000; |
|
|
|
|
|
|
|
|
|
int start(int argc, char *argv[]); |
|
|
|
|
int stop(); |
|
|
|
|
int info(); |
|
|
|
|
void usage(); |
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Start the driver. |
|
|
|
|
*/ |
|
|
|
|
int |
|
|
|
|
start(int argc, char *argv[]) |
|
|
|
|
I2CSPIDriverBase *PX4FLOW::instantiate(const BusCLIArguments &cli, const BusInstanceIterator &iterator, |
|
|
|
|
int runtime_instance) |
|
|
|
|
{ |
|
|
|
|
/* entry check: */ |
|
|
|
|
if (start_in_progress) { |
|
|
|
|
PX4_WARN("start already in progress"); |
|
|
|
|
return 1; |
|
|
|
|
PX4FLOW *instance = new PX4FLOW(iterator.configuredBusOption(), iterator.bus(), cli.i2c_address, cli.orientation, |
|
|
|
|
cli.bus_frequency); |
|
|
|
|
|
|
|
|
|
if (!instance) { |
|
|
|
|
PX4_ERR("alloc failed"); |
|
|
|
|
return nullptr; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (g_dev != nullptr) { |
|
|
|
|
start_in_progress = false; |
|
|
|
|
PX4_WARN("already started"); |
|
|
|
|
return 1; |
|
|
|
|
if (OK != instance->init()) { |
|
|
|
|
delete instance; |
|
|
|
|
return nullptr; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* parse command line options */ |
|
|
|
|
int address = I2C_FLOW_ADDRESS_DEFAULT; |
|
|
|
|
int conversion_interval = PX4FLOW_CONVERSION_INTERVAL_DEFAULT; |
|
|
|
|
return instance; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* don't exit from getopt loop to leave getopt global variables in consistent state,
|
|
|
|
|
* set error flag instead */ |
|
|
|
|
bool err_flag = false; |
|
|
|
|
int |
|
|
|
|
px4flow_main(int argc, char *argv[]) |
|
|
|
|
{ |
|
|
|
|
int ch; |
|
|
|
|
int myoptind = 1; |
|
|
|
|
const char *myoptarg = nullptr; |
|
|
|
|
uint8_t sonar_rotation = distance_sensor_s::ROTATION_DOWNWARD_FACING; |
|
|
|
|
using ThisDriver = PX4FLOW; |
|
|
|
|
BusCLIArguments cli{true, false}; |
|
|
|
|
cli.default_i2c_frequency = PX4FLOW_I2C_MAX_BUS_SPEED; |
|
|
|
|
cli.orientation = distance_sensor_s::ROTATION_DOWNWARD_FACING; |
|
|
|
|
cli.i2c_address = I2C_FLOW_ADDRESS_DEFAULT; |
|
|
|
|
|
|
|
|
|
while ((ch = px4_getopt(argc, argv, "a:i:R:", &myoptind, &myoptarg)) != EOF) { |
|
|
|
|
while ((ch = cli.getopt(argc, argv, "R:")) != EOF) { |
|
|
|
|
switch (ch) { |
|
|
|
|
case 'a': |
|
|
|
|
address = strtoul(myoptarg, nullptr, 16); |
|
|
|
|
|
|
|
|
|
if (address < I2C_FLOW_ADDRESS_MIN || address > I2C_FLOW_ADDRESS_MAX) { |
|
|
|
|
PX4_WARN("invalid i2c address '%s'", myoptarg); |
|
|
|
|
err_flag = true; |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
|
|
case 'i': |
|
|
|
|
conversion_interval = strtoul(myoptarg, nullptr, 10); |
|
|
|
|
|
|
|
|
|
if (conversion_interval < PX4FLOW_CONVERSION_INTERVAL_MIN || conversion_interval > PX4FLOW_CONVERSION_INTERVAL_MAX) { |
|
|
|
|
PX4_WARN("invalid conversion interval '%s'", myoptarg); |
|
|
|
|
err_flag = true; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
|
|
case 'R': |
|
|
|
|
sonar_rotation = (uint8_t)atoi(myoptarg); |
|
|
|
|
PX4_INFO("Setting sonar orientation to %d", (int)sonar_rotation); |
|
|
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
|
|
default: |
|
|
|
|
err_flag = true; |
|
|
|
|
cli.orientation = atoi(cli.optarg()); |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (err_flag) { |
|
|
|
|
usage(); |
|
|
|
|
return PX4_ERROR; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* starting */ |
|
|
|
|
start_in_progress = true; |
|
|
|
|
PX4_INFO("scanning I2C buses for device.."); |
|
|
|
|
|
|
|
|
|
int retry_nr = 0; |
|
|
|
|
|
|
|
|
|
while (1) { |
|
|
|
|
const int busses_to_try[] = { |
|
|
|
|
PX4_I2C_BUS_EXPANSION, |
|
|
|
|
#ifdef PX4_I2C_BUS_ONBOARD |
|
|
|
|
PX4_I2C_BUS_ONBOARD, |
|
|
|
|
#endif |
|
|
|
|
#ifdef PX4_I2C_BUS_EXPANSION1 |
|
|
|
|
PX4_I2C_BUS_EXPANSION1, |
|
|
|
|
#endif |
|
|
|
|
#ifdef PX4_I2C_BUS_EXPANSION2 |
|
|
|
|
PX4_I2C_BUS_EXPANSION2, |
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
-1 |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
const int *cur_bus = busses_to_try; |
|
|
|
|
|
|
|
|
|
while (*cur_bus != -1) { |
|
|
|
|
/* create the driver */ |
|
|
|
|
/* PX4_WARN("trying bus %d", *cur_bus); */ |
|
|
|
|
g_dev = new PX4FLOW(*cur_bus, address, (enum Rotation)0, conversion_interval, sonar_rotation); |
|
|
|
|
|
|
|
|
|
if (g_dev == nullptr) { |
|
|
|
|
/* this is a fatal error */ |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* init the driver: */ |
|
|
|
|
if (OK == g_dev->init()) { |
|
|
|
|
/* success! */ |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* destroy it again because it failed. */ |
|
|
|
|
delete g_dev; |
|
|
|
|
g_dev = nullptr; |
|
|
|
|
|
|
|
|
|
/* try next! */ |
|
|
|
|
cur_bus++; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* check whether we found it: */ |
|
|
|
|
if (*cur_bus != -1) { |
|
|
|
|
const char *verb = cli.optarg(); |
|
|
|
|
|
|
|
|
|
/* check for failure: */ |
|
|
|
|
if (g_dev == nullptr) { |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* success! */ |
|
|
|
|
start_in_progress = false; |
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (retry_nr < START_RETRY_COUNT) { |
|
|
|
|
/* lets not be too verbose */ |
|
|
|
|
// PX4_WARN("PX4FLOW not found on I2C busses. Retrying in %d ms. Giving up in %d retries.", START_RETRY_TIMEOUT, START_RETRY_COUNT - retry_nr);
|
|
|
|
|
px4_usleep(START_RETRY_TIMEOUT * 1000); |
|
|
|
|
retry_nr++; |
|
|
|
|
|
|
|
|
|
} else { |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
if (!verb) { |
|
|
|
|
ThisDriver::print_usage(); |
|
|
|
|
return -1; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (g_dev != nullptr) { |
|
|
|
|
delete g_dev; |
|
|
|
|
g_dev = nullptr; |
|
|
|
|
} |
|
|
|
|
BusInstanceIterator iterator(MODULE_NAME, cli, DRV_FLOW_DEVTYPE_PX4FLOW); |
|
|
|
|
|
|
|
|
|
start_in_progress = false; |
|
|
|
|
|
|
|
|
|
return PX4_OK; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Stop the driver |
|
|
|
|
*/ |
|
|
|
|
int |
|
|
|
|
stop() |
|
|
|
|
{ |
|
|
|
|
start_in_progress = false; |
|
|
|
|
|
|
|
|
|
if (g_dev != nullptr) { |
|
|
|
|
delete g_dev; |
|
|
|
|
g_dev = nullptr; |
|
|
|
|
|
|
|
|
|
return PX4_OK; |
|
|
|
|
|
|
|
|
|
} else { |
|
|
|
|
PX4_WARN("driver not running"); |
|
|
|
|
if (!strcmp(verb, "start")) { |
|
|
|
|
return ThisDriver::module_start(cli, iterator); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return PX4_ERROR; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Print a little info about the driver. |
|
|
|
|
*/ |
|
|
|
|
int |
|
|
|
|
info() |
|
|
|
|
{ |
|
|
|
|
if (g_dev == nullptr) { |
|
|
|
|
PX4_WARN("driver not running"); |
|
|
|
|
return PX4_ERROR; |
|
|
|
|
if (!strcmp(verb, "stop")) { |
|
|
|
|
return ThisDriver::module_stop(iterator); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
g_dev->print_info(); |
|
|
|
|
|
|
|
|
|
return PX4_OK; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void usage() |
|
|
|
|
{ |
|
|
|
|
PX4_INFO("usage: px4flow {start|info'}"); |
|
|
|
|
PX4_INFO(" [-a i2c_address]"); |
|
|
|
|
PX4_INFO(" [-i i2c_interval]"); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
} // namespace
|
|
|
|
|
|
|
|
|
|
int |
|
|
|
|
px4flow_main(int argc, char *argv[]) |
|
|
|
|
{ |
|
|
|
|
if (argc < 2) { |
|
|
|
|
px4flow::usage(); |
|
|
|
|
return 1; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Start/load the driver. |
|
|
|
|
*/ |
|
|
|
|
if (!strcmp(argv[1], "start")) { |
|
|
|
|
return px4flow::start(argc, argv); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Stop the driver |
|
|
|
|
*/ |
|
|
|
|
if (!strcmp(argv[1], "stop")) { |
|
|
|
|
return px4flow::stop(); |
|
|
|
|
if (!strcmp(verb, "status")) { |
|
|
|
|
return ThisDriver::module_status(iterator); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Print driver information. |
|
|
|
|
*/ |
|
|
|
|
if (!strcmp(argv[1], "info") || !strcmp(argv[1], "status")) { |
|
|
|
|
return px4flow::info(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
px4flow::usage(); |
|
|
|
|
|
|
|
|
|
return PX4_OK; |
|
|
|
|
ThisDriver::print_usage(); |
|
|
|
|
return -1; |
|
|
|
|
} |
|
|
|
|