123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565 |
- /*
- This software is subject to the license described in the License.txt file
- included with this software distribution. You may not use this file except in compliance
- with this license.
- Copyright (c) Dynastream Innovations Inc. 2012
- All rights reserved.
- */
-
- #pragma once
- #include "types.h"
- #define MSM_REV 1.0 // Device Profile Revision Number
- public ref class MSM
- {
- public:
- // Channel Parameters
- static const UCHAR DEVICE_TYPE = 15;
- static const UCHAR TX_TYPE = 5;
- static const USHORT MSG_PERIOD = 8192; // 4 Hz
- static const USHORT HALF_PERIOD = 16384; // 2 Hz
-
- // Data Pages
- static const UCHAR PAGE_1 = 0x01;
- static const UCHAR PAGE_2 = 0x02;
- static const UCHAR PAGE_3 = 0x03;
- static const UCHAR PAGE_4 = 0x04;
- static const UCHAR PAGE_CALIBRATION = 0x30;
- // Calibration Messages
- static const USHORT CAL_SCALE_CONF = 0x2710; // this translates to 10000 or 1.0000 for a scale factor
- static const USHORT CAL_SCALE_REQUEST = 0x0000;
- static const USHORT CAL_SCALE_INVALID = 0xFFFF;
- static const USHORT CAL_SF_SCALE_FACTOR = 10000;
- static const UCHAR CAL_MODE_INVALID = 0xFF;
- // Acknowledged Messages
- static const UCHAR ACK_FAIL = 0;
- static const UCHAR ACK_SUCCESS = 1;
-
- // Reserved/invalid/special values
- static const UCHAR RESERVED = 0xFF;
- static const USHORT INVALID_SPEED = 0xFFFF;
- static const USHORT INVALID_HEADING = 0x0FFF;
- static const USHORT INVALID_ELEVATION = 0xFFFF;
- static const USHORT INVALID_DISTANCE = 0xFFFF;
- static const USHORT MAX_SPEED = 0xFFFE;
- // Bit Masks
- static const UCHAR BYTE_MASK = 0xFF;
- static const UCHAR UPPER_NIBBLE_MASK = 0xF0;
- static const UCHAR LOWER_NIBBLE_MASK = 0x0F;
- static const UCHAR NEGATIVE_BYTE_MASK = 0x80;
- static const UCHAR REMOVE_SIGNED_BIT_MASK = 0x7F;
- static const USHORT HEADING_MASK = 0x0FF0;
- static const ULONG NEGATIVE_LONG_MASK = 0xF0000000;
- // Bit shifts
- static const UCHAR NIBBLE_SHIFT = 4;
- static const UCHAR BYTE_SHIFT = 8;
- static const UCHAR LAT_BYTE_2_SHIFT = 8;
- static const UCHAR LAT_BYTE_3_SHIFT = 16;
- static const UCHAR LAT_BYTE_4_SHIFT = 24;
- static const UCHAR LON_BYTE_5_SHIFT = 4;
- static const UCHAR LON_BYTE_6_SHIFT = 12;
- static const UCHAR LON_BYTE_7_SHIFT = 20;
- //Scale and offset Factors
- static const USHORT TIME_SCALE_FACTOR = 1024;
- static const UCHAR DIST_SCALE_FACTOR = 10;
- static const USHORT SPEED_SCALE_FACTOR = 1000;
- static const UCHAR HEADING_SCALE_FACTOR = 10;
- static const UCHAR ELEVATION_SCALE_FACTOR = 5;
- static const USHORT ELEVATION_OFFSET = 500;
- static const DOUBLE SEMI_CIRCLE_CONVERSION = System::Math::Pow(2.0, 27) / 180; // conversion to semicircles from degrees
- enum class GpsFix : UCHAR
- {
- NONE,
- SEARCHING,
- PROPAGATING,
- LAST_KNOWN,
- TWO_D,
- TWO_D_WAAS,
- TWO_D_DIF,
- THREE_D,
- THREE_D_WAAS,
- THREE_D_DIF,
- INVALID = 0x0F
- };
- enum class TurnByTurns : UCHAR
- {
- DESTINATION,
- TURN,
- HARD_TURN,
- SLIGHT_TURN,
- U_TURN,
- EXIT,
- LEFT_MASK = 0x80,
- RIGHT_MASK = 0x7F,
- };
- enum class CalibrationStatus : UCHAR
- {
- NONE,
- REQUEST_IN_PROGRESS,
- SET_SCALE_IN_PROGRESS,
- COMPLETE
- };
- // Error handling
- // Flags indicate errors causing the exception
- ref class Error : public System::Exception{
- public:
- BOOL bBadReserved; // Invalid values on reserved fields
- BOOL bUndefPage; // Undefined page
- BOOL bUndefCalID; // Undefined calibration message ID
- BOOL bUndefCTFID; // Undefined CTF calibration message ID
- BOOL bUndefCTFAck; // Undefined CTF Acked message
- BOOL bUndefAutoZero; // Undefined auto zero status
- enum class Code : UCHAR // Error code definitions
- {
- INVALID_RESERVED, // Invalid value in reserved field
- UNDEF_PAGE, // Undefined data page
- UNDEF_CAL_ID, // Undefined calibration message ID
- UNDEF_CTF_ID, // Undefined CTF calibration message ID
- UNDEF_CTF_ACKED, // Undefined CTF acked message
- UNDEF_AUTOZERO, // Invalid auto zero status
- };
- Error()
- {
- ClearFlags();
- }
- Error(Code eCode1_)
- {
- ClearFlags();
- SetFlags(eCode1_);
- }
- Error(Code eCode1_, Code eCode2_)
- {
- ClearFlags();
- SetFlags(eCode1_);
- SetFlags(eCode2_);
- }
- private:
- void ClearFlags()
- {
- bBadReserved = FALSE;
- bUndefPage = FALSE;
- bUndefCalID = FALSE;
- bUndefCTFID = FALSE;
- bUndefCTFAck = FALSE;
- bUndefAutoZero = FALSE;
- }
- void SetFlags(Code eCode_)
- {
- switch(eCode_)
- {
- case Code::INVALID_RESERVED:
- bBadReserved = TRUE;
- break;
- case Code::UNDEF_PAGE:
- bUndefPage = TRUE;
- break;
- case Code::UNDEF_CAL_ID:
- bUndefCalID = TRUE;
- break;
- case Code::UNDEF_CTF_ID:
- bUndefCTFID = TRUE;
- break;
- case Code::UNDEF_CTF_ACKED:
- bUndefCTFAck = TRUE;
- break;
- case Code::UNDEF_AUTOZERO:
- bUndefAutoZero = TRUE;
- break;
- default:
- break;
- }
- }
- };
- public:
- // MSM Data Page 1
- USHORT usAcumTime1024; // Cumulative time (1/1024 s)
- USHORT usAcumDist10; // Accumulated Distance (0.1 m)
- USHORT usInstSpeed1000; // Instantaneous speed (0.001 m/s)
- // MSM Data Page 2
- SLONG slLatitude_SC; // Latitude (pi/2^27 radians)
- SLONG slLongitude_SC; // Longitude (pi/2^27 radians)
- BOOL bPage2Enabled; // Signals if page 2 is to be transmitted
- // MSM Data Page 3
- UCHAR ucFixType; // Current fix of GPS receiver
- USHORT usHeading10; // Heading of the user (0.1 degrees)
- USHORT usElevation5; // Elevation of position (0.2 m)
- BOOL bPage3Enabled; // Determines if page 3 is to be transmitted
- //MSMS Data Page 4
- USHORT usDistanceTwo; //Distance between 2nd and 1st Turn by Turn comamnds
- UCHAR ucTurnByTurnTwo; //Second turn by turn command required
- USHORT usDistanceOne; //Distance until 1st turn by turn command
- UCHAR ucTurnByTurnOne; //First turn by turn command required
- BOOL bPage4Enabled;
- // MSM Calibration Variables
- UCHAR ucMode; // The calibration mode (km/h)
- USHORT usScaleFactor10000; // Scale Factor of calibration (0.0001)
- // Error handling
- BOOL bValidation; // Turns validation on/off
- public:
- MSM()
- {
- bValidation = FALSE; // Validation is disabled by default
- //initialize variables to invalid if possible, otherwise 0
- usAcumTime1024 = 0;
- usAcumDist10 = 0;
- usInstSpeed1000 = INVALID_SPEED;
- slLatitude_SC = 0;
- slLongitude_SC = 0;
- ucFixType = 0;
- usHeading10 = INVALID_HEADING;
- usElevation5 = INVALID_ELEVATION;
- ucMode = CAL_MODE_INVALID;
- usScaleFactor10000 = CAL_SCALE_INVALID;
- bPage2Enabled = FALSE;
- bPage3Enabled = FALSE;
- bPage4Enabled = FALSE;
- usDistanceTwo = INVALID_DISTANCE;
- ucTurnByTurnTwo = 0;
- usDistanceOne = 0;
- ucTurnByTurnOne = 0;
- }
- ~MSM()
- {
- }
- public:
- /**************************************************************************
- * MSM::Decode
- *
- * Decodes all main data pages and calibration pages
- * Exceptions are thrown when dealing with non compliant pages
- *
- * pucRxBuffer_: pointer to the buffer containing the received data
- *
- * returns: N/A
- *
- **************************************************************************/
- void Decode(UCHAR* pucRxBuffer_)
- {
- switch(pucRxBuffer_[0])
- {
- case PAGE_1:
- // decode time and distance - required fields
- usAcumTime1024 = pucRxBuffer_[2] + (pucRxBuffer_[3] << BYTE_SHIFT);
- usAcumDist10 = pucRxBuffer_[4] + (pucRxBuffer_[5] << BYTE_SHIFT);
- // decode optional field - speed
- usInstSpeed1000 = pucRxBuffer_[6] + (pucRxBuffer_[7] << BYTE_SHIFT);
- // ensure the reserved fields are using the correct values
- if(pucRxBuffer_[1] != RESERVED && bValidation)
- {
- throw gcnew Error(Error::Code::INVALID_RESERVED); // Error: Invalid value in reserved field
- }
-
- break;
- case PAGE_2:
- bPage2Enabled = TRUE; // enable page 2 display
- // decode latitude
- 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);
- // check if latitude is negative
- if (pucRxBuffer_[4] & NEGATIVE_BYTE_MASK)
- slLatitude_SC = slLatitude_SC | NEGATIVE_LONG_MASK;
- // decode longitude
- 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);
- // check if longitude is negative
- if (pucRxBuffer_[7] & NEGATIVE_BYTE_MASK)
- slLongitude_SC = slLongitude_SC | NEGATIVE_LONG_MASK;
-
- break;
- case PAGE_3:
- bPage3Enabled = TRUE; // enabled page 3 display
- // decode fix type
- ucFixType = (pucRxBuffer_[4] & UPPER_NIBBLE_MASK) >> NIBBLE_SHIFT;
- // decode Heading and scale appropriatley
- usHeading10 = (pucRxBuffer_[4] & LOWER_NIBBLE_MASK) + (pucRxBuffer_[5] << NIBBLE_SHIFT);
- // decode Elevation and scale appropriately
- usElevation5 = pucRxBuffer_[6] + (pucRxBuffer_[7] << BYTE_SHIFT);
- // ensure the reserved fields are using the correct values
- for (int i = 1; i < 4; i++)
- {
- if(pucRxBuffer_[i] != RESERVED && bValidation)
- throw gcnew Error(Error::Code::INVALID_RESERVED); // Error: Invalid value in reserved field
- }
- break;
- case PAGE_4:
- bPage4Enabled = TRUE; //enable page 4 display
- usDistanceTwo = (pucRxBuffer_[3] << BYTE_SHIFT) | pucRxBuffer_[2];
- ucTurnByTurnTwo = pucRxBuffer_[4];
- usDistanceOne = (pucRxBuffer_[6] << BYTE_SHIFT) | pucRxBuffer_[5];
- ucTurnByTurnOne = pucRxBuffer_[7];
- break;
- case PAGE_CALIBRATION:
- // decode calibration mode and the scale factor
- ucMode = pucRxBuffer_[5];
- usScaleFactor10000 = pucRxBuffer_[6] + (pucRxBuffer_[7] << BYTE_SHIFT);
- // ensure the reserved fields are using the correct values
- for (int i = 1; i < 5; i++)
- {
- if(pucRxBuffer_[i] != RESERVED && bValidation)
- throw gcnew Error(Error::Code::INVALID_RESERVED); // Error: Invalid value in reserved field
- }
- break;
- default:
- break;
- }
- }
-
- /**************************************************************************
- * MSM::EncodeData
- *
- * Encodes the MSM data pages:
- * - Main data page 1 - time, distance, speed
- * - Calibration data page
- * - Secondary data pages - Lat/Long, Elevation/Heading
- *
- * Exceptions are thrown when dealing with invalid data
- *
- * ucPageNum_: number of page to encode
- * pucTxBuffer_: pointer to the buffer that will store the encoded data
- *
- * returns: N/A
- *
- **************************************************************************/
- void EncodeData(UCHAR ucPageNum_, UCHAR* pucTxBuffer_)
- {
- // need these variables so that the bit shifting does not get messed up when using negative values
- ULONG ulTempLat = slLatitude_SC;
- ULONG ulTempLon = slLongitude_SC;
- switch(ucPageNum_)
- {
- case PAGE_1:
- pucTxBuffer_[0] = ucPageNum_;
- pucTxBuffer_[1] = RESERVED;
- pucTxBuffer_[2] = usAcumTime1024 & BYTE_MASK; // Acumulated time in 1/1024 seconds
- pucTxBuffer_[3] = (usAcumTime1024 >> BYTE_SHIFT) & BYTE_MASK;
- pucTxBuffer_[4] = usAcumDist10 & BYTE_MASK; // Acumulated distance (0.1 m)
- pucTxBuffer_[5] = (usAcumDist10 >> BYTE_SHIFT) & BYTE_MASK;
- pucTxBuffer_[6] = usInstSpeed1000 & BYTE_MASK; // Instantaneous speed (0.001 m/s)
- pucTxBuffer_[7] = (usInstSpeed1000 >> BYTE_SHIFT) & BYTE_MASK;
- break;
- case PAGE_2:
- pucTxBuffer_[0] = ucPageNum_;
- pucTxBuffer_[1] = slLatitude_SC & BYTE_MASK; // Latitude in semicircles
- pucTxBuffer_[2] = (slLatitude_SC >> LAT_BYTE_2_SHIFT) & BYTE_MASK;
- pucTxBuffer_[3] = (slLatitude_SC >> LAT_BYTE_3_SHIFT) & BYTE_MASK;
- // byte 4 is the shared byte between lat and long
- if (slLatitude_SC < 0) // check if latitude is negative
- pucTxBuffer_[4] = (((((slLatitude_SC >> LAT_BYTE_4_SHIFT) & LOWER_NIBBLE_MASK) << NIBBLE_SHIFT) & UPPER_NIBBLE_MASK) | NEGATIVE_BYTE_MASK) + (ulTempLon & LOWER_NIBBLE_MASK);
- else
- 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
-
- pucTxBuffer_[5] = (slLongitude_SC >> LON_BYTE_5_SHIFT) & BYTE_MASK; // Longitude in semicircles
- pucTxBuffer_[6] = (slLongitude_SC >> LON_BYTE_6_SHIFT) & BYTE_MASK;
- // check if longitude is negative
- if (slLongitude_SC < 0)
- pucTxBuffer_[7] = ((slLongitude_SC >> LON_BYTE_7_SHIFT) & BYTE_MASK) | NEGATIVE_BYTE_MASK;
- else
- pucTxBuffer_[7] = (slLongitude_SC >> LON_BYTE_7_SHIFT) & BYTE_MASK;
- break;
- case PAGE_3:
- pucTxBuffer_[0] = ucPageNum_;
- pucTxBuffer_[1] = RESERVED;
- pucTxBuffer_[2] = RESERVED;
- pucTxBuffer_[3] = RESERVED;
- pucTxBuffer_[4] = (ucFixType << NIBBLE_SHIFT) + (usHeading10 & LOWER_NIBBLE_MASK);
- pucTxBuffer_[5] = (usHeading10 & HEADING_MASK) >> NIBBLE_SHIFT;
- pucTxBuffer_[6] = usElevation5 & BYTE_MASK;
- pucTxBuffer_[7] = (usElevation5 >> BYTE_SHIFT) & BYTE_MASK;
- break;
- case PAGE_4:
- pucTxBuffer_[0] = ucPageNum_;
- pucTxBuffer_[1] = RESERVED;
- pucTxBuffer_[2] = usDistanceTwo & BYTE_MASK;
- pucTxBuffer_[3] = (usDistanceTwo >> BYTE_SHIFT) & BYTE_MASK;
- pucTxBuffer_[4] = ucTurnByTurnTwo;
- pucTxBuffer_[5] = usDistanceOne & BYTE_MASK;
- pucTxBuffer_[6] = (usDistanceOne >> BYTE_SHIFT) & BYTE_MASK;
- pucTxBuffer_[7] = ucTurnByTurnOne;
- break;
- case PAGE_CALIBRATION:
- pucTxBuffer_[0] = ucPageNum_;
- pucTxBuffer_[1] = RESERVED;
- pucTxBuffer_[2] = RESERVED;
- pucTxBuffer_[3] = RESERVED;
- pucTxBuffer_[4] = RESERVED;
- pucTxBuffer_[5] = ucMode;
- pucTxBuffer_[6] = usScaleFactor10000 & BYTE_MASK;
- pucTxBuffer_[7] = (usScaleFactor10000 >> BYTE_SHIFT) & BYTE_MASK;
- break;
- default:
- break;
- }
- }
- /**************************************************************************
- * MSM::IsSpeedValid
- *
- * Checks if the speed value is invalid
- *
- * usSpeed1000_: speed (m/s)
- *
- * returns: TRUE if speed is valid, FALSE otherwise
- *
- **************************************************************************/
- BOOL IsSpeedValid(USHORT usSpeed1000_)
- {
- if(usSpeed1000_ == INVALID_SPEED)
- return FALSE;
- else
- return TRUE;
- }
- /**************************************************************************
- * MSM::IsFixTypeValid
- *
- * Checks if the fix type is invalid
- *
- * ucFixType_: GPS Fix Type
- *
- * returns: TRUE if fix type is valid, FALSE otherwise
- *
- **************************************************************************/
- BOOL IsFixTypeValid(UCHAR ucFixType_)
- {
- if(ucFixType_ == 0x0F)//MSM::GpsFix::INVALID)
- return FALSE;
- else
- return TRUE;
- }
- /**************************************************************************
- * MSM::IsHeadingValid
- *
- * Checks if the heading is invalid
- *
- * usHeading10_: 0.1 degrees
- *
- * returns: TRUE if heading is valid, false otherwise
- *
- **************************************************************************/
- BOOL IsHeadingValid()
- {
- if(usHeading10 == INVALID_HEADING)
- return FALSE;
- else
- return TRUE;
- }
- /**************************************************************************
- * MSM::IsElevationValid
- *
- * Checks if the elvation is invalid
- *
- * usElevation5_: 0.2 m
- *
- * returns: TRUE if elevation is valid, FALSE otherwise
- *
- **************************************************************************/
- BOOL IsElevationValid()
- {
- if(usElevation5 == INVALID_ELEVATION)
- return FALSE;
- else
- return TRUE;
- }
- /**************************************************************************
- * MSM::IsCalModeValid
- *
- * Checks if the calibration mode is invalid
- *
- * ucCalMode_: mode (km/h)
- *
- * returns: TRUE if calibration mode is valid, FALSE otherwise
- *
- **************************************************************************/
- BOOL IsCalModeValid(UCHAR ucCalMode_)
- {
- if(ucCalMode_ == CAL_MODE_INVALID)
- return FALSE;
- else
- return TRUE;
- }
- /**************************************************************************
- * MSM::IsCalScaleValid
- *
- * Checks if the scale factor is invalid
- *
- * usCalScale10000_: scale factor
- *
- * returns: TRUE if the scale factor is valid, FALSE otherwise
- *
- **************************************************************************/
- BOOL IsCalScaleValid(USHORT usCalScale10000_)
- {
- if(usCalScale10000_ == CAL_SCALE_INVALID)
- return FALSE;
- else
- return TRUE;
- }
- BOOL IsDistanceValid(USHORT usDistance_)
- {
- if(usDistance_ == INVALID_DISTANCE)
- return FALSE;
- else
- return TRUE;
- }
- };
|