iNavFlight之MSP DJI协议分析

  • 1. iNav串行口通信
    • 1.1 iNav 串口任务
    • 1.2 调用逻辑
  • 2. iNav串行抽象
    • 2.1 框架代码
    • 2.2 MSP(DJI)协议处理
  • 3. DJI协议相关实现
    • 3.1 DJI串口初始化
    • 3.2 DJI命令集
    • 3.3. DJI相关函数
  • 4. 协议格式
  • 5. 参考资料

MSP DJI协议主要是为了解决如何将飞控内部信息传送到DJI数字图传,进而在DJI的数字系统的视频上叠加飞控OSD信息。

注:目前模拟图传的做法是通过MAX7456芯片将模拟VI和飞控

1. iNav串行口通信

1.1 iNav 串口任务

taskHandleSerial是STM32任务之一。

    [TASK_SERIAL] = {.taskName = "SERIAL",.taskFunc = taskHandleSerial,.desiredPeriod = TASK_PERIOD_HZ(100),     // 100 Hz should be enough to flush up to 115 bytes @ 115200 baud.staticPriority = TASK_PRIORITY_LOW,},

1.2 调用逻辑

taskHandleSerial是专门集中处理串口的任务。其中djiOsdSerialProcess是与DJI天空端通信的实现代码入口。

void taskHandleSerial(timeUs_t currentTimeUs)
{UNUSED(currentTimeUs);// in cli mode, all serial stuff goes to here. enter cli mode by sending #if (cliMode) {cliProcess();}// Allow MSP processing even if in CLI modemspSerialProcess(ARMING_FLAG(ARMED) ? MSP_SKIP_NON_MSP_DATA : MSP_EVALUATE_NON_MSP_DATA, mspFcProcessCommand);#if defined(USE_DJI_HD_OSD)// DJI OSD uses a special flavour of MSP (subset of Betaflight 4.1.1 MSP) - process as part of serial taskdjiOsdSerialProcess();
#endif#ifdef USE_MSP_OSD// Capture MSP Displayport messages to determine if VTX is connectedmspOsdSerialProcess(mspFcProcessCommand);
#endif
}

mspSerialProcess是正常的MSP控制协议函数实现。

void mspSerialProcess(mspEvaluateNonMspData_e evaluateNonMspData, mspProcessCommandFnPtr mspProcessCommandFn)
{for (uint8_t portIndex = 0; portIndex < MAX_MSP_PORT_COUNT; portIndex++) {mspPort_t * const mspPort = &mspPorts[portIndex];if (mspPort->port) {mspSerialProcessOnePort(mspPort, evaluateNonMspData, mspProcessCommandFn);}}
}

djiOsdSerialProcess是专门用于处理与DJI天空端通信的函数实现。

void djiOsdSerialProcess(void)
{// Check if DJI OSD is configuredif (!djiMspPort.port) {return;}// Piggyback on existing MSP protocol stack, but pass our special command processing functionmspSerialProcessOnePort(&djiMspPort, MSP_SKIP_NON_MSP_DATA, djiProcessMspCommand);
}

这段代码据说没有使能,详见:how to open MSP_DISPLAYPORT #6415。但是从代码上看是有编译到的,详见:#define USE_MSP_OSD,因此应该是特殊配置的FUNCTION_MSP_OSD端口(且不是DJI的)。

#ifdef USE_MSP_OSD// Capture MSP Displayport messages to determine if VTX is connectedmspOsdSerialProcess(mspFcProcessCommand);
#endif

2. iNav串行抽象

从该代码实现角度看,是典型的C/S模型。

通用框架mspSerialProcessOnePort主要是提供收包,异常处理,解析,调用命令处理流程和报文反馈,其主要差异在于命令处理流程部分。

2.1 框架代码

mspSerialProcessOnePort框架代码是MSP协议的通用实现,其主要差异在于命令码处理的mspProcessCommandFn函数。

  1. 当MSP_SKIP_NON_MSP_DATA,用mspProcessCommandFn处理;

a) djiProcessMspCommand: MSP(DJI)协议处理
b) mspFcProcessCommand: MSP(Control)协议处理

  1. 当MSP_EVALUATE_NON_MSP_DATA,mspEvaluateNonMspData;

命令行模式

