The online racing simulator
Simple OutGauge app in C not working
Hi, I was playing around a bit on my macbook, and made this app so I can get outgauge data to display on it in a fancy way
So I decided to make a simple application first in C and BSD sockets. I can receive the UDP packets fine, and can clearly see the car's name when the app receives a packet, but the rest is messed up.

As you can see I changed the default outgauge struct a bit, because there are no byte and word data types in C or objective-C, so I just put chars there with the right sizes.

Here is the code:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#define OG_SHIFTLIGHT 1
#define OG_FULLBEAM 2
#define OG_HANDBRAKE 4
#define OG_PITSPEED 8
#define OG_TC 16
#define OG_HEADLIGHTS 32
#define OG_SIGNAL_L 64
#define OG_SIGNAL_R 128
#define OG_REDLINE 256
#define OG_OILWARN 512
#define OG_1 1024
#define OG_2 2048
#define OG_3 4096
#define OG_4 8192
#define OG_KM 16384
#define OG_BAR 32768

#define MYPORT 55555 // the port users will be connecting to
#define MAXBUFLEN 96

typedef struct {
unsigned Time;
char Car[4];
char Flags[2];
char Gear;
char SpareB;
float Speed;
float RPM;
float Turbo; // BAR
float EngTemp; // C
float Fuel; // 0 to 1
float OilPress; // BAR
float Spare1;
float Spare2;
float Spare3;
float Throttle; // 0 to 1
float Brake; // 0 to 1
float Clutch; // 0 to 1
char Display1[16]; // Usually Fuel
char Display2[16]; // Usually Settings
} OutGauge;

int main(void)
{
int sockfd;
OutGauge new;
struct sockaddr_in my_addr; // my address information
struct sockaddr_in their_addr; // connector's address information
socklen_t addr_len;
int numbytes;

memset(&(new),'\0',96); // zero out the struct

if ((sockfd = socket(PF_INET, SOCK_DGRAM, 0)) == -1) {
perror("socket");
exit(1);
}

my_addr.sin_family = AF_INET;
my_addr.sin_port = htons(MYPORT); // short, network byte order
my_addr.sin_addr.s_addr = INADDR_ANY; // automatically fill with my IP
memset(&(my_addr.sin_zero), '\0', 8); // zero the rest of the struct

if (bind(sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr)) == -1) {
perror("bind");
exit(1);
}

addr_len = sizeof(struct sockaddr);
if ((numbytes=recvfrom(sockfd, &new, MAXBUFLEN-1 , 0, (struct sockaddr *)&their_addr, &addr_len)) == -1) {
perror("recvfrom");
exit(1);
}

printf("got packet from %s\n",inet_ntoa(their_addr.sin_addr));
printf("packet is %d bytes long\n\n", numbytes);

printf("Time = %u\n", new.Time);
printf("Car = %s\n", &new.Car);

printf("Speed = %f\n", new.Speed);
printf("RPM = %f\n", new.RPM);

close(sockfd);

return 0;
}

It would be great if someone can help me make this app work. By the way, I know this isn't the preferred style of coding, but it was just something simple.

Check the attachment to see the weird output sometimes. You can see it gets the type of car right, but everything else is just messed up.
Attached images
Picture 3.png
After a very quick scan, the things that immediately jump out;

You've got the struct wrong. Hence the screwed values.

Time should be an unsigned int, not unsigned. You shouldn't rely on int being the default datatype.

"word" is usually defined as an unsigned short (or the equivilent 2 byte datatype on your OS). You will also discover that in many non-windows systems WORD is defined, like BOOL, by default. This is what's causing your problem.

You should read BYTE's as unsigned char's.

Might want to rethink the recvfrom directly into the outgauge struct. You also want to rethink the size of the struct. It's not 96 bytes, unless you include the optional ID - which you don't have in your struct. This is a buffer overflow.
Ok, I've changed the things which you mentioned, and the app is still acting the same

The updated source is here:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#define OG_SHIFTLIGHT 1
#define OG_FULLBEAM 2
#define OG_HANDBRAKE 4
#define OG_PITSPEED 8
#define OG_TC 16
#define OG_HEADLIGHTS 32
#define OG_SIGNAL_L 64
#define OG_SIGNAL_R 128
#define OG_REDLINE 256
#define OG_OILWARN 512
#define OG_1 1024
#define OG_2 2048
#define OG_3 4096
#define OG_4 8192
#define OG_KM 16384
#define OG_BAR 32768

#define MYPORT 55555 // the port users will be connecting to
#define MAXBUFLEN 92

