You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
296 lines
7.7 KiB
296 lines
7.7 KiB
/* |
|
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/>. |
|
*/ |
|
/* |
|
Simulator for the FETtecOneWire ESCs |
|
|
|
./Tools/autotest/sim_vehicle.py --gdb --debug -v ArduCopter -A --uartF=sim:fetteconewireesc --speedup=1 --console |
|
|
|
param set SERIAL5_PROTOCOL 38 |
|
param set SERIAL5_BAUD 500000 |
|
param set SERVO_FTW_MASK 15 |
|
param set SIM_FTOWESC_ENA 1 |
|
reboot |
|
|
|
param fetch |
|
|
|
#param set SIM_FTOWESC_FM 1 # fail mask |
|
|
|
./Tools/autotest/autotest.py --gdb --debug build.ArduCopter fly.ArduCopter.FETtecESC |
|
|
|
*/ |
|
|
|
#pragma once |
|
|
|
#include <AP_Param/AP_Param.h> |
|
|
|
#include "SITL_Input.h" |
|
|
|
#include "SIM_SerialDevice.h" |
|
|
|
#include <stdio.h> |
|
|
|
#define SIM_FTW_DEBUGGING 0 |
|
#if SIM_FTW_DEBUGGING |
|
#define simfet_debug(fmt, args ...) do {::fprintf(stderr,"SIMFET: %s:%d: " fmt "\n", __FUNCTION__, __LINE__, ## args); } while(0) |
|
#else |
|
#define simfet_debug(fmt, args ...) |
|
#endif |
|
|
|
|
|
namespace SITL { |
|
|
|
class FETtecOneWireESC : public SerialDevice { |
|
public: |
|
|
|
FETtecOneWireESC(); |
|
|
|
// update state |
|
void update(const class Aircraft &aircraft); |
|
|
|
static const AP_Param::GroupInfo var_info[]; |
|
|
|
bool enabled() const { return _enabled.get(); } |
|
|
|
void update_sitl_input_pwm(struct sitl_input &input); |
|
|
|
private: |
|
|
|
AP_Int8 _enabled; // enable FETtec ESC sim |
|
AP_Int32 _powered_mask; // mask of ESCs with power |
|
|
|
struct PACKED ConfigMessageHeader { |
|
uint8_t header; // master is always 0x01 |
|
uint8_t target_id; // 5 bits only |
|
uint16_t frame_type; |
|
uint8_t frame_len; |
|
uint8_t request_type; |
|
}; |
|
|
|
enum class TLMType : uint8_t { |
|
NORMAL = 0, |
|
ALTERNATIVE =1, |
|
}; |
|
|
|
template <typename T> |
|
class PACKED PackedMessage { |
|
public: |
|
PackedMessage(uint8_t _target_id, T _msg) : |
|
target_id{_target_id}, |
|
msg{_msg} |
|
{ |
|
frame_len = 6 + sizeof(T); |
|
update_checksum(); |
|
} |
|
uint8_t header = (uint8_t)ResponseFrameHeaderID::ESC; // master is always 0x01 |
|
uint8_t target_id; // 5 bits only |
|
uint16_t frame_type = 0; |
|
uint8_t frame_len; |
|
T msg; |
|
uint8_t checksum; |
|
|
|
uint8_t calculate_checksum() const WARN_IF_UNUSED { |
|
return crc8_dvb_update(0, (const uint8_t*)this, frame_len-1); |
|
} |
|
|
|
void update_checksum() { |
|
checksum = calculate_checksum(); |
|
} |
|
}; |
|
|
|
class PACKED SetTLMType { |
|
public: |
|
SetTLMType(uint8_t _type) : |
|
type(_type) |
|
{ } |
|
uint8_t request_type { (uint8_t)ConfigMessageType::SET_TLM_TYPE }; |
|
uint8_t type; |
|
}; |
|
|
|
class PACKED OK { |
|
public: |
|
OK() { } |
|
uint8_t request_type { (uint8_t)ConfigMessageType::OK }; |
|
}; |
|
|
|
class PACKED ESC_TYPE { |
|
public: |
|
ESC_TYPE(uint8_t _type) : |
|
type{_type} { } |
|
uint8_t type; |
|
}; |
|
|
|
class PACKED SW_VER { |
|
public: |
|
SW_VER(uint8_t _version, uint8_t _subversion) : |
|
version{_version}, |
|
subversion{_subversion} |
|
{ } |
|
uint8_t version; |
|
uint8_t subversion; |
|
}; |
|
|
|
class PACKED SN { |
|
public: |
|
SN(uint8_t *_sn, uint8_t snlen) { |
|
memset(sn, 0, ARRAY_SIZE(sn)); |
|
memcpy(sn, _sn, MIN(ARRAY_SIZE(sn), snlen)); |
|
} |
|
uint8_t sn[12]; |
|
}; |
|
|
|
class PACKED SetFastComLength { |
|
public: |
|
SetFastComLength() { |
|
} |
|
uint8_t length; |
|
uint8_t byte_count; |
|
uint8_t min_esc_id; |
|
uint8_t id_count; |
|
}; |
|
|
|
// tlm_from_id = (uint8_t)telem[1]; |
|
|
|
// t.temperature_cdeg = int16_t(telem[5+0] * 100); |
|
// t.voltage = float((telem[5+1]<<8)|telem[5+2]) * 0.01f; |
|
// t.current = float((telem[5+3]<<8)|telem[5+4]) * 0.01f; |
|
// centi_erpm = (telem[5+5]<<8)|telem[5+6]; |
|
// t.consumption_mah = float((telem[5+7]<<8)|telem[5+8]); |
|
// tx_err_count = (telem[5+9]<<8)|telem[5+10]; |
|
class PACKED ESCTelem { |
|
public: |
|
ESCTelem(int8_t _temp, uint16_t _voltage, uint16_t _current, int16_t _rpm, uint16_t _consumption_mah, uint16_t _tx_err_count) : |
|
temp{_temp}, |
|
voltage{_voltage}, |
|
current{_current}, |
|
rpm{_rpm}, |
|
consumption_mah{_consumption_mah}, |
|
tx_err_count{_tx_err_count} |
|
{ } |
|
int8_t temp; // centidegrees |
|
uint16_t voltage; // centivolts |
|
uint16_t current; // centiamps (signed?) |
|
int16_t rpm; // centi-rpm |
|
uint16_t consumption_mah; // ??? |
|
uint16_t tx_err_count; |
|
}; |
|
|
|
|
|
union MessageUnion { |
|
MessageUnion() { } |
|
uint8_t buffer[255]; |
|
// uint16_t checksum_buffer[35]; |
|
struct ConfigMessageHeader config_message_header; |
|
|
|
PackedMessage<OK> packed_ok; |
|
PackedMessage<SetTLMType> packed_set_tlm_type; |
|
PackedMessage<SetFastComLength> packed_set_fast_com_length; |
|
|
|
// void update_checksum(); |
|
}; |
|
MessageUnion u; |
|
uint8_t buflen; |
|
|
|
// remove count bytes from the start of u.buffer |
|
void consume_bytes(uint8_t count); |
|
|
|
enum class ConfigMessageType { |
|
OK = 0, |
|
BL_PAGE_CORRECT = 1, // BL only |
|
NOT_OK = 2, |
|
BL_START_FW = 3, // BL only |
|
BL_PAGES_TO_FLASH = 4, // BL only |
|
REQ_TYPE = 5, |
|
REQ_SN = 6, |
|
REQ_SW_VER = 7, |
|
BEEP = 13, |
|
SET_FAST_COM_LENGTH = 26, |
|
SET_TLM_TYPE = 27, //1 for alternative telemetry. ESC sends full telem per ESC: Temp, Volt, Current, ERPM, Consumption, CrcErrCount |
|
SET_LED_TMP_COLOR = 51, |
|
}; |
|
|
|
class ESC { |
|
public: |
|
|
|
enum class State { |
|
POWERED_OFF = 17, |
|
IN_BOOTLOADER, |
|
RUNNING_START, |
|
RUNNING, |
|
// UNRESPONSIVE, |
|
}; |
|
|
|
void set_state(State _state) { |
|
simfet_debug("Moving ESC.id=%u from state=%u to state=%u", (unsigned)id, (unsigned)state, (unsigned)_state); |
|
state = _state; |
|
} |
|
|
|
State state = State::POWERED_OFF; |
|
|
|
uint8_t sn[12]; |
|
TLMType telem_type; |
|
uint8_t id; |
|
uint8_t type = 34; |
|
static const uint8_t sw_version = 3; |
|
static const uint8_t sw_subversion = 4; |
|
|
|
// make sure to zero any state when powering the virtual ESC on |
|
struct { |
|
uint8_t length; |
|
uint8_t byte_count; |
|
uint8_t min_esc_id; |
|
uint8_t id_count = 255; |
|
} fast_com; |
|
|
|
uint16_t pwm; |
|
bool telem_request; // true if we've been asked to send telem |
|
|
|
uint8_t ofs; |
|
|
|
float temperature; |
|
}; |
|
|
|
// canonical structure used for fast com, copied from an ESC |
|
struct { |
|
uint8_t min_esc_id; |
|
uint8_t id_count = 255; |
|
} fast_com; |
|
|
|
void bootloader_handle_config_message(ESC &esc); |
|
void running_handle_config_message(ESC &esc); |
|
|
|
void handle_config_message(); |
|
void handle_config_message_set_tlm_type(ESC &esc); |
|
|
|
void handle_fast_esc_data(); |
|
|
|
void update_escs(); |
|
void update_send(const class Aircraft &aircraft); |
|
void update_input(); |
|
|
|
void send_esc_telemetry(const class Aircraft &aircraft); |
|
|
|
template <typename T> |
|
void send_response(const T& r); |
|
|
|
enum class ResponseFrameHeaderID { |
|
MASTER = 0x01, |
|
BOOTLOADER = 0x02, |
|
ESC = 0x03, |
|
}; |
|
|
|
ESC escs[16]; |
|
}; |
|
|
|
}
|
|
|