antPlus_MSM.h 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565
  1. /*
  2. This software is subject to the license described in the License.txt file
  3. included with this software distribution. You may not use this file except in compliance
  4. with this license.
  5. Copyright (c) Dynastream Innovations Inc. 2012
  6. All rights reserved.
  7. */
  8. #pragma once
  9. #include "types.h"
  10. #define MSM_REV 1.0 // Device Profile Revision Number
  11. public ref class MSM
  12. {
  13. public:
  14. // Channel Parameters
  15. static const UCHAR DEVICE_TYPE = 15;
  16. static const UCHAR TX_TYPE = 5;
  17. static const USHORT MSG_PERIOD = 8192; // 4 Hz
  18. static const USHORT HALF_PERIOD = 16384; // 2 Hz
  19. // Data Pages
  20. static const UCHAR PAGE_1 = 0x01;
  21. static const UCHAR PAGE_2 = 0x02;
  22. static const UCHAR PAGE_3 = 0x03;
  23. static const UCHAR PAGE_4 = 0x04;
  24. static const UCHAR PAGE_CALIBRATION = 0x30;
  25. // Calibration Messages
  26. static const USHORT CAL_SCALE_CONF = 0x2710; // this translates to 10000 or 1.0000 for a scale factor
  27. static const USHORT CAL_SCALE_REQUEST = 0x0000;
  28. static const USHORT CAL_SCALE_INVALID = 0xFFFF;
  29. static const USHORT CAL_SF_SCALE_FACTOR = 10000;
  30. static const UCHAR CAL_MODE_INVALID = 0xFF;
  31. // Acknowledged Messages
  32. static const UCHAR ACK_FAIL = 0;
  33. static const UCHAR ACK_SUCCESS = 1;
  34. // Reserved/invalid/special values
  35. static const UCHAR RESERVED = 0xFF;
  36. static const USHORT INVALID_SPEED = 0xFFFF;
  37. static const USHORT INVALID_HEADING = 0x0FFF;
  38. static const USHORT INVALID_ELEVATION = 0xFFFF;
  39. static const USHORT INVALID_DISTANCE = 0xFFFF;
  40. static const USHORT MAX_SPEED = 0xFFFE;
  41. // Bit Masks
  42. static const UCHAR BYTE_MASK = 0xFF;
  43. static const UCHAR UPPER_NIBBLE_MASK = 0xF0;
  44. static const UCHAR LOWER_NIBBLE_MASK = 0x0F;
  45. static const UCHAR NEGATIVE_BYTE_MASK = 0x80;
  46. static const UCHAR REMOVE_SIGNED_BIT_MASK = 0x7F;
  47. static const USHORT HEADING_MASK = 0x0FF0;
  48. static const ULONG NEGATIVE_LONG_MASK = 0xF0000000;
  49. // Bit shifts
  50. static const UCHAR NIBBLE_SHIFT = 4;
  51. static const UCHAR BYTE_SHIFT = 8;
  52. static const UCHAR LAT_BYTE_2_SHIFT = 8;
  53. static const UCHAR LAT_BYTE_3_SHIFT = 16;
  54. static const UCHAR LAT_BYTE_4_SHIFT = 24;
  55. static const UCHAR LON_BYTE_5_SHIFT = 4;
  56. static const UCHAR LON_BYTE_6_SHIFT = 12;
  57. static const UCHAR LON_BYTE_7_SHIFT = 20;
  58. //Scale and offset Factors
  59. static const USHORT TIME_SCALE_FACTOR = 1024;
  60. static const UCHAR DIST_SCALE_FACTOR = 10;
  61. static const USHORT SPEED_SCALE_FACTOR = 1000;
  62. static const UCHAR HEADING_SCALE_FACTOR = 10;
  63. static const UCHAR ELEVATION_SCALE_FACTOR = 5;
  64. static const USHORT ELEVATION_OFFSET = 500;
  65. static const DOUBLE SEMI_CIRCLE_CONVERSION = System::Math::Pow(2.0, 27) / 180; // conversion to semicircles from degrees
  66. enum class GpsFix : UCHAR
  67. {
  68. NONE,
  69. SEARCHING,
  70. PROPAGATING,
  71. LAST_KNOWN,
  72. TWO_D,
  73. TWO_D_WAAS,
  74. TWO_D_DIF,
  75. THREE_D,
  76. THREE_D_WAAS,
  77. THREE_D_DIF,
  78. INVALID = 0x0F
  79. };
  80. enum class TurnByTurns : UCHAR
  81. {
  82. DESTINATION,
  83. TURN,
  84. HARD_TURN,
  85. SLIGHT_TURN,
  86. U_TURN,
  87. EXIT,
  88. LEFT_MASK = 0x80,
  89. RIGHT_MASK = 0x7F,
  90. };
  91. enum class CalibrationStatus : UCHAR
  92. {
  93. NONE,
  94. REQUEST_IN_PROGRESS,
  95. SET_SCALE_IN_PROGRESS,
  96. COMPLETE
  97. };
  98. // Error handling
  99. // Flags indicate errors causing the exception
  100. ref class Error : public System::Exception{
  101. public:
  102. BOOL bBadReserved; // Invalid values on reserved fields
  103. BOOL bUndefPage; // Undefined page
  104. BOOL bUndefCalID; // Undefined calibration message ID
  105. BOOL bUndefCTFID; // Undefined CTF calibration message ID
  106. BOOL bUndefCTFAck; // Undefined CTF Acked message
  107. BOOL bUndefAutoZero; // Undefined auto zero status
  108. enum class Code : UCHAR // Error code definitions
  109. {
  110. INVALID_RESERVED, // Invalid value in reserved field
  111. UNDEF_PAGE, // Undefined data page
  112. UNDEF_CAL_ID, // Undefined calibration message ID
  113. UNDEF_CTF_ID, // Undefined CTF calibration message ID
  114. UNDEF_CTF_ACKED, // Undefined CTF acked message
  115. UNDEF_AUTOZERO, // Invalid auto zero status
  116. };
  117. Error()
  118. {
  119. ClearFlags();
  120. }
  121. Error(Code eCode1_)
  122. {
  123. ClearFlags();
  124. SetFlags(eCode1_);
  125. }
  126. Error(Code eCode1_, Code eCode2_)
  127. {
  128. ClearFlags();
  129. SetFlags(eCode1_);
  130. SetFlags(eCode2_);
  131. }
  132. private:
  133. void ClearFlags()
  134. {
  135. bBadReserved = FALSE;
  136. bUndefPage = FALSE;
  137. bUndefCalID = FALSE;
  138. bUndefCTFID = FALSE;
  139. bUndefCTFAck = FALSE;
  140. bUndefAutoZero = FALSE;
  141. }
  142. void SetFlags(Code eCode_)
  143. {
  144. switch(eCode_)
  145. {
  146. case Code::INVALID_RESERVED:
  147. bBadReserved = TRUE;
  148. break;
  149. case Code::UNDEF_PAGE:
  150. bUndefPage = TRUE;
  151. break;
  152. case Code::UNDEF_CAL_ID:
  153. bUndefCalID = TRUE;
  154. break;
  155. case Code::UNDEF_CTF_ID:
  156. bUndefCTFID = TRUE;
  157. break;
  158. case Code::UNDEF_CTF_ACKED:
  159. bUndefCTFAck = TRUE;
  160. break;
  161. case Code::UNDEF_AUTOZERO:
  162. bUndefAutoZero = TRUE;
  163. break;
  164. default:
  165. break;
  166. }
  167. }
  168. };
  169. public:
  170. // MSM Data Page 1
  171. USHORT usAcumTime1024; // Cumulative time (1/1024 s)
  172. USHORT usAcumDist10; // Accumulated Distance (0.1 m)
  173. USHORT usInstSpeed1000; // Instantaneous speed (0.001 m/s)
  174. // MSM Data Page 2
  175. SLONG slLatitude_SC; // Latitude (pi/2^27 radians)
  176. SLONG slLongitude_SC; // Longitude (pi/2^27 radians)
  177. BOOL bPage2Enabled; // Signals if page 2 is to be transmitted
  178. // MSM Data Page 3
  179. UCHAR ucFixType; // Current fix of GPS receiver
  180. USHORT usHeading10; // Heading of the user (0.1 degrees)
  181. USHORT usElevation5; // Elevation of position (0.2 m)
  182. BOOL bPage3Enabled; // Determines if page 3 is to be transmitted
  183. //MSMS Data Page 4
  184. USHORT usDistanceTwo; //Distance between 2nd and 1st Turn by Turn comamnds
  185. UCHAR ucTurnByTurnTwo; //Second turn by turn command required
  186. USHORT usDistanceOne; //Distance until 1st turn by turn command
  187. UCHAR ucTurnByTurnOne; //First turn by turn command required
  188. BOOL bPage4Enabled;
  189. // MSM Calibration Variables
  190. UCHAR ucMode; // The calibration mode (km/h)
  191. USHORT usScaleFactor10000; // Scale Factor of calibration (0.0001)
  192. // Error handling
  193. BOOL bValidation; // Turns validation on/off
  194. public:
  195. MSM()
  196. {
  197. bValidation = FALSE; // Validation is disabled by default
  198. //initialize variables to invalid if possible, otherwise 0
  199. usAcumTime1024 = 0;
  200. usAcumDist10 = 0;
  201. usInstSpeed1000 = INVALID_SPEED;
  202. slLatitude_SC = 0;
  203. slLongitude_SC = 0;
  204. ucFixType = 0;
  205. usHeading10 = INVALID_HEADING;
  206. usElevation5 = INVALID_ELEVATION;
  207. ucMode = CAL_MODE_INVALID;
  208. usScaleFactor10000 = CAL_SCALE_INVALID;
  209. bPage2Enabled = FALSE;
  210. bPage3Enabled = FALSE;
  211. bPage4Enabled = FALSE;
  212. usDistanceTwo = INVALID_DISTANCE;
  213. ucTurnByTurnTwo = 0;
  214. usDistanceOne = 0;
  215. ucTurnByTurnOne = 0;
  216. }
  217. ~MSM()
  218. {
  219. }
  220. public:
  221. /**************************************************************************
  222. * MSM::Decode
  223. *
  224. * Decodes all main data pages and calibration pages
  225. * Exceptions are thrown when dealing with non compliant pages
  226. *
  227. * pucRxBuffer_: pointer to the buffer containing the received data
  228. *
  229. * returns: N/A
  230. *
  231. **************************************************************************/
  232. void Decode(UCHAR* pucRxBuffer_)
  233. {
  234. switch(pucRxBuffer_[0])
  235. {
  236. case PAGE_1:
  237. // decode time and distance - required fields
  238. usAcumTime1024 = pucRxBuffer_[2] + (pucRxBuffer_[3] << BYTE_SHIFT);
  239. usAcumDist10 = pucRxBuffer_[4] + (pucRxBuffer_[5] << BYTE_SHIFT);
  240. // decode optional field - speed
  241. usInstSpeed1000 = pucRxBuffer_[6] + (pucRxBuffer_[7] << BYTE_SHIFT);
  242. // ensure the reserved fields are using the correct values
  243. if(pucRxBuffer_[1] != RESERVED && bValidation)
  244. {
  245. throw gcnew Error(Error::Code::INVALID_RESERVED); // Error: Invalid value in reserved field
  246. }
  247. break;
  248. case PAGE_2:
  249. bPage2Enabled = TRUE; // enable page 2 display
  250. // decode latitude
  251. slLatitude_SC = pucRxBuffer_[1] + (pucRxBuffer_[2] << LAT_BYTE_2_SHIFT) + (pucRxBuffer_[3] << LAT_BYTE_3_SHIFT) + (((pucRxBuffer_[4] & UPPER_NIBBLE_MASK) >> 4) << LAT_BYTE_4_SHIFT);
  252. // check if latitude is negative
  253. if (pucRxBuffer_[4] & NEGATIVE_BYTE_MASK)
  254. slLatitude_SC = slLatitude_SC | NEGATIVE_LONG_MASK;
  255. // decode longitude
  256. slLongitude_SC = (pucRxBuffer_[4] & LOWER_NIBBLE_MASK) + (pucRxBuffer_[5] << LON_BYTE_5_SHIFT) + (pucRxBuffer_[6] << LON_BYTE_6_SHIFT) + (pucRxBuffer_[7] << LON_BYTE_7_SHIFT);
  257. // check if longitude is negative
  258. if (pucRxBuffer_[7] & NEGATIVE_BYTE_MASK)
  259. slLongitude_SC = slLongitude_SC | NEGATIVE_LONG_MASK;
  260. break;
  261. case PAGE_3:
  262. bPage3Enabled = TRUE; // enabled page 3 display
  263. // decode fix type
  264. ucFixType = (pucRxBuffer_[4] & UPPER_NIBBLE_MASK) >> NIBBLE_SHIFT;
  265. // decode Heading and scale appropriatley
  266. usHeading10 = (pucRxBuffer_[4] & LOWER_NIBBLE_MASK) + (pucRxBuffer_[5] << NIBBLE_SHIFT);
  267. // decode Elevation and scale appropriately
  268. usElevation5 = pucRxBuffer_[6] + (pucRxBuffer_[7] << BYTE_SHIFT);
  269. // ensure the reserved fields are using the correct values
  270. for (int i = 1; i < 4; i++)
  271. {
  272. if(pucRxBuffer_[i] != RESERVED && bValidation)
  273. throw gcnew Error(Error::Code::INVALID_RESERVED); // Error: Invalid value in reserved field
  274. }
  275. break;
  276. case PAGE_4:
  277. bPage4Enabled = TRUE; //enable page 4 display
  278. usDistanceTwo = (pucRxBuffer_[3] << BYTE_SHIFT) | pucRxBuffer_[2];
  279. ucTurnByTurnTwo = pucRxBuffer_[4];
  280. usDistanceOne = (pucRxBuffer_[6] << BYTE_SHIFT) | pucRxBuffer_[5];
  281. ucTurnByTurnOne = pucRxBuffer_[7];
  282. break;
  283. case PAGE_CALIBRATION:
  284. // decode calibration mode and the scale factor
  285. ucMode = pucRxBuffer_[5];
  286. usScaleFactor10000 = pucRxBuffer_[6] + (pucRxBuffer_[7] << BYTE_SHIFT);
  287. // ensure the reserved fields are using the correct values
  288. for (int i = 1; i < 5; i++)
  289. {
  290. if(pucRxBuffer_[i] != RESERVED && bValidation)
  291. throw gcnew Error(Error::Code::INVALID_RESERVED); // Error: Invalid value in reserved field
  292. }
  293. break;
  294. default:
  295. break;
  296. }
  297. }
  298. /**************************************************************************
  299. * MSM::EncodeData
  300. *
  301. * Encodes the MSM data pages:
  302. * - Main data page 1 - time, distance, speed
  303. * - Calibration data page
  304. * - Secondary data pages - Lat/Long, Elevation/Heading
  305. *
  306. * Exceptions are thrown when dealing with invalid data
  307. *
  308. * ucPageNum_: number of page to encode
  309. * pucTxBuffer_: pointer to the buffer that will store the encoded data
  310. *
  311. * returns: N/A
  312. *
  313. **************************************************************************/
  314. void EncodeData(UCHAR ucPageNum_, UCHAR* pucTxBuffer_)
  315. {
  316. // need these variables so that the bit shifting does not get messed up when using negative values
  317. ULONG ulTempLat = slLatitude_SC;
  318. ULONG ulTempLon = slLongitude_SC;
  319. switch(ucPageNum_)
  320. {
  321. case PAGE_1:
  322. pucTxBuffer_[0] = ucPageNum_;
  323. pucTxBuffer_[1] = RESERVED;
  324. pucTxBuffer_[2] = usAcumTime1024 & BYTE_MASK; // Acumulated time in 1/1024 seconds
  325. pucTxBuffer_[3] = (usAcumTime1024 >> BYTE_SHIFT) & BYTE_MASK;
  326. pucTxBuffer_[4] = usAcumDist10 & BYTE_MASK; // Acumulated distance (0.1 m)
  327. pucTxBuffer_[5] = (usAcumDist10 >> BYTE_SHIFT) & BYTE_MASK;
  328. pucTxBuffer_[6] = usInstSpeed1000 & BYTE_MASK; // Instantaneous speed (0.001 m/s)
  329. pucTxBuffer_[7] = (usInstSpeed1000 >> BYTE_SHIFT) & BYTE_MASK;
  330. break;
  331. case PAGE_2:
  332. pucTxBuffer_[0] = ucPageNum_;
  333. pucTxBuffer_[1] = slLatitude_SC & BYTE_MASK; // Latitude in semicircles
  334. pucTxBuffer_[2] = (slLatitude_SC >> LAT_BYTE_2_SHIFT) & BYTE_MASK;
  335. pucTxBuffer_[3] = (slLatitude_SC >> LAT_BYTE_3_SHIFT) & BYTE_MASK;
  336. // byte 4 is the shared byte between lat and long
  337. if (slLatitude_SC < 0) // check if latitude is negative
  338. pucTxBuffer_[4] = (((((slLatitude_SC >> LAT_BYTE_4_SHIFT) & LOWER_NIBBLE_MASK) << NIBBLE_SHIFT) & UPPER_NIBBLE_MASK) | NEGATIVE_BYTE_MASK) + (ulTempLon & LOWER_NIBBLE_MASK);
  339. else
  340. pucTxBuffer_[4] = ((((slLatitude_SC >> LAT_BYTE_4_SHIFT) & LOWER_NIBBLE_MASK) << NIBBLE_SHIFT) & UPPER_NIBBLE_MASK) + (slLongitude_SC & LOWER_NIBBLE_MASK); // the shared byte between lat and long
  341. pucTxBuffer_[5] = (slLongitude_SC >> LON_BYTE_5_SHIFT) & BYTE_MASK; // Longitude in semicircles
  342. pucTxBuffer_[6] = (slLongitude_SC >> LON_BYTE_6_SHIFT) & BYTE_MASK;
  343. // check if longitude is negative
  344. if (slLongitude_SC < 0)
  345. pucTxBuffer_[7] = ((slLongitude_SC >> LON_BYTE_7_SHIFT) & BYTE_MASK) | NEGATIVE_BYTE_MASK;
  346. else
  347. pucTxBuffer_[7] = (slLongitude_SC >> LON_BYTE_7_SHIFT) & BYTE_MASK;
  348. break;
  349. case PAGE_3:
  350. pucTxBuffer_[0] = ucPageNum_;
  351. pucTxBuffer_[1] = RESERVED;
  352. pucTxBuffer_[2] = RESERVED;
  353. pucTxBuffer_[3] = RESERVED;
  354. pucTxBuffer_[4] = (ucFixType << NIBBLE_SHIFT) + (usHeading10 & LOWER_NIBBLE_MASK);
  355. pucTxBuffer_[5] = (usHeading10 & HEADING_MASK) >> NIBBLE_SHIFT;
  356. pucTxBuffer_[6] = usElevation5 & BYTE_MASK;
  357. pucTxBuffer_[7] = (usElevation5 >> BYTE_SHIFT) & BYTE_MASK;
  358. break;
  359. case PAGE_4:
  360. pucTxBuffer_[0] = ucPageNum_;
  361. pucTxBuffer_[1] = RESERVED;
  362. pucTxBuffer_[2] = usDistanceTwo & BYTE_MASK;
  363. pucTxBuffer_[3] = (usDistanceTwo >> BYTE_SHIFT) & BYTE_MASK;
  364. pucTxBuffer_[4] = ucTurnByTurnTwo;
  365. pucTxBuffer_[5] = usDistanceOne & BYTE_MASK;
  366. pucTxBuffer_[6] = (usDistanceOne >> BYTE_SHIFT) & BYTE_MASK;
  367. pucTxBuffer_[7] = ucTurnByTurnOne;
  368. break;
  369. case PAGE_CALIBRATION:
  370. pucTxBuffer_[0] = ucPageNum_;
  371. pucTxBuffer_[1] = RESERVED;
  372. pucTxBuffer_[2] = RESERVED;
  373. pucTxBuffer_[3] = RESERVED;
  374. pucTxBuffer_[4] = RESERVED;
  375. pucTxBuffer_[5] = ucMode;
  376. pucTxBuffer_[6] = usScaleFactor10000 & BYTE_MASK;
  377. pucTxBuffer_[7] = (usScaleFactor10000 >> BYTE_SHIFT) & BYTE_MASK;
  378. break;
  379. default:
  380. break;
  381. }
  382. }
  383. /**************************************************************************
  384. * MSM::IsSpeedValid
  385. *
  386. * Checks if the speed value is invalid
  387. *
  388. * usSpeed1000_: speed (m/s)
  389. *
  390. * returns: TRUE if speed is valid, FALSE otherwise
  391. *
  392. **************************************************************************/
  393. BOOL IsSpeedValid(USHORT usSpeed1000_)
  394. {
  395. if(usSpeed1000_ == INVALID_SPEED)
  396. return FALSE;
  397. else
  398. return TRUE;
  399. }
  400. /**************************************************************************
  401. * MSM::IsFixTypeValid
  402. *
  403. * Checks if the fix type is invalid
  404. *
  405. * ucFixType_: GPS Fix Type
  406. *
  407. * returns: TRUE if fix type is valid, FALSE otherwise
  408. *
  409. **************************************************************************/
  410. BOOL IsFixTypeValid(UCHAR ucFixType_)
  411. {
  412. if(ucFixType_ == 0x0F)//MSM::GpsFix::INVALID)
  413. return FALSE;
  414. else
  415. return TRUE;
  416. }
  417. /**************************************************************************
  418. * MSM::IsHeadingValid
  419. *
  420. * Checks if the heading is invalid
  421. *
  422. * usHeading10_: 0.1 degrees
  423. *
  424. * returns: TRUE if heading is valid, false otherwise
  425. *
  426. **************************************************************************/
  427. BOOL IsHeadingValid()
  428. {
  429. if(usHeading10 == INVALID_HEADING)
  430. return FALSE;
  431. else
  432. return TRUE;
  433. }
  434. /**************************************************************************
  435. * MSM::IsElevationValid
  436. *
  437. * Checks if the elvation is invalid
  438. *
  439. * usElevation5_: 0.2 m
  440. *
  441. * returns: TRUE if elevation is valid, FALSE otherwise
  442. *
  443. **************************************************************************/
  444. BOOL IsElevationValid()
  445. {
  446. if(usElevation5 == INVALID_ELEVATION)
  447. return FALSE;
  448. else
  449. return TRUE;
  450. }
  451. /**************************************************************************
  452. * MSM::IsCalModeValid
  453. *
  454. * Checks if the calibration mode is invalid
  455. *
  456. * ucCalMode_: mode (km/h)
  457. *
  458. * returns: TRUE if calibration mode is valid, FALSE otherwise
  459. *
  460. **************************************************************************/
  461. BOOL IsCalModeValid(UCHAR ucCalMode_)
  462. {
  463. if(ucCalMode_ == CAL_MODE_INVALID)
  464. return FALSE;
  465. else
  466. return TRUE;
  467. }
  468. /**************************************************************************
  469. * MSM::IsCalScaleValid
  470. *
  471. * Checks if the scale factor is invalid
  472. *
  473. * usCalScale10000_: scale factor
  474. *
  475. * returns: TRUE if the scale factor is valid, FALSE otherwise
  476. *
  477. **************************************************************************/
  478. BOOL IsCalScaleValid(USHORT usCalScale10000_)
  479. {
  480. if(usCalScale10000_ == CAL_SCALE_INVALID)
  481. return FALSE;
  482. else
  483. return TRUE;
  484. }
  485. BOOL IsDistanceValid(USHORT usDistance_)
  486. {
  487. if(usDistance_ == INVALID_DISTANCE)
  488. return FALSE;
  489. else
  490. return TRUE;
  491. }
  492. };