10 changed files with 1151 additions and 2 deletions
@ -0,0 +1,88 @@
@@ -0,0 +1,88 @@
|
||||
/****************************************************************************
|
||||
* |
||||
* Copyright (C) 2020 PX4 Development Team. All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions |
||||
* are met: |
||||
* |
||||
* 1. Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* 2. Redistributions in binary form must reproduce the above copyright |
||||
* notice, this list of conditions and the following disclaimer in |
||||
* the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* 3. Neither the name PX4 nor the names of its contributors may be |
||||
* used to endorse or promote products derived from this software |
||||
* without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS |
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE |
||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, |
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, |
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS |
||||
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED |
||||
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN |
||||
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
||||
* POSSIBILITY OF SUCH DAMAGE. |
||||
* |
||||
****************************************************************************/ |
||||
|
||||
#include <board_config.h> |
||||
#ifndef BOARD_DISABLE_I2C_SPI |
||||
|
||||
#include <px4_platform_common/i2c.h> |
||||
|
||||
#ifndef BOARD_OVERRIDE_I2C_BUS_EXTERNAL |
||||
bool px4_i2c_bus_external(const px4_i2c_bus_t &bus) |
||||
{ |
||||
return bus.is_external; |
||||
} |
||||
#endif |
||||
|
||||
bool I2CBusIterator::next() |
||||
{ |
||||
while (++_index < I2C_BUS_MAX_BUS_ITEMS && px4_i2c_buses[_index].bus != -1) { |
||||
const px4_i2c_bus_t &bus_data = px4_i2c_buses[_index]; |
||||
|
||||
if (!board_has_bus(BOARD_I2C_BUS, bus_data.bus)) { |
||||
continue; |
||||
} |
||||
|
||||
switch (_filter) { |
||||
case FilterType::All: |
||||
if (_bus == bus_data.bus || _bus == -1) { |
||||
return true; |
||||
} |
||||
|
||||
break; |
||||
|
||||
case FilterType::InternalBus: |
||||
if (!px4_i2c_bus_external(bus_data)) { |
||||
if (_bus == bus_data.bus || _bus == -1) { |
||||
return true; |
||||
} |
||||
} |
||||
|
||||
break; |
||||
|
||||
case FilterType::ExternalBus: |
||||
if (px4_i2c_bus_external(bus_data)) { |
||||
++_external_bus_counter; |
||||
|
||||
if (_bus == _external_bus_counter || _bus == -1) { |
||||
return true; |
||||
} |
||||
} |
||||
|
||||
break; |
||||
} |
||||
} |
||||
|
||||
return false; |
||||
} |
||||
|
||||
#endif /* BOARD_DISABLE_I2C_SPI */ |
@ -0,0 +1,393 @@
@@ -0,0 +1,393 @@
|
||||
/****************************************************************************
|
||||
* |
||||
* Copyright (C) 2020 PX4 Development Team. All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions |
||||
* are met: |
||||
* |
||||
* 1. Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* 2. Redistributions in binary form must reproduce the above copyright |
||||
* notice, this list of conditions and the following disclaimer in |
||||
* the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* 3. Neither the name PX4 nor the names of its contributors may be |
||||
* used to endorse or promote products derived from this software |
||||
* without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS |
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE |
||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, |
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, |
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS |
||||
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED |
||||
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN |
||||
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
||||
* POSSIBILITY OF SUCH DAMAGE. |
||||
* |
||||
****************************************************************************/ |
||||
|
||||
#include <board_config.h> |
||||
#ifndef BOARD_DISABLE_I2C_SPI |
||||
|
||||
#ifndef MODULE_NAME |
||||
#define MODULE_NAME "SPI_I2C" |
||||
#endif |
||||
|
||||
#include <lib/drivers/device/Device.hpp> |
||||
#include <px4_platform_common/i2c_spi_buses.h> |
||||
#include <px4_platform_common/log.h> |
||||
|
||||
BusInstanceIterator::BusInstanceIterator(I2CSPIInstance **instances, int max_num_instances, |
||||
const BusCLIArguments &cli_arguments, uint16_t devid_driver_index) |
||||
: _instances(instances), _max_num_instances(max_num_instances), |
||||
_bus_option(cli_arguments.bus_option), |
||||
_spi_bus_iterator(spiFilter(cli_arguments.bus_option), |
||||
cli_arguments.bus_option == I2CSPIBusOption::SPIExternal ? cli_arguments.chipselect_index : devid_driver_index, |
||||
cli_arguments.requested_bus), |
||||
_i2c_bus_iterator(i2cFilter(cli_arguments.bus_option), cli_arguments.requested_bus) |
||||
{ |
||||
} |
||||
|
||||
bool BusInstanceIterator::next() |
||||
{ |
||||
int bus = -1; |
||||
|
||||
if (busType() == BOARD_INVALID_BUS) { |
||||
while (++_current_instance < _max_num_instances && _instances[_current_instance] == nullptr) {} |
||||
|
||||
return _current_instance < _max_num_instances; |
||||
|
||||
} else if (busType() == BOARD_SPI_BUS) { |
||||
if (_spi_bus_iterator.next()) { |
||||
bus = _spi_bus_iterator.bus().bus; |
||||
} |
||||
|
||||
} else { |
||||
if (_i2c_bus_iterator.next()) { |
||||
bus = _i2c_bus_iterator.bus().bus; |
||||
} |
||||
} |
||||
|
||||
if (bus != -1) { |
||||
// find matching runtime instance
|
||||
_current_instance = -1; |
||||
|
||||
for (int i = 0; i < _max_num_instances; ++i) { |
||||
if (!_instances[i]) { |
||||
continue; |
||||
} |
||||
|
||||
if (_bus_option == _instances[i]->_bus_option && bus == _instances[i]->_bus) { |
||||
_current_instance = i; |
||||
} |
||||
} |
||||
|
||||
return true; |
||||
} |
||||
|
||||
return false; |
||||
} |
||||
|
||||
int BusInstanceIterator::nextFreeInstance() const |
||||
{ |
||||
for (int i = 0; i < _max_num_instances; ++i) { |
||||
if (_instances[i] == nullptr) { |
||||
return i; |
||||
} |
||||
} |
||||
|
||||
return -1; |
||||
} |
||||
|
||||
I2CSPIInstance *BusInstanceIterator::instance() const |
||||
{ |
||||
if (_current_instance < 0 || _current_instance >= _max_num_instances) { |
||||
return nullptr; |
||||
} |
||||
|
||||
return _instances[_current_instance]; |
||||
} |
||||
|
||||
void BusInstanceIterator::resetInstance() |
||||
{ |
||||
if (_current_instance >= 0 && _current_instance < _max_num_instances) { |
||||
_instances[_current_instance] = nullptr; |
||||
} |
||||
} |
||||
|
||||
board_bus_types BusInstanceIterator::busType() const |
||||
{ |
||||
switch (_bus_option) { |
||||
case I2CSPIBusOption::All: |
||||
return BOARD_INVALID_BUS; |
||||
|
||||
case I2CSPIBusOption::I2CInternal: |
||||
case I2CSPIBusOption::I2CExternal: |
||||
return BOARD_I2C_BUS; |
||||
|
||||
case I2CSPIBusOption::SPIInternal: |
||||
case I2CSPIBusOption::SPIExternal: |
||||
return BOARD_SPI_BUS; |
||||
} |
||||
|
||||
return BOARD_INVALID_BUS; |
||||
} |
||||
|
||||
int BusInstanceIterator::bus() const |
||||
{ |
||||
if (busType() == BOARD_INVALID_BUS) { |
||||
return -1; |
||||
|
||||
} else if (busType() == BOARD_SPI_BUS) { |
||||
return _spi_bus_iterator.bus().bus; |
||||
|
||||
} else { |
||||
return _i2c_bus_iterator.bus().bus; |
||||
} |
||||
} |
||||
|
||||
uint32_t BusInstanceIterator::devid() const |
||||
{ |
||||
if (busType() == BOARD_INVALID_BUS) { |
||||
return 0; |
||||
|
||||
} else if (busType() == BOARD_SPI_BUS) { |
||||
return _spi_bus_iterator.devid(); |
||||
|
||||
} else { |
||||
return 0; |
||||
} |
||||
} |
||||
|
||||
uint32_t BusInstanceIterator::DRDYGPIO() const |
||||
{ |
||||
if (busType() == BOARD_INVALID_BUS) { |
||||
return 0; |
||||
|
||||
} else if (busType() == BOARD_SPI_BUS) { |
||||
return _spi_bus_iterator.DRDYGPIO(); |
||||
|
||||
} else { |
||||
return 0; |
||||
} |
||||
} |
||||
|
||||
bool BusInstanceIterator::external() const |
||||
{ |
||||
if (busType() == BOARD_INVALID_BUS) { |
||||
return false; |
||||
|
||||
} else if (busType() == BOARD_SPI_BUS) { |
||||
return _spi_bus_iterator.external(); |
||||
|
||||
} else { |
||||
return _i2c_bus_iterator.external(); |
||||
} |
||||
} |
||||
|
||||
I2CBusIterator::FilterType BusInstanceIterator::i2cFilter(I2CSPIBusOption bus_option) |
||||
{ |
||||
switch (bus_option) { |
||||
case I2CSPIBusOption::All: return I2CBusIterator::FilterType::All; |
||||
|
||||
case I2CSPIBusOption::I2CExternal: return I2CBusIterator::FilterType::ExternalBus; |
||||
|
||||
case I2CSPIBusOption::I2CInternal: return I2CBusIterator::FilterType::InternalBus; |
||||
|
||||
default: break; |
||||
} |
||||
|
||||
return I2CBusIterator::FilterType::All; |
||||
} |
||||
|
||||
SPIBusIterator::FilterType BusInstanceIterator::spiFilter(I2CSPIBusOption bus_option) |
||||
{ |
||||
switch (bus_option) { |
||||
case I2CSPIBusOption::SPIExternal: return SPIBusIterator::FilterType::ExternalBus; |
||||
|
||||
case I2CSPIBusOption::SPIInternal: return SPIBusIterator::FilterType::InternalBus; |
||||
|
||||
default: break; |
||||
} |
||||
|
||||
return SPIBusIterator::FilterType::InternalBus; |
||||
} |
||||
|
||||
|
||||
int I2CSPIDriverBase::module_start(const BusCLIArguments &cli, BusInstanceIterator &iterator, |
||||
void(*print_usage)(), |
||||
instantiate_method instantiate, I2CSPIInstance **instances) |
||||
{ |
||||
if (iterator.configuredBusOption() == I2CSPIBusOption::All) { |
||||
PX4_ERR("need to specify a bus type"); |
||||
print_usage(); |
||||
return -1; |
||||
} |
||||
|
||||
bool started = false; |
||||
|
||||
while (iterator.next()) { |
||||
if (iterator.instance()) { |
||||
continue; // already running
|
||||
} |
||||
|
||||
const int free_index = iterator.nextFreeInstance(); |
||||
|
||||
if (free_index < 0) { |
||||
PX4_ERR("Not enough instances"); |
||||
return -1; |
||||
} |
||||
|
||||
device::Device::DeviceId device_id{}; |
||||
device_id.devid_s.bus = iterator.bus(); |
||||
|
||||
switch (iterator.busType()) { |
||||
case BOARD_I2C_BUS: device_id.devid_s.bus_type = device::Device::DeviceBusType_I2C; break; |
||||
|
||||
case BOARD_SPI_BUS: device_id.devid_s.bus_type = device::Device::DeviceBusType_SPI; break; |
||||
|
||||
case BOARD_INVALID_BUS: device_id.devid_s.bus_type = device::Device::DeviceBusType_UNKNOWN; break; |
||||
} |
||||
|
||||
// initialize the object and bus on the work queue thread - this will also probe for the device
|
||||
I2CSPIDriverInitializer initializer(px4::device_bus_to_wq(device_id.devid), cli, iterator, instantiate, free_index); |
||||
initializer.ScheduleNow(); |
||||
initializer.wait(); |
||||
I2CSPIDriverBase *instance = initializer.instance(); |
||||
|
||||
if (!instance) { |
||||
PX4_DEBUG("instantiate failed (no device on bus %i (devid 0x%x)?)", iterator.bus(), iterator.devid()); |
||||
continue; |
||||
} |
||||
|
||||
instances[free_index] = instance; |
||||
started = true; |
||||
|
||||
// print some info that we are running
|
||||
switch (iterator.busType()) { |
||||
case BOARD_I2C_BUS: |
||||
PX4_INFO_RAW("%s #%i on I2C bus %d%s\n", |
||||
instance->ItemName(), free_index, iterator.bus(), iterator.external() ? " (external)" : ""); |
||||
break; |
||||
|
||||
case BOARD_SPI_BUS: |
||||
PX4_INFO_RAW("%s #%i on SPI bus %d (devid=0x%x)%s\n", |
||||
instance->ItemName(), free_index, iterator.bus(), PX4_SPI_DEV_ID(iterator.devid()), |
||||
iterator.external() ? " (external)" : ""); |
||||
break; |
||||
|
||||
case BOARD_INVALID_BUS: |
||||
break; |
||||
} |
||||
} |
||||
|
||||
return started ? 0 : -1; |
||||
} |
||||
|
||||
|
||||
int I2CSPIDriverBase::module_stop(BusInstanceIterator &iterator) |
||||
{ |
||||
bool is_running = false; |
||||
|
||||
while (iterator.next()) { |
||||
if (iterator.instance()) { |
||||
I2CSPIDriverBase *instance = (I2CSPIDriverBase *)iterator.instance(); |
||||
instance->request_stop_and_wait(); |
||||
delete iterator.instance(); |
||||
iterator.resetInstance(); |
||||
is_running = true; |
||||
} |
||||
} |
||||
|
||||
if (!is_running) { |
||||
PX4_ERR("Not running"); |
||||
return -1; |
||||
} |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
int I2CSPIDriverBase::module_status(BusInstanceIterator &iterator) |
||||
{ |
||||
bool is_running = false; |
||||
|
||||
while (iterator.next()) { |
||||
if (iterator.instance()) { |
||||
I2CSPIDriverBase *instance = (I2CSPIDriverBase *)iterator.instance(); |
||||
instance->print_status(); |
||||
is_running = true; |
||||
} |
||||
} |
||||
|
||||
if (!is_running) { |
||||
PX4_INFO("Not running"); |
||||
return -1; |
||||
} |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
int I2CSPIDriverBase::module_custom_method(const BusCLIArguments &cli, BusInstanceIterator &iterator) |
||||
{ |
||||
while (iterator.next()) { |
||||
if (iterator.instance()) { |
||||
I2CSPIDriverBase *instance = (I2CSPIDriverBase *)iterator.instance(); |
||||
instance->custom_method(cli); |
||||
} |
||||
} |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
void I2CSPIDriverBase::print_status() |
||||
{ |
||||
bool is_i2c_bus = _bus_option == I2CSPIBusOption::I2CExternal || _bus_option == I2CSPIBusOption::I2CInternal; |
||||
PX4_INFO("Running on %s Bus %i", is_i2c_bus ? "I2C" : "SPI", _bus); |
||||
} |
||||
|
||||
void I2CSPIDriverBase::request_stop_and_wait() |
||||
{ |
||||
_task_should_exit.store(true); |
||||
ScheduleNow(); // wake up the task (in case it is not scheduled anymore or just to be faster)
|
||||
unsigned int i = 0; |
||||
|
||||
do { |
||||
px4_usleep(20000); // 20 ms
|
||||
// wait at most 2 sec
|
||||
} while (++i < 100 && !_task_exited.load()); |
||||
|
||||
if (i >= 100) { |
||||
PX4_ERR("Module did not respond to stop request"); |
||||
} |
||||
} |
||||
|
||||
I2CSPIDriverInitializer::I2CSPIDriverInitializer(const px4::wq_config_t &config, const BusCLIArguments &cli, |
||||
const BusInstanceIterator &iterator, instantiate_method instantiate, int runtime_instance) |
||||
: px4::WorkItem("<driver_init>", config), |
||||
_cli(cli), _iterator(iterator), _runtime_instance(runtime_instance), _instantiate(instantiate) |
||||
{ |
||||
px4_sem_init(&_sem, 0, 0); |
||||
} |
||||
|
||||
I2CSPIDriverInitializer::~I2CSPIDriverInitializer() |
||||
{ |
||||
px4_sem_destroy(&_sem); |
||||
} |
||||
|
||||
void I2CSPIDriverInitializer::wait() |
||||
{ |
||||
while (px4_sem_wait(&_sem) != 0) {} |
||||
} |
||||
|
||||
void I2CSPIDriverInitializer::Run() |
||||
{ |
||||
_instance = _instantiate(_cli, _iterator, _runtime_instance); |
||||
px4_sem_post(&_sem); |
||||
} |
||||
|
||||
#endif /* BOARD_DISABLE_I2C_SPI */ |
@ -0,0 +1,100 @@
@@ -0,0 +1,100 @@
|
||||
/****************************************************************************
|
||||
* |
||||
* Copyright (c) 2020 PX4 Development Team. All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions |
||||
* are met: |
||||
* |
||||
* 1. Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* 2. Redistributions in binary form must reproduce the above copyright |
||||
* notice, this list of conditions and the following disclaimer in |
||||
* the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* 3. Neither the name PX4 nor the names of its contributors may be |
||||
* used to endorse or promote products derived from this software |
||||
* without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS |
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE |
||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, |
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, |
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS |
||||
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED |
||||
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN |
||||
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
||||
* POSSIBILITY OF SUCH DAMAGE. |
||||
* |
||||
****************************************************************************/ |
||||
|
||||
#pragma once |
||||
|
||||
#include <board_config.h> |
||||
|
||||
#define I2C_BUS_MAX_BUS_ITEMS PX4_NUMBER_I2C_BUSES |
||||
|
||||
struct px4_i2c_bus_t { |
||||
int bus{-1}; ///< physical bus number (1, ...) (-1 means this is unused)
|
||||
bool is_external; ///< static external configuration. Use px4_i2c_bus_external() to check if a bus is really external
|
||||
}; |
||||
|
||||
__EXPORT extern const px4_i2c_bus_t px4_i2c_buses[I2C_BUS_MAX_BUS_ITEMS]; ///< board-specific I2C bus configuration
|
||||
|
||||
/**
|
||||
* runtime-check if a board has a specific bus as external. |
||||
* This can be overridden by a board to add run-time checks. |
||||
*/ |
||||
__EXPORT bool px4_i2c_bus_external(const px4_i2c_bus_t &bus); |
||||
|
||||
/**
|
||||
* runtime-check if a board has a specific bus as external. |
||||
*/ |
||||
static inline bool px4_i2c_bus_external(int bus) |
||||
{ |
||||
for (int i = 0; i < I2C_BUS_MAX_BUS_ITEMS; ++i) { |
||||
if (px4_i2c_buses[i].bus == bus) { |
||||
return px4_i2c_bus_external(px4_i2c_buses[i]); |
||||
} |
||||
} |
||||
|
||||
return true; |
||||
} |
||||
|
||||
|
||||
/**
|
||||
* @class I2CBusIterator |
||||
* Iterate over configured I2C buses by the board |
||||
*/ |
||||
class I2CBusIterator |
||||
{ |
||||
public: |
||||
enum class FilterType { |
||||
All, ///< specific or all buses
|
||||
InternalBus, ///< specific or all internal buses
|
||||
ExternalBus, ///< specific or all external buses
|
||||
}; |
||||
|
||||
/**
|
||||
* @param bus specify bus: starts with 1, -1=all. Internal: arch-specific bus numbering is used, |
||||
* external: n-th external bus |
||||
*/ |
||||
I2CBusIterator(FilterType filter, int bus = -1) |
||||
: _filter(filter), _bus(bus) {} |
||||
|
||||
bool next(); |
||||
|
||||
const px4_i2c_bus_t &bus() const { return px4_i2c_buses[_index]; } |
||||
|
||||
bool external() const { return px4_i2c_bus_external(bus()); } |
||||
|
||||
private: |
||||
const FilterType _filter; |
||||
const int _bus; |
||||
int _index{-1}; |
||||
int _external_bus_counter{0}; |
||||
}; |
||||
|
@ -0,0 +1,229 @@
@@ -0,0 +1,229 @@
|
||||
/****************************************************************************
|
||||
* |
||||
* Copyright (c) 2020 PX4 Development Team. All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions |
||||
* are met: |
||||
* |
||||
* 1. Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* 2. Redistributions in binary form must reproduce the above copyright |
||||
* notice, this list of conditions and the following disclaimer in |
||||
* the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* 3. Neither the name PX4 nor the names of its contributors may be |
||||
* used to endorse or promote products derived from this software |
||||
* without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS |
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE |
||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, |
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, |
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS |
||||
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED |
||||
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN |
||||
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
||||
* POSSIBILITY OF SUCH DAMAGE. |
||||
* |
||||
****************************************************************************/ |
||||
|
||||
#pragma once |
||||
|
||||
#include "i2c.h" |
||||
#include "spi.h" |
||||
|
||||
#include <stdint.h> |
||||
|
||||
#include <lib/conversion/rotation.h> |
||||
#include <px4_platform_common/atomic.h> |
||||
#include <px4_platform_common/px4_work_queue/ScheduledWorkItem.hpp> |
||||
#include <px4_platform_common/sem.h> |
||||
#include <board_config.h> |
||||
|
||||
enum class I2CSPIBusOption : uint8_t { |
||||
All = 0, ///< select all runnning instances
|
||||
I2CInternal, |
||||
I2CExternal, |
||||
SPIInternal, |
||||
SPIExternal, |
||||
}; |
||||
|
||||
/**
|
||||
* @class I2CSPIInstance |
||||
* I2C/SPI driver instance used by BusInstanceIterator to find running instances. |
||||
*/ |
||||
class I2CSPIInstance |
||||
{ |
||||
public: |
||||
I2CSPIInstance(I2CSPIBusOption bus_option, int bus) |
||||
: _bus_option(bus_option), _bus(bus) {} |
||||
|
||||
virtual ~I2CSPIInstance() = default; |
||||
|
||||
private: |
||||
friend class BusInstanceIterator; |
||||
friend class I2CSPIDriverBase; |
||||
|
||||
const I2CSPIBusOption _bus_option; |
||||
const int _bus; |
||||
}; |
||||
|
||||
struct BusCLIArguments { |
||||
I2CSPIBusOption bus_option{I2CSPIBusOption::All}; |
||||
int requested_bus{-1}; |
||||
int chipselect_index{1}; |
||||
Rotation rotation{ROTATION_NONE}; |
||||
int custom1; ///< driver-specific custom argument
|
||||
int custom2; ///< driver-specific custom argument
|
||||
}; |
||||
|
||||
/**
|
||||
* @class BusInstanceIterator |
||||
* Iterate over running instances and/or configured I2C/SPI buses with given filter options. |
||||
*/ |
||||
class BusInstanceIterator |
||||
{ |
||||
public: |
||||
BusInstanceIterator(I2CSPIInstance **instances, int max_num_instances, |
||||
const BusCLIArguments &cli_arguments, uint16_t devid_driver_index); |
||||
~BusInstanceIterator() = default; |
||||
|
||||
I2CSPIBusOption configuredBusOption() const { return _bus_option; } |
||||
|
||||
int nextFreeInstance() const; |
||||
|
||||
bool next(); |
||||
|
||||
I2CSPIInstance *instance() const; |
||||
void resetInstance(); |
||||
board_bus_types busType() const; |
||||
int bus() const; |
||||
uint32_t devid() const; |
||||
uint32_t DRDYGPIO() const; |
||||
bool external() const; |
||||
|
||||
static I2CBusIterator::FilterType i2cFilter(I2CSPIBusOption bus_option); |
||||
static SPIBusIterator::FilterType spiFilter(I2CSPIBusOption bus_option); |
||||
private: |
||||
I2CSPIInstance **_instances; |
||||
const int _max_num_instances; |
||||
const I2CSPIBusOption _bus_option; |
||||
SPIBusIterator _spi_bus_iterator; |
||||
I2CBusIterator _i2c_bus_iterator; |
||||
int _current_instance{-1}; |
||||
}; |
||||
|
||||
/**
|
||||
* @class I2CSPIDriverBase |
||||
* Base class for I2C/SPI driver modules (non-templated, used by I2CSPIDriver) |
||||
*/ |
||||
class I2CSPIDriverBase : public px4::ScheduledWorkItem, public I2CSPIInstance |
||||
{ |
||||
public: |
||||
I2CSPIDriverBase(const char *module_name, const px4::wq_config_t &config, I2CSPIBusOption bus_option, int bus) |
||||
: ScheduledWorkItem(module_name, config), |
||||
I2CSPIInstance(bus_option, bus) {} |
||||
|
||||
static int module_stop(BusInstanceIterator &iterator); |
||||
static int module_status(BusInstanceIterator &iterator); |
||||
static int module_custom_method(const BusCLIArguments &cli, BusInstanceIterator &iterator); |
||||
|
||||
using instantiate_method = I2CSPIDriverBase * (*)(const BusCLIArguments &cli, const BusInstanceIterator &iterator, |
||||
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, I2CSPIInstance **instances); |
||||
|
||||
private: |
||||
void request_stop_and_wait(); |
||||
|
||||
px4::atomic_bool _task_should_exit{false}; |
||||
px4::atomic_bool _task_exited{false}; |
||||
}; |
||||
|
||||
/**
|
||||
* @class I2CSPIDriver |
||||
* Base class for I2C/SPI driver modules |
||||
*/ |
||||
template<class T, int MAX_NUM = 3> |
||||
class I2CSPIDriver : public I2CSPIDriverBase |
||||
{ |
||||
public: |
||||
static constexpr int max_num_instances = MAX_NUM; |
||||
|
||||
static int module_start(const BusCLIArguments &cli, BusInstanceIterator &iterator) |
||||
{ |
||||
return I2CSPIDriverBase::module_start(cli, iterator, &T::print_usage, &T::instantiate, _instances); |
||||
} |
||||
|
||||
static I2CSPIInstance **instances() { return _instances; } |
||||
|
||||
protected: |
||||
I2CSPIDriver(const char *module_name, const px4::wq_config_t &config, I2CSPIBusOption bus_option, int bus) |
||||
: I2CSPIDriverBase(module_name, config, bus_option, bus) {} |
||||
|
||||
virtual ~I2CSPIDriver() = default; |
||||
|
||||
void Run() final { |
||||
static_cast<T *>(this)->RunImpl(); |
||||
|
||||
if (should_exit()) |
||||
{ |
||||
exit_and_cleanup(); |
||||
} |
||||
} |
||||
private: |
||||
static I2CSPIInstance *_instances[MAX_NUM]; |
||||
}; |
||||
|
||||
template<class T, int MAX_NUM> |
||||
I2CSPIInstance *I2CSPIDriver<T, MAX_NUM>::_instances[MAX_NUM] {}; |
||||
|
||||
|
||||
/**
|
||||
* @class I2CSPIDriverInitializer |
||||
* Helper class to initialize a driver: it ensures the object is initialzed on |
||||
* the work queue where the driver is running. This is required so that all |
||||
* bus accesses come from the same thread. |
||||
*/ |
||||
class I2CSPIDriverInitializer : public px4::WorkItem |
||||
{ |
||||
public: |
||||
using instantiate_method = I2CSPIDriverBase::instantiate_method; |
||||
|
||||
I2CSPIDriverInitializer(const px4::wq_config_t &config, |
||||
const BusCLIArguments &cli, const BusInstanceIterator &iterator, |
||||
instantiate_method instantiate, int runtime_instance); |
||||
~I2CSPIDriverInitializer(); |
||||
void wait(); |
||||
|
||||
I2CSPIDriverBase *instance() const { return _instance; } |
||||
protected: |
||||
void Run() override; |
||||
private: |
||||
I2CSPIDriverBase *_instance{nullptr}; |
||||
const BusCLIArguments &_cli; |
||||
const BusInstanceIterator &_iterator; |
||||
const int _runtime_instance; |
||||
instantiate_method _instantiate; |
||||
px4_sem_t _sem; |
||||
}; |
@ -0,0 +1,165 @@
@@ -0,0 +1,165 @@
|
||||
/****************************************************************************
|
||||
* |
||||
* Copyright (c) 2020 PX4 Development Team. All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions |
||||
* are met: |
||||
* |
||||
* 1. Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* 2. Redistributions in binary form must reproduce the above copyright |
||||
* notice, this list of conditions and the following disclaimer in |
||||
* the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* 3. Neither the name PX4 nor the names of its contributors may be |
||||
* used to endorse or promote products derived from this software |
||||
* without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS |
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE |
||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, |
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, |
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS |
||||
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED |
||||
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN |
||||
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
||||
* POSSIBILITY OF SUCH DAMAGE. |
||||
* |
||||
****************************************************************************/ |
||||
|
||||
#pragma once |
||||
|
||||
#include <stdint.h> |
||||
#include <board_config.h> |
||||
|
||||
/*
|
||||
* Helper macros to handle device ID's. They are used to match drivers against SPI buses and chip-select signals. |
||||
* They match with corresponding definitions in NuttX. |
||||
* 'type' is typically PX4_SPI_DEVICE_ID for PX4 drivers, and 'index' is used for the driver (DRV_*) or chip-select index. |
||||
*/ |
||||
//#define PX4_SPIDEV_ID(type, index) ((((type) & 0xffff) << 16) | ((index) & 0xffff))
|
||||
//#define PX4_SPI_DEVICE_ID (1 << 12)
|
||||
//#define PX4_SPI_DEV_ID(devid) ((devid) & 0xffff)
|
||||
#define PX4_SPIDEVID_TYPE(devid) (((uint32_t)(devid) >> 16) & 0xffff) |
||||
|
||||
#define SPI_BUS_MAX_DEVICES 5 |
||||
struct px4_spi_bus_device_t { |
||||
uint32_t cs_gpio; ///< chip-select GPIO (0 if this device is not used)
|
||||
uint32_t drdy_gpio; ///< data ready GPIO (0 if not set)
|
||||
uint32_t devid; ///< SPIDEV_ID(type,index). For PX4 devices on NuttX: index is the device type, and for external buses the CS index
|
||||
uint16_t devtype_driver; ///< driver device type, e.g. DRV_IMU_DEVTYPE_ICM20689 (on NuttX: PX4_SPI_DEV_ID(devid) == devtype_driver)
|
||||
}; |
||||
|
||||
struct px4_spi_bus_devices_t { |
||||
px4_spi_bus_device_t devices[SPI_BUS_MAX_DEVICES]; |
||||
}; |
||||
|
||||
struct px4_spi_bus_t { |
||||
px4_spi_bus_device_t devices[SPI_BUS_MAX_DEVICES]; |
||||
int bus{-1}; ///< physical bus number (1, ...) (-1 means this is unused)
|
||||
uint32_t power_enable_gpio{0}; ///< GPIO (if non-zero) to control the power of the attached devices on this bus (0 means power is off)
|
||||
bool is_external; ///< static external configuration. Use px4_spi_bus_external() to check if a bus is really external
|
||||
bool requires_locking; ///< whether the bus should be locked during transfers (true if NuttX drivers access the bus)
|
||||
}; |
||||
|
||||
|
||||
struct px4_spi_bus_all_hw_t { |
||||
px4_spi_bus_t buses[SPI_BUS_MAX_BUS_ITEMS]; |
||||
int board_hw_version; ///< 0=default, >0 for a specific revision (see board_get_hw_version)
|
||||
}; |
||||
|
||||
#if BOARD_NUM_SPI_CFG_HW_VERSIONS > 1 |
||||
/**
|
||||
* initialze px4_spi_buses from px4_spi_buses_all_hw and the hardware version. |
||||
* Call this on early boot before anything else accesses px4_spi_buses (e.g. from stm32_spiinitialize). |
||||
*/ |
||||
__EXPORT void px4_set_spi_buses_from_hw_version(); |
||||
|
||||
__EXPORT extern const px4_spi_bus_all_hw_t |
||||
px4_spi_buses_all_hw[BOARD_NUM_SPI_CFG_HW_VERSIONS]; ///< board-specific SPI bus configuration all hw versions
|
||||
|
||||
__EXPORT extern const px4_spi_bus_t *px4_spi_buses; ///< board-specific SPI bus configuration for current board revision
|
||||
#else |
||||
static inline void px4_set_spi_buses_from_hw_version() {} |
||||
__EXPORT extern const px4_spi_bus_t px4_spi_buses[SPI_BUS_MAX_BUS_ITEMS]; ///< board-specific SPI bus configuration
|
||||
#endif |
||||
|
||||
|
||||
/**
|
||||
* Find a SPI bus given a device ID. Note: only internal buses are checked. |
||||
* @return the bus or -1 |
||||
*/ |
||||
__EXPORT int px4_find_spi_bus(uint32_t devid); |
||||
|
||||
/**
|
||||
* Check if a bus requires locking during a SPI transfer (because it is potentially accessed by different threads) |
||||
*/ |
||||
__EXPORT bool px4_spi_bus_requires_locking(int bus); |
||||
|
||||
/**
|
||||
* runtime-check if a board has a specific bus as external. |
||||
* This can be overridden by a board to add run-time checks. |
||||
*/ |
||||
__EXPORT bool px4_spi_bus_external(const px4_spi_bus_t &bus); |
||||
|
||||
/**
|
||||
* runtime-check if a board has a specific bus as external. |
||||
*/ |
||||
static inline bool px4_spi_bus_external(int bus) |
||||
{ |
||||
for (int i = 0; i < SPI_BUS_MAX_BUS_ITEMS; ++i) { |
||||
if (px4_spi_buses[i].bus == bus) { |
||||
return px4_spi_bus_external(px4_spi_buses[i]); |
||||
} |
||||
} |
||||
|
||||
return true; |
||||
} |
||||
|
||||
|
||||
/**
|
||||
* @class SPIBusIterator |
||||
* Iterate over configured SPI buses by the board |
||||
*/ |
||||
class SPIBusIterator |
||||
{ |
||||
public: |
||||
enum class FilterType { |
||||
InternalBus, ///< specific or all internal buses
|
||||
ExternalBus, ///< specific external bus + CS index
|
||||
}; |
||||
|
||||
/**
|
||||
* Constructor |
||||
* Note: only for devices of type PX4_SPI_DEVICE_ID |
||||
* @param filter |
||||
* @param devid_driver_index DRV_* or chip-select index starting from 1 |
||||
* @param bus starts with 1 (-1=all, but only for internal). Numbering for internal is arch-specific, for external |
||||
* it is the n-th external bus. |
||||
*/ |
||||
SPIBusIterator(FilterType filter, uint16_t devid_driver_index, int bus = -1) |
||||
: _filter(filter), _devid_driver_index(devid_driver_index), |
||||
_bus(filter == FilterType::ExternalBus && bus == -1 ? 1 : bus) {} |
||||
|
||||
bool next(); |
||||
|
||||
const px4_spi_bus_t &bus() const { return px4_spi_buses[_index]; } |
||||
uint32_t DRDYGPIO() const { return px4_spi_buses[_index].devices[_bus_device_index].drdy_gpio; } |
||||
|
||||
uint32_t devid() const { return px4_spi_buses[_index].devices[_bus_device_index].devid; } |
||||
|
||||
bool external() const { return px4_spi_bus_external(bus()); } |
||||
|
||||
private: |
||||
const FilterType _filter; |
||||
const uint16_t _devid_driver_index; |
||||
const int _bus; |
||||
int _index{-1}; |
||||
int _external_bus_counter{0}; |
||||
int _bus_device_index{0}; |
||||
}; |
||||
|
@ -0,0 +1,157 @@
@@ -0,0 +1,157 @@
|
||||
/****************************************************************************
|
||||
* |
||||
* Copyright (C) 2020 PX4 Development Team. All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions |
||||
* are met: |
||||
* |
||||
* 1. Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* 2. Redistributions in binary form must reproduce the above copyright |
||||
* notice, this list of conditions and the following disclaimer in |
||||
* the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* 3. Neither the name PX4 nor the names of its contributors may be |
||||
* used to endorse or promote products derived from this software |
||||
* without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS |
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE |
||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, |
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, |
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS |
||||
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED |
||||
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN |
||||
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
||||
* POSSIBILITY OF SUCH DAMAGE. |
||||
* |
||||
****************************************************************************/ |
||||
|
||||
#include <board_config.h> |
||||
#ifndef BOARD_DISABLE_I2C_SPI |
||||
|
||||
#include <px4_platform_common/spi.h> |
||||
|
||||
#if BOARD_NUM_SPI_CFG_HW_VERSIONS > 1 |
||||
void px4_set_spi_buses_from_hw_version() |
||||
{ |
||||
int hw_version = board_get_hw_version(); |
||||
|
||||
for (int i = 0; i < BOARD_NUM_SPI_CFG_HW_VERSIONS; ++i) { |
||||
if (!px4_spi_buses && px4_spi_buses_all_hw[i].board_hw_version == 0) { |
||||
px4_spi_buses = px4_spi_buses_all_hw[i].buses; |
||||
} |
||||
|
||||
if (px4_spi_buses_all_hw[i].board_hw_version == hw_version) { |
||||
px4_spi_buses = px4_spi_buses_all_hw[i].buses; |
||||
} |
||||
} |
||||
|
||||
if (!px4_spi_buses) { // fallback
|
||||
px4_spi_buses = px4_spi_buses_all_hw[0].buses; |
||||
} |
||||
} |
||||
|
||||
const px4_spi_bus_t *px4_spi_buses{}; |
||||
#endif |
||||
|
||||
int px4_find_spi_bus(uint32_t devid) |
||||
{ |
||||
for (int i = 0; i < SPI_BUS_MAX_BUS_ITEMS; ++i) { |
||||
const px4_spi_bus_t &bus_data = px4_spi_buses[i]; |
||||
|
||||
if (bus_data.bus == -1) { |
||||
break; |
||||
} |
||||
|
||||
if (px4_spi_bus_external(bus_data)) { |
||||
continue; |
||||
} |
||||
|
||||
for (int j = 0; j < SPI_BUS_MAX_DEVICES; ++j) { |
||||
if (PX4_SPIDEVID_TYPE(devid) == PX4_SPIDEVID_TYPE(bus_data.devices[j].devid) && |
||||
PX4_SPI_DEV_ID(devid) == bus_data.devices[j].devtype_driver) { |
||||
return bus_data.bus; |
||||
} |
||||
} |
||||
} |
||||
|
||||
return -1; |
||||
} |
||||
|
||||
bool px4_spi_bus_requires_locking(int bus) |
||||
{ |
||||
for (int i = 0; i < SPI_BUS_MAX_BUS_ITEMS; ++i) { |
||||
const px4_spi_bus_t &bus_data = px4_spi_buses[i]; |
||||
|
||||
if (bus_data.bus == bus) { |
||||
return bus_data.requires_locking; |
||||
} |
||||
} |
||||
|
||||
return true; |
||||
} |
||||
|
||||
|
||||
bool px4_spi_bus_external(const px4_spi_bus_t &bus) |
||||
{ |
||||
return bus.is_external; |
||||
} |
||||
|
||||
bool SPIBusIterator::next() |
||||
{ |
||||
// we have at most 1 match per bus, so we can directly jump to the next bus
|
||||
while (++_index < SPI_BUS_MAX_BUS_ITEMS && px4_spi_buses[_index].bus != -1) { |
||||
const px4_spi_bus_t &bus_data = px4_spi_buses[_index]; |
||||
|
||||
if (!board_has_bus(BOARD_SPI_BUS, bus_data.bus)) { |
||||
continue; |
||||
} |
||||
|
||||
// Note: we use bus_data.is_external here instead of px4_spi_bus_external(),
|
||||
// otherwise the chip-select matching does not work if a bus is configured as
|
||||
// external/internal, but at runtime the other way around.
|
||||
// (On boards where a bus can be internal/external at runtime, it should be
|
||||
// configured as external.)
|
||||
switch (_filter) { |
||||
case FilterType::InternalBus: |
||||
if (!bus_data.is_external) { |
||||
if (_bus == bus_data.bus || _bus == -1) { |
||||
// find device id
|
||||
for (int i = 0; i < SPI_BUS_MAX_DEVICES; ++i) { |
||||
if (PX4_SPI_DEVICE_ID == PX4_SPIDEVID_TYPE(bus_data.devices[i].devid) && |
||||
_devid_driver_index == bus_data.devices[i].devtype_driver) { |
||||
_bus_device_index = i; |
||||
return true; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
break; |
||||
|
||||
case FilterType::ExternalBus: |
||||
if (bus_data.is_external) { |
||||
++_external_bus_counter; |
||||
uint16_t cs_index = _devid_driver_index - 1; |
||||
|
||||
if (_bus == _external_bus_counter && cs_index < SPI_BUS_MAX_DEVICES && |
||||
bus_data.devices[cs_index].cs_gpio != 0) { |
||||
// we know that bus_data.devices[cs_index].devtype_driver == cs_index
|
||||
_bus_device_index = cs_index; |
||||
return true; |
||||
} |
||||
} |
||||
|
||||
break; |
||||
} |
||||
} |
||||
|
||||
return false; |
||||
} |
||||
|
||||
#endif /* BOARD_DISABLE_I2C_SPI */ |
Loading…
Reference in new issue