GPSTrackerTools.cs 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945
  1. using System;
  2. using System.Collections.Generic;
  3. namespace Comal.Classes.Entities.GPSTracker
  4. {
  5. internal class GPSTrackerTools
  6. {
  7. /*
  8. function decode()
  9. {
  10. let stream = document.getElementById("encoded").value.trim();
  11. let num_messages = stream.split("0255").length - 1;
  12. let messages = stream.split("0255");
  13. messages.shift();
  14. let decoded_messages = [num_messages];
  15. for (let i = 0; i < num_messages; i++)
  16. {
  17. let byte_stream = [];
  18. if (isHex(stream))
  19. {
  20. byte_stream = getHex("0255" + messages[i]);
  21. }
  22. let decoded_object = parseOysterGSM(byte_stream);
  23. decoded_messages.push(decoded_object);
  24. }
  25. decoded_messages.shift();
  26. if (decoded_messages.includes(null))
  27. document.getElementById("decoded").innerHTML = "Invalid stream";
  28. else if (decoded_messages.includes(false))
  29. document.getElementById("decoded").innerHTML = "Using deprecated fields";
  30. else
  31. document.getElementById("decoded").innerHTML = JSON.stringify(decoded_messages, null, 2);
  32. }
  33. */
  34. public string[] Decode(string payload)
  35. {
  36. var results = new List<string>();
  37. var messages = payload.Split(new[] { "0255" }, StringSplitOptions.RemoveEmptyEntries);
  38. foreach (var message in messages)
  39. {
  40. //if (IsHex(message))
  41. //{
  42. // byte[] bytes = GetHex(String.Concat("0255", message));
  43. // String result = parseOysterGSM(bytes);
  44. // results.Add(result);
  45. //}
  46. }
  47. return results.ToArray();
  48. }
  49. /*
  50. function isHex(value)
  51. {
  52. if (value.length == 0)
  53. return false;
  54. if (value.startsWith('0x') || value.startsWith('0X'))
  55. {
  56. value = value.substring(2);
  57. }
  58. let reg_exp = /^[0 - 9a - fA - F] +$/;
  59. if (reg_exp.test(value) && value.length % 2 == 0)
  60. {
  61. return true;
  62. }
  63. else
  64. {
  65. return false;
  66. }
  67. }
  68. */
  69. /*
  70. function getHex(value)
  71. {
  72. if (value.startsWith('0x') || value.startsWith('0X'))
  73. {
  74. value = value.substring(2);
  75. }
  76. let num_bytes = value.length / 2;
  77. let bytes = [];
  78. for (let i = 0; i < num_bytes; i++)
  79. {
  80. bytes.push(parseInt(value.substring(i * 2, (i * 2) + 2), 16));
  81. }
  82. return bytes;
  83. }
  84. */
  85. }
  86. }
  87. /*
  88. <script>
  89. function parseOysterGSM(buffer)
  90. {
  91. if (buffer == null)
  92. return null;
  93. let message_type = buffer[2];
  94. switch (message_type)
  95. {
  96. case 0: //hello request
  97. return parseHelloRequest(buffer);
  98. case 1: //hello response
  99. return parseHelloResponse(buffer);
  100. case 4: //data record upload
  101. return parseRecordUpload(buffer);
  102. case 5: //commit request
  103. return parseCommitRequest(buffer);
  104. case 6: //commit response
  105. return parseCommitResponse(buffer);
  106. case 14: //canned response 1 - not being used
  107. return null
  108. case 22: //canned response 2 - not being used
  109. return null
  110. default:
  111. return null;
  112. }
  113. }
  114. function parseLittleEndianInt32(buffer, offset)
  115. {
  116. return (buffer[offset + 3] << 24) +
  117. (buffer[offset + 2] << 16) +
  118. (buffer[offset + 1] << 8) +
  119. (buffer[offset]);
  120. }
  121. function parseLittleEndianInt16(buffer, offset)
  122. {
  123. let result = (buffer[offset + 1] << 8) + buffer[offset];
  124. if ((result & 0x8000) > 0)
  125. result = result - 0x10000;
  126. return result;
  127. }
  128. function parseHexToASCII(buffer, start, end)
  129. {
  130. let sub_array = buffer.slice(start, end);
  131. let result = '';
  132. for (let i = 0; i < sub_array.length; i++)
  133. result += String.fromCharCode(sub_array[i]);
  134. return result;
  135. }
  136. function parseDecToHex(buffer)
  137. {
  138. let hex_result = '';
  139. buffer.forEach(element => {
  140. hex_result += element.toString(16);
  141. });
  142. return hex_result;
  143. }
  144. function parseDecToBin(buffer)
  145. {
  146. let bin_result = parseInt(buffer).toString(2);
  147. return bin_result;
  148. }
  149. function parseSliceInt(value, start, length)
  150. {
  151. let binary = parseInt(value).toString(2).padStart(8,"0").slice(start, start + length);
  152. if (binary.includes("1"))
  153. {
  154. return parseInt(binary, 2);
  155. }
  156. return 0;
  157. }
  158. function parseSliceInt16(value, start, length)
  159. {
  160. let binary = parseInt(value).toString(2).padStart(16,"0").slice(start, start + length);
  161. if (binary.includes("1"))
  162. {
  163. return parseInt(binary, 2);
  164. }
  165. return 0;
  166. }
  167. function parseGPSData(value)
  168. {
  169. let utc_date_time = parseLittleEndianInt32(value, 0);
  170. let latitude = parseLittleEndianInt32(value, 4);
  171. let longitude = parseLittleEndianInt32(value, 8);
  172. let altitude = parseLittleEndianInt16(value, 12);
  173. let ground_speed = parseLittleEndianInt16(value, 14);
  174. let speed_accuracy_estimate = value[16];
  175. let heading = value[17];
  176. let pdop = value[18];
  177. let position_accuracy_estimate = value[19];
  178. let status_flags = parseDecToBin(value[20]);
  179. return {
  180. UTCDateTime: utc_date_time,
  181. Latitude: latitude,
  182. Longitude: longitude,
  183. Altitude: altitude,
  184. GroundSpeed: ground_speed,
  185. SpeedAccuracyEstimate: speed_accuracy_estimate,
  186. Heading: heading,
  187. PDOP: pdop,
  188. PositionAccuracyEstimate: position_accuracy_estimate,
  189. StatusFlags: status_flags
  190. }
  191. }
  192. function parseDebugEvent(length, value)
  193. {
  194. let severity = parseSliceInt(value[0], 6, 2);
  195. let module_id = parseSliceInt(value[0], 1, 5);
  196. let event_code = value[1];
  197. let ascii_debug_string = parseHexToASCII(value, 2, length);
  198. return {
  199. Severity: severity,
  200. ModuleID: module_id,
  201. EventCode: event_code,
  202. ASCIIDebugString: ascii_debug_string
  203. }
  204. }
  205. function parseDigitalData(value)
  206. {
  207. let digital_inputs = parseLittleEndianInt32(value, 0);
  208. let digital_outputs = parseLittleEndianInt16(value, 4);
  209. let status_flags = parseDecToBin(parseLittleEndianInt16(value, 6));
  210. return {
  211. DigitalInputs: digital_inputs,
  212. DigitalOutputs: digital_outputs,
  213. StatusFlags: status_flags
  214. }
  215. }
  216. function parseDriverOperatorID(length, value)
  217. {
  218. let driver_id_type = value[0];
  219. let driver_id_data = ''
  220. if (driver_id_type == 1 || driver_id_type == 2)
  221. {
  222. driver_id_data = value.slice(1, length - 1);
  223. }
  224. else{
  225. driver_id_data = parseHexToASCII(value, 1, length);
  226. }
  227. return {
  228. DriverIDType: driver_id_type,
  229. DriverIDData: driver_id_data
  230. }
  231. }
  232. function parseSDI12Identification(length, value)
  233. {
  234. let device_address = value[0];
  235. let sdi12_identification = parseHexToASCII(value, 1, length);
  236. return {
  237. DeviceAddress: device_address,
  238. SDI12Identification: sdi12_identification
  239. }
  240. }
  241. function parseSDI12Measurement(length, value)
  242. {
  243. let sdi12_measurement_type = value[0];
  244. let measurements = [];
  245. for (let i = 0; i < length; i += 4)
  246. {
  247. measurements.push(parseLittleEndianInt32(value, 1 + i ));
  248. }
  249. return {
  250. SDI12MeasurementType: sdi12_measurement_type,
  251. Measurements: measurements
  252. }
  253. }
  254. function parseINT16AnalogueData(length, value)
  255. {
  256. let analogue_objects = []
  257. for (let i = 0; i < length; i+=3)
  258. {
  259. let current_analogue_number = value[i];
  260. let current_analogue_value = parseLittleEndianInt16(value, 1 + i);
  261. let current_analogue_object = {
  262. AnalogueNumber: current_analogue_number,
  263. Value: current_analogue_value
  264. }
  265. analogue_objects.push(current_analogue_object);
  266. }
  267. return {
  268. INT16AnalogueData: analogue_objects
  269. }
  270. }
  271. function parseINT32AnalogueData(length, value)
  272. {
  273. let analogue_objects = []
  274. for (let i = 0; i < length; i+=5)
  275. {
  276. let current_analogue_number = value[i];
  277. let current_analogue_value = parseLittleEndianInt32(value, 1 + i);
  278. let current_analogue_object = {
  279. AnalogueNumber: current_analogue_number,
  280. Value: current_analogue_value
  281. }
  282. analogue_objects.push(current_analogue_object);
  283. }
  284. return {
  285. INT32AnalogueData: analogue_objects
  286. }
  287. }
  288. function parseDevice3rdPartyAsyncMessage(value)
  289. {
  290. let hex_result = parseDecToHex(value);
  291. return {
  292. Device3rdPartyAsyncMessage: hex_result
  293. }
  294. }
  295. function parseProjectCode(value)
  296. {
  297. let ascii_project_code = parseHexToASCII(value);
  298. return {
  299. ProjectCode: ascii_project_code
  300. }
  301. }
  302. function parseTripTypeCode(value)
  303. {
  304. let ascii_trip_type_code = parseHexToASCII(value);
  305. return {
  306. TripTypeCode: ascii_trip_type_code
  307. }
  308. }
  309. function parseDeviceTripTypeAndData(value)
  310. {
  311. let device_trip_type = value[0];
  312. let movement_trip_trimming_amount = parseLittleEndianInt16(value, 1);
  313. return {
  314. DeviceTripType: device_trip_type,
  315. MovementTripTrimmingAmount: movement_trip_trimming_amount
  316. }
  317. }
  318. function parseGarminFMIStopResponse(value)
  319. {
  320. let message_id = parseLittleEndianInt32(value, 0);
  321. let message_response = value[4];
  322. return {
  323. MessageID: message_id,
  324. MessageResponse: message_response
  325. }
  326. }
  327. function parseAccelerometerTraceHeader(value)
  328. {
  329. let accident_id = parseLittleEndianInt32(value, 0);
  330. let force_matrix = [3][3];
  331. let force_counter = 4;
  332. for (let i = 0; i < 3; i++)
  333. {
  334. for (let j = 0; j < 3; j++)
  335. {
  336. force_matrix[i][j] = parseLittleEndianInt32(value, force_counter);
  337. force_counter += 4;
  338. }
  339. }
  340. let filter_pole = parseLittleEndianInt32(value, 40);
  341. let filter_gain = parseLittleEndianInt32(value, 44);
  342. let final_input = [3];
  343. for (let i = 0; i < 3; i++)
  344. {
  345. final_input.push(parseLittleEndianInt16(value, 48 + i*2));
  346. }
  347. let trigger_point_in_samples = parseLittleEndianInt16(value, 54);
  348. let number_of_samples = parseLittleEndianInt16(value, 56);
  349. return {
  350. AccidentID: accident_id,
  351. ForceMatrix: force_matrix,
  352. FilterPole: filter_pole,
  353. FilterGain: filter_gain,
  354. FinalInput: final_input,
  355. TriggerPointInSamples: trigger_point_in_samples,
  356. NumberSamples: number_of_samples
  357. }
  358. }
  359. function parseAccelerometerTraceSampples(length, value)
  360. {
  361. let accident_id = parseLittleEndianInt32(value, 0);
  362. let num_samples = (length - 4) / 6;
  363. let samples = [num_samples][3];
  364. let sample_counter = 2;
  365. for (let i = 0; i < num_samples; i++)
  366. {
  367. for (let j = 0; j < 3; j++)
  368. {
  369. samples[i][j] = parseLittleEndianInt16(value, force_counter);
  370. sample_counter += 2;
  371. }
  372. }
  373. return {
  374. AccidentID: accident_id,
  375. Samples: samples
  376. }
  377. }
  378. function parseAccidentData(value)
  379. {
  380. let accident_id = parseLittleEndianInt32(value, 0);
  381. let gps_utc_date_time = parseLittleEndianInt32(value, 4);
  382. let latitude = parseLittleEndianInt32(value, 8);
  383. let longitude = parseLittleEndianInt32(value, 12);
  384. let altitude = parseLittleEndianInt16(value, 16);
  385. let ground_speed = parseLittleEndianInt16(value, 18);
  386. let speed_accuracy_estimate = value[20];
  387. let heading = value[21];
  388. let pdop = value[22];
  389. let position_accuracy_estimate = value[23];
  390. let gps_status_flags = parseDecToBin(value[24]);
  391. let max_x_delta_velocity = parseSliceInt16(parseLittleEndianInt16(value, 25), 0, 10);
  392. let max_y_delta_velocity = parseSliceInt16(parseLittleEndianInt16(value, 26), 2, 10);
  393. let max_z_delta_velocity = parseSliceInt16(parseLittleEndianInt16(value, 27), 4, 10);
  394. let delta_orientation = parseSliceInt16(parseLittleEndianInt16(value, 28), 6, 1);
  395. return {
  396. AccidentID: accident_id,
  397. GPSUTCDateTime: gps_utc_date_time,
  398. Latitude: latitude,
  399. Longitude: longitude,
  400. Altitude: altitude,
  401. GroundSpeed: ground_speed,
  402. SpeedAccuracyEstimate: speed_accuracy_estimate,
  403. Heading: heading,
  404. PDOP: pdop,
  405. PositionAccuracyEstimate: position_accuracy_estimate,
  406. GPSStatusFlags: gps_status_flags,
  407. MaximumXDeltaVelocity: max_x_delta_velocity,
  408. MaximumYDeltaVelocity: max_y_delta_velocity,
  409. MaximumZDeltaVelocity: max_z_delta_velocity,
  410. DeltaOrientation: delta_orientation
  411. }
  412. }
  413. function parseProfileCounterID(id)
  414. {
  415. switch(id)
  416. {
  417. case 0: return "Internal Battery Voltage"
  418. case 1: return "Internal Battery"
  419. case 2: return "Est. Battery Capacity Used"
  420. case 3: return "Maximum Temperature"
  421. case 4: return "Initial Internal Battery Voltage"
  422. case 5: return "Average Successful GPS Fix Time"
  423. case 6: return "Average Failed GPS Fix Time"
  424. case 7: return "Average GPS Freshen Time"
  425. case 8: return "Average Wakeups Per Trip"
  426. case 128: return "Successful Uploads"
  427. case 129: return "Successful Upload Time"
  428. case 130: return "Failed Uploads"
  429. case 131: return "Failed Upload Time"
  430. case 132: return "Successful GPS Fixes"
  431. case 133: return "Successful GPS Fix Time"
  432. case 134: return "Failed GPS Fixes"
  433. case 135: return "Failed GPS Fix Time"
  434. case 136: return "GPS Freshen Attempts"
  435. case 137: return "GPS Freshen Time"
  436. case 138: return "Accelerometer Wakeups"
  437. case 139: return "Trips"
  438. case 140: return "GPS Fixes Due to ‘Upload on Jostle’"
  439. case 141: return "Uploads Due to ‘Upload on Jostle’"
  440. case 142: return "Uptime"
  441. case 143: return "Tx Count"
  442. case 144: return "Rx Count"
  443. case 145: return "Successful Wifi Scans"
  444. case 146: return "Failed Wifi Scans"
  445. default: return "Unknown ID"
  446. }
  447. }
  448. function parseProfilingCounters(length, value)
  449. {
  450. let counter = 0;
  451. let profiling_counters = [];
  452. while (counter != length)
  453. {
  454. let counter_id = value[counter];
  455. let counter_id_description = parseProfileCounterID(counter_id);
  456. counter++;
  457. let counter_value = null;
  458. let counter_id_top_bit = parseInt(parseInt(counter_id).toString(2).padStart(8, "0").slice(0, 1), 2);
  459. if (counter_id_top_bit == 0)
  460. {
  461. counter_value = parseLittleEndianInt16(value, counter)
  462. counter += 2;
  463. }
  464. else
  465. {
  466. counter_value = parseLittleEndianInt32(value, counter)
  467. counter += 4;
  468. }
  469. profiling_counters.push([counter_id, counter_id_description, counter_value]);
  470. }
  471. return {
  472. ProfilingCounterPairs: profiling_counters
  473. }
  474. }
  475. function parseHighGEvent(value)
  476. {
  477. let peak_g_force = parseLittleEndianInt16(value, 0);
  478. let avg_abs_g_force = parseLittleEndianInt16(value, 2);
  479. let duration = parseLittleEndianInt16(value, 4);
  480. return {
  481. PeakGForce: peak_g_force,
  482. AverageAbsoluteGForce: avg_abs_g_force,
  483. Duration: duration
  484. }
  485. }
  486. function parseWiFiLocationScan(length, value)
  487. {
  488. let mac_address_array = [];
  489. let signal_strength_array = [];
  490. let channel_num_array = [];
  491. let data_field_length = 8;
  492. let max_entries = 30;
  493. for (let iteration = 0; iteration < length / data_field_length; iteration++)
  494. {
  495. if (iteration > max_entries) break;
  496. let mac_address = [6];
  497. for (let i = 0; i < 6; i++)
  498. {
  499. mac_address[i] = parseDecToHex(value[i + iteration * data_field_length]);
  500. }
  501. let signal_strength = value[6 + iteration * data_field_length];
  502. let channel_num = parseSliceInt(value[7 + iteration * data_field_length], 0, 4);
  503. mac_address_array.push(mac_address);
  504. signal_strength_array.push(signal_strength);
  505. channel_num_array.push(channel_num);
  506. }
  507. return {
  508. MACAddress: mac_address_array,
  509. SignalStrength: signal_strength_array,
  510. ChanelNum: channel_num_array
  511. }
  512. }
  513. function parseTripOdometerRunHours(value)
  514. {
  515. let trip_distance = parseLittleEndianInt32(value, 0);
  516. let trip_run_hours = parseLittleEndianInt32(value, 4);
  517. return {
  518. TripDistance: trip_distance,
  519. TripRunHours: trip_run_hours
  520. }
  521. }
  522. function parseDeviceOdometerRunHours(length, value)
  523. {
  524. let device_odo = parseLittleEndianInt32(value, 0);
  525. let run_hours = parseLittleEndianInt32(value, 4);
  526. if (length == 12)
  527. {
  528. let secondary_run_hours = parseLittleEndianInt32(value, 8);
  529. return {
  530. DeviceOdo: device_odo,
  531. RunHours: run_hours,
  532. SecondaryRunHours: secondary_run_hours
  533. }
  534. }
  535. return {
  536. DeviceOdo: device_odo,
  537. RunHours: run_hours
  538. }
  539. }
  540. function parseCellTowerScan(length, value)
  541. {
  542. let cell_id_array = [];
  543. let location_area_code_array = [];
  544. let mobile_country_code_array = [];
  545. let mobile_network_code_array = []
  546. let data_field_length = 10;
  547. let max_entries = 20;
  548. for (let iteration = 0; iteration < length / data_field_length; iteration++)
  549. {
  550. if (iteration > max_entries) break;
  551. let cell_id = parseLittleEndianInt32(value, 0 + iteration * data_field_length);
  552. let location_area_code = parseLittleEndianInt16(value, 4 + iteration * data_field_length);
  553. let mobile_country_code = parseLittleEndianInt16(value, 6 + iteration * data_field_length);
  554. let mobile_network_code = parseLittleEndianInt16(value, 8 + iteration * data_field_length);
  555. cell_id_array.push(cell_id);
  556. location_area_code_array.push(location_area_code);
  557. mobile_country_code_array.push(mobile_country_code);
  558. mobile_network_code_array.push(mobile_network_code);
  559. }
  560. return {
  561. CellID: cell_id_array,
  562. LocationAreaCode: location_area_code_array,
  563. MobileCountryCode: mobile_country_code_array,
  564. MobileNetworkCode: mobile_network_code_array
  565. }
  566. }
  567. function parseDataField(id, length, value)
  568. {
  569. switch(id)
  570. {
  571. case 0: //GPS Data
  572. return parseGPSData(value);
  573. case 1: //Debug Event
  574. return parseDebugEvent(length, value);
  575. case 2: //Digital Data
  576. return parseDigitalData(value);
  577. case 3: //Driver or Operator ID
  578. return parseDriverOperatorID(length, value);
  579. case 4: //SDI-12 Device Identification
  580. return parseSDI12Identification(length, value);
  581. case 5: //SDI-12 Measurement
  582. return parseSDI12Measurement(length, value);
  583. case 6: //INT16 Analogue Data
  584. return parseINT16AnalogueData(length, value);
  585. case 7: //INT32 Analogue Data
  586. return parseINT32AnalogueData(length, value);
  587. case 9: //Device 3rd Party Async Message
  588. return parseDevice3rdPartyAsyncMessage(value);
  589. case 10: //Project Code
  590. return parseProjectCode(value);
  591. case 11: //Trip Type Code
  592. return parseTripTypeCode(value);
  593. case 12: //Not implemented due to lack of use
  594. return null
  595. case 13: //RF Tag data - Deprecated
  596. return false
  597. case 14: //RF Tag Lost - Deprecated
  598. return false
  599. case 15: //Device Trip Type and Data
  600. return parseDeviceTripTypeAndData(value);
  601. case 16: //Garmin FMI Stop Response
  602. return parseGarminFMIStopResponse(value);
  603. case 17: //Accident Data
  604. return parseAccidentData(value);
  605. case 18: //Accelerometer Trace Header
  606. return parseAccelerometerTraceHeader(value);
  607. case 19: //Accelerometer Trace Samples
  608. return parseAccelerometerTraceSampples(length, value);
  609. case 20: //V5 RF Message - Functionality no longer offered
  610. return false
  611. case 21: //Profiling Counters
  612. return parseProfilingCounters(length, value);
  613. case 22: //Not currently required
  614. return null
  615. case 23: //Deprecated
  616. return false
  617. case 24: //High-G Event
  618. return parseHighGEvent(value);
  619. case 25: //WiFi Location Scan
  620. return parseWiFiLocationScan(length, value);
  621. case 26: //Trip Odometer, Run Hours
  622. return parseTripOdometerRunHours(value);
  623. case 27: //Device Odometer, Run Hours
  624. return parseDeviceOdometerRunHours(length, value);
  625. case 28: //Cell Tower Scan
  626. return parseCellTowerScan(length, value);
  627. default:
  628. return null;
  629. }
  630. }
  631. //Test: 02550031009CFC0100333539363836303735383531303431003839343034373030303030303037373639313435003A01010400000000
  632. function parseHelloRequest(buffer)
  633. {
  634. let sync_chars = "0" + parseDecToHex([buffer[0], buffer[1]]);
  635. let message_type = buffer[2];
  636. let payload_length = parseLittleEndianInt16(buffer, 3);
  637. let serial_num = parseLittleEndianInt32(buffer, 5);
  638. let imei = parseHexToASCII(buffer, 9, 24);
  639. let sim_iccid = parseHexToASCII(buffer, 25, 45);
  640. let product_id = buffer[46];
  641. let hardware_rev = buffer[47];
  642. let firmware_major = buffer[48];
  643. let firmware_minor = buffer[49];
  644. let flags = parseDecToBin(parseLittleEndianInt32(buffer, 50));
  645. return {
  646. SyncChars: sync_chars,
  647. MessageType: message_type,
  648. PayloadLength: payload_length,
  649. SerialNum: serial_num,
  650. IMEI: imei,
  651. SIMICCID: sim_iccid,
  652. ProductID: product_id,
  653. HardwareRev: hardware_rev,
  654. FirmwareMajor: firmware_major,
  655. FirmwareMinor: firmware_minor,
  656. Flags: flags
  657. };
  658. }
  659. //Test: 0255010800677C370200000000
  660. function parseHelloResponse(buffer)
  661. {
  662. let sync_chars = "0" + parseDecToHex([buffer[0], buffer[1]]);
  663. let message_type = buffer[2];
  664. let payload_length = parseLittleEndianInt16(buffer, 3);
  665. let utc_date_time = parseLittleEndianInt32(buffer, 5);
  666. let flags = parseDecToBin(parseLittleEndianInt32(buffer, 9));
  667. return {
  668. SyncChars: sync_chars,
  669. MessageType: message_type,
  670. PayloadLength: payload_length,
  671. UTCDateTime: utc_date_time,
  672. Flags: flags
  673. };
  674. }
  675. //Test (single record): 0255043D003d004746000096D684020b001502D48402F043F4EC2A6909452B001F00050011230302080000000000000A00060F041D0001FE0F021E0005000003BF08
  676. //Test (multiple record): 0255047A003d004746000096D684020b001502D48402F043F4EC2A6909452B001F00050011230302080000000000000A00060F041D0001FE0F021E0005000003BF083d004746000096D684020b001502D48402F043F4EC2A6909452B001F00050011230302080000000000000A00060F041D0001FE0F021E0005000003BF08
  677. function parseRecordUpload(buffer)
  678. {
  679. let sync_chars = "0" + parseDecToHex([buffer[0], buffer[1]]);
  680. let message_type = buffer[2];
  681. let payload_length = parseLittleEndianInt16(buffer, 3);
  682. let iterated_payload_length = 0;
  683. let record_objects = [];
  684. while (iterated_payload_length < payload_length)
  685. {
  686. let record_length = parseLittleEndianInt16(buffer, 5 + iterated_payload_length);
  687. let record_seq_num = parseLittleEndianInt32(buffer, 7 + iterated_payload_length);
  688. let record_rtc_date_time = parseLittleEndianInt32(buffer, 11 + iterated_payload_length);
  689. let record_log_reason = buffer[15 + iterated_payload_length];
  690. let record_keys = [];
  691. let record_values = [];
  692. let record_current_length = 11;
  693. let record_data_fields = [];
  694. let record_parsed_data_fields = [];
  695. while (record_current_length < record_length)
  696. {
  697. let data_field_id = buffer[record_current_length + 5 + iterated_payload_length];
  698. let data_field_length = buffer[record_current_length + 6 + iterated_payload_length];
  699. if (data_field_length == 255)
  700. {
  701. data_field_length = parseLittleEndianInt16(buffer, record_current_length + 7 + iterated_payload_length);
  702. record_current_length += 2;
  703. }
  704. record_keys.push([data_field_id, data_field_length]);
  705. record_current_length += 2;
  706. let current_values = [];
  707. for (let i = 0; i < data_field_length; i++)
  708. {
  709. current_values.push(buffer[record_current_length + 5 + i + iterated_payload_length])
  710. }
  711. record_values.push(current_values);
  712. record_current_length += data_field_length;
  713. record_data_fields.push([[data_field_id, data_field_length], current_values]);
  714. record_parsed_data_fields.push(parseDataField(data_field_id, data_field_length, current_values));
  715. }
  716. let record = {
  717. Length: record_length,
  718. SequenceNumber: record_seq_num,
  719. RTCDateTime: record_rtc_date_time,
  720. LogReason: record_log_reason,
  721. DataFields: record_parsed_data_fields
  722. }
  723. record_objects.push(record)
  724. iterated_payload_length += record_length;
  725. }
  726. return {
  727. SyncChars: sync_chars,
  728. MessageType: message_type,
  729. PayloadLength: payload_length,
  730. Records: record_objects
  731. };
  732. }
  733. //Test: 0255050000
  734. function parseCommitRequest(buffer)
  735. {
  736. let sync_chars = "0" + parseDecToHex([buffer[0], buffer[1]]);
  737. let message_type = buffer[2];
  738. let payload_length = parseLittleEndianInt16(buffer, 3);
  739. return {
  740. SyncChars: sync_chars,
  741. MessageType: message_type,
  742. PayloadLength: payload_length,
  743. }
  744. }
  745. //Test: 025506010001
  746. function parseCommitResponse(buffer)
  747. {
  748. let sync_chars = "0" + parseDecToHex([buffer[0], buffer[1]]);
  749. let message_type = buffer[2];
  750. let payload_length = parseLittleEndianInt16(buffer, 3);
  751. let flags = parseDecToBin(buffer[5]);
  752. return {
  753. SyncChars: sync_chars,
  754. MessageType: message_type,
  755. PayloadLength: payload_length,
  756. Flags: flags
  757. }
  758. }
  759. //Test (combined): 02550031009CFC0100333539363836303735383531303431003839343034373030303030303037373639313435003A010104000000000255010800677C3702000000000255047A003d004746000096D684020b001502D48402F043F4EC2A6909452B001F00050011230302080000000000000A00060F041D0001FE0F021E0005000003BF083d004746000096D684020b001502D48402F043F4EC2A6909452B001F00050011230302080000000000000A00060F041D0001FE0F021E0005000003BF080255050000025506010001
  760. </script>
  761. </body>
  762. </html>
  763. */