extern crate kampu; use once_cell::sync::Lazy; use serde_json::{json, Value}; use kampu::forest::{is_tree_planted, parse_tree, plant_tree}; use kampu::utils::hex_to_bin; ////////////////// qstarz_ble tests /* ref formula: int tmp_lat = dLat / 100; int tmp_lon = dLon / 100; dLat = tmp_lat + (dLat - tmp_lat * 100) / 60.0; dLon = tmp_lon + (dLon - tmp_lon * 100) / 60.0; */ const QSTARZ_LAT_LON_DDDMM_MMMM_FORMULA_EVAL_STR:&str = r#" tmp_lat = value_float / 100.0; tmp_lat + (value_float - tmp_lat * 100.0) / 60.0 "#; const QSTARZ_G_SENSOR_EVAL_STR:&str = "value_int / 256.0"; const QSTARZ_BLE_SCHEMA_TREE_ID:u64 = 1; const QSTARZ_BLE_TREE_SCHEMA: Lazy = Lazy::new(|| { json!({ "branches": [ { "name": "fix_status", "type": "u8", "match": { "1": "Fix not available", "2": "2D", "3": "3D", } }, { "name": "rcr", "type": "u8" }, { "name": "millisecond", "type": "u16" }, { "name": "latitude", "type": "f64", "eval": QSTARZ_LAT_LON_DDDMM_MMMM_FORMULA_EVAL_STR }, { "name": "longitude", "type": "f64", "eval": QSTARZ_LAT_LON_DDDMM_MMMM_FORMULA_EVAL_STR }, { "name": "timestamp_s", "type": "u32" }, { "name": "float_speed_kmh", "type": "f32" }, { "name": "float_height_m", "type": "f32" }, { "name": "heading_degrees", "type": "f32" }, { "name": "g_sensor_x", "type": "i16", "eval": QSTARZ_G_SENSOR_EVAL_STR }, { "name": "g_sensor_y", "type": "i16", "eval": QSTARZ_G_SENSOR_EVAL_STR }, { "name": "g_sensor_z", "type": "i16", "eval": QSTARZ_G_SENSOR_EVAL_STR }, { "name": "max_snr", "type": "u16" }, { "name": "hdop", "type": "f32" }, { "name": "vdop", "type": "f32" }, { "name": "satellite_count_view", "type": "u8" }, { "name": "satellite_count_used", "type": "u8" }, { "name": "fix_quality", "type": "u8", "match": { "0": "invalid", "1": "GPS fix (SPS)", "2": "DGPS fix", "3": "PPS fix", "4": "Real Time Kinematic", "5": "Float RTK", "6": "estimated (dead reckoning) (2.3 feature)", "7": "Manual input mode", "8": "Simulation mode" } }, { "name": "battery_percent", "type": "u8" }, { "name": "dummy", "type": "u16" }, { "name": "series_number", "type": "u8" }, { "name": "gsv_fields", "loop_count": 3, "branches": [ { "name": "prn", "type": "u8" }, { "name": "elevation", "type": "u16" }, { "name": "azimuth", "type": "u16" }, { "name": "snr", "type": "u8" } ] } ] }) }); fn setup_parse_trees() { if !is_tree_planted(QSTARZ_BLE_SCHEMA_TREE_ID) { plant_tree(QSTARZ_BLE_SCHEMA_TREE_ID, QSTARZ_BLE_TREE_SCHEMA.clone()); } } #[test] fn test_qstarz_ble_packet_gps_not_fixed() { setup_parse_trees(); /* 19:03:33.506 - Characteristic (6E400004-B5A3-F393-E0A9-E50E24DCCA9E) notified: <01547801 00000000 00000080 00000000 00000080> 01=GPS is not fixed 19:03:33.506 - Characteristic (6E400004-B5A3-F393-E0A9-E50E24DCCA9E) notified: <85f2de60 61a6fd3f 00000000 14aeca42 6800a9ff> 19:03:33.507 - Characteristic (6E400004-B5A3-F393-E0A9-E50E24DCCA9E) notified: <46001400 00000000 00000000 0d00003c 00000000> 19:03:33.507 - Characteristic (6E400004-B5A3-F393-E0A9-E50E24DCCA9E) notified: <05460300 3b000041 0c001300 00551100 b00000> 05=GSV #5 */ let data = hex_to_bin(r#" 01547801 00000000 00000080 00000000 00000080 85f2de60 61a6fd3f 00000000 14aeca42 6800a9ff 46001400 00000000 00000000 0d00003c 00000000 05460300 3b000041 0c001300 00551100 b00000 "# ); let parsed_json = parse_tree(QSTARZ_BLE_SCHEMA_TREE_ID, &data).unwrap(); println!("parsed_json: {}", serde_json::to_string_pretty(&parsed_json).unwrap()); assert_eq!( parsed_json, json!( { "fix_status": 1, "fix_status_matched": "Fix not available", "rcr": 84, "millisecond": 376, "latitude": -0.0, "longitude": -0.0, "timestamp_s": 1625223813, "float_speed_kmh": 1.9816399812698364, "float_height_m": 0.0, "heading_degrees": 101.33999633789062, "g_sensor_x": 104.0/256.0, "g_sensor_y": -87.0/256.0, "g_sensor_z": 70.0/256.0, "max_snr": 20, "hdop": 0.0, "vdop": 0.0, "satellite_count_view": 13, "satellite_count_used": 0, "fix_quality": 0, "fix_quality_matched": "invalid", "battery_percent": 60, "dummy": 0, "series_number": 0, "gsv_fields": [ { "prn": 0, "elevation": 17925, "azimuth": 3, "snr": 59 }, { "prn": 0, "elevation": 16640, "azimuth": 12, "snr": 19 }, { "prn": 0, "elevation": 21760, "azimuth": 17, "snr": 176 } ] } ) ); } #[test] fn test_qstarz_ble_packet_gps_fixed_wo_gsv() { setup_parse_trees(); /* 19:03:34.403 - Characteristic (6E400004-B5A3-F393-E0A9-E50E24DCCA9E) notified: <0354c800 cd94d6df 8a91a340 821e6adb 2eadc740> 03=GPS is fixed 19:03:34.403 - Characteristic (6E400004-B5A3-F393-E0A9-E50E24DCCA9E) notified: <86f2de60 3a924340 10c89943 ec51c842 610077ff> 19:03:34.404 - Characteristic (6E400004-B5A3-F393-E0A9-E50E24DCCA9E) notified: <72001300 b81ee53f ec51783f 0d05013c 0000> */ let data = hex_to_bin(r#" 0354c800 cd94d6df 8a91a340 821e6adb 2eadc740 86f2de60 3a924340 10c89943 ec51c842 610077ff 72001300 b81ee53f ec51783f 0d05013c 0000 "# ); let parsed_json = parse_tree(QSTARZ_BLE_SCHEMA_TREE_ID, &data).unwrap(); println!("parsed_json: {}", serde_json::to_string_pretty(&parsed_json).unwrap()); assert_eq!( parsed_json, json!({ "battery_percent": 60, "dummy": 0, "fix_quality": 1, "fix_quality_matched": "GPS fix (SPS)", "fix_status": 3, "fix_status_matched": "3D", "float_height_m": 307.56298828125, "float_speed_kmh": 3.055799961090088, "g_sensor_x": 97.0/256.0, "g_sensor_y": -137.0/256.0, "g_sensor_z": 114.0/256.0, "hdop": 1.7899999618530273, "heading_degrees": 100.16000366210938, "latitude": 25.04771239, "longitude": 121.22366071, "max_snr": 19, "millisecond": 200, "rcr": 84, "satellite_count_used": 5, "satellite_count_view": 13, "timestamp_s": 1625223814, "vdop": 0.9700000286102295 }) ); ////////////////////////// } #[test] fn test_qstarz_ble_packet_gps_fixed_w_gsv() { setup_parse_trees(); /* 19:03:34.555 - Characteristic (6E400004-B5A3-F393-E0A9-E50E24DCCA9E) notified: <03549001 faf202ec 8b91a340 69519fe4 2eadc740> 03=GPS is fixed 19:03:34.555 - Characteristic (6E400004-B5A3-F393-E0A9-E50E24DCCA9E) notified: <86f2de60 40de4b40 aec79943 5c8fd442 480082ff> 19:03:34.555 - Characteristic (6E400004-B5A3-F393-E0A9-E50E24DCCA9E) notified: <52001100 b81ee53f ec51783f 0d05013c 00000000> 19:03:34.555 - Characteristic (6E400004-B5A3-F393-E0A9-E50E24DCCA9E) notified: <05460300 3b000041 0c001300 00551100 b00000> 05=GSV #5 */ let data = hex_to_bin(r#" 03549001 faf202ec 8b91a340 69519fe4 2eadc740 86f2de60 40de4b40 aec79943 5c8fd442 480082ff 52001100 b81ee53f ec51783f 0d05013c 00000000 05460300 3b000041 0c001300 00551100 b00000 "# ); let parsed_json = parse_tree(QSTARZ_BLE_SCHEMA_TREE_ID, &data).unwrap(); println!("parsed_json: {}", serde_json::to_string_pretty(&parsed_json).unwrap()); assert_eq!( parsed_json, json!({ "fix_status": 3, "fix_status_matched": "3D", "rcr": 84, "millisecond": 400, "latitude": 25.047732850000003, "longitude": 121.22366351999999, "timestamp_s": 1625223814, "float_speed_kmh": 3.1854400634765625, "float_height_m": 307.55999755859375, "heading_degrees": 106.27999877929688, "g_sensor_x": 0.28125, "g_sensor_y": -0.4921875, "g_sensor_z": 0.3203125, "max_snr": 17, "hdop": 1.7899999618530273, "vdop": 0.9700000286102295, "satellite_count_view": 13, "satellite_count_used": 5, "fix_quality": 1, "fix_quality_matched": "GPS fix (SPS)", "battery_percent": 60, "dummy": 0, "series_number": 0, "gsv_fields": [ { "prn": 0, "elevation": 17925, "azimuth": 3, "snr": 59 }, { "prn": 0, "elevation": 16640, "azimuth": 12, "snr": 19 }, { "prn": 0, "elevation": 21760, "azimuth": 17, "snr": 176 } ] } ) ); ////////////////////////// }