typedef struct
{
unsigned int Time; // time in milliseconds (to check order)

char Car [4]; // Car name
unsigned short Flags; // OG_FLAGS (see below)
unsigned char Gear; // Reverse:0, Neutral:1, First:2...
unsigned char SpareB;
float Speed; // M/S
float RPM; // RPM
float Turbo; // BAR
float EngTemp; // C
float Fuel; // 0 to 1
float OilPress; // BAR
float Spare1;
float Spare2;
float Spare3;
float Throttle; // 0 to 1
float Brake; // 0 to 1
float Clutch; // 0 to 1
char Display1[16]; // Usually Fuel
char Display2[16]; // Usually Settings
}OutGauge;

int main(void)
{
int sockfd;
OutGauge new;
struct sockaddr_in my_addr; // my address information
struct sockaddr_in their_addr; // connector's address information
socklen_t addr_len;
int numbytes;

memset(&(new),'\0',95); // zero out the struct

if ((sockfd = socket(PF_INET, SOCK_DGRAM, 0)) == -1) {
perror("socket");
exit(1);
}

my_addr.sin_family = AF_INET;
my_addr.sin_port = htons(MYPORT); // short, network byte order
my_addr.sin_addr.s_addr = INADDR_ANY; // automatically fill with my IP
memset(&(my_addr.sin_zero), '\0', 8); // zero the rest of the struct

if (bind(sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr)) == -1) {
perror("bind");
exit(1);
}

addr_len = sizeof(struct sockaddr);
if ((numbytes=recvfrom(sockfd, &new, MAXBUFLEN-1 , 0, (struct sockaddr *)&their_addr, &addr_len)) == -1) {
perror("recvfrom");
exit(1);
}
new.Speed = htonl(new.Speed);
printf("\n\ngot packet from %s\n",inet_ntoa(their_addr.sin_addr));
printf("packet is %d bytes long\n\n", numbytes);

printf("Time = %u, memory address is %X\n", new.Time &new.Time);
printf("Car = %s, memory address is %X\n", &new.Car, &new.Car);

printf("Speed = %f, memory address is %X\n", new.Speed, &new.Speed);
printf("RPM = %f, memory address is %X\n", new.RPM, &new.RPM);

close(sockfd);

return 0;
}

You can see the output in the attachment along with the memory addresses (check the memory address of new.Time )

The thing that is still puzzelling me, is that the car name is read perfectly everytime, but the other field are just bogus.
By the way, if you have a better way to get the data from recvfrom() to a structure, please post. There isn't a single tutorial or sample app here in C or Objective-C, so I really need some help.
Attached images
Picture 5.png
I'm actually quite interested in this, seeing I have my iMac, and having an outgauge program connected to LFS may be rather useful, Mikey, do you happen to have MSN? I may be able to help a bit.
pm sent

Well, I'm trying to make 2 full screen apps in Mac OS X. 1 that shows a pitboard so I can drive with shift-F on, and another one that shows all the outgauge of a group of people, so you can track your team for example.
But the future of those apps look pale, when I can't even make this simple app work
Hmm, maybe finding a Cocoa developers forum might possibly help with development of said application?
Well, the only thing I have to focus on now is getting this to work, so it's better if I stay here to solve the outgauge problem.
Making those full screen apps in cocoa wouldn't be a big problem, because there are good resources for it if you get stuck.
Hi,
after quick look, you are missing the __attribute__ ((packed)) for OutGauge struct definition, i. e.:
typedef struct {
...
} __attribute__ ((packed)) OutGaugePacket;

If you have "char" as struct field, it doesn't mean (without "packed" keyword), that it takes only one byte in memory (google packed, c, struct for explanation). Maybe for your compiler the __attribute__ ((packed)) has to be something different, look at documentation for your compiler.

You may look at sources in C for my Gear Indicator to see working app (the main.c is kind of mess, I know :-)).
Cocoa is amazingly easy to create a GUI for, it should almost be illegal. I created a string character counter in like 3 minutes, with a GUI that looks remarkably sexy.
Well, I've added that to my structure, but didn't solve anything. I also did a sizeof() on the structure, and with and without it came back as 92 bytes in total.
I will definitely look at your sources to discover how you're doing it (and I'm quite used to messy code ).
Quote from dawesdust_12 :Cocoa is amazingly easy to create a GUI for, it should almost be illegal. I created a string character counter in like 3 minutes, with a GUI that looks remarkably sexy.

Yup, everything looks hot in Cocoa
Your updated code, that you have posted above, still misses the "int ID" field, as the_angry_angel mentioned. The field is _not_ optional in the declaration, it's optional to use it.
Yeah, here the lastest version, with the ID int because I do want to have that in my app.

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#define OG_SHIFTLIGHT 1
#define OG_FULLBEAM 2
#define OG_HANDBRAKE 4
#define OG_PITSPEED 8
#define OG_TC 16
#define OG_HEADLIGHTS 32
#define OG_SIGNAL_L 64
#define OG_SIGNAL_R 128
#define OG_REDLINE 256
#define OG_OILWARN 512
#define OG_1 1024
#define OG_2 2048
#define OG_3 4096
#define OG_4 8192
#define OG_KM 16384
#define OG_BAR 32768

