mirror of
https://github.com/ArduPilot/ardupilot
synced 2025-01-03 14:38:30 -04:00
f98ce3dc9e
correct settings when power set is received add support for capturing all supported power levels learn power levels in SmartAudio 2.1 add better support for VTX power levels don't set power to 0 if in pitmode add option for iNav compatibility support non-conforming SmartAudio implementations re-enable pitmode on SmartAudio 2.0 add support for "blind" VTX setting
272 lines
8.7 KiB
C++
272 lines
8.7 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/>.
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include <AP_HAL/AP_HAL.h>
|
|
|
|
#ifndef HAL_SMARTAUDIO_ENABLED
|
|
#define HAL_SMARTAUDIO_ENABLED !HAL_MINIMIZE_FEATURES
|
|
#endif
|
|
|
|
#if HAL_SMARTAUDIO_ENABLED
|
|
|
|
#include <AP_Param/AP_Param.h>
|
|
#include <AP_SerialManager/AP_SerialManager.h>
|
|
#include <AP_HAL/utility/RingBuffer.h>
|
|
#include "AP_VideoTX.h"
|
|
|
|
#define SMARTAUDIO_BUFFER_CAPACITY 5
|
|
|
|
// SmartAudio Serial Protocol
|
|
#define AP_SMARTAUDIO_UART_BAUD 4800
|
|
#define AP_SMARTAUDIO_SMARTBAUD_MIN 4560 // -5%
|
|
#define AP_SMARTAUDIO_SMARTBAUD_MAX 5040 // +5%
|
|
#define AP_SMARTAUDIO_SMARTBAUD_STEP 60
|
|
#define AP_SMARTAUDIO_UART_BUFSIZE_RX 16
|
|
#define AP_SMARTAUDIO_UART_BUFSIZE_TX 16
|
|
#define AP_SMARTAUDIO_MAX_PACKET_SIZE 32
|
|
|
|
#define SMARTAUDIO_SYNC_BYTE 0xAA
|
|
#define SMARTAUDIO_HEADER_BYTE 0x55
|
|
#define SMARTAUDIO_START_CODE SMARTAUDIO_SYNC_BYTE + SMARTAUDIO_HEADER_BYTE
|
|
#define SMARTAUDIO_GET_PITMODE_FREQ (1 << 14)
|
|
#define SMARTAUDIO_SET_PITMODE_FREQ (1 << 15)
|
|
#define SMARTAUDIO_FREQUENCY_MASK 0x3FFF
|
|
|
|
#define SMARTAUDIO_CMD_GET_SETTINGS 0x03
|
|
#define SMARTAUDIO_CMD_SET_POWER 0x05
|
|
#define SMARTAUDIO_CMD_SET_CHANNEL 0x07
|
|
#define SMARTAUDIO_CMD_SET_FREQUENCY 0x09
|
|
#define SMARTAUDIO_CMD_SET_MODE 0x0B
|
|
|
|
#define SMARTAUDIO_COMMAND_FRAME_SIZE (sizeof(FrameHeader) + 1)
|
|
#define SMARTAUDIO_U8_COMMAND_FRAME_SIZE (sizeof(FrameHeader) + 2)
|
|
#define SMARTAUDIO_U16_COMMAND_FRAME_SIZE (sizeof(FrameHeader) + 3)
|
|
|
|
#define SMARTAUDIO_RSP_GET_SETTINGS_V1 SMARTAUDIO_CMD_GET_SETTINGS >> 1
|
|
#define SMARTAUDIO_RSP_GET_SETTINGS_V2 (SMARTAUDIO_CMD_GET_SETTINGS >> 1) | 0x08
|
|
#define SMARTAUDIO_RSP_GET_SETTINGS_V21 (SMARTAUDIO_CMD_GET_SETTINGS >> 1) | 0x10
|
|
#define SMARTAUDIO_RSP_SET_POWER SMARTAUDIO_CMD_SET_POWER >> 1
|
|
#define SMARTAUDIO_RSP_SET_CHANNEL SMARTAUDIO_CMD_SET_CHANNEL >> 1
|
|
#define SMARTAUDIO_RSP_SET_FREQUENCY SMARTAUDIO_CMD_SET_FREQUENCY >> 1
|
|
#define SMARTAUDIO_RSP_SET_MODE SMARTAUDIO_CMD_SET_MODE >> 1
|
|
|
|
#define SMARTAUDIO_BANDCHAN_TO_INDEX(band, channel) (band * VTX_MAX_CHANNELS + (channel))
|
|
|
|
//#define SA_DEBUG
|
|
|
|
class AP_SmartAudio
|
|
{
|
|
public:
|
|
enum ProtocolVersion {
|
|
SMARTAUDIO_SPEC_PROTOCOL_v1 = 0,
|
|
SMARTAUDIO_SPEC_PROTOCOL_v2 = 1,
|
|
SMARTAUDIO_SPEC_PROTOCOL_v21 = 2
|
|
};
|
|
|
|
struct Settings {
|
|
uint8_t version;
|
|
uint8_t mode;
|
|
uint8_t channel;
|
|
uint8_t power;
|
|
uint16_t frequency;
|
|
uint8_t band;
|
|
|
|
uint8_t num_power_levels;
|
|
uint8_t power_levels[8];
|
|
uint8_t power_in_dbm;
|
|
|
|
uint16_t pitmodeFrequency;
|
|
bool userFrequencyMode; // user is setting freq
|
|
bool initialized;
|
|
};
|
|
|
|
struct FrameHeader {
|
|
uint8_t syncByte;
|
|
uint8_t headerByte;
|
|
uint8_t command;
|
|
uint8_t length;
|
|
|
|
void init(uint8_t cmd, uint8_t payloadLength) {
|
|
syncByte = SMARTAUDIO_SYNC_BYTE;
|
|
headerByte= SMARTAUDIO_HEADER_BYTE;
|
|
length = payloadLength;
|
|
command = cmd;
|
|
}
|
|
} PACKED;
|
|
|
|
struct Frame {
|
|
FrameHeader header;
|
|
uint8_t payload[3];
|
|
} PACKED;
|
|
|
|
struct U8ResponseFrame {
|
|
FrameHeader header;
|
|
uint8_t payload;
|
|
//uint8_t reserved;
|
|
//uint8_t crc;
|
|
} PACKED;
|
|
|
|
struct U16ResponseFrame {
|
|
FrameHeader header;
|
|
uint16_t payload;
|
|
//uint8_t reserved;
|
|
//uint8_t crc;
|
|
} PACKED;
|
|
|
|
struct SettingsResponseFrame {
|
|
FrameHeader header;
|
|
uint8_t channel;
|
|
uint8_t power;
|
|
uint8_t operationMode;
|
|
uint16_t frequency;
|
|
//uint8_t crc;
|
|
} PACKED;
|
|
|
|
struct SettingsExtendedResponseFrame {
|
|
SettingsResponseFrame settings;
|
|
uint8_t power_dbm; // current power
|
|
uint8_t num_power_levels;
|
|
uint8_t power_levels[8]; // first in the list of dbm levels
|
|
//uint8_t crc;
|
|
} PACKED;
|
|
|
|
// v 2.1 additions to response frame
|
|
//0x0E (current power in dBm) 0x03 (amount of power levels) 0x00(dBm level 1) 0x0E (dBm level 2) 0x14 (dBm level 3) 0x1A (dBm level 4) 0x01(CRC8)
|
|
|
|
// request packet to be processed
|
|
struct Packet {
|
|
Frame frame;
|
|
uint8_t frame_size;
|
|
} PACKED;
|
|
|
|
AP_SmartAudio();
|
|
|
|
static AP_SmartAudio *get_singleton(void)
|
|
{
|
|
return _singleton;
|
|
}
|
|
|
|
/* Do not allow copies */
|
|
AP_SmartAudio(const AP_SmartAudio &other) = delete;
|
|
|
|
AP_SmartAudio &operator=(const AP_SmartAudio&) = delete;
|
|
|
|
// init threads and lookup for io uart.
|
|
bool init();
|
|
|
|
private:
|
|
// serial interface
|
|
AP_HAL::UARTDriver *_port; // UART used to send data to SmartAudio VTX
|
|
|
|
//Pointer to singleton
|
|
static AP_SmartAudio* _singleton;
|
|
|
|
// response buffer length, permit splitted responses
|
|
uint8_t _inline_buffer_length;
|
|
// expected packet size
|
|
uint8_t _packet_size;
|
|
|
|
ProtocolVersion _protocol_version;
|
|
// statistics
|
|
uint16_t _packets_sent;
|
|
uint16_t _packets_rcvd;
|
|
|
|
bool _vtx_freq_change_pending; // a vtx command has been issued but not confirmed by a vtx broadcast frame
|
|
bool _vtx_power_change_pending;
|
|
bool _vtx_options_change_pending;
|
|
bool _vtx_changes_pending;
|
|
bool _vtx_use_set_freq; // should frequency set by band/channel or frequency
|
|
|
|
// value for current baud adjust
|
|
int32_t _smartbaud = AP_SMARTAUDIO_UART_BAUD;
|
|
int32_t _smartbaud_direction = 1;
|
|
|
|
// hw vtx state control with 2 elements array use methods _push _peek
|
|
uint8_t _vtx_state_idx;
|
|
Settings _vtx_states_buffer[2];
|
|
Settings *_vtx_current_state;
|
|
|
|
// ready to go
|
|
volatile bool _initialised;
|
|
|
|
// RingBuffer to store outgoing request.
|
|
ObjectBuffer<Packet> requests_queue{SMARTAUDIO_BUFFER_CAPACITY};
|
|
|
|
// time the last_request is process
|
|
uint32_t _last_request_sent_ms;
|
|
|
|
// loops is waiting a response after a request
|
|
bool _is_waiting_response;
|
|
|
|
#ifdef SA_DEBUG
|
|
// utility method for debugging.
|
|
void print_bytes_to_hex_string(const char* msg, const uint8_t buf[], uint8_t length);
|
|
#endif
|
|
void print_settings(const Settings* settings);
|
|
|
|
void update_vtx_params();
|
|
void update_vtx_settings(const Settings& settings);
|
|
|
|
bool ignore_crc() const { return AP::vtx().has_option(AP_VideoTX::VideoOptions::VTX_SA_IGNORE_CRC); }
|
|
|
|
// looping over requests
|
|
void loop();
|
|
// send a frame over the wire
|
|
void send_request(const Frame& requestFrame, uint8_t size);
|
|
// receive a frame response over the wire
|
|
bool read_response(uint8_t *response_buffer);
|
|
// parses the response and updates the vtx settings
|
|
bool parse_frame_response(const uint8_t *buffer);
|
|
bool parse_response_buffer(const uint8_t *buffer);
|
|
// get last reading from the fifo queue
|
|
bool get_readings(AP_VideoTX *vtx_dest);
|
|
|
|
// command functions
|
|
// request settings
|
|
void request_settings();
|
|
// change the mode
|
|
void set_operation_mode(uint8_t mode);
|
|
// change the frequency
|
|
void set_frequency(uint16_t frequency, bool isPitModeFreq);
|
|
// change the channel
|
|
void set_channel(uint8_t chan);
|
|
// get the pitmode frequency
|
|
void request_pit_mode_frequency();
|
|
// set the power
|
|
void set_power(uint16_t power_mw, uint16_t dbm);
|
|
// set the power using power_level, spec versions 1 and 2 or dbm value for spec version 2.1
|
|
void set_power(uint8_t power_level);
|
|
// set the band and channel
|
|
void set_band_channel(const uint8_t band, const uint8_t channel);
|
|
|
|
// command functions
|
|
void push_command_only_frame(uint8_t command);
|
|
void push_uint8_command_frame(uint8_t command, uint8_t data);
|
|
void push_uint16_command_frame(uint8_t command, uint16_t data);
|
|
|
|
static void unpack_frequency(Settings *settings, const uint16_t frequency);
|
|
static void unpack_settings(Settings *settings, const SettingsResponseFrame *frame);
|
|
static void unpack_settings(Settings *settings, const SettingsExtendedResponseFrame *frame);
|
|
|
|
// change baud automatically when request-response fails many times
|
|
void update_baud_rate();
|
|
|
|
void set_configuration_pending(bool pending) { _vtx_changes_pending = pending; }
|
|
bool is_configuration_pending(){ return _vtx_changes_pending;}
|
|
};
|
|
#endif
|