GPS tracking software

B

Bubba

Greetings,

I got a GPS tracker that can operate via GPRS. The software provided
with it is... well, BAD. Bad as in not-useful-at-all bad. Not only it
uses practically no advance options that tracker provides of
whatsoever, but it works only on Windows and it requires way too much
tampering for such simple task.

So, since the GPRS communication protocol was also provided, I figured
to create my own custom based GPRS communication software. Here are the
relevant extracts from the begining of the protocol:

§

Depending on the direction of the GPRS package, the communication
protocol is defined as following format

A. The GPRS package from call center to track unit:
@@ + L + ID (7byte) + command (2byte) + DATA + checksum(2byte) +\r\n
B. The GPRS package from track unit to call center:
$$ + L + ID (7byte) + command (2byte) + DATA + checksum(2byte) + \r\n

....

Login after power on
Command code: 0x5000
After the IP/PORT/APN is set ,the tracker unit apply for GPRS service
by sending command every 30 second until it login the server.

For example:
Login command from tracker unit to server to apply GPRS service:
$$ + L + ID + 0x5000 + Checksum(2byte) + \r\n
Following message will be send back from server when the server
receive the login command
@@ + L + ID + 0x4000 + 1B Flag + Checksum(2byte) +\r\n

1B Flag:
= 0x00 means login failed
= 0x01 means login success

§

I am supplying the main loop for receiving data from the tracker:

#define rwerror(x) { if (x < 0) fprintf (stderr, "r/w error\n"); }
....
while (1)
{
struct sockaddr_in client_info;
unsigned int client_info_size = sizeof(client_info);
int session_socket = accept (main_socket, (struct sockaddr *) &client_info, &client_info_size);
if (session_socket < 0)
{
if (errno==EINTR)
continue;
perror("accept");
usleep(100);
continue;
}
session_number+=1;
char * who_is_it = inet_ntoa(client_info.sin_addr);
printf("[session %d accepted from %s]\n", session_number, who_is_it);
memset (buffer, '\0', 256);
r = read (session_socket,buffer,256); //cita duljinu vektora
rwerror (r);
puts (buffer);
printf("\n[session %d dissconnected]\n", session_number);
close(session_socket);
}

This should, as far as I understood from the communication protocol,
receive this type of command:
$$ + L + ID (7byte) + command (2byte) + DATA + checksum(2byte) + \r\n

However, the best I got was this:

bubba@korea:~/gps_server$ ./server1.out 12345
Listening on port 12345
[session 1 accepted from 212.15.188.234]
$$

[session 1 dissconnected]
[session 2 accepted from 212.15.188.234]
$$

[session 2 dissconnected]
[session 3 accepted from 212.15.188.234]
$$

[session 3 dissconnected]
^C
bubba@korea:~/gps_server$

I presume that the problem is in "read" function, that is, it is
probably "too fast" to "grab" all the date from the tracker. If so, can
it be fixed? Or am I doing it totally wrong?

TIA!
 
B

Ben Bacarisse

Bubba said:
So, since the GPRS communication protocol was also provided, I figured
to create my own custom based GPRS communication software. Here are the
relevant extracts from the begining of the protocol:

Depending on the direction of the GPRS package, the communication
protocol is defined as following format

A. The GPRS package from call center to track unit:
@@ + L + ID (7byte) + command (2byte) + DATA + checksum(2byte) +\r\n
B. The GPRS package from track unit to call center:
$$ + L + ID (7byte) + command (2byte) + DATA + checksum(2byte) + \r\n

Eventually a bit of explanation about this might be needed. For
example I am just guessing that L is a length? How many bytes? 1?
Anyway...

printf("[session %d accepted from %s]\n", session_number, who_is_it);
memset (buffer, '\0', 256);
r = read (session_socket,buffer,256); //cita duljinu vektora
rwerror (r);
puts (buffer);
printf("\n[session %d dissconnected]\n", session_number);
This should, as far as I understood from the communication protocol,
receive this type of command:
$$ + L + ID (7byte) + command (2byte) + DATA + checksum(2byte) + \r\n

However, the best I got was this:

bubba@korea:~/gps_server$ ./server1.out 12345
Listening on port 12345
[session 1 accepted from 212.15.188.234]
$$

[session 1 dissconnected]
I presume that the problem is in "read" function, that is, it is
probably "too fast" to "grab" all the date from the tracker. If so, can
it be fixed? Or am I doing it totally wrong?

Currently there is no evidence that this is the problem. Your puts
will stop at the first null byte which may well be just after the L.
If the L (whatever that is) is a byte that does not print, the output
you get is exactly as I'd expect. To debug programs that use binary
data you need to print that data in some visible form. I use a small
"print n bytes in hex" function for such tasks. At the very least,
print 'r' so you can see how many byte you did get. Of course, you
may be right and read is not giving you more than 2 bytes, but there
is no way anyone can tell from this output.

When you get further, this may not be the best place to post.
comp.unix.programmer has many people who a lot about sockets and
protocols and I think you will get better help there once your program
progresses a little further.
 
B

Bubba

Ben Bacarisse's log on stardate 28 vlj 2009
Eventually a bit of explanation about this might be needed. For
example I am just guessing that L is a length? How many bytes? 1?
Anyway...

I am sorry, here it is:

@@ 2Bytes, means the package header from call center to track unit,
it is in ASCII code (in hex code ,it is 0x40)

$$ 2Bytes, means the package header from tracker unit to call
center ,it is in ASCII code ( in hex code ,it is 0x24)

L 2Bytes, meaning the length of the whole package ,including the
header and end character of the package, it is in hex code

ID 7Bytes, the unused byte will be stuffed by 0xff,it is in format of
hex code. For example when ID is 13612345678 ,then it will be
show as following: 0x13,0x61,0x23,0x45,0x67,0x8f,0xff.When all
7 bytes is 0xff,it is a broadcast command. ID is in hex code
Command 2Bytes, as command list and command explain shows. The
command code is in hex code

Data Support min 0 Bytes, max 100 bytes. All data is in ASCII code
Checksum 2Bytes,indicate CRC-CCITT(default is 0xffff) checksum of all
data(not including CRC itself and the end character),it is in hex
code
For example:
24 24 00 11 13 61 23 45 67 8f ff 50 00 05 d8 0d 0a
0x05d8 = CRC-CCITT (24 24 00 11 13 61 23 45 67 8f ff 50 00)

\r\n 2Bytes,end character ,it is in hex code(0x0d,0x0a in hex code)
Currently there is no evidence that this is the problem. Your puts
will stop at the first null byte which may well be just after the L.
If the L (whatever that is) is a byte that does not print, the output
you get is exactly as I'd expect. To debug programs that use binary
data you need to print that data in some visible form. I use a small
"print n bytes in hex" function for such tasks. At the very least,
print 'r' so you can see how many byte you did get. Of course, you
may be right and read is not giving you more than 2 bytes, but there
is no way anyone can tell from this output.

bubba@korea:~/gps_server$ ./server1.out 12345
Listening on port 12345
[session 1 accepted from 77.237.118.53]
Bytes: 86
$$

[session 1 dissconnected]
[session 2 accepted from 77.237.118.53]
Bytes: 86
$$

[session 2 dissconnected]
[session 3 accepted from 77.237.118.53]
Bytes: 86
$$

[session 3 dissconnected]
bubba@korea:~/gps_server$

So you were right.

How do you propose I write (IOW, display on stdout for now) entire
content of buffer?
When you get further, this may not be the best place to post.
comp.unix.programmer has many people who a lot about sockets and
protocols and I think you will get better help there once your
program progresses a little further.

Thx, while reading clc on Google groups, I figured it out. :)

However, I would appreciate any useful feedback (such as yours).

Thank you once again.
 
B

Ben Bacarisse

Bubba said:
Ben Bacarisse's log on stardate 28 vlj 2009
So you were right.

