Skip to content

Commit 2f2d0a5

Browse files
committed
Update pushRawData to avoid single byte writes. Change len to uint16_t. Avoid compiler warning (#
1 parent 0268b1f commit 2f2d0a5

File tree

3 files changed

+78
-17
lines changed

3 files changed

+78
-17
lines changed

keywords.txt

+2
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,8 @@ setI2CpollingWait KEYWORD2
5656
setSPIpollingWait KEYWORD2
5757
setI2CTransactionSize KEYWORD2
5858
getI2CTransactionSize KEYWORD2
59+
setI2cStopRestart KEYWORD2
60+
getI2cStopRestart KEYWORD2
5961
setSpiTransactionSize KEYWORD2
6062
getSpiTransactionSize KEYWORD2
6163
setMaxNMEAByteCount KEYWORD2

src/SparkFun_u-blox_GNSS_Arduino_Library.cpp

+61-15
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ SFE_UBLOX_GNSS::SFE_UBLOX_GNSS(void)
5555
_processNMEA.all = SFE_UBLOX_FILTER_NMEA_ALL; // Default to passing all NMEA messages to processNMEA
5656

5757
// 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.
5859
#if defined(ARDUINO_ARCH_ESP32)
5960
_i2cStopRestart = true; // Always use a stop
6061
#else
@@ -725,7 +726,7 @@ boolean SFE_UBLOX_GNSS::checkUbloxI2C(ubxPacket *incomingUBX, uint8_t requestedC
725726
uint16_t bytesAvailable = 0;
726727
_i2cPort->beginTransmission(_gpsI2Caddress);
727728
_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.
729730
if (i2cError != 0)
730731
{
731732
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
736737
return (false); //Sensor did not ACK
737738
}
738739

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));
740742
if (bytesReturned != 2)
741743
{
742744
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
746748
}
747749
return (false); //Sensor did not return 2 bytes
748750
}
749-
//if (_i2cPort->available())
751+
else //if (_i2cPort->available())
750752
{
751753
uint8_t msb = _i2cPort->read();
752754
uint8_t lsb = _i2cPort->read();
@@ -859,21 +861,28 @@ boolean SFE_UBLOX_GNSS::checkUbloxI2C(ubxPacket *incomingUBX, uint8_t requestedC
859861
// return (false); //Sensor did not ACK
860862

861863
//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
864866
bytesToRead = i2cTransactionSize;
865867

866-
TRY_AGAIN:
868+
//TRY_AGAIN:
867869

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)
870875
{
871876
for (uint16_t x = 0; x < bytesToRead; x++)
872877
{
873878
uint8_t incoming = _i2cPort->read(); //Grab the actual character
874879

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.
877886
// if (x == 0)
878887
// {
879888
// if ((incoming == 0x7F) && (ubx7FcheckDisabled == false))
@@ -2619,7 +2628,7 @@ void SFE_UBLOX_GNSS::processUBXpacket(ubxPacket *msg)
26192628
{
26202629
packetUBXESFMEAS->data.data[i].data.all = extractLong(msg, 8 + (i * 4));
26212630
}
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)))
26232632
packetUBXESFMEAS->data.calibTtag = extractLong(msg, 8 + (packetUBXESFMEAS->data.flags.bits.numMeas * 4));
26242633

