diff --git a/ArduCopter/motors.cpp b/ArduCopter/motors.cpp index 4b8bc879cc..eff6c47f75 100644 --- a/ArduCopter/motors.cpp +++ b/ArduCopter/motors.cpp @@ -4,9 +4,14 @@ #define DISARM_DELAY 20 // called at 10hz so 2 seconds #define AUTO_TRIM_DELAY 100 // called at 10hz so 10 seconds #define LOST_VEHICLE_DELAY 10 // called at 10hz so 1 second +#define UINT_8BIT_MAX 255 static uint32_t auto_disarm_begin; +#define MOTOR_COUNT 4 +static bool motor_kill_all = false; +static bool motor_kill[MOTOR_COUNT] {}; + // arm_motors_check - checks for pilot input to arm or disarm the copter // called at 10hz void Copter::arm_motors_check() @@ -176,10 +181,26 @@ void Copter::motors_output() motors->output(); } + // implement motor kill for parachute testing + for (uint8_t i = 0; i < MOTOR_COUNT; ++i) { + if (motor_kill_all || motor_kill[i]) { + hal.rcout->write(i, 1000); + } + } + // push all channels SRV_Channels::push(); } +void set_motor_kill(uint8_t motor_num, bool kill) +{ + if (motor_num == UINT_8BIT_MAX) { + motor_kill_all = kill; + } else if (motor_num < MOTOR_COUNT) { + motor_kill[motor_num] = kill; + } +} + // check for pilot stick input to trigger lost vehicle alarm void Copter::lost_vehicle_check() { diff --git a/libraries/AP_Compass/AP_Compass.h b/libraries/AP_Compass/AP_Compass.h index e4d02d1605..8b80ce133c 100644 --- a/libraries/AP_Compass/AP_Compass.h +++ b/libraries/AP_Compass/AP_Compass.h @@ -341,6 +341,11 @@ friend class AP_Compass_Backend; MAV_RESULT mag_cal_fixed_yaw(float yaw_deg, uint8_t compass_mask, float lat_deg, float lon_deg); + // set a mask to disable sensor for failure testing + void set_disable_mask(uint8_t mask) { + _disable_mask = mask; + } + private: static Compass *_singleton; @@ -593,6 +598,9 @@ friend class AP_Compass_Backend; /// void try_set_initial_location(); bool _initial_location_set; + + // mask of disabled sensors + uint8_t _disable_mask; }; namespace AP { diff --git a/libraries/AP_Compass/AP_Compass_Backend.cpp b/libraries/AP_Compass/AP_Compass_Backend.cpp index cba5958283..245d21930a 100644 --- a/libraries/AP_Compass/AP_Compass_Backend.cpp +++ b/libraries/AP_Compass/AP_Compass_Backend.cpp @@ -120,6 +120,11 @@ void AP_Compass_Backend::correct_field(Vector3f &mag, uint8_t i) void AP_Compass_Backend::accumulate_sample(Vector3f &field, uint8_t instance, uint32_t max_samples) { + if (_compass._disable_mask & (1U< NO_FIX) { - return NO_FIX; - } return state[instance].status; } GPS_Status status(void) const { @@ -474,8 +471,8 @@ class AP_GPS bool logging_enabled(void) const { return _raw_data != 0; } // used to disable GPS for GPS failure testing in flight - void force_disable(bool disable) { - _force_disable_gps = disable; + void force_disable(uint8_t mask) { + _force_disable_mask = mask; } // handle possibly fragmented RTCM injection data @@ -495,6 +492,11 @@ class AP_GPS // announce GPS version on mavlink void broadcast_gps_version(void); + // used to disable SBAS + void sbas_disable(uint8_t mask) { + _sbas_disable_mask = mask; + } + protected: // configuration parameters @@ -684,8 +686,12 @@ class AP_GPS GPS_AUTO_CONFIG_ENABLE = 1 }; - // used for flight testing with GPS loss - bool _force_disable_gps; + // mask of GPS instances to disable. Used for flight testing with + // GPS loss + uint8_t _force_disable_mask; + + // mask of SBAS instances to disable + uint8_t _sbas_disable_mask; // used to ensure we continue sending status messages if we ever detected the second GPS bool has_had_second_instance; diff --git a/libraries/AP_GPS/AP_GPS_UAVCAN.cpp b/libraries/AP_GPS/AP_GPS_UAVCAN.cpp index d1d5c18e28..bfd8fb235f 100644 --- a/libraries/AP_GPS/AP_GPS_UAVCAN.cpp +++ b/libraries/AP_GPS/AP_GPS_UAVCAN.cpp @@ -150,6 +150,9 @@ AP_GPS_UAVCAN* AP_GPS_UAVCAN::get_uavcan_backend(AP_UAVCAN* ap_uavcan, uint8_t n void AP_GPS_UAVCAN::handle_fix_msg(const FixCb &cb) { + if (is_disabled()) { + return; + } if (seen_fix2) { // use Fix2 instead return; @@ -265,6 +268,9 @@ void AP_GPS_UAVCAN::handle_fix_msg(const FixCb &cb) void AP_GPS_UAVCAN::handle_fix2_msg(const Fix2Cb &cb) { + if (is_disabled()) { + return; + } bool process = false; seen_fix2 = true; @@ -377,6 +383,9 @@ void AP_GPS_UAVCAN::handle_fix2_msg(const Fix2Cb &cb) void AP_GPS_UAVCAN::handle_aux_msg(const AuxCb &cb) { + if (is_disabled()) { + return; + } WITH_SEMAPHORE(sem); if (!uavcan::isNaN(cb.msg->hdop)) { diff --git a/libraries/AP_GPS/AP_GPS_UBLOX.cpp b/libraries/AP_GPS/AP_GPS_UBLOX.cpp index 706ce20149..96deebf709 100644 --- a/libraries/AP_GPS/AP_GPS_UBLOX.cpp +++ b/libraries/AP_GPS/AP_GPS_UBLOX.cpp @@ -567,8 +567,16 @@ AP_GPS_UBLOX::read(void) } numc = port->available(); - for (int16_t i = 0; i < numc; i++) { // Process bytes received + if (is_disabled()) { + // drain data + for (int16_t i = 0; i < numc; i++) { + data = port->read(); + } + return false; + } + + for (int16_t i = 0; i < numc; i++) { // Process bytes received // read the next byte data = port->read(); @@ -975,6 +983,11 @@ AP_GPS_UBLOX::_parse_gps(void) (unsigned)_buffer.gnss.configBlock[i].flags); } #endif + if (_buffer.gnss.configBlock[1].flags & 0x1) { + // GCS_SEND_TEXT(MAV_SEVERITY_ALERT, "SBAS Enabled!\n"); + } else { + GCS_SEND_TEXT(MAV_SEVERITY_ALERT, "SBAS Disabled!\n"); + } for(int i = 0; i < UBLOX_MAX_GNSS_CONFIG_BLOCKS; i++) { if((gps._gnss_mode[state.instance] & (1 << i)) && i != GNSS_SBAS) { @@ -988,11 +1001,20 @@ AP_GPS_UBLOX::_parse_gps(void) if(GNSS_SBAS !=_buffer.gnss.configBlock[i].gnssId) { _buffer.gnss.configBlock[i].resTrkCh = (_buffer.gnss.numTrkChHw - 3) / (gnssCount * 2); _buffer.gnss.configBlock[i].maxTrkCh = _buffer.gnss.numTrkChHw; + _buffer.gnss.configBlock[i].flags = _buffer.gnss.configBlock[i].flags | 0x00000001; } else { - _buffer.gnss.configBlock[i].resTrkCh = 1; - _buffer.gnss.configBlock[i].maxTrkCh = 3; + // SBAS configuration + _buffer.gnss.configBlock[i].flags &= 0xFF000000; // this will disable SBAS + if (is_sbas_disabled()) { + // nothing needs to be done + } + else { + // bit 0, 1 = enable + // bit 16, 1 = SBAS L1 C/A + _buffer.gnss.configBlock[i].flags |= (1U<<16); + _buffer.gnss.configBlock[i].flags |= 0x00000001; + } } - _buffer.gnss.configBlock[i].flags = _buffer.gnss.configBlock[i].flags | 0x00000001; } else { _buffer.gnss.configBlock[i].resTrkCh = 0; _buffer.gnss.configBlock[i].maxTrkCh = 0; diff --git a/libraries/AP_GPS/GPS_Backend.cpp b/libraries/AP_GPS/GPS_Backend.cpp index 81ef664f4e..eb40f5ad22 100644 --- a/libraries/AP_GPS/GPS_Backend.cpp +++ b/libraries/AP_GPS/GPS_Backend.cpp @@ -289,3 +289,17 @@ void AP_GPS_Backend::check_new_itow(uint32_t itow, uint32_t msg_length) state.uart_timestamp_ms = local_us / 1000U; } } + +// check if an instance is disabled +bool AP_GPS_Backend::is_disabled(void) const +{ + const uint8_t instance = &state - &gps.state[0]; + return ((1U<printf("I2C: not owner of 0x%x for addr 0x%02x\n", (unsigned)get_bus_id(), _address); return false; @@ -256,6 +263,9 @@ bool I2CDevice::transfer(const uint8_t *send, uint32_t send_len, bool I2CDevice::_transfer(const uint8_t *send, uint32_t send_len, uint8_t *recv, uint32_t recv_len) { + if (_i2c_disable) { + return false; + } i2cAcquireBus(I2CD[bus.busnum].i2c); if (!bus.bouncebuffer_setup(send, send_len, recv, recv_len)) { @@ -383,4 +393,10 @@ uint32_t I2CDeviceManager::get_bus_mask_external(void) const return get_bus_mask() & ~HAL_I2C_INTERNAL_MASK; } +// disable i2c devices for testing +void I2CDeviceManager::i2c_disable(bool disable) +{ + _i2c_disable = disable; +} + #endif // HAL_USE_I2C diff --git a/libraries/AP_HAL_ChibiOS/I2CDevice.h b/libraries/AP_HAL_ChibiOS/I2CDevice.h index 72580d7a88..21502cf714 100644 --- a/libraries/AP_HAL_ChibiOS/I2CDevice.h +++ b/libraries/AP_HAL_ChibiOS/I2CDevice.h @@ -143,6 +143,9 @@ class I2CDeviceManager : public AP_HAL::I2CDeviceManager { get mask of bus numbers for all configured internal I2C buses */ uint32_t get_bus_mask_internal(void) const override; + + // disable i2c devices for testing + void i2c_disable(bool disable) override; }; } diff --git a/libraries/AP_HAL_ChibiOS/hwdef/MttrCubeOrange/defaults.parm b/libraries/AP_HAL_ChibiOS/hwdef/MttrCubeOrange/defaults.parm index 77f6477d08..0b15c32b46 100644 --- a/libraries/AP_HAL_ChibiOS/hwdef/MttrCubeOrange/defaults.parm +++ b/libraries/AP_HAL_ChibiOS/hwdef/MttrCubeOrange/defaults.parm @@ -86,6 +86,8 @@ FS_GCS_ENABLE 0 FS_THR_ENABLE 6 FS_THR_VALUE 0 GND_EFFECT_COMP 1 +GPS_GNSS_MODE 127 +GPS_GNSS_MODE2 127 GPS_HDOP_GOOD 175 GPS_POS1_X 0.182 GPS_POS1_Y -0.05 diff --git a/libraries/AP_IRLock/AP_IRLock_I2C.cpp b/libraries/AP_IRLock/AP_IRLock_I2C.cpp index f42018ef12..e00822dc39 100644 --- a/libraries/AP_IRLock/AP_IRLock_I2C.cpp +++ b/libraries/AP_IRLock/AP_IRLock_I2C.cpp @@ -162,6 +162,10 @@ void AP_IRLock_I2C::read_frames(void) return; } + if (_disabled) { + return; + } + // The objects in each frame are sorted by size, with the largest objects sent first. struct frame *irframe = &blocks[0]; int16_t corner1_pix_x = irframe->pixel_x - irframe->pixel_size_x/2; diff --git a/libraries/AP_IRLock/AP_IRLock_SITL.cpp b/libraries/AP_IRLock/AP_IRLock_SITL.cpp index f54c483d97..3ec33a0197 100644 --- a/libraries/AP_IRLock/AP_IRLock_SITL.cpp +++ b/libraries/AP_IRLock/AP_IRLock_SITL.cpp @@ -34,6 +34,9 @@ void AP_IRLock_SITL::init(int8_t bus) // retrieve latest sensor data - returns true if new data is available bool AP_IRLock_SITL::update() { + if (_disabled) { + return false; + } // return immediately if not healthy _flags.healthy = _sitl->precland_sim.healthy(); if (!_flags.healthy) { diff --git a/libraries/AP_IRLock/IRLock.cpp b/libraries/AP_IRLock/IRLock.cpp index 1308e3fac4..57dd7d919d 100644 --- a/libraries/AP_IRLock/IRLock.cpp +++ b/libraries/AP_IRLock/IRLock.cpp @@ -7,6 +7,8 @@ #include "IRLock.h" +IRLock *IRLock::singleton; + // retrieve body frame unit vector in direction of target // returns true if data is available bool IRLock::get_unit_vector_body(Vector3f& ret) const @@ -23,3 +25,10 @@ bool IRLock::get_unit_vector_body(Vector3f& ret) const ret /= ret.length(); return true; } + +namespace AP { +IRLock *irlock() +{ + return IRLock::get_singleton(); +} +} diff --git a/libraries/AP_IRLock/IRLock.h b/libraries/AP_IRLock/IRLock.h index 28dcb82b12..2bfc13e795 100644 --- a/libraries/AP_IRLock/IRLock.h +++ b/libraries/AP_IRLock/IRLock.h @@ -26,6 +26,10 @@ class IRLock { public: + IRLock(void) { + singleton = this; + } + // init - initialize sensor library // library won't be useable unless this is first called virtual void init(int8_t bus) = 0; @@ -45,7 +49,14 @@ class IRLock // retrieve body frame unit vector in direction of target // returns true if data is available bool get_unit_vector_body(Vector3f& ret) const; - + + void set_disable(bool disable) { + _disabled = disable; + } + + static IRLock *get_singleton(void) { + return singleton; + } protected: struct AP_IRLock_Flags { @@ -64,4 +75,12 @@ class IRLock } irlock_target_info; irlock_target_info _target_info; + + bool _disabled; + + static IRLock *singleton; +}; + +namespace AP { + IRLock *irlock(); }; diff --git a/libraries/AP_RangeFinder/AP_RangeFinder_LightWareI2C.cpp b/libraries/AP_RangeFinder/AP_RangeFinder_LightWareI2C.cpp index 8ed510ccd7..a5b2a9a536 100644 --- a/libraries/AP_RangeFinder/AP_RangeFinder_LightWareI2C.cpp +++ b/libraries/AP_RangeFinder/AP_RangeFinder_LightWareI2C.cpp @@ -445,6 +445,9 @@ void AP_RangeFinder_LightWareI2C::update(void) void AP_RangeFinder_LightWareI2C::sf20_timer(void) { + if (state.disabled) { + return; + } #ifdef MFG_TEST_BUILD static const uint32_t TIMER_FREQ_HZ = 20; static uint32_t count = 0; diff --git a/libraries/AP_RangeFinder/AP_RangeFinder_LightWareSerial.cpp b/libraries/AP_RangeFinder/AP_RangeFinder_LightWareSerial.cpp index de0ae939a9..272d85878c 100644 --- a/libraries/AP_RangeFinder/AP_RangeFinder_LightWareSerial.cpp +++ b/libraries/AP_RangeFinder/AP_RangeFinder_LightWareSerial.cpp @@ -65,6 +65,10 @@ bool AP_RangeFinder_LightWareSerial::get_reading(uint16_t &reading_cm) int16_t nbytes = uart->available(); while (nbytes-- > 0) { char c = uart->read(); + if (state.disabled) { + continue; + } + if (c == '\r') { linebuf[linebuf_len] = 0; const float dist = (float)atof(linebuf); diff --git a/libraries/AP_RangeFinder/AP_RangeFinder_UAVCAN.cpp b/libraries/AP_RangeFinder/AP_RangeFinder_UAVCAN.cpp index 2ed6b3490a..c4ca107b5c 100644 --- a/libraries/AP_RangeFinder/AP_RangeFinder_UAVCAN.cpp +++ b/libraries/AP_RangeFinder/AP_RangeFinder_UAVCAN.cpp @@ -129,6 +129,9 @@ void AP_RangeFinder_UAVCAN::handle_measurement(AP_UAVCAN* ap_uavcan, uint8_t nod if (driver == nullptr) { return; } + if (driver->state.disabled) { + return; + } WITH_SEMAPHORE(driver->_sem); switch (cb.msg->reading_type) { case uavcan::equipment::range_sensor::Measurement::READING_TYPE_VALID_RANGE: diff --git a/libraries/AP_RangeFinder/AP_RangeFinder_uLanding.cpp b/libraries/AP_RangeFinder/AP_RangeFinder_uLanding.cpp index b8ab474630..711032c3df 100644 --- a/libraries/AP_RangeFinder/AP_RangeFinder_uLanding.cpp +++ b/libraries/AP_RangeFinder/AP_RangeFinder_uLanding.cpp @@ -74,7 +74,9 @@ bool AP_RangeFinder_uLanding::detect_version(void) while (nbytes-- > 0) { uint8_t c = uart->read(); - + if (state.disabled) { + continue; + } if (((c == ULANDING_HDR_V0) || (c == ULANDING_HDR)) && !hdr_found) { byte1 = c; hdr_found = true; diff --git a/libraries/AP_RangeFinder/RangeFinder.h b/libraries/AP_RangeFinder/RangeFinder.h index fd402e2e0c..97a9e1018c 100644 --- a/libraries/AP_RangeFinder/RangeFinder.h +++ b/libraries/AP_RangeFinder/RangeFinder.h @@ -106,6 +106,7 @@ class RangeFinder uint32_t last_reading_ms; // system time of last successful update from sensor const struct AP_Param::GroupInfo *var_info; + bool disabled; }; static const struct AP_Param::GroupInfo *backend_var_info[RANGEFINDER_MAX_INSTANCES]; @@ -170,6 +171,13 @@ class RangeFinder static RangeFinder *get_singleton(void) { return _singleton; } + // allow disable of set of rangefinders + void set_disable_mask(uint8_t mask) { + for (uint8_t i=0; i #include #include +#include +#include + +void set_motor_kill(uint8_t motor_num, bool kill); #define SWITCH_DEBOUNCE_TIME_MS 200 @@ -475,6 +479,26 @@ void RC_Channel::init_aux_function(const aux_func_t ch_option, const aux_switch_ case AUX_FUNC::GPS_DISABLE: case AUX_FUNC::KILL_IMU1: case AUX_FUNC::KILL_IMU2: + case AUX_FUNC::GPS_DISABLE1: + case AUX_FUNC::GPS_DISABLE2: + case AUX_FUNC::GPS_DISABLE_BOTH: + case AUX_FUNC::MAG_DISABLE1: + case AUX_FUNC::MAG_DISABLE2: + case AUX_FUNC::MAG_DISABLE_BOTH: + case AUX_FUNC::RFND_DISABLE1: + case AUX_FUNC::RFND_DISABLE2: + case AUX_FUNC::RFND_DISABLE_BOTH: + case AUX_FUNC::PIXY_DISABLE: + case AUX_FUNC::I2C_DISABLE: + case AUX_FUNC::PLAND_DISABLE: + case AUX_FUNC::GPS_SBAS_DISABLE1: + case AUX_FUNC::GPS_SBAS_DISABLE2: + case AUX_FUNC::GPS_SBAS_DISABLE_BOTH: + case AUX_FUNC::MOTOR_KILL_ALL: + case AUX_FUNC::MOTOR_KILL_1: + case AUX_FUNC::MOTOR_KILL_2: + case AUX_FUNC::MOTOR_KILL_3: + case AUX_FUNC::MOTOR_KILL_4: do_aux_function(ch_option, ch_flag); break; default: @@ -762,7 +786,84 @@ void RC_Channel::do_aux_function(const aux_func_t ch_option, const aux_switch_po } case AUX_FUNC::GPS_DISABLE: - AP::gps().force_disable(ch_flag == HIGH); + AP::gps().force_disable(ch_flag == HIGH?1:0); + break; + + case AUX_FUNC::GPS_DISABLE1: + AP::gps().force_disable(ch_flag == HIGH?1:0); + break; + case AUX_FUNC::GPS_DISABLE2: + AP::gps().force_disable(ch_flag == HIGH?2:0); + break; + case AUX_FUNC::GPS_DISABLE_BOTH: + AP::gps().force_disable(ch_flag == HIGH?3:0); + break; + + case AUX_FUNC::GPS_SBAS_DISABLE1: + AP::gps().sbas_disable(ch_flag == HIGH?1:0); + break; + case AUX_FUNC::GPS_SBAS_DISABLE2: + AP::gps().sbas_disable(ch_flag == HIGH?2:0); + break; + case AUX_FUNC::GPS_SBAS_DISABLE_BOTH: + AP::gps().sbas_disable(ch_flag == HIGH?3:0); + break; + + case AUX_FUNC::MOTOR_KILL_ALL: + set_motor_kill(0xFF, ch_flag == HIGH); + break; + case AUX_FUNC::MOTOR_KILL_1: + set_motor_kill(0, ch_flag == HIGH); + break; + case AUX_FUNC::MOTOR_KILL_2: + set_motor_kill(1, ch_flag == HIGH); + break; + case AUX_FUNC::MOTOR_KILL_3: + set_motor_kill(2, ch_flag == HIGH); + break; + case AUX_FUNC::MOTOR_KILL_4: + set_motor_kill(3, ch_flag == HIGH); + break; + + case AUX_FUNC::MAG_DISABLE1: + AP::compass().set_disable_mask(ch_flag == HIGH?1:0); + break; + case AUX_FUNC::MAG_DISABLE2: + AP::compass().set_disable_mask(ch_flag == HIGH?2:0); + break; + case AUX_FUNC::MAG_DISABLE_BOTH: + AP::compass().set_disable_mask(ch_flag == HIGH?3:0); + break; + + case AUX_FUNC::RFND_DISABLE1: + AP::rangefinder()->set_disable_mask(ch_flag == HIGH?1:0); + break; + case AUX_FUNC::RFND_DISABLE2: + AP::rangefinder()->set_disable_mask(ch_flag == HIGH?2:0); + break; + case AUX_FUNC::RFND_DISABLE_BOTH: + AP::rangefinder()->set_disable_mask(ch_flag == HIGH?3:0); + break; + + case AUX_FUNC::PIXY_DISABLE: { + auto *irlock = AP::irlock(); + if (irlock) { + irlock->set_disable(ch_flag == HIGH); + } + break; + } + + case AUX_FUNC::PLAND_DISABLE: { + auto *irlock = AP::irlock(); + if (irlock) { + irlock->set_disable(ch_flag == HIGH); + } + AP::rangefinder()->set_disable_mask(ch_flag == HIGH?3:0); + break; + } + + case AUX_FUNC::I2C_DISABLE: + hal.i2c_mgr->i2c_disable(ch_flag == HIGH); break; case AUX_FUNC::MOTOR_ESTOP: diff --git a/libraries/RC_Channel/RC_Channel.h b/libraries/RC_Channel/RC_Channel.h index a226034228..be15059910 100644 --- a/libraries/RC_Channel/RC_Channel.h +++ b/libraries/RC_Channel/RC_Channel.h @@ -181,6 +181,32 @@ class RC_Channel { // if you add something here, make sure to update the documentation of the parameter in RC_Channel.cpp! // also, if you add an option >255, you will need to fix duplicate_options_exist + // custom sensor disable options + GPS_DISABLE1 = 150, + GPS_DISABLE2 = 151, + GPS_DISABLE_BOTH = 152, + + MAG_DISABLE1 = 153, + MAG_DISABLE2 = 154, + MAG_DISABLE_BOTH = 155, + + RFND_DISABLE1 = 156, + RFND_DISABLE2 = 157, + RFND_DISABLE_BOTH = 158, + PIXY_DISABLE = 159, + PLAND_DISABLE = 160, + I2C_DISABLE = 161, + + GPS_SBAS_DISABLE1 = 162, + GPS_SBAS_DISABLE2 = 163, + GPS_SBAS_DISABLE_BOTH = 164, + + MOTOR_KILL_ALL = 165, + MOTOR_KILL_1 = 166, + MOTOR_KILL_2 = 167, + MOTOR_KILL_3 = 168, + MOTOR_KILL_4 = 169, + // inputs eventually used to replace RCMAP MAINSAIL = 207, // mainsail input };