feat(gx12): add Ground Station AUX1 mode
This commit is contained in:
@@ -0,0 +1,77 @@
|
||||
#include "edgetx.h"
|
||||
#include "groundstation.h"
|
||||
#include "os/timer.h"
|
||||
#include "tasks/mixer_task.h"
|
||||
|
||||
namespace {
|
||||
constexpr uint8_t kMagic0 = 'G';
|
||||
constexpr uint8_t kMagic1 = 'S';
|
||||
constexpr uint8_t kVersion = 1;
|
||||
constexpr uint8_t kTypeRCChannels = 1;
|
||||
constexpr uint8_t kChannels = 16;
|
||||
constexpr uint8_t kFrameSize = 10 + kChannels * 2 + 2;
|
||||
constexpr uint32_t kPeriodMs = 40; // 25 Hz
|
||||
|
||||
const etx_serial_driver_t *driver = nullptr;
|
||||
void *driverCtx = nullptr;
|
||||
timer_handle_t timer = TIMER_INITIALIZER;
|
||||
uint16_t sequence = 0;
|
||||
|
||||
uint16_t crc16(const uint8_t *data, size_t size)
|
||||
{
|
||||
uint16_t crc = 0xffff;
|
||||
for (size_t i = 0; i < size; ++i) {
|
||||
crc ^= uint16_t(data[i]) << 8;
|
||||
for (uint8_t bit = 0; bit < 8; ++bit)
|
||||
crc = (crc & 0x8000) ? uint16_t((crc << 1) ^ 0x1021) : uint16_t(crc << 1);
|
||||
}
|
||||
return crc;
|
||||
}
|
||||
|
||||
void sendRCFrame()
|
||||
{
|
||||
if (!driver || !driver->sendByte || !mixerTaskRunning()) return;
|
||||
|
||||
uint8_t frame[kFrameSize] = { kMagic0, kMagic1, kVersion, kTypeRCChannels };
|
||||
frame[4] = sequence & 0xff;
|
||||
frame[5] = sequence >> 8;
|
||||
const uint32_t timestamp = get_tmr10ms() * 10;
|
||||
frame[6] = timestamp & 0xff;
|
||||
frame[7] = (timestamp >> 8) & 0xff;
|
||||
frame[8] = (timestamp >> 16) & 0xff;
|
||||
frame[9] = (timestamp >> 24) & 0xff;
|
||||
|
||||
for (uint8_t i = 0; i < kChannels; ++i) {
|
||||
const uint16_t value = channelOutputs[i];
|
||||
frame[10 + i * 2] = value & 0xff;
|
||||
frame[11 + i * 2] = value >> 8;
|
||||
}
|
||||
|
||||
const uint16_t crc = crc16(frame, kFrameSize - 2);
|
||||
frame[kFrameSize - 2] = crc & 0xff;
|
||||
frame[kFrameSize - 1] = crc >> 8;
|
||||
for (uint8_t byte : frame) driver->sendByte(driverCtx, byte);
|
||||
++sequence;
|
||||
}
|
||||
|
||||
void timerCb(timer_handle_t *)
|
||||
{
|
||||
// Drain input now so the future profile-control parser has a single owner.
|
||||
// The baseline intentionally does not act on received bytes yet.
|
||||
if (driver && driver->getByte) {
|
||||
uint8_t ignored;
|
||||
while (driver->getByte(driverCtx, &ignored)) {}
|
||||
}
|
||||
sendRCFrame();
|
||||
}
|
||||
} // namespace
|
||||
|
||||
void groundstationSetSerialDriver(void *ctx, const etx_serial_driver_t *drv)
|
||||
{
|
||||
driverCtx = ctx;
|
||||
driver = drv;
|
||||
sequence = 0;
|
||||
if (!timer_is_created(&timer))
|
||||
timer_create(&timer, timerCb, "gstation", kPeriodMs, true);
|
||||
timer_start(&timer);
|
||||
}
|
||||
Reference in New Issue
Block a user