mirror of
https://github.com/ArduPilot/ardupilot.git
synced 2026-10-02 10:23:25 +08:00
The buzzer, sprayer, both grippers, parachute, precland, i2c and DroneCAN-test sims are all owned by SITL::SIM (each carrying its SIM_* parameters where it has them), and the aircraft model already holds the SITL::SIM singleton and uses it directly for the physics models (e.g. sitl->models.slung_payload_sim). Reach these sims the same way instead of injecting a raw pointer into the aircraft from SITL_State. Removes set_buzzer()/set_sprayer()/set_gripper_servo()/set_gripper_epm()/ set_parachute()/set_precland()/set_i2c()/set_dronecan_device(), their cached pointers and the SITL_State wiring, and updates each sim straight from sitl->xxx_sim in update_external_payload(). For precland the home-based beacon seeding (set_default_location, which is idempotent) moves into update_external_payload() ahead of the enable check, so it keeps running for the IRLock / PrecLand SITL backends that consume the sim directly. The simulated i2c bus now sets up its device table itself: I2C::init() is self-guarded and called lazily from the top of update() and ioctl() (either may run first), so the previous explicit i2c_sim.init() calls in SITL_State and SITL_Periph_State are gone and the bus needs no external setup. The DroneCAN device sim stays behind AP_TEST_DRONECAN_DRIVERS as before; only the vehicle SITL state ever drove it, and update_external_payload() (which is only run by the vehicle model, not AP_Periph's SimMCast) now calls sitl->dronecan_sim.update() directly. No functional change: the AP_Periph SITL model (SimMCast) never ran the external payload update, so it never drove these sims, and still doesn't. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
300 lines
8.5 KiB
C++
300 lines
8.5 KiB
C++
/*
|
|
This program is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
/*
|
|
Simulated i2c buses and devices
|
|
*/
|
|
|
|
|
|
#include "SIM_config.h"
|
|
#include <GCS_MAVLink/GCS.h>
|
|
#include <SITL/SITL.h>
|
|
|
|
#include "SIM_I2C.h"
|
|
|
|
#include "SIM_Airspeed_DLVR.h"
|
|
#include "SIM_AS5600.h"
|
|
#include "SIM_BattMonitor_SMBus_Generic.h"
|
|
#include "SIM_BattMonitor_SMBus_Maxell.h"
|
|
#include "SIM_BattMonitor_SMBus_Rotoye.h"
|
|
#include "SIM_ICM40609.h"
|
|
#include "SIM_INA3221.h"
|
|
#include "SIM_IS31FL3195.h"
|
|
#include "SIM_RF_LightWareI2C_Legacy16Bit.h"
|
|
#include "SIM_RF_TOFSenseF_I2C.h"
|
|
#include "SIM_RF_LightWare_GRF_I2C.h"
|
|
#include "SIM_LM2755.h"
|
|
#include "SIM_LP5562.h"
|
|
#include "SIM_MaxSonarI2CXL.h"
|
|
#include "SIM_MS5525.h"
|
|
#include "SIM_MS5611.h"
|
|
#include "SIM_QMC5883L.h"
|
|
#include "SIM_RF_Benewake_TFMiniPlus.h"
|
|
#include "SIM_Temperature_MCP9600.h"
|
|
#include "SIM_Temperature_SHT3x.h"
|
|
#include "SIM_Temperature_TSYS01.h"
|
|
#include "SIM_Temperature_TSYS03.h"
|
|
#include "SIM_TeraRangerI2C.h"
|
|
#include "SIM_TFS20L.h"
|
|
#include "SIM_ToshibaLED.h"
|
|
|
|
#include <signal.h>
|
|
|
|
using namespace SITL;
|
|
|
|
enum class IOCtlType {
|
|
RDWR = 0,
|
|
};
|
|
|
|
class IgnoredI2CDevice : public I2CDevice
|
|
{
|
|
public:
|
|
int rdwr(I2C::i2c_rdwr_ioctl_data *&data) override {
|
|
return -1;
|
|
}
|
|
};
|
|
static IgnoredI2CDevice ignored;
|
|
|
|
#if AP_SIM_TOSHIBALED_ENABLED
|
|
static ToshibaLED toshibaled;
|
|
#endif
|
|
#if AP_SIM_RF_LIGHTWAREI2C_LEGACY16BIT_ENABLED
|
|
static LightWareI2C_Legacy16Bit lightwarei2c_legacy16bit;
|
|
#endif // AP_SIM_RF_LIGHTWAREI2C_LEGACY16BIT_ENABLED
|
|
#if AP_SIM_MAXSONAR_I2C_XL_ENABLED
|
|
static MaxSonarI2CXL maxsonari2cxl;
|
|
static MaxSonarI2CXL maxsonari2cxl_2;
|
|
#endif
|
|
#if AP_SIM_BATT_MONITOR_SMBUS_MAXELL_ENABLED
|
|
static Maxell maxell;
|
|
#endif
|
|
#if AP_SIM_BATT_MONITOR_SMBUS_ROTOYE_ENABLED
|
|
static Rotoye rotoye;
|
|
#endif
|
|
static SIM_BattMonitor_SMBus_Generic smbus_generic;
|
|
#if AP_SIM_AIRSPEED_DLVR_ENABLED
|
|
static Airspeed_DLVR airspeed_dlvr;
|
|
#endif
|
|
#if AP_SIM_TEMPERATURE_SHT3X_ENABLED
|
|
static SHT3x sht3x;
|
|
#endif // AP_SIM_TEMPERATURE_SHT3X_ENABLED
|
|
#if AP_SIM_TEMPERATURE_TSYS01_ENABLED
|
|
static TSYS01 tsys01;
|
|
#endif
|
|
#if AP_SIM_TSYS03_ENABLED
|
|
static TSYS03 tsys03;
|
|
#endif
|
|
#if AP_SIM_TEMPERATURE_MCP9600_ENABLED
|
|
static MCP9600 mcp9600;
|
|
#endif
|
|
#if AP_SIM_ICM40609_ENABLED
|
|
static ICM40609 icm40609;
|
|
#endif
|
|
#if AP_SIM_MS5525_ENABLED
|
|
static MS5525 ms5525;
|
|
#endif
|
|
#if AP_SIM_MS5611_ENABLED
|
|
static MS5611 ms5611;
|
|
#endif
|
|
#if AP_SIM_LP5562_ENABLED
|
|
static LP5562 lp5562;
|
|
#endif
|
|
#if AP_SIM_LM2755_ENABLED
|
|
static LM2755 lm2755;
|
|
#endif
|
|
#if AP_SIM_IS31FL3195_ENABLED
|
|
static IS31FL3195 is31fl3195;
|
|
#define SIM_IS31FL3195_ADDR 0x54
|
|
#endif
|
|
#if AP_SIM_COMPASS_QMC5883L_ENABLED
|
|
static QMC5883L qmc5883l;
|
|
#endif
|
|
#if AP_SIM_RF_BENEWAKE_TFMINIPLUS_ENABLED
|
|
static Benewake_TFMiniPlus benewake_tfminiplus;
|
|
#endif // AP_SIM_RF_BENEWAKE_TFMINIPLUS_ENABLED
|
|
#if AP_SIM_INA3221_ENABLED
|
|
static INA3221 ina3221;
|
|
#endif
|
|
#if AP_SIM_TERARANGERI2C_ENABLED
|
|
static TeraRangerI2C terarangeri2c;
|
|
#endif
|
|
#if AP_SIM_AS5600_ENABLED
|
|
static AS5600 as5600; // AoA sensor
|
|
#endif // AP_SIM_AS5600_ENABLED
|
|
|
|
#if AP_SIM_TFS20L_ENABLED
|
|
static TFS20L tfs20l; // Benewake TFS20L rangefinder
|
|
#endif // AP_SIM_TFS20L_ENABLED
|
|
|
|
#if AP_SIM_RF_TOFSENSEF_I2C_ENABLED
|
|
static TOFSenseF_I2C tofsensef;
|
|
#endif // AP_SIM_RF_TOFSENSEF_I2C_ENABLED
|
|
|
|
#if AP_SIM_RF_LIGHTWARE_GRF_I2C_ENABLED
|
|
static LightWareGRF_I2C lightware_grf_i2c;
|
|
#endif // AP_SIM_RF_LIGHTWARE_GRF_I2C_ENABLED
|
|
|
|
struct i2c_device_at_address {
|
|
uint8_t bus;
|
|
uint8_t addr;
|
|
I2CDevice &device;
|
|
} i2c_devices[] {
|
|
#if AP_SIM_TERARANGERI2C_ENABLED
|
|
{ 0, 0x31, terarangeri2c }, // RNGFNDx_TYPE = 14, RNGFNDx_ADDR = 49
|
|
#endif // AP_SIM_TERARANGERI2C_ENABLED
|
|
#if AP_SIM_RF_LIGHTWAREI2C_LEGACY16BIT_ENABLED
|
|
{ 0, 0x66, lightwarei2c_legacy16bit }, // RNGFNDx_TYPE = 7, RNGFNDx_ADDR = 0x66
|
|
#endif // AP_SIM_RF_LIGHTWAREI2C_LEGACY16BIT_ENABLED
|
|
#if AP_SIM_MAXSONAR_I2C_XL_ENABLED
|
|
{ 0, 0x70, maxsonari2cxl }, // RNGFNDx_TYPE = 2, RNGFNDx_ADDR = 112
|
|
#endif
|
|
#if AP_SIM_TEMPERATURE_MCP9600_ENABLED
|
|
{ 0, 0x60, mcp9600 }, // 0x60 is low address
|
|
#endif
|
|
#if AP_SIM_MAXSONAR_I2C_XL_ENABLED
|
|
{ 0, 0x71, maxsonari2cxl_2 }, // RNGFNDx_TYPE = 2, RNGFNDx_ADDR = 113
|
|
#endif
|
|
#if AP_SIM_ICM40609_ENABLED
|
|
{ 1, 0x01, icm40609 },
|
|
#endif
|
|
#if AP_SIM_TEMPERATURE_SHT3X_ENABLED
|
|
{ 1, 0x44, sht3x },
|
|
#endif
|
|
#if AP_SIM_TOSHIBALED_ENABLED
|
|
{ 1, 0x55, toshibaled },
|
|
#endif
|
|
{ 1, 0x38, ignored }, // NCP5623
|
|
{ 1, 0x39, ignored }, // NCP5623C
|
|
#if AP_SIM_AS5600_ENABLED
|
|
{ 1, 0x36, as5600 },
|
|
#endif
|
|
{ 1, 0x40, ignored }, // KellerLD
|
|
#if AP_SIM_MS5525_ENABLED
|
|
{ 1, 0x76, ms5525 }, // MS5525: ARSPD_TYPE = 4
|
|
#endif
|
|
#if AP_SIM_INA3221_ENABLED
|
|
{ 1, 0x42, ina3221 },
|
|
#endif
|
|
#if AP_SIM_TEMPERATURE_TSYS01_ENABLED
|
|
{ 1, 0x77, tsys01 },
|
|
#endif
|
|
#if AP_SIM_BATT_MONITOR_SMBUS_ROTOYE_ENABLED
|
|
{ 1, 0x0B, rotoye }, // Rotoye: BATTx_MONITOR 19, BATTx_I2C_ADDR 13
|
|
#endif
|
|
#if AP_SIM_BATT_MONITOR_SMBUS_MAXELL_ENABLED
|
|
{ 2, 0x0B, maxell }, // Maxell: BATTx_MONITOR 16, BATTx_I2C_ADDR 13
|
|
#endif
|
|
{ 3, 0x0B, smbus_generic}, // BATTx_MONITOR 7, BATTx_I2C_ADDR 13
|
|
#if AP_SIM_AIRSPEED_DLVR_ENABLED
|
|
{ 2, 0x28, airspeed_dlvr }, // ARSPD_TYPE = 7 5inch H2O sensor
|
|
#endif
|
|
#if AP_SIM_LP5562_ENABLED
|
|
{ 2, 0x30, lp5562 }, // LP5562 RGB LED driver
|
|
#endif
|
|
#if AP_SIM_LM2755_ENABLED
|
|
{ 2, 0x67, lm2755 }, // LM2755 RGB LED driver
|
|
#endif
|
|
#if AP_SIM_IS31FL3195_ENABLED
|
|
{ 2, SIM_IS31FL3195_ADDR, is31fl3195 }, // IS31FL3195 RGB LED driver; see page 9
|
|
#endif
|
|
#if AP_SIM_RF_BENEWAKE_TFMINIPLUS_ENABLED
|
|
{ 2, 0x09, benewake_tfminiplus }, // TFMiniPlus rfnd, non-default-address
|
|
#endif // AP_SIM_RF_BENEWAKE_TFMINIPLUS_ENABLED
|
|
#if AP_SIM_TSYS03_ENABLED
|
|
{ 2, 0x40, tsys03 },
|
|
#endif
|
|
#if AP_SIM_MS5611_ENABLED
|
|
{ 2, 0x77, ms5611 }, // MS5611: BARO_PROBE_EXT = 2
|
|
#endif
|
|
#if AP_SIM_COMPASS_QMC5883L_ENABLED
|
|
{ 2, 0x0D, qmc5883l },
|
|
#endif
|
|
#if AP_SIM_TFS20L_ENABLED
|
|
{ 0, 0x10, tfs20l }, // RNGFNDx_TYPE = 46, RNGFNDx_ADDR = 0x10
|
|
#endif // AP_SIM_TFS20L_ENABLED
|
|
#if AP_SIM_RF_TOFSENSEF_I2C_ENABLED
|
|
{ 0, 0x08, tofsensef }, // RNGFNDx_TYPE = 40, RNGFNDx_ADDR = 0x08
|
|
#endif // AP_SIM_RF_TOFSENSEF_I2C_ENABLED
|
|
#if AP_SIM_RF_LIGHTWARE_GRF_I2C_ENABLED
|
|
{ 2, 0x66, lightware_grf_i2c }, // RNGFNDx_TYPE = 48, RNGFNDx_ADDR = 0x66
|
|
#endif // AP_SIM_RF_LIGHTWARE_GRF_I2C_ENABLED
|
|
};
|
|
|
|
void I2C::init()
|
|
{
|
|
if (initialised) {
|
|
return;
|
|
}
|
|
initialised = true;
|
|
|
|
for (auto &i : i2c_devices) {
|
|
i.device.init();
|
|
}
|
|
|
|
#if AP_SIM_IS31FL3195_ENABLED
|
|
// IS31FL3195 needs to know its own address:
|
|
is31fl3195.set_product_id(SIM_IS31FL3195_ADDR);
|
|
#endif
|
|
|
|
// sanity check the i2c_devices structure to ensure we don't have
|
|
// two devices at the same address on the same bus:
|
|
for (uint8_t i=0; i<ARRAY_SIZE(i2c_devices)-1; i++) {
|
|
const auto &dev_i = i2c_devices[i];
|
|
for (uint8_t j=i+1; j<ARRAY_SIZE(i2c_devices); j++) {
|
|
const auto &dev_j = i2c_devices[j];
|
|
if (dev_i.bus == dev_j.bus &&
|
|
dev_i.addr == dev_j.addr) {
|
|
AP_HAL::panic("Two devices at the same address on the same bus");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void I2C::update(const class Aircraft &aircraft)
|
|
{
|
|
init(); // lazily set up the device table on first use
|
|
|
|
for (auto daa : i2c_devices) {
|
|
daa.device.update(aircraft);
|
|
}
|
|
}
|
|
|
|
int I2C::ioctl_rdwr(i2c_rdwr_ioctl_data *data)
|
|
{
|
|
const uint8_t addr = data->msgs[0].addr;
|
|
const uint8_t bus = data->msgs[0].bus;
|
|
for (auto &dev_at_address : i2c_devices) {
|
|
if (dev_at_address.addr != addr) {
|
|
continue;
|
|
}
|
|
if (dev_at_address.bus != bus) {
|
|
continue;
|
|
}
|
|
return dev_at_address.device.rdwr(data);
|
|
}
|
|
// ::fprintf(stderr, "Unhandled i2c message: bus=%u addr=0x%02x flags=%u len=%u\n", msg.bus, msg.addr, msg.flags, msg.len);
|
|
return -1; // ?!
|
|
}
|
|
|
|
int I2C::ioctl(uint8_t ioctl_type, void *data)
|
|
{
|
|
init(); // lazily set up the device table on first use
|
|
|
|
switch ((IOCtlType) ioctl_type) {
|
|
case IOCtlType::RDWR:
|
|
return ioctl_rdwr((i2c_rdwr_ioctl_data*)data);
|
|
}
|
|
return -1;
|
|
}
|