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


    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 ListNode
    {
    public:
    
    	void setSibling(T sibling) { _list_node_sibling = sibling; }
    	const T getSibling() const { return _list_node_sibling; }
    
    protected:
    
    	T _list_node_sibling{nullptr};
    
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    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 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};
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125

    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
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78

    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::Iterator _current_instance;
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53

    2.5 I2CSPIInstance类

    I2CSPI实例类对象定义。

    主要功能描述:

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

    class I2CSPIInstance

    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
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    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};
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40

    2.7 I2CSPIDriver类

    I2CSPI驱动类对象定义。

    主要功能描述:

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

    class I2CSPIDriver

    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;
    	}
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56

    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
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    3. 总结

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

    4. 参考资料

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

  • 相关阅读:
    文心一言 VS 讯飞星火 VS chatgpt (286)-- 算法导论21.2 5题
    回归算法的评估指标
    【Redis-09】面试题之Redis数据结构与对象-RedisObject(下篇)
    编程开发中的的字符编码与解码-原理篇
    【python】OpenCV—Statistics
    MySQL数据库库表管理
    无胁科技-TVD每日漏洞情报-2022-11-28
    element-ui的form校验失败
    docker 使用Ubuntu作为基础镜像:安装jdk1.8一直停留,怎么选择都不能跳过去
    海豚调度系列之:任务类型——SQL节点
  • 原文地址:https://blog.csdn.net/lida2003/article/details/126970484