主要功能描述:
注:这个类类似于C语言单向链表的一个节点结构声明。
template
class ListNode
{
public:
void setSibling(T sibling) { _list_node_sibling = sibling; }
const T getSibling() const { return _list_node_sibling; }
protected:
T _list_node_sibling{nullptr};
};
主要功能描述:
template
class List
{
public:
void add(T newNode)
{
if (_head == nullptr) {
// list is empty, add as head
_head = newNode;
return;
} else {
// find last node and add to end
T node = _head;
while (node != nullptr) {
if (node->getSibling() == nullptr) {
// found last node, now add newNode
node->setSibling(newNode);
return;
}
node = node->getSibling();
}
}
}
bool remove(T removeNode)
{
if (removeNode == nullptr) {
return false;
}
// base case
if (removeNode == _head) {
if (_head != nullptr) {
_head = _head->getSibling();
}
removeNode->setSibling(nullptr);
return true;
}
for (T node = getHead(); node != nullptr; node = node->getSibling()) {
// is sibling the node to remove?
if (node->getSibling() == removeNode) {
// replace sibling
if (node->getSibling() != nullptr) {
node->setSibling(node->getSibling()->getSibling());
} else {
node->setSibling(nullptr);
}
removeNode->setSibling(nullptr);
return true;
}
}
return false;
}
struct Iterator {
T node;
explicit Iterator(T v) : node(v) {}
operator T() const { return node; }
operator T &() { return node; }
const T &operator* () const { return node; }
Iterator &operator++ ()
{
if (node) {
node = node->getSibling();
}
return *this;
}
};
Iterator begin() { return Iterator(getHead()); }
Iterator end() { return Iterator(nullptr); }
const T getHead() const { return _head; }
bool empty() const { return getHead() == nullptr; }
size_t size() const
{
size_t sz = 0;
for (auto node = getHead(); node != nullptr; node = node->getSibling()) {
sz++;
}
return sz;
}
void deleteNode(T node)
{
if (remove(node)) {
// only delete if node was successfully removed
delete node;
}
}
void clear()
{
auto node = getHead();
while (node != nullptr) {
auto next = node->getSibling();
delete node;
node = next;
}
_head = nullptr;
}
protected:
T _head{nullptr};
};
命令行参数配置总线设备。
主要功能描述:
class BusCLIArguments
{
public:
BusCLIArguments(bool i2c_support, bool spi_support)
#if defined(CONFIG_I2C) || defined(CONFIG_SPI)
:
#endif // CONFIG_I2C || CONFIG_SPI
#if defined(CONFIG_I2C)
_i2c_support(i2c_support)
#endif // CONFIG_I2C
#if defined(CONFIG_I2C) && defined(CONFIG_SPI)
,
#endif // CONFIG_I2C && CONFIG_SPI
#if defined(CONFIG_SPI)
_spi_support(spi_support)
#endif // CONFIG_SPI
{}
/**
* Parse CLI arguments (for drivers that don't need any custom arguments, otherwise getopt() should be used)
* @return command (e.g. "start") or nullptr on error or unknown argument
*/
const char *parseDefaultArguments(int argc, char *argv[]);
/**
* Like px4_getopt(), but adds and handles i2c/spi driver-specific arguments
*/
int getOpt(int argc, char *argv[], const char *options);
/**
* returns the current optional argument (for options like 'T:'), or the command (e.g. "start")
* @return nullptr or argument/command
*/
const char *optArg() const { return _optarg; }
I2CSPIBusOption bus_option{I2CSPIBusOption::All};
int requested_bus{-1};
int bus_frequency{0};
#if defined(CONFIG_SPI)
int chipselect {-1};
spi_mode_e spi_mode{SPIDEV_MODE3};
#endif // CONFIG_SPI
#if defined(CONFIG_I2C)
uint8_t i2c_address {0}; ///< I2C address (a driver must set the default address)
#endif // CONFIG_I2C
bool quiet_start {false}; ///< do not print a message when startup fails
bool keep_running{false}; ///< keep driver running even if no device is detected on startup
Rotation rotation{ROTATION_NONE}; ///< sensor rotation (MAV_SENSOR_ROTATION_* or distance_sensor_s::ROTATION_*)
int custom1{0}; ///< driver-specific custom argument
int custom2{0}; ///< driver-specific custom argument
void *custom_data{nullptr}; ///< driver-specific custom argument
// driver defaults, if not specified via CLI
#if defined(CONFIG_SPI)
int default_spi_frequency {-1}; ///< default spi bus frequency (driver needs to set this) [Hz]
#endif // CONFIG_SPI
#if defined(CONFIG_I2C)
int default_i2c_frequency {-1}; ///< default i2c bus frequency (driver needs to set this) [Hz]
#endif // CONFIG_I2C
bool support_keep_running{false}; ///< true if keep_running (see above) is supported
private:
bool validateConfiguration();
char _options[32] {};
int _optind{1};
const char *_optarg{nullptr};
#if defined(CONFIG_I2C)
const bool _i2c_support;
#endif // CONFIG_I2C
#if defined(CONFIG_SPI)
const bool _spi_support;
#endif // CONFIG_SPI
};
使用给定的过滤器选项迭代运行实例和/或配置的I2C/SPI总线。
主要功能描述:
class BusInstanceIterator
{
public:
BusInstanceIterator(const char *module_name, const BusCLIArguments &cli_arguments, uint16_t devid_driver_index);
~BusInstanceIterator();
I2CSPIBusOption configuredBusOption() const { return _bus_option; }
int runningInstancesCount() const;
bool next();
I2CSPIInstance *instance() const;
void removeInstance();
board_bus_types busType() const;
int bus() const;
uint32_t devid() const;
#if defined(CONFIG_SPI)
spi_drdy_gpio_t DRDYGPIO() const;
#endif // CONFIG_SPI
bool external() const;
int externalBusIndex() const;
int busDeviceIndex() const;
void addInstance(I2CSPIInstance *instance);
#if defined(CONFIG_I2C)
static I2CBusIterator::FilterType i2cFilter(I2CSPIBusOption bus_option);
#endif // CONFIG_I2C
#if defined(CONFIG_SPI)
static SPIBusIterator::FilterType spiFilter(I2CSPIBusOption bus_option);
#endif // CONFIG_SPI
const char *moduleName() const { return _module_name; }
uint16_t devidDriverIndex() const { return _devid_driver_index; }
private:
const char *_module_name;
const I2CSPIBusOption _bus_option;
const uint16_t _devid_driver_index;
#if defined(CONFIG_I2C)
const uint8_t _i2c_address;
#endif // CONFIG_I2C
#if defined(CONFIG_SPI)
SPIBusIterator _spi_bus_iterator;
#endif // CONFIG_SPI
#if defined(CONFIG_I2C)
I2CBusIterator _i2c_bus_iterator;
#endif // CONFIG_I2C
List::Iterator _current_instance;
};
I2CSPI实例类对象定义。
主要功能描述:
class I2CSPIInstance : public ListNode
{
public:
virtual ~I2CSPIInstance() = default;
#if defined(CONFIG_I2C)
virtual int8_t get_i2c_address() {return _i2c_address;}
#endif // CONFIG_I2C
private:
I2CSPIInstance(const I2CSPIDriverConfig &config)
: _module_name(config.module_name), _bus_option(config.bus_option), _bus(config.bus),
_devid_driver_index(config.devid_driver_index), _bus_device_index(config.bus_device_index)
#if defined(CONFIG_I2C)
, _i2c_address(config.i2c_address)
#endif // CONFIG_I2C
{}
friend class BusInstanceIterator;
friend class I2CSPIDriverBase;
const char *_module_name;
const I2CSPIBusOption _bus_option;
const int _bus;
const uint16_t _devid_driver_index;
const int8_t _bus_device_index;
#if defined(CONFIG_I2C)
const int8_t _i2c_address; ///< I2C address (optional)
#endif // CONFIG_I2C
};
I2CSPI驱动基础功能类对象定义。
主要功能描述:
class I2CSPIDriverBase : public px4::ScheduledWorkItem, public I2CSPIInstance
{
public:
I2CSPIDriverBase(const I2CSPIDriverConfig &config)
: ScheduledWorkItem(config.module_name, config.wq_config),
I2CSPIInstance(config) {}
static int module_stop(BusInstanceIterator &iterator);
static int module_status(BusInstanceIterator &iterator);
static int module_custom_method(const BusCLIArguments &cli, BusInstanceIterator &iterator,
bool run_on_work_queue = true);
using instantiate_method = I2CSPIDriverBase * (*)(const I2CSPIDriverConfig &config, int runtime_instance);
protected:
virtual ~I2CSPIDriverBase() = default;
virtual void print_status();
virtual void custom_method(const BusCLIArguments &cli) {}
/**
* Exiting the module. A driver can override this, for example to unregister interrupt callbacks.
* This will be called from the work queue.
* A module overriding this, needs to call I2CSPIDriverBase::exit_and_cleanup() as the very last statement.
*/
virtual void exit_and_cleanup() { ScheduleClear(); _task_exited.store(true); }
bool should_exit() const { return _task_should_exit.load(); }
static int module_start(const BusCLIArguments &cli, BusInstanceIterator &iterator, void(*print_usage)(),
instantiate_method instantiate);
private:
static void custom_method_trampoline(void *argument);
void request_stop_and_wait();
px4::atomic_bool _task_should_exit{false};
px4::atomic_bool _task_exited{false};
};
I2CSPI驱动类对象定义。
主要功能描述:
template
class I2CSPIDriver : public I2CSPIDriverBase
{
public:
static int module_start(const BusCLIArguments &cli, BusInstanceIterator &iterator)
{
return I2CSPIDriverBase::module_start(cli, iterator, &T::print_usage, InstantiateHelper::m);
}
protected:
I2CSPIDriver(const I2CSPIDriverConfig &config)
: I2CSPIDriverBase(config) {}
virtual ~I2CSPIDriver() = default;
// *INDENT-OFF* remove once there's astyle >3.1 in CI
void Run() final
{
static_cast(this)->RunImpl();
if (should_exit()) {
exit_and_cleanup();
}
}
// *INDENT-ON*
private:
// SFINAE to use R::instantiate if it exists, and R::instantiate_default otherwise
template
class InstantiateHelper
{
template
static constexpr I2CSPIDriverBase::instantiate_method get(decltype(&C::instantiate)) { return &C::instantiate; }
template
static constexpr I2CSPIDriverBase::instantiate_method get(...) { return &C::instantiate_default; }
public:
static constexpr I2CSPIDriverBase::instantiate_method m = get(0);
};
static I2CSPIDriverBase *instantiate_default(const I2CSPIDriverConfig &config, int runtime_instance)
{
T *instance = new T(config);
if (!instance) {
PX4_ERR("alloc failed");
return nullptr;
}
if (OK != instance->init()) {
delete instance;
return nullptr;
}
return instance;
}
};
PX4系统的I2C/SPI总线分为I2C内部和外部,以及SPI内部和外部四大类。
enum class I2CSPIBusOption : uint8_t {
All = 0, ///< select all runnning instances
#if defined(CONFIG_I2C)
I2CInternal,
I2CExternal,
#endif // CONFIG_I2C
#if defined(CONFIG_SPI)
SPIInternal,
SPIExternal,
#endif // CONFIG_SPI
};
注:暂时先整理这些内容,后续随着代码阅读的增加,再补充完善。
【1】PX4开源软件框架简明简介
【2】PX4模块设计之十二:High Resolution Timer设计
【3】PX4模块设计之十三:WorkQueue设计