I am glad.
How do you propose I write (IOW, display on stdout for now) entire
content of buffer?

This part is, of course, a C question so it is entirely topical here.
I'd use something like this:

void print_bytes(unsigned char *buf, size_t n)
{
printf("%zu:", n);
while (n--)
printf(" %02x", *buf++);
printf("\n");
}

unsigned char is usually best for data that is arbitrary bytes.
Thx, while reading clc on Google groups, I figured it out. :)

I suspect that very soon your programs will be system specific.
 
B

Bubba

Ben Bacarisse's log on stardate 28 vlj 2009
I am glad.

Me too, trust me! :)
This part is, of course, a C question so it is entirely topical here.
I'd use something like this:

void print_bytes(unsigned char *buf, size_t n)
{
printf("%zu:", n);
while (n--)
printf(" %02x", *buf++);
printf("\n");
}

!

Thank you very much. Now this looks sometnihg like this:

[session 3 accepted from 77.237.103.225]
Bytes: 19
19: 24 24 00 11 12 34 ff ff ff ff ff 50 00 65 58 0d 0a 00 00

[session 3 dissconnected]

That's the "login format" I was seeking for!

Once again, many thanks!

I suppose that 2 bytes of overhead (there are actually 17 effective
bytes up there) are due to null character or something like that?
I suspect that very soon your programs will be system specific.

Perhaps. Although I might have more operative questions ISO C related.

However, without any suspicion, I owe you a beer! Thank you once again.
Good night! :)
 
B

Bubba

Ben Bacarisse's log on stardate 28 vlj 2009
I suspect that very soon your programs will be system specific.

As I said, so far, so god, but I would require some further hints.

Data is sampled and written in a file, fully hexadecimal.

Here's the sample:

28.02.2009. - 16:22:53.805867 § 24 24 00 5b 12 34 ff ff ff ff ff 99 55
31 35 32 35 32 32 2e 30 30 30 2c 41 2c 34 35 34 38 2e 34 37 31 38 2c 4e
2c 30 31 35 35 38 2e 39 37 33 38 2c 45 2c 33 2e 34 39 2c 33 33 30 2e 36
38 2c 32 38 30 32 30 39 2c 2c 2a 30 41 7c 31 2e 31 7c 31 32 30 7c 30 30
30 30 57 de 0d 0a

Data is perfectly well gathered and I can interpret it manually.
Naturally, I would like to make it automatic.

I modified your function and it looks like this now:

void print_bytes (unsigned char *buf, char *tbuf, size_t n, long int usec, FILE *fptr)
{
fprintf (fptr, "%s%ld § ", tbuf, usec);
while (n--)
{
fprintf (fptr, " %02X", *buf++);
}
fprintf (fptr, "\n");
}

What would be the easiest way to interpret that data in to a human
readable format *on the fly*? For having such raw data in the file, I
got the idea to parse the part after '§' sign, chop them with strtok();
and have a counter that will define how data is interpreted (eg. first
two tokens would be $$ or @@, next two would define the length, next 7
represent the tracker ID and would be concatenated after removing FF
parts, etc.).

I attempted to modify the code from above in this fashion:

void print_bytes (unsigned char *buf, char *tbuf, size_t n, long int usec, FILE *fptr)
{
int tmp = n; //remenbers initial size
fprintf (fptr, "%s%ld § ", tbuf, usec);
while (n--)
{
if (n = tmp - 1 || n = tmp - 2)
fprintf (fptr, " %c", *buf++); //prints $$ or @@ rather than hex code for first two bytes
...
}
fprintf (fptr, "\n");
}

but it doesn't works so well. Even if it would, the problem with
variable length of data from tracker would remain, since that data
should be assessed last, after processing control and technical parts
of the stream from tracker (the part explained few posts before).

Can this be easily done in C at all or should I seek help from some
specified programming language such as sed/awk or such?

TIA!
 
B

Ben Bacarisse

Bubba said:
Here's the sample:

