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/cammusc5.c
|
||||||
usb/wheels/cammusc12.h
|
usb/wheels/cammusc12.h
|
||||||
usb/wheels/cammusc12.c
|
usb/wheels/cammusc12.c
|
||||||
|
usb/wheels/gtneo.h
|
||||||
|
usb/wheels/gtneo.c
|
||||||
sound/usb_generic_shaker_pulse.c
|
sound/usb_generic_shaker_pulse.c
|
||||||
serial/arduino.h
|
serial/arduino.h
|
||||||
serial/arduino.c
|
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/cammusc5.h"
|
||||||
#include "usb/wheels/cammusc12.h"
|
#include "usb/wheels/cammusc12.h"
|
||||||
|
#include "usb/wheels/gtneo.h"
|
||||||
#include "serial/moza.h"
|
#include "serial/moza.h"
|
||||||
|
|
||||||
#include "simdevice.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);
|
cammusc12_update(usbdevice, simdata->maxrpm, simdata->rpms, simdata->gear, simdata->velocity);
|
||||||
}
|
}
|
||||||
break;
|
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;
|
return 0;
|
||||||
|
|
@ -93,6 +103,28 @@ int wheeldev_init(USBDevice* usbdevice, DeviceSettings* ds)
|
||||||
error = cammusc12_init(usbdevice, NULL);
|
error = cammusc12_init(usbdevice, NULL);
|
||||||
}
|
}
|
||||||
break;
|
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:
|
default:
|
||||||
wheeldevice->type = WHEELDEV_UNKNOWN;
|
wheeldevice->type = WHEELDEV_UNKNOWN;
|
||||||
slogw("Unknown cammus wheel detected, trying C5");
|
slogw("Unknown cammus wheel detected, trying C5");
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,8 @@ typedef enum
|
||||||
WHEELDEV_UNKNOWN = 0,
|
WHEELDEV_UNKNOWN = 0,
|
||||||
WHEELDEV_CAMMUSC5 = 1,
|
WHEELDEV_CAMMUSC5 = 1,
|
||||||
WHEELDEV_CAMMUSC12 = 2,
|
WHEELDEV_CAMMUSC12 = 2,
|
||||||
WHEELDEV_MOZAR5 = 3
|
WHEELDEV_MOZAR5 = 3,
|
||||||
|
WHEELDEV_SIMAGICGTNEO = 4
|
||||||
}
|
}
|
||||||
WheelType;
|
WheelType;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -113,6 +113,11 @@ int strtodevsubsubtype(const char* device_subsubtype, DeviceSettings* ds)
|
||||||
ds->dev_subsubtype = SIMDEVSUBTYPE_SIMAGICP1000PEDALS;
|
ds->dev_subsubtype = SIMDEVSUBTYPE_SIMAGICP1000PEDALS;
|
||||||
devfound = true;
|
devfound = true;
|
||||||
}
|
}
|
||||||
|
if (strcicmp(device_subsubtype, "SIMAGICGTNEO") == 0)
|
||||||
|
{
|
||||||
|
ds->dev_subsubtype = SIMDEVSUBTYPE_SIMAGICGTNEO;
|
||||||
|
devfound = true;
|
||||||
|
}
|
||||||
|
|
||||||
if(devfound == false)
|
if(devfound == false)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -41,7 +41,8 @@ typedef enum
|
||||||
SIMDEVSUBTYPE_CAMMUSC12 = 2,
|
SIMDEVSUBTYPE_CAMMUSC12 = 2,
|
||||||
SIMDEVSUBTYPE_MOZAR5 = 3,
|
SIMDEVSUBTYPE_MOZAR5 = 3,
|
||||||
SIMDEVSUBTYPE_CSLELITEV3PEDALS = 4,
|
SIMDEVSUBTYPE_CSLELITEV3PEDALS = 4,
|
||||||
SIMDEVSUBTYPE_SIMAGICP1000PEDALS =5
|
SIMDEVSUBTYPE_SIMAGICP1000PEDALS = 5,
|
||||||
|
SIMDEVSUBTYPE_SIMAGICGTNEO = 6
|
||||||
}
|
}
|
||||||
DeviceSubSubType;
|
DeviceSubSubType;
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue