PX4模块设计之四十一:I2C/SPI Bus Instance基础知识

2023-05-16

PX4模块设计之四十一:I2C/SPI Bus Instance基础知识

  • 1. 基础知识
  • 2. 基础类和定义
    • 2.1 ListNode类
    • 2.2 List类
    • 2.3 BusCLIArguments类
    • 2.4 BusInstanceIterator类
    • 2.5 I2CSPIInstance类
    • 2.6 I2CSPIDriverBase类
    • 2.7 I2CSPIDriver类
    • 2.8 I2C/SPI总线选项
  • 3. 总结
  • 4. 参考资料

1. 基础知识

  1. ListNode类
  2. List类
  3. BusCLIArguments类
  4. BusInstanceIterator类
  5. I2CSPIInstance类
  6. I2CSPIDriverBase类
  7. I2CSPIDriver类
  8. I2C/SPI总线选项

2. 基础类和定义

2.1 ListNode类

主要功能描述:

  1. 采用类模板扩展ListNode应用范围
  2. 通过 setSibling 设置成员变量_list_node_sibling
  3. 通过 getSibling 获取成员变量_list_node_sibling

注:这个类类似于C语言单向链表的一个节点结构声明。

class ListNode

template<class T>
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};

};

2.2 List类

主要功能描述:

  1. 基于ListNode类实现了单链表功能
  2. 支持新增一个ListNode操作: void add(T newNode)
  3. 支持删除一个ListNode操作: bool remove(T removeNode)/void deleteNode(T node)
  4. 支持列表是否为空判断: bool empty()
  5. 支持列表清空操作: void clear()
  6. 支持列表元素数量获取: size_t size()
  7. 支持列表头元素获取: const T getHead()
  8. 支持Iterator操作: Iterator begin()/Iterator end()

class List

template<class T>
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};
};

2.3 BusCLIArguments类

命令行参数配置总线设备。

主要功能描述:

  1. 支持总线参数命令行解析: parseDefaultArguments
  2. 支持总线参数检查: validateConfiguration
  3. 总线参数类型:I2C(_i2c_support) or SPI(_spi_support)
  4. 支持总线选项: I2C/SPI 内部/外部(bus_option)
  5. 内部总线号(requested_bus)
  6. 支持总线工作频率设置(bus_frequency)
  7. 支持静默启动功能(quiet_start) //do not print a message when startup fails
  8. 【代码中未见相关功能】支持总线PNP动态功能???(keep_running) //eep driver running even if no device is detected on startup
  9. 支持是否需要keep_running功能(support_keep_running) //true if keep_running (see above) is supported
  10. 支持硬件mount方向修正(rotation) //sensor rotation (MAV_SENSOR_ROTATION_* or distance_sensor_s::ROTATION_*)
  11. 支持设备相关自定义参数(custom1/custom2/custom_data) //driver-specific custom argument
  12. I2C 总线
    I2C Slave地址(i2c_address)
    I2C默认频率(default_i2c_frequency)
  13. SPI 总线
    SPI芯片选择(chipselect)
    SPI工作模式(spi_mode)
    SPI默认频率(default_spi_frequency)

class BusCLIArguments

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
};

2.4 BusInstanceIterator类

使用给定的过滤器选项迭代运行实例和/或配置的I2C/SPI总线。

主要功能描述:

  1. 支持I2C/SPI总线配置
  2. 支持I2C/SPI总线设备添加
  3. 支持I2C/SPI总线设备移除
  4. 支持I2C/SPI总线设备相关属性的获取

class BusInstanceIterator

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<I2CSPIInstance *>::Iterator _current_instance;
};

2.5 I2CSPIInstance类

I2CSPI实例类对象定义。

主要功能描述:

  1. 支持I2C/SPI总线实例对象类声明
  2. 支持I2C/SPI总线类对象BusInstanceIterator/I2CSPIDriverBase友元类

class I2CSPIInstance

class I2CSPIInstance : public ListNode<I2CSPIInstance *>
{
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
};

2.6 I2CSPIDriverBase类

I2CSPI驱动基础功能类对象定义。

