cndroneid.cpp 40 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241
  1. /*
  2. Copyright (C) 2019 Intel Corporation
  3. SPDX-License-Identifier: Apache-2.0
  4. Open Drone ID C Library
  5. Maintainer:
  6. Gabriel Cox
  7. gabriel.c.cox@intel.com
  8. */
  9. /*看到最后发现,国标跟国际的区别:去掉认证 认证ID 系统里对保留的3bit用了2bit作为坐标系 其他完全一样*/
  10. #include "cndroneid.h"
  11. #include <math.h>
  12. #include <stdio.h>
  13. #define ENABLE_DEBUG 1
  14. const float CN_SPEED_DIV[2] = {0.25f, 0.75f};
  15. const float CN_VSPEED_DIV = 0.5f;
  16. const int32_t CN_LATLON_MULT = 10000000;
  17. const float CN_ALT_DIV = 0.5f;
  18. const int CN_ALT_ADDER = 1000;
  19. static char *safe_dec_copyfill(char *dstStr, const char *srcStr, int dstSize);
  20. static int intRangeMax(int64_t inValue, int startRange, int endRange);
  21. static int intInRange(int inValue, int startRange, int endRange);
  22. /**
  23. * Initialize basic ID data fields to their default values
  24. *
  25. * @param data (non encoded/packed) structure
  26. */
  27. void cndid_initBasicIDData(CNDID_BasicID_data *data)
  28. {
  29. if (!data)
  30. return;
  31. memset(data, 0, sizeof(CNDID_BasicID_data));
  32. }
  33. /**
  34. * Initialize location data fields to their default values
  35. *
  36. * @param data (non encoded/packed) structure
  37. */
  38. void cndid_initLocationData(CNDID_Location_data *data)
  39. {
  40. if (!data)
  41. return;
  42. memset(data, 0, sizeof(CNDID_Location_data));
  43. data->Direction = CN_INV_DIR;
  44. data->SpeedHorizontal = CN_INV_SPEED_H;
  45. data->SpeedVertical = CN_INV_SPEED_V;
  46. data->AltitudeBaro = CN_INV_ALT;
  47. data->AltitudeGeo = CN_INV_ALT;
  48. data->Height = CN_INV_ALT;
  49. }
  50. /**
  51. * Initialize self ID data fields to their default values
  52. *
  53. * @param data (non encoded/packed) structure
  54. */
  55. void cndid_initSelfIDData(CNDID_SelfID_data *data)
  56. {
  57. if (!data)
  58. return;
  59. memset(data, 0, sizeof(CNDID_SelfID_data));
  60. }
  61. /**
  62. * Initialize system data fields to their default values
  63. *
  64. * @param data (non encoded/packed) structure
  65. */
  66. void cndid_initSystemData(CNDID_System_data *data)
  67. {
  68. if (!data)
  69. return;
  70. memset(data, 0, sizeof(CNDID_System_data));
  71. data->AreaCount = 1;
  72. data->AreaCeiling = CN_INV_ALT;
  73. data->AreaFloor = CN_INV_ALT;
  74. data->OperatorAltitudeGeo = CN_INV_ALT;
  75. }
  76. /**
  77. * Initialize message pack data fields to their default values
  78. *
  79. * @param data (non encoded/packed) structure
  80. */
  81. void cndid_initMessagePackData(CNDID_MessagePack_data *data)
  82. {
  83. if (!data)
  84. return;
  85. memset(data, 0, sizeof(CNDID_MessagePack_data));
  86. data->SingleMessageSize = CNDID_MESSAGE_SIZE;
  87. }
  88. /**
  89. * Initialize UAS data fields to their default values
  90. *
  91. * @param data (non encoded/packed) structure
  92. */
  93. void cndid_initUasData(CNDID_UAS_Data *data)
  94. {
  95. if (!data)
  96. return;
  97. for (int i = 0; i < CNDID_BASIC_ID_MAX_MESSAGES; i++) {
  98. data->BasicIDValid[i] = 0;
  99. cndid_initBasicIDData(&data->BasicID[i]);
  100. }
  101. data->LocationValid = 0;
  102. cndid_initLocationData(&data->Location);
  103. data->SelfIDValid = 0;
  104. cndid_initSelfIDData(&data->SelfID);
  105. data->SystemValid = 0;
  106. cndid_initSystemData(&data->System);
  107. }
  108. /**
  109. * Encode direction as defined by Open Drone ID
  110. *
  111. * The encoding method uses 8 bits for the direction in degrees and
  112. * one extra bit for indicating the East/West direction.
  113. *
  114. * @param Direcction in degrees. 0 <= x < 360. Route course based on true North
  115. * @param EWDirection Bit flag indicating whether the direction is towards
  116. East (0 - 179 degrees) or West (180 - 359)
  117. * @return Encoded Direction in a single byte
  118. */
  119. static uint8_t encodeDirection(float Direction, uint8_t *EWDirection)
  120. {
  121. unsigned int direction_int = (unsigned int) roundf(Direction);
  122. if (direction_int < 180) {
  123. *EWDirection = 0;
  124. } else {
  125. *EWDirection = 1;
  126. direction_int -= 180;
  127. }
  128. return (uint8_t) intRangeMax(direction_int, 0, UINT8_MAX);
  129. }
  130. /**
  131. * Encode speed into units defined by Open Drone ID
  132. *
  133. * The quantization algorithm allows for speed to be stored in units of 0.25 m/s
  134. * on the low end of the scale and 0.75 m/s on the high end of the scale.
  135. * This allows for more precise speeds to be represented in a single Uint8 byte
  136. * rather than using a large float value.
  137. *
  138. * @param Speed_data Speed (and decimal) in m/s
  139. * @param mult a (write only) value that sets the multiplier flag
  140. * @return Encoded Speed in a single byte or max speed if over max encoded speed.
  141. */
  142. static uint8_t encodeSpeedHorizontal(float Speed_data, uint8_t *mult)
  143. {
  144. if (Speed_data <= UINT8_MAX * CN_SPEED_DIV[0]) {
  145. *mult = 0;
  146. return (uint8_t) (Speed_data / CN_SPEED_DIV[0]);
  147. } else {
  148. *mult = 1;
  149. int big_value = (int) ((Speed_data - (UINT8_MAX * CN_SPEED_DIV[0])) / CN_SPEED_DIV[1]);
  150. return (uint8_t) intRangeMax(big_value, 0, UINT8_MAX);
  151. }
  152. }
  153. /**
  154. * Encode Vertical Speed into a signed Integer CNDID format
  155. *
  156. * @param SpeedVertical_data vertical speed (in m/s)
  157. * @return Encoded vertical speed
  158. */
  159. static int8_t encodeSpeedVertical(float SpeedVertical_data)
  160. {
  161. int encValue = (int) (SpeedVertical_data / CN_VSPEED_DIV);
  162. return (int8_t) intRangeMax(encValue, INT8_MIN, INT8_MAX);
  163. }
  164. /**
  165. * Encode Latitude or Longitude value into a signed Integer CNDID format
  166. *
  167. * This encodes a 64bit double into a 32 bit integer yet still maintains
  168. * 10^7 of a degree of accuracy (about 1cm)
  169. *
  170. * @param LatLon_data Either Lat or Lon double float value
  171. * @return Encoded Lat or Lon
  172. */
  173. static int32_t encodeLatLon(double LatLon_data)
  174. {
  175. return (int32_t) intRangeMax((int64_t) (LatLon_data * CN_LATLON_MULT), -180 * CN_LATLON_MULT, 180 * CN_LATLON_MULT);
  176. }
  177. /**
  178. * Encode Altitude value into an int16 CNDID format
  179. *
  180. * This encodes a 32bit floating point altitude into an uint16 compressed
  181. * scale that starts at -1000m.
  182. *
  183. * @param Alt_data Altitude to encode (in meters)
  184. * @return Encoded Altitude
  185. */
  186. static uint16_t encodeAltitude(float Alt_data)
  187. {
  188. return (uint16_t) intRangeMax( (int) ((Alt_data + (float) CN_ALT_ADDER) / CN_ALT_DIV), 0, UINT16_MAX);
  189. }
  190. /**
  191. * Encode timestamp data in CNDID format
  192. *
  193. * This encodes a fractional seconds value into a 2 byte int16
  194. * on a scale of tenths of seconds since after the hour.
  195. *
  196. * @param Seconds_data Seconds (to at least 1 decimal place) since the hour
  197. * @return Encoded timestamp (Tenths of seconds since the hour)
  198. */
  199. static uint16_t encodeTimeStamp(float Seconds_data)
  200. {
  201. if (Seconds_data == CN_INV_TIMESTAMP)
  202. return CN_INV_TIMESTAMP;
  203. else
  204. return (uint16_t) intRangeMax((int64_t) roundf(Seconds_data*10), 0, CN_MAX_TIMESTAMP * 10);
  205. }
  206. /**
  207. * Encode area radius data in CNDID format
  208. *
  209. * This encodes the area radius in meters into a 1 byte value
  210. *
  211. * @param Radius The radius of the drone area/swarm
  212. * @return Encoded area radius
  213. */
  214. static uint8_t encodeAreaRadius(uint16_t Radius)
  215. {
  216. return (uint8_t) intRangeMax(Radius / 10, 0, 255);
  217. }
  218. /**
  219. * Encode Basic ID message (packed, ready for broadcast)
  220. *
  221. * @param outEncoded Output (encoded/packed) structure
  222. * @param inData Input data (non encoded/packed) structure
  223. * @return CNDID_SUCCESS or CNDID_FAIL;
  224. */
  225. int encodeCNBasicIDMessage(CNDID_BasicID_encoded *outEncoded, CNDID_BasicID_data *inData)
  226. {
  227. if (!outEncoded || !inData ||
  228. !intInRange(inData->IDType, 0, 15) ||
  229. !intInRange(inData->UAType, 0, 15))
  230. return CNDID_FAIL;
  231. outEncoded->MessageType = CNDID_MESSAGETYPE_BASIC_ID;
  232. outEncoded->ProtoVersion = CNDID_PROTOCOL_VERSION;
  233. outEncoded->IDType = inData->IDType;
  234. outEncoded->UAType = inData->UAType;
  235. strncpy(outEncoded->UASID, inData->UASID, sizeof(outEncoded->UASID));
  236. memset(outEncoded->Reserved, 0, sizeof(outEncoded->Reserved));
  237. return CNDID_SUCCESS;
  238. }
  239. /**
  240. * Encode Location message (packed, ready for broadcast)
  241. *
  242. * @param outEncoded Output (encoded/packed) structure
  243. * @param inData Input data (non encoded/packed) structure
  244. * @return CNDID_SUCCESS or CNDID_FAIL;
  245. */
  246. int encodeCNLocationMessage(CNDID_Location_encoded *outEncoded, CNDID_Location_data *inData)
  247. {
  248. uint8_t bitflag;
  249. if (!outEncoded || !inData ||
  250. !intInRange(inData->Status, 0, 15) ||
  251. !intInRange(inData->HeightType, 0, 1) ||
  252. !intInRange(inData->HorizAccuracy, 0, 15) ||
  253. !intInRange(inData->VertAccuracy, 0, 15) ||
  254. !intInRange(inData->BaroAccuracy, 0, 15) ||
  255. !intInRange(inData->SpeedAccuracy, 0, 15) ||
  256. !intInRange(inData->TSAccuracy, 0, 15))
  257. return CNDID_FAIL;
  258. if (inData->Direction < CN_MIN_DIR || inData->Direction > CN_INV_DIR ||
  259. (inData->Direction > CN_MAX_DIR && inData->Direction < CN_INV_DIR))
  260. return CNDID_FAIL;
  261. if (inData->SpeedHorizontal < CN_MIN_SPEED_H || inData->SpeedHorizontal > CN_INV_SPEED_H ||
  262. (inData->SpeedHorizontal > CN_MAX_SPEED_H && inData->SpeedHorizontal < CN_INV_SPEED_H))
  263. return CNDID_FAIL;
  264. if (inData->SpeedVertical < CN_MIN_SPEED_V || inData->SpeedVertical > CN_INV_SPEED_V ||
  265. (inData->SpeedVertical > CN_MAX_SPEED_V && inData->SpeedVertical < CN_INV_SPEED_V))
  266. return CNDID_FAIL;
  267. if (inData->Latitude < CN_MIN_LAT || inData->Latitude > CN_MAX_LAT ||
  268. inData->Longitude < CN_MIN_LON || inData->Longitude > CN_MAX_LON)
  269. return CNDID_FAIL;
  270. if (inData->AltitudeBaro < CN_MIN_ALT || inData->AltitudeBaro > CN_MAX_ALT ||
  271. inData->AltitudeGeo < CN_MIN_ALT || inData->AltitudeGeo > CN_MAX_ALT ||
  272. inData->Height < CN_MIN_ALT || inData->Height > CN_MAX_ALT)
  273. return CNDID_FAIL;
  274. if (inData->TimeStamp < 0 ||
  275. (inData->TimeStamp > CN_MAX_TIMESTAMP && inData->TimeStamp != CN_INV_TIMESTAMP))
  276. return CNDID_FAIL;
  277. outEncoded->MessageType = CNDID_MESSAGETYPE_LOCATION;
  278. outEncoded->ProtoVersion = CNDID_PROTOCOL_VERSION;
  279. outEncoded->Status = inData->Status;
  280. outEncoded->Reserved = 0;
  281. outEncoded->Direction = encodeDirection(inData->Direction, &bitflag);
  282. outEncoded->EWDirection = bitflag;
  283. outEncoded->SpeedHorizontal = encodeSpeedHorizontal(inData->SpeedHorizontal, &bitflag);
  284. outEncoded->SpeedMult = bitflag;
  285. outEncoded->SpeedVertical = encodeSpeedVertical(inData->SpeedVertical);
  286. outEncoded->Latitude = encodeLatLon(inData->Latitude);
  287. outEncoded->Longitude = encodeLatLon(inData->Longitude);
  288. outEncoded->AltitudeBaro = encodeAltitude(inData->AltitudeBaro);
  289. outEncoded->AltitudeGeo = encodeAltitude(inData->AltitudeGeo);
  290. outEncoded->HeightType = inData->HeightType;
  291. outEncoded->Height = encodeAltitude(inData->Height);
  292. outEncoded->HorizAccuracy = inData->HorizAccuracy;
  293. outEncoded->VertAccuracy = inData->VertAccuracy;
  294. outEncoded->BaroAccuracy = inData->BaroAccuracy;
  295. outEncoded->SpeedAccuracy = inData->SpeedAccuracy;
  296. outEncoded->TSAccuracy = inData->TSAccuracy;
  297. outEncoded->Reserved2 = 0;
  298. outEncoded->TimeStamp = encodeTimeStamp(inData->TimeStamp);
  299. outEncoded->Reserved3 = 0;
  300. return CNDID_SUCCESS;
  301. }
  302. /**
  303. * Encode Self ID message (packed, ready for broadcast)
  304. *
  305. * @param outEncoded Output (encoded/packed) structure
  306. * @param inData Input data (non encoded/packed) structure
  307. * @return CNDID_SUCCESS or CNDID_FAIL;
  308. */
  309. int encodeCNSelfIDMessage(CNDID_SelfID_encoded *outEncoded, CNDID_SelfID_data *inData)
  310. {
  311. if (!outEncoded || !inData || !intInRange(inData->DescType, 0, 255))
  312. return CNDID_FAIL;
  313. outEncoded->MessageType = CNDID_MESSAGETYPE_SELF_ID;
  314. outEncoded->ProtoVersion = CNDID_PROTOCOL_VERSION;
  315. outEncoded->DescType = inData->DescType;
  316. strncpy(outEncoded->Desc, inData->Desc, sizeof(outEncoded->Desc));
  317. return CNDID_SUCCESS;
  318. }
  319. /**
  320. * Encode System message (packed, ready for broadcast)
  321. *
  322. * @param outEncoded Output (encoded/packed) structure
  323. * @param inData Input data (non encoded/packed) structure
  324. * @return CNDID_SUCCESS or CNDID_FAIL;
  325. */
  326. int encodeCNSystemMessage(CNDID_System_encoded *outEncoded, CNDID_System_data *inData)
  327. {
  328. if (!outEncoded || !inData ||
  329. !intInRange(inData->OperatorLocationType, 0, 3) ||
  330. !intInRange(inData->Classification_Type, 0, 7) ||
  331. !intInRange(inData->CategoryCN, 0, 15) ||
  332. !intInRange(inData->ClassCN, 0, 15)||
  333. !intInRange(inData->Coord_Type,0, 3)) // 坐标系类型
  334. return CNDID_FAIL;
  335. if (inData->OperatorLatitude < CN_MIN_LAT || inData->OperatorLatitude > CN_MAX_LAT ||
  336. inData->OperatorLongitude < CN_MIN_LON || inData->OperatorLongitude > CN_MAX_LON)
  337. return CNDID_FAIL;
  338. if (inData->AreaRadius > CN_MAX_AREA_RADIUS)
  339. return CNDID_FAIL;
  340. if (inData->AreaCeiling < CN_MIN_ALT || inData->AreaCeiling > CN_MAX_ALT ||
  341. inData->AreaFloor < CN_MIN_ALT || inData->AreaFloor > CN_MAX_ALT ||
  342. inData->OperatorAltitudeGeo < CN_MIN_ALT || inData->OperatorAltitudeGeo > CN_MAX_ALT)
  343. return CNDID_FAIL;
  344. outEncoded->MessageType = CNDID_MESSAGETYPE_SYSTEM;
  345. outEncoded->ProtoVersion = CNDID_PROTOCOL_VERSION;
  346. outEncoded->Reserved = 0;
  347. outEncoded->CoordType = inData->Coord_Type;
  348. outEncoded->OperatorLocationType = inData->OperatorLocationType;
  349. outEncoded->ClassificationType = inData->Classification_Type;
  350. outEncoded->OperatorLatitude = encodeLatLon(inData->OperatorLatitude);
  351. outEncoded->OperatorLongitude = encodeLatLon(inData->OperatorLongitude);
  352. outEncoded->AreaCount = inData->AreaCount;
  353. outEncoded->AreaRadius = encodeAreaRadius(inData->AreaRadius);
  354. outEncoded->AreaCeiling = encodeAltitude(inData->AreaCeiling);
  355. outEncoded->AreaFloor = encodeAltitude(inData->AreaFloor);
  356. outEncoded->CategoryCN = inData->CategoryCN;
  357. outEncoded->ClassCN = inData->ClassCN;
  358. outEncoded->OperatorAltitudeGeo = encodeAltitude(inData->OperatorAltitudeGeo);
  359. outEncoded->Timestamp = inData->Timestamp;
  360. outEncoded->Reserved2 = 0;
  361. return CNDID_SUCCESS;
  362. }
  363. /**
  364. * 检查数据包结构的数据字段是否有效
  365. *
  366. * @param msgs 指向包含消息的缓冲区的指针
  367. * @param amount 数据包中的消息数量
  368. * @return CNDID_SUCCESS 或 CNDID_FAIL;
  369. */
  370. static int checkPackContent(CNDID_Message_encoded *msgs, int amount)
  371. {
  372. if (amount <= 0 || amount > CNDID_PACK_MAX_MESSAGES)
  373. return CNDID_FAIL;
  374. int numMessages[4] = { 0 }; // CNDID_messagetype_t相关部分的计数器
  375. for (int i = 0; i < amount; i++) {
  376. uint8_t MessageType = decodeCNMessageType(msgs[i].rawData[0]);
  377. // 检查非法内容。这也避免了之间的递归调用
  378. // decodeOpenDroneID()以及decodeMessagePack()/checkPackContent()
  379. if (MessageType <= CNDID_MESSAGETYPE_SYSTEM) // 对待发送组包消息进行格式检查 最后一条消息就是系统报文
  380. numMessages[MessageType]++;
  381. else
  382. return CNDID_FAIL;
  383. }
  384. // 除基本ID和授权外,每条消息最多允许出现一次。
  385. if (numMessages[CNDID_MESSAGETYPE_BASIC_ID] > CNDID_BASIC_ID_MAX_MESSAGES ||
  386. numMessages[CNDID_MESSAGETYPE_LOCATION] > 1 ||
  387. numMessages[CNDID_MESSAGETYPE_SELF_ID] > 1 ||
  388. numMessages[CNDID_MESSAGETYPE_SYSTEM] > 1 )
  389. return CNDID_FAIL;
  390. return CNDID_SUCCESS;
  391. }
  392. /**
  393. * Encode message pack. I.e. a collection of multiple encoded messages
  394. *
  395. * @param outEncoded Output (encoded/packed) structure
  396. * @param inData Input data (non encoded/packed) structure
  397. * @return CNDID_SUCCESS or CNDID_FAIL;
  398. */
  399. int encodeCNMessagePack(CNDID_MessagePack_encoded *outEncoded, CNDID_MessagePack_data *inData)
  400. {
  401. if (!outEncoded || !inData || inData->SingleMessageSize != CNDID_MESSAGE_SIZE)
  402. return CNDID_FAIL;
  403. if (checkPackContent(inData->Messages, inData->MsgPackSize) != CNDID_SUCCESS)
  404. return CNDID_FAIL;
  405. outEncoded->MessageType = CNDID_MESSAGETYPE_PACKED;
  406. outEncoded->ProtoVersion = CNDID_PROTOCOL_VERSION;
  407. outEncoded->SingleMessageSize = inData->SingleMessageSize;
  408. outEncoded->MsgPackSize = inData->MsgPackSize;
  409. for (int i = 0; i < inData->MsgPackSize; i++)
  410. memcpy(&outEncoded->Messages[i], &inData->Messages[i], CNDID_MESSAGE_SIZE);
  411. return CNDID_SUCCESS;
  412. }
  413. /**
  414. * Dencode direction from Open Drone ID packed message
  415. *
  416. * @param Direction_enc encoded direction
  417. * @param EWDirection East/West direction flag
  418. * @return direction in degrees (0 - 359)
  419. */
  420. static float decodeDirection(uint8_t Direction_enc, uint8_t EWDirection)
  421. {
  422. if (EWDirection)
  423. return (float) Direction_enc + 180;
  424. else
  425. return (float) Direction_enc;
  426. }
  427. /**
  428. * Dencode speed from Open Drone ID packed message
  429. *
  430. * @param Speed_enc encoded speed
  431. * @param mult multiplier flag
  432. * @return decoded speed in m/s
  433. */
  434. static float decodeSpeedHorizontal(uint8_t Speed_enc, uint8_t mult)
  435. {
  436. if (mult)
  437. return ((float) Speed_enc * CN_SPEED_DIV[1]) + (UINT8_MAX * CN_SPEED_DIV[0]);
  438. else
  439. return (float) Speed_enc * CN_SPEED_DIV[0];
  440. }
  441. /**
  442. * Decode Vertical Speed from Open Drone ID Packed Message
  443. *
  444. * @param SpeedVertical_enc Encoded Vertical Speed
  445. * @return decoded Vertical Speed in m/s
  446. */
  447. static float decodeSpeedVertical(int8_t SpeedVertical_enc)
  448. {
  449. return (float) SpeedVertical_enc * CN_VSPEED_DIV;
  450. }
  451. /**
  452. * Decode Latitude or Longitude value into a signed Integer CNDID format
  453. *
  454. * @param LatLon_enc Either Lat or Lon ecoded int value
  455. * @return decoded (double) Lat or Lon
  456. */
  457. static double decodeLatLon(int32_t LatLon_enc)
  458. {
  459. return (double) LatLon_enc / CN_LATLON_MULT;
  460. }
  461. /**
  462. * Decode Altitude from CNDID packed format
  463. *
  464. * @param Alt_enc Encoded Altitude to decode
  465. * @return decoded Altitude (in meters)
  466. */
  467. static float decodeAltitude(uint16_t Alt_enc)
  468. {
  469. return (float) Alt_enc * CN_ALT_DIV - (float) CN_ALT_ADDER;
  470. }
  471. /**
  472. * Decode timestamp data from CNDID packed format
  473. *
  474. * @param Seconds_enc Encoded Timestamp
  475. * @return Decoded timestamp (seconds since the hour)
  476. */
  477. static float decodeTimeStamp(uint16_t Seconds_enc)
  478. {
  479. if (Seconds_enc == CN_INV_TIMESTAMP)
  480. return CN_INV_TIMESTAMP;
  481. else
  482. return (float) Seconds_enc / 10;
  483. }
  484. /**
  485. * Decode area radius data from CNDID format
  486. *
  487. * This decodes a 1 byte value to the area radius in meters
  488. *
  489. * @param Radius_enc Encoded area radius
  490. * @return The radius of the drone area/swarm in meters
  491. */
  492. static uint16_t decodeAreaRadius(uint8_t Radius_enc)
  493. {
  494. return (uint16_t) ((int) Radius_enc * 10);
  495. }
  496. /**
  497. * Get the ID type of the basic ID message
  498. *
  499. * @param inEncoded Input message (encoded/packed) structure
  500. * @param idType Output: The ID type of this basic ID message
  501. * @return CNDID_SUCCESS or CNDID_FAIL;
  502. */
  503. int getCNBasicIDType(CNDID_BasicID_encoded *inEncoded, enum CNDID_idtype *idType)
  504. {
  505. if (!inEncoded || !idType || inEncoded->MessageType != CNDID_MESSAGETYPE_BASIC_ID)
  506. return CNDID_FAIL;
  507. *idType = (enum CNDID_idtype) inEncoded->IDType;
  508. return CNDID_SUCCESS;
  509. }
  510. /**
  511. * 从打包消息中解码基本ID数据
  512. *
  513. * @param outData 输出:解码后的消息
  514. * @param inEncoded 输入消息(已编码/打包)结构
  515. * @return CNDID_SUCCESS 或 CNDID_FAIL;
  516. */
  517. int decodeCNBasicIDMessage(CNDID_BasicID_data *outData, CNDID_BasicID_encoded *inEncoded)
  518. {
  519. if (!outData || !inEncoded ||
  520. inEncoded->MessageType != CNDID_MESSAGETYPE_BASIC_ID ||
  521. !intInRange(inEncoded->IDType, 0, 15) ||
  522. !intInRange(inEncoded->UAType, 0, 15))
  523. return CNDID_FAIL;
  524. outData->IDType = (CNDID_IDType_t) inEncoded->IDType;
  525. outData->UAType = (CNDID_UAType_t) inEncoded->UAType;
  526. safe_dec_copyfill(outData->UASID, inEncoded->UASID, sizeof(outData->UASID));
  527. return CNDID_SUCCESS;
  528. }
  529. /**
  530. * Decode Location data from packed message
  531. *
  532. * @param outData Output: decoded message
  533. * @param inEncoded Input message (encoded/packed) structure
  534. * @return CNDID_SUCCESS or CNDID_FAIL;
  535. */
  536. int decodeCNLocationMessage(CNDID_Location_data *outData, CNDID_Location_encoded *inEncoded)
  537. {
  538. if (!outData || !inEncoded ||
  539. inEncoded->MessageType != CNDID_MESSAGETYPE_LOCATION ||
  540. !intInRange(inEncoded->Status, 0, 15))
  541. return CNDID_FAIL;
  542. outData->Status = (CNDID_Status_t) inEncoded->Status;
  543. outData->Direction = decodeDirection(inEncoded->Direction, inEncoded-> EWDirection);
  544. outData->SpeedHorizontal = decodeSpeedHorizontal(inEncoded->SpeedHorizontal, inEncoded->SpeedMult);
  545. outData->SpeedVertical = decodeSpeedVertical(inEncoded->SpeedVertical);
  546. outData->Latitude = decodeLatLon(inEncoded->Latitude);
  547. outData->Longitude = decodeLatLon(inEncoded->Longitude);
  548. outData->AltitudeBaro = decodeAltitude(inEncoded->AltitudeBaro);
  549. outData->AltitudeGeo = decodeAltitude(inEncoded->AltitudeGeo);
  550. outData->HeightType = (CNDID_HeightReference_t) inEncoded->HeightType;
  551. outData->Height = decodeAltitude(inEncoded->Height);
  552. outData->HorizAccuracy = (CNDID_HorizontalAccuracy_t) inEncoded->HorizAccuracy;
  553. outData->VertAccuracy = (CNDID_VerticalAccuracy_t) inEncoded->VertAccuracy;
  554. outData->BaroAccuracy = (CNDID_VerticalAccuracy_t) inEncoded->BaroAccuracy;
  555. outData->SpeedAccuracy = (CNDID_SpeedAccuracy_t) inEncoded->SpeedAccuracy;
  556. outData->TSAccuracy = (CNDID_TimeStampAccuracy_t) inEncoded->TSAccuracy;
  557. outData->TimeStamp = decodeTimeStamp(inEncoded->TimeStamp);
  558. return CNDID_SUCCESS;
  559. }
  560. /**
  561. * Decode Self ID data from packed message
  562. *
  563. * @param outData Output: decoded message
  564. * @param inEncoded Input message (encoded/packed) structure
  565. * @return CNDID_SUCCESS or CNDID_FAIL;
  566. */
  567. int decodeCNSelfIDMessage(CNDID_SelfID_data *outData, CNDID_SelfID_encoded *inEncoded)
  568. {
  569. if (!outData || !inEncoded ||
  570. inEncoded->MessageType != CNDID_MESSAGETYPE_SELF_ID)
  571. return CNDID_FAIL;
  572. outData->DescType = (CNDID_DescType_t) inEncoded->DescType;
  573. safe_dec_copyfill(outData->Desc, inEncoded->Desc, sizeof(outData->Desc));
  574. return CNDID_SUCCESS;
  575. }
  576. /**
  577. * Decode System data from packed message
  578. *
  579. * @param outData Output: decoded message
  580. * @param inEncoded Input message (encoded/packed) structure
  581. * @return CNDID_SUCCESS or CNDID_FAIL;
  582. */
  583. int decodeCNSystemMessage(CNDID_System_data *outData, CNDID_System_encoded *inEncoded)
  584. {
  585. if (!outData || !inEncoded ||
  586. inEncoded->MessageType != CNDID_MESSAGETYPE_SYSTEM)
  587. return CNDID_FAIL;
  588. outData->OperatorLocationType =
  589. (CNDID_operator_location_type_t) inEncoded->OperatorLocationType;
  590. outData->Classification_Type =
  591. (CNDID_classification_type_t) inEncoded->ClassificationType;
  592. outData->Coord_Type =
  593. (CNDID_CoordType_t) inEncoded->CoordType;
  594. outData->OperatorLatitude = decodeLatLon(inEncoded->OperatorLatitude);
  595. outData->OperatorLongitude = decodeLatLon(inEncoded->OperatorLongitude);
  596. outData->AreaCount = inEncoded->AreaCount;
  597. outData->AreaRadius = decodeAreaRadius(inEncoded->AreaRadius);
  598. outData->AreaCeiling = decodeAltitude(inEncoded->AreaCeiling);
  599. outData->AreaFloor = decodeAltitude(inEncoded->AreaFloor);
  600. outData->CategoryCN = (CNDID_category_CN_t) inEncoded->CategoryCN;
  601. outData->ClassCN = (CNDID_class_CN_t) inEncoded->ClassCN;
  602. outData->OperatorAltitudeGeo = decodeAltitude(inEncoded->OperatorAltitudeGeo);
  603. outData->Timestamp = inEncoded->Timestamp;
  604. return CNDID_SUCCESS;
  605. }
  606. /**
  607. * Decode Message Pack from packed message
  608. *
  609. * The various Valid flags in uasData are set true whenever a message has been
  610. * decoded and the corresponding data structure has been filled. The caller must
  611. * clear these flags before calling decodeMessagePack().
  612. *
  613. * @param uasData Output: Structure containing buffers for all message data
  614. * @param pack Pointer to an encoded packed message
  615. * @return CNDID_SUCCESS or CNDID_FAIL;
  616. */
  617. int decodeCNMessagePack(CNDID_UAS_Data *uasData, CNDID_MessagePack_encoded *pack)
  618. {
  619. if (!uasData || !pack || pack->MessageType != CNDID_MESSAGETYPE_PACKED)
  620. return CNDID_FAIL;
  621. if (pack->SingleMessageSize != CNDID_MESSAGE_SIZE)
  622. return CNDID_FAIL;
  623. if (checkPackContent(pack->Messages, pack->MsgPackSize) != CNDID_SUCCESS)
  624. return CNDID_FAIL;
  625. for (int i = 0; i < pack->MsgPackSize; i++) {
  626. decodeCNDroneID(uasData, pack->Messages[i].rawData);
  627. }
  628. return CNDID_SUCCESS;
  629. }
  630. /**
  631. * Decodes the message type of a packed Open Drone ID message
  632. *
  633. * @param byte The first byte of the message
  634. * @return The message type: CNDID_messagetype_t
  635. */
  636. CNDID_MessageType_t decodeCNMessageType(uint8_t byte)
  637. {
  638. switch (byte >> 4)
  639. {
  640. case CNDID_MESSAGETYPE_BASIC_ID:
  641. return CNDID_MESSAGETYPE_BASIC_ID;
  642. case CNDID_MESSAGETYPE_LOCATION:
  643. return CNDID_MESSAGETYPE_LOCATION;
  644. case CNDID_MESSAGETYPE_SELF_ID:
  645. return CNDID_MESSAGETYPE_SELF_ID;
  646. case CNDID_MESSAGETYPE_SYSTEM:
  647. return CNDID_MESSAGETYPE_SYSTEM;
  648. case CNDID_MESSAGETYPE_PACKED:
  649. return CNDID_MESSAGETYPE_PACKED;
  650. default:
  651. return CNDID_MESSAGETYPE_INVALID;
  652. }
  653. }
  654. /**
  655. * Parse encoded Open Drone ID data to identify the message type. Then decode
  656. * from Open Drone ID packed format into the appropriate Open Drone ID structure
  657. *
  658. * This function assumes that msgData points to a buffer containing all
  659. * CNDID_MESSAGE_SIZE bytes of an Open Drone ID message.
  660. *
  661. * The various Valid flags in uasData are set true whenever a message has been
  662. * decoded and the corresponding data structure has been filled. The caller must
  663. * clear these flags before calling decodeOpenDroneID().
  664. *
  665. * @param uasData Structure containing buffers for all message data
  666. * @param msgData Pointer to a buffer containing a full encoded Open Drone ID
  667. * message
  668. * @return The message type: CNDID_messagetype_t
  669. */
  670. CNDID_MessageType_t decodeCNDroneID(CNDID_UAS_Data *uasData, uint8_t *msgData)
  671. {
  672. if (!uasData || !msgData)
  673. return CNDID_MESSAGETYPE_INVALID;
  674. switch (decodeCNMessageType(msgData[0]))
  675. {
  676. case CNDID_MESSAGETYPE_BASIC_ID: {
  677. CNDID_BasicID_encoded *basicId = (CNDID_BasicID_encoded *) msgData;
  678. enum CNDID_idtype idType;
  679. if (getCNBasicIDType(basicId, &idType) == CNDID_SUCCESS) {
  680. // 找到一个空闲位置来存储当前消息,或者覆盖相同类型的旧数据。
  681. for (int i = 0; i < CNDID_BASIC_ID_MAX_MESSAGES; i++) {
  682. enum CNDID_idtype storedType = uasData->BasicID[i].IDType;
  683. if (storedType == CNDID_IDTYPE_NONE || storedType == idType) {
  684. if (decodeCNBasicIDMessage(&uasData->BasicID[i], basicId) == CNDID_SUCCESS) {
  685. uasData->BasicIDValid[i] = 1; // 重复ID ID非法
  686. return CNDID_MESSAGETYPE_BASIC_ID;
  687. }
  688. }
  689. }
  690. }
  691. break;
  692. }
  693. case CNDID_MESSAGETYPE_LOCATION: {
  694. CNDID_Location_encoded *location = (CNDID_Location_encoded *) msgData;
  695. if (decodeCNLocationMessage(&uasData->Location, location) == CNDID_SUCCESS) {
  696. uasData->LocationValid = 1;
  697. return CNDID_MESSAGETYPE_LOCATION;
  698. }
  699. break;
  700. }
  701. case CNDID_MESSAGETYPE_SELF_ID: {
  702. CNDID_SelfID_encoded *selfId = (CNDID_SelfID_encoded *) msgData;
  703. if (decodeCNSelfIDMessage(&uasData->SelfID, selfId) == CNDID_SUCCESS) {
  704. uasData->SelfIDValid = 1;
  705. return CNDID_MESSAGETYPE_SELF_ID;
  706. }
  707. break;
  708. }
  709. case CNDID_MESSAGETYPE_SYSTEM: {
  710. CNDID_System_encoded *system = (CNDID_System_encoded *) msgData;
  711. if (decodeCNSystemMessage(&uasData->System, system) == CNDID_SUCCESS) {
  712. uasData->SystemValid = 1;
  713. return CNDID_MESSAGETYPE_SYSTEM;
  714. }
  715. break;
  716. }
  717. case CNDID_MESSAGETYPE_PACKED: {
  718. CNDID_MessagePack_encoded *pack = (CNDID_MessagePack_encoded *) msgData;
  719. if (decodeCNMessagePack(uasData, pack) == CNDID_SUCCESS)
  720. return CNDID_MESSAGETYPE_PACKED;
  721. break;
  722. }
  723. default:
  724. break;
  725. }
  726. return CNDID_MESSAGETYPE_INVALID;
  727. }
  728. /**
  729. * Safely fill then copy string to destination (when decoding)
  730. *
  731. * This prevents overrun and guarantees copy behavior (fully null padded)
  732. * This function was specially made because the encoded data may not be null
  733. * terminated (if full size).
  734. * Therefore, the destination must use the last byte for a null (and is +1 in size)
  735. *
  736. * @param dstStr Destination string
  737. * @param srcStr Source string
  738. * @param dstSize Destination size
  739. */
  740. static char *safe_dec_copyfill(char *dstStr, const char *srcStr, int dstSize)
  741. {
  742. memset(dstStr, 0, dstSize); // fills destination with nulls
  743. strncpy(dstStr, srcStr, dstSize-1); // copy only up to dst size-1 (no overruns)
  744. return dstStr;
  745. }
  746. /**
  747. * Safely range check a value and return the minimum or max within the range if exceeded
  748. *
  749. * @param inValue Value to range-check
  750. * @param startRange Start of range to compare
  751. * @param endRange End of range to compare
  752. * @return same value if it fits, otherwise, min or max of range as appropriate.
  753. */
  754. static int intRangeMax(int64_t inValue, int startRange, int endRange) {
  755. if ( inValue < startRange ) {
  756. return startRange;
  757. } else if (inValue > endRange) {
  758. return endRange;
  759. } else {
  760. return (int) inValue;
  761. }
  762. }
  763. /**
  764. * Determine if an Int is in range
  765. *
  766. * @param inValue Value to range-check
  767. * @param startRange Start of range to compare
  768. * @param endRange End of range to compare
  769. * @return 1 = yes, 0 = no
  770. */
  771. static int intInRange(int inValue, int startRange, int endRange)
  772. {
  773. if (inValue < startRange || inValue > endRange) {
  774. return 0;
  775. } else {
  776. return 1;
  777. }
  778. }
  779. /**
  780. * This converts a horizontal accuracy float value to the corresponding enum
  781. *
  782. * @param Accuracy The horizontal accuracy in meters
  783. * @return Enum value representing the accuracy
  784. */
  785. CNDID_HorizontalAccuracy_t createCNEnumHorizontalAccuracy(float Accuracy)
  786. {
  787. if (Accuracy >= 18520)
  788. return CNDID_HOR_ACC_UNKNOWN;
  789. else if (Accuracy >= 7408)
  790. return CNDID_HOR_ACC_10NM;
  791. else if (Accuracy >= 3704)
  792. return CNDID_HOR_ACC_4NM;
  793. else if (Accuracy >= 1852)
  794. return CNDID_HOR_ACC_2NM;
  795. else if (Accuracy >= 926)
  796. return CNDID_HOR_ACC_1NM;
  797. else if (Accuracy >= 555.6f)
  798. return CNDID_HOR_ACC_0_5NM;
  799. else if (Accuracy >= 185.2f)
  800. return CNDID_HOR_ACC_0_3NM;
  801. else if (Accuracy >= 92.6f)
  802. return CNDID_HOR_ACC_0_1NM;
  803. else if (Accuracy >= 30)
  804. return CNDID_HOR_ACC_0_05NM;
  805. else if (Accuracy >= 10)
  806. return CNDID_HOR_ACC_30_METER;
  807. else if (Accuracy >= 3)
  808. return CNDID_HOR_ACC_10_METER;
  809. else if (Accuracy >= 1)
  810. return CNDID_HOR_ACC_3_METER;
  811. else if (Accuracy > 0)
  812. return CNDID_HOR_ACC_1_METER;
  813. else
  814. return CNDID_HOR_ACC_UNKNOWN;
  815. }
  816. /**
  817. * This converts a vertical accuracy float value to the corresponding enum
  818. *
  819. * @param Accuracy The vertical accuracy in meters
  820. * @return Enum value representing the accuracy
  821. */
  822. CNDID_VerticalAccuracy_t createCNEnumVerticalAccuracy(float Accuracy)
  823. {
  824. if (Accuracy >= 150)
  825. return CNDID_VER_ACC_UNKNOWN;
  826. else if (Accuracy >= 45)
  827. return CNDID_VER_ACC_150_METER;
  828. else if (Accuracy >= 25)
  829. return CNDID_VER_ACC_45_METER;
  830. else if (Accuracy >= 10)
  831. return CNDID_VER_ACC_25_METER;
  832. else if (Accuracy >= 3)
  833. return CNDID_VER_ACC_10_METER;
  834. else if (Accuracy >= 1)
  835. return CNDID_VER_ACC_3_METER;
  836. else if (Accuracy > 0)
  837. return CNDID_VER_ACC_1_METER;
  838. else
  839. return CNDID_VER_ACC_UNKNOWN;
  840. }
  841. /**
  842. * This converts a speed accuracy float value to the corresponding enum
  843. *
  844. * @param Accuracy The speed accuracy in m/s
  845. * @return Enum value representing the accuracy
  846. */
  847. CNDID_SpeedAccuracy_t createCNEnumSpeedAccuracy(float Accuracy)
  848. {
  849. if (Accuracy >= 10)
  850. return CNDID_SPEED_ACC_UNKNOWN;
  851. else if (Accuracy >= 3)
  852. return CNDID_SPEED_ACC_10_METERS_PER_SECOND;
  853. else if (Accuracy >= 1)
  854. return CNDID_SPEED_ACC_3_METERS_PER_SECOND;
  855. else if (Accuracy >= 0.3f)
  856. return CNDID_SPEED_ACC_1_METERS_PER_SECOND;
  857. else if (Accuracy > 0)
  858. return CNDID_SPEED_ACC_0_3_METERS_PER_SECOND;
  859. else
  860. return CNDID_SPEED_ACC_UNKNOWN;
  861. }
  862. /**
  863. * This converts a timestamp accuracy float value to the corresponding enum
  864. *
  865. * @param Accuracy The timestamp accuracy in seconds
  866. * @return Enum value representing the accuracy
  867. */
  868. CNDID_TimeStampAccuracy_t createCNEnumTimestampAccuracy(float Accuracy)
  869. {
  870. if (Accuracy > 1.5f)
  871. return CNDID_TIME_ACC_UNKNOWN;
  872. else if (Accuracy > 1.4f)
  873. return CNDID_TIME_ACC_1_5_SECOND;
  874. else if (Accuracy > 1.3f)
  875. return CNDID_TIME_ACC_1_4_SECOND;
  876. else if (Accuracy > 1.2f)
  877. return CNDID_TIME_ACC_1_3_SECOND;
  878. else if (Accuracy > 1.1f)
  879. return CNDID_TIME_ACC_1_2_SECOND;
  880. else if (Accuracy > 1.0f)
  881. return CNDID_TIME_ACC_1_1_SECOND;
  882. else if (Accuracy > 0.9f)
  883. return CNDID_TIME_ACC_1_0_SECOND;
  884. else if (Accuracy > 0.8f)
  885. return CNDID_TIME_ACC_0_9_SECOND;
  886. else if (Accuracy > 0.7f)
  887. return CNDID_TIME_ACC_0_8_SECOND;
  888. else if (Accuracy > 0.6f)
  889. return CNDID_TIME_ACC_0_7_SECOND;
  890. else if (Accuracy > 0.5f)
  891. return CNDID_TIME_ACC_0_6_SECOND;
  892. else if (Accuracy > 0.4f)
  893. return CNDID_TIME_ACC_0_5_SECOND;
  894. else if (Accuracy > 0.3f)
  895. return CNDID_TIME_ACC_0_4_SECOND;
  896. else if (Accuracy > 0.2f)
  897. return CNDID_TIME_ACC_0_3_SECOND;
  898. else if (Accuracy > 0.1f)
  899. return CNDID_TIME_ACC_0_2_SECOND;
  900. else if (Accuracy > 0.0f)
  901. return CNDID_TIME_ACC_0_1_SECOND;
  902. else
  903. return CNDID_TIME_ACC_UNKNOWN;
  904. }
  905. /**
  906. * This decodes a horizontal accuracy enum to the corresponding float value
  907. *
  908. * @param Accuracy Enum value representing the accuracy
  909. * @return The maximum horizontal accuracy in meters
  910. */
  911. float decodeCNHorizontalAccuracy(CNDID_HorizontalAccuracy_t Accuracy)
  912. {
  913. switch (Accuracy)
  914. {
  915. case CNDID_HOR_ACC_UNKNOWN:
  916. return 18520;
  917. case CNDID_HOR_ACC_10NM:
  918. return 18520;
  919. case CNDID_HOR_ACC_4NM:
  920. return 7808;
  921. case CNDID_HOR_ACC_2NM:
  922. return 3704;
  923. case CNDID_HOR_ACC_1NM:
  924. return 1852;
  925. case CNDID_HOR_ACC_0_5NM:
  926. return 926;
  927. case CNDID_HOR_ACC_0_3NM:
  928. return 555.6f;
  929. case CNDID_HOR_ACC_0_1NM:
  930. return 185.2f;
  931. case CNDID_HOR_ACC_0_05NM:
  932. return 92.6f;
  933. case CNDID_HOR_ACC_30_METER:
  934. return 30;
  935. case CNDID_HOR_ACC_10_METER:
  936. return 10;
  937. case CNDID_HOR_ACC_3_METER:
  938. return 3;
  939. case CNDID_HOR_ACC_1_METER:
  940. return 1;
  941. default:
  942. return 18520;
  943. }
  944. }
  945. /**
  946. * This decodes a vertical accuracy enum to the corresponding float value
  947. *
  948. * @param Accuracy Enum value representing the accuracy
  949. * @return The maximum vertical accuracy in meters
  950. */
  951. float decodeCNVerticalAccuracy(CNDID_VerticalAccuracy_t Accuracy)
  952. {
  953. switch (Accuracy)
  954. {
  955. case CNDID_VER_ACC_UNKNOWN:
  956. return 150;
  957. case CNDID_VER_ACC_150_METER:
  958. return 150;
  959. case CNDID_VER_ACC_45_METER:
  960. return 45;
  961. case CNDID_VER_ACC_25_METER:
  962. return 25;
  963. case CNDID_VER_ACC_10_METER:
  964. return 10;
  965. case CNDID_VER_ACC_3_METER:
  966. return 3;
  967. case CNDID_VER_ACC_1_METER:
  968. return 1;
  969. default:
  970. return 150;
  971. }
  972. }
  973. /**
  974. * This decodes a speed accuracy enum to the corresponding float value
  975. *
  976. * @param Accuracy Enum value representing the accuracy
  977. * @return The maximum speed accuracy in m/s
  978. */
  979. float decodeCNSpeedAccuracy(CNDID_SpeedAccuracy_t Accuracy)
  980. {
  981. switch (Accuracy)
  982. {
  983. case CNDID_SPEED_ACC_UNKNOWN:
  984. return 10;
  985. case CNDID_SPEED_ACC_10_METERS_PER_SECOND:
  986. return 10;
  987. case CNDID_SPEED_ACC_3_METERS_PER_SECOND:
  988. return 3;
  989. case CNDID_SPEED_ACC_1_METERS_PER_SECOND:
  990. return 1;
  991. case CNDID_SPEED_ACC_0_3_METERS_PER_SECOND:
  992. return 0.3f;
  993. default:
  994. return 10;
  995. }
  996. }
  997. /**
  998. * This decodes a timestamp accuracy enum to the corresponding float value
  999. *
  1000. * @param Accuracy Enum value representing the accuracy
  1001. * @return The maximum timestamp accuracy in seconds
  1002. */
  1003. float decodeCNTimestampAccuracy(CNDID_TimeStampAccuracy_t Accuracy)
  1004. {
  1005. switch (Accuracy)
  1006. {
  1007. case CNDID_TIME_ACC_UNKNOWN:
  1008. return 0.0f;
  1009. case CNDID_TIME_ACC_0_1_SECOND:
  1010. return 0.1f;
  1011. case CNDID_TIME_ACC_0_2_SECOND:
  1012. return 0.2f;
  1013. case CNDID_TIME_ACC_0_3_SECOND:
  1014. return 0.3f;
  1015. case CNDID_TIME_ACC_0_4_SECOND:
  1016. return 0.4f;
  1017. case CNDID_TIME_ACC_0_5_SECOND:
  1018. return 0.5f;
  1019. case CNDID_TIME_ACC_0_6_SECOND:
  1020. return 0.6f;
  1021. case CNDID_TIME_ACC_0_7_SECOND:
  1022. return 0.7f;
  1023. case CNDID_TIME_ACC_0_8_SECOND:
  1024. return 0.8f;
  1025. case CNDID_TIME_ACC_0_9_SECOND:
  1026. return 0.9f;
  1027. case CNDID_TIME_ACC_1_0_SECOND:
  1028. return 1.0f;
  1029. case CNDID_TIME_ACC_1_1_SECOND:
  1030. return 1.1f;
  1031. case CNDID_TIME_ACC_1_2_SECOND:
  1032. return 1.2f;
  1033. case CNDID_TIME_ACC_1_3_SECOND:
  1034. return 1.3f;
  1035. case CNDID_TIME_ACC_1_4_SECOND:
  1036. return 1.4f;
  1037. case CNDID_TIME_ACC_1_5_SECOND:
  1038. return 1.5f;
  1039. default:
  1040. return 0.0f;
  1041. }
  1042. }
  1043. #ifndef CNDID_DISABLE_PRINTF
  1044. /**
  1045. * Print array of bytes as a hex string
  1046. *
  1047. * @param byteArray Array of bytes to be printed
  1048. * @param asize Size of array of bytes to be printed
  1049. */
  1050. void PrintByteArray(uint8_t *byteArray, uint16_t asize, int spaced)
  1051. {
  1052. if (ENABLE_DEBUG) {
  1053. int x;
  1054. for (x=0;x<asize;x++) {
  1055. printf("%02x", (unsigned int) byteArray[x]);
  1056. if (spaced) {
  1057. printf(" ");
  1058. }
  1059. }
  1060. printf("\n");
  1061. }
  1062. }
  1063. /**
  1064. * Print formatted BasicID Data
  1065. *
  1066. * @param BasicID structure to be printed
  1067. */
  1068. void PrintBasicID_data(CNDID_BasicID_data *BasicID)
  1069. {
  1070. // Ensure the ID is null-terminated
  1071. char buf[CNDID_ID_SIZE + 1] = { 0 };
  1072. memcpy(buf, BasicID->UASID, CNDID_ID_SIZE);
  1073. const char CNDID_BasicID_data_format[] =
  1074. "UAType: %d\nIDType: %d\nUASID: %s\n";
  1075. printf(CNDID_BasicID_data_format, BasicID->IDType, BasicID->UAType, buf);
  1076. }
  1077. /**
  1078. * Print formatted Location Data
  1079. *
  1080. * @param Location structure to be printed
  1081. */
  1082. void PrintLocation_data(CNDID_Location_data *Location)
  1083. {
  1084. const char CNDID_Location_data_format[] =
  1085. "Status: %d\nDirection: %.1f\nSpeedHori: %.2f\nSpeedVert: "\
  1086. "%.2f\nLat/Lon: %.7f, %.7f\nAlt: Baro, Geo, Height above %s: %.2f, "\
  1087. "%.2f, %.2f\nHoriz, Vert, Baro, Speed, TS Accuracy: %.1f, %.1f, %.1f, "\
  1088. "%.1f, %.1f\nTimeStamp: %.2f\n";
  1089. printf(CNDID_Location_data_format, Location->Status,
  1090. (double) Location->Direction, (double) Location->SpeedHorizontal,
  1091. (double) Location->SpeedVertical, Location->Latitude,
  1092. Location->Longitude, Location->HeightType ? "Ground" : "TakeOff",
  1093. (double) Location->AltitudeBaro, (double) Location->AltitudeGeo,
  1094. (double) Location->Height,
  1095. (double) decodeCNHorizontalAccuracy(Location->HorizAccuracy),
  1096. (double) decodeCNVerticalAccuracy(Location->VertAccuracy),
  1097. (double) decodeCNVerticalAccuracy(Location->BaroAccuracy),
  1098. (double) decodeCNSpeedAccuracy(Location->SpeedAccuracy),
  1099. (double) decodeCNTimestampAccuracy(Location->TSAccuracy),
  1100. (double) Location->TimeStamp);
  1101. }
  1102. /**
  1103. * Print formatted SelfID Data
  1104. *
  1105. * @param SelfID structure to be printed
  1106. */
  1107. void PrintSelfID_data(CNDID_SelfID_data *SelfID)
  1108. {
  1109. // Ensure the description is null-terminated
  1110. char buf[CNDID_STR_SIZE + 1] = { 0 };
  1111. memcpy(buf, SelfID->Desc, CNDID_STR_SIZE);
  1112. const char CNDID_SelfID_data_format[] = "DescType: %d\nDesc: %s\n";
  1113. printf(CNDID_SelfID_data_format, SelfID->DescType, buf);
  1114. }
  1115. /**
  1116. * Print formatted System Data
  1117. *
  1118. * @param System_data structure to be printed
  1119. */
  1120. void PrintSystem_data(CNDID_System_data *System_data)
  1121. {
  1122. const char CNDID_System_data_format[] = "Operator Location Type: %d\n"
  1123. "Classification Type: %d\nLat/Lon: %.7f, %.7f\n"
  1124. "Area Count, Radius, Ceiling, Floor: %d, %d, %.2f, %.2f\n"
  1125. "Category EU: %d, Class EU: %d, Altitude: %.2f, Timestamp: %u\n";
  1126. printf(CNDID_System_data_format, System_data->OperatorLocationType,
  1127. System_data->Classification_Type,
  1128. System_data->OperatorLatitude, System_data->OperatorLongitude,
  1129. System_data->AreaCount, System_data->AreaRadius,
  1130. (double) System_data->AreaCeiling, (double) System_data->AreaFloor,
  1131. System_data->CategoryCN, System_data->ClassCN,
  1132. (double) System_data->OperatorAltitudeGeo, System_data->Timestamp);
  1133. }
  1134. #endif // CNDID_DISABLE_PRINTF