void mspSerialProcessOnePort(mspPort_t * const mspPort, mspEvaluateNonMspData_e evaluateNonMspData, mspProcessCommandFnPtr mspProcessCommandFn)
{mspPostProcessFnPtr mspPostProcessFn = NULL;if (serialRxBytesWaiting(mspPort->port)) {// There are bytes incoming - abort pending requestmspPort->lastActivityMs = millis();mspPort->pendingRequest = MSP_PENDING_NONE;// Process incoming byteswhile (serialRxBytesWaiting(mspPort->port)) {const uint8_t c = serialRead(mspPort->port);const bool consumed = mspSerialProcessReceivedData(mspPort, c);if (!consumed && evaluateNonMspData == MSP_EVALUATE_NON_MSP_DATA) {mspEvaluateNonMspData(mspPort, c);}if (mspPort->c_state == MSP_COMMAND_RECEIVED) {mspPostProcessFn = mspSerialProcessReceivedCommand(mspPort, mspProcessCommandFn);break; // process one command at a time so as not to block.}}if (mspPostProcessFn) {waitForSerialPortToFinishTransmitting(mspPort->port);mspPostProcessFn(mspPort->port);}}else {mspProcessPendingRequest(mspPort);}
}

2.2 MSP(DJI)协议处理

DJI天空端发出请求,FC接收到请求后反馈请求结果,详见:djiProcessMspCommand。

static mspResult_e djiProcessMspCommand(mspPacket_t *cmd, mspPacket_t *reply, mspPostProcessFnPtr *mspPostProcessFn)
{UNUSED(mspPostProcessFn);sbuf_t *dst = &reply->buf;sbuf_t *src = &cmd->buf;// Start initializing the reply messagereply->cmd = cmd->cmd;reply->result = MSP_RESULT_ACK;switch (cmd->cmd) {case DJI_MSP_API_VERSION:sbufWriteU8(dst, MSP_PROTOCOL_VERSION);sbufWriteU8(dst, DJI_API_VERSION_MAJOR);sbufWriteU8(dst, DJI_API_VERSION_MINOR);break;case DJI_MSP_FC_VARIANT:{const char * const flightControllerIdentifier = INAV_IDENTIFIER;sbufWriteData(dst, flightControllerIdentifier, FLIGHT_CONTROLLER_IDENTIFIER_LENGTH);}break;case DJI_MSP_FC_VERSION:sbufWriteU8(dst, 4);sbufWriteU8(dst, 1);sbufWriteU8(dst, 0);break;case DJI_MSP_NAME:{
#if defined(USE_OSD)if (djiOsdConfig()->use_name_for_messages)  {djiSerializeCraftNameOverride(dst);} else {
#endifsbufWriteData(dst, systemConfig()->name, (int)strlen(systemConfig()->name));
#if defined(USE_OSD)}
#endifbreak;}break;case DJI_MSP_STATUS:case DJI_MSP_STATUS_EX:{// DJI OSD relies on a statically defined bit order and doesn't use MSP_BOXIDS// to get actual BOX order. We need a special packBoxModeFlags()boxBitmask_t flightModeBitmask;djiPackBoxModeBitmask(&flightModeBitmask);sbufWriteU16(dst, (uint16_t)cycleTime);sbufWriteU16(dst, 0);sbufWriteU16(dst, packSensorStatus());sbufWriteData(dst, &flightModeBitmask, 4);        // unconditional part of flags, first 32 bitssbufWriteU8(dst, getConfigProfile());sbufWriteU16(dst, constrain(averageSystemLoadPercent, 0, 100));if (cmd->cmd == MSP_STATUS_EX) {sbufWriteU8(dst, 3);            // PID_PROFILE_COUNTsbufWriteU8(dst, 1);            // getCurrentControlRateProfileIndex()} else {sbufWriteU16(dst, cycleTime);   // gyro cycle time}// Cap BoxModeFlags to 32 bits// write flightModeFlags header. Lowest 4 bits contain number of bytes that followsbufWriteU8(dst, 0);// sbufWriteData(dst, ((uint8_t*)&flightModeBitmask) + 4, byteCount);// Write arming disable flagssbufWriteU8(dst, DJI_ARMING_DISABLE_FLAGS_COUNT);sbufWriteU32(dst, djiPackArmingDisabledFlags());// Extra flagssbufWriteU8(dst, 0);}break;case DJI_MSP_RC:// Only send sticks (first 4 channels)for (int i = 0; i < STICK_CHANNEL_COUNT; i++) {sbufWriteU16(dst, rxGetChannelValue(i));}break;case DJI_MSP_RAW_GPS:sbufWriteU8(dst, gpsSol.fixType);sbufWriteU8(dst, gpsSol.numSat);sbufWriteU32(dst, gpsSol.llh.lat);sbufWriteU32(dst, gpsSol.llh.lon);sbufWriteU16(dst, gpsSol.llh.alt / 100);sbufWriteU16(dst, osdGetSpeedFromSelectedSource());sbufWriteU16(dst, gpsSol.groundCourse);break;case DJI_MSP_COMP_GPS:sbufWriteU16(dst, GPS_distanceToHome);sbufWriteU16(dst, GPS_directionToHome);sbufWriteU8(dst, gpsSol.flags.gpsHeartbeat ? 1 : 0);break;case DJI_MSP_ATTITUDE:sbufWriteU16(dst, attitude.values.roll);sbufWriteU16(dst, attitude.values.pitch);sbufWriteU16(dst, DECIDEGREES_TO_DEGREES(attitude.values.yaw));break;case DJI_MSP_ALTITUDE:sbufWriteU32(dst, lrintf(getEstimatedActualPosition(Z)));sbufWriteU16(dst, lrintf(getEstimatedActualVelocity(Z)));break;case DJI_MSP_ANALOG:sbufWriteU8(dst,  constrain(getBatteryVoltage() / 10, 0, 255));sbufWriteU16(dst, constrain(getMAhDrawn(), 0, 0xFFFF)); // milliamp hours drawn from battery
#ifdef USE_SERIALRX_CRSF// Range of RSSI field: 0-99: 99 = 150 hz , 0 - 98 50 hz / 4 hzif (djiOsdConfig()->rssi_source == DJI_CRSF_LQ) {uint16_t scaledLq = 0;if (rxLinkStatistics.rfMode >= 2) {scaledLq = RSSI_MAX_VALUE;} else {scaledLq = scaleRange(constrain(rxLinkStatistics.uplinkLQ, 0, 100), 0, 100, 0, RSSI_BOUNDARY(98));}sbufWriteU16(dst, scaledLq);} else {
#endifsbufWriteU16(dst, getRSSI());
#ifdef USE_SERIALRX_CRSF}
#endifsbufWriteU16(dst, constrain(getAmperage(), -0x8000, 0x7FFF)); // send amperage in 0.01 A steps, range is -320A to 320AsbufWriteU16(dst, getBatteryVoltage());break;case DJI_MSP_PID:for (unsigned i = 0; i < ARRAYLEN(djiPidIndexMap); i++) {sbufWriteU8(dst, pidBank()->pid[djiPidIndexMap[i]].P);sbufWriteU8(dst, pidBank()->pid[djiPidIndexMap[i]].I);sbufWriteU8(dst, pidBank()->pid[djiPidIndexMap[i]].D);}break;case DJI_MSP_BATTERY_STATE:// Battery characteristicssbufWriteU8(dst, constrain(getBatteryCellCount(), 0, 255));sbufWriteU16(dst, currentBatteryProfile->capacity.value);// Battery statesbufWriteU8(dst, constrain(getBatteryVoltage() / 10, 0, 255)); // in 0.1V stepssbufWriteU16(dst, constrain(getMAhDrawn(), 0, 0xFFFF));sbufWriteU16(dst, constrain(getAmperage(), -0x8000, 0x7FFF));// Battery alerts - used values match Betaflight's/DJI'ssbufWriteU8(dst,  getBatteryState());// Additional battery voltage field (in 0.01V steps)sbufWriteU16(dst, getBatteryVoltage());break;case DJI_MSP_RTC:{dateTime_t datetime;// We don't care about validity here - dt will be always set to a sane value// rtcGetDateTime() will call rtcGetDefaultDateTime() internallyrtcGetDateTime(&datetime);sbufWriteU16(dst, datetime.year);sbufWriteU8(dst, datetime.month);sbufWriteU8(dst, datetime.day);sbufWriteU8(dst, datetime.hours);sbufWriteU8(dst, datetime.minutes);sbufWriteU8(dst, datetime.seconds);sbufWriteU16(dst, datetime.millis);}break;case DJI_MSP_ESC_SENSOR_DATA:if (djiOsdConfig()->proto_workarounds & DJI_OSD_USE_NON_STANDARD_MSP_ESC_SENSOR_DATA) {// Version 1.00.06 of DJI firmware is not using the standard MSP_ESC_SENSOR_DATAuint16_t protoRpm = 0;int16_t protoTemp = 0;#if defined(USE_ESC_SENSOR)if (STATE(ESC_SENSOR_ENABLED) && getMotorCount() > 0) {uint32_t motorRpmAcc = 0;int32_t motorTempAcc = 0;for (int i = 0; i < getMotorCount(); i++) {const escSensorData_t * escSensor = getEscTelemetry(i);motorRpmAcc += escSensor->rpm;motorTempAcc += escSensor->temperature;}protoRpm = motorRpmAcc / getMotorCount();protoTemp = motorTempAcc / getMotorCount();}
#endifswitch (djiOsdConfig()->esc_temperature_source) {// This is ESC temperature (as intended)case DJI_OSD_TEMP_ESC:// No-op, temperature is already set to ESCbreak;// Re-purpose the field for core temperaturecase DJI_OSD_TEMP_CORE:getIMUTemperature(&protoTemp);protoTemp = protoTemp / 10;break;// Re-purpose the field for baro temperaturecase DJI_OSD_TEMP_BARO:getBaroTemperature(&protoTemp);protoTemp = protoTemp / 10;break;}// No motor count, just raw temp and RPM datasbufWriteU8(dst, protoTemp);sbufWriteU16(dst, protoRpm);}else {// Use standard MSP_ESC_SENSOR_DATA messagesbufWriteU8(dst, getMotorCount());for (int i = 0; i < getMotorCount(); i++) {uint16_t motorRpm = 0;int16_t motorTemp = 0;// If ESC_SENSOR is enabled, pull the telemetry data and get motor RPM
#if defined(USE_ESC_SENSOR)if (STATE(ESC_SENSOR_ENABLED)) {const escSensorData_t * escSensor = getEscTelemetry(i);motorRpm = escSensor->rpm;motorTemp = escSensor->temperature;}
#endif// Now populate temperature field (which we may override for different purposes)switch (djiOsdConfig()->esc_temperature_source) {// This is ESC temperature (as intended)case DJI_OSD_TEMP_ESC:// No-op, temperature is already set to ESCbreak;// Re-purpose the field for core temperaturecase DJI_OSD_TEMP_CORE:getIMUTemperature(&motorTemp);motorTemp = motorTemp / 10;break;// Re-purpose the field for baro temperaturecase DJI_OSD_TEMP_BARO:getBaroTemperature(&motorTemp);motorTemp = motorTemp / 10;break;}// Add data for this motor to the packetsbufWriteU8(dst, motorTemp);sbufWriteU16(dst, motorRpm);}}break;case DJI_MSP_OSD_CONFIG:
#if defined(USE_OSD)// This involved some serious magic, better contain in a separate function for readabilitydjiSerializeOSDConfigReply(dst);
#elsesbufWriteU8(dst, 0);
#endifbreak;case DJI_MSP_FILTER_CONFIG:sbufWriteU8(dst, gyroConfig()->gyro_main_lpf_hz);           // BF: gyroConfig()->gyro_lowpass_hzsbufWriteU16(dst, pidProfile()->dterm_lpf_hz);              // BF: currentPidProfile->dterm_lowpass_hzsbufWriteU16(dst, pidProfile()->yaw_lpf_hz);                // BF: currentPidProfile->yaw_lowpass_hzsbufWriteU16(dst, 0);                                       // BF: gyroConfig()->gyro_soft_notch_hz_1sbufWriteU16(dst, 1);                                       // BF: gyroConfig()->gyro_soft_notch_cutoff_1sbufWriteU16(dst, 0);                                       // BF: currentPidProfile->dterm_notch_hzsbufWriteU16(dst, 1);                                       // BF: currentPidProfile->dterm_notch_cutoffsbufWriteU16(dst, 0);                                       // BF: gyroConfig()->gyro_soft_notch_hz_2sbufWriteU16(dst, 1);                                       // BF: gyroConfig()->gyro_soft_notch_cutoff_2sbufWriteU8(dst, 0);                                        // BF: currentPidProfile->dterm_filter_typesbufWriteU8(dst, gyroConfig()->gyro_lpf);                   // BF: gyroConfig()->gyro_hardware_lpf);sbufWriteU8(dst, 0);                                        // BF: DEPRECATED: gyro_32khz_hardware_lpfsbufWriteU16(dst, gyroConfig()->gyro_main_lpf_hz);          // BF: gyroConfig()->gyro_lowpass_hz);sbufWriteU16(dst, 0);                                       // BF: gyroConfig()->gyro_lowpass2_hz);sbufWriteU8(dst, 0);                                        // BF: gyroConfig()->gyro_lowpass_type);sbufWriteU8(dst, 0);                                        // BF: gyroConfig()->gyro_lowpass2_type);sbufWriteU16(dst, 0);                                       // BF: currentPidProfile->dterm_lowpass2_hz);sbufWriteU8(dst, 0);                                        // BF: currentPidProfile->dterm_filter2_type);break;case DJI_MSP_RC_TUNING:sbufWriteU8(dst, 100);                                      // INAV doesn't use rcRatesbufWriteU8(dst, currentControlRateProfile->stabilized.rcExpo8);for (int i = 0 ; i < 3; i++) {// R,P,Y rates see flight_dynamics_index_tsbufWriteU8(dst, currentControlRateProfile->stabilized.rates[i]);}sbufWriteU8(dst, currentControlRateProfile->throttle.dynPID);sbufWriteU8(dst, currentControlRateProfile->throttle.rcMid8);sbufWriteU8(dst, currentControlRateProfile->throttle.rcExpo8);sbufWriteU16(dst, currentControlRateProfile->throttle.pa_breakpoint);sbufWriteU8(dst, currentControlRateProfile->stabilized.rcYawExpo8);sbufWriteU8(dst, 100);                                      // INAV doesn't use rcRatesbufWriteU8(dst, 100);                                      // INAV doesn't use rcRatesbufWriteU8(dst, currentControlRateProfile->stabilized.rcExpo8);// added in 1.41sbufWriteU8(dst, 0);sbufWriteU8(dst, currentControlRateProfile->throttle.dynPID);break;case DJI_MSP_SET_PID:// Check if we have enough data for all PID coefficientsif ((unsigned)sbufBytesRemaining(src) >= ARRAYLEN(djiPidIndexMap) * 3) {for (unsigned i = 0; i < ARRAYLEN(djiPidIndexMap); i++) {pidBankMutable()->pid[djiPidIndexMap[i]].P = sbufReadU8(src);pidBankMutable()->pid[djiPidIndexMap[i]].I = sbufReadU8(src);pidBankMutable()->pid[djiPidIndexMap[i]].D = sbufReadU8(src);}schedulePidGainsUpdate();}else {reply->result = MSP_RESULT_ERROR;}break;case DJI_MSP_PID_ADVANCED:// TODOreply->result = MSP_RESULT_ERROR;break;case DJI_MSP_SET_FILTER_CONFIG:case DJI_MSP_SET_PID_ADVANCED:case DJI_MSP_SET_RC_TUNING:// TODOreply->result = MSP_RESULT_ERROR;break;default:// debug[1]++;// debug[2] = cmd->cmd;reply->result = MSP_RESULT_ERROR;break;}// Process DONT_REPLY flagif (cmd->flags & MSP_FLAG_DONT_REPLY) {reply->result = MSP_RESULT_NO_REPLY;}return reply->result;
}

3. DJI协议相关实现

3.1 DJI串口初始化

main└──> init└──> djiOsdSerialInit

3.2 DJI命令集

最新DJI命令集请查阅这里。

#define DJI_MSP_API_VERSION             1       // INAV: Implemented     | DSI: ???             |
#define DJI_MSP_FC_VARIANT              2       // INAV: Implemented     | DSI: ???             |
#define DJI_MSP_FC_VERSION              3       // INAV: Implemented     | DSI: ???             |
#define DJI_MSP_NAME                    10      // INAV: Implemented     | DSI: Implemented     | For OSD 'Craft Name'
#define DJI_MSP_OSD_CONFIG              84      // INAV: Implemented     | DSI: Implemented     | OSD item count + positions
#define DJI_MSP_FILTER_CONFIG           92      // INAV: Not implemented | DSI: Implemented     |
#define DJI_MSP_PID_ADVANCED            94      // INAV: Not implemented | DSI: Implemented     |
#define DJI_MSP_STATUS                  101     // INAV: Implemented     | DSI: Implemented     | For OSD ‘armingTime’, Flight controller arming status
#define DJI_MSP_RC                      105     // INAV: Implemented     | DSI: Implemented     |
#define DJI_MSP_RAW_GPS                 106     // INAV: Implemented     | DSI: Implemented     | For OSD ‘GPS Sats’ + coordinates
#define DJI_MSP_COMP_GPS                107     // INAV: Implemented     | DSI: Not implemented | GPS direction to home & distance to home
#define DJI_MSP_ATTITUDE                108     // INAV: Implemented     | DSI: Implemented     | For OSD ‘Angle: roll & pitch’
#define DJI_MSP_ALTITUDE                109     // INAV: Implemented     | DSI: Implemented     | For OSD ‘Numerical Vario’
#define DJI_MSP_ANALOG                  110     // INAV: Implemented     | DSI: Implemented     | For OSD ‘RSSI Value’, For OSD ‘Battery voltage’ etc
#define DJI_MSP_RC_TUNING               111     // INAV: Not implemented | DSI: Implemented     |
#define DJI_MSP_PID                     112     // INAV: Implemented     | DSI: Implemented     | For OSD ‘PID roll, yaw, pitch'
#define DJI_MSP_BATTERY_STATE           130     // INAV: Implemented     | DSI: Implemented     | For OSD ‘Battery current mAh drawn’ etc
#define DJI_MSP_ESC_SENSOR_DATA         134     // INAV: Implemented     | DSI: Implemented     | For OSD ‘ESC temperature’
#define DJI_MSP_STATUS_EX               150     // INAV: Implemented     | DSI: Implemented     | For OSD ‘Fly mode', For OSD ‘Disarmed’
#define DJI_MSP_RTC                     247     // INAV: Implemented     | DSI: Implemented     | For OSD ‘RTC date time’

3.3. DJI相关函数

static void djiPackBoxModeBitmask(boxBitmask_t * flightModeBitmask)
static uint32_t djiPackArmingDisabledFlags(void)
static uint32_t djiEncodeOSDEnabledWarnings(void)  //TODO
static void djiSerializeOSDConfigReply(sbuf_t *dst)
static char * osdArmingDisabledReasonMessage(void)
static char * osdFailsafePhaseMessage(void)
static char * osdFailsafeInfoMessage(void)
static char * navigationStateMessage(void)
static int32_t osdConvertVelocityToUnit(int32_t vel)
void osdDJIFormatVelocityStr(char* buff)
static void osdDJIFormatThrottlePosition(char *buff, bool autoThr )
static void osdDJIFormatDistanceStr(char *buff, int32_t dist)
static void osdDJIEfficiencyMahPerKM(char *buff)
static void osdDJIAdjustmentMessage(char *buff, uint8_t adjustmentFunction)
static bool osdDJIFormatAdjustments(char *buff)
static bool djiFormatMessages(char *buff)
static void djiSerializeCraftNameOverride(sbuf_t *dst)

4. 协议格式

  +---+---+--------+---------+--------+------+---------+------------------------------+-------------+|                            Multiwii Serial Protocol V2                length = 9 + payload size |+---+---+--------+---------+--------+------+---------+------------------------------+-------------+| $ | X | < ! >  | flag(1) | cmd(2)        | size(2) | payload(16bit len)           | checksum_v2 |+---+---+--------+---------+--------+------+---------+------------------------------+-------------+
  • ‘$’:表示SOF(Start Of a frame)
  • ‘X’:表示V2
  • ‘<’: 表示request
  • ‘>’:表示response
  • ‘!’:表示error

5. 参考资料

【1】iNav 2.4.0 Release Notes – Support for DJI HD FPV in Feb 6, 2020
【2】Multiwii Serial Protocol
【3】Multiwii Serial Protocol (MSP)
【4】BetaFlight模块设计之三十二:MSP协议模块分析
【5】iNavFlight之MSP DJI协议天空端请求报文
【6】iNavFlight之MSP DJI协议飞控端请求应答

iNavFlight之MSP DJI协议分析相关推荐

  1. iNavFlight之MSP DJI协议飞控端请求应答

    iNavFlight之MSP DJI协议飞控端请求应答 1. 报文格式 2. 报文标志(flag) 3. 报文命令(cmd) 4. 请求应答 & 反馈报文 4.1 DJI_MSP_API_VE ...

  2. iNavFlight之MSP v2 Sensor报文格式

    iNavFlight之MSP v2 Sensor报文格式 1. MSP v2传感报文介绍 2. MSP v2协议格式 3. MSP v2传感代码流程 4. MSP v2 传感器 4.1 光流传感报文- ...

  3. iNavFlight之电传MAVLink协议

    iNavFlight之电传MAVLink协议 1. 业务逻辑框架 2. MAVLink电传报文 2.1 MAVLink电传报文格式 2.2 iNav支持地面站报文(接收) 2.3 iNav支持飞控报文 ...

  4. WebSocket协议分析

    点击上方↑↑↑蓝字[协议分析与还原]关注我们 " 解析websocket数据格式." 好久不见,一晃一年又过去了,祝大家新年好运. 今天,给大家分析一个常见的协议--WebSock ...

  5. 宅男抖音某猫协议分析及应用破解

    " 分析传说中的快x,顺便提供破VIP线路及去启动广告方法." 在当今这个由应用市场主导的网络上,流传着一批应用,它们低调又神秘,依赖口碑与独立网站在地下渠道传播,应用市场中从来都 ...

  6. 从新手到入门,如何进入协议分析的世界

    " 协议分析与还原自学及入门指南." 有部分朋友给我发消息,说对协议还原很感兴趣,但苦于没人指导,希望得到我的帮助,问我如何进行协议分析的学习. 这篇文章从初学者的角度,编列了一个 ...

  7. 协议分析中的TCP/IP网络协议

    " TCP/IP协议作为互联网的基础,在协议分析中不可或缺,本文介绍在对协议进行分析还原的过程中的一些要点,快速掌握协议还原的精髓." 注意,本文比较枯燥乏味,若非需要了解TCP/ ...

  8. 五款常用协议分析处理工具推荐

    工欲善其事,必先利其器,一款好的工具,能取到事半功倍的效果. 进行协议分析,好的辅助工具必不可少,本文推荐五款最常用且易用的协议分析工具给大家,包括两款综合抓包及分析工具,一款协议重放工具,一款pca ...

  9. PYTHON黑帽编程1.5 使用WIRESHARK练习网络协议分析

    Python黑帽编程1.5  使用Wireshark练习网络协议分析 1.5.0.1  本系列教程说明 本系列教程,采用的大纲母本为<Understanding Network Hacks At ...

  10. TCP/IP协议分析

    一;前言 学习过TCP/IP协议的人多有一种感觉,这东西太抽象了,没有什么数据实例,看完不久就忘了.本文将介绍一种直观的学习方法,利用协议分析工具学习TCP/IP,在学习的过程中能直观的看到数据的具体 ...

最新文章

  1. 计算机与plc链接通信协议,实现上位计算机与PLC的上位链接系统的通信设计
  2. 以AI制作AI,当AutoML加入AI研究员内卷大潮
  3. git使用的详细过程
  4. 《kafka中文手册》-快速开始(二)
  5. LeetCode 783二叉搜索树节点最小距离-简单
  6. Iptables入门教程
  7. 玩转oracle 11g(6): oracle用户管理
  8. strlwr,strupr函数
  9. Java一个月学到springboot_Java基础学习路线之SpringBoot入门
  10. Eclipse中执行Tomcat源代码
  11. MySQL建表规范与常见问题
  12. 聊聊我所从事过的通信行业
  13. blender 常用快捷键
  14. PostgreSQL 9.1 选项standard_conforming_strings默认值为on
  15. python正则爬取微信阅读总榜单写入csv
  16. 国内计算机类三大中文学报投稿体会(转载)
  17. 从 Go log 库到 Zap,怎么打造出好用又实用的 Logger
  18. greenplum数据库的使用
  19. 从头开始写STM32F103C8T6驱动库(二)——编写系统初始化程序,配置时钟树
  20. 手机芯片里的NPU到底是什么?看完这篇终于懂了

热门文章

  1. c语言编程2的10次方,疯狂编程,计算2的10万次方
  2. 奥普泰安防监控智能配电箱——为安防行业添新助力
  3. STC8H开发(十二): I2C驱动AT24C08,AT24C32系列EEPROM存储
  4. 信息系统项目管理师(2022年) —— 第 11 章 项目风险管理
  5. 在Linux下使用GIMP打印一寸照
  6. VUE项目 高德地图使用热力图--实例
  7. Ucos操作系统任务优先级分配原则
  8. 郝斌老师 c语言学习笔记
  9. c语言符号字符集包括,c语言基本符号
  10. 【Modern Robotics】 Mechanics, Planning and Control现代机器人学:机构、规划与控制