主要功能描述:

  1. 支持I2C/SPI驱动基础功能模块启动
  2. 支持I2C/SPI驱动基础功能模块停止
  3. 支持I2C/SPI驱动基础功能模块状态查询

class I2CSPIDriverBase

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};
};

2.7 I2CSPIDriver类

I2CSPI驱动类对象定义。

主要功能描述:

  1. 支持驱动定制启动
  2. 支持驱动定义业务运行逻辑

class I2CSPIDriver

template<class T>
class I2CSPIDriver : public I2CSPIDriverBase
{
public:
	static int module_start(const BusCLIArguments &cli, BusInstanceIterator &iterator)
	{
		return I2CSPIDriverBase::module_start(cli, iterator, &T::print_usage, InstantiateHelper<T>::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<T *>(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 <typename R>
	class InstantiateHelper
	{
		template <typename C>
		static constexpr I2CSPIDriverBase::instantiate_method get(decltype(&C::instantiate)) { return &C::instantiate; }
		template <typename C>
		static constexpr I2CSPIDriverBase::instantiate_method get(...) { return &C::instantiate_default; }
	public:
		static constexpr I2CSPIDriverBase::instantiate_method m = get<R>(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;
	}
};

2.8 I2C/SPI总线选项

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
};

3. 总结

注:暂时先整理这些内容,后续随着代码阅读的增加,再补充完善。

4. 参考资料

【1】PX4开源软件框架简明简介
【2】PX4模块设计之十二:High Resolution Timer设计
【3】PX4模块设计之十三:WorkQueue设计

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

PX4模块设计之四十一:I2C/SPI Bus Instance基础知识 的相关文章

  • ucos多任务与linux进程、多线程的比较分析

    从最初使用51片机 xff0c 再到avr msp430 xff0c arm7 arm9裸机 xff0c 单片机的处理速度越来越快 xff0c 而产品需求的日新月异 xff0c 在硬件成本 功耗 体积以及开发周期等的限制下 xff0c 开发
  • 【记录】Ubuntu下简单的软件安装-aptitude安装,samba安装,terminator软件

    Ubuntu下安装简单的软件 一 安装aptitude管理软件 sudo apt get install aptitude 这样可以使用aptitude来管理软件 如下命令 xff1a sudo aptitude update 更新软件源
  • freeRTOS开源项目crazyflie

    不小心接触到了开源飞控 xff0c 有一个小四轴的项目 xff1a crazyflie xff0c 有兴趣百度搜 使用的就是freeRTOS内核 xff0c 可以作为学习freeRTOS应用的一个参考 另外freeRTOS官方源码包里面就有
  • ROS serial串口通讯

    目录 ROS serial 串口通讯安装基本使用代码示例 Reference ROS serial 串口通讯 安装 sudo apt get install ros kinetic serial 基本使用 代码示例 include lt r
  • 四轴飞控DIY简明步骤介绍

    新手四轴飞控DIY组装简明步骤介绍 1 什么叫做新手 xff1f 2 新手如何思考 xff1f 3 上手步骤Step1 xff1a 四轴飞控介绍定义运动原理组成 Step2 xff1a 四轴飞控组装视频Step3 xff1a 四轴飞控新手规
  • BetaFlight开源工程结构简明介绍

    BetaFlight开源工程结构简明介绍 Step1 获取开源代码开源代码版本克隆开源代码 Step2 了解工程情况支持模型类型 xff1a 多旋翼 amp 固定翼支持特性 amp 功能安装 amp 文档链接配置工具下载其他介绍 xff08
  • 四轴FPV无人机手动操作简明介绍

    四轴FPV无人机手动操作简明介绍 通常航拍机都是有自稳算法 43 GPS导航 43 辅助功能 避障 的支持 xff0c 从而保证飞手能够相对容易且稳定的操作模型飞机 xff0c 通常通过阅读说明书都能很快上手 xff0c 这里就不在赘述 本
  • BetaFlight模块设计之三十:Cli模块分析

    BetaFlight模块设计之三十 xff1a Cli模块分析 Cli模块Cli接口Cli框架Cli命令结构主要函数分析cliProcess函数processCharacterInteractive函数processCharacter函数
  • PX4开发环境搭建--模拟器编译及QGroundControl & RC遥控模拟配置

    PX4开发环境搭建 模拟器编译 1 PX4开发环境介绍2 PX4开发环境搭建2 1代码下载2 2 国内环境调整2 3 建立ubuntu开发环境2 4 构建jMAVSim仿真2 5 补充版本信息 3 jmavsim仿真环境3 1 仿真命令集3
  • Android中的枚举

    在ARouter源码中发现使用到了枚举 xff0c 说明枚举并不是不常见的 xff0c 刚好枚举在我的视野中处于盲区 xff0c 于是打算周末加班给拿下 xff0c 扩展视野 了解枚举之前首先说一下什么是常量和变量 常量 声明后无法改变的量
  • PX4开源工程结构简明介绍

    PX4开源工程结构简明介绍 Step1 获取开源代码1 1 开源代码版本1 2 克隆开源代码 Step2 了解工程情况2 1 支持模型类型2 2 支持特性 amp 功能2 3 安装 amp 文档链接2 4 配置工具下载2 5 其他介绍 xf
  • PX4开源软件框架简明简介

    PX4开源软件框架简明简介 1 PX4系统构架1 1 飞控 43 地面站 RC控制1 2 飞控 43 伴飞电脑 43 地面站 集成RC控制 2 PX4软件构架2 1 设计概念2 2 软件构架2 1 中间件2 2 飞控代码 3 PX4运行环境
  • PX4模块设计之一:SITL & HITL模拟框架

    PX4模块设计之一 xff1a SITL amp HITL模拟框架 1 模拟框架1 1 SITL模拟框架1 2 HITL模拟框架 2 模拟器类型3 MAVLink API4 总结 基于PX4开源软件框架简明简介的框架设计 xff0c 逐步分
  • PX4模块设计之二:uORB消息代理

    PX4模块设计之二 xff1a uORB消息代理 1 uORB模块接口1 1 uORB服务接口1 2 uORB消息注册 去注册接口1 3 uORB消息发布接口1 4 uORB消息订阅 去订阅接口1 5 uORB辅助功能接口2 Hello W
  • PX4模块设计之三:自定义uORB消息

    PX4模块设计之三 xff1a 自定义uORB消息 1 新增自定义uORB消息步骤2 应用ext hello world消息示例3 编译执行结果4 参考资料 基于PX4开源软件框架简明简介和PX4模块设计之二 xff1a uORB消息代理
  • PX4模块设计之四:MAVLink简介

    PX4模块设计之四 xff1a MAVLink简介 1 MAVLink PX4 应用简介2 MAVLink v2 0新特性3 MAVLink协议版本4 MAVLink通信协议帧4 1 MAVLink v1 0 帧格式4 2 MAVLink
  • PX4模块设计之五:自定义MAVLink消息

    PX4模块设计之五 xff1a 自定义MAVLink消息 1 MAVLink Dialects1 1 PX4 Dialects1 2 Paprazzi Dialects1 3 MAVLink XML File Format 2 添加自定义M
  • PX4模块设计之六:PX4-Fast RTPS(DDS)简介

    64 TOC PX4模块设计之六 xff1a PX4 Fast RTPS DDS 简介 基于PX4开源软件框架简明简介的框架设计 xff0c 逐步分析内部模块功能设计 PX4 Fast RTPS DDS 具有实时发布 订阅uORB消息接口
  • PX4模块设计之九:PX4飞行模式简介

    PX4模块设计之九 xff1a PX4飞行模式简介 关于模式的探讨1 需求角度1 1 多旋翼 MC multi copter 1 1 1 RC控制模式1 1 1 1 Position Mode1 1 1 2 Altitude Mode1 1
  • PX4模块设计之十:PX4启动过程

    PX4模块设计之十 xff1a PX4启动过程 1 硬件 飞控硬件上电2 硬件 飞控硬件初始化3 硬件 43 软件 飞控bootloader初始化4 硬件 43 软件 飞控系统初始化5 软件 飞控应用初始化6 配置 SD卡配置文件6 1 e

随机推荐