#define MYPORT 55555 // the port users will be connecting to
#define MAXBUFLEN 92

typedef struct
{
unsigned int Time; // time in milliseconds (to check order)

char Car [4]; // Car name
unsigned short Flags; // OG_FLAGS (see below)
unsigned char Gear; // Reverse:0, Neutral:1, First:2...
unsigned char SpareB;
float Speed; // M/S
float RPM; // RPM
float Turbo; // BAR
float EngTemp; // C
float Fuel; // 0 to 1
float OilPress; // BAR
float Spare1;
float Spare2;
float Spare3;
float Throttle; // 0 to 1
float Brake; // 0 to 1
float Clutch; // 0 to 1
char Display1[16]; // Usually Fuel
char Display2[16]; // Usually Settings
int ID;
} __attribute__ ((packed)) OutGaugePacket;

int main(void)
{
int sockfd;
OutGaugePacket og_packet;
struct sockaddr_in my_addr; // my address information
struct sockaddr_in their_addr; // connector's address information
socklen_t addr_len;
int numbytes;

//memset(&(og_packet),'\0',95); // zero out the struct

if ((sockfd = socket(PF_INET, SOCK_DGRAM, 0)) == -1) {
perror("socket");
exit(1);
}

my_addr.sin_family = AF_INET;
my_addr.sin_port = htons(MYPORT); // short, network byte order
my_addr.sin_addr.s_addr = INADDR_ANY; // automatically fill with my IP
memset(&(my_addr.sin_zero), '\0', 8); // zero the rest of the struct

if (bind(sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr)) == -1) {
perror("bind");
exit(1);
}

addr_len = sizeof(struct sockaddr);
if ((numbytes=recvfrom(sockfd, &og_packet, MAXBUFLEN-1 , 0, (struct sockaddr *)&their_addr, &addr_len)) == -1) {
perror("recvfrom");
exit(1);
}

printf("\n\ngot packet from %s\n",inet_ntoa(their_addr.sin_addr));
printf("packet is %d bytes long\n\n", numbytes);

printf("Time = %u, memory address is %X\n", og_packet.Time &og_packet.Time);
printf("Car = %s, memory address is %X\n", &og_packet.Car, &og_packet.Car);

printf("Speed = %f, memory address is %X\n", og_packet.Speed, &og_packet.Speed);
printf("RPM = %f, memory address is %X\n", og_packet.RPM, &og_packet.RPM);
printf("ID of connection = %d", og_packet.ID);
printf("\nsizeof struct = %d", sizeof(og_packet));

close(sockfd);

return 0;
}

As you can see, I stole your packet name, it made more sense

The above is still not working btw
Ok, let's make things working :-). There is comma missing between og_packet.Time and &og_packet.Time. Surprisingly, my gcc compiles it, only with warning. The "MAXBUFLEN-1" should be: sizeof (OutGaugePacket). Then it works, at least for me. Maybe it just doesn't produce the results, that you are expected. The speed is in metres per second. Receive more then one packed in a loop and observe what happens.
oy, that comma was indeed a bad mistake. Xcode didn't even complain about it (shows how good it is)
But I'll definitely try to make this working tomorrow in a loop, and if it doesn't I'll just start from scratch again with your sources as guidance.

btw, I did the changes you said, but i still get huge floating point numbers as results, and they're hardly stable (sometimes a negative number, sometimes positive, maybe there are some alignment issues, but I can't really find them).
It seems, that I was wrong with the "int ID" field. If "OutGauge ID" is set to 0 in the cfg.txt, then LFS (0.5W) sends only 92 bytes in the packet. If "OutGauge ID" is anything nonzero, then LFS send 96 bytes. I'm not sure, if it's a bug or a feature .
Quote from mikey_G :
btw, I did the changes you said, but i still get huge floating point numbers as results, and they're hardly stable (sometimes a negative number, sometimes positive, maybe there are some alignment issues, but I can't really find them).

Ha, maybe I got it. Mac is a "big endian" system, PC is a "little endian", maybe this is the problem.
Quote from Kada_CZ :It seems, that I was wrong with the "int ID" field. If "OutGauge ID" is set to 0 in the cfg.txt, then LFS (0.5W) sends only 92 bytes in the packet. If "OutGauge ID" is anything nonzero, then LFS send 96 bytes. I'm not sure, if it's a bug or a feature .

Yeah, I just tried that, and that's the case, pretty weird normal behaviour if you ask me

Quote from Kada_CZ :Ha, maybe I got it. Mac is a "big endian" system, PC is a "little endian", maybe this is the problem.

Hmm, kinda forgot how to change that around. I know that with the port and ip address you can do htons() and htonl(). I'll try to look a bit more into this.
try:
printf("RPM = %f, memory address is %X\n", (float)ntohl((unsigned int)og_packet.RPM), &og_packet.RPM);

or
printf("RPM = %f, memory address is %X\n", (float)htonl((unsigned int)og_packet.RPM), &og_packet.RPM);

Tried them both, this is the output what i get, your commands are on the bottom

[Session started at 2007-04-24 00:31:52 +0200.]


got packet from 192.168.1.2
packet is 96 bytes long

Time = 2929786880, memory address is BFFFF950
Car = RB4, memory address is BFFFF954
Speed = 1587048.125000, memory address is BFFFF95C
RPM = -29579291864432017246519296.000000, memory address is BFFFF960
ID of connection = 16777216
sizeof struct = 96

RPM = 2147483648.000000, memory address is BFFFF960

RPM = 2147483648.000000, memory address is BFFFF960


OutGuage has exited with status 0.

I'm getting more confused by the moment, and have an urge to throw this mac away
Don't throw it away, mail it to Canada :P
No, but seriously, I had some plans for some nice apps but if I'm not even able to do this then I beter throw them into the bin.
So far my only accomplishments are getting the car name and getting a connection ID that actually stays stable, the other values just change with every packet
Quote :ID of connection = 16777216

This is right, if you have "OutGauge ID" set to 1. 16777216 = 0x01 00 00 00. Probably the endian conversion for floats should be different.

EDIT: I was wrong again. Don't use htonl functions, on Mac it simply returns the argument. You have to write your own conversion func. Try one of these:
#define HTONL(n) (((((unsigned long)(n) & 0xFF)) << 24) | \
((((unsigned long)(n) & 0xFF00)) << 8) | \
((((unsigned long)(n) & 0xFF0000)) >> 8) | \
((((unsigned long)(n) & 0xFF000000)) >> 24))

#define NTOHL(n) (((((unsigned long)(n) & 0xFF)) << 24) | \
((((unsigned long)(n) & 0xFF00)) << 8) | \
((((unsigned long)(n) & 0xFF0000)) >> 8) | \
((((unsigned long)(n) & 0xFF000000)) >> 24))

(stolen from inet.h)
So try something like:
Quote :printf("RPM = %f, memory address is %X\n", (float)NTOHL((unsigned int)og_packet.RPM), &og_packet.RPM);

or the other one.
Ok, got the connection number endiannes swapped with this

// 4-byte number
int INT_little_endian_TO_big_endian(int i)
{
return((i&0xff)<<24)+((i&0xff00)<<8)+((i&0xff0000)>>8)+((i>>24)&0xff);
}

It now shows Connection number = 1

babysteps for me
Quote from Kada_CZ :
#define HTONL(n) (((((unsigned long)(n) & 0xFF)) << 24) | \
((((unsigned long)(n) & 0xFF00)) << 8) | \
((((unsigned long)(n) & 0xFF0000)) >> 8) | \
((((unsigned long)(n) & 0xFF000000)) >> 24))

#define NTOHL(n) (((((unsigned long)(n) & 0xFF)) << 24) | \
((((unsigned long)(n) & 0xFF00)) << 8) | \
((((unsigned long)(n) & 0xFF0000)) >> 8) | \
((((unsigned long)(n) & 0xFF000000)) >> 24))


It works great for the ints, time and connection ID show up perfectly, but the floats are still messed up

[Session started at 2007-04-24 01:11:59 +0200.]


got packet from 192.168.1.2
packet is 96 bytes long

Time = 255830, memory address is BFFFF790
Car = RB4, memory address is BFFFF794
Speed = 0.000000, memory address is A
RPM = -419242517033593602048.000000, memory address is BFFFF7A0
ID of connection = 1
sizeof struct = 96

RPM = 128.000000, memory address is BFFFF7A0

RPM = 128.000000, memory address is BFFFF7A0

RPM = 128.000000, memory address is BFFFF7A0

OutGuage has exited with status 0.
[Session started at 2007-04-24 01:12:04 +0200.]


got packet from 192.168.1.2
packet is 96 bytes long

Time = 261400, memory address is BFFFF790
Car = RB4, memory address is BFFFF794
Speed = nan, memory address is A
RPM = -16382559176468975824404480.000000, memory address is BFFFF7A0
ID of connection = 1
sizeof struct = 96

RPM = 128.000000, memory address is BFFFF7A0

RPM = 128.000000, memory address is BFFFF7A0

RPM = 128.000000, memory address is BFFFF7A0

OutGuage has exited with status 0.

But indeed, the OSX functions were just nothing more then some useless shit, weird...
I did get warnings though that I was overriding NTOHL and HTONL, so maybe they existed already.
1

FGED GREDG RDFGDR GSFDG