Add GT Neo LED update feature
This commit is contained in:
parent
6c902b4c2b
commit
b90c396d34
|
|
@ -29,6 +29,8 @@ set(devices_source_files
|
|||
usb/wheels/cammusc5.c
|
||||
usb/wheels/cammusc12.h
|
||||
usb/wheels/cammusc12.c
|
||||
usb/wheels/gtneo.h
|
||||
usb/wheels/gtneo.c
|
||||
sound/usb_generic_shaker_pulse.c
|
||||
serial/arduino.h
|
||||
serial/arduino.c
|
||||
|
|
|
|||
|
|
@ -0,0 +1,225 @@
|
|||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
#include <unistd.h>
|
||||
#include <hidapi/hidapi.h>
|
||||
|
||||
#include "gtneo.h"
|
||||
#include <string.h>
|
||||
#include "../../../slog/slog.h"
|
||||
#include "../../serial/arduinoledlua.h"
|
||||
|
||||
// Simagic allows setting any led, therefore LED index should be defined.
|
||||
struct LED {
|
||||
uint8_t index;
|
||||
uint8_t red;
|
||||
uint8_t green;
|
||||
uint8_t blue;
|
||||
};
|
||||
|
||||
// Simagic is using SEND_FEATURE_REPORT
|
||||
// ReportID is 240 (0xf0)
|
||||
// Data length is 64 bytes
|
||||
// Prefix is 00 00 00 00 00
|
||||
// Then we have some descriptor. I had 0xEC and 0x03.
|
||||
// Then: length of LED array
|
||||
// Then: number of LED in hex
|
||||
// RGB value for that LED
|
||||
|
||||
|
||||
void prepare_device(hid_device *device) {
|
||||
uint8_t prepare_report[SIMAGIC_MAX_PAYLOAD_SIZE] = {0};
|
||||
prepare_report[0] = 0x00;
|
||||
prepare_report[1] = 0x00;
|
||||
prepare_report[2] = 0x00;
|
||||
prepare_report[3] = 0x00;
|
||||
prepare_report[4] = 0x00;
|
||||
prepare_report[5] = SIMAGIC_LED_DESCRIPTOR_LED_CONTROL;
|
||||
prepare_report[6] = SIMAGIC_LED_DESCRIPTOR_PREPARE_LEDS;
|
||||
prepare_report[7] = 0x01;
|
||||
|
||||
uint8_t report_id_with_data[SIMAGIC_MAX_PAYLOAD_SIZE] = {SIMAGIC_LED_REPORT_ID}; // Report ID at the start
|
||||
memcpy(&report_id_with_data[1], prepare_report, SIMAGIC_MAX_PAYLOAD_SIZE-1);
|
||||
|
||||
// Send the HID feature report
|
||||
int res = hid_send_feature_report(device, report_id_with_data, sizeof(report_id_with_data));
|
||||
if (res < 0) {
|
||||
fprintf(stderr, "Failed to send HID feature report\n");
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Arbitrary function for sending out leds to simagic.
|
||||
Inputs:
|
||||
device: hid_device handle
|
||||
leds: array of the struct LED
|
||||
led_count: count of leds in leds array
|
||||
*/
|
||||
int send_leds(hid_device *device, struct LED* leds, size_t led_count) {
|
||||
uint8_t descriptor[2] = {SIMAGIC_LED_DESCRIPTOR_LED_CONTROL, SIMAGIC_LED_DESCRIPTOR_SET_LEDS};
|
||||
|
||||
prepare_device(device);
|
||||
int result = 0;
|
||||
size_t led_i = 0;
|
||||
while (led_i < led_count) {
|
||||
size_t chunk_length = (SIMAGIC_MAX_PAYLOAD_SIZE -1-9) / 4; // 1 for reportid, 9 bytes for header, rest for LED data (each LED is 4 bytes)
|
||||
size_t chunk_size = chunk_length * 4;
|
||||
|
||||
uint8_t report[SIMAGIC_MAX_PAYLOAD_SIZE] = {0}; // SIMAGIC_MAX_PAYLOAD_SIZE bytes per report
|
||||
memcpy(report, (uint8_t[]){0x00, 0x00, 0x00, 0x00, 0x00}, 5); // Set the prefix (5 bytes)
|
||||
|
||||
memcpy(&report[5], descriptor, 2); // Set the descriptor (2 bytes)
|
||||
|
||||
// Fill in the LED data
|
||||
for (size_t i = 0; i < chunk_length && led_i + i < led_count; ++i) {
|
||||
memcpy(&report[8+i*4], &leds[led_i+i], 4);
|
||||
report[7]++; // Set the LED array length for this chunk
|
||||
}
|
||||
|
||||
uint8_t report_id_with_data[SIMAGIC_MAX_PAYLOAD_SIZE] = {SIMAGIC_LED_REPORT_ID};
|
||||
memcpy(&report_id_with_data[1], report, SIMAGIC_MAX_PAYLOAD_SIZE-1);
|
||||
|
||||
// Send the HID feature report
|
||||
int res = hid_send_feature_report(device, report_id_with_data, sizeof(report_id_with_data));
|
||||
if (res < 0) {
|
||||
fprintf(stderr, "Failed to send HID feature report chunk\n");
|
||||
return -1;
|
||||
}
|
||||
result += res;
|
||||
|
||||
// Move to the next chunk of LEDs
|
||||
led_i += chunk_length;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
// default simpro profile:
|
||||
// 97: b b b b b b b b b b b b b b b //flashing
|
||||
// 93: b b b b b b b b b b b b b b b //flashing
|
||||
// 90: g g g g g g g g g y y y w w w
|
||||
// 88: g g g g g g g g g y y y
|
||||
// 85: g g g g g g g g g
|
||||
// 83: g g g g g g g
|
||||
// 78: g g g g g
|
||||
// 75: g g g
|
||||
// 70: g
|
||||
// less: empty (000000)
|
||||
// Telemetry LEDs are 58-72
|
||||
|
||||
|
||||
int simagic_gtneo_customled_update(USBDevice* usbdevice, SimData* simdata)
|
||||
{
|
||||
int res = 1;
|
||||
|
||||
size_t led_count = GT_NEO_LEDS_TOTAL-GT_NEO_LEDS_TELEMETRY_START; // Expose whole LED array
|
||||
size_t bufsize = (led_count * 3);
|
||||
char ledbytes[bufsize];
|
||||
for(int x = 0; x < bufsize; x++)
|
||||
ledbytes[x] = 0x00;
|
||||
|
||||
lua_State* L = usbdevice->m.L;
|
||||
|
||||
lua_pushstring(L, "buff");
|
||||
lua_pushlightuserdata(L, &ledbytes);
|
||||
lua_settable(L, LUA_REGISTRYINDEX);
|
||||
|
||||
simdata_to_lua(L, simdata);
|
||||
lua_setglobal(L, "simdata");
|
||||
|
||||
lua_pushinteger(L, led_count);
|
||||
lua_setglobal(L, "TotalLeds");
|
||||
|
||||
lua_register(L, "set_led_to_color", set_led_to_color);
|
||||
lua_register(L, "set_led_range_to_color", set_led_range_to_color);
|
||||
lua_register(L, "set_led_to_rgb_color", set_led_to_rgb_color);
|
||||
lua_register(L, "set_led_range_to_rgb_color", set_led_range_to_rgb_color);
|
||||
lua_register(L, "led_clear_all", led_clear_all);
|
||||
|
||||
lua_pushinteger(L, LUALEDCOLOR_RED);
|
||||
lua_setglobal(L, "RED");
|
||||
lua_pushinteger(L, LUALEDCOLOR_GREEN);
|
||||
lua_setglobal(L, "GREEN");
|
||||
lua_pushinteger(L, LUALEDCOLOR_BLUE);
|
||||
lua_setglobal(L, "BLUE");
|
||||
lua_pushinteger(L, LUALEDCOLOR_YELLOW);
|
||||
lua_setglobal(L, "YELLOW");
|
||||
lua_pushinteger(L, LUALEDCOLOR_ORANGE);
|
||||
lua_setglobal(L, "ORANGE");
|
||||
|
||||
lua_getglobal(L,"myFunc");
|
||||
if (lua_pcall(L, 0, 0, 0) != LUA_OK)
|
||||
{
|
||||
fprintf(stderr, "Error calling Lua script: %s\n", lua_tostring(L, -1));
|
||||
}
|
||||
|
||||
// ledbytes is an array of leds. We need to copy colours to our struct LED and call 'send_leds'
|
||||
struct LED teleleds[led_count];
|
||||
|
||||
for (int i = 0; i < led_count; i++) {
|
||||
teleleds[i] = (struct LED){GT_NEO_LEDS_TELEMETRY_START+i, 0x00, 0x00, 0x00};
|
||||
teleleds[i].red = ledbytes[(i * 3) + 0];
|
||||
teleleds[i].green = ledbytes[(i * 3) + 1];
|
||||
teleleds[i].blue = ledbytes[(i * 3) + 2];
|
||||
}
|
||||
|
||||
res = send_leds(usbdevice->handle, teleleds, led_count);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
int simagic_gtneo_init(USBDevice* wheeldevice, const char* luafile)
|
||||
{
|
||||
wheeldevice->u.wheeldevice.useLua = false;
|
||||
|
||||
slogi("initializing Simagic GT Neo wheel...");
|
||||
|
||||
int res = 0;
|
||||
|
||||
res = hid_init();
|
||||
|
||||
wheeldevice->handle = hid_open(SIMAGIC_GTNEO_VENDORID, SIMAGIC_GTNEO_PRODUCTID, NULL);
|
||||
|
||||
if (!wheeldevice->handle)
|
||||
{
|
||||
sloge("Could not find attached GT Neo Wheel");
|
||||
res = hid_exit();
|
||||
return 1;
|
||||
}
|
||||
slogd("Found Simagic GT Neo Wheel...");
|
||||
|
||||
slogt("Using lua file");
|
||||
|
||||
lua_State* L = luaL_newstate();
|
||||
luaL_openlibs(L);
|
||||
|
||||
//int top=lua_gettop(L);
|
||||
int status = luaL_loadfile(L, luafile);
|
||||
|
||||
if (status) {
|
||||
/* If something went wrong, error message is at the top of */
|
||||
/* the stack */
|
||||
sloge("There is an issue with your lua script");
|
||||
fprintf(stderr, "Couldn't load file: %s\n", lua_tostring(L, -1));
|
||||
lua_close(L);
|
||||
return -1;
|
||||
//exit(1);
|
||||
}
|
||||
|
||||
wheeldevice->u.wheeldevice.useLua = true;
|
||||
lua_setglobal(L,"myFunc");
|
||||
|
||||
wheeldevice->m.L = L;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
int simagic_gtneo_free(USBDevice* wheeldevice)
|
||||
{
|
||||
int res = 0;
|
||||
|
||||
hid_close(wheeldevice->handle);
|
||||
res = hid_exit();
|
||||
|
||||
return res;
|
||||
}
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
#ifndef _GTNEO_H
|
||||
#define _GTNEO_H
|
||||
|
||||
#include "../../wheeldevice.h"
|
||||
#include "../../simdevice.h"
|
||||
|
||||
#define SIMAGIC_GTNEO_VENDORID 0x3670
|
||||
#define SIMAGIC_GTNEO_PRODUCTID 0x0805
|
||||
|
||||
#define SIMAGIC_MAX_PAYLOAD_SIZE 64
|
||||
#define SIMAGIC_LED_REPORT_ID 0xf0 // LED control report id?
|
||||
|
||||
#define SIMAGIC_LED_DESCRIPTOR_LED_CONTROL 0xEC // LED control?
|
||||
#define SIMAGIC_LED_DESCRIPTOR_PREPARE_LEDS 0x02 //probably something like 'prepare led canvas'
|
||||
#define SIMAGIC_LED_DESCRIPTOR_SET_LEDS 0x03 //probably 'set temporare leds'
|
||||
|
||||
// expose whole LED array to the lua.
|
||||
// Telemetry leds are 58-72
|
||||
#define GT_NEO_LEDS_TELEMETRY_START 0
|
||||
#define GT_NEO_LEDS_TOTAL 73
|
||||
|
||||
int simagic_gtneo_init(USBDevice* wheeldevice, const char* luafile);
|
||||
int simagic_gtneo_free(USBDevice* wheeldevice);
|
||||
int simagic_gtneo_customled_update(USBDevice* usbdevice, SimData* simdata);
|
||||
|
||||
#endif
|
||||
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
#include "usb/wheels/cammusc5.h"
|
||||
#include "usb/wheels/cammusc12.h"
|
||||
#include "usb/wheels/gtneo.h"
|
||||
#include "serial/moza.h"
|
||||
|
||||
#include "simdevice.h"
|
||||
|
|
@ -30,7 +31,16 @@ int wheeldev_update(USBDevice* usbdevice, SimData* simdata)
|
|||
cammusc12_update(usbdevice, simdata->maxrpm, simdata->rpms, simdata->gear, simdata->velocity);
|
||||
}
|
||||
break;
|
||||
|
||||
case WHEELDEV_SIMAGICGTNEO :
|
||||
if(usbdevice->u.wheeldevice.useLua == true)
|
||||
{
|
||||
simagic_gtneo_customled_update(usbdevice, simdata);
|
||||
}
|
||||
else
|
||||
{
|
||||
sloge("GT Neo requires config file");
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
@ -93,6 +103,28 @@ int wheeldev_init(USBDevice* usbdevice, DeviceSettings* ds)
|
|||
error = cammusc12_init(usbdevice, NULL);
|
||||
}
|
||||
break;
|
||||
case SIMDEVSUBTYPE_SIMAGICGTNEO:
|
||||
wheeldevice->type = WHEELDEV_SIMAGICGTNEO;
|
||||
slogi("Attempting to initialize Simagic GT Neo");
|
||||
|
||||
if(ds->has_config == true)
|
||||
{
|
||||
usbdevice->m.device_specific_config_file = strdup(ds->specific_config_file);
|
||||
error = simagic_gtneo_init(usbdevice, usbdevice->m.device_specific_config_file);
|
||||
if(error != 0)
|
||||
{
|
||||
if(usbdevice->m.device_specific_config_file != NULL)
|
||||
{
|
||||
free(usbdevice->m.device_specific_config_file);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sloge("Simagic GT Neo requires lua config file to function");
|
||||
error = -1;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
wheeldevice->type = WHEELDEV_UNKNOWN;
|
||||
slogw("Unknown cammus wheel detected, trying C5");
|
||||
|
|
|
|||
|
|
@ -11,7 +11,8 @@ typedef enum
|
|||
WHEELDEV_UNKNOWN = 0,
|
||||
WHEELDEV_CAMMUSC5 = 1,
|
||||
WHEELDEV_CAMMUSC12 = 2,
|
||||
WHEELDEV_MOZAR5 = 3
|
||||
WHEELDEV_MOZAR5 = 3,
|
||||
WHEELDEV_SIMAGICGTNEO = 4
|
||||
}
|
||||
WheelType;
|
||||
|
||||
|
|
|
|||
|
|
@ -113,6 +113,11 @@ int strtodevsubsubtype(const char* device_subsubtype, DeviceSettings* ds)
|
|||
ds->dev_subsubtype = SIMDEVSUBTYPE_SIMAGICP1000PEDALS;
|
||||
devfound = true;
|
||||
}
|
||||
if (strcicmp(device_subsubtype, "SIMAGICGTNEO") == 0)
|
||||
{
|
||||
ds->dev_subsubtype = SIMDEVSUBTYPE_SIMAGICGTNEO;
|
||||
devfound = true;
|
||||
}
|
||||
|
||||
if(devfound == false)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -41,7 +41,8 @@ typedef enum
|
|||
SIMDEVSUBTYPE_CAMMUSC12 = 2,
|
||||
SIMDEVSUBTYPE_MOZAR5 = 3,
|
||||
SIMDEVSUBTYPE_CSLELITEV3PEDALS = 4,
|
||||
SIMDEVSUBTYPE_SIMAGICP1000PEDALS =5
|
||||
SIMDEVSUBTYPE_SIMAGICP1000PEDALS = 5,
|
||||
SIMDEVSUBTYPE_SIMAGICGTNEO = 6
|
||||
}
|
||||
DeviceSubSubType;
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue