trouble decoding the serial GPS using readfile function - c++

i m trying to use readfile function to read the serial port in c++. i manage to open and read the serial port in c++. the problem i facing now is the decoding of data after i read from the serial port. The below are my codes. When i run my code, my loop of decoding could not detect ((*&szChar == '$')), and it exit the loop by printing error. May i know how could i decode the gps data that i read from my serial port? thanks
char szChar[100];
int nRet;
DWORD dwBytesRead = 10;
char ReadBuffer[BUFFERSIZE] = {0};
nRet = ReadFile(hCom,&szChar,BUFFERSIZE-1,&dwBytesRead,NULL);
if((*&szChar == '$'))
{
printf("%s\n", &szChar);
}
else
{
printf("error\n");

I have to say, I find your code quite confused and confusing. Just for example, you're creating szChar as an array of 100 char, and ReadBuffer as an array of BUFFERSIZE chars. When you call ReadFile, however, you're passing the base address of szChar with the size given as BUFFERSIZE. Unless, by some coincidence, BUFFERSIZE happens to equal 100, that looks a lot like a potential buffer overrun.
Then we get to *&szChar. This doesn't really make much sense either. From the looks of things, you probably want szChar[0] -- but even that's not really a good idea, because you might not receive the data in exactly line-sized pieces. As such, you probably want to scan through the data to find the '$'.
int Ret;
DWORD BytesRead;
char ReadBuffer[BUFFERSIZE] = {0};
Ret = ReadFile(hCom,ReadBuffer,sizeof(ReadBuffer)-1,&BytesRead,NULL);
ReadBuffer[BytesRead] = '\0';
if (ReadBuffer[0] == '$')
printf(%s\n", ReadBuffer);
else
printf("error\n");

#Jerry: Thanks.. so i edited my code below to decode my data, is it correct way to put my ReadBuffer into another array for checking?
char lastCommaPosition;
char latitudeString[11];
char stringRead[MAXSIZE];
char tempString[MAXSIZE];
char *pChar;
char dummyChar;
float latitude;
int latDegrees;
float latMinutes;
int numLinesRead;
int Ret,i,j,k;
if (ReadBuffer[0] == '$')
{
i = 0;
numLinesRead++;
stringRead[i] = ReadBuffer;
}
stringRead[i+1] = '\0';
j = 0;
pChar = stringRead;
while(*(pChar+j) != ',')
{
tempString[j] = *(pChar+j);
j++;
}
tempString[j] = '\0';
if(tempString[3] == 'G' && tempString[4] == 'G' && tempString[5] == 'A')
{
pChar = stringRead;
j = lastCommaPosition + 1;
k = 0;
while(*(pChar+j) != ',')
{
latitudeString[k] = *(pChar+j);
j++;
k++;
}
lastCommaPosition = j;
latitudeString[k] = '\0';
sscanf(latitudeString, "%f", &latitude);
latDegrees = (int)(latitude/100);
latMinutes = (float)(latitude - latDegrees*100);
printf("\t%02d DEG\t%2.4f MIN", latDegrees, latMinutes);

Related

Socket Communication Data Corruption on Write/Read

I've got a C++ server that communicates with multiple clients. It uses a vector to store the handles to the sockets for those clients (playerSockets in the code below). At the end of the "game" I want the server to loop through that vector and write the same string to each client. However, sometimes the data that the client reads (and then displays) is "corrupted" as you can see in the screenshot, but this doesn't happen for the first client, only the second. I can't figure out why this is happening! I use this same technique (looping and writing) earlier in the program and it always works fine in that instance.
Here is what it is supposed to be shown:
Here and here's what I get:
Here is the server code that writes:
std::string announcement = "";
if (playerWon) {
...
}
} else {
announcement = "?No one won the game!\nGAME BOARD: " + cn.getGameBoard();
for (int player : gameData->playerSockets) {
write(player, announcement.c_str(), announcement.size() + 1);
}
}
And here's the client code that reads. Keep in mind that more than one client is running and connected to the server, and this issue only happens with a client OTHER THAN the first client in the server's loop:
static bool readMyTurn(int clientSd) {
...
char buf[BUFSIZE];
read(clientSd, buf, BUFSIZE);
string myTurn(buf);
cout << "MYMYMYMY: " << myTurn << endl;
myTurn.erase(0, 1);
cout << myTurn << endl;
...
}
UPDATE
Here is my current code to read until encountering the null-terminator character.
string readOneStringFromServer(int clientSd, string &leftovers) {
ssize_t nullTerminatorPosition = 0;
std::string stringToReturn = "";
do {
char buf[BUFSIZE];
ssize_t bytesRead = read(clientSd, buf, BUFSIZE);
nullTerminatorPosition = findPositionOfNullTerminator(buf, bytesRead);
// found a null terminator
if (nullTerminatorPosition != -1) {
// create a buffer to hold all of the chars from buf1 up to and including the null terminator
char upToNullTerminator[nullTerminatorPosition + 1];
// get those chars from buf1 and put them into buf2 (including the null terminator)
for (int i = 0; i < nullTerminatorPosition + 1; ++i) {
upToNullTerminator[i] = buf[i];
}
// use buf2 to create a string
stringToReturn += upToNullTerminator;
// check if there are leftover bytes after the null terminator
int leftoverBytes = bytesRead - nullTerminatorPosition - 1;
if (leftoverBytes != 0) {
// if there are, create a char array of that size
char leftoverChars[leftoverBytes];
// loop through buf1 and add the leftover chars to buf3
for (int i = nullTerminatorPosition + 1; i < bytesRead; ++i) {
leftoverChars[i - (nullTerminatorPosition + 1)] = buf[i];
}
// make a string out of those leftover chars
leftovers = leftoverChars;
} else {
// if there are no leftover bytes, then we want to "erase" what is currently held in leftovers so that
// it doesn't get passed to the next function call
leftovers = "";
}
// didn't find one
} else {
stringToReturn += buf;
}
} while (nullTerminatorPosition == -1);
return stringToReturn;
}

Arduino hanging when data sent via bluetooth serial

Below is the code being used by Arduino to extract two integers at a time, from formatted text in the serial. The format being two numbers. each followed by a comma, eg 51,7, After reading in the ints, it is supposed to do stuff with them, then loop back and go again, unless there is no data, then it is supposed to skip past the if and do stuff using the current int values.
void setup() {
Serial.begin(9600);
}
char rx_byte = 0;
String rx_str[2] = {""};
int nums[2] = {0}, a;
int PIN = 13;
boolean not_read = true;
void loop() {
if (Serial.available() > 0) { // is a character available?
memset(nums, 0, sizeof(nums));
rx_str[0] = "";
rx_str[1] = "";
a = 0;
while( a < 2 ){
not_read = true;
while(not_read){
rx_byte = Serial.read(); // get the character
if ((rx_byte >= '0') && (rx_byte <= '9')) {
rx_str[a] += rx_byte;
} // if ((rx_byte >= '0') && (rx_byte <= '9'))
else if (rx_byte == ',') {
not_read = false;
a++;
} // else if (rx_byte == ',')
} // while(not_read)
} // while(int a < 2)
nums[0] = rx_str[0].toInt();
nums[1] = rx_str[1].toInt();
} // if (Serial.available() > 0)
// do stuff with ints
} // void loop
This turnout works fine when the Arduino is plugged into the usb and the right data is entered into the serial monitor. The problem is, when the data is written by another program in c, using bluetooth with an HC-05-1 module, when there is no data, arduino hangs at the if statement waiting for serial input, instead of skipping past and doing stuff. Below is the C++ code for writing the data.
void right( double times[3] ) {
nums[0] = (int) times[0];
nums[1] = (int) times[1];
int bytes_written = 0; // bytes_read = 0;
printf( "\n nums[0]: %d ", nums[0]);
printf( "\n nums[1]: %d ", nums[1]);
sprintf( buf, "%d,%d,", nums[0],nums[1] );
printf( "\n writing ");
puts(buf);
bytes_written = write(s, buf, sizeof(buf));
printf("\n %d Bytes written to bluetooth", bytes_written);
printf("\n +----------------------------------+\n\n");
}
And this is sample output from function right()
nums[0]: 4
nums[1]: 2
writing 4,2,
15 Bytes written to bluetooth
+----------------------------------+
I dont kmow how relevant this is but here some output from function right() when the bluetooth and board are not powered up.
nums[0]: 16
nums[1]: 5
writing 16,5,
16,5,
15 Bytes written to bluetooth
+----------------------------------+
Not sure where that extra line of output comes from. Last week it used to output 0 Bytes written to bluetooth without the extra line, but changes have been made since then.
Edit....
Patrick Trentin's diagnosis was right.
sprintf( buf, "%d,%d,", nums[0],nums[1] );
needed to be changed to
int str_len = sprintf( buf, "%d,%d,", nums[0],nums[1] );
and
bytes_written = write(s, buf, sizeof(buf));
needed to be changed to
bytes_written = write(s, buf, str_len);
It was a bit disappointing how long the read process took, so some pretty serious optimization is needed, but it does seem to do what was intended... eventually.

How to implement a stream that can be splitted by newline

The following code works, but is about twice as inefficient compared to when I use a (linux) pipe that gives unzipped data to the (modified) program. I need a steady stream within the program which I can keep splitting by \n. Is there a way to do this using a (string?) stream or any other trick?
int main(int argc, char *argv[]) {
static const int unzipBufferSize = 8192;
long long int counter = 0;
int i = 0, p = 0, n = 0;
int offset = 0;
char *end = NULL;
char *begin = NULL;
unsigned char unzipBuffer[unzipBufferSize];
unsigned int unzippedBytes;
char * inFileName = argv[1];
char buffer[200];
buffer[0] = '\0';
bool breaker = false;
char pch[4][200];
Read *aRead = new Read;
gzFile inFileZ;
inFileZ = gzopen(inFileName, "rb");
while (true) {
unzippedBytes = gzread(inFileZ, unzipBuffer, unzipBufferSize);
if (unzippedBytes > 0) {
unzipBuffer[unzippedBytes] = '\0'; //put a 0-char after the total buffer
begin = (char*) &unzipBuffer[0]; // point to the address of the first char
do {
end = strchr(begin,(int)'\n'); //find the end of line
if (end != NULL) *(end) = '\0'; // put 0-char to use it as a c-string
pch[p][0] = '\0'; \\ put a 0-char to be able to strcat
if (strlen(buffer) > 0) { // if buffer from previous iteration contains something
strcat(pch[p], buffer); // cat it to the p-th pch
buffer[0] = '\0'; \\ set buffer to null-string or ""
}
strcat(pch[p], begin); // put begin (or rest of line in case there was a buffer into p-th pch
if (end != NULL) { // see if it already points to something
begin = end+1; // if so, advance begin to old end+1
p++;
}
if(p>3) { // a 'read' contains 4 lines, so if p>3
strcat(aRead->bases,pch[1]); // we use line 2 and 4 as
strcat(aRead->scores,pch[3]); // bases and scores
//do things with the reads
aRead->bases[0] = '\0'; //put them back to 0-char
aRead->scores[0] = '\0';
p = 0; // start counting next 4 lines
}
}
while (end != NULL );
strcat(buffer,pch[p]); //move the left-over of unzipBuffer to buffer
}
else {
break; // when no unzippedBytes, exit the loop
}
}
Your main problem is probably the standard C string library.
With using strxxx() funcions, you are iterating through the complete buffer multiple times each call, first for strchr(), then for strlen(), then for each of the strcat() calls.
Using the standard library is a nice thing, but here, it's just plain inefficient.
Try if you could come up with something simpler that touches each character only once like (code just to show the principle, do not expect it working):
do
{
do
{
*tp++ = *sp++;
} while (sp < buffer_end && *sp != '\n');
/* new line, do whatever it requires */
...
/* reset tp to beginning of buffer */
} while (sp < buffer_end);
I am trying to get this to work, but all it does is giving a Segmentation Fault at runtime:
do {
unzippedBytes = gzread(inFileZ, unzipBuffer, unzipBufferSize);
if (unzippedBytes > 0) {
while (*unzipBuffer < unzippedBytes) {
*pch = *unzipBuffer++;
cout << pch;
i++;
}
i=0;
}
else break;
} while (true);
What am I doing wrong here?

How can I send all data over a socket?

I am trying to send large amounts of data over a socket, sometimes when I call send (on Windows) it won't send all the data I requested, as expected. So, I wrote a little function that should have solved my problems- but it's causing problems where the data isn't being sent correctly and causing the images to be corrupted. I'm making a simple chat room where you can send images (screenshots) to each other.
Why is my function not working?
How can I make it work?
void _internal_SendFile_alignment_512(SOCKET sock, BYTE *data, DWORD datasize)
{
Sock::Packet packet;
packet.DataSize = datasize;
packet.PacketType = PACKET_FILETRANSFER_INITIATE;
DWORD until = datasize / 512;
send(sock, (const char*)&packet, sizeof(packet), 0);
unsigned int pos = 0;
while( pos != datasize )
{
pos += send(sock, (char *)(data + pos), datasize - pos, 0);
}
}
My receive side is:
public override void OnReceiveData(TcpLib.ConnectionState state)
{
if (state.fileTransfer == true && state.waitingFor > 0)
{
byte[] buffer = new byte[state.AvailableData];
int readBytes = state.Read(buffer, 0, state.AvailableData);
state.waitingFor -= readBytes;
state.bw.Write(buffer);
state.bw.Flush();
if (state.waitingFor == 0)
{
state.bw.Close();
state.hFile.Close();
state.fileTransfer = false;
IPEndPoint ip = state.RemoteEndPoint as IPEndPoint;
Program.MainForm.log("Ended file transfer with " + ip);
}
}
else if( state.AvailableData > 7)
{
byte[] buffer = new byte[8];
int readBytes = state.Read(buffer, 0, 8);
if (readBytes == 8)
{
Packet packet = ByteArrayToStructure<Packet>(buffer);
if (packet.PacketType == PACKET_FILETRANSFER_INITIATE)
{
IPEndPoint ip = state.RemoteEndPoint as IPEndPoint;
String filename = getUniqueFileName("" + ip.Address);
if (filename == null)
{
Program.MainForm.log("Error getting filename for " + ip);
state.EndConnection();
return;
}
byte[] data = new byte[state.AvailableData];
readBytes = state.Read(data, 0, state.AvailableData);
state.waitingFor = packet.DataSize - readBytes;
state.hFile = new FileStream(filename, FileMode.Append);
state.bw = new BinaryWriter(state.hFile);
state.bw.Write(data);
state.bw.Flush();
state.fileTransfer = true;
Program.MainForm.log("Initiated file transfer with " + ip);
}
}
}
}
It receives all the data, when I debug my code and see that send() does not return the total data size (i.e. it has to be called more than once) and the image gets yellow lines or purple lines in it — I suspect there's something wrong with sending the data.
I mis-understood the question and solution intent. Thanks #Remy Lebeau for the comment to clarify that. Based on that, you can write a sendall() function as given in section 7.3 of http://beej.us/guide/bgnet/output/print/bgnet_USLetter.pdf
int sendall(int s, char *buf, int *len)
{
int total = 0; // how many bytes we've sent
int bytesleft = *len; // how many we have left to send
int n = 0;
while(total < *len) {
n = send(s, buf+total, bytesleft, 0);
if (n == -1) {
/* print/log error details */
break;
}
total += n;
bytesleft -= n;
}
*len = total; // return number actually sent here
return n==-1?-1:0; // return -1 on failure, 0 on success
}
You need to check the returnvalue of send(). In particular, you can't simply assume that it is the number of bytes sent, there is also the case that there was an error. Try this instead:
while(datasize != 0)
{
n = send(...);
if(n == SOCKET_ERROR)
throw exception("send() failed with errorcode #" + to_string(WSAGetLastEror()));
// adjust pointer and remaining number of bytes
datasize -= n;
data += n;
}
BTW:
Make that BYTE const* data, you're not going to modify what it points to.
The rest of your code seems too complicated, in particular you don't solve things by aligning to magic numbers like 512.

storing return value from function into pointer to char variable is rightway to do?

I have written a read function which reads values from serial port(LINUX) . It returns values as pointer to char . I am calling this function in another function and storing it again in a variable as pointer to char . I occasionally got stack over flow problem and not sure if this function is creating problem.
The sample is provided below. Please give some suggestions or criticism .
char *ReadToSerialPort( )
{
const int buffer_size = 1024;
char *buffer = (char *)malloc(buffer_size);
char *bufptr = buffer;
size_t iIn;
int iMax = buffer+buffer_size-bufptr;
if ( fd < 1 )
{
printf( "port is not open\n" );
// return -1;
}
iIn = read( fd, bufptr, iMax-1 );
if ( iIn < 0 )
{
if ( errno == EAGAIN )
{
printf( "The errror in READ" );
return 0; // assume that command generated no response
}
else
printf( "read error %d %s\n", errno, strerror(errno) );
}
else
{
// *bufptr = '\0';
bufptr[(int)iIn<iMax?iIn:iMax] = '\0';
if(bufptr != buffer)
return bufptr;
}
free(buffer);
return 0;
} // end ReadAdrPort
int ParseFunction(void)
{
// some other code
char *sResult;
if( ( sResult = ReadToSerialPort()) >= 0)
{
printf("Response is %s\n", sResult);
// code to store char in string and put into db .
}
}
Thanks and regards,
SamPrat
You do not deallocate the buffer. You need to make free after you finished working with it.
char * getData()
{
char *buf = (char *)malloc(255);
// Fill buffer
return buf;
}
void anotherFunc()
{
char *data = getData();
// Process data
free(data);
}
In your case I think you should free the buffer after printf:
if( ( sResult = ReadToSerialPort()) >= 0)
{
printf("Response is %s\n", sResult);
// code to store char in string and put into db .
free(sResult);
}
UPDATE Static buffer
Another option to use static buffers. It could increase performance a little bit, but getData method will be not a thread-safe.
char buff[1024];
char *getData()
{
// Write data to buff
return buff;
}
int main()
{
char *data = getData();
printf("%s", data);
}
UPDATE Some notes about your code
int iMax = buffer+buffer_size-bufptr; - iMax will always be 1024;
I do not see any idea of using bufptr since its value is the same as buffer and you do not change it anywhere in your function;
iIn = read( fd, bufptr, buffer_size-1 );
You can replace bufptr[(int)iIn<iMax?iIn:iMax] = '\0'; with bufptr[iIn] = '\0';
if(bufptr != buffer) is always false and this is why your pointer is incorrect and you always return 0;
Do not forget to free the buffer if errno == EAGAIN is true. Currently you just return 0 without free(buffer).
Good luck ;)
Elalfer is partially correct. You do free() your buffer, but not in every case.
For example, when you reach if ( errno == EAGAIN ) and it evaluates to true, you return without doing free on your buffer.
The best would be to pass the buffer as a parameter and make it obvious that the user must free the buffer, outside the function. (this is what basically Elalfer sais in his edited answer).
Just realized this is a C question, I blame SO filtering for this :D sorry! Disregard the following, I'm leaving it so that comments still make sense.
The correct solution should use std::vector<char>, that way the destructor handles memory deallocation for you at the end of scope.
what is the purpose of the second pointer?
char *buffer = (char *)malloc(buffer_size);
char *bufptr = buffer;
what is the purpose of this?
int iMax = buffer+buffer_size-bufptr; // eh?
What is the purpose of this?
bufptr[(int)iIn<iMax?iIn:iMax] = '\0'; // so you pass in 1023 (iMax - 1), it reads 1023, you've effectively corrupted the last byte.
I would start over, consider using std::vector<char>, something like:
std::vector<char> buffer(1500); // default constructs 1500 chars
int iRead = read(fd, &buffer[0], 1500);
// resize the buffer if valid
if (iRead > 0)
buffer.resize(iRead); // this logically trims the buffer so that the iterators begin/end are correct.
return buffer;
Then in your calling function, use the vector<char> and if you need a string, construct one from this: std::string foo(vect.begin(), vect.end()); etc.
When you are setting the null terminator "bufptr[(int)iIn
bufptr[iMax]=>bufptr[1024]=>one byte beyond your allocation since arrays start at 0.
Also int this case "int iMax = buffer+buffer_size-bufptr;" can be re-written as iMax = buffer_size. It makes the code less readable.