/*
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 .
*/
/*
* AP_EFI_Currawong_ECU.cpp
*
* Author: Reilly Callaway / Currawong Engineering Pty Ltd
*/
#include "AP_EFI_Currawong_ECU.h"
#if HAL_EFI_CURRAWONG_ECU_ENABLED
#include
#include
#include
AP_EFI_Currawong_ECU* AP_EFI_Currawong_ECU::_singleton;
AP_EFI_Currawong_ECU::AP_EFI_Currawong_ECU(AP_EFI &_frontend) :
AP_EFI_Backend(_frontend)
{
_singleton = this;
// Indicate that temperature and fuel pressure are supported
internal_state.fuel_pressure_status = Fuel_Pressure_Status::OK;
internal_state.temperature_status = Temperature_Status::OK;
}
void AP_EFI_Currawong_ECU::update()
{
// copy the data to the front end
copy_to_frontend();
}
bool AP_EFI_Currawong_ECU::handle_message(AP_HAL::CANFrame &frame)
{
bool valid = true;
// There are differences between Ardupilot EFI_State and types/scaling of Piccolo packets.
// First decode to Piccolo structs, and then store the data we need in internal_state with any scaling required.
// Structs to decode Piccolo messages into
ECU_TelemetryFast_t telemetry_fast;
ECU_TelemetrySlow0_t telemetry_slow0;
ECU_TelemetrySlow1_t telemetry_slow1;
ECU_TelemetrySlow2_t telemetry_slow2;
// Throw the message at the decoding functions
if (decodeECU_TelemetryFastPacketStructure(&frame, &telemetry_fast)) {
internal_state.throttle_position_percent = static_cast(telemetry_fast.throttle);
internal_state.engine_load_percent = static_cast(telemetry_fast.throttle);
internal_state.engine_speed_rpm = static_cast(telemetry_fast.rpm);
if (internal_state.engine_speed_rpm > 0) {
internal_state.engine_state = Engine_State::RUNNING;
} else {
internal_state.engine_state = Engine_State::STOPPED;
}
// Prevent div by zero
if (get_ecu_fuel_density() > 0.01) {
internal_state.estimated_consumed_fuel_volume_cm3 = static_cast(telemetry_fast.fuelUsed) / KG_PER_M3_TO_G_PER_CM3(get_ecu_fuel_density());
} else {
// If no (reasonable) density is provided
internal_state.estimated_consumed_fuel_volume_cm3 = 0.;
}
internal_state.general_error = telemetry_fast.ecuStatusBits.errorIndicator;
if (!telemetry_fast.ecuStatusBits.enabled) {
internal_state.engine_state = Engine_State::STOPPED;
}
} else if (decodeECU_TelemetrySlow0PacketStructure(&frame, &telemetry_slow0)) {
internal_state.intake_manifold_pressure_kpa = telemetry_slow0.map;
internal_state.atmospheric_pressure_kpa = telemetry_slow0.baro;
internal_state.cylinder_status[0].cylinder_head_temperature = C_TO_KELVIN(telemetry_slow0.cht);
} else if (decodeECU_TelemetrySlow1PacketStructure(&frame, &telemetry_slow1)) {
internal_state.intake_manifold_temperature = C_TO_KELVIN(telemetry_slow1.mat);
internal_state.fuel_pressure = telemetry_slow1.fuelPressure;
} else if (decodeECU_TelemetrySlow2PacketStructure(&frame, &telemetry_slow2)) {
internal_state.cylinder_status[0].ignition_timing_deg = telemetry_slow2.ignAngle1;
if (ENGINE_MAX_CYLINDERS > 1) {
internal_state.cylinder_status[1].ignition_timing_deg = telemetry_slow2.ignAngle2;
}
internal_state.fuel_consumption_rate_cm3pm = telemetry_slow2.flowRate / KG_PER_M3_TO_G_PER_CM3(get_ecu_fuel_density());
} else {
valid = false;
}
if (valid) {
internal_state.last_updated_ms = AP_HAL::millis();
}
return valid;
}
#endif // HAL_EFI_CURRAWONG_ECU_ENABLED