28.02.2009. - 16:22:53.805867 § 24 24 00 5b 12 34 ff ff ff ff ff 99 55
31 35 32 35 32 32 2e 30 30 30 2c 41 2c 34 35 34 38 2e 34 37 31 38 2c 4e
2c 30 31 35 35 38 2e 39 37 33 38 2c 45 2c 33 2e 34 39 2c 33 33 30 2e 36
38 2c 32 38 30 32 30 39 2c 2c 2a 30 41 7c 31 2e 31 7c 31 32 30 7c 30 30
30 30 57 de 0d 0a

Data is perfectly well gathered and I can interpret it manually.
Naturally, I would like to make it automatic.

I modified your function and it looks like this now:

void print_bytes (unsigned char *buf, char *tbuf, size_t n, long int usec, FILE *fptr)
{
fprintf (fptr, "%s%ld § ", tbuf, usec);
while (n--)
{
fprintf (fptr, " %02X", *buf++);
}
fprintf (fptr, "\n");
}

What would be the easiest way to interpret that data in to a human
readable format *on the fly*? For having such raw data in the file, I
got the idea to parse the part after '§' sign, chop them with strtok();
and have a counter that will define how data is interpreted (eg. first
two tokens would be $$ or @@, next two would define the length, next 7
represent the tracker ID and would be concatenated after removing FF
parts, etc.).

It rather depends on what kinds of representation are used. I don't
understand what you want to do with the ID (if it "means" nothing,
why not just print the bytes in hex?) but for the length you would
write code like:

int length = buf[2] * 256 + buf[3];

In fact, I'd write a function to pull a two-byte integer out of the
buffer at a given offset:

unsigned int get_16bit_int(unsigned char *buf, int offset)
{
return buf[offset] * 256 + buf[offset + 1];
}
I attempted to modify the code from above in this fashion:

void print_bytes (unsigned char *buf, char *tbuf, size_t n, long int usec, FILE *fptr)
{
int tmp = n; //remenbers initial size
fprintf (fptr, "%s%ld § ", tbuf, usec);
while (n--)
{
if (n = tmp - 1 || n = tmp - 2)

C pitfall #1: = is assignment, == is comparison. You should read a
few pages from the comp.lang.c FAQ each day: http://c-faq.com (which
looks to be down at the moment).
fprintf (fptr, " %c", *buf++); //prints $$ or @@ rather than hex code for first two bytes
...
}
fprintf (fptr, "\n");
}

but it doesn't works so well. Even if it would, the problem with
variable length of data from tracker would remain, since that data
should be assessed last, after processing control and technical parts
of the stream from tracker (the part explained few posts before).

Can this be easily done in C at all or should I seek help from some
specified programming language such as sed/awk or such?

C is good for this sort of thing. I don't think awk would buy you
much. Perl can do it easily enough, but unless you know Perl, there
is little here that would merit learning it.
 
B

Bubba

Ben Bacarisse's log on stardate 01 ožu 2009

/snip
C pitfall #1: = is assignment, == is comparison.

I'm aware of that, naturally... :)
C is good for this sort of thing. I don't think awk would buy you
much. Perl can do it easily enough, but unless you know Perl, there
is little here that would merit learning it.

Note to self: doing anything, especially writing C programming code is
bad if you are too tired and consume alcohol during weekend. :)

Of course, I have totally "forgotten" about pointer arithmetic and
accessing data in arrays.

I still do have a slight issue with my code, apparently. Please, look
at this:

void print_bytes (unsigned char *buf, char *tbuf, size_t n, long int usec, FILE *fptr)
{
int ID = 7, size = *(buf+3), data_size = size - 17;
unsigned char * ID_buf = buf + 4, * data = buf + 13;
fprintf (fptr, "%s%ld\n", tbuf, usec);
fprintf (fptr, "%c%c\n", *(buf), *(buf+1));
fprintf (fptr, "Length: %d\n", *(buf+3));
fprintf (fptr, "Tracker ID:");
while (ID--)
fprintf (fptr, " %02X", *ID_buf++);
fprintf (fptr, "\n");
fprintf (fptr, "Command: %02X%02X\n", *(buf+11), *(buf+12));
if (*(buf+3) > 17)
{
while (data_size--)
fprintf (fptr, "%c", *data++);
fprintf (fptr, "\n");
}
fprintf (fptr, "Checksum: %02X%02X\n", *(buf+size-4),*(buf+size-3));
}

As you can see, I access fixed parts of the data stream, write them,
calculate how big data part is and then print it accordingly.

02.03.2009. - 01:28:52.87266
$$
Length: 85
Tracker ID: 12 34 FF FF FF FF FF
Command: 9955
003126.000,A,4548.4289,N,01559.0217,E,0.00,,020309,,*15|1.6|164|0000
Checksum: A2F6
02.03.2009. - 01:29:22.54221
$$
Length: 91
Tracker ID: 12 34 FF FF FF FF FF
Command: 9955
003200.000,A,4548.4011,N,01559.0451,E,2.87,153.40,020309,,*05|1.6|139|0000
Checksum: D087
02.03.2009. - 01:29:51.332479
$$
Length: 91
Tracker ID: 12 34 12 34 FF FF FF FF FF
Command: 9955
003231.000,A,4548.4020,N,01559.0214,E,3.11,295.07,020309,,*06|1.6|138|0000
Checksum: 0849

The only thing I can't figure out is why is tracker ID written with
blanks between bytes? Any clue?

Thank you once again for everything. Until next (de)bugging, good night
to all! :)
 
B

Ben Bacarisse

Bubba said:
Note to self: doing anything, especially writing C programming code is
bad if you are too tired and consume alcohol during weekend. :)

See below...
Of course, I have totally "forgotten" about pointer arithmetic and
accessing data in arrays.

I still do have a slight issue with my code, apparently. Please, look
at this:

void print_bytes (unsigned char *buf, char *tbuf, size_t n, long int usec, FILE *fptr)
{
int ID = 7, size = *(buf+3), data_size = size - 17;

I think you said earlier that the length was two bytes. That is why I
suggested a function to extract two bytes and combine them into an
integer value.
unsigned char * ID_buf = buf + 4, * data = buf + 13;
fprintf (fptr, "%s%ld\n", tbuf, usec);
fprintf (fptr, "%c%c\n", *(buf), *(buf+1));
fprintf (fptr, "Length: %d\n", *(buf+3));
fprintf (fptr, "Tracker ID:");
while (ID--)
fprintf (fptr, " %02X", *ID_buf++);

You say later:
| The only thing I can't figure out is why is tracker ID written with
| blanks between bytes? Any clue?

Look at the format string -- you ask for a space before each bytes.
I'll assume that is the alcohol at work.
fprintf (fptr, "\n");
fprintf (fptr, "Command: %02X%02X\n", *(buf+11), *(buf+12));
if (*(buf+3) > 17)
{
while (data_size--)
fprintf (fptr, "%c", *data++);
fprintf (fptr, "\n");
}
fprintf (fptr, "Checksum: %02X%02X\n", *(buf+size-4),*(buf+size-3));
}

I would not keep writing *(buf+11) and so on. C has array notation.
buf[11] or buf[size-4] is, to my mind, clearer.
 
B

Bubba

Ben Bacarisse's log on stardate 02 ožu 2009
I think you said earlier that the length was two bytes. That is why
I suggested a function to extract two bytes and combine them into an
integer value.

Indeed. However, maximum length is 117 bytes (plus I don't thing there's
NMEA 0183 sentence larger that 255 bytes), so since that value can be
represented with a single byte, I didn't want to tamper to much.
Look at the format string -- you ask for a space before each bytes.
I'll assume that is the alcohol at work.

I really gotta stop drinking and work this late. Thx! ;)
fprintf (fptr, "\n");
fprintf (fptr, "Command: %02X%02X\n", *(buf+11), *(buf+12));
if (*(buf+3) > 17)
{
while (data_size--)
fprintf (fptr, "%c", *data++);
fprintf (fptr, "\n");
}
fprintf (fptr, "Checksum: %02X%02X\n",
*(buf+size-4),*(buf+size-3));
}

I would not keep writing *(buf+11) and so on. C has array notation.
buf[11] or buf[size-4] is, to my mind, clearer.

I am aware of second notation. Nevertheless, can pointer notation present
any potential hazard (particularly with architecture portability)?
 
B

Ben Bacarisse

Bubba said:
Ben Bacarisse's log on stardate 02 ožu 2009
I would not keep writing *(buf+11) and so on. C has array notation.
buf[11] or buf[size-4] is, to my mind, clearer.

I am aware of second notation. Nevertheless, can pointer notation present
any potential hazard (particularly with architecture portability)?

The syntax E1[E2] is defined to be the same as *(E1+E2) so there is
not reason to choose one over the other except for neatness/convenience.
 
B

Bubba

Bubba's log on stardate 28 vlj 2009

/snip

I managed to grab data from the tracker, and format it nicely. It looks
like this now:

System time: 03.03.2009. - 18:35:00.231994
Length: 85
Tracker ID:1234FFFFFFFFFF
Command: 9955
Status indicator: A - Valid
Latitude: 45° 48.4550' N
Longitude: 015° 58.8147' E
Speed (knots): 0.00
Heading (degrees): none
GPS date: 03.03.2009.
GPS time: 17:37:48.000
Checksum: 63F3

System time: 03.03.2009. - 18:35:15.630549
Length: 90
Tracker ID:1234FFFFFFFFFF
Command: 9955
Status indicator: A - Valid
Latitude: 45° 48.4523' N
Longitude: 015° 58.8240' E
Speed (knots): 1.81
Heading (degrees): 99.57
GPS date: 03.03.2009.
GPS time: 17:37:56.000
Checksum: 313A

The second part, probably again trivial one (hopefully), is how to send
data back to tracker *in hex format*?

The most trivial message would look like this:

@@ (2 bytes) + L(ength, 2 bytes) + (Tracker)(ID 7 bytes) + 0x4000
(command, 2 bytes) + 0x01 (Flag, 2 bytes) + checksum (2 bytes) +\r\n (2
bytes)

"Translated" in to hex, it should (I suppose) look like this:

0x40 0x40 (@@)
0x00 0x12 (Length of message, 18 bytes in upper case)
0x12 0x34 0xFF 0xFF 0xFF 0xFF 0xFF (Tracker ID)
0x40 0x00 (Command)
0x01 (Flag)
0x76 0x7B (CRC-CCITT (0xFFFF) checksum of data without \r\n)
0x0D 0x0A \r\n

404000121234FFFFFFFFFF400001767B0D0A (1)

I have no way of debugging data sent to tracker and I only know that it
accepts messages in hex code. :(

Is it safe to assume that I should send data in pure ASCII (like in
example (1)) and tracker will decode them as hex for himself or...?
 
B

Bubba

Bubba's log on stardate 03 ožu 2009
Is it safe to assume that I should send data in pure ASCII (like in
example (1)) and tracker will decode them as hex for himself or...?

I'll give myself an answer to that one - no, evidently, it is not. :)
 
B

Bubba

Bubba's log on stardate 03 ožu 2009
I'll give myself an answer to that one - no, evidently, it is not. :)

Neither this worked:

unsigned char x[18];
x[0] = 0x40;
x[1] = 0x40;
x[2] = 0x00;
x[3] = 0x12;
x[4] = 0x12;
x[5] = 0x34;
x[6] = 0xFF;
x[7] = 0xFF;
x[8] = 0xFF;
x[9] = 0xFF;
x[10] = 0xFF;
x[11] = 0x40;
x[12] = 0x00;
x[13] = 0x01;
x[14] = 0x76;
x[15] = 0x7B;
x[16] = 0x0D;
x[17] = 0x0A;
w = write (session_socket,x,sizeof(x));

Am I missing something?
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,034
Messages
2,570,356
Members
47,002
Latest member
RobertoLip

Latest Threads

Top