diff --git a/src/main/io/rcdevice.c b/src/main/io/rcdevice.c index 14c02c6ee6..befd3b2833 100644 --- a/src/main/io/rcdevice.c +++ b/src/main/io/rcdevice.c @@ -187,11 +187,11 @@ static bool runcamDeviceSendRequestAndWaitingResp(runcamDevice_t *device, uint8_ // only the command sending on initializing step need retry logic, // otherwise, the timeout of 1000 ms is enough for the response from device if (commandID == RCDEVICE_PROTOCOL_COMMAND_GET_DEVICE_INFO) { - max_retries = 3; - timeoutMs = 100; // we have test some device, 100ms as timeout, and retry times be 3, it's stable for most case + max_retries = 5; + timeoutMs = 60; // we have test some device, 60ms as timeout, and retry times be 5, it's stable for most case } - while (max_retries--) { + for (int i = 0; i < max_retries; i++) { // flush rx buffer runcamDeviceFlushRxBuffer(device); @@ -212,10 +212,95 @@ static bool runcamDeviceSendRequestAndWaitingResp(runcamDevice_t *device, uint8_ return false; } +static uint8_t calcCRCFromData(uint8_t *ptr, uint8_t len) +{ + uint8_t i; + uint8_t crc = 0x00; + while (len--) { + crc ^= *ptr++; + for (i = 8; i > 0; --i) { + if (crc & 0x80) { + crc = (crc << 1) ^ 0x31; + } else { + crc = (crc << 1); + } + } + } + return crc; +} + +static void sendCtrlCommand(runcamDevice_t *device, rcsplit_ctrl_argument_e argument) +{ + if (!device->serialPort) { + return ; + } + + uint8_t uart_buffer[5] = {0}; + uint8_t crc = 0; + + uart_buffer[0] = RCSPLIT_PACKET_HEADER; + uart_buffer[1] = RCSPLIT_PACKET_CMD_CTRL; + uart_buffer[2] = argument; + uart_buffer[3] = RCSPLIT_PACKET_TAIL; + crc = calcCRCFromData(uart_buffer, 4); + + // build up a full request [header]+[command]+[argument]+[crc]+[tail] + uart_buffer[3] = crc; + uart_buffer[4] = RCSPLIT_PACKET_TAIL; + + // write to device + serialWriteBuf(device->serialPort, uart_buffer, 5); +} + // get the device info(firmware version, protocol version and features, see the // definition of runcamDeviceInfo_t to know more) static bool runcamDeviceGetDeviceInfo(runcamDevice_t *device, uint8_t *outputBuffer) { + // Send "who are you" command to device to detect the device whether is running RCSplit FW1.0 or RCSplit FW1.1 + int max_retries = 2; + for (int i = 0; i < max_retries; i++) { + runcamDeviceFlushRxBuffer(device); + sendCtrlCommand(device, RCSPLIT_CTRL_ARGU_WHO_ARE_YOU); + + timeMs_t timeout = millis() + 500; + uint8_t response[5] = { 0 }; + while (millis() < timeout) { + if (serialRxBytesWaiting(device->serialPort) >= 5) { + response[0] = serialRead(device->serialPort); + response[1] = serialRead(device->serialPort); + response[2] = serialRead(device->serialPort); + response[3] = serialRead(device->serialPort); + response[4] = serialRead(device->serialPort); + if (response[0] != RCSPLIT_PACKET_HEADER || response[1] != RCSPLIT_PACKET_CMD_CTRL || response[2] != RCSPLIT_CTRL_ARGU_WHO_ARE_YOU || response[4] != RCSPLIT_PACKET_TAIL) { + break; + } + + uint8_t crcFromPacket = response[3]; + response[3] = response[4]; // move packet tail field to crc field, and calc crc with first 4 bytes + uint8_t crc = calcCRCFromData(response, 4); + if (crc != crcFromPacket) { + break; + } + + // generate response for RCSplit FW 1.0 and FW 1.1 + outputBuffer[0] = RCDEVICE_PROTOCOL_HEADER; + // protocol version + outputBuffer[1] = RCDEVICE_PROTOCOL_RCSPLIT_VERSION; + // features + outputBuffer[2] = RCDEVICE_PROTOCOL_FEATURE_SIMULATE_POWER_BUTTON | RCDEVICE_PROTOCOL_FEATURE_SIMULATE_WIFI_BUTTON | RCDEVICE_PROTOCOL_FEATURE_CHANGE_MODE; + outputBuffer[3] = 0; + + crc = 0; + const uint8_t * const end = outputBuffer + 4; + for (const uint8_t *ptr = outputBuffer; ptr < end; ++ptr) { + crc = crc8_dvb_s2(crc, *ptr); + } + outputBuffer[4] = crc; + return true; + } + } + } + return runcamDeviceSendRequestAndWaitingResp(device, RCDEVICE_PROTOCOL_COMMAND_GET_DEVICE_INFO, NULL, 0, outputBuffer, NULL); } @@ -277,7 +362,14 @@ bool runcamDeviceInit(runcamDevice_t *device) bool runcamDeviceSimulateCameraButton(runcamDevice_t *device, uint8_t operation) { - runcamDeviceSendPacket(device, RCDEVICE_PROTOCOL_COMMAND_CAMERA_CONTROL, &operation, sizeof(operation)); + if (device->info.protocolVersion == RCDEVICE_PROTOCOL_RCSPLIT_VERSION) { + sendCtrlCommand(device, operation + 1); + } else if (device->info.protocolVersion == RCDEVICE_PROTOCOL_VERSION_1_0) { + runcamDeviceSendPacket(device, RCDEVICE_PROTOCOL_COMMAND_CAMERA_CONTROL, &operation, sizeof(operation)); + } else { + return false; + } + return true; } diff --git a/src/main/target/SPRACINGF3MINI/target.h b/src/main/target/SPRACINGF3MINI/target.h index 0cc2c80cb3..e0e924aea3 100644 --- a/src/main/target/SPRACINGF3MINI/target.h +++ b/src/main/target/SPRACINGF3MINI/target.h @@ -30,6 +30,9 @@ #define SPRACINGF3MINI_REV 2 #endif +// Space reduction measures to make the firmware fit into flash: +#undef USE_RCDEVICE + #define CONFIG_FASTLOOP_PREFERRED_ACC ACC_NONE #define LED0_PIN PB3 diff --git a/src/test/unit/rcdevice_unittest.cc b/src/test/unit/rcdevice_unittest.cc index 19ea262996..ff4fe383fb 100644 --- a/src/test/unit/rcdevice_unittest.cc +++ b/src/test/unit/rcdevice_unittest.cc @@ -1575,6 +1575,9 @@ extern "C" { // // reset the input buffer testData.responseDataReadPos = 0; testData.indexOfCurrentRespBuf++; + if (testData.indexOfCurrentRespBuf >= testData.responseBufCount) { + testData.indexOfCurrentRespBuf = 0; + } // testData.maxTimesOfRespDataAvailable = testData.responseDataLen + 1; }