26252634
//Mark all datums as fresh (not read before)
@@ -2863,11 +2872,13 @@ sfe_ublox_status_e SFE_UBLOX_GNSS::sendCommand(ubxPacket *outgoingUBX, uint16_t
28632872

28642873
calcChecksum(outgoingUBX); //Sets checksum A and B bytes of the packet
28652874

2875+
#ifndef SFE_UBLOX_REDUCED_PROG_MEM
28662876
if (_printDebug == true)
28672877
{
28682878
_debugSerial->print(F("\nSending: "));
28692879
printPacket(outgoingUBX, true); // Always print payload
28702880
}
2881+
#endif
28712882

28722883
if (commType == COMM_TYPE_I2C)
28732884
{
@@ -2968,7 +2979,7 @@ sfe_ublox_status_e SFE_UBLOX_GNSS::sendI2cCommand(ubxPacket *outgoingUBX, uint16
29682979
uint16_t startSpot = 0;
29692980
while (bytesLeftToSend > 0)
29702981
{
2971-
uint8_t len = bytesLeftToSend; // How many bytes should we actually write?
2982+
uint16_t len = bytesLeftToSend; // How many bytes should we actually write?
29722983
if (len > i2cTransactionSize) // Limit len to i2cTransactionSize
29732984
len = i2cTransactionSize;
29742985

@@ -3799,6 +3810,10 @@ void SFE_UBLOX_GNSS::checkCallbacks(void)
37993810
// On processors like the ESP32, you can use setI2CTransactionSize to increase the size of each transmission - to e.g. 128 bytes
38003811
boolean SFE_UBLOX_GNSS::pushRawData(uint8_t *dataBytes, size_t numDataBytes, boolean stop)
38013812
{
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+
38023817
if (commType == COMM_TYPE_SERIAL)
38033818
{
38043819
// Serial: write all the bytes in one go
@@ -3807,6 +3822,16 @@ boolean SFE_UBLOX_GNSS::pushRawData(uint8_t *dataBytes, size_t numDataBytes, boo
38073822
}
38083823
else if (commType == COMM_TYPE_I2C)
38093824
{
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+
38103835
// If stop is true then always use a stop
38113836
// Else if _i2cStopRestart is true then always use a stop
38123837
// Else use a restart where needed
@@ -3821,6 +3846,9 @@ boolean SFE_UBLOX_GNSS::pushRawData(uint8_t *dataBytes, size_t numDataBytes, boo
38213846
size_t bytesLeftToWrite = numDataBytes;
38223847
size_t bytesWrittenTotal = 0;
38233848

3849+
if (_pushSingleByte == true) // Increment bytesLeftToWrite if we have a single byte waiting to be pushed
3850+
bytesLeftToWrite++;
3851+
38243852
while (bytesLeftToWrite > 0)
38253853
{
38263854
size_t bytesToWrite; // Limit bytesToWrite to i2cTransactionSize
@@ -3829,12 +3857,30 @@ boolean SFE_UBLOX_GNSS::pushRawData(uint8_t *dataBytes, size_t numDataBytes, boo
38293857
else
38303858
bytesToWrite = bytesLeftToWrite;
38313859

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+
38323864
_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+
}
38343881

38353882
bytesWrittenTotal += bytesWritten; // Update the totals
38363883
bytesLeftToWrite -= bytesToWrite;
3837-
dataBytes += bytesToWrite; // Point to fresh data
38383884

38393885
if (bytesLeftToWrite > 0)
38403886
{
@@ -3848,7 +3894,7 @@ boolean SFE_UBLOX_GNSS::pushRawData(uint8_t *dataBytes, size_t numDataBytes, boo
38483894
}
38493895
}
38503896

3851-
return (bytesWrittenTotal == numDataBytes);
3897+
return (bytesWrittenTotal == numDataBytes); //Return true if the correct number of bytes were written
38523898
}
38533899
else // SPI
38543900
{

src/SparkFun_u-blox_GNSS_Arduino_Library.h

+15-2
Original file line numberDiff line numberDiff line change
@@ -56,9 +56,14 @@
5656
#include "u-blox_config_keys.h"
5757
#include "u-blox_structs.h"
5858

59-
//Unomment the next line (or add SFE_UBLOX_REDUCED_PROG_MEM as a compiler directive) to reduce the amount of program memory used by the library
59+
//Uncomment the next line (or add SFE_UBLOX_REDUCED_PROG_MEM as a compiler directive) to reduce the amount of program memory used by the library
6060
//#define SFE_UBLOX_REDUCED_PROG_MEM // Uncommenting this line will delete the minor debug messages to save memory
6161

62+
//The code just about fills the program memory on the ATmega328P (Arduino Uno), so let's delete the minor debug messages anyway
63+
#if !defined(SFE_UBLOX_REDUCED_PROG_MEM) && defined(ARDUINO_AVR_UNO)
64+
#define SFE_UBLOX_REDUCED_PROG_MEM
65+
#endif
66+
6267
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
6368

6469
//Define a digital pin to aid debugging
@@ -590,7 +595,9 @@ class SFE_UBLOX_GNSS
590595
uint8_t getI2CTransactionSize(void);
591596

592597
// Support for platforms like ESP32 which do not support multiple I2C restarts
593-
void i2cStopRestart(boolean stop) { _i2cStopRestart = stop; }; // If stop is true, endTransmission will always use a stop. If false, a restart will be used where needed.
598+
// If _i2cStopRestart is true, endTransmission will always use a stop. If false, a restart will be used where needed.
599+
// The default value for _i2cStopRestart is set in the class instantiation code.
600+
void setI2cStopRestart(boolean stop) { _i2cStopRestart = stop; };
594601
boolean getI2cStopRestart(void) { return (_i2cStopRestart); };
595602

596603
//Control the size of the spi buffer. If the buffer isn't big enough, we'll start to lose bytes
@@ -1400,8 +1407,14 @@ class SFE_UBLOX_GNSS
14001407
void writeToFileBuffer(uint8_t *theBytes, uint16_t numBytes); // Write theBytes to the file buffer
14011408

14021409
// Support for platforms like ESP32 which do not support multiple I2C restarts
1410+
// If _i2cStopRestart is true, endTransmission will always use a stop. If false, a restart will be used where needed.
1411+
// The default value for _i2cStopRestart is set in the class instantiation code.
14031412
boolean _i2cStopRestart;
14041413

1414+
// Storage just in case the user tries to push a single byte using pushRawBytes
1415+
boolean _pushSingleByte = false;
1416+
uint8_t _pushThisSingleByte;
1417+
14051418
};
14061419

14071420
#endif

0 commit comments

Comments
 (0)