@@ -55,6 +55,7 @@ SFE_UBLOX_GNSS::SFE_UBLOX_GNSS(void)
55
55
_processNMEA.all = SFE_UBLOX_FILTER_NMEA_ALL; // Default to passing all NMEA messages to processNMEA
56
56
57
57
// Support for platforms like ESP32 which do not support multiple I2C restarts
58
+ // If _i2cStopRestart is true, endTransmission will always use a stop. If false, a restart will be used where needed.
58
59
#if defined(ARDUINO_ARCH_ESP32)
59
60
_i2cStopRestart = true; // Always use a stop
60
61
#else
@@ -725,7 +726,7 @@ boolean SFE_UBLOX_GNSS::checkUbloxI2C(ubxPacket *incomingUBX, uint8_t requestedC
725
726
uint16_t bytesAvailable = 0;
726
727
_i2cPort->beginTransmission(_gpsI2Caddress);
727
728
_i2cPort->write(0xFD); //0xFD (MSB) and 0xFE (LSB) are the registers that contain number of bytes available
728
- uint8_t i2cError = _i2cPort->endTransmission (false ); // Always send a restart command. Do not release bus. ESP32 supports this.
729
+ uint8_t i2cError = _i2cPort->endTransmission(false); //Always send a restart command. Do not release the bus. ESP32 supports this.
729
730
if (i2cError != 0)
730
731
{
731
732
if ((_printDebug == true) || (_printLimitedDebug == true)) // This is important. Print this if doing limited debugging
@@ -736,7 +737,8 @@ boolean SFE_UBLOX_GNSS::checkUbloxI2C(ubxPacket *incomingUBX, uint8_t requestedC
736
737
return (false); //Sensor did not ACK
737
738
}
738
739
739
- uint8_t bytesReturned = _i2cPort->requestFrom ((uint8_t )_gpsI2Caddress, (uint8_t )2 ); // TO DO: add _i2cStopRestart here
740
+ //Forcing requestFrom to use a restart would be unwise. If bytesAvailable is zero, we want to surrender the bus.
741
+ uint8_t bytesReturned = _i2cPort->requestFrom((uint8_t)_gpsI2Caddress, static_cast<uint8_t>(2));
740
742
if (bytesReturned != 2)
741
743
{
742
744
if ((_printDebug == true) || (_printLimitedDebug == true)) // This is important. Print this if doing limited debugging
@@ -746,7 +748,7 @@ boolean SFE_UBLOX_GNSS::checkUbloxI2C(ubxPacket *incomingUBX, uint8_t requestedC
746
748
}
747
749
return (false); //Sensor did not return 2 bytes
748
750
}
749
- // if (_i2cPort->available())
751
+ else //if (_i2cPort->available())
750
752
{
751
753
uint8_t msb = _i2cPort->read();
752
754
uint8_t lsb = _i2cPort->read();
@@ -859,21 +861,28 @@ boolean SFE_UBLOX_GNSS::checkUbloxI2C(ubxPacket *incomingUBX, uint8_t requestedC
859
861
// return (false); //Sensor did not ACK
860
862
861
863
//Limit to 32 bytes or whatever the buffer limit is for given platform
862
- uint16_t bytesToRead = bytesAvailable;
863
- if (bytesToRead > i2cTransactionSize)
864
+ uint16_t bytesToRead = bytesAvailable; // 16-bit
865
+ if (bytesToRead > i2cTransactionSize) // Limit for i2cTransactionSize is 8-bit
864
866
bytesToRead = i2cTransactionSize;
865
867
866
- TRY_AGAIN:
868
+ // TRY_AGAIN:
867
869
868
- _i2cPort->requestFrom ((uint8_t )_gpsI2Caddress, (uint8_t )bytesToRead); // TO DO: add _i2cStopRestart here
869
- if (_i2cPort->available ())
870
+ //Here it would be desireable to use a restart where possible / supported, but only if there will be multiple reads.
871
+ //However, if an individual requestFrom fails, we could end up leaving the bus hanging.
872
+ //On balance, it is probably safest to not use restarts.
873
+ uint8_t bytesReturned = _i2cPort->requestFrom((uint8_t)_gpsI2Caddress, (uint8_t)bytesToRead);
874
+ if ((uint16_t)bytesReturned == bytesToRead)
870
875
{
871
876
for (uint16_t x = 0; x < bytesToRead; x++)
872
877
{
873
878
uint8_t incoming = _i2cPort->read(); //Grab the actual character
874
879
875
- // Check to see if the first read is 0x7F. If it is, the module is not ready
876
- // to respond. Stop, wait, and try again
880
+ //Check to see if the first read is 0x7F. If it is, the module is not ready to respond. Stop, wait, and try again
881
+ //Note: the integration manual says:
882
+ //"If there is no data awaiting transmission from the receiver, then this register will deliver the value 0xFF,
883
+ // which cannot be the first byte of a valid message."
884
+ //But it can be the first byte waiting to be read from the buffer if we have already read part of the message.
885
+ //Therefore I think this check needs to be commented.
877
886
// if (x == 0)
878
887
// {
879
888
// if ((incoming == 0x7F) && (ubx7FcheckDisabled == false))
@@ -2619,7 +2628,7 @@ void SFE_UBLOX_GNSS::processUBXpacket(ubxPacket *msg)
2619
2628
{
2620
2629
packetUBXESFMEAS->data.data[i].data.all = extractLong(msg, 8 + (i * 4));
2621
2630
}
2622
- if (msg->len > (8 + (packetUBXESFMEAS->data .flags .bits .numMeas * 4 ))) // IGNORE COMPILER WARNING comparison between signed and unsigned integer expressions
2631
+ if ((uint16_t) msg->len > (uint16_t)( 8 + (packetUBXESFMEAS->data.flags.bits.numMeas * 4)))
2623
2632
packetUBXESFMEAS->data.calibTtag = extractLong(msg, 8 + (packetUBXESFMEAS->data.flags.bits.numMeas * 4));
2624
2633
2625
2634
//Mark all datums as fresh (not read before)
@@ -2863,11 +2872,13 @@ sfe_ublox_status_e SFE_UBLOX_GNSS::sendCommand(ubxPacket *outgoingUBX, uint16_t
2863
2872
2864
2873
calcChecksum(outgoingUBX); //Sets checksum A and B bytes of the packet
2865
2874
2875
+ #ifndef SFE_UBLOX_REDUCED_PROG_MEM
2866
2876
if (_printDebug == true)
2867
2877
{
2868
2878
_debugSerial->print(F("\nSending: "));
2869
2879
printPacket(outgoingUBX, true); // Always print payload
2870
2880
}
2881
+ #endif
2871
2882
2872
2883
if (commType == COMM_TYPE_I2C)
2873
2884
{
@@ -2968,7 +2979,7 @@ sfe_ublox_status_e SFE_UBLOX_GNSS::sendI2cCommand(ubxPacket *outgoingUBX, uint16
2968
2979
uint16_t startSpot = 0;
2969
2980
while (bytesLeftToSend > 0)
2970
2981
{
2971
- uint8_t len = bytesLeftToSend; // How many bytes should we actually write?
2982
+ uint16_t len = bytesLeftToSend; // How many bytes should we actually write?
2972
2983
if (len > i2cTransactionSize) // Limit len to i2cTransactionSize
2973
2984
len = i2cTransactionSize;
2974
2985
@@ -3799,6 +3810,10 @@ void SFE_UBLOX_GNSS::checkCallbacks(void)
3799
3810
// On processors like the ESP32, you can use setI2CTransactionSize to increase the size of each transmission - to e.g. 128 bytes
3800
3811
boolean SFE_UBLOX_GNSS::pushRawData(uint8_t *dataBytes, size_t numDataBytes, boolean stop)
3801
3812
{
3813
+ // Return now if numDataBytes is zero
3814
+ if (numDataBytes == 0)
3815
+ return (false); // Indicate to the user that there was no data to push
3816
+
3802
3817
if (commType == COMM_TYPE_SERIAL)
3803
3818
{
3804
3819
// Serial: write all the bytes in one go
@@ -3807,6 +3822,16 @@ boolean SFE_UBLOX_GNSS::pushRawData(uint8_t *dataBytes, size_t numDataBytes, boo
3807
3822
}
3808
3823
else if (commType == COMM_TYPE_I2C)
3809
3824
{
3825
+ // We can not write a single data byte to I2C as it would look like the address of a random read.
3826
+ // If numDataBytes is 1, we should probably just reject the data and return false.
3827
+ // But we'll be nice and store the byte until the next time pushRawData is called.
3828
+ if ((numDataBytes == 1) && (_pushSingleByte == false))
3829
+ {
3830
+ _pushThisSingleByte = *dataBytes;
3831
+ _pushSingleByte = true;
3832
+ return (false); // Indicate to the user that their data has not been pushed yet
3833
+ }
3834
+
3810
3835
// If stop is true then always use a stop
3811
3836
// Else if _i2cStopRestart is true then always use a stop
3812
3837
// Else use a restart where needed
@@ -3821,6 +3846,9 @@ boolean SFE_UBLOX_GNSS::pushRawData(uint8_t *dataBytes, size_t numDataBytes, boo
3821
3846
size_t bytesLeftToWrite = numDataBytes;
3822
3847
size_t bytesWrittenTotal = 0;
3823
3848
3849
+ if (_pushSingleByte == true) // Increment bytesLeftToWrite if we have a single byte waiting to be pushed
3850
+ bytesLeftToWrite++;
3851
+
3824
3852
while (bytesLeftToWrite > 0)
3825
3853
{
3826
3854
size_t bytesToWrite; // Limit bytesToWrite to i2cTransactionSize
@@ -3829,12 +3857,30 @@ boolean SFE_UBLOX_GNSS::pushRawData(uint8_t *dataBytes, size_t numDataBytes, boo
3829
3857
else
3830
3858
bytesToWrite = bytesLeftToWrite;
3831
3859
3860
+ //If there would be one byte left to be written next time, send one byte less now
3861
+ if ((bytesLeftToWrite - bytesToWrite) == 1)
3862
+ bytesToWrite--;
3863
+
3832
3864
_i2cPort->beginTransmission(_gpsI2Caddress);
3833
- size_t bytesWritten = _i2cPort->write (dataBytes, bytesToWrite); // Write the bytes
3865
+
3866
+ size_t bytesWritten = 0;
3867
+
3868
+ //If _pushSingleByte is true, push it now
3869
+ if (_pushSingleByte == true)
3870
+ {
3871
+ bytesWritten += _i2cPort->write(_pushThisSingleByte); // Write the single byte
3872
+ bytesWritten += _i2cPort->write(dataBytes, bytesToWrite - 1); // Write the bytes - but send one byte less
3873
+ dataBytes += bytesToWrite - 1; // Point to fresh data
3874
+ _pushSingleByte = false; // Clear the flag
3875
+ }
3876
+ else
3877
+ {
3878
+ bytesWritten += _i2cPort->write(dataBytes, bytesToWrite); // Write the bytes
3879
+ dataBytes += bytesToWrite; // Point to fresh data
3880
+ }
3834
3881
3835
3882
bytesWrittenTotal += bytesWritten; // Update the totals
3836
3883
bytesLeftToWrite -= bytesToWrite;
3837
- dataBytes += bytesToWrite; // Point to fresh data
3838
3884
3839
3885
if (bytesLeftToWrite > 0)
3840
3886
{
@@ -3848,7 +3894,7 @@ boolean SFE_UBLOX_GNSS::pushRawData(uint8_t *dataBytes, size_t numDataBytes, boo
3848
3894
}
3849
3895
}
3850
3896
3851
- return (bytesWrittenTotal == numDataBytes);
3897
+ return (bytesWrittenTotal == numDataBytes); //Return true if the correct number of bytes were written
3852
3898
}
3853
3899
else // SPI
3854
3900
{
0 commit comments