Add support for Forza telemetry to PQ35 CAN bus
This commit is contained in:
parent
2d41df1c83
commit
c130714bca
7 changed files with 163 additions and 15 deletions
|
@ -7,7 +7,8 @@ INCLUDE_PATH = ../include
|
|||
CFLAGS += -I$(INCLUDE_PATH)
|
||||
LDFLAGS = -L../src -lhexagram
|
||||
STATIC = ../src/libhexagram.a
|
||||
OBJS = capture.o can2dump.o replay.o pcapreplay.o pcap2can.o main.o
|
||||
OBJS = capture.o can2dump.o replay.o pcapreplay.o pcap2can.o main.o \
|
||||
dash2can.o
|
||||
NAME = hexagram
|
||||
|
||||
INSTALL = install
|
||||
|
|
143
bin/dash2can.c
Normal file
143
bin/dash2can.c
Normal file
|
@ -0,0 +1,143 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#include <math.h>
|
||||
#include <inttypes.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <hexagram/can.h>
|
||||
#include <hexagram/capture.h>
|
||||
#include <hexagram/telemetry/forza-dash.h>
|
||||
|
||||
#include "dash2can.h"
|
||||
|
||||
char *hexagram_arglist_dash2can(void) {
|
||||
return "udp-port canif";
|
||||
}
|
||||
|
||||
static void usage(int argc, char **argv, const char *message, ...) {
|
||||
if (message) {
|
||||
va_list args;
|
||||
|
||||
va_start(args, message);
|
||||
vfprintf(stderr, message, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
fprintf(stderr, "usage: hexagram %s %s\n", argv[0], hexagram_arglist_dash2can());
|
||||
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int hexagram_main_dash2can(int argc, char **argv) {
|
||||
int sock;
|
||||
|
||||
struct sockaddr_in sockaddr;
|
||||
hexagram_can_if *can_if;
|
||||
|
||||
if (argc < 2) {
|
||||
usage(argc, argv, "No listening UDP port provided");
|
||||
} else if (argc < 3) {
|
||||
usage(argc, argv, "No CAN interface name provided");
|
||||
} else if (argc > 3) {
|
||||
usage(argc, argv, "Too many arguments provided");
|
||||
}
|
||||
|
||||
if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
|
||||
goto error_socket;
|
||||
}
|
||||
|
||||
memset(&sockaddr, '\0', sizeof(sockaddr));
|
||||
sockaddr.sin_family = AF_INET;
|
||||
sockaddr.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||
sockaddr.sin_port = htons(atoi(argv[1]));
|
||||
|
||||
if (bind(sock, (struct sockaddr *)&sockaddr, sizeof(sockaddr)) < 0) {
|
||||
goto error_bind;
|
||||
}
|
||||
|
||||
if ((can_if = hexagram_can_if_open(argv[2])) == NULL) {
|
||||
perror("hexagram_can_if_open()");
|
||||
|
||||
goto error_can_if_open;
|
||||
}
|
||||
|
||||
while (1) {
|
||||
hexagram_telemetry_forza_dash_packet packet;
|
||||
struct can_frame frame;
|
||||
ssize_t len;
|
||||
|
||||
float speed_ms = sqrt(powf(packet.velocity.x, 2)
|
||||
+ powf(packet.velocity.z, 2));
|
||||
|
||||
uint16_t engine_rpm = (uint16_t)(packet.engine_rpm.current * 4),
|
||||
speed_rps = (uint16_t)(speed_ms * 2.0);
|
||||
|
||||
if ((len = recv(sock, &packet, sizeof(packet), 0)) < 0) {
|
||||
goto error_io;
|
||||
} else if (len < (ssize_t)sizeof(packet)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Engine speed */
|
||||
memset(&frame, '\0', sizeof(frame));
|
||||
frame.can_id = 0x280;
|
||||
frame.data[3] = (engine_rpm & 0xff00) >> 8;
|
||||
frame.data[2] = engine_rpm & 0x00ff;
|
||||
|
||||
if (hexagram_can_if_write(can_if, &frame) < 0) {
|
||||
goto error_io;
|
||||
}
|
||||
|
||||
/* Engine temperature */
|
||||
memset(frame.data, '\0', sizeof(frame.data));
|
||||
frame.can_id = 0x288;
|
||||
frame.data[1] = (uint8_t)((87.0 / 0.75) + 48);
|
||||
|
||||
if (hexagram_can_if_write(can_if, &frame) < 0) {
|
||||
goto error_io;
|
||||
}
|
||||
|
||||
/* Fuel status */
|
||||
memset(frame.data, '\0', sizeof(frame.data));
|
||||
frame.can_id = 0x320;
|
||||
frame.data[2] = ((uint8_t)(packet.car.fuel / 15.0) & 0xff);
|
||||
|
||||
if (hexagram_can_if_write(can_if, &frame) < 0) {
|
||||
goto error_io;
|
||||
}
|
||||
|
||||
/* Vehicle speed */
|
||||
memset(frame.data, '\0', sizeof(frame.data));
|
||||
frame.can_id = 0x5a0;
|
||||
frame.data[1] = (speed_rps & 0xff00) >> 8;
|
||||
frame.data[2] = speed_rps & 0x00ff;
|
||||
|
||||
if (hexagram_can_if_write(can_if, &frame) < 0) {
|
||||
goto error_io;
|
||||
}
|
||||
}
|
||||
|
||||
hexagram_can_if_close(can_if);
|
||||
|
||||
close(sock);
|
||||
|
||||
return 0;
|
||||
|
||||
error_io:
|
||||
fprintf(stderr, "BOO: %s\n", strerror(errno));
|
||||
hexagram_can_if_close(can_if);
|
||||
|
||||
error_can_if_open:
|
||||
error_bind:
|
||||
close(sock);
|
||||
|
||||
error_socket:
|
||||
return 1;
|
||||
}
|
8
bin/dash2can.h
Normal file
8
bin/dash2can.h
Normal file
|
@ -0,0 +1,8 @@
|
|||
#ifndef _DASH2CAN_H
|
||||
#define _DASH2CAN_H
|
||||
|
||||
char *hexagram_arglist_dash2can(void);
|
||||
|
||||
int hexagram_main_dash2can(int argc, char **argv);
|
||||
|
||||
#endif /* _DASH2CAN_H */
|
|
@ -8,6 +8,7 @@
|
|||
#include "can2dump.h"
|
||||
#include "pcap2can.h"
|
||||
#include "pcapreplay.h"
|
||||
#include "dash2can.h"
|
||||
|
||||
typedef struct {
|
||||
const char *name;
|
||||
|
@ -21,6 +22,7 @@ hexagram_app apps[] = {
|
|||
{ "can2dump", hexagram_arglist_can2dump, hexagram_main_can2dump },
|
||||
{ "pcap2can", hexagram_arglist_pcap2can, hexagram_main_pcap2can },
|
||||
{ "pcapreplay", hexagram_arglist_pcapreplay, hexagram_main_pcapreplay },
|
||||
{ "dash2can", hexagram_arglist_dash2can, hexagram_main_dash2can },
|
||||
{ NULL, NULL, NULL }
|
||||
};
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include <hexagram/gauge.h>
|
||||
|
||||
#define HEXAGRAM_SPEEDO_MAX_KPH 289.682
|
||||
#define HEXAGRAM_SPEEDO_MAX_MPH 180.000
|
||||
|
||||
typedef struct _hexagram_speedo {
|
||||
hexagram_gauge gauge;
|
||||
|
|
|
@ -4,14 +4,6 @@
|
|||
#include <inttypes.h>
|
||||
#include <hexagram/types.h>
|
||||
|
||||
hexagram_coord {
|
||||
float x, y, z;
|
||||
};
|
||||
|
||||
hexagram_corner {
|
||||
float front_left, front_right, rear_left, rear_right;
|
||||
};
|
||||
|
||||
typedef struct _hexagram_telemetry_forza_dash_car {
|
||||
int32_t id,
|
||||
class,
|
||||
|
|
13
src/speedo.c
13
src/speedo.c
|
@ -61,16 +61,17 @@ void hexagram_speedo_draw_face(hexagram_speedo *speedo,
|
|||
void hexagram_speedo_draw_needle(hexagram_speedo *speedo,
|
||||
cairo_t *cr,
|
||||
double rps) {
|
||||
double kph = (2.00152 * rps * 3600) / 1000.0;
|
||||
double kph = (2.00152 * rps * 3600) / 1000.0,
|
||||
mph = kph * 0.621371;
|
||||
|
||||
if (kph < 0) {
|
||||
kph = 0;
|
||||
} else if (kph > 290) {
|
||||
kph = 290;
|
||||
if (mph < 0) {
|
||||
mph = 0;
|
||||
} else if (mph > HEXAGRAM_SPEEDO_MAX_MPH) {
|
||||
mph = HEXAGRAM_SPEEDO_MAX_MPH;
|
||||
}
|
||||
|
||||
hexagram_gauge_draw_needle(&speedo->gauge,
|
||||
cr,
|
||||
0.8,
|
||||
kph / HEXAGRAM_SPEEDO_MAX_KPH);
|
||||
mph / HEXAGRAM_SPEEDO_MAX_MPH);
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue