positioning updates
Fork of gnss by
TESTS/unit_tests/default/main.cpp@1:ef70a58a6c98, 2017-04-10 (annotated)
- Committer:
- rob.meades@u-blox.com
- Date:
- Mon Apr 10 11:28:24 2017 +0100
- Revision:
- 1:ef70a58a6c98
- Child:
- 6:56eda66d585b
Add files to repo, removing temp.txt placeholder.
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
rob.meades@u-blox.com | 1:ef70a58a6c98 | 1 | #include "mbed.h" |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 2 | #include "greentea-client/test_env.h" |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 3 | #include "unity.h" |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 4 | #include "utest.h" |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 5 | #include "gnss.h" |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 6 | extern "C" { |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 7 | #include "c030_api.h" |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 8 | } |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 9 | |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 10 | using namespace utest::v1; |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 11 | |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 12 | // ---------------------------------------------------------------- |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 13 | // COMPILE-TIME MACROS |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 14 | // ---------------------------------------------------------------- |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 15 | |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 16 | // How long to wait for a GNSS result |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 17 | #define GNSS_WAIT_SECONDS 120 |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 18 | |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 19 | // ---------------------------------------------------------------- |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 20 | // PRIVATE VARIABLES |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 21 | // ---------------------------------------------------------------- |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 22 | |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 23 | // ---------------------------------------------------------------- |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 24 | // PRIVATE FUNCTIONS |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 25 | // ---------------------------------------------------------------- |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 26 | |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 27 | static void printHex (char * pData, uint32_t lenData) |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 28 | { |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 29 | char * pEnd = pData + lenData; |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 30 | uint8_t x; |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 31 | |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 32 | printf (" 0 1 2 3 4 5 6 7 8 9 A B C D E F\n"); |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 33 | while (pData < pEnd) { |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 34 | for (x = 1; (x <= 32) && (pData < pEnd); x++) { |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 35 | if (x % 16 == 8) { |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 36 | printf ("%02x ", *pData); |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 37 | } else if (x % 16 == 0) { |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 38 | printf ("%02x\n", *pData); |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 39 | } else { |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 40 | printf ("%02x-", *pData); |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 41 | } |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 42 | pData++; |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 43 | } |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 44 | |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 45 | |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 46 | if (x % 16 != 1) { |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 47 | printf("\n"); |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 48 | } |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 49 | } |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 50 | } |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 51 | |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 52 | // ---------------------------------------------------------------- |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 53 | // TESTS |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 54 | // ---------------------------------------------------------------- |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 55 | |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 56 | // Test sending a u-blox command over serial |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 57 | void test_serial_ubx() { |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 58 | char buffer[64]; |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 59 | int responseLength = 0; |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 60 | int returnCode; |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 61 | |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 62 | GnssSerial *pGnss = new GnssSerial(); |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 63 | |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 64 | // Initialise the GNSS chip and wait for it to start up |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 65 | pGnss->init(NC); |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 66 | wait_ms(1000); |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 67 | |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 68 | // See ublox7-V14_ReceiverDescrProtSpec section 30.11.15 (CFG-NAV5) |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 69 | // Set automotive mode, which should be acknowledged |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 70 | memset (buffer, 0, sizeof (buffer)); |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 71 | buffer[0] = 0x00; |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 72 | buffer[1] = 0x01; // Set dynamic config only |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 73 | buffer[2] = 0x04; // Automotive |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 74 | // Send length is 32 bytes of payload + 6 bytes header + 2 bytes CRC |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 75 | TEST_ASSERT_EQUAL_INT (40, pGnss->sendUbx(0x06, 0x24, buffer, 32)); |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 76 | while (responseLength == 0) { |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 77 | // Wait for the required Ack |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 78 | returnCode = pGnss->getMessage(buffer, sizeof(buffer)); |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 79 | if ((returnCode != GnssSerial::WAIT) && (returnCode != GnssSerial::NOT_FOUND)) { |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 80 | responseLength = LENGTH(returnCode); |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 81 | if ((PROTOCOL(returnCode) == GnssSerial::UBX)) { |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 82 | printHex(buffer, responseLength); |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 83 | // Ack is 0xb5-62-05-00-02-00-msgclass-msgid-crcA-crcB |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 84 | // Nack is 0xb5-62-05-01-02-00-msgclass-msgid-crcA-crcB |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 85 | TEST_ASSERT_EQUAL_UINT8(0xb5, buffer[0]); |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 86 | TEST_ASSERT_EQUAL_UINT8(0x62, buffer[1]); |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 87 | TEST_ASSERT_EQUAL_UINT8(0x05, buffer[2]); |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 88 | TEST_ASSERT_EQUAL_UINT8(0x00, buffer[3]); |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 89 | TEST_ASSERT_EQUAL_UINT8(0x02, buffer[4]); |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 90 | TEST_ASSERT_EQUAL_UINT8(0x00, buffer[5]); |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 91 | TEST_ASSERT_EQUAL_UINT8(0x06, buffer[6]); |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 92 | TEST_ASSERT_EQUAL_UINT8(0x24, buffer[7]); |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 93 | } else if ((PROTOCOL(returnCode) == GnssSerial::NMEA)) { |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 94 | printf ("%.*s", responseLength, buffer); |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 95 | responseLength = 0; |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 96 | } else { |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 97 | printHex(buffer, responseLength); |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 98 | responseLength = 0; |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 99 | } |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 100 | } |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 101 | wait_ms (100); |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 102 | } |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 103 | } |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 104 | |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 105 | // Test getting a response from GNSS using the serial interface |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 106 | void test_serial_time() { |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 107 | GnssSerial *pGnss = new GnssSerial(); |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 108 | |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 109 | bool gotLatLong = false; |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 110 | bool gotElevation = false; |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 111 | bool gotSpeed = false; |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 112 | bool gotTime = false; |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 113 | char buffer[256]; |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 114 | int returnCode; |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 115 | double latitude; |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 116 | double longitude; |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 117 | double elevation; |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 118 | double speed; |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 119 | |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 120 | printf("GNSS: powering up and waiting up to %d second(s) for something to happen.\n", GNSS_WAIT_SECONDS); |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 121 | pGnss->init(); |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 122 | |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 123 | memset(buffer, 0, sizeof(buffer)); |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 124 | for (uint32_t x = 0; (x < GNSS_WAIT_SECONDS) && !gotTime; x++) |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 125 | { |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 126 | while (((returnCode = pGnss->getMessage(buffer, sizeof(buffer))) > 0) && |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 127 | !(gotLatLong && gotElevation && gotSpeed && gotTime)) |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 128 | { |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 129 | int32_t length = LENGTH(returnCode); |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 130 | |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 131 | if ((PROTOCOL(returnCode) == GnssParser::NMEA) && (length > 6)) |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 132 | { |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 133 | printf("."); |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 134 | |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 135 | // talker is $GA=Galileo $GB=Beidou $GL=Glonass $GN=Combined $GP=GNSS |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 136 | if ((buffer[0] == '$') || buffer[1] == 'G') |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 137 | { |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 138 | #define _CHECK_TALKER(s) ((buffer[3] == s[0]) && (buffer[4] == s[1]) && (buffer[5] == s[2])) |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 139 | if (_CHECK_TALKER("GLL")) |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 140 | { |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 141 | char ch; |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 142 | |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 143 | if (pGnss->getNmeaAngle(1, buffer, length, latitude) && |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 144 | pGnss->getNmeaAngle(3, buffer, length, longitude) && |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 145 | pGnss->getNmeaItem(6, buffer, length, ch) && |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 146 | ch == 'A') |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 147 | { |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 148 | gotLatLong = true; |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 149 | latitude *= 60000; |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 150 | longitude *= 60000; |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 151 | printf("\nGNSS: location %.5f %.5f %c.\n", latitude, longitude, ch); |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 152 | } |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 153 | } |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 154 | else if (_CHECK_TALKER("GGA") || _CHECK_TALKER("GNS")) |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 155 | { |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 156 | const char *pTimeString = NULL; |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 157 | |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 158 | // Retrieve the time |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 159 | pTimeString = pGnss->findNmeaItemPos(1, buffer, buffer + length); |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 160 | if (pTimeString != NULL) |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 161 | { |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 162 | gotTime = true; |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 163 | printf("\nGNSS: time is %.6s.", pTimeString); |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 164 | } |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 165 | |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 166 | if (pGnss->getNmeaItem(9, buffer, length, elevation)) // altitude msl [m] |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 167 | { |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 168 | gotElevation = true; |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 169 | printf("\nGNSS: elevation: %.1f.", elevation); |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 170 | } |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 171 | } |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 172 | else if (_CHECK_TALKER("VTG")) |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 173 | { |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 174 | if (pGnss->getNmeaItem(7, buffer, length, speed)) // speed [km/h] |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 175 | { |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 176 | gotSpeed = true; |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 177 | printf("\nGNSS: speed: %.1f.", speed); |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 178 | } |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 179 | } |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 180 | } |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 181 | } |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 182 | } |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 183 | |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 184 | wait_ms(1000); |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 185 | } |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 186 | |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 187 | printf("\n"); |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 188 | |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 189 | // Depending on antenna positioning we may not be able to get a GNSS fix but we |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 190 | // should at least be able to receive the time from a satellite |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 191 | TEST_ASSERT(gotTime); |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 192 | } |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 193 | |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 194 | // ---------------------------------------------------------------- |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 195 | // TEST ENVIRONMENT |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 196 | // ---------------------------------------------------------------- |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 197 | |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 198 | // Setup the test environment |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 199 | utest::v1::status_t test_setup(const size_t number_of_cases) { |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 200 | // Setup Greentea with a timeout |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 201 | GREENTEA_SETUP(120, "default_auto"); |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 202 | return verbose_test_setup_handler(number_of_cases); |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 203 | } |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 204 | |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 205 | // Test cases |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 206 | Case cases[] = { |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 207 | Case("Ubx command", test_serial_ubx), |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 208 | Case("Get time", test_serial_time), |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 209 | }; |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 210 | |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 211 | Specification specification(test_setup, cases); |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 212 | |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 213 | // ---------------------------------------------------------------- |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 214 | // MAIN |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 215 | // ---------------------------------------------------------------- |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 216 | |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 217 | int main() { |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 218 | |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 219 | c030_init(); // HACK |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 220 | |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 221 | return !Harness::run(specification); |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 222 | } |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 223 | |
rob.meades@u-blox.com | 1:ef70a58a6c98 | 224 | // End Of File |