Compare commits

...
143 Commits
Author SHA1 Message Date
Paul Dino Jones 99d63a0598 Add support for custom lua scripts to control leds 2025-02-25 18:31:09 -05:00
Paul Dino Jones 7a2eccdbe1 Updated to latest simapi for getpid improvements 2025-02-19 17:15:47 -05:00
Paul Dino Jones f43a287f2f Update sketches to use 115200 baud 2025-02-19 17:15:47 -05:00
Paul Dino Jones e331938a9e fix improper detecting of usb haptic device 2025-02-19 17:15:47 -05:00
Paul Dino Jones 1945a0e892 Adding support for simled sketch 2025-02-14 02:20:10 -05:00
Paul Dino Jones 20935c33a2 readd and refactor simlighttest 2025-02-12 15:03:11 -05:00
Paul Dino Jones 29fbc7c798 Refactor serial devices so a single open handle is shared throughout 2025-01-25 09:52:38 -05:00
Paul Dino Jones f10540069c moved some confusing code 2025-01-25 09:51:20 -05:00
Paul Dino Jones 86a21d9c89 improve process of closing sound devices 2025-01-25 09:50:11 -05:00
Paul Dino Jones 84dc8a1753 pulling in latest simapi for improvements to pcars2 2025-01-21 17:23:28 -05:00
Paul Dino Jones ce53ff5da1 Adding max frequency and modulation to sound devices 2025-01-21 17:23:10 -05:00
Paul Dino Jones fa3bb6e80f Fix bug causing no tyre effects 2025-01-20 12:13:49 -05:00
Paul Dino Jones 2462dfd0c9 Update to latest simapi, allow sim strings in configs 2025-01-20 10:53:57 -05:00
Paul Dino Jones fefecd76df updated to latest simapi 2025-01-19 15:16:30 -05:00
Paul Dino Jones e9c7264b4e Updated to latest simapi for AC EVO support 2025-01-19 09:57:57 -05:00
Paul Dino Jones c7ee4bad32 fixed sound readme again 2025-01-19 09:57:23 -05:00
Paul Dino Jones 1c279e071f Removed calls to abort 2025-01-18 19:01:52 -05:00
Paul Dino Jones a6146f5644 moved to latest simapi 2025-01-18 13:36:03 -05:00
Paul Dino Jones 23db7cb4dc Add numlights setting 2025-01-18 13:20:56 -05:00
Paul Dino Jones 2676e31094 fix revburner typo 2025-01-18 12:26:23 -05:00
Paul Dino Jones d161eb19c4 Initially adding support for SIMAGIC P1000 Pedals 2025-01-18 03:30:11 -05:00
Paul Dino Jones 4aa7fe6391 lock pulseaudio mainloop while freeing sound devices 2025-01-17 19:41:12 -05:00
Paul Dino Jones 1e6d630be5 use more standard channel map 2025-01-17 18:22:51 -05:00
Paul Dino Jones 9a05458a84 more details in README 2025-01-17 10:41:18 -05:00
Paul Dino Jones 0c8c508dd8 added global refresh rate -f 2025-01-17 10:29:27 -05:00
Paul Dino Jones 7397491eb8 added a few commands to help with sound setup 2025-01-17 10:28:25 -05:00
Paul Dino Jones 637c5b8c6c move logging around to make output a little cleaner 2025-01-16 22:22:49 -05:00
Paul Dino Jones 164b0a1533 remove old commented code 2025-01-16 22:10:44 -05:00
Paul Dino Jones f5eae498ef I knew there was a reason it was commented out. It makes valgrind happy but causes the program to segfault on exit. 2025-01-16 17:00:15 -05:00
Paul Dino Jones 07a51011c6 fix more malloc complaints 2025-01-16 16:57:34 -05:00
Paul Dino Jones 08e2e971e7 fix bad memory management around device threading model 2025-01-16 16:45:37 -05:00
Paul Dino Jones 2cd57396ec updated readme for getting device name 2025-01-16 14:28:29 -05:00
Paul Dino Jones ac8fd3ce56 sound devices stay on main thread 2025-01-16 01:08:00 -05:00
Paul Dino Jones 598e8f9b3a fix some effects in test loop 2025-01-15 23:43:25 -05:00
Paul Dino Jones e3ba5c08ee add sim entry to diameters file 2025-01-15 23:42:57 -05:00
Paul Dino Jones 1c253975e5 add logging for haptic effects, fix consistency of test sequence 2025-01-15 18:16:07 -05:00
Paul Dino Jones 34ae67b788 fix bug in tyre effects and its test 2025-01-15 14:11:42 -05:00
Paul Dino Jones 160c98f46b fixed return of checkbyte for moza 2025-01-15 12:24:08 -05:00
Paul Dino Jones 5f526af1e3 Updated PKGBUILD files to use libpulse 2025-01-15 12:23:34 -05:00
Paul Dino Jones 90960dddda fix floating point issue on moza 2025-01-14 20:23:43 -05:00
Paul Dino Jones 7573583644 temporarily add another step with rpms at 7000 to assist in debugging some wheels 2025-01-14 20:23:11 -05:00
Paul Dino Jones 41c5ceefc7 updated to latest simapi 2025-01-14 18:25:42 -05:00
Paul Dino Jones 079dc9716c fix issues with serial wheel 2025-01-14 18:09:35 -05:00
Paul Dino Jones 3476959f98 Improve config handling 2025-01-14 17:40:07 -05:00
Paul Dino Jones bf4f1f0353 removed unused jansson header 2025-01-13 19:17:42 -05:00
Paul Dino Jones 4fcd4e3be1 Add support for per device fps settings. 2025-01-13 15:16:57 -05:00
Paul Dino Jones ca18f2ff10 updated monocoque PKGBUILDS 2025-01-11 03:19:19 -05:00
Paul Dino Jones 81b85c89f2 moved PKGBUILD to stable folder 2025-01-11 03:18:09 -05:00
Paul Dino Jones 73f3b7c6a9 add example pacman command for dependencies 2025-01-11 03:06:27 -05:00
Paul Dino Jones 27d4472440 Use STARTLED default of 1 2025-01-02 16:21:15 -05:00
Paul Dino Jones 82fa5a7087 Update simlight test 2025-01-02 15:57:13 -05:00
Paul Dino Jones 70da7cf0a3 Add start led 2025-01-02 15:54:46 -05:00
Paul Dino Jones 64229b5318 updated TODO 2024-12-04 14:44:09 -05:00
Paul Dino Jones a6683fd78f updated TODO 2024-12-04 14:42:37 -05:00
Paul Dino Jones ea9ec5b566 disable all tests for now 2024-12-04 12:34:21 -05:00
Paul Dino Jones c4e57b8db8 add code to smooth out frequencies between audio frames 2024-12-04 11:20:21 -05:00
Paul Dino Jones b5211a8ea4 persist phase to stop disjointed sine waves 2024-12-03 20:47:57 -05:00
Paul Dino Jones aa6963529e improve stability of config file loading when multiple configs are in use 2024-11-22 16:21:30 -05:00
Paul Dino Jones 71d1a4cd29 fix issues with simapi mapping correctly when using simd 2024-11-22 16:21:08 -05:00
Paul Dino Jones f57c51eca8 Use more generic sysfs path to find csl elite v3 pedals 2024-11-19 11:57:58 -05:00
Paul Dino Jones 91335c0802 Use latest simapi to improve tyre slip effects 2024-11-19 11:55:55 -05:00
Paul Dino Jones 3ea20310aa stable pkgbuild 2024-11-18 16:53:27 -05:00
Paul Dino Jones 0bec1e0050 Added ampfactor to serial haptic log message 2024-10-10 15:00:39 -04:00
Paul Dino Jones f6def08b01 Add xdg to dependencies 2024-10-06 00:52:17 -04:00
Paul Dino Jones cb2985071f upgraed to latest simapi 2024-10-06 00:49:08 -04:00
Paul Dino Jones 7a46e9daf8 various readme updates 2024-10-06 00:12:50 -04:00
Paul Dino Jones 68ab4f6d45 upgraded to new simapi 2024-10-05 17:10:00 -04:00
Paul Dino Jones ac2f8525e4 Updated to latest simapi 2024-10-05 08:32:01 -04:00
Paul Dino Jones c9b257dc80 Updated to latest simapi 2024-10-05 08:28:26 -04:00
Paul Dino Jones 06da8c2e2e UDP support and upgrade to latest simapi for udp and logging support 2024-10-01 12:46:41 -04:00
Paul Dino Jones 27b793f27e Fix issue not setting correct baud rate through to libserialport 2024-09-30 22:21:35 -04:00
Paul Dino Jones 82a8e79d2b set simhaptic baud to 9600 2024-09-30 20:34:29 -04:00
Paul Dino Jones e2d715ee49 forgot to add submodules 2024-09-19 21:44:22 -04:00
Paul Dino Jones b4801dabf2 Fixed overlook device settings in config processing 2024-09-19 21:22:00 -04:00
Paul Dino Jones 1453c522bf Updated pkgbuild to actually install 2024-09-19 21:21:30 -04:00
Paul Dino Jones d7d3c47d0e Fix a couple things i missed in the merge 2024-09-19 18:59:46 -04:00
Paul Dino Jones 89b2593a56 Reorganization and config updates for Moza wheel 2024-09-19 18:54:16 -04:00
Paul Dino Jones 2361599340 Add ability to specify baud rate in config file 2024-09-19 18:54:12 -04:00
Lawstorant 538ce54b44 Initial work 2024-09-19 18:53:04 -04:00
Paul Jones 232d39b19d Serial8 (#11)
* Using 8 bits per int for serial devices

* Refactor simwind code slightly to improve performance
2024-09-19 17:05:42 -04:00
Paul Dino Jones 08e12546ed Moved baud rate to serial device struct and fixed log message 2024-09-17 10:17:40 -04:00
Paul Dino Jones 9377188cf7 Fix velocity bytes on cammus c12 hid message 2024-09-16 16:48:17 -04:00
Paul Dino Jones d100d570be Support for cammus c12 2024-09-16 16:14:18 -04:00
Paul Dino Jones 5de6b1cb7f Add some robustness to diameters file and slip effect code 2024-09-16 14:08:58 -04:00
Paul Dino Jones c86a7509ad Fix issue with test not having a car set 2024-09-15 12:24:23 -04:00
Paul Dino Jones 56700c8018 Added more checks to make sure sims do not try to set tyre diameters without a car set 2024-09-08 18:49:01 -04:00
Paul Dino Jones edaa7e8b81 Do not compare car if it is null 2024-09-08 18:44:21 -04:00
Paul Dino Jones 5e61e32795 Added more robustness to config lookup 2024-09-06 14:50:00 -04:00
Paul Dino Jones 794f8fb0b0 Added more logging to config load 2024-09-06 14:30:12 -04:00
Paul Dino Jones 56e0d71893 Put default configs closer to the bottom 2024-09-04 16:22:36 -04:00
Paul Dino Jones f962bfa8ef Fix some issues with config loading 2024-09-04 16:15:34 -04:00
Paul Dino Jones c257222509 Add ability to specify baud rate in config file 2024-09-04 12:56:02 -04:00
Paul Dino Jones 723d2e6463 Update loop to 60fps. Update some arduino devices to 115200. Refactor shiftlights code for performance. 2024-09-04 12:16:21 -04:00
Paul Dino Jones 63fe5007b7 Updated config example to support profiles 2024-09-03 16:59:48 -04:00
Paul Dino Jones ce2049a552 Update CMake so project build 2024-09-02 13:24:34 -04:00
Paul Dino Jones 4913e6b8ae Updated to latest simapi 2024-09-02 13:20:28 -04:00
spikerguy 152431cb8b Add supported games list (#9)
* Add supported games list

* readme: get car tyre diameter

* typo
2024-09-02 12:53:22 -04:00
Paul Dino Jones b8df16dd67 Added link to Linux Sim Racing Matrix space 2024-09-02 12:50:06 -04:00
Paul Dino Jones ca17d84c0c Added arch linux PKGBUILD 2024-09-02 12:47:17 -04:00
Paul Dino Jones 820bdaa15a Update to latest simapi 2024-09-02 12:40:40 -04:00
Paul Dino Jones 644cc95ac2 Updated to latest simapi 2024-09-02 12:09:18 -04:00
Paul Dino Jones e25fa700d1 Initialize some data so tyre diameter detection works, and motors spin down. 2024-09-02 11:15:19 -04:00
Paul Dino Jones a1c26b4228 Set gameloop to 8fps for now to avoid issues 2024-09-02 11:13:19 -04:00
Paul Dino Jones c7b3607e33 Improving loop management to prevent double freeing. Fixing other memory issues 2024-09-02 10:43:36 -04:00
Paul Dino Jones 235d4257d4 making log statement more accurate 2024-08-31 16:14:33 -04:00
Paul Dino Jones 7c8273bcde Move some things around and add another indicator to prevent double frees 2024-08-31 16:02:34 -04:00
Paul Dino Jones 15d18bbe8f Fix log statement so it actual outputs the amount of slip 2024-08-31 16:02:04 -04:00
Paul Dino Jones 7c0e17342e Major overhault to add libuv event loop. Enhancements to config file to support profiles. 2024-08-30 13:46:56 -04:00
Paul Dino Jones 8f59254c67 update to latest simapi 2024-08-12 23:50:18 -04:00
Paul Dino Jones d97e919d7c Update to latest simapi to fix gear in truck sims 2024-08-11 23:48:00 -04:00
Paul Dino Jones 49b0d764c9 Add SCS Truck Sim support 2024-08-11 23:28:29 -04:00
Paul Dino Jones 7714c2cb8e Move from libusb to hidraw backend hid api 2024-08-11 20:12:27 -04:00
Paul Dino Jones cb39d17b22 Refactored wheel diameters config logic 2024-08-08 21:19:52 -04:00
Paul Dino Jones fedbf473bb Set useconfig before initializing devices 2024-08-08 15:02:55 -04:00
Paul Dino Jones d62e4c7d1b Fixing issue with diameters file. Disabling diameters config checking during monocoque test. Additonal logging 2024-08-08 00:28:54 -04:00
Paul Dino Jones 89e49353e4 setting uninitialized values on sound devices 2024-08-08 00:28:03 -04:00
Paul Dino Jones 007a786c14 No longer abort on one failed write to a serial device. Log error instead. 2024-08-06 16:45:29 -04:00
Paul Dino Jones e194642d6e Add Reverse for Cammus C5 2024-08-06 10:06:49 -04:00
Paul Dino Jones 9eb1cd75b0 Update gameloop so it sets gear to neutral on shutdown. Add enum for gears. 2024-08-06 10:06:24 -04:00
Paul Dino Jones ae9293ba08 Fix issue with bad data being send to cammus wheel on quit 2024-08-05 17:08:23 -04:00
Paul Dino Jones 5b24faa7f1 Fix include paths 2024-08-05 17:07:04 -04:00
Paul Dino Jones cf61b8a4e5 Add more logging for cammus 2024-08-05 16:43:47 -04:00
Paul Dino Jones df199b5f5c clear bytes on each update 2024-08-05 16:31:58 -04:00
Paul Dino Jones ca4f1654fa Fix gear 2024-08-05 16:18:51 -04:00
Paul Dino Jones 622e46a42f Using correct pid for cammus 2024-08-05 16:11:29 -04:00
Paul Dino Jones d5c0c485cf Small fixes for speed and gear 2024-08-05 16:10:15 -04:00
Paul Dino Jones c983cb2b4e rpm margin must return as an integer 2024-08-05 14:49:32 -04:00
Paul Dino Jones 8d04c3aa04 Initial attempt at adding support CammusC5 wheel with underlying code for future wheels. 2024-08-05 13:42:17 -04:00
Paul Dino Jones 270a075292 Reverse regression in previous commit 2024-08-04 17:07:09 -04:00
Paul Dino Jones c36658e0e1 Refactor motor haptic effect slightly. Add logging. 2024-08-04 14:58:01 -04:00
Paul Dino Jones e4634721a1 Pull in and use latest simapi 2024-07-28 19:02:40 -04:00
Paul Dino Jones 2129299f5f Start sound devices with frequency set to 0 to avoid loud start ups 2024-07-28 11:18:41 -04:00
Paul Dino Jones 3fc3ce3ea0 Fix small buffer overflow on the diameters file string 2024-07-28 11:00:26 -04:00
Paul Dino Jones 254c891528 Update to latest simapi to fix issues with file descriptors 2024-07-28 02:23:45 -04:00
Paul Dino Jones 0c74666409 Add more logging for mem freeing 2024-07-28 02:08:18 -04:00
Paul Dino Jones 82c45f1bca update to latest simapi to bypass wrong behavior 2024-07-28 02:06:44 -04:00
Paul Dino Jones bb5c2069c9 Added extra logging. Added code to free mapped memory and file descriptors 2024-07-27 20:32:09 -04:00
Paul Dino Jones ac749cebfa Fix issue with tyre effects on sound devices 2024-07-27 20:09:24 -04:00
Paul Dino Jones e125b33a85 update to latest simapi 2024-07-27 19:51:17 -04:00
Paul Dino Jones 6e041152a2 More support for beyond stereo 2024-07-22 21:45:57 -04:00
Paul Dino Jones 6945b026e9 Better handle volume math 2024-07-20 20:15:16 -04:00
Paul Dino Jones b7c5e1a9fa Updated readme with some instructions on bass shakers 2024-07-20 16:39:53 -04:00
Paul Dino Jones 178c16b0d7 Add ability to use sound cards with more than 2 channels. 2024-07-20 16:31:17 -04:00
60 changed files with 3761 additions and 899 deletions
+2
View File
@@ -1,3 +1,5 @@
/build
/src/monocoque/tags
/src/monocoque/simulatorapi/simapi
.vscode
+58 -58
View File
@@ -1,6 +1,6 @@
# minimum CMake version required for C++20 support, among other things
cmake_minimum_required(VERSION 3.15)
cmake_minimum_required(VERSION 3.18)
# detect if Monocoque is being used as a sub-project of another CMake project
if(NOT DEFINED PROJECT_NAME)
@@ -20,30 +20,30 @@ set(CMAKE_EXE_LINKER_FLAGS "-Wl,--no-as-needed -ldl")
set(LIBUSB_INCLUDE_DIR /usr/include/libusb-1.0)
set(LIBXML_INCLUDE_DIR /usr/include/libxml2)
FIND_PATH(LIBUSB_INCLUDE_DIR libusb.h
HINTS $ENV{LIBUSB_ROOT}
PATHS ${PC_LIBUSB_INCLUDEDIR} ${PC_LIBUSB_INCLUDE_DIRS}
PATH_SUFFIXES include)
FIND_LIBRARY(LIBUSB_LIBRARY NAMES usb-1.0
HINTS $ENV{LIBUSB_ROOT}
PATHS ${PC_LIBUSB_LIBDIR} ${PC_LIBUSB_LIBRARY_DIRS}
PATH_SUFFIXES lib)
set(HIDAPI_WITH_LIBUSB TRUE) # surely will be used only on Linux
#FIND_PATH(LIBUSB_INCLUDE_DIR libusb.h
# HINTS $ENV{LIBUSB_ROOT}
# PATHS ${PC_LIBUSB_INCLUDEDIR} ${PC_LIBUSB_INCLUDE_DIRS}
# PATH_SUFFIXES include)
#
#FIND_LIBRARY(LIBUSB_LIBRARY NAMES usb-1.0
# HINTS $ENV{LIBUSB_ROOT}
# PATHS ${PC_LIBUSB_LIBDIR} ${PC_LIBUSB_LIBRARY_DIRS}
# PATH_SUFFIXES lib)
#
set(HIDAPI_WITH_LIBUSB FALSE) # surely will be used only on Linux
set(BUILD_SHARED_LIBS TRUE) # HIDAPI as static library on all platforms
add_executable(monocoque src/monocoque/monocoque.c)
if(USE_PULSEAUDIO)
message("Using pulseaudio backend...")
add_compile_definitions(USE_PULSEAUDIO=true)
target_link_libraries(monocoque m ${LIBUSB_LIBRARY} hidapi-libusb pulse serialport xml2 argtable2 config gameloop helper devices slog simulatorapi)
target_link_libraries(monocoque m hidapi-hidraw pulse serialport xml2 argtable2 config gameloop helper devices slog simulatorapi uv xdg-basedir lua5.4)
else()
message("Using portaudio backend...")
target_link_libraries(monocoque m ${LIBUSB_LIBRARY} hidapi-libusb portaudio serialport xml2 argtable2 config gameloop helper devices slog simulatorapi)
target_link_libraries(monocoque m hidapi-hidraw portaudio serialport xml2 argtable2 config gameloop helper devices slog simulatorapi uv xdg-basedir lua5.4)
endif()
target_include_directories(monocoque PUBLIC config ${LIBUSB_INCLUDE_DIR} ${LIBXML_INCLUDE_DIR})
target_include_directories(monocoque PUBLIC config ${LIBXML_INCLUDE_DIR})
add_subdirectory(src/monocoque/gameloop)
add_subdirectory(src/monocoque/simulatorapi)
@@ -51,51 +51,51 @@ add_subdirectory(src/monocoque/helper)
add_subdirectory(src/monocoque/devices)
add_subdirectory(src/monocoque/slog)
add_executable(listusb tests/testlibusb.c)
target_include_directories(listusb PUBLIC ${LIBUSB_INCLUDE_DIR})
target_link_libraries(listusb ${LIBUSB_LIBRARY} portaudio)
add_test(listusb list-usb-devices listusb)
#add_executable(listusb tests/testlibusb.c)
#target_include_directories(listusb PUBLIC)
#target_link_libraries(listusb portaudio hidapi-hidraw)
#add_test(listusb list-usb-devices listusb)
add_executable(testrevburner tests/testrevburner.c)
target_include_directories(testrevburner PUBLIC ${LIBUSB_INCLUDE_DIR})
target_link_libraries(testrevburner ${LIBUSB_LIBRARY})
add_test(testrevburner testrevburner)
add_executable(listsound tests/pa_devs.c)
target_include_directories(listsound PUBLIC)
target_link_libraries(listsound m portaudio)
add_test(list-sound-devices listsound)
add_executable(longsine tests/patest_longsine.c)
target_include_directories(longsine PUBLIC ${LIBUSB_INCLUDE_DIR} ${LIBXML_INCLUDE_DIR})
target_link_libraries(longsine ${LIBUSB_LIBRARY} m portaudio)
add_test(longsine longsine)
add_executable(parserevburnerxml tests/revburnerparsetest.c)
target_include_directories(parserevburnerxml PUBLIC ${LIBXML_INCLUDE_DIR})
target_link_libraries(parserevburnerxml ${LIBUSB_LIBRARY} portaudio xml2)
add_test(parserevburnerxml parserevburnerxml)
add_executable(setmem tests/setmem.c)
target_include_directories(setmem PUBLIC)
target_link_libraries(setmem)
add_test(setmem setmem)
add_executable(getmem tests/getmem.c)
target_include_directories(getmem PUBLIC)
target_link_libraries(getmem)
add_test(getmem getmem)
add_executable(setsimdata tests/setsimdata.c)
target_include_directories(setsimdata PUBLIC)
target_link_libraries(setsimdata)
add_test(setsimdata setsimdata)
add_executable(hidtest tests/hidtest.c)
target_include_directories(hidtest PUBLIC ${LIBUSB_INCLUDE_DIR})
target_link_libraries(hidtest ${LIBUSB_LIBRARY} hidapi-libusb)
add_test(hidtest hidtest)
#add_executable(testrevburner tests/testrevburner.c)
#target_include_directories(testrevburner PUBLIC)
#target_link_libraries(testrevburner hidapi-hidraw)
#add_test(testrevburner testrevburner)
#add_executable(listsound tests/pa_devs.c)
#target_include_directories(listsound PUBLIC)
#target_link_libraries(listsound m portaudio)
#add_test(list-sound-devices listsound)
#
#add_executable(longsine tests/patest_longsine.c)
#target_include_directories(longsine PUBLIC ${LIBXML_INCLUDE_DIR})
#target_link_libraries(longsine m portaudio)
#add_test(longsine longsine)
#
#add_executable(parserevburnerxml tests/revburnerparsetest.c)
#target_include_directories(parserevburnerxml PUBLIC ${LIBXML_INCLUDE_DIR})
#target_link_libraries(parserevburnerxml portaudio xml2)
#add_test(parserevburnerxml parserevburnerxml)
#
#add_executable(setmem tests/setmem.c)
#target_include_directories(setmem PUBLIC)
#target_link_libraries(setmem)
#add_test(setmem setmem)
#
#add_executable(getmem tests/getmem.c)
#target_include_directories(getmem PUBLIC)
#target_link_libraries(getmem)
#add_test(getmem getmem)
#
#add_executable(setsimdata tests/setsimdata.c)
#target_include_directories(setsimdata PUBLIC)
#target_link_libraries(setsimdata)
#add_test(setsimdata setsimdata)
#
#add_executable(hidtest tests/hidtest.c)
#target_include_directories(hidtest PUBLIC)
#target_link_libraries(hidtest hidapi-hidraw)
#add_test(hidtest hidtest)
#
add_executable(simlighttest tests/simlighttest.c)
target_include_directories(simlighttest PUBLIC)
target_link_libraries(simlighttest serialport)
+55 -9
View File
@@ -9,28 +9,49 @@ _ / / / / /_/ / / / / /_/ / /__ / /_/ / /_/ // /_/ // __/
Cross Platform device manager for driving and flight simulators, for use with common simulator software titles.
## Features
- Updates at 120 frames per seconds.
- Updates at 60 frames per seconds.
- Modular design for support with various titles and devices.
- Supports bass shakers, tachometers, simlights, simwind etc, through usb and arduino serial.
- Supports bass shakers, tachometers, several wheels, simlights, simwind etc, through usb and arduino serial.
- Tachometer support is currently limited to the Revburner model. Supports existing revburner xml configuration files.
- Includes utility to configure revburner tachometer
- Can send data to any serial device. So far only tested with arduino. Includes sample arduino sketch for sim lights.
- The support for haptic bass shakers is limited and needs the most work. So far the engine rev is a simple sine wave, which I find convincing. The gear shift event works but not convincing enough for me.
- Choice of Portaudio or Pulseaudio backend.
- Can send data to any serial device. So far only tested with arduino. Includes sample arduino sketch for sim lights, simwind, and simhaptic effects for motors.
- Convincing shaker effects for noise tranducers for wheel slip, wheel lock, and abs, as well as engine rpm and gear shifts.
- Choice of Portaudio or Pulseaudio (libpulse) backend.
## Supported Games ( see [simapi](https://github.com/spacefreak18/simapi) for more details of what is supported from each sim )
- Using [SimSHMBridge](https://github.com/spacefreak18/simshmbridge)
- Asseto Corsa
- Assetto Corsa Competizione
- Project Cars 2 (untested)
- Automobilista 2
- Using [scs-sdk-plugin](https://github.com/jackz314/scs-sdk-plugin/releases)
- Euro Truck Simuator 2
- American Truck Simulator
- Using [rfactor 2 plugin](https://github.com/schlegp/rF2SharedMemoryMapPlugin_Wine)
- RFactor 2
- Using UDP
- Automobilista 2
- Project Cars 2 (untested)
## Dependencies
- libserialport - arduino serial devices
- hidapi - usb hid devices
- libusb - used by hidapi
- portaudio - sound devices (haptic bass shakers)
- pulseaudio - sound devices (haptic bass shakers)
- libenet - UDP support (not yet implemented)
- libpulse - sound devices (haptic bass shakers)
- libuv base event loop
- libxml2
- argtable2
- libconfig
- xdg-basedir
- [slog](https://github.com/kala13x/slog) (static)
- [simshmbridge](https://github.com/spacefreak18/simshmbridge) - for sims that need shared memory mapping like AC and Project Cars related.
- [simapi](https://github.com/spacefreak18/simapi)
```
pacman -Syu git cmake pulse-native-provider libxdg-basedir libserialport libconfig libuv argtable hidapi
```
## Building
This code depends on the shared memory data headers in the simapi [repo](https://github.com/spacefreak18/simapi). When pulling lastest if the submodule does not download run:
@@ -50,6 +71,21 @@ to use the pulseaudio backend use this cmake command
```
cmake -DUSE_PULSEAUDIO=YES ..
```
## Bass Shaker Sound Devices
When using pulseaudio it is necesarry to provide a devid in the configuration. This command should list available sound cards with the "Name" being the "devid" needed in the monocoque config.
```
pactl list sinks | grep -E -i 'index:|name:' -A 4
```
One can generate sample sine waves at specific frequency on a specific channel on a specific sound card with this command (change -d to the Name of your desired target card and change 440 to any frequency)
```
ffmpeg -f lavfi -i "sine=f=440" -af "pan=7.1|c1=c0" -f wav pipe:1 | paplay --no-remap --no-remix -d alsa_output.pci-0000_00_1b.0.analog-stereo --volume=65536 -n "Monocoque" --stream-name="Haptic Test"
```
(BE CAREFUL!!! AS THIS SETS THE MAXIMUM STREAM VOLUME!!! the -n and --stream-name are optional but it helps you identify the stream in pavucontrol)
The channel map from the pactl command is the order of channels. Change c1 in this above command to the desired output channel.
The effects generated by monocoque should match the effects generated by this ffmpeg command. The frequency will differ slightly due to having to [fit in the buffer size](https://stackoverflow.com/questions/40078417/how-to-calculate-minimum-cycles-of-sine-wave-to-have-integer-n-cycles-in-a-buffe)
(monocoque lowers the target frequency until it fits in the audio buffer).
## Using Arduino Devices
@@ -89,7 +125,10 @@ make # Make sure serial connection is the same as on the host pc and it have th
### SimHaptic Ardunio Motor Connection
- Acc Pedal Motor to be connected to M1
- Brake Pedal Motor to be connected to M3
- you can actually connect the motors how you wish, but you'd have to make the appropriate changes to the config and to the arduino sketch.
## Getting car tyre diameter for rumbles to work
- User needs to start monocoque and drive the new car straight at 70 kmph and then stop steering, acc or brake input
## Testing
```
@@ -103,6 +142,7 @@ make # Make sure serial connection is the same as on the host pc and it have th
cmake -Danalyze=on ..
make
```
### Valgrind
```
cd build
@@ -112,9 +152,15 @@ make # Make sure serial connection is the same as on the host pc and it have th
### Logs file location
`~/.cache/monocoque/*.log`
## Join the Discussion
[Sim Racing Matrix Space](https://matrix.to/#/#simracing:matrix.org)
## ToDo
- add option to specify frame rate
- add ability to set frame rate per effect
- add frequency cap (low pass filter) to sound haptic effects
- add road and kerb sound haptic effects
- windows port
- more memory testing
- move config code around
- cleanup tests which are basically just copies of the example from their respective projects
- much, much more
+68 -64
View File
@@ -1,64 +1,68 @@
devices = ( { device = "USB";
type = "Tachometer";
devid = "98FD:83AC";
subtype = "Revburner";
granularity = 2;
config = "~/.config/monocoque/revburner15000.xml"; },
{ device = "Sound";
effect = "Engine";
devid = "alsa_output.usb-Generic_USB2.0_Device_20170726905959-00.analog-stereo";
pan = 1;
volume = 90;
frequency = 27; },
{ device = "Sound";
effect = "Gear"
devid = "alsa_output.usb-Generic_USB2.0_Device_20170726905959-00.analog-stereo";
pan = 1;
duration = .25;
volume = 100;
frequency = 27; },
{ device = "USB";
type = "Haptic";
subtype = "ClubSportElitePedalsV3";
effect = "ABS";
tyre = "ALL";
threshold = 0.05; },
{ device = "USB";
type = "Haptic";
subtype = "ClubSportElitePedalsV3";
effect = "Slip";
tyre = "REARS";
threshold = 0.75; },
{ device = "USB";
type = "Haptic";
subtype = "ClubSportElitePedalsV3";
effect = "Lock";
tyre = "ALL";
threshold = 0.75; },
{ device = "Serial";
type = "SimWind";
config = "None";
devpath = "/dev/ttyACM1"; },
{ device = "Serial";
type = "ShiftLights";
config = "None";
devpath = "/dev/ttyACM0"; },
{ device = "Serial";
type = "Haptic";
effect = "TyreSlip";
tyre = "ALL"; // motor m1 connected to throttle
motors = 0;
devpath = "/dev/ttyACM0"; },
{ device = "Serial";
type = "Haptic";
effect = "TyreLock";
tyre = "ALL"; // motor m3 connected to brake;
motors = 2;
devpath = "/dev/ttyACM0"; },
{ device = "Serial";
type = "Haptic"
effect = "ABS";
tyre = "ALL"; // this will have to be documented, this tells the code to spin both motors
motors = 8;
devpath = "/dev/ttyACM0";}
);
configs = ({
sim = 0;
car = "default";
devices = ( { device = "USB";
type = "Tachometer";
devid = "98FD:83AC";
subtype = "Revburner";
granularity = 2;
config = "~/.config/monocoque/revburner15000.xml"; },
{ device = "Sound";
effect = "Engine";
devid = "alsa_output.usb-Generic_USB2.0_Device_20170726905959-00.analog-stereo";
pan = 1;
volume = 90;
frequency = 27; },
{ device = "Sound";
effect = "Gear"
devid = "alsa_output.usb-Generic_USB2.0_Device_20170726905959-00.analog-stereo";
pan = 1;
duration = .25;
volume = 100;
frequency = 27; },
{ device = "USB";
type = "Haptic";
subtype = "ClubSportElitePedalsV3";
effect = "ABS";
tyre = "ALL";
threshold = 0.05; },
{ device = "USB";
type = "Haptic";
subtype = "ClubSportElitePedalsV3";
effect = "Slip";
tyre = "REARS";
threshold = 0.75; },
{ device = "USB";
type = "Haptic";
subtype = "ClubSportElitePedalsV3";
effect = "Lock";
tyre = "ALL";
threshold = 0.75; },
{ device = "Serial";
type = "SimWind";
config = "None";
devpath = "/dev/ttyACM1"; },
{ device = "Serial";
type = "ShiftLights";
config = "None";
devpath = "/dev/ttyACM0"; },
{ device = "Serial";
type = "Haptic";
effect = "TyreSlip";
tyre = "ALL"; // motor m1 connected to throttle
motors = 0;
devpath = "/dev/ttyACM0"; },
{ device = "Serial";
type = "Haptic";
effect = "TyreLock";
tyre = "ALL"; // motor m3 connected to brake;
motors = 2;
devpath = "/dev/ttyACM0"; },
{ device = "Serial";
type = "Haptic"
effect = "ABS";
tyre = "ALL"; // this will have to be documented, this tells the code to spin both motors
motors = 8;
devpath = "/dev/ttyACM0";}
);
});
+15 -14
View File
@@ -6,20 +6,21 @@
typedef struct
{
unsigned char color_1_red;
unsigned char color_1_green;
unsigned char color_1_blue;
unsigned char color_2_red;
unsigned char color_2_green;
unsigned char color_2_blue;
unsigned char color_3_red;
unsigned char color_3_green;
unsigned char color_3_blue;
unsigned char space_1;
unsigned char space_2;
unsigned char space_3;
uint32_t maxrpm;
uint32_t rpm;
uint8_t litleds;
//unsigned char color_1_red;
//unsigned char color_1_green;
//unsigned char color_1_blue;
//unsigned char color_2_red;
//unsigned char color_2_green;
//unsigned char color_2_blue;
//unsigned char color_3_red;
//unsigned char color_3_green;
//unsigned char color_3_blue;
//unsigned char space_1;
//unsigned char space_2;
//unsigned char space_3;
//uint32_t maxrpm;
//uint32_t rpm;
}
ShiftLightsData;
+24 -40
View File
@@ -6,16 +6,17 @@
#define LED_PIN 7
#define NUM_LEDS 6
#define BRIGHTNESS 40
#define STARTLED 1
#define COLOR1A 0
#define COLOR1R 0
#define COLOR1G 255
#define COLOR1B 0
#define COLOR1C 255
#define COLOR2A 0
#define COLOR2B 255
#define COLOR2C 0
#define COLOR3A 255
#define COLOR2R 255
#define COLOR2G 255
#define COLOR2B 0
#define COLOR3R 255
#define COLOR3G 0
#define COLOR3B 0
#define COLOR3C 0
CRGB leds[NUM_LEDS];
ShiftLightsData sd;
@@ -23,12 +24,12 @@ int maxrpm = 0;
int rpm = 0;
int numlights = NUM_LEDS;
int pin = LED_PIN;
int lights[6];
int lights[NUM_LEDS];
void setup()
{
Serial.begin(9600);
Serial.begin(115200);
FastLED.addLeds<WS2812, LED_PIN, GRB>(leds, NUM_LEDS);
FastLED.setMaxPowerInVoltsAndMilliamps(5, 500);
FastLED.setBrightness(BRIGHTNESS);
@@ -39,62 +40,45 @@ void setup()
}
FastLED.clear();
sd.rpm = 0;
sd.maxrpm = 6500;
sd.litleds = 0;
//sd.rpm = 0;
//sd.maxrpm = 6500;
}
void loop()
{
int l = 0;
int lit = sd.litleds;
char buff[SIMDATA_SIZE];
if (Serial.available() >= SIMDATA_SIZE)
{
Serial.readBytes(buff, SIMDATA_SIZE);
memcpy(&sd, &buff, SIMDATA_SIZE);
rpm = sd.rpm;
maxrpm = sd.maxrpm;
}
while (l < numlights)
{
lights[l] = 0;
l++;
}
l = -1;
int rpmlights = 0;
while (rpm > rpmlights)
{
if (l>=0)
{
lights[l] = 1;
}
l++;
rpmlights = rpmlights + (((maxrpm-250)/numlights));
lit = sd.litleds;
}
l = 0;
FastLED.clear();
while (l < numlights)
while (l < lit)
{
if (l >= numlights / 2)
{
leds[l] = CRGB ( COLOR1A, COLOR1B, COLOR1C);
leds[l+STARTLED-1] = CRGB ( COLOR2R, COLOR2G, COLOR2B);
}
if (l < numlights / 2)
{
leds[l] = CRGB ( COLOR2A, COLOR2B, COLOR2C);
leds[l+STARTLED-1] = CRGB ( COLOR1R, COLOR1G, COLOR1B);
}
if (l == numlights - 1)
{
leds[l] = CRGB ( COLOR3A, COLOR3B, COLOR3C);
leds[l+STARTLED-1] = CRGB ( COLOR3R, COLOR3G, COLOR3B);
}
if (lights[l] <= 0)
{
leds[l] = CRGB ( 0, 0, 0);
}
FastLED.show();
//if (lights[l] <= 0)
//{
// leds[l] = CRGB ( 0, 0, 0);
//}
l++;
}
FastLED.show();
}
+8 -8
View File
@@ -6,14 +6,14 @@
typedef struct
{
uint32_t motor1;
uint32_t effect1;
uint32_t motor2;
uint32_t effect2;
uint32_t motor3;
uint32_t effect3;
uint32_t motor4;
uint32_t effect4;
uint8_t motor1;
uint8_t effect1;
uint8_t motor2;
uint8_t effect2;
uint8_t motor3;
uint8_t effect3;
uint8_t motor4;
uint8_t effect4;
}
SimHapticData;
+1 -1
View File
@@ -22,7 +22,7 @@ int effect3 = 0;
int effect4 = 0;
void setup() {
Serial.begin(9600);
Serial.begin(115200);
if (!AFMS.begin()) {
Serial.println("Could not find Motor Shield. Check wiring.");
while (1);
+2 -2
View File
@@ -6,8 +6,8 @@
typedef struct
{
uint32_t velocity;
float fanpower;
uint8_t velocity;
uint8_t fanpower;
}
SimWindData;
+4 -8
View File
@@ -14,7 +14,7 @@ SimWindData sd;
int velocity = 0;
void setup() {
Serial.begin(9600);
Serial.begin(115200);
if (!AFMS.begin()) {
Serial.println("Could not find Motor Shield. Check wiring.");
while (1);
@@ -37,11 +37,7 @@ void loop() {
memcpy(&sd, &buff, BYTE_SIZE);
velocity = sd.velocity;
}
int v = ceil(velocity * KPHTOMPH);
if (v >= 255)
{
v = 255;
}
myMotor1->setSpeed(v*FANPOWER);
myMotor2->setSpeed(v*FANPOWER);
myMotor1->setSpeed(velocity*FANPOWER);
myMotor2->setSpeed(velocity*FANPOWER);
}
+14
View File
@@ -7,8 +7,12 @@ set(devices_source_files
sounddevice.c
serialdevice.h
serialdevice.c
serialadapter.h
serialadapter.c
tachdevice.h
tachdevice.c
wheeldevice.h
wheeldevice.c
usbhapticdevice.h
usbhapticdevice.c
hapticeffect.h
@@ -19,11 +23,21 @@ set(devices_source_files
usb/revburner.c
usb/cslelitev3.h
usb/cslelitev3.c
usb/simagicp1000.h
usb/simagicp1000.c
usb/wheels/cammusc5.h
usb/wheels/cammusc5.c
usb/wheels/cammusc12.h
usb/wheels/cammusc12.c
sound/usb_generic_shaker.h
sound/usb_generic_shaker.c
sound/usb_generic_shaker_pulse.c
serial/arduino.h
serial/arduino.c
serial/arduinoledlua.h
serial/arduinoledlua.c
serial/moza.h
serial/moza.c
)
include_directories("." "usb" "sound" "serial")
+108 -171
View File
@@ -3,12 +3,12 @@
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <jansson.h>
#include <math.h>
#include "usbhapticdevice.h"
#include "../../helper/confighelper.h"
#include "../../simulatorapi/simapi/simapi/simdata.h"
#include "../../simulatorapi/simapi/simapi/simmapper.h"
#include "../../slog/slog.h"
#define kmhtoms 0.277778
@@ -45,136 +45,78 @@ int loadtyreconfig(SimData* simdata, char* configfile)
config_cars = config_lookup(&cfg, "cars");
if(config_cars == NULL)
{
slogd("diameters config file corrupted");
config_destroy(&cfg);
return 1;
}
slogt("parsing diameters config file");
int cars = config_setting_length(config_cars);
int i = 0;
while (i<cars)
{
DeviceSettings settings;
config_setting_t* config_car = config_setting_get_elem(config_cars, i);
const char* car;
double tyre0;
double tyre1;
double tyre2;
double tyre3;
config_setting_lookup_string(config_car, "car", &car);
config_setting_lookup_float(config_car, "tyre0", &tyre0);
config_setting_lookup_float(config_car, "tyre1", &tyre1);
config_setting_lookup_float(config_car, "tyre2", &tyre2);
config_setting_lookup_float(config_car, "tyre3", &tyre3);
if(simdata->car != NULL)
if(config_car != NULL)
{
if (strcicmp(car, simdata->car) == 0)
const char* car;
const char* simstr;
int sim = 0;
double tyre0;
double tyre1;
double tyre2;
double tyre3;
config_setting_lookup_string(config_car, "car", &car);
config_setting_lookup_float(config_car, "tyre0", &tyre0);
config_setting_lookup_float(config_car, "tyre1", &tyre1);
config_setting_lookup_float(config_car, "tyre2", &tyre2);
config_setting_lookup_float(config_car, "tyre3", &tyre3);
int found = config_setting_lookup_string(config_car, "sim", &simstr);
if(found == 0)
{
simdata->tyrediameter[0] = tyre0;
simdata->tyrediameter[1] = tyre1;
simdata->tyrediameter[2] = tyre2;
simdata->tyrediameter[3] = tyre3;
break;
int found = config_setting_lookup_int(config_car, "sim", &sim);
}
else
{
sim = simapi_strtogame(simstr);
}
if(simdata->car != NULL && car != NULL)
{
if(simdata->car[0] != '\0' && car[0] != '\0')
{
slogt("%s %s %i %i", simdata->car, car, simdata->simexe, sim);
if (strcicmp(car, simdata->car) == 0 && sim == simdata->simexe)
{
slogi("found saved car %s with tyre diameters %f %f %f %f", car, tyre0, tyre1, tyre2, tyre3);
simdata->tyrediameter[0] = tyre0;
simdata->tyrediameter[1] = tyre1;
simdata->tyrediameter[2] = tyre2;
simdata->tyrediameter[3] = tyre3;
break;
}
}
}
}
else
{
slogw("Possible corruption in config file on entry %i attempting to continue", i+1);
}
i++;
}
config_destroy(&cfg);
return 0;
}
//void loadtyreconfig(SimData* simdata, char* configfile)
//{
// json_t *root;
// json_error_t error;
//
// root = json_load_file(configfile, 0, NULL);
//
// if(!root)
// {
// slogw("could not open config file for tyre diameters");
// return;
// }
//
// if(!json_is_object(root))
// {
// slogw("Malformed content (1) in tyre diameters config");
// json_decref(root);
// return;
// }
//
// json_t* cararray = json_object_get(root, "cars");
// if(!json_is_array(cararray))
// {
// slogw("Malformed content (2) in tyre diameters config");
// json_decref(root);
// json_decref(cararray);
// return;
// }
//
// for(int i = 0; i < json_array_size(cararray); i++)
// {
// json_t *data, *sha, *commit, *message;
// const char *message_text;
//
// data = json_array_get(cararray, i);
// if(!json_is_object(data))
// {
// slogw("Malformed content (3) in tyre diameters config");
// break;
// }
// json_t* jcar = json_object_get(data, "car");
//
// if(!json_is_string(jcar))
// {
// slogw("Malformed content (4) in tyre diameters config");
//
// json_decref(data);
// json_decref(jcar);
// break;
// }
// const char* car = json_string_value(jcar);
//
// json_t* jtyre0 = json_object_get(data, "tyre0");
// json_t* jtyre1 = json_object_get(data, "tyre1");
// json_t* jtyre2 = json_object_get(data, "tyre2");
// json_t* jtyre3 = json_object_get(data, "tyre3");
//
// double diameter0 = json_real_value(jtyre0);
// double diameter1 = json_real_value(jtyre1);
// double diameter2 = json_real_value(jtyre2);
// double diameter3 = json_real_value(jtyre3);
//
// slogt("car is: %s", car);
// slogt("diameter 0 is %f", diameter0);
// slogt("diameter 1 is %f", diameter1);
// slogt("diameter 2 is %f", diameter2);
// slogt("diameter 3 is %f", diameter3);
//
// json_decref(data);
// json_decref(jcar);
// json_decref(jtyre0);
// json_decref(jtyre1);
// json_decref(jtyre2);
// json_decref(jtyre3);
//
// if(simdata->car != NULL)
// {
// if (strcicmp(car, simdata->car) == 0)
// {
// simdata->tyrediameter[0] = diameter0;
// simdata->tyrediameter[1] = diameter1;
// simdata->tyrediameter[2] = diameter2;
// simdata->tyrediameter[3] = diameter3;
// break;
// }
// }
// }
//
// json_decref(root);
// json_decref(cararray);
//}
void savetyreconfig(SimData* simdata, char* configfile)
int savetyreconfig(SimData* simdata, char* configfile)
{
config_t cfg;
config_setting_t* root;
@@ -195,10 +137,13 @@ void savetyreconfig(SimData* simdata, char* configfile)
array = config_lookup(&cfg, "cars");
}
// TODO add check to not add same car-sim combination twice
carobject = config_setting_add(array, "cars", CONFIG_TYPE_GROUP);
setting = config_setting_add(carobject, "car", CONFIG_TYPE_STRING);
config_setting_set_string(setting, simdata->car);
setting = config_setting_add(carobject, "sim", CONFIG_TYPE_INT);
config_setting_set_string(setting, simapi_gametostr(simdata->simexe));
setting = config_setting_add(carobject, "tyre0", CONFIG_TYPE_FLOAT);
config_setting_set_float(setting, simdata->tyrediameter[0]);
setting = config_setting_add(carobject, "tyre1", CONFIG_TYPE_FLOAT);
@@ -218,62 +163,17 @@ void savetyreconfig(SimData* simdata, char* configfile)
slogi("New configuration successfully written to: %s\n", configfile);
config_destroy(&cfg);
}
//void savetyreconfig(SimData* simdata, char* configfile)
//{
//
// json_t* object = json_object();
// json_t* array = json_array();
// json_t* car = json_string(simdata->car);
// json_t* tyre0 = json_real(simdata->tyrediameter[0]);
// json_t* tyre1 = json_real(simdata->tyrediameter[1]);
// json_t* tyre2 = json_real(simdata->tyrediameter[2]);
// json_t* tyre3 = json_real(simdata->tyrediameter[3]);
// json_object_set_new(object, "car", car);
// json_object_set_new(object, "tyre0", tyre0);
// json_object_set_new(object, "tyre1", tyre1);
// json_object_set_new(object, "tyre2", tyre2);
// json_object_set_new(object, "tyre3", tyre3);
//
// json_array_append(array, object);
//
// json_t* file = json_load_file(configfile, 0, NULL);
//
// if(!file)
// {
// slogw("could not open config file for tyre diameters");
// return;
// }
//
// if(!json_is_object(file))
// {
// json_object_set_new(file, "cars", array);
// }
// else
// {
// json_t* cararray = json_object_get(file, "cars");
// json_array_append(cararray, array);
// }
//
// json_dump_file(file, configfile, 0);
//
// json_decref(tyre0);
// json_decref(tyre1);
// json_decref(tyre2);
// json_decref(tyre3);
// json_decref(car);
// json_decref(object);
// json_decref(array);
//}
return 0;
}
void getTyreDiameter(SimData* simdata)
{
if(simdata->velocity > minvelocity && simdata->brake <= maxbrake && simdata->gas <= maxthrottle)
{
if (simdata->velocityX/simdata->velocity < maxXvelocity)
double Speedms = kmhtoms * simdata->velocity;
if (simdata->Xvelocity/Speedms < maxXvelocity)
{
double Speedms = kmhtoms * simdata->velocity;
for(int i = 0; i < 4; i++)
{
simdata->tyrediameter[i] = Speedms / simdata->tyreRPS[i] * 2;
@@ -294,31 +194,47 @@ double slipeffect(SimData* simdata, int effecttype, int tyre, double threshold,
wheelslip[2] = 0;
wheelslip[3] = 0;
slogt("wheel vibration calculation");
if(simdata->car == NULL)
{
slogw("sim is not compatible with wheel and tyre effects, or car and session not loaded.");
return 0;
}
if(simdata->car[0] == '\0')
{
slogw("sim is not compatible with wheel and tyre effects, or car not loaded.");
return 0;
}
slogt("wheel vibration calculation with wheel config set to %i configchecked %i configfile %s car %s", useconfig, *configcheck, configfile, simdata->car);
switch (effecttype)
{
case (EFFECT_TYRESLIP):
case (EFFECT_TYRELOCK):
case (EFFECT_ABSBRAKES):
if(hasTyreDiameter(simdata)==false)
if(useconfig == 1 && configfile != NULL)
{
// check for saved tyre diameter in config file
// if not saved version exists get tyre diameter and save it
// use config check variable to track if the config check has been performed
// avoid many opens of the same file
if(useconfig == 1 && configfile != NULL && *configcheck == 0)
int error = 0;
if(hasTyreDiameter(simdata)==false && *configcheck == 0)
{
int error = loadtyreconfig(simdata, configfile);
slogi("attempting load of tyre diameter config");
error = loadtyreconfig(simdata, configfile);
*configcheck = 1;
}
if(hasTyreDiameter(simdata)==false)
{
slogt("could not find tyre diameter in config file, attempting to calculate new");
getTyreDiameter(simdata);
if(useconfig == 1 && hasTyreDiameter(simdata)==true)
if(hasTyreDiameter(simdata)==true)
{
savetyreconfig(simdata, configfile);
slogi("saving tyre config");
error = savetyreconfig(simdata, configfile);
}
}
}
@@ -340,11 +256,21 @@ double slipeffect(SimData* simdata, int effecttype, int tyre, double threshold,
wheelslip[i] = 0;
}
}
slogt("wheelslip values are %f %f %f %f", wheelslip[0], wheelslip[1], wheelslip[2], wheelslip[3]);
slogt("velocities (x,y,z) are %f %f %f", simdata->Xvelocity, simdata->Yvelocity, simdata->Zvelocity);
}
break;
default:
slogt("Unknown effect type");
slogd("Unknown effect type");
}
if(simdata->Yvelocity <= 0)
{
return 0;
}
if(simdata->Zvelocity > 1 || simdata->Zvelocity < -1)
{
return 0;
}
switch (effecttype)
@@ -357,6 +283,7 @@ double slipeffect(SimData* simdata, int effecttype, int tyre, double threshold,
if(wheelslip[0] < -threshold)
{
play += fabs(wheelslip[0]) - fabs(threshold);
slogt("slip is %f", play);
}
}
if (tyre == FRONTRIGHT || tyre == FRONTS || tyre == ALLFOUR)
@@ -364,6 +291,7 @@ double slipeffect(SimData* simdata, int effecttype, int tyre, double threshold,
if(wheelslip[1] < -threshold)
{
play += fabs(wheelslip[1]) - fabs(threshold);
slogt("slip is %f", play);
}
}
if (tyre == REARLEFT || tyre == REARS || tyre == ALLFOUR)
@@ -371,6 +299,7 @@ double slipeffect(SimData* simdata, int effecttype, int tyre, double threshold,
if(wheelslip[2] < -threshold)
{
play += fabs(wheelslip[2]) - fabs(threshold);
slogt("slip is %f", play);
}
}
if (tyre == REARRIGHT || tyre == REARS || tyre == ALLFOUR)
@@ -378,17 +307,18 @@ double slipeffect(SimData* simdata, int effecttype, int tyre, double threshold,
if(wheelslip[3] < -threshold)
{
play += fabs(wheelslip[3]) - fabs(threshold);
slogt("slip is %f", play);
}
}
break;
case (EFFECT_TYRELOCK):
if (tyre == FRONTLEFT || tyre == FRONTS || tyre == ALLFOUR)
{
if(wheelslip[0] > threshold)
{
play += wheelslip[0] - threshold;
slogt("lock is %f", play);
}
}
if (tyre == FRONTRIGHT || tyre == FRONTS || tyre == ALLFOUR)
@@ -396,6 +326,7 @@ double slipeffect(SimData* simdata, int effecttype, int tyre, double threshold,
if(wheelslip[1] > threshold)
{
play += wheelslip[1] - threshold;
slogt("lock is %f", play);
}
}
if (tyre == REARLEFT || tyre == REARS || tyre == ALLFOUR)
@@ -403,6 +334,7 @@ double slipeffect(SimData* simdata, int effecttype, int tyre, double threshold,
if(wheelslip[2] > threshold)
{
play += wheelslip[2] - threshold;
slogt("lock is %f", play);
}
}
if (tyre == REARRIGHT || tyre == REARS || tyre == ALLFOUR)
@@ -410,6 +342,7 @@ double slipeffect(SimData* simdata, int effecttype, int tyre, double threshold,
if(wheelslip[3] > threshold)
{
play += wheelslip[3] - threshold;
slogt("lock is %f", play);
}
}
@@ -421,6 +354,7 @@ double slipeffect(SimData* simdata, int effecttype, int tyre, double threshold,
if(wheelslip[0] > threshold)
{
play += wheelslip[0] - threshold;
slogt("abs is %f", play);
}
}
if (tyre == FRONTRIGHT || tyre == FRONTS || tyre == ALLFOUR)
@@ -428,6 +362,7 @@ double slipeffect(SimData* simdata, int effecttype, int tyre, double threshold,
if(wheelslip[1] > threshold)
{
play += wheelslip[1] - threshold;
slogt("abs is %f", play);
}
}
if (tyre == REARLEFT || tyre == REARS || tyre == ALLFOUR)
@@ -435,6 +370,7 @@ double slipeffect(SimData* simdata, int effecttype, int tyre, double threshold,
if(wheelslip[2] > threshold)
{
play += wheelslip[2] - threshold;
slogt("abs is %f", play);
}
}
if (tyre == REARRIGHT || tyre == REARS || tyre == ALLFOUR)
@@ -442,6 +378,7 @@ double slipeffect(SimData* simdata, int effecttype, int tyre, double threshold,
if(wheelslip[3] > threshold)
{
play += wheelslip[3] - threshold;
slogt("abs is %f", play);
}
}
if(simdata->abs <= 0)
+301 -76
View File
@@ -2,105 +2,330 @@
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include "arduino.h"
#include "arduinoledlua.h"
#include "../serialadapter.h"
#include "../../slog/slog.h"
#define arduino_timeout 5000
int arduino_update(SerialDevice* serialdevice, void* data, size_t size)
int arduino_check(enum sp_return result)
{
int result = 1;
if (serialdevice->port)
{
slogt("copying %i bytes to arduino device", size);
result = check(sp_blocking_write(serialdevice->port, data, size, arduino_timeout));
}
return result;
}
//int arduino_shiftlights_update(SerialDevice* serialdevice, SimData* simdata)
//{
// int result = 1;
// if (serialdevice->port)
// {
// result = check(sp_blocking_write(serialdevice->port, simdata, sizeof(SimData), arduino_timeout));
// }
//
// return result;
//}
//
//int arduino_simwind_update(SerialDevice* serialdevice, SimData* simdata)
//{
// int result = 1;
// if (serialdevice->port)
// {
// result = check(sp_blocking_write(serialdevice->port, simdata, sizeof(SimData), arduino_timeout));
// }
//
// return result;
//}
int arduino_init(SerialDevice* serialdevice, const char* portdev)
{
slogi("initializing arduino serial device...");
int error = 0;
char* port_name = strdup(portdev);
slogd("Looking for port %s.\n", port_name);
error = check(sp_get_port_by_name(port_name, &serialdevice->port));
if (error != 0)
{
return error;
}
slogd("Opening port.\n");
check(sp_open(serialdevice->port, SP_MODE_READ_WRITE));
slogd("Setting port to 9600 8N1, no flow control.\n");
check(sp_set_baudrate(serialdevice->port, 9600));
check(sp_set_bits(serialdevice->port, 8));
check(sp_set_parity(serialdevice->port, SP_PARITY_NONE));
check(sp_set_stopbits(serialdevice->port, 1));
check(sp_set_flowcontrol(serialdevice->port, SP_FLOWCONTROL_NONE));
free(port_name);
slogd("Successfully setup arduino serial device...");
return 0;
}
int arduino_free(SerialDevice* serialdevice)
{
check(sp_close(serialdevice->port));
sp_free_port(serialdevice->port);
}
int check(enum sp_return result)
{
/* For this example we'll just exit on any error by calling abort(). */
char* error_message;
switch (result)
{
case SP_ERR_ARG:
//printf("Error: Invalid argument.\n");
return 1;
//abort();
case SP_ERR_FAIL:
error_message = sp_last_error_message();
printf("Error: Failed: %s\n", error_message);
sloge("error: serial write failed: %s", error_message);
sp_free_error_message(error_message);
abort();
case SP_ERR_SUPP:
printf("Error: Not supported.\n");
abort();
case SP_ERR_MEM:
printf("Error: Couldn't allocate memory.\n");
abort();
case SP_OK:
default:
return result;
}
}
int arduino_update(SerialDevice* serialdevice, void* data, size_t size)
{
int result = 1;
slogt("copying %i bytes to arduino device", size);
result = monocoque_serial_write(serialdevice->id, data, size, arduino_timeout);
return result;
}
int arduino_init(SerialDevice* serialdevice, const char* portdev)
{
serialdevice->id = monocoque_serial_open(serialdevice, portdev);
return serialdevice->id;
}
int arduino_customled_init(SerialDevice* serialdevice, const char* portdev, const char* luafile)
{
serialdevice->id = monocoque_serial_open(serialdevice, portdev);
size_t bufsize1 = 11;
size_t recv_bufsize1 = 5;
char recv_buf1[recv_bufsize1];
char bytes1[bufsize1];
for(int j = 0; j < bufsize1; j++)
{
bytes1[j] = 0x00;
}
bytes1[0] = 0xff;
bytes1[1] = 0xff;
bytes1[2] = 0xff;
bytes1[3] = 0xff;
bytes1[4] = 0xff;
bytes1[5] = 0xff;
bytes1[6] = 0x6c;
bytes1[7] = 0x65;
bytes1[8] = 0x64;
bytes1[9] = 0x73;
bytes1[10] = 0x63;
int result = 0;
unsigned int timeout = 2000;
result = monocoque_serial_write_block(serialdevice->id, &bytes1, bufsize1, timeout);
result = monocoque_serial_read_block(serialdevice->id, &recv_buf1, recv_bufsize1, timeout);
//slogi("wrote %i bytes", result);
//sleep(2);
//monocoque_serial_device monocoque_serial_dev = monocoque_serial_devices[serialdevice->id];
//result = arduino_check(sp_blocking_read(monocoque_serial_dev.port, &recv_buf1, recv_bufsize1, 5000));
//slogi("read %i bytes", result);
//result = sp_blocking_read(serialdevice->port, &recv_buf1, recv_bufsize1, timeout);
char numstr[recv_bufsize1];
for(int j = 0; j < recv_bufsize1; j++)
{
numstr[j] = '\0';
}
for(int j = 0; j < recv_bufsize1; j++)
{
if(recv_buf1[j] != 0 && recv_buf1[j] != 0x0d && recv_buf1[j] != 0x0a)
{
numstr[j] = recv_buf1[j];
}
}
int numlights = atoi(numstr);
serialdevice->numleds = numlights;
slogi("numlights is %i\n", numlights);
if(luafile == NULL)
{
return serialdevice->id;
}
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 */
fprintf(stderr, "Couldn't load file: %s\n", lua_tostring(L, -1));
exit(1);
}
lua_setglobal(L,"myFunc");
serialdevice->L = L;
return serialdevice->id;
}
int arduino_simled_update(SimDevice* this, SimData* simdata)
{
SerialDevice* serialdevice = (void *) this->derived;
int result = 1;
int total_leds = serialdevice->numleds;
size_t bufsize = (total_leds * 3) + 14;
char bytes[bufsize];
int endled = serialdevice->endled;
int startled = serialdevice->startled;
if(endled == 0)
{
endled = total_leds;
}
int num_avail_leds = endled - startled + 1;
int rpm = simdata->rpms;
int maxrpm = simdata->maxrpm;
int litleds = 0;
if(rpm > 0 && maxrpm > 0)
{
int rpmmargin = ceil(.05*maxrpm);
int rpminterval = (maxrpm-rpmmargin) / (num_avail_leds);
for (int l = 1; l <= (num_avail_leds); l++)
{
if(rpm >= (rpminterval * l))
{
litleds = l;
}
}
for(int j = 0; j < bufsize; j++)
{
bytes[j] = 0x00;
}
bytes[0] = 0xff;
bytes[1] = 0xff;
bytes[2] = 0xff;
bytes[3] = 0xff;
bytes[4] = 0xff;
bytes[5] = 0xff;
bytes[6] = 0x73;
bytes[7] = 0x6c;
bytes[8] = 0x65;
bytes[9] = 0x64;
bytes[10] = 0x73;
bytes[bufsize-1] = 0xfd;
bytes[bufsize-2] = 0xfe;
bytes[bufsize-3] = 0xff;
for(int i = 0; i < litleds; i++)
{
if(i < ((num_avail_leds) / 2))
{
//green
bytes[11 + ((i + startled - 1) * 3) + 1] = 0xff;
}
else
{
if(i < num_avail_leds - 1)
{
//yellow
bytes[11 + ((i + startled - 1) * 3) + 0] = 0xff;
bytes[11 + ((i + startled - 1) * 3) + 1] = 0xff;
}
}
if(i == num_avail_leds - 1)
{
//red
bytes[11 + ((i + startled - 1) * 3) + 0] = 0xff;
}
}
}
slogt("Updating arduino device lights to %i", litleds);
// we can add configs to set all the colors
size_t size = sizeof(bytes);
result = monocoque_serial_write(serialdevice->id, &bytes, size, arduino_timeout);
return result;
}
int arduino_customled_update(SimDevice* this, SimData* simdata)
{
SerialDevice* serialdevice = (void *) this->derived;
int result = 1;
int total_leds = serialdevice->numleds;
size_t bufsize = (total_leds * 3) + 14;
char bytes[bufsize];
for(int j = 0; j < bufsize; j++)
{
bytes[j] = 0x00;
}
bytes[0] = 0xff;
bytes[1] = 0xff;
bytes[2] = 0xff;
bytes[3] = 0xff;
bytes[4] = 0xff;
bytes[5] = 0xff;
bytes[6] = 0x73;
bytes[7] = 0x6c;
bytes[8] = 0x65;
bytes[9] = 0x64;
bytes[10] = 0x73;
bytes[bufsize-1] = 0xfd;
bytes[bufsize-2] = 0xfe;
bytes[bufsize-3] = 0xff;
lua_State* L = serialdevice->L;
lua_pushstring(L, "buff");
lua_pushlightuserdata(L, &bytes);
lua_settable(L, LUA_REGISTRYINDEX);
simdata_to_lua(L, simdata);
lua_setglobal(L, "simdata");
lua_pushinteger(L, total_leds);
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));
}
size_t size = sizeof(bytes);
arduino_update(serialdevice, &bytes, size);
// move to free
return result;
}
int arduino_customled_free(SerialDevice* serialdevice, bool lua)
{
size_t bufsize = (serialdevice->numleds * 3) + 14;
char bytes[bufsize];
int endled = serialdevice->endled;
int startled = serialdevice->startled;
if(endled == 0)
for(int j = 0; j < bufsize; j++)
{
bytes[j] = 0x00;
}
bytes[0] = 0xff;
bytes[1] = 0xff;
bytes[2] = 0xff;
bytes[3] = 0xff;
bytes[4] = 0xff;
bytes[5] = 0xff;
bytes[6] = 0x73;
bytes[7] = 0x6c;
bytes[8] = 0x65;
bytes[9] = 0x64;
bytes[10] = 0x73;
bytes[bufsize-1] = 0xfd;
bytes[bufsize-2] = 0xfe;
bytes[bufsize-3] = 0xff;
for(int i = 0; i < serialdevice->numleds; i++)
{
bytes[11 + (i * 3) + 0] = 0x00;
bytes[11 + (i * 3) + 1] = 0x00;
bytes[11 + (i * 3) + 2] = 0x00;
}
size_t size = sizeof(bytes);
int result = monocoque_serial_write(serialdevice->id, &bytes, size, arduino_timeout);
if(lua == true)
{
lua_close(serialdevice->L);
}
return result;
}
+4 -1
View File
@@ -5,9 +5,12 @@
#include "../serialdevice.h"
int arduino_simled_update(SimDevice* this, SimData* simdata);
int arduino_update(SerialDevice* serialdevice, void* data, size_t size);
int arduino_customled_init(SerialDevice* serialdevice, const char* portdev, const char* luafile);
int arduino_customled_update(SimDevice* this, SimData* simdata);
int arduino_init(SerialDevice* serialdevice, const char* portdev);
int arduino_free(SerialDevice* serialdevice);
int check(enum sp_return result);
int arduino_customled_free(SerialDevice* serialdevice, bool lua);
#endif
@@ -0,0 +1,302 @@
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include "arduinoledlua.h"
#include "arduino.h"
#include "../../slog/slog.h"
int simdata_to_lua(lua_State *L, SimData* simdata) {
lua_newtable(L);
lua_pushinteger(L, simdata->playerflag);
lua_setfield(L, -2, "playerflag");
lua_pushinteger(L, simdata->rpms);
lua_setfield(L, -2, "rpm");
lua_pushinteger(L, simdata->maxrpm);
lua_setfield(L, -2, "maxrpm");
return 1; // Return the table to Lua
}
uint8_t get_color_rgb_value(int color, int rgb)
{
switch (color)
{
case LUALEDCOLOR_RED:
switch (rgb)
{
case 0:
return 255;
case 1:
return 0;
case 2:
return 0;
}
case LUALEDCOLOR_GREEN:
switch (rgb)
{
case 0:
return 0;
case 1:
return 255;
case 2:
return 0;
}
case LUALEDCOLOR_BLUE:
switch (rgb)
{
case 0:
return 0;
case 1:
return 0;
case 2:
return 255;
}
case LUALEDCOLOR_YELLOW:
switch (rgb)
{
case 0:
return 255;
case 1:
return 255;
case 2:
return 0;
}
case LUALEDCOLOR_ORANGE:
switch (rgb)
{
case 0:
return 255;
case 1:
return 165;
case 2:
return 0;
}
default:
return 0;
}
}
int set_led_range_to_color(lua_State *L)
{
slogt("lua called c function set_led_range_to_color");
int range_start = lua_tonumber(L, 1);
int range_end = lua_tonumber(L, 2);
int color = lua_tonumber(L, 3);
slogd("lua range start is %i", range_start);
slogd("lua range end is %i", range_end);
slogd("lua color is %i", color);
range_start = range_start - 1;
lua_getglobal(L, "TotalLeds");
int numlights = 0;
if (lua_isnumber(L, -1))
{
numlights = lua_tonumber(L, -1);
}
slogd("num leds is %i", numlights);
if(range_end > numlights)
{
range_end = numlights;
}
if(range_end == 0)
{
slogt("Invalid range, doing nothing");
return 1;
}
lua_pushstring(L, "buff");
lua_gettable(L, LUA_REGISTRYINDEX);
char* bytes = lua_touserdata(L, -1);
slogt("tenth byte of buff is x%02x", bytes[10]);
uint8_t color0 = get_color_rgb_value(color, 0);
uint8_t color1 = get_color_rgb_value(color, 1);
uint8_t color2 = get_color_rgb_value(color, 2);
for( int i = range_start; i < range_end; i++)
{
bytes[(i * 3) + 11 + 0] = color0;
bytes[(i * 3) + 11 + 1] = color1;
bytes[(i * 3) + 11 + 2] = color2;
}
}
int set_led_range_to_rgb_color(lua_State *L)
{
slogt("lua called c function set_led_range_to_rgb_color");
int range_start = lua_tonumber(L, 1);
int range_end = lua_tonumber(L, 2);
int color0 = lua_tonumber(L, 3);
int color1 = lua_tonumber(L, 4);
int color2 = lua_tonumber(L, 5);
slogd("lua range start is %i", range_start);
slogd("lua range end is %i", range_end);
slogd("lua color0 is %i", color0);
slogd("lua color1 is %i", color1);
slogd("lua color2 is %i", color2);
range_start = range_start - 1;
lua_getglobal(L, "TotalLeds");
int numlights = 0;
if (lua_isnumber(L, -1))
{
numlights = lua_tonumber(L, -1);
}
slogd("num leds is %i", numlights);
if(range_end > numlights)
{
range_end = numlights;
}
if(range_end == 0)
{
return 1;
}
lua_pushstring(L, "buff");
lua_gettable(L, LUA_REGISTRYINDEX);
char* bytes = lua_touserdata(L, -1);
slogt("tenth byte of buff is x%02x", bytes[10]);
for( int i = range_start; i < range_end; i++)
{
bytes[(i * 3) + 11 + 0] = color0;
bytes[(i * 3) + 11 + 1] = color1;
bytes[(i * 3) + 11 + 2] = color2;
}
}
int set_led_to_color(lua_State *L)
{
slogt("lua called c function set_led_to_rgb_color");
int led = lua_tonumber(L, 1);
int color = lua_tonumber(L, 2);
slogd("lua led is %i", led);
slogd("lua color is %i", color);
led = led - 1;
lua_getglobal(L, "TotalLeds");
int numlights = 0;
if (lua_isnumber(L, -1))
{
numlights = lua_tonumber(L, -1);
}
slogd("num leds is %i", numlights);
if(led > numlights)
{
return 1;
}
lua_pushstring(L, "buff");
lua_gettable(L, LUA_REGISTRYINDEX);
char* bytes = lua_touserdata(L, -1);
slogt("tenth byte of buff is x%02x", bytes[10]);
uint8_t color0 = get_color_rgb_value(color, 0);
uint8_t color1 = get_color_rgb_value(color, 1);
uint8_t color2 = get_color_rgb_value(color, 2);
bytes[(led * 3) + 11 + 0] = color0;
bytes[(led * 3) + 11 + 1] = color1;
bytes[(led * 3) + 11 + 2] = color2;
}
int set_led_to_rgb_color(lua_State *L)
{
slogt("lua called c function set_led_to_rgb_color");
int led = lua_tonumber(L, 1);
int color0 = lua_tonumber(L, 2);
int color1 = lua_tonumber(L, 3);
int color2 = lua_tonumber(L, 4);
slogd("lua led is %i", led);
slogd("lua color0 is %i", color0);
slogd("lua color1 is %i", color1);
slogd("lua color2 is %i", color2);
led = led - 1;
lua_getglobal(L, "TotalLeds");
int numlights = 0;
if (lua_isnumber(L, -1))
{
numlights = lua_tonumber(L, -1);
}
slogd("num leds is %i", numlights);
if(led > numlights)
{
return 1;
}
lua_pushstring(L, "buff");
lua_gettable(L, LUA_REGISTRYINDEX);
char* bytes = lua_touserdata(L, -1);
slogt("tenth byte of buff is x%02x", bytes[10]);
bytes[(led * 3) + 11 + 0] = color0;
bytes[(led * 3) + 11 + 1] = color1;
bytes[(led * 3) + 11 + 2] = color2;
}
int led_clear_all(lua_State *L)
{
slogt("lua called c function led_clear_all");
lua_getglobal(L, "TotalLeds");
int numlights = 0;
if (lua_isnumber(L, -1))
{
numlights = lua_tonumber(L, -1);
}
slogd("num leds is %i", numlights);
lua_pushstring(L, "buff");
lua_gettable(L, LUA_REGISTRYINDEX);
char* bytes = lua_touserdata(L, -1);
slogt("tenth byte of buff is x%02x", bytes[10]);
for( int i = 0; i < numlights; i++)
{
bytes[(i * 3) + 11 + 0] = 0x00;
bytes[(i * 3) + 11 + 1] = 0x00;
bytes[(i * 3) + 11 + 2] = 0x00;
}
}
@@ -0,0 +1,25 @@
#ifndef _ARDUINOLEDLUA_H
#define _ARDUINOLEDLUA_H
#include "lua5.4/lua.h"
#include "lua5.4/lauxlib.h"
#include "lua5.4/lualib.h"
#include "../../simulatorapi/simapi/simapi/simdata.h"
typedef enum {
LUALEDCOLOR_RED = 1,
LUALEDCOLOR_GREEN,
LUALEDCOLOR_BLUE,
LUALEDCOLOR_YELLOW,
LUALEDCOLOR_ORANGE,
} LUALEDColor;
int simdata_to_lua(lua_State *L, SimData* simdata);
int set_led_range_to_color(lua_State *L);
int set_led_to_color(lua_State *L);
int set_led_range_to_rgb_color(lua_State *L);
int set_led_to_rgb_color(lua_State *L);
int led_clear_all(lua_State *L);
#endif
+88
View File
@@ -0,0 +1,88 @@
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include <hidapi/hidapi.h>
#include "moza.h"
#include "../serialadapter.h"
#include "../../slog/slog.h"
#define MOZA_TIMEOUT 1000
#define MOZA_SERIAL_TEMPLATE {0x7e, 0x06, 0x41, 0x17, 0xfd, 0xde, 0x0, 0x0, 0x0, 0x0, 0x0}
#define MOZA_NUM_AVAILABLE_LEDS 10
#define MOZA_BLINKING_BIT 7
#define MOZA_MAGIC_VALUE 0x0d
#define BIT(nr) (1UL << (nr))
unsigned char moza_checksum(unsigned char *data)
{
unsigned char ret = MOZA_MAGIC_VALUE;
for (short i = 0; i < sizeof(data)/sizeof(data[0]); i++)
{
ret += data[i];
}
return ret;
}
int moza_update(SerialDevice* serialdevice, unsigned short maxrpm, unsigned short rpm)
{
unsigned char bytes[] = MOZA_SERIAL_TEMPLATE;
int size = sizeof(bytes)/sizeof(bytes[0]);
float perct = (float)rpm/(float)maxrpm;
if (perct >= 0.8)
bytes[9] |= BIT(0);
if (perct >= 0.83)
bytes[9] |= BIT(1);
if (perct >= 0.86)
bytes[9] |= BIT(2);
if (perct >= 0.89)
bytes[9] |= BIT(3);
if (perct >= 0.91)
bytes[8] |= BIT(4);
if (perct >= 0.92)
bytes[8] |= BIT(5);
if (perct >= 0.93)
bytes[8] |= BIT(6);
if (perct >= 0.94)
bytes[8] |= BIT(7);
if (perct >= 0.96)
bytes[8] |= BIT(0);
if (perct >= 0.96)
bytes[8] |= BIT(1);
// blinking
if (perct >= 0.97)
bytes[9] |= BIT(MOZA_BLINKING_BIT);
bytes[10] = moza_checksum(bytes);
int result = 1;
if (serialdevice->port)
{
slogd("copying %i bytes to moza device", size);
slogt("writing bytes %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x from rpm %i maxrpm %i", bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6], bytes[7], bytes[8], bytes[9], bytes[10], rpm, maxrpm);
result = monocoque_serial_write(serialdevice->id, bytes, size, MOZA_TIMEOUT);
}
return result;
}
int moza_init(SerialDevice* serialdevice, const char* portdev)
{
serialdevice->id = monocoque_serial_open(serialdevice, portdev);
return serialdevice->id;
}
+13
View File
@@ -0,0 +1,13 @@
#ifndef _MOZA_H
#define _MOZA_H
#include "../serialdevice.h"
#include "../simdevice.h"
int moza_update(SerialDevice* serialdevice, unsigned short maxrpm, unsigned short rpm);
int moza_init(SerialDevice* serialdevice, const char* portdev);
int moza_free(SerialDevice* serialdevice);
int moza_serial_check(enum sp_return result);
#endif
+236
View File
@@ -0,0 +1,236 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "serialadapter.h"
#include "../slog/slog.h"
int msastrcicmp(char const *a, char const *b)
{
for (;; a++, b++) {
int d = tolower((unsigned char)*a) - tolower((unsigned char)*b);
if (d != 0 || !*a)
return d;
}
}
int check(enum sp_return result)
{
char* error_message;
switch (result)
{
case SP_ERR_ARG:
return 1;
case SP_ERR_FAIL:
error_message = sp_last_error_message();
sloge("error: serial write failed: %s", error_message);
sp_free_error_message(error_message);
case SP_ERR_SUPP:
printf("Error: Not supported.\n");
case SP_ERR_MEM:
printf("Error: Couldn't allocate memory.\n");
case SP_OK:
default:
return result;
}
}
int monocoque_serial_free(SerialDevice* serialdevice)
{
monocoque_serial_device monocoque_serial_dev = monocoque_serial_devices[serialdevice->id];
if(monocoque_serial_dev.open == true)
{
while(monocoque_serial_dev.busy == true)
{
slogt("hopefully this doesn't happen long");
continue;
}
monocoque_serial_devices[serialdevice->id].busy = true;
monocoque_serial_devices[serialdevice->id].refs--;
if(monocoque_serial_devices[serialdevice->id].refs == 0)
{
slogd("freeing physical device %s", monocoque_serial_devices[serialdevice->id].portname);
sp_close(monocoque_serial_devices[serialdevice->id].port);
sp_free_port(monocoque_serial_devices[serialdevice->id].port);
monocoque_serial_devices[serialdevice->id].busy = false;
monocoque_serial_devices[serialdevice->id].open = false;
monocoque_serial_devices[serialdevice->id].openfail = false;
free(monocoque_serial_devices[serialdevice->id].portname);
}
else
{
monocoque_serial_devices[serialdevice->id].busy = false;
}
}
}
int monocoque_serial_write(uint8_t serialdevicenum, void* data, size_t size, int timeout)
{
slogt("serial device id %i", serialdevicenum);
monocoque_serial_device monocoque_serial_dev = monocoque_serial_devices[serialdevicenum];
slogt("port name: %s, busy %i, open %i, openfail %i", monocoque_serial_dev.portname, monocoque_serial_dev.busy, monocoque_serial_dev.open, monocoque_serial_dev.busy);
if(monocoque_serial_dev.port == NULL)
{
sloge("port is null");
}
int result = -1;
if(monocoque_serial_dev.busy == false && monocoque_serial_dev.open == true)
{
monocoque_serial_dev.busy = true;
result = sp_blocking_write(monocoque_serial_dev.port, data, size, timeout);
}
else
{
slogw("serial device data update ignored due to busy or lost device");
result = -1;
}
slogt("write result is %i", result);
monocoque_serial_dev.busy = false;
return result;
}
int monocoque_serial_write_block(uint8_t serialdevicenum, void* data, size_t size, int timeout)
{
slogt("serial device id %i", serialdevicenum);
monocoque_serial_device monocoque_serial_dev = monocoque_serial_devices[serialdevicenum];
slogt("port name: %s, busy %i, open %i, openfail %i", monocoque_serial_dev.portname, monocoque_serial_dev.busy, monocoque_serial_dev.open, monocoque_serial_dev.busy);
if(monocoque_serial_dev.port == NULL)
{
sloge("port is null");
}
int result = -1;
if(monocoque_serial_dev.open == true)
{
while(monocoque_serial_dev.busy == true)
{
slogt("hopefully this doesn't happen long");
continue;
}
monocoque_serial_dev.busy = true;
result = sp_blocking_write(monocoque_serial_dev.port, data, size, timeout);
slogi("actually performed write");
}
monocoque_serial_dev.busy = false;
return result;
}
int monocoque_serial_read_block(uint8_t serialdevicenum, void* data, size_t size, int timeout)
{
slogt("serial device id %i", serialdevicenum);
monocoque_serial_device monocoque_serial_dev = monocoque_serial_devices[serialdevicenum];
slogt("port name: %s, busy %i, open %i, openfail %i", monocoque_serial_dev.portname, monocoque_serial_dev.busy, monocoque_serial_dev.open, monocoque_serial_dev.busy);
if(monocoque_serial_dev.port == NULL)
{
sloge("port is null");
}
int result = -1;
if(monocoque_serial_dev.open == true)
{
while(monocoque_serial_dev.busy == true)
{
slogt("hopefully this doesn't happen long");
continue;
}
monocoque_serial_dev.busy = true;
result = sp_blocking_read(monocoque_serial_dev.port, data, size, timeout);
slogi("actually performed read");
}
monocoque_serial_dev.busy = false;
return result;
}
int monocoque_serial_open(SerialDevice* serialdevice, const char* portdev)
{
int serial_device_num = -1;
bool notfound = true;
slogi("looking to open physical serialdevice %s", portdev);
for(int i = 0; i < 10; i++)
{
if(monocoque_serial_devices[i].open == true || monocoque_serial_devices[i].openfail == true)
{
if(msastrcicmp(monocoque_serial_devices[i].portname, portdev) == 0)
{
notfound = false;
serial_device_num = i;
monocoque_serial_devices[i].refs++;
slogd("found exisiting handle to serial device %s", portdev);
}
}
}
if(notfound == true)
{
slogd("no existing connections found, looking to create new");
int i = -1;
bool avail = false;
while(avail == false)
{
i++;
if(monocoque_serial_devices[i].open == false && monocoque_serial_devices[i].openfail == false)
{
avail = true;
break;
}
}
slogi("opening physical serial device...");
int error = 0;
char* port_name = strdup(portdev);
monocoque_serial_devices[i].portname = strdup(port_name);
struct sp_port* sp;
slogd("Looking for port %s", port_name);
error = check(sp_get_port_by_name(port_name, &sp));
if (error != 0)
{
sloge("Error opening serial port");
monocoque_serial_devices[i].open = false;
monocoque_serial_devices[i].openfail = true;
return -1;
}
slogd("Opening port");
check(sp_open(sp, SP_MODE_READ_WRITE));
slogd("Setting port to %i 8N1, no flow control", serialdevice->baudrate);
check(sp_set_baudrate(sp, serialdevice->baudrate));
check(sp_set_bits(sp, 8));
check(sp_set_parity(sp, SP_PARITY_NONE));
check(sp_set_stopbits(sp, 1));
check(sp_set_flowcontrol(sp, SP_FLOWCONTROL_NONE));
monocoque_serial_devices[i].port = sp;
monocoque_serial_devices[i].open = true;
monocoque_serial_devices[i].openfail = false;
monocoque_serial_devices[i].busy = false;
monocoque_serial_devices[i].refs++;
serial_device_num = i;
free(port_name);
slogd("Successfully setup arduino serial device...");
}
return serial_device_num;
}
+29
View File
@@ -0,0 +1,29 @@
#ifndef _SERIALADAPTER_H
#define _SERIALADAPTER_H
#include <stdint.h>
#include <stdbool.h>
#include <libserialport.h>
#include "simdevice.h"
typedef struct
{
char* portname;
struct sp_port* port;
uint8_t refs;
bool open;
bool openfail;
bool busy;
}
monocoque_serial_device;
static monocoque_serial_device monocoque_serial_devices[10];
int monocoque_serial_write(uint8_t serialdevicenum, void* data, size_t size, int timeout);
int monocoque_serial_write_block(uint8_t serialdevicenum, void* data, size_t size, int timeout);
int monocoque_serial_read_block(uint8_t serialdevicenum, void* data, size_t size, int timeout);
int monocoque_serial_open(SerialDevice* serialdevice, const char* port);
int monocoque_serial_free(SerialDevice* serialdevice);
#endif
+147 -19
View File
@@ -6,19 +6,31 @@
#include "simdevice.h"
#include "serialdevice.h"
#include "serialadapter.h"
#include "hapticeffect.h"
#include "serial/arduino.h"
#include "serial/moza.h"
#include "../helper/parameters.h"
#include "../simulatorapi/simapi/simapi/simdata.h"
#include "../slog/slog.h"
#define KPHTOMPH .621317
int serial_wheel_update(SimDevice* this, SimData* simdata)
{
SerialDevice* serialdevice = (void *) this->derived;
moza_update(serialdevice, simdata->maxrpm, simdata->rpms);
return 0;
}
int serialdev_update(SimDevice* this, SimData* simdata)
{
SerialDevice* serialdevice = (void *) this->derived;
arduino_update(serialdevice, simdata, sizeof(SimData));
return 0;
}
@@ -28,9 +40,28 @@ int arduino_shiftlights_update(SimDevice* this, SimData* simdata)
int result = 1;
serialdevice->u.shiftlightsdata.maxrpm = simdata->maxrpm;
serialdevice->u.shiftlightsdata.rpm = simdata->rpms;
slogt("Updating arduino device rpms to %i", serialdevice->u.shiftlightsdata.rpm);
int num_avail_leds = serialdevice->numlights;
int rpm = simdata->rpms;
int maxrpm = simdata->maxrpm;
int litleds = 0;
if(rpm > 0 && maxrpm > 0)
{
int rpmmargin = ceil(.05*maxrpm);
int rpminterval = (maxrpm-rpmmargin) / (num_avail_leds);
for (int l = 1; l <= (num_avail_leds); l++)
{
if(rpm >= (rpminterval * l))
{
litleds = l;
}
}
}
serialdevice->u.shiftlightsdata.litleds = litleds;
//serialdevice->u.shiftlightsdata.rpm = simdata->rpms;
slogt("Updating arduino device lights to %i", serialdevice->u.shiftlightsdata.litleds);
// we can add configs to set all the colors
// i can move the size to the initialization since it should not change
size_t size = sizeof(ShiftLightsData);
@@ -39,15 +70,19 @@ int arduino_shiftlights_update(SimDevice* this, SimData* simdata)
return result;
}
int arduino_simwind_update(SimDevice* this, SimData* simdata)
{
SerialDevice* serialdevice = (void *) this->derived;
int result = 1;
serialdevice->u.simwinddata.velocity = simdata->velocity;
// sending over as mph, when you consider 255mph to be a reasonable upper limit
serialdevice->u.simwinddata.velocity = ceil(simdata->velocity*KPHTOMPH);
slogt("Updating arduino device speed to %i", serialdevice->u.simwinddata.velocity);
// this can be added to the config, all config dependent can be added to init
serialdevice->u.simwinddata.fanpower = 0.6;
serialdevice->u.simwinddata.fanpower = (int)0.6 * 255;
size_t size = sizeof(SimWindData);
arduino_update(serialdevice, &serialdevice->u.simwinddata, size);
@@ -81,13 +116,13 @@ int arduino_simhaptic_update(SimDevice* this, SimData* simdata)
{
serialdevice->u.simhapticdata.effect1 = effectspeed;
serialdevice->u.simhapticdata.motor1 = 1;
slogt("Updating arduino haptic device speed motor speed %i on motor %i from original effect %f", serialdevice->u.simhapticdata.effect1, serialdevice->motorsposition, rplay);
slogt("Updating arduino haptic device with effect type %i speed motor speed %i on motor %i from original effect %f with ampfactor %f", this->hapticeffect.effecttype, serialdevice->u.simhapticdata.effect3, serialdevice->motorsposition, rplay, serialdevice->ampfactor);
}
if (motor == 2 || motor == 6 || motor == 8 || motor == 9 || motor == 10 || motor == 11 || motor == 12 || motor == 14)
{
serialdevice->u.simhapticdata.effect3 = effectspeed;
serialdevice->u.simhapticdata.motor3 = 1;
slogt("Updating arduino haptic device speed motor speed %i on motor %i from original effect %f", serialdevice->u.simhapticdata.effect3, serialdevice->motorsposition, rplay);
slogt("Updating arduino haptic device with effect type %i speed motor speed %i on motor %i from original effect %f with ampfactor %f", this->hapticeffect.effecttype, serialdevice->u.simhapticdata.effect3, serialdevice->motorsposition, rplay, serialdevice->ampfactor);
}
serialdevice->state = play;
}
@@ -95,7 +130,6 @@ int arduino_simhaptic_update(SimDevice* this, SimData* simdata)
size_t size = sizeof(SimHapticData);
arduino_update(serialdevice, &serialdevice->u.simhapticdata, size);
return result;
}
@@ -103,31 +137,89 @@ int serialdev_free(SimDevice* this)
{
SerialDevice* serialdevice = (void *) this->derived;
arduino_free(serialdevice);
switch (serialdevice->devicetype) {
case (ARDUINODEV__HAPTIC):
serialdevice->u.simhapticdata.effect1 = 0;
serialdevice->u.simhapticdata.motor1 = 1;
serialdevice->u.simhapticdata.effect2 = 0;
serialdevice->u.simhapticdata.motor2 = 1;
serialdevice->u.simhapticdata.effect3 = 0;
serialdevice->u.simhapticdata.motor3 = 1;
serialdevice->u.simhapticdata.effect4 = 0;
serialdevice->u.simhapticdata.motor4 = 1;
serialdevice->state = 0;
size_t size = sizeof(SimHapticData);
monocoque_serial_write_block(serialdevice->id, &serialdevice->u.simhapticdata, size, 9000);
slogi("set zero to arduino device");
break;
case ARDUINODEV__SIMLED__CUSTOM:
arduino_customled_free(serialdevice, true);
break;
case ARDUINODEV__SIMLED:
arduino_customled_free(serialdevice, false);
break;
}
monocoque_serial_free(serialdevice);
free(serialdevice);
return 0;
}
int serialdev_init(SerialDevice* serialdevice, const char* portdev, int motorsposition)
int serial_wheel_free(SimDevice* this)
{
slogi("initializing serial device...");
SerialDevice* serialdevice = (void *) this->derived;
monocoque_serial_free(serialdevice);
free(serialdevice);
return 0;
}
int serialdev_init(SerialDevice* serialdevice, DeviceSettings* ds)
{
slogi("initializing serial device on port %s to %i...", ds->serialdevsettings.portdev, ds->serialdevsettings.baud);
int error = 0;
serialdevice->type = SERIALDEV_UNKNOWN;
serialdevice->type = SERIALDEV_ARDUINO;
serialdevice->motorsposition = motorsposition;
serialdevice->motorsposition = ds->serialdevsettings.motorsposition;
serialdevice->baudrate = ds->serialdevsettings.baud;
switch (serialdevice->devicetype)
{
case SERIALDEV__MOZAR5:
// the wheel stuff assumed it was a usb
//error = wheeldev_init(&serialdevice->u.wheeldevice, ds);
// maybe this call a more generic serial wheel init first
error = moza_init(serialdevice, ds->serialdevsettings.portdev);
break;
case ARDUINODEV__SIMLED__CUSTOM:
error = arduino_customled_init(serialdevice, ds->serialdevsettings.portdev, ds->serialdevsettings.config_file);
break;
case ARDUINODEV__SIMLED:
error = arduino_customled_init(serialdevice, ds->serialdevsettings.portdev, NULL);
break;
default:
error = arduino_init(serialdevice, ds->serialdevsettings.portdev);
break;
}
error = arduino_init(serialdevice, portdev);
return error;
}
static const vtable serial_simdevice_vtable = { &serialdev_update, &serialdev_free };
static const vtable arduino_shiftlights_vtable = { &arduino_shiftlights_update, &serialdev_free };
static const vtable arduino_simled_vtable = { &arduino_simled_update, &serialdev_free };
static const vtable arduino_simled_custom_vtable = { &arduino_customled_update, &serialdev_free };
static const vtable arduino_simwind_vtable = { &arduino_simwind_update, &serialdev_free };
static const vtable arduino_simhaptic_vtable = { &arduino_simhaptic_update, &serialdev_free };
static const vtable serialwheel_vtable = { &serial_wheel_update, &serial_wheel_free };
SerialDevice* new_serial_device(DeviceSettings* ds, MonocoqueSettings* ms) {
@@ -137,14 +229,36 @@ SerialDevice* new_serial_device(DeviceSettings* ds, MonocoqueSettings* ms) {
this->m.free = &simdevfree;
this->m.derived = this;
this->m.vtable = &serial_simdevice_vtable;
this->type = SERIALDEV_ARDUINO;
slogt("Attempting to configure arduino device with subtype: %i", ds->dev_subtype);
switch (ds->dev_subtype) {
case (SIMDEVTYPE_SHIFTLIGHTS):
this->devicetype = ARDUINODEV__SHIFTLIGHTS;
this->numlights = ds->serialdevsettings.numlights;
this->m.vtable = &arduino_shiftlights_vtable;
slogi("Initializing arduino device for shiftlights.");
break;
case (SIMDEVTYPE_SIMLED):
if(ds->has_config == true)
{
this->devicetype = ARDUINODEV__SIMLED__CUSTOM;
this->startled = ds->serialdevsettings.startled;
this->endled = ds->serialdevsettings.endled;
this->m.vtable = &arduino_simled_custom_vtable;
slogi("Initializing arduino device for custom simled.");
}
else
{
this->devicetype = ARDUINODEV__SIMLED;
this->numleds = ds->serialdevsettings.numleds;
this->startled = ds->serialdevsettings.startled;
this->endled = ds->serialdevsettings.endled;
this->m.vtable = &arduino_simled_vtable;
slogi("Initializing arduino device for simled.");
}
break;
case (SIMDEVTYPE_SIMWIND):
this->devicetype = ARDUINODEV__SIMWIND;
this->m.vtable = &arduino_simwind_vtable;
@@ -165,6 +279,20 @@ SerialDevice* new_serial_device(DeviceSettings* ds, MonocoqueSettings* ms) {
this->ampfactor = ds->serialdevsettings.ampfactor;
slogi("Initializing arduino device for haptic effects.");
break;
case (SIMDEVTYPE_SERIALWHEEL):
this->type = SERIALDEV_WHEEL;
slogi("Initializing serial wheel device.");
switch (ds->dev_subsubtype) {
case SIMDEVSUBTYPE_MOZAR5:
default:
//move this stuff to wheeldevice or it's own serial wheel device module
this->devicetype = SERIALDEV__MOZAR5;
this->m.vtable = &serialwheel_vtable;
break;
}
}
if(this->devicetype == ARDUINODEV__HAPTIC)
@@ -178,9 +306,9 @@ SerialDevice* new_serial_device(DeviceSettings* ds, MonocoqueSettings* ms) {
this->m.hapticeffect.tyrediameterconfig = ms->tyre_diameter_config;
}
int error = serialdev_init(this, ds->serialdevsettings.portdev, ds->serialdevsettings.motorsposition);
int error = serialdev_init(this, ds);
if (error != 0)
if (error < 0)
{
free(this);
return NULL;
+4
View File
@@ -2,12 +2,16 @@
#define _SERIALDEVICE_H
#include <libserialport.h>
#include "wheeldevice.h"
typedef enum
{
ARDUINODEV__SHIFTLIGHTS = 0,
ARDUINODEV__SIMWIND = 1,
ARDUINODEV__HAPTIC = 2,
SERIALDEV__MOZAR5 = 3,
ARDUINODEV__SIMLED = 4,
ARDUINODEV__SIMLED__CUSTOM = 5
}
SerialDeviceType;
+3
View File
@@ -40,6 +40,7 @@ int devinit(SimDevice* simdevices, int numdevices, DeviceSettings* ds, Monocoque
simdevices[j] = sim->m;
simdevices[j].initialized = true;
simdevices[j].type = SIMDEV_USB;
simdevices[j].fps = ds[j].fps;
devices++;
}
else
@@ -57,6 +58,7 @@ int devinit(SimDevice* simdevices, int numdevices, DeviceSettings* ds, Monocoque
simdevices[j] = sim->m;
simdevices[j].initialized = true;
simdevices[j].type = SIMDEV_SOUND;
simdevices[j].fps = ds[j].fps;
devices++;
}
else
@@ -73,6 +75,7 @@ int devinit(SimDevice* simdevices, int numdevices, DeviceSettings* ds, Monocoque
simdevices[j] = sim->m;
simdevices[j].initialized = true;
simdevices[j].type = SIMDEV_SERIAL;
simdevices[j].fps = ds[j].fps;
devices++;
}
+16 -3
View File
@@ -3,6 +3,8 @@
#include <stdbool.h>
#include "lua5.4/lua.h"
#include "usbdevice.h"
#include "sounddevice.h"
#include "serialdevice.h"
@@ -23,6 +25,7 @@ struct SimDevice
int (*free)(SimDevice*);
void* derived;
int id;
int fps;
bool initialized;
DeviceType type;
HapticEffect hapticeffect;
@@ -37,7 +40,8 @@ typedef struct {
typedef enum
{
SERIALDEV_UNKNOWN = 0,
SERIALDEV_ARDUINO = 1
SERIALDEV_ARDUINO = 1,
SERIALDEV_WHEEL = 2,
}
SerialType;
@@ -47,9 +51,15 @@ typedef struct
int id;
SerialType type;
struct sp_port* port;
lua_State* L;
SerialDeviceType devicetype;
// move these two they only apply to the haptic device
int motorsposition;
int numlights;
int numleds;
int startled;
int endled;
int baudrate;
double ampfactor;
double state;
union
@@ -57,6 +67,7 @@ typedef struct
SimWindData simwinddata;
SimHapticData simhapticdata;
ShiftLightsData shiftlightsdata;
WheelDevice wheeldevice;
} u;
}
SerialDevice;
@@ -73,7 +84,8 @@ typedef enum
{
USBDEV_UNKNOWN = 0,
USBDEV_TACHOMETER = 1,
USBDEV_GENERICHAPTIC = 2
USBDEV_GENERICHAPTIC = 2,
USBDEV_WHEEL = 3
}
USBType;
@@ -85,6 +97,7 @@ typedef struct
union
{
TachDevice tachdevice;
WheelDevice wheeldevice;
USBGenericHapticDevice hapticdevice;
} u;
}
@@ -101,8 +114,8 @@ typedef struct
{
SimDevice m;
int id;
SoundType type;
int configcheck;
SoundEffectModulationType modulationType;
SoundData sounddata;
#ifdef USE_PULSEAUDIO
pa_stream *stream;
+4 -4
View File
@@ -50,23 +50,23 @@ int setupsound()
int freesound()
{
if (mainloop) {
pa_threaded_mainloop_lock(mainloop);
}
if (context)
pa_context_unref(context);
if (mainloop) {
pa_signal_done();
pa_threaded_mainloop_unlock(mainloop);
pa_threaded_mainloop_free(mainloop);
}
}
#else
int setupsound()
{
slogi("connecting portaudio...");
}
@@ -4,10 +4,11 @@
#include "../simdevice.h"
#ifdef USE_PULSEAUDIO
int usb_generic_shaker_init(SoundDevice* sounddevice, pa_threaded_mainloop* mainloop, pa_context* context, const char* devname, int volume, int pan, const char* streamname);
int usb_generic_shaker_init(SoundDevice* sounddevice, pa_threaded_mainloop* mainloop, pa_context* context, const char* devname, int volume, int pan, int channels, const char* streamname);
int usb_generic_shaker_free(SoundDevice* sounddevice, pa_threaded_mainloop* mainloop);
#else
int usb_generic_shaker_init(SoundDevice* sounddevice);
#endif
int usb_generic_shaker_free(SoundDevice* sounddevice);
#endif
#endif
@@ -11,15 +11,14 @@
#include "../sounddevice.h"
#define FORMAT PA_SAMPLE_S16LE
#define SAMPLE_RATE (48000)
#define SAMPLE_RATE (44100)
#define AMPLITUDE .5
#define DURATION 4.0
#define DURATION 1.0
#ifndef M_PI
#define M_PI (3.14159265)
#endif
void gear_sound_stream(pa_stream *s, size_t length, void *userdata) {
SoundData* data = (SoundData*)userdata;
@@ -47,27 +46,46 @@ void gear_sound_stream(pa_stream *s, size_t length, void *userdata) {
pa_stream_write(s, buffer, length, NULL, 0LL, PA_SEEK_RELATIVE);
}
double get_closest_frequency(size_t num_samples, double input_frequency) {
double samples_per_cycle = SAMPLE_RATE / input_frequency;
double adjusted_frequency = SAMPLE_RATE / (num_samples / floor(num_samples/samples_per_cycle) );
return adjusted_frequency;
}
void engine_sound_stream(pa_stream *s, size_t length, void *userdata) {
SoundData* data = (SoundData*)userdata;
double freq = data->curr_frequency;
size_t num_samples = length / sizeof(int16_t);
freq = get_closest_frequency( num_samples, freq );
//size_t num_samples = (size_t) (DURATION * SAMPLE_RATE);
int16_t buffer[num_samples];
//double t = 0;
for (size_t i = 0; i < num_samples; i++) {
static double t = 0.0;
double sample = AMPLITUDE * 32767.0 * sin(2.0 * M_PI * data->curr_frequency * t);
double t = data->phase;
double sample = AMPLITUDE * 32767.0 * sin( 2.0 * M_PI * freq * t );
buffer[i] = (int16_t)sample;
t += 1.0 / SAMPLE_RATE;
if (t >= DURATION) {
t = 0.0;
if (t >= SAMPLE_RATE) {
t = 0;
}
data->phase = t;
}
data->phase = round(data->phase);
pa_stream_write(s, buffer, length, NULL, 0LL, PA_SEEK_RELATIVE);
}
void stream_success_cb(pa_stream *stream, int success, void *userdata) {
return;
}
@@ -76,42 +94,58 @@ void stream_state_cb(pa_stream *s, void *mainloop) {
pa_threaded_mainloop_signal(mainloop, 0);
}
int usb_generic_shaker_free(SoundDevice* sounddevice)
int usb_generic_shaker_free(SoundDevice* sounddevice, pa_threaded_mainloop* mainloop)
{
pa_threaded_mainloop_lock(mainloop);
int err = 0;
//err = Pa_CloseStream( sounddevice->stream );
//if( err != paNoError )
//{
// err = Pa_Terminate();
//}
if (sounddevice->stream)
{
pa_stream_disconnect(sounddevice->stream);
pa_stream_unref(sounddevice->stream);
pa_xfree(sounddevice->stream);
// why is this wrong
//pa_xfree(sounddevice->stream);
}
pa_threaded_mainloop_unlock(mainloop);
return err;
}
int usb_generic_shaker_init(SoundDevice* sounddevice, pa_threaded_mainloop* mainloop, pa_context* context, const char* devname, int volume, int pan, const char* streamname)
int usb_generic_shaker_init(SoundDevice* sounddevice, pa_threaded_mainloop* mainloop, pa_context* context, const char* devname, int volume, int pan, int channels, const char* streamname)
{
pa_threaded_mainloop_lock(mainloop);
pa_stream *stream;
// Create a playback stream
pa_sample_spec sample_specifications;
sample_specifications.format = FORMAT;
sample_specifications.rate = SAMPLE_RATE;
sample_specifications.channels = 2;
sample_specifications.channels = channels;
pa_channel_map channel_map;
pa_channel_map_init_stereo(&channel_map);
pa_channel_map_parse(&channel_map, "front-left,front-right");
pa_channel_map_init_auto(&channel_map, channels, PA_CHANNEL_MAP_DEFAULT);
//pa_channel_map_init_stereo(&channel_map);
// not sure about what to do here
if(channels == 2)
{
pa_channel_map_parse(&channel_map, "front-left,front-right");
}
if(channels == 4)
{
pa_channel_map_parse(&channel_map, "front-left,front-right,rear-left,rear-right");
}
if(channels == 6)
{
pa_channel_map_parse(&channel_map, "front-left,front-right,front-center,lfe,rear-left,rear-right");
}
if(channels == 8)
{
pa_channel_map_parse(&channel_map, "front-left,front-right,front-center,lfe,rear-left,rear-right,side-left,side-right");
}
stream = pa_stream_new(context, streamname, &sample_specifications, &channel_map);
pa_stream_set_state_callback(stream, stream_state_cb, mainloop);
if (sounddevice->m.hapticeffect.effecttype == EFFECT_GEARSHIFT)
{
pa_stream_set_write_callback(stream, gear_sound_stream, &sounddevice->sounddata);
@@ -129,16 +163,16 @@ int usb_generic_shaker_init(SoundDevice* sounddevice, pa_threaded_mainloop* main
buffer_attr.minreq = (uint32_t) -1;
pa_cvolume cv;
uint16_t pvolume = ceil(((double) volume/100.0d)*65535);
// Settings copied as per the chromium browser source
pa_cvolume_mute(&cv, channels);
pa_volume_t channel_volume = PA_CLAMP_VOLUME((pa_volume_t)((volume/100.d)*PA_VOLUME_NORM));
pa_stream_flags_t stream_flags;
stream_flags = PA_STREAM_INTERPOLATE_TIMING | PA_STREAM_NOT_MONOTONIC | PA_STREAM_AUTO_TIMING_UPDATE | PA_STREAM_ADJUST_LATENCY | PA_STREAM_START_CORKED;
// Connect stream to the default audio output sink
pa_cvolume_set(&cv, sample_specifications.channels, pvolume);
pa_cvolume_set_balance(&cv, &channel_map, pan);
// for now i'm only supporting playing on one specified channel which is the concept you should build your setups around
cv.values[pan] = channel_volume;
assert(pa_stream_connect_playback(stream, devname, &buffer_attr, stream_flags, &cv, NULL) == 0);
@@ -146,17 +180,17 @@ int usb_generic_shaker_init(SoundDevice* sounddevice, pa_threaded_mainloop* main
for(;;) {
pa_stream_state_t stream_state = pa_stream_get_state(stream);
assert(PA_STREAM_IS_GOOD(stream_state));
if (stream_state == PA_STREAM_READY) break;
if (stream_state == PA_STREAM_READY) break;
pa_threaded_mainloop_wait(mainloop);
}
//pa_threaded_mainloop_unlock(mainloop);
// Uncork the stream so it will start playing
pa_stream_cork(stream, 0, stream_success_cb, mainloop);
sounddevice->stream = stream;
pa_threaded_mainloop_unlock(mainloop);
return 0;
}
+87 -37
View File
@@ -38,15 +38,34 @@ int sounddev_engine_update(SimDevice* this, SimData* simdata)
slogt("set engine frequency to %i", sounddevice->sounddata.frequency);
}
double modulate(SoundDevice* sounddevice, double raw_effect, SoundEffectModulationType modulation)
{
double modulated_effect = raw_effect;
switch (modulation)
{
case SOUND_EFFECT_MODULATION_FREQUENCY:
modulated_effect = (sounddevice->sounddata.frequencyMax - sounddevice->sounddata.frequency) * raw_effect;
break;
case SOUND_EFFECT_MODULATION_AMPLIFY:
case SOUND_EFFECT_MODULATION_NONE:
default:
modulated_effect = raw_effect;
}
return modulated_effect;
}
int sounddev_tyreslip_update(SimDevice* this, SimData* simdata)
{
SoundDevice* sounddevice = (void *) this->derived;
int play = slipeffect(simdata, this->hapticeffect.effecttype, this->hapticeffect.tyre, this->hapticeffect.threshold, this->hapticeffect.useconfig, this->hapticeffect.configcheck, this->hapticeffect.tyrediameterconfig);
double effect = slipeffect(simdata, this->hapticeffect.effecttype, this->hapticeffect.tyre, this->hapticeffect.threshold, this->hapticeffect.useconfig, this->hapticeffect.configcheck, this->hapticeffect.tyrediameterconfig);
slogt("Updating sound device frequency from original tyre slip effect %f", effect);
if (play > 0)
if (effect > 0)
{
sounddevice->sounddata.curr_frequency = sounddevice->sounddata.frequency * play;
effect = modulate(sounddevice, effect, sounddevice->modulationType);
sounddevice->sounddata.curr_frequency = sounddevice->sounddata.frequency;
sounddevice->sounddata.curr_duration = sounddevice->sounddata.duration;
}
else
@@ -54,17 +73,19 @@ int sounddev_tyreslip_update(SimDevice* this, SimData* simdata)
sounddevice->sounddata.curr_frequency = 0;
sounddevice->sounddata.curr_duration = 0;
}
}
int sounddev_tyrelock_update(SimDevice* this, SimData* simdata)
{
SoundDevice* sounddevice = (void *) this->derived;
int play = slipeffect(simdata, this->hapticeffect.effecttype, this->hapticeffect.tyre, this->hapticeffect.threshold, this->hapticeffect.useconfig, this->hapticeffect.configcheck, this->hapticeffect.tyrediameterconfig);
double play = slipeffect(simdata, this->hapticeffect.effecttype, this->hapticeffect.tyre, this->hapticeffect.threshold, this->hapticeffect.useconfig, this->hapticeffect.configcheck, this->hapticeffect.tyrediameterconfig);
slogt("Updating sound device frequency from original tyre lock effect %f", play);
if (play > 0)
{
sounddevice->sounddata.curr_frequency = sounddevice->sounddata.frequency * play;
sounddevice->sounddata.curr_frequency = sounddevice->sounddata.frequency;
sounddevice->sounddata.curr_duration = sounddevice->sounddata.duration;
}
else
@@ -77,8 +98,10 @@ int sounddev_tyrelock_update(SimDevice* this, SimData* simdata)
int sounddev_absbrakes_update(SimDevice* this, SimData* simdata)
{
SoundDevice* sounddevice = (void *) this->derived;
double play = slipeffect(simdata, this->hapticeffect.effecttype, this->hapticeffect.tyre, this->hapticeffect.threshold, this->hapticeffect.useconfig, this->hapticeffect.configcheck, this->hapticeffect.tyrediameterconfig);
slogt("Updating sound device frequency from original abs effect %f", play);
if (simdata->abs > 0)
if (play > 0)
{
sounddevice->sounddata.curr_frequency = sounddevice->sounddata.frequency;
sounddevice->sounddata.curr_duration = sounddevice->sounddata.duration;
@@ -97,75 +120,78 @@ int sounddev_gearshift_update(SimDevice* this, SimData* simdata)
gear_sound_set(sounddevice, simdata);
}
#ifdef USE_PULSEAUDIO
int sounddev_free(SimDevice* this)
{
SoundDevice* sounddevice = (void *) this->derived;
//figure out why this is causing problems
//usb_generic_shaker_free(sounddevice);
usb_generic_shaker_free(sounddevice, mainloop);
free(sounddevice);
return 0;
}
int sounddev_init(SoundDevice* sounddevice, const char* devname, int volume, int frequency, int pan, double duration, double threshold)
#else
int sounddev_free(SimDevice* this)
{
SoundDevice* sounddevice = (void *) this->derived;
usb_generic_shaker_free(sounddevice);
free(sounddevice);
return 0;
}
#endif
int sounddev_init(SoundDevice* sounddevice, const char* devname, MonocoqueTyreIdentifier tyre, SoundDeviceSettings sds)
{
slogi("initializing standalone sound device...");
slogi("volume is: %i", volume);
slogi("frequency is: %i", frequency);
slogi("pan is: %i", pan);
slogi("duration is: %f", duration);
slogi("volume is: %i", sds.volume);
slogi("frequency is: %i", sds.frequency);
slogi("frequency Max is: %i", sds.frequencyMax);
slogi("pan is: %i", sds.pan);
slogi("channels is: %i", sds.channels);
slogi("duration is: %f", sds.duration);
sounddevice->sounddata.frequency = frequency;
//sounddevice->sounddata.pitch = 1;
//sounddevice->sounddata.pitch = 261.626;
//sounddevice->sounddata.amp = 32;
//sounddevice->sounddata.left_phase = sounddevice->sounddata.right_phase = 0;
//sounddevice->sounddata.table_size = 48000/(100/60);
sounddevice->sounddata.curr_frequency = 100/60;
sounddevice->modulationType = sds.modulation;
sounddevice->sounddata.frequency = sds.frequency;
sounddevice->sounddata.curr_frequency = 0;
sounddevice->sounddata.curr_duration = 0;
sounddevice->sounddata.phase = 0;
const char* streamname= "Engine";
switch (sounddevice->m.hapticeffect.effecttype) {
case (EFFECT_GEARSHIFT):
sounddevice->sounddata.last_gear = 0;
//sounddevice->sounddata.pitch = 500;
//sounddevice->sounddata.amp = 128;
//sounddevice->sounddata.left_phase = sounddevice->sounddata.right_phase = 0;
//sounddevice->sounddata.table_size = 48000/(1);
sounddevice->sounddata.duration = duration;
sounddevice->sounddata.curr_duration = duration;
sounddevice->sounddata.duration = sds.duration;
streamname = "Gear";
break;
case (EFFECT_TYRESLIP):
sounddevice->sounddata.duration = duration;
sounddevice->sounddata.curr_duration = duration;
streamname = "TyreSlip";
break;
case (EFFECT_TYRELOCK):
sounddevice->sounddata.duration = duration;
sounddevice->sounddata.curr_duration = duration;
streamname = "TyreLock";
break;
case (EFFECT_ABSBRAKES):
sounddevice->sounddata.duration = duration;
sounddevice->sounddata.curr_duration = duration;
streamname = "ABS";
break;
}
#ifdef USE_PULSEAUDIO
//pa_threaded_mainloop* mainloop;
//pa_context* context;
usb_generic_shaker_init(sounddevice, mainloop, context, devname, volume, pan, streamname);
usb_generic_shaker_init(sounddevice, mainloop, context, devname, sds.volume, sds.pan, sds.channels, streamname);
#else
usb_generic_shaker_init(sounddevice);
#endif
@@ -200,26 +226,50 @@ SoundDevice* new_sound_device(DeviceSettings* ds, MonocoqueSettings* ms) {
case (EFFECT_TYRESLIP):
this->m.hapticeffect.effecttype = EFFECT_TYRESLIP;
this->m.hapticeffect.threshold = ds->threshold;
this->m.hapticeffect.threshold = ds->threshold;
slogt("Haptic effect: %i %i", this->m.hapticeffect.effecttype, ds->effect_type);
this->m.hapticeffect.tyre = ds->tyre;
this->m.hapticeffect.useconfig = ms->useconfig;
this->m.hapticeffect.configcheck = &ms->configcheck;
this->m.hapticeffect.tyrediameterconfig = ms->tyre_diameter_config;
this->m.vtable = &tyreslip_sound_simdevice_vtable;
slogi("Initializing sound device for tyre slip vibrations.");
break;
case (EFFECT_TYRELOCK):
this->m.hapticeffect.effecttype = EFFECT_TYRELOCK;
this->m.hapticeffect.threshold = ds->threshold;
this->m.hapticeffect.threshold = ds->threshold;
slogt("Haptic effect: %i %i", this->m.hapticeffect.effecttype, ds->effect_type);
this->m.hapticeffect.tyre = ds->tyre;
this->m.hapticeffect.useconfig = ms->useconfig;
this->m.hapticeffect.configcheck = &ms->configcheck;
this->m.hapticeffect.tyrediameterconfig = ms->tyre_diameter_config;
this->m.vtable = &tyrelock_sound_simdevice_vtable;
slogi("Initializing sound device for tyre slip vibrations.");
break;
case (EFFECT_ABSBRAKES):
this->m.hapticeffect.effecttype = EFFECT_ABSBRAKES;
this->m.hapticeffect.threshold = ds->threshold;
this->m.hapticeffect.threshold = ds->threshold;
slogt("Haptic effect: %i %i", this->m.hapticeffect.effecttype, ds->effect_type);
this->m.hapticeffect.tyre = ds->tyre;
this->m.hapticeffect.useconfig = ms->useconfig;
this->m.hapticeffect.configcheck = &ms->configcheck;
this->m.hapticeffect.tyrediameterconfig = ms->tyre_diameter_config;
this->m.vtable = &absbrakes_sound_simdevice_vtable;
slogi("Initializing sound device for abs vibrations.");
break;
}
slogt("Attempting to use device %s", ds->sounddevsettings.dev);
slogt("Attempting to use sound device %s", ds->sounddevsettings.dev);
int error = sounddev_init(this, ds->sounddevsettings.dev, ds->sounddevsettings.volume, ds->sounddevsettings.frequency, ds->sounddevsettings.pan, ds->sounddevsettings.duration, ds->threshold);
int error = sounddev_init(this, ds->sounddevsettings.dev, ds->tyre, ds->sounddevsettings);
if (error != 0)
{
free(this);
+8 -4
View File
@@ -7,22 +7,26 @@
#include "portaudio.h"
#endif
typedef enum
{
SOUNDDEV_UNKNOWN = 0,
SOUNDDEV_SHAKER = 1
SOUND_EFFECT_MODULATION_NONE = 0,
SOUND_EFFECT_MODULATION_FREQUENCY = 1,
SOUND_EFFECT_MODULATION_AMPLIFY = 2,
}
SoundType;
SoundEffectModulationType;
#define MAX_TABLE_SIZE (6000)
typedef struct
{
int last_gear;
int volume;
int frequency;
uint32_t frequency;
uint32_t frequencyMax;
double duration;
int curr_frequency;
double curr_duration;
double phase;
}
SoundData;
+7 -7
View File
@@ -8,7 +8,7 @@
#include "../../helper/confighelper.h"
#include "../slog/slog.h"
const char* SYSFSRUMBLEPATH = "/sys/module/hid_fanatec/drivers/hid:ftec_csl_elite/0003:0EB7:183B.*/rumble";
const char* SYSFSRUMBLEPATH = "/sys/module/hid_fanatec/drivers/hid:f*/0003:0EB7:183B.*/rumble";
int cslelitev3_update(USBGenericHapticDevice* usbhapticdevice, int effecttype, int play)
@@ -34,8 +34,8 @@ int cslelitev3_update(USBGenericHapticDevice* usbhapticdevice, int effecttype, i
}
fprintf(usbhapticdevice->handle, "%i\n", value);
fflush(usbhapticdevice->handle);
fprintf(usbhapticdevice->filehandle, "%i\n", value);
fflush(usbhapticdevice->filehandle);
return res;
}
@@ -46,8 +46,8 @@ int cslelitev3_free(USBGenericHapticDevice* usbhapticdevice)
free(usbhapticdevice->dev);
fflush(usbhapticdevice->handle);
fclose(usbhapticdevice->handle);
fflush(usbhapticdevice->filehandle);
fclose(usbhapticdevice->filehandle);
return res;
}
@@ -91,9 +91,9 @@ int cslelitev3_init(USBGenericHapticDevice* usbhapticdevice)
return res;
}
usbhapticdevice->handle = fopen(usbhapticdevice->dev, "w");
usbhapticdevice->filehandle = fopen(usbhapticdevice->dev, "w");
if (!usbhapticdevice->handle)
if (!usbhapticdevice->filehandle)
{
sloge("Could not open pedal device...");
return res;
+4 -4
View File
@@ -5,7 +5,7 @@
#include "tachdevice.h"
#include "../slog/slog.h"
const int buf_size = 65;
const size_t REVBURNER_BUFSIZE = 8;
int revburner_update(TachDevice* tachdevice, int pulses)
@@ -13,8 +13,8 @@ int revburner_update(TachDevice* tachdevice, int pulses)
int res = 0;
unsigned char bytes[buf_size];
for (int x = 0; x < buf_size; x++)
unsigned char bytes[REVBURNER_BUFSIZE];
for (int x = 0; x < REVBURNER_BUFSIZE; x++)
{
bytes[x] = 0x00;
}
@@ -27,7 +27,7 @@ int revburner_update(TachDevice* tachdevice, int pulses)
if (tachdevice->handle)
{
res = hid_write(tachdevice->handle, bytes, buf_size);
res = hid_write(tachdevice->handle, bytes, REVBURNER_BUFSIZE);
}
else
{
+133
View File
@@ -0,0 +1,133 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <hidapi/hidapi.h>
#include "usbhapticdevice.h"
#include "../../helper/confighelper.h"
#include "../slog/slog.h"
#define SIMAGIC_VENDOR_ID 0x0483
#define SIMAGIC_PRODUCT_ID_P1000 0x0525
const size_t SIMAGIC_P1000_BUFSIZE = 49;
const char* SIMAGICP1000DEVSTRING = "SIMAGIC P1000 Pedals";
int senddevreport(USBGenericHapticDevice* usbhapticdevice, unsigned char* buf, size_t bufsize)
{
int res = 0;
if (usbhapticdevice->handle)
{
res = hid_write(usbhapticdevice->handle, buf, SIMAGIC_P1000_BUFSIZE);
slogd("sent %i bytes to %s", bufsize, SIMAGICP1000DEVSTRING);
slogt("sent bytes %02x %02x %02x %02x %02x %02x %02x", buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]);
}
else
{
slogd("no handle");
}
return res;
}
int simagicp1000_update(USBGenericHapticDevice* usbhapticdevice, int effecttype, int play)
{
int res = 0;
int value = 0;
unsigned char bytes[SIMAGIC_P1000_BUFSIZE];
for (int x = 0; x < SIMAGIC_P1000_BUFSIZE; x++)
{
bytes[x] = 0x00;
}
if (play > 0)
{
bytes[0] = 0xEC;
// we can add config settings for these values
bytes[2] = 0x01;
bytes[3] = 0x0A;
bytes[4] = 0xFF;
switch (effecttype)
{
case (EFFECT_TYRESLIP):
bytes[1] = 0x02;
senddevreport(usbhapticdevice, bytes, SIMAGIC_P1000_BUFSIZE);
break;
case (EFFECT_TYRELOCK):
bytes[1] = 0x01;
senddevreport(usbhapticdevice, bytes, SIMAGIC_P1000_BUFSIZE);
break;
case (EFFECT_ABSBRAKES):
bytes[1] = 0x02;
senddevreport(usbhapticdevice, bytes, SIMAGIC_P1000_BUFSIZE);
bytes[1] = 0x01;
senddevreport(usbhapticdevice, bytes, SIMAGIC_P1000_BUFSIZE);
break;
}
}
else
{
bytes[1] = 0x01;
senddevreport(usbhapticdevice, bytes, SIMAGIC_P1000_BUFSIZE);
bytes[1] = 0x02;
senddevreport(usbhapticdevice, bytes, SIMAGIC_P1000_BUFSIZE);
}
return res;
}
int simagicp1000_free(USBGenericHapticDevice* usbhapticdevice)
{
int res = 0;
hid_close(usbhapticdevice->handle);
res = hid_exit();
return res;
return res;
}
int simagicp1000_init(USBGenericHapticDevice* usbhapticdevice)
{
slogi("initializing %s...", SIMAGICP1000DEVSTRING);
int res = 0;
res = hid_init();
usbhapticdevice->handle = hid_open(SIMAGIC_VENDOR_ID, SIMAGIC_PRODUCT_ID_P1000, NULL);
if (!usbhapticdevice->handle)
{
sloge("Could not find attached %s", SIMAGICP1000DEVSTRING);
res = hid_exit();
return 1;
}
else
{
unsigned char bytes[SIMAGIC_P1000_BUFSIZE];
for (int x = 0; x < SIMAGIC_P1000_BUFSIZE; x++)
{
bytes[x] = 0x00;
}
bytes[0] = 0xF1;
bytes[1] = 0x17;
bytes[2] = 0x00;
bytes[3] = 0x00;
bytes[4] = 0x00;
bytes[5] = 0x01;
bytes[6] = 0x02;
res = senddevreport(usbhapticdevice, bytes, SIMAGIC_P1000_BUFSIZE);
slogd("Initialization returned %i", res);
if(res != 0)
{
slogw("Problem with initialization of %s", SIMAGICP1000DEVSTRING);
}
}
slogd("Found %s...", SIMAGICP1000DEVSTRING);
return res;
}
+8
View File
@@ -0,0 +1,8 @@
#ifndef _SIMAGICP1000_H
#define _SIMAGICP1000_H
int simagicp1000_update(USBGenericHapticDevice* usbhapticdevice, int effecttype, int play);
int simagicp1000_init(USBGenericHapticDevice* usbhapticdevice);
int simagicp1000_free(USBGenericHapticDevice* usbhapticdevice);
#endif
@@ -0,0 +1,86 @@
#include <stdio.h>
#include <math.h>
#include <hidapi/hidapi.h>
#include "cammusc12.h"
#include "../../../slog/slog.h"
const int cammusc12_hidupdate_buf_size = 16;
int cammusc12_update(WheelDevice* wheeldevice, int maxrpm, int rpm, int gear, int velocity)
{
int res = 0;
unsigned char bytes[cammusc12_hidupdate_buf_size];
for (int x = 0; x < cammusc12_hidupdate_buf_size; x++)
{
bytes[x] = 0x00;
}
// byte 1 must be fc it seems
bytes[0] = 0xFA;
bytes[1] = 0xFB;
bytes[2] = 0xD4;
int perct = 0;
if(rpm > 0 && maxrpm > 0)
{
double rpmperct = (double) rpm / (double) maxrpm;
perct = trunc(nearbyint( rpmperct * 100 ));
}
bytes[3] = perct;
// bytes 2 and 3 are a 16 bit velocity
if ( velocity > 0 )
{
bytes[5] = (velocity >> 8) & 0xFF;
bytes[4] = velocity & 0xFF;
}
// byte 4 is gear
bytes[6] = gear-1;
slogt("writing bytes x%02xx%02xx%02xx%02xx%02x%02x%02x from rpm %i velocity %i gear %i", bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6], rpm, velocity, gear);
if (wheeldevice->handle)
{
res = hid_write(wheeldevice->handle, bytes, cammusc12_hidupdate_buf_size);
}
else
{
slogd("no handle");
}
return res;
}
int cammusc12_free(WheelDevice* wheeldevice)
{
int res = 0;
hid_close(wheeldevice->handle);
res = hid_exit();
return res;
}
int cammusc12_init(WheelDevice* wheeldevice)
{
slogi("initializing cammus c12 wheel...");
int res = 0;
res = hid_init();
wheeldevice->handle = hid_open(0x3416, 0x1023, NULL);
if (!wheeldevice->handle)
{
sloge("Could not find attached Cammus C12 Wheel");
res = hid_exit();
return 1;
}
slogd("Found Cammus C12 Wheel...");
return res;
}
@@ -0,0 +1,10 @@
#ifndef _CAMMUSC12_H
#define _CAMMUSC12_H
#include "../../wheeldevice.h"
int cammusc12_update(WheelDevice* wheeldevice, int maxrpm, int rpm, int gear, int velocity);
int cammusc12_init(WheelDevice* wheeldevice);
int cammusc12_free(WheelDevice* wheeldevice);
#endif
@@ -0,0 +1,99 @@
#include <stdio.h>
#include <math.h>
#include <hidapi/hidapi.h>
#include "cammusc5.h"
#include "../../../slog/slog.h"
const int cammusc5_hidupdate_buf_size = 14;
const int num_avail_leds = 9;
int cammusc5_update(WheelDevice* wheeldevice, int maxrpm, int rpm, int gear, int velocity)
{
int res = 0;
unsigned char bytes[cammusc5_hidupdate_buf_size];
for (int x = 0; x < cammusc5_hidupdate_buf_size; x++)
{
bytes[x] = 0x00;
}
// byte 1 must be fc it seems
bytes[0] = 0xFC;
// byte 2 is number of lit leds, assuming 9 available leds,
// if we send 10, all leds will blink singling a gear change
// attempting to build in a margin before the maxrpm is achieved
int litleds = 0;
if(rpm > 0 && maxrpm > 0)
{
int rpmmargin = ceil(.05*maxrpm);
int rpminterval = (maxrpm-rpmmargin) / (num_avail_leds+1);
for (int l = 1; l <= (num_avail_leds+1); l++)
{
if(rpm >= (rpminterval * l))
{
litleds = l;
}
}
}
bytes[1] = litleds;
// bytes 2 and 3 are a 16 bit velocity
if ( velocity > 0 )
{
bytes[2] = (velocity >> 8) & 0xFF;
bytes[3] = velocity & 0xFF;
}
// byte 4 is gear
bytes[4] = gear-1;
slogt("writing bytes x%02xx%02xx%02xx%02xx%02x from rpm %i velocity %i gear %i", bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], rpm, velocity, gear);
if (wheeldevice->handle)
{
res = hid_write(wheeldevice->handle, bytes, cammusc5_hidupdate_buf_size);
}
else
{
slogd("no handle");
}
return res;
}
int cammusc5_free(WheelDevice* wheeldevice)
{
int res = 0;
hid_close(wheeldevice->handle);
res = hid_exit();
return res;
}
int cammusc5_init(WheelDevice* wheeldevice)
{
slogi("initializing cammus c5 wheel...");
int res = 0;
res = hid_init();
wheeldevice->handle = hid_open(0x3416, 0x1021, NULL);
if (!wheeldevice->handle)
{
sloge("Could not find attached Cammus C5 Wheel");
res = hid_exit();
return 1;
}
slogd("Found Cammus C5 Wheel...");
return res;
}
@@ -0,0 +1,10 @@
#ifndef _CAMMUSC5_H
#define _CAMMUSC5_H
#include "../../wheeldevice.h"
int cammusc5_update(WheelDevice* wheeldevice, int maxrpm, int rpm, int gear, int velocity);
int cammusc5_init(WheelDevice* wheeldevice);
int cammusc5_free(WheelDevice* wheeldevice);
#endif
+19 -1
View File
@@ -19,6 +19,9 @@ int usbdev_update(SimDevice* this, SimData* simdata)
case USBDEV_TACHOMETER :
tachdev_update(&usbdevice->u.tachdevice, simdata);
break;
case USBDEV_WHEEL :
wheeldev_update(&usbdevice->u.wheeldevice, simdata);
break;
case USBDEV_GENERICHAPTIC :
usbhapticdev_update(&usbdevice->u.hapticdevice, simdata, this->hapticeffect.tyre, this->hapticeffect.useconfig, this->hapticeffect.configcheck, this->hapticeffect.tyrediameterconfig);
break;
@@ -38,6 +41,9 @@ int usbdev_free(SimDevice* this)
case USBDEV_TACHOMETER :
tachdev_free(&usbdevice->u.tachdevice);
break;
case USBDEV_WHEEL :
wheeldev_free(&usbdevice->u.wheeldevice);
break;
case USBDEV_GENERICHAPTIC :
usbhapticdev_free(&usbdevice->u.hapticdevice);
break;
@@ -60,6 +66,9 @@ int usbdev_init(USBDevice* usbdevice, DeviceSettings* ds)
case USBDEV_TACHOMETER :
error = tachdev_init(&usbdevice->u.tachdevice, ds);
break;
case USBDEV_WHEEL :
error = wheeldev_init(&usbdevice->u.wheeldevice, ds);
break;
case USBDEV_GENERICHAPTIC :
error = usbhapticdev_init(&usbdevice->u.hapticdevice, ds);
break;
@@ -81,8 +90,17 @@ USBDevice* new_usb_device(DeviceSettings* ds, MonocoqueSettings* ms) {
// TODO: turn this into a switch when we get more devices
this->type = USBDEV_TACHOMETER;
if(ds->dev_subtype == SIMDEVTYPE_USBWHEEL)
{
this->type = USBDEV_WHEEL;
}
// really generic haptic isn't and shouldn't be it's own type
// it's an attribute that is added to a device via composition
// same if that haptic device is a serial device
if (ds->dev_subtype == SIMDEVTYPE_USBHAPTIC)
{
this->m.hapticeffect.threshold = ds->threshold;
+1
View File
@@ -2,6 +2,7 @@
#define _USBDEVICE_H
#include "tachdevice.h"
#include "wheeldevice.h"
#include "usbhapticdevice.h"
#endif
+42 -12
View File
@@ -6,6 +6,8 @@
#include "usbhapticdevice.h"
#include "hapticeffect.h"
#include "usb/cslelitev3.h"
#include "usb/simagicp1000.h"
#include "../../helper/confighelper.h"
#include "../../simulatorapi/simapi/simapi/simdata.h"
#include "../../slog/slog.h"
@@ -15,18 +17,34 @@ int usbhapticdev_update(USBGenericHapticDevice* usbhapticdevice, SimData* simdat
{
double play = slipeffect(simdata, usbhapticdevice->effecttype, tyre, usbhapticdevice->threshold, useconfig, configcheck, configfile);
if (play != usbhapticdevice->state)
{
int rplay = 0;
if(play > 0)
{
rplay = 1;
cslelitev3_update(usbhapticdevice, usbhapticdevice->effecttype, rplay);
switch ( usbhapticdevice->type )
{
case USBHAPTIC_CSLELITEV3PEDALS:
cslelitev3_update(usbhapticdevice, usbhapticdevice->effecttype, rplay);
break;
case USBHAPTIC_SIMAGICP1000PEDALS:
simagicp1000_update(usbhapticdevice, usbhapticdevice->effecttype, rplay);
break;
}
}
else
{
cslelitev3_update(usbhapticdevice, usbhapticdevice->effecttype, rplay);
switch ( usbhapticdevice->type )
{
case USBHAPTIC_CSLELITEV3PEDALS:
cslelitev3_update(usbhapticdevice, usbhapticdevice->effecttype, rplay);
break;
case USBHAPTIC_SIMAGICP1000PEDALS:
simagicp1000_update(usbhapticdevice, usbhapticdevice->effecttype, rplay);
break;
}
}
usbhapticdevice->state = play;
}
@@ -36,7 +54,16 @@ int usbhapticdev_update(USBGenericHapticDevice* usbhapticdevice, SimData* simdat
int usbhapticdev_free(USBGenericHapticDevice* usbhapticdevice)
{
slogt("closing usb haptic device");
cslelitev3_free(usbhapticdevice);
switch ( usbhapticdevice->type )
{
case USBHAPTIC_CSLELITEV3PEDALS:
cslelitev3_free(usbhapticdevice);
break;
case USBHAPTIC_SIMAGICP1000PEDALS:
simagicp1000_free(usbhapticdevice);
break;
}
return 0;
}
@@ -65,14 +92,17 @@ int usbhapticdev_init(USBGenericHapticDevice* usbhapticdevice, DeviceSettings* d
slogi("initializing standalone usb haptic device...");
// detection of usb device model
usbhapticdevice->type = HAPTIC_UNKNOWN;
usbhapticdevice->type = HAPTIC_CSLELITEV3;
error = cslelitev3_init(usbhapticdevice);
if(usbhapticdevice->handle == 0)
{
error = MONOCOQUE_ERROR_INVALID_DEV;
return error;
switch (ds->dev_subsubtype) {
case (SIMDEVSUBTYPE_SIMAGICP1000PEDALS):
usbhapticdevice->type = USBHAPTIC_SIMAGICP1000PEDALS;
error = simagicp1000_init(usbhapticdevice);
break;
case (SIMDEVSUBTYPE_CSLELITEV3PEDALS):
usbhapticdevice->type = USBHAPTIC_CSLELITEV3PEDALS;
error = cslelitev3_init(usbhapticdevice);
break;
default:
slogw("Possibly unknown device");
}
return error;
+5 -3
View File
@@ -8,8 +8,9 @@
typedef enum
{
HAPTIC_UNKNOWN = 0,
HAPTIC_CSLELITEV3 = 1
USBHAPTIC_UNKNOWN = 0,
USBHAPTIC_CSLELITEV3PEDALS = 1,
USBHAPTIC_SIMAGICP1000PEDALS = 2
}
HapticType;
@@ -22,7 +23,8 @@ typedef struct
int value0;
int value1;
VibrationEffectType effecttype;
FILE* handle;
FILE* filehandle;
hid_device* handle;
char* dev;
}
USBGenericHapticDevice;
+74
View File
@@ -0,0 +1,74 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "usb/wheels/cammusc5.h"
#include "usb/wheels/cammusc12.h"
#include "serial/moza.h"
#include "wheeldevice.h"
#include "../helper/confighelper.h"
#include "../simulatorapi/simapi/simapi/simdata.h"
#include "../slog/slog.h"
int wheeldev_update(WheelDevice* wheeldevice, SimData* simdata)
{
switch ( wheeldevice->type )
{
case WHEELDEV_UNKNOWN :
case WHEELDEV_CAMMUSC5 :
cammusc5_update(wheeldevice, simdata->maxrpm, simdata->rpms, simdata->gear, simdata->velocity);
break;
case WHEELDEV_CAMMUSC12 :
cammusc12_update(wheeldevice, simdata->maxrpm, simdata->rpms, simdata->gear, simdata->velocity);
break;
}
return 0;
}
int wheeldev_free(WheelDevice* wheeldevice)
{
switch ( wheeldevice->type )
{
case WHEELDEV_UNKNOWN :
case WHEELDEV_CAMMUSC5 :
cammusc5_update(wheeldevice, 0, 0, 0, 0);
cammusc5_free(wheeldevice);
break;
case WHEELDEV_CAMMUSC12 :
cammusc12_update(wheeldevice, 0, 0, 0, 0);
cammusc12_free(wheeldevice);
break;
}
return 0;
}
int wheeldev_init(WheelDevice* wheeldevice, DeviceSettings* ds)
{
slogi("initializing wheel device...");
int error = 0;
// detection of wheel model
switch (ds->dev_subsubtype) {
case SIMDEVSUBTYPE_CAMMUSC5:
wheeldevice->type = WHEELDEV_CAMMUSC5;
slogi("Attempting to initialize cammus C5");
error = cammusc5_init(wheeldevice);
break;
case SIMDEVSUBTYPE_CAMMUSC12:
wheeldevice->type = WHEELDEV_CAMMUSC12;
slogi("Attempting to initialize cammus C12");
error = cammusc12_init(wheeldevice);
break;
default:
wheeldevice->type = WHEELDEV_UNKNOWN;
slogw("Unknown cammus wheel detected, trying C5");
error = cammusc5_init(wheeldevice);
break;
}
return error;
}
+32
View File
@@ -0,0 +1,32 @@
#ifndef _WHEELDEVICE_H
#define _WHEELDEVICE_H
#include <hidapi/hidapi.h>
#include "../helper/confighelper.h"
#include "../simulatorapi/simapi/simapi/simdata.h"
//typedef int (*tachdev_update)(int revs);
typedef enum
{
WHEELDEV_UNKNOWN = 0,
WHEELDEV_CAMMUSC5 = 1,
WHEELDEV_CAMMUSC12 = 2,
WHEELDEV_MOZAR5 = 3
}
WheelType;
typedef struct
{
int id;
WheelType type;
hid_device* handle;
char* port;
}
WheelDevice;
int wheeldev_update(WheelDevice* wheeldevice, SimData* simdata);
int wheeldev_init(WheelDevice* wheeldevice, DeviceSettings* ds);
int wheeldev_free(WheelDevice* wheeldevice);
#endif
+1
View File
@@ -3,6 +3,7 @@ set(gameloop_source_files
gameloop.h
tachconfig.c
tachconfig.h
loopdata.h
)
set(LIBXML_INCLUDE_DIR /usr/include/libxml2)
+454 -105
View File
@@ -7,11 +7,15 @@
#include <poll.h>
#include <termios.h>
#include <signal.h>
#include <uv.h>
#include "gameloop.h"
#include "loopdata.h"
#include "../helper/parameters.h"
#include "../helper/confighelper.h"
#include "../devices/simdevice.h"
#include "../devices/serialadapter.h"
#include "../simulatorapi/simapi/simapi/simdata.h"
#include "../simulatorapi/simapi/simapi/simmapper.h"
#include "../slog/slog.h"
@@ -22,15 +26,18 @@ bool go = false;
bool go2 = false;
struct sigaction act;
void sighandler(int signum, siginfo_t* info, void* ptr)
{
sloge("caught signal");
go = false;
go2 = false;
//gfx_clear(pixels, pixels_len);
//gfx_swapbuffers();
//gfx_close();
}
uv_idle_t idler;
uv_timer_t datachecktimer;
uv_timer_t datamaptimer;
uv_udp_t recv_socket;
bool doui = false;
int appstate = 0;
void shmdatamapcallback(uv_timer_t* handle);
void datacheckcallback(uv_timer_t* handle);
void startdatalogger(MonocoqueSettings* ms, loop_data* l);
int showstats(SimData* simdata)
{
@@ -181,74 +188,400 @@ int showstats(SimData* simdata)
fflush(stdout);
}
int clilooper(SimDevice* devices, int numdevices, Parameters* p, SimData* simdata, SimMap* simmap)
void simapilib_loginfo(char* message)
{
struct pollfd mypoll = { STDIN_FILENO, POLLIN|POLLPRI };
double update_rate = DEFAULT_UPDATE_RATE;
char ch;
int t=0;
int s=0;
go2 = true;
while (go2 == true && simdata->simstatus > 1)
slogi(message);
}
void simapilib_logdebug(char* message)
{
slogd(message);
}
void simapilib_logtrace(char* message)
{
slog_display(SLOG_TRACE, 1, message);
}
void on_timer_close_complete(uv_handle_t* handle)
{
free(handle);
}
void devicetimercallback(uv_timer_t* handle)
{
void* b = uv_handle_get_data((uv_handle_t*) handle);
device_loop_data* f = (device_loop_data*) b;
SimData* simdata = f->simdata;
SimDevice* device = f->simdevice;
device->update(device, simdata);
}
void looprun(MonocoqueSettings* ms, loop_data* f, SimData* simdata)
{
if (doui == true)
{
simdatamap(simdata, simmap, p->sim);
showstats(simdata);
t++;
s++;
if(simdata->rpms<100)
slogi("looking for ui config %s pass 1", ms->config_str);
int confignum = getconfigtouse2(ms->config_str, simdata->car, f->sim);
if(confignum == -1)
{
simdata->rpms=100;
slogi("looking for ui config %s pass 2", ms->config_str);
confignum = getconfigtouse1(ms->config_str, simdata->car, f->sim);
}
if(confignum == -1)
{
slogi("looking for ui config %s pass 3", ms->config_str);
confignum = getconfigtouse(ms->config_str, simdata->car, f->sim);
}
int configureddevices;
configcheck(ms->config_str, confignum, &configureddevices);
DeviceSettings* ds = malloc(configureddevices * sizeof(DeviceSettings));
slogd("loading confignum %i, with %i devices.", confignum, configureddevices);
f->numdevices = uiloadconfig(ms->config_str, confignum, configureddevices, ms, ds);
if(ms->useconfig == 1)
{
ms->configcheck = 0;
}
f->simdevices = malloc(f->numdevices * sizeof(SimDevice));
int initdevices = devinit(f->simdevices, configureddevices, ds, ms);
int i = 0;
for( i = 0; i < configureddevices; i++)
{
settingsfree(ds[i]);
}
free(ds);
for(int d = 0; d < 10; d++)
{
monocoque_serial_devices[d].open = false;
monocoque_serial_devices[d].openfail = false;
monocoque_serial_devices[d].busy = false;
monocoque_serial_devices[d].refs = 0;
}
int numdevices = f->numdevices;
SimDevice* devices = f->simdevices;
f->device_timers = (uv_timer_t*) (malloc(uv_handle_size(UV_TIMER) * numdevices));
f->device_batons = (device_loop_data*) (malloc(sizeof(device_loop_data) * numdevices));
for (int x = 0; x < numdevices; x++)
{
if (devices[x].initialized == true)
{
devices[x].update(&devices[x], simdata);
device_loop_data* dld = &f->device_batons[x];
dld->simdevice = &devices[x];
dld->simdata = simdata;
uv_timer_t* dt = &f->device_timers[x];
uv_timer_init(uv_default_loop(), dt);
uv_handle_set_data((uv_handle_t*) dt, (void*) dld);
int interval = 1000/devices[x].fps;
uv_timer_start(dt, devicetimercallback, 0, interval);
slogi("starting device at %i fps (%i ms ticks)", devices[x].fps, interval);
}
}
if( poll(&mypoll, 1, 1000.0/update_rate) )
{
scanf("%c", &ch);
if(ch == 'q')
{
go2 = false;
}
}
doui = false;
}
else
{
showstats(simdata);
//SimDevice* devices = f->simdevices;
//int numdevices = f->numdevices;
//for (int x = 0; x < numdevices; x++)
//{
// if (devices[x].initialized == true && devices[x].type == 2)
// {
// devices[x].update(&devices[x], simdata);
// }
//}
}
}
void shmdatamapcallback(uv_timer_t* handle)
{
void* b = uv_handle_get_data((uv_handle_t*) handle);
loop_data* f = (loop_data*) b;
SimData* simdata = f->simdata;
SimMap* simmap = f->simmap;
MonocoqueSettings* ms = f->ms;
//appstate = 2;
if (appstate == 2)
{
simdatamap(simdata, simmap, NULL, f->map, false, NULL);
looprun(ms, f, simdata);
}
simdata->velocity = 0;
simdata->rpms = 100;
for (int x = 0; x < numdevices; x++)
if (f->simstate == false || simdata->simstatus <= 1 || appstate <= 1)
{
if (devices[x].initialized == true)
if(f->releasing == false)
{
devices[x].update(&devices[x], simdata);
f->releasing = true;
uv_timer_stop(handle);
slogi("releasing devices, please wait");
f->uion = false;
SimDevice* devices = f->simdevices;
int numdevices = f->numdevices;
// help things spin down
simdata->rpms = 0;
simdata->velocity = 0;
for (int x = 0; x < numdevices; x++)
{
if (devices[x].initialized == true)
{
uv_timer_t* dt = &f->device_timers[x];
slogt("attempting device timer stop and release");
slogt("timer active status %i", uv_is_active((uv_handle_t*) dt));
uv_timer_stop(dt);
//uv_close((uv_handle_t*) dt, on_timer_close_complete);
}
}
free(f->device_batons);
free(f->device_timers);
slogt("stopped device timers");
for (int x = 0; x < numdevices; x++)
{
if (devices[x].initialized == true)
{
devices[x].update(&devices[x], simdata);
}
}
for (int x = 0; x < numdevices; x++)
{
if (devices[x].initialized == true)
{
devices[x].free(&devices[x]);
}
}
free(devices);
for(int d = 0; d < 10; d++)
{
if(monocoque_serial_devices[d].portname != NULL)
{
free(monocoque_serial_devices[d].portname);
}
}
int r = simfree(simdata, simmap, f->map);
slogd("simfree returned %i", r);
f->numdevices = 0;
slogi("stopped mapping data, press q again to quit");
//stopui(ms->ui_type, f);
// free loop data
if(appstate > 0)
{
uv_timer_start(&datachecktimer, datacheckcallback, 3000, 1000);
}
f->releasing = false;
if(appstate > 1)
{
appstate = 1;
}
}
}
}
void on_alloc(uv_handle_t* client, size_t suggested_size, uv_buf_t* buf) {
buf->base = malloc(suggested_size);
buf->len = suggested_size;
bzero(buf->base, suggested_size);
slogt("udp malloc:%lu %p\n",buf->len,buf->base);
}
static void on_udp_recv(uv_udp_t* handle, ssize_t nread, const uv_buf_t* rcvbuf, const struct sockaddr* addr, unsigned flags) {
if (nread > 0) {
slogt("udp data received");
}
char* a;
a = rcvbuf->base;
void* b = uv_handle_get_data((uv_handle_t*) handle);
loop_data* f = (loop_data*) b;
SimData* simdata = f->simdata;
SimMap* simmap = f->simmap;
MonocoqueSettings* ms = f->ms;
if (appstate == 2)
{
simdatamap(simdata, simmap, NULL, f->map, true, a);
looprun(ms, f, simdata);
}
if (f->simstate == false || simdata->simstatus <= 1 || appstate <= 1)
{
if(f->releasing == false)
{
f->releasing = true;
uv_udp_recv_stop(handle);
slogi("releasing devices, please wait");
f->uion = false;
SimDevice* devices = f->simdevices;
int numdevices = f->numdevices;
// help things spin down
simdata->rpms = 0;
simdata->velocity = 0;
for (int x = 0; x < numdevices; x++)
{
if (devices[x].initialized == true)
{
devices[x].update(&devices[x], simdata);
}
}
for (int x = 0; x < numdevices; x++)
{
if (devices[x].initialized == true)
{
devices[x].free(&devices[x]);
}
}
free(devices);
int r = simfree(simdata, simmap, f->map);
slogd("simfree returned %i", r);
f->numdevices = 0;
slogi("stopped mapping data, press q again to quit");
//stopui(ms->ui_type, f);
// free loop data
if(appstate > 0)
{
uv_timer_start(&datachecktimer, datacheckcallback, 3000, 1000);
}
f->releasing = false;
if(appstate > 1)
{
appstate = 1;
}
}
}
fprintf(stdout, "\n");
return 0;
slogt("udp free :%lu %p\n",rcvbuf->len,rcvbuf->base);
free(rcvbuf->base);
}
int looper(SimDevice* devices, int numdevices, Parameters* p)
int startudp(int port)
{
uv_udp_init(uv_default_loop(), &recv_socket);
struct sockaddr_in recv_addr;
uv_ip4_addr("0.0.0.0", port, &recv_addr);
int err = uv_udp_bind(&recv_socket, (const struct sockaddr *) &recv_addr, UV_UDP_REUSEADDR);
slogt("initial udp error is %i", err);
return err;
}
void udpstart(MonocoqueSettings* sms, loop_data* f, SimData* simdata, SimMap* simmap)
{
if (appstate == 2)
{
simdatamap(simdata, simmap, NULL, f->sim, true, NULL);
if (doui == true)
{
looprun(sms, f, simdata);
}
}
}
void datacheckcallback(uv_timer_t* handle)
{
void* b = uv_handle_get_data((uv_handle_t*) handle);
loop_data* f = (loop_data*) b;
SimData* simdata = f->simdata;
SimMap* simmap = f->simmap;
if ( appstate == 1 )
{
SimInfo si = getSim(simdata, simmap, f->ms->force_udp_mode, startudp, false);
//TODO: move all this to a siminfo struct in loop_data
f->simstate = si.isSimOn;
f->sim = si.simulatorapi;
f->map = si.mapapi;
f->use_udp = si.SimUsesUDP;
if(f->ms->force_udp_mode == true)
{
f->use_udp = true;
}
}
if (f->simstate == true && simdata->simstatus >= 2)
{
if ( appstate == 1 )
{
appstate++;
doui = true;
simdata->tyrediameter[0] = -1;
simdata->tyrediameter[1] = -1;
simdata->tyrediameter[2] = -1;
simdata->tyrediameter[3] = -1;
if(f->use_udp == true)
{
slogt("starting udp receive loop");
udpstart(f->ms, f, simdata, simmap);
uv_udp_recv_start(&recv_socket, on_alloc, on_udp_recv);
slogt("udp receive loop started");
}
else
{
int interval = 1000 / f->ms->fps;
slogd("starting telemetry mapping at %i fps (%i ms ticks)", f->ms->fps, interval);
uv_timer_start(&datamaptimer, shmdatamapcallback, 2000, interval);
}
uv_timer_stop(handle);
}
}
if (appstate == 0)
{
slogi("stopping checking for data");
uv_timer_stop(handle);
}
}
void cb(uv_poll_t* handle, int status, int events)
{
void* b = uv_handle_get_data((uv_handle_t*) handle);
loop_data* f = (loop_data*) b;
char ch;
scanf("%c", &ch);
if (ch == 'q')
{
if(f->releasing == false && doui == false)
{
appstate--;
fprintf(stdout, "\nUser requested stop appstate is now %i\n", appstate);
fflush(stdout);
slogi("User requested stop appstate is now %i", appstate);
}
}
if (appstate == 0)
{
slogi("Monocoque is exiting...");
uv_timer_stop(&datachecktimer);
uv_poll_stop(handle);
}
}
int monocoque_mainloop(MonocoqueSettings* ms)
{
memset(&act, 0, sizeof(act));
act.sa_sigaction = sighandler;
act.sa_flags = SA_SIGINFO;
sigaction(SIGTERM, &act, NULL);
sigaction(SIGINT, &act, NULL);
sigaction(SIGTSTP, &act, NULL);
SimData* simdata = malloc(sizeof(SimData));
SimMap* simmap = malloc(sizeof(SimMap));
simdata->tyrediameter[0] = -1;
simdata->tyrediameter[1] = -1;
simdata->tyrediameter[2] = -1;
simdata->tyrediameter[3] = -1;
SimMap* simmap = createSimMap();
struct termios newsettings, canonicalmode;
tcgetattr(0, &canonicalmode);
@@ -260,57 +593,52 @@ int looper(SimDevice* devices, int numdevices, Parameters* p)
char ch;
struct pollfd mypoll = { STDIN_FILENO, POLLIN|POLLPRI };
uv_poll_t* poll = (uv_poll_t*) malloc(uv_handle_size(UV_POLL));
loop_data* baton = (loop_data*) malloc(sizeof(loop_data));
baton->simmap = simmap;
baton->simdata = simdata;
baton->ms = ms;
baton->simstate = false;
baton->uion = false;
baton->releasing = false;
baton->sim = 0;
baton->req.data = (void*) baton;
uv_handle_set_data((uv_handle_t*) &datachecktimer, (void*) baton);
uv_handle_set_data((uv_handle_t*) &datamaptimer, (void*) baton);
uv_handle_set_data((uv_handle_t*) &recv_socket, (void*) baton);
uv_handle_set_data((uv_handle_t*) poll, (void*) baton);
appstate = 1;
slogd("setting initial app state");
uv_timer_init(uv_default_loop(), &datachecktimer);
fprintf(stdout, "Searching for sim data... Press q to quit...\n");
p->simon = false;
double update_rate = SIM_CHECK_RATE;
go = true;
while (go == true)
uv_timer_start(&datachecktimer, datacheckcallback, 1000, 1000);
set_simapi_log_info(simapilib_loginfo);
set_simapi_log_debug(simapilib_logdebug);
set_simapi_log_trace(simapilib_logtrace);
if (0 != uv_poll_init(uv_default_loop(), poll, 0))
{
p->simon = false;
getSim(simdata, simmap, &p->simon, &p->sim);
if (p->simon == true && simdata->simstatus > 1)
{
slogi("preparing game loop with %i devices...", numdevices);
return 1;
};
if (0 != uv_poll_start(poll, UV_READABLE, cb))
{
return 2;
};
slogi("sending initial data to devices");
simdata->velocity = 16;
simdata->rpms = 100;
for (int x = 0; x < numdevices; x++)
{
devices[x].update(&devices[x], simdata);
}
sleep(3);
clilooper(devices, numdevices, p, simdata, simmap);
}
if (p->simon == true)
{
p->simon = false;
fprintf(stdout, "Searching for sim data... Press q again to quit...\n");
sleep(2);
}
if (poll(&mypoll, 1, 1000.0/update_rate) )
{
if (go != false )
{
scanf("%c", &ch);
if(ch == 'q')
{
go = false;
}
}
}
}
uv_timer_init(uv_default_loop(), &datamaptimer);
uv_run(uv_default_loop(), UV_RUN_DEFAULT);
fprintf(stdout, "\n");
fflush(stdout);
tcsetattr(0, TCSANOW, &canonicalmode);
free(baton);
free(simdata);
free(simmap);
freesimmap(simmap, false);
return 0;
}
@@ -330,7 +658,12 @@ int tester(SimDevice* devices, int numdevices)
tcsetattr(0, TCSANOW, &newsettings);
fprintf(stdout, "\n");
simdata->gear = 0;
simdata->car[0] = 'C';
simdata->car[1] = 'A';
simdata->car[2] = 'R';
simdata->car[3] = '\0';
simdata->gear = MONOCOQUE_GEAR_NEUTRAL;
simdata->velocity = 16;
simdata->rpms = 100;
simdata->maxrpm = 8000;
@@ -339,6 +672,9 @@ int tester(SimDevice* devices, int numdevices)
simdata->tyrediameter[1] = -1;
simdata->tyrediameter[2] = -1;
simdata->tyrediameter[3] = -1;
simdata->Xvelocity = 0;
simdata->Yvelocity = 100;
simdata->Zvelocity = 0;
sleep(3);
@@ -376,14 +712,15 @@ int tester(SimDevice* devices, int numdevices)
sleep(3);
fprintf(stdout, "testing wheel spin\n");
simdata->velocity = 15;
simdata->tyreRPS[0] = 50;
simdata->tyreRPS[1] = 50;
simdata->tyreRPS[2] = 50;
simdata->tyreRPS[3] = 50;
simdata->tyrediameter[0] = 0.638636385206394;
simdata->tyrediameter[1] = 0.633384434597093;
simdata->tyrediameter[2] = 0.710475735564615;
simdata->tyrediameter[3] = 0.710475735564615;
simdata->tyreRPS[0] = 103;
simdata->tyreRPS[1] = 103;
simdata->tyreRPS[2] = 103;
simdata->tyreRPS[3] = 103;
for (int x = 0; x < numdevices; x++)
{
if (devices[x].initialized == true)
@@ -394,11 +731,11 @@ int tester(SimDevice* devices, int numdevices)
sleep(3);
fprintf(stdout, "Testing wheel Lock\n");
simdata->tyreRPS[0] = 50;
simdata->tyreRPS[1] = 50;
simdata->tyreRPS[2] = 50;
simdata->tyreRPS[3] = 50;
simdata->velocity = 100;
simdata->tyreRPS[0] = 25;
simdata->tyreRPS[1] = 25;
simdata->tyreRPS[2] = 25;
simdata->tyreRPS[3] = 25;
simdata->velocity = 150;
for (int x = 0; x < numdevices; x++)
{
if (devices[x].initialized == true)
@@ -432,11 +769,11 @@ int tester(SimDevice* devices, int numdevices)
simdata->tyreRPS[0] = 50;
simdata->tyreRPS[1] = 50;
simdata->tyreRPS[2] = 50;
simdata->tyreRPS[3] = 50;
simdata->tyrediameter[0] = 0.638636385206394;
simdata->tyrediameter[1] = 0.633384434597093;
simdata->tyrediameter[2] = 0.710475735564615;
simdata->tyrediameter[3] = 0.710475735564615;
simdata->tyreRPS[3] = 50;
simdata->abs = .11;
for (int x = 0; x < numdevices; x++)
{
@@ -522,6 +859,17 @@ int tester(SimDevice* devices, int numdevices)
}
sleep(3);
fprintf(stdout, "Setting rpms to 7000\n");
simdata->rpms = 7000;
for (int x = 0; x < numdevices; x++)
{
if (devices[x].initialized == true)
{
devices[x].update(&devices[x], simdata);
}
}
sleep(3);
fprintf(stdout, "Setting rpms to 8000\n");
simdata->rpms = 8000;
for (int x = 0; x < numdevices; x++)
@@ -535,6 +883,7 @@ int tester(SimDevice* devices, int numdevices)
simdata->velocity = 0;
simdata->rpms = 100;
simdata->gear = MONOCOQUE_GEAR_NEUTRAL;
for (int x = 0; x < numdevices; x++)
{
if (devices[x].initialized == true)
+2
View File
@@ -3,3 +3,5 @@
int tester(SimDevice* devices, int numdevices);
int looper(SimDevice* devices, int numdevices, Parameters* p);
int monocoque_mainloop(MonocoqueSettings* ms);
+38
View File
@@ -0,0 +1,38 @@
#ifndef _LOOPDATA_H
#define _LOOPDATA_H
#include <uv.h>
#include "../helper/parameters.h"
#include "../helper/confighelper.h"
#include "../devices/simdevice.h"
#include "../simulatorapi/simapi/simapi/simdata.h"
#include "../simulatorapi/simapi/simapi/simmapper.h"
typedef struct device_loop_data
{
uv_work_t req;
SimData* simdata;
SimDevice* simdevice;
} device_loop_data;
typedef struct loop_data
{
uv_work_t req;
SimulatorAPI sim;
SimulatorAPI map;
bool use_udp;
bool simstate;
bool uion;
bool releasing;
int numdevices;
MonocoqueSettings* ms;
SimData* simdata;
SimMap* simmap;
SimDevice* simdevices;
uv_timer_t* device_timers;
device_loop_data* device_batons;
} loop_data;
#endif
+480 -39
View File
@@ -11,9 +11,14 @@
#include "confighelper.h"
#include "../slog/slog.h"
#include "parameters.h"
#include "../simulatorapi/simapi/simapi/simmapper.h"
#include <pulse/pulseaudio.h>
int strcicmp(char const *a, char const *b)
@@ -25,34 +30,6 @@ int strcicmp(char const *a, char const *b)
}
}
int strtogame(const char* game, MonocoqueSettings* ms)
{
slogd("Checking for %s in list of supported simulators.", game);
if (strcicmp(game, "ac") == 0)
{
slogd("Setting simulator to Assetto Corsa");
ms->sim_name = SIMULATOR_ASSETTO_CORSA;
}
else if (strcicmp(game, "rf2") == 0)
{
slogd("Setting simulator to RFactor 2");
ms->sim_name = SIMULATOR_RFACTOR2;
}
else
if (strcicmp(game, "test") == 0)
{
slogd("Setting simulator to Test Data");
ms->sim_name = SIMULATOR_SIMAPI_TEST;
}
else
{
slogi("%s does not appear to be a supported simulator.", game);
return MONOCOQUE_ERROR_INVALID_SIM;
}
return MONOCOQUE_ERROR_NONE;
}
int strtoeffecttype(const char* effect, DeviceSettings* ds)
{
ds->is_valid = false;
@@ -95,6 +72,51 @@ int strtoeffecttype(const char* effect, DeviceSettings* ds)
return MONOCOQUE_ERROR_NONE;
}
int strtodevsubsubtype(const char* device_subsubtype, DeviceSettings* ds)
{
ds->dev_subsubtype = SIMDEVSUBTYPE_UNKNOWN;
bool devfound = false;
if (strcicmp(device_subsubtype, "CammusC5") == 0)
{
ds->dev_subsubtype = SIMDEVSUBTYPE_CAMMUSC5;
bool devfound = true;
}
if (strcicmp(device_subsubtype, "CammusC12") == 0)
{
ds->dev_subsubtype = SIMDEVSUBTYPE_CAMMUSC12;
bool devfound = true;
}
if (strcicmp(device_subsubtype, "MozaR5") == 0)
{
ds->dev_subsubtype = SIMDEVSUBTYPE_MOZAR5;
bool devfound = true;
}
if (strcicmp(device_subsubtype, "MozaR8") == 0)
{
ds->dev_subsubtype = SIMDEVSUBTYPE_MOZAR5;
bool devfound = true;
}
if (strcicmp(device_subsubtype, "CSLELITEV3PEDALS") == 0)
{
ds->dev_subsubtype = SIMDEVSUBTYPE_CSLELITEV3PEDALS;
bool devfound = true;
}
if (strcicmp(device_subsubtype, "SIMAGICP1000PEDALS") == 0)
{
ds->dev_subsubtype = SIMDEVSUBTYPE_SIMAGICP1000PEDALS;
bool devfound = true;
}
if(devfound == false)
{
slogw("%s does not appear to be a valid device sub sub type, but attempting to continue with other devices", device_subsubtype);
return MONOCOQUE_ERROR_INVALID_DEV;
}
return MONOCOQUE_ERROR_NONE;
}
int strtodevsubtype(const char* device_subtype, DeviceSettings* ds, int simdev)
{
ds->is_valid = false;
@@ -107,6 +129,11 @@ int strtodevsubtype(const char* device_subtype, DeviceSettings* ds, int simdev)
ds->dev_subtype = SIMDEVTYPE_TACHOMETER;
break;
}
if (strcicmp(device_subtype, "Wheel") == 0)
{
ds->dev_subtype = SIMDEVTYPE_USBWHEEL;
break;
}
if (strcicmp(device_subtype, "UsbHaptic") == 0 || strcicmp(device_subtype, "Haptic") == 0)
{
ds->dev_subtype = SIMDEVTYPE_USBHAPTIC;
@@ -118,6 +145,11 @@ int strtodevsubtype(const char* device_subtype, DeviceSettings* ds, int simdev)
ds->dev_subtype = SIMDEVTYPE_SHIFTLIGHTS;
break;
}
if (strcicmp(device_subtype, "Simleds") == 0)
{
ds->dev_subtype = SIMDEVTYPE_SIMLED;
break;
}
if (strcicmp(device_subtype, "SimWind") == 0)
{
ds->dev_subtype = SIMDEVTYPE_SIMWIND;
@@ -129,6 +161,11 @@ int strtodevsubtype(const char* device_subtype, DeviceSettings* ds, int simdev)
ds->dev_subtype = SIMDEVTYPE_SERIALHAPTIC;
break;
}
if (strcicmp(device_subtype, "Wheel") == 0)
{
ds->dev_subtype = SIMDEVTYPE_SERIALWHEEL;
break;
}
case SIMDEV_SOUND:
ds->is_valid = true;
break;
@@ -171,6 +208,233 @@ int strtodev(const char* device_type, const char* device_subtype, DeviceSettings
return MONOCOQUE_ERROR_NONE;
}
int getsimfromconfig(config_setting_t* c)
{
int sim = 0;
const char* simstr = NULL;
int found = config_setting_lookup_string(c, "sim", &simstr);
if(found == 0)
{
int found = config_setting_lookup_int(c, "sim", &sim);
}
else
{
sim = simapi_strtogame(simstr);
}
return sim;
}
int getNumberOfConfigs(const char* config_file_str)
{
config_t cfg;
config_init(&cfg);
if (!config_read_file(&cfg, config_file_str))
{
fprintf(stderr, "%s:%d - %s\n", config_error_file(&cfg), config_error_line(&cfg), config_error_text(&cfg));
return -1;
}
config_setting_t* config = NULL;
config_setting_t* config_widgets = NULL;
config = config_lookup(&cfg, "configs");
int configs = config_setting_length(config);
return configs;
}
int getconfigtouse2(const char* config_file_str, char* car, int sim)
{
config_t cfg;
config_init(&cfg);
if (!config_read_file(&cfg, config_file_str))
{
fprintf(stderr, "%s:%d - %s\n", config_error_file(&cfg), config_error_line(&cfg), config_error_text(&cfg));
return -1;
}
config_setting_t* config = NULL;
config_setting_t* config_widgets = NULL;
config = config_lookup(&cfg, "configs");
int configs = config_setting_length(config);
const char* temp;
config_setting_t* config_config = NULL;
int j = 0;
if ( configs == 1 )
{
return -1;
}
int confignum = -1;
slogt("Multiple configs found");
for (j = 0; j < configs; j++)
{
config_config = config_setting_get_elem(config, j);
int found = 0;
int csim = 0;
slogt("sim is %i", sim);
csim = getsimfromconfig(config_config);
if (csim != sim)
{
slogt("rejected config %i", j);
continue;
}
slogt("checking if car is matched %i", j);
temp = NULL;
found = config_setting_lookup_string(config_config, "car", &temp);
slogt("config car is %s found is %i", temp, found);
if(temp != NULL && found > 0 && car > 0 && car != NULL)
{
slogt("checking against sim car of %s", car);
if(strcicmp(temp, car) == 0)
{
confignum = j;
}
}
if(confignum>=0)
{
break;
}
}
return confignum;
}
int getconfigtouse1(const char* config_file_str, char* car, int sim)
{
config_t cfg;
config_init(&cfg);
if (!config_read_file(&cfg, config_file_str))
{
fprintf(stderr, "%s:%d - %s\n", config_error_file(&cfg), config_error_line(&cfg), config_error_text(&cfg));
return -1;
}
config_setting_t* config = NULL;
config_setting_t* config_widgets = NULL;
config = config_lookup(&cfg, "configs");
int configs = config_setting_length(config);
const char* temp;
config_setting_t* config_config = NULL;
int j = 0;
if ( configs == 1 )
{
return -1;
}
int confignum = -1;
slogt("Multiple configs found");
for (j = 0; j < configs; j++)
{
config_config = config_setting_get_elem(config, j);
int found = 0;
int csim = 0;
slogt("sim is %i", sim);
csim = getsimfromconfig(config_config);
if (csim != sim)
{
slogt("rejected config %i", j);
continue;
}
slogt("checking if car is matched %i", j);
temp = NULL;
found = config_setting_lookup_string(config_config, "car", &temp);
slogt("config car is %s found is %i", temp, found);
if(temp != NULL && found > 0 && car > 0 && car != NULL)
{
slogt("checking against sim car of %s", car);
if(strcicmp(temp, car) == 0)
{
confignum = j;
}
if(strcicmp("default", temp) == 0)
{
slogt("matched default car");
confignum = j;
}
}
else
{
slogt("assuming default car");
confignum = j;
}
slogt("bomb");
if(confignum>=0)
{
break;
}
}
return confignum;
}
int getconfigtouse(const char* config_file_str, char* car, int sim)
{
config_t cfg;
config_init(&cfg);
if (!config_read_file(&cfg, config_file_str))
{
fprintf(stderr, "%s:%d - %s\n", config_error_file(&cfg), config_error_line(&cfg), config_error_text(&cfg));
return -1;
}
config_setting_t* config = NULL;
config_setting_t* config_widgets = NULL;
config = config_lookup(&cfg, "configs");
int configs = config_setting_length(config);
const char* temp;
config_setting_t* config_config = NULL;
int j = 0;
if ( configs == 1 )
{
return 0;
}
int confignum = 0;
slogt("Multiple configs found");
for (j = 0; j < configs; j++)
{
config_config = config_setting_get_elem(config, j);
int found = 0;
int csim = 0;
slogt("sim is %i", sim);
csim = getsimfromconfig(config_config);
if (csim != sim && csim != 0)
{
slogt("rejected config %i", j);
continue;
}
slogt("checking if car is matched %i", j);
temp = NULL;
found = config_setting_lookup_string(config_config, "car", &temp);
slogt("config car is %s found is %i", temp, found);
if(temp != NULL && found > 0 && car > 0 && car != NULL)
{
slogt("checking against sim car of %s", car);
if(strcicmp(temp, car) == 0)
{
confignum = j;
}
if(strcicmp("default", temp) == 0)
{
slogt("matched default car");
confignum = j;
}
}
else
{
slogt("assuming default car");
confignum = j;
}
slogt("bomb");
if(confignum<configs-1)
{
break;
}
}
return confignum;
}
int loadtachconfig(const char* config_file, DeviceSettings* ds)
{
@@ -307,6 +571,28 @@ int loadconfig(const char* config_file, DeviceSettings* ds)
return 0;
}
int configcheck(const char* config_file_str, int confignum, int* devices)
{
slogt("ui config check");
config_t cfg;
config_init(&cfg);
if (!config_read_file(&cfg, config_file_str))
{
fprintf(stderr, "%s:%d - %s\n", config_error_file(&cfg), config_error_line(&cfg), config_error_text(&cfg));
}
config_setting_t* config = NULL;
config = config_lookup(&cfg, "configs");
config_setting_t* selectedconfig = config_setting_get_elem(config, confignum);
slogt("selected num %i", confignum);
config_setting_t* config_devices = NULL;
config_devices = config_setting_lookup(selectedconfig, "devices");
*devices = config_setting_length(config_devices);
config_destroy(&cfg);
return 0;
//return cfg;
}
int devsetup(const char* device_type, const char* device_subtype, const char* config_file, MonocoqueSettings* ms, DeviceSettings* ds, config_setting_t* device_settings)
{
int error = MONOCOQUE_ERROR_NONE;
@@ -330,6 +616,8 @@ int devsetup(const char* device_type, const char* device_subtype, const char* co
}
ds->fps = 60;
config_setting_lookup_int(device_settings, "fps", &ds->fps);
if (ds->dev_subtype == SIMDEVTYPE_TACHOMETER)
{
@@ -350,9 +638,17 @@ int devsetup(const char* device_type, const char* device_subtype, const char* co
}
}
if (ds->dev_subtype == SIMDEVTYPE_USBHAPTIC)
if (ds->dev_subtype == SIMDEVTYPE_USBHAPTIC || ds->dev_subtype == SIMDEVTYPE_USBWHEEL)
{
// logic for different devices
int b = 0;
const char* temp;
int found = config_setting_lookup_string(device_settings, "subtype", &temp);
if(temp != NULL && found > 0)
{
b = strtodevsubsubtype(temp, ds);
}
}
if (ds->dev_subtype == SIMDEVTYPE_USBHAPTIC || ds->dev_type == SIMDEV_SOUND || ds->dev_subtype == SIMDEVTYPE_SERIALHAPTIC)
@@ -371,11 +667,11 @@ int devsetup(const char* device_type, const char* device_subtype, const char* co
if (ds->dev_type == SIMDEV_SOUND)
{
slogi("reading configured sound device settings");
ds->sounddevsettings.frequency = -1;
ds->sounddevsettings.volume = -1;
ds->sounddevsettings.lowbound_frequency = -1;
ds->sounddevsettings.upperbound_frequency = -1;
ds->sounddevsettings.frequency = 0;
ds->sounddevsettings.frequencyMax = 0;
ds->sounddevsettings.volume = 0;
ds->sounddevsettings.pan = 0;
ds->sounddevsettings.channels = 1;
ds->sounddevsettings.duration = 2.0;
if (ds->effect_type == EFFECT_GEARSHIFT)
{
@@ -386,7 +682,9 @@ int devsetup(const char* device_type, const char* device_subtype, const char* co
config_setting_lookup_int(device_settings, "volume", &ds->sounddevsettings.volume);
config_setting_lookup_int(device_settings, "frequency", &ds->sounddevsettings.frequency);
config_setting_lookup_int(device_settings, "frequencyMax", &ds->sounddevsettings.frequencyMax);
config_setting_lookup_int(device_settings, "pan", &ds->sounddevsettings.pan);
config_setting_lookup_int(device_settings, "channels", &ds->sounddevsettings.channels);
config_setting_lookup_float(device_settings, "duration", &ds->sounddevsettings.duration);
const char* temp;
@@ -400,11 +698,46 @@ int devsetup(const char* device_type, const char* device_subtype, const char* co
{
ds->sounddevsettings.dev = strdup(temp);
}
found = config_setting_lookup_string(device_settings, "modulation", &temp);
ds->sounddevsettings.modulation = SOUND_EFFECT_MODULATION_NONE;
if (found == 0)
{
ds->sounddevsettings.modulation = SOUND_EFFECT_MODULATION_NONE;
slogd("Effect modulation not found, set to none");
}
else
{
if(strcicmp(temp, "FREQUENCY"))
{
ds->sounddevsettings.modulation = SOUND_EFFECT_MODULATION_FREQUENCY;
if(ds->sounddevsettings.frequencyMax == 0 || ds->sounddevsettings.frequencyMax < ds->sounddevsettings.frequency)
{
ds->sounddevsettings.modulation = SOUND_EFFECT_MODULATION_NONE;
slogw("Falling back to no frequency modulation since frequencyMax is either not set or set below target frequency");
}
else
{
slogi("Effect modulation found, set to FREQUENCY");
}
}
else if(strcicmp(temp, "AMPLIFY"))
{
ds->sounddevsettings.modulation = SOUND_EFFECT_MODULATION_AMPLIFY;
slogi("Effect modulation found, set to AMPLIFY");
}
else
{
slogw("%s is not a valid modulation type, falling back to no effect modulation");
ds->sounddevsettings.modulation = SOUND_EFFECT_MODULATION_NONE;
}
}
}
}
}
if (ds->dev_subtype == SIMDEVTYPE_SIMWIND || ds->dev_subtype == SIMDEVTYPE_SHIFTLIGHTS || ds->dev_subtype == SIMDEVTYPE_SERIALHAPTIC)
if (ds->dev_type == SIMDEV_SERIAL)
{
if (device_settings != NULL)
{
@@ -416,17 +749,46 @@ int devsetup(const char* device_type, const char* device_subtype, const char* co
config_setting_lookup_int(device_settings, "motors", &motorposition);
ds->serialdevsettings.motorsposition = motorposition;
int numlights = 6;
config_setting_lookup_int(device_settings, "numlights", &numlights);
ds->serialdevsettings.numlights = numlights;
int numleds = 6;
config_setting_lookup_int(device_settings, "numleds", &numleds);
ds->serialdevsettings.numleds = numleds;
int startled = 1;
config_setting_lookup_int(device_settings, "startled", &startled);
ds->serialdevsettings.startled = startled;
int endled = 1;
config_setting_lookup_int(device_settings, "endled", &endled);
ds->serialdevsettings.endled = endled;
int baud = 9600;
config_setting_lookup_int(device_settings, "baud", &baud);
ds->serialdevsettings.baud = baud;
double ampfactor = 1.0;
ds->serialdevsettings.ampfactor = 1.0;
int found = config_setting_lookup_float(device_settings, "ampfactor", &ampfactor);
if(found == 0)
ds->serialdevsettings.ampfactor = ampfactor;
slogt("set port baud rate to %i, ampfactor %f", baud, ampfactor);
ds->has_config = false;
const char* temp2;
found = config_setting_lookup_string(device_settings, "config", &temp2);
slogt("config is %s found is %i", temp2, found);
if(strcicmp(temp2, "none") == 0)
{
ds->serialdevsettings.ampfactor = 1.0;
slogt("config set to none");
}
else
{
ds->serialdevsettings.ampfactor = ampfactor;
slogt("Set ampflication factor for motors to %f", ampfactor);
ds->has_config = true;
ds->serialdevsettings.config_file = strdup(temp2);
slogt("will try to load config file at %s", ds->serialdevsettings.config_file);
}
}
@@ -435,10 +797,69 @@ int devsetup(const char* device_type, const char* device_subtype, const char* co
return error;
}
int uiloadconfig(const char* config_file_str, int confignum, int configureddevices, MonocoqueSettings* ms, DeviceSettings* ds)
{
int numdevices = 0;
config_t cfg;
config_init(&cfg);
if (!config_read_file(&cfg, config_file_str))
{
fprintf(stderr, "%s:%d - %s\n", config_error_file(&cfg), config_error_line(&cfg), config_error_text(&cfg));
}
else
{
slogi("Parsing config file");
config_setting_t* config = NULL;
config = config_lookup(&cfg, "configs");
config_setting_t* selectedconfig = config_setting_get_elem(config, confignum);
config_setting_t* config_devices = NULL;
config_devices = config_setting_lookup(selectedconfig, "devices");
int i = 0;
int error = MONOCOQUE_ERROR_NONE;
while (i<configureddevices)
{
error = MONOCOQUE_ERROR_NONE;
DeviceSettings settings;
config_setting_t* config_device = config_setting_get_elem(config_devices, i);
const char* device_type;
const char* device_subtype;
const char* device_config_file;
config_setting_lookup_string(config_device, "device", &device_type);
config_setting_lookup_string(config_device, "type", &device_subtype);
config_setting_lookup_string(config_device, "config", &device_config_file);
//slogt("device type: %s", device_type);
//slogt("device sub type: %s", device_subtype);
//slogt("device config file: %s", device_config_file);
if (error == MONOCOQUE_ERROR_NONE)
{
error = devsetup(device_type, device_subtype, device_config_file, ms, &settings, config_device);
}
if (error == MONOCOQUE_ERROR_NONE)
{
numdevices++;
}
ds[i] = settings;
i++;
}
}
config_destroy(&cfg);
return numdevices;
}
int settingsfree(DeviceSettings ds)
{
if (ds.dev_subtype == SIMDEVTYPE_SIMWIND || ds.dev_subtype == SIMDEVTYPE_SHIFTLIGHTS)
if (ds.dev_subtype == SIMDEVTYPE_SIMWIND || ds.dev_subtype == SIMDEVTYPE_SHIFTLIGHTS || ds.dev_subtype == SIMDEVTYPE_SIMLED)
{
if (ds.serialdevsettings.portdev != NULL)
{
@@ -456,3 +877,23 @@ int settingsfree(DeviceSettings ds)
return 0;
}
int monocoquesettingsfree(MonocoqueSettings* ms)
{
if(ms->tyre_diameter_config != NULL)
{
free(ms->tyre_diameter_config);
}
if(ms->config_str != NULL)
{
free(ms->config_str);
}
if(ms->log_filename_str != NULL)
{
free(ms->log_filename_str);
}
if(ms->log_dirname_str != NULL)
{
free(ms->log_dirname_str);
}
}
+64 -4
View File
@@ -9,6 +9,8 @@
#include "parameters.h"
#include "../devices/sounddevice.h"
typedef enum
{
SIMDEV_UNKNOWN = 0,
@@ -25,10 +27,24 @@ typedef enum
SIMDEVTYPE_USBHAPTIC = 2,
SIMDEVTYPE_SHIFTLIGHTS = 3,
SIMDEVTYPE_SIMWIND = 4,
SIMDEVTYPE_SERIALHAPTIC = 5
SIMDEVTYPE_SERIALHAPTIC = 5,
SIMDEVTYPE_USBWHEEL = 6,
SIMDEVTYPE_SERIALWHEEL = 7,
SIMDEVTYPE_SIMLED = 8
}
DeviceSubType;
typedef enum
{
SIMDEVSUBTYPE_UNKNOWN = 0,
SIMDEVSUBTYPE_CAMMUSC5 = 1,
SIMDEVSUBTYPE_CAMMUSC12 = 2,
SIMDEVSUBTYPE_MOZAR5 = 3,
SIMDEVSUBTYPE_CSLELITEV3PEDALS = 4,
SIMDEVSUBTYPE_SIMAGICP1000PEDALS =5
}
DeviceSubSubType;
typedef enum
{
@@ -71,6 +87,21 @@ typedef enum
}
MotorPosition;
typedef enum
{
MONOCOQUE_GEAR_REVERSE = 0,
MONOCOQUE_GEAR_NEUTRAL = 1,
MONOCOQUE_GEAR_ONE = 2,
MONOCOQUE_GEAR_TWO = 3,
MONOCOQUE_GEAR_THREE = 4,
MONOCOQUE_GEAR_FOUR = 5,
MONOCOQUE_GEAR_FIVE = 6,
MONOCOQUE_GEAR_SIX = 7,
MONOCOQUE_GEAR_SEVEN = 8,
MONOCOQUE_GEAR_EIGHT = 9,
}
MonocoqueGear;
typedef enum
{
MONOCOQUE_ERROR_NONE = 0,
@@ -97,10 +128,16 @@ MonocoqueTyreIdentifier;
typedef struct
{
ProgramAction program_action;
Simulator sim_name;
SimulatorAPI sim_name;
int configcheck;
int useconfig;
int verbosity_count;
int fps;
bool force_udp_mode;
char* tyre_diameter_config;
char* config_str;
char* log_filename_str;
char* log_dirname_str;
}
MonocoqueSettings;
@@ -117,20 +154,29 @@ TachometerSettings;
typedef struct
{
char* portdev;
char* config_file;
MotorPosition motorsposition;
int numlights;
int numleds;
int startled;
int endled;
float ampfactor;
int baud;
}
SerialDeviceSettings;
typedef struct
{
int frequency;
int volume;
uint32_t frequency;
uint32_t volume;
int lowbound_frequency;
int upperbound_frequency;
uint32_t frequencyMax;
int pan;
int channels;
double duration;
char* dev;
SoundEffectModulationType modulation;
}
SoundDeviceSettings;
@@ -145,13 +191,16 @@ USBDeviceSettings;
typedef struct
{
bool is_valid;
int fps;
DeviceType dev_type;
DeviceSubType dev_subtype;
DeviceSubSubType dev_subsubtype;
// to get really fancy move the effect information to it's own structure that would be a member of
// any device settings member structure that can carry an effect
VibrationEffectType effect_type;
MonocoqueTyreIdentifier tyre;
double threshold;
bool has_config;
// union?
TachometerSettings tachsettings;
SerialDeviceSettings serialdevsettings;
@@ -167,6 +216,17 @@ int devsetup(const char* device_type, const char* device_subtype, const char* co
int settingsfree(DeviceSettings ds);
int monocoquesettingsfree(MonocoqueSettings* ms);
int strcicmp(char const *a, char const *b);
int getconfigtouse2(const char* config_file_str, char* car, int sim);
int getconfigtouse1(const char* config_file_str, char* car, int sim);
int getconfigtouse(const char* config_file_str, char* car, int sim);
int configcheck(const char* config_file_str, int confignum, int* devices);
int uiloadconfig(const char* config_file_str, int confignum, int configureddevices, MonocoqueSettings* ms, DeviceSettings* ds);
int getNumberOfConfigs(const char* config_file_str);
#endif
+88 -19
View File
@@ -13,6 +13,36 @@
#include <string.h>
void create_dir(char* dir)
{
struct stat st = {0};
if (stat(dir, &st) == -1)
{
mkdir(dir, 0700);
}
}
void create_xdg_dir(const char* dir)
{
struct stat st = {0};
if (stat(dir, &st) == -1)
{
mkdir(dir, 0700);
}
}
char* create_user_dir(char* home_dir_str, const char* dirtype, const char* programname)
{
// +3 for slashes
size_t ss = (4 + strlen(home_dir_str) + strlen(dirtype) + strlen(programname));
char* config_dir_str = malloc(ss);
snprintf (config_dir_str, ss, "%s/%s/%s/", home_dir_str, dirtype, programname);
create_dir(config_dir_str);
return config_dir_str;
}
char* gethome()
{
char* homedir = getenv("HOME");
@@ -175,28 +205,67 @@ void restrict_folders_to_cache(char* path, int cachesize)
}
bool does_directory_exist(char* path, char* dirname)
bool does_directory_exist(char* path)
{
struct dirent* de;
DIR* dr = opendir(path);
if (dr == NULL)
DIR* dir = opendir(path);
if (dir)
{
printf("Could not open current directory");
// Directory exists
closedir(dir);
return true;
}
else
{
// Directory does not exist or cannot be opened
return false;
}
// Refer http://pubs.opengroup.org/onlinepubs/7990989775/xsh/readdir.html
bool answer = false;
while ((de = readdir(dr)) != NULL)
{
if (strcmp(dirname,de->d_name) == 0)
{
answer = true;
}
}
closedir(dr);
return answer;
}
bool does_file_exist(const char* file)
{
if (file == NULL)
{
return false;
}
#if defined(OS_WIN)
#if defined(WIN_API)
// if you want the WinAPI, versus CRT
if (strnlen(file, MAX_PATH+1) > MAX_PATH)
{
// ... throw error here or ...
return false;
}
DWORD res = GetFileAttributesA(file);
return (res != INVALID_FILE_ATTRIBUTES &&
!(res& FILE_ATTRIBUTE_DIRECTORY));
#else
// Use Win CRT
struct stat fi;
if (_stat(file, &fi) == 0)
{
#if defined(S_ISSOCK)
// sockets come back as a 'file' on some systems
// so make sure it's not a socket or directory
// (in other words, make sure it's an actual file)
return !(S_ISDIR(fi.st_mode)) &&
!(S_ISSOCK(fi.st_mode));
#else
return !(S_ISDIR(fi.st_mode));
#endif
}
return false;
#endif
#else
struct stat fi;
if (stat(file, &fi) == 0)
{
#if defined(S_ISSOCK)
return !(S_ISDIR(fi.st_mode)) &&
!(S_ISSOCK(fi.st_mode));
#else
return !(S_ISDIR(fi.st_mode));
#endif
}
return false;
#endif
}
+5 -1
View File
@@ -3,10 +3,14 @@
#include <stdbool.h>
void create_dir(char* dir);
void create_xdg_dir(const char* dir);
char* create_user_dir(char* home_dir_str, const char* dirtype, const char* programpath);
char* gethome();
char* str2md5(const char* str, int length);
bool does_directory_exist(char* path, char* dirname);
bool does_directory_exist(char* path);
void restrict_folders_to_cache(char* path, int cachesize);
void delete_dir(char* path);
bool does_file_exist(const char* file);
#endif
+65 -3
View File
@@ -2,12 +2,39 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <libgen.h>
#include <libconfig.h>
#include <argtable2.h>
#include <regex.h>
int freeparams(Parameters* p)
{
if(p->config_dirpath != NULL)
{
free(p->config_dirpath);
}
if(p->config_filepath != NULL)
{
free(p->config_filepath);
}
if(p->log_filename_str != NULL)
{
free(p->log_filename_str);
}
if(p->log_fullfilename_str != NULL)
{
free(p->log_fullfilename_str);
}
if(p->log_dirname_str != NULL)
{
free(p->log_dirname_str);
}
return 0;
}
ConfigError getParameters(int argc, char** argv, Parameters* p)
{
@@ -17,6 +44,13 @@ ConfigError getParameters(int argc, char** argv, Parameters* p)
p->program_action = 0;
p->max_revs = 0;
p->verbosity_count = 0;
p->fps = 60;
p->udp = false;
p->user_specified_config_file = false;
p->user_specified_log_file = false;
p->user_specified_config_dir = false;
// setup argument handling structures
const char* progname = "monocoque";
@@ -26,11 +60,15 @@ ConfigError getParameters(int argc, char** argv, Parameters* p)
struct arg_lit* arg_verbosity3 = arg_litn("v","verbose", 0, 2, "increase logging verbosity");
struct arg_rex* cmd1 = arg_rex1(NULL, NULL, "play", NULL, REG_ICASE, NULL);
struct arg_str* arg_sim = arg_strn("s", "sim", "<gamename>", 0, 1, NULL);
struct arg_lit* arg_udp = arg_lit0("d", "udp", "force udp mode for sims which support it");
struct arg_file* arg_conf = arg_filen(NULL, "uiconf", "<config_file>", 0, 1, NULL);
struct arg_file* arg_log = arg_filen("l", "log", "<log_file>", 0, 1, NULL);
struct arg_str* arg_confdir = arg_strn(NULL, "configdir", "config_dir>", 0, 1, NULL);
struct arg_int* arg_fps = arg_int0("f", "fps", "fps", "main data refresh rate");
struct arg_lit* help = arg_litn(NULL,"help", 0, 1, "print this help and exit");
struct arg_lit* vers = arg_litn(NULL,"version", 0, 1, "print version information and exit");
struct arg_end* end1 = arg_end(20);
void* argtable1[] = {cmd1,arg_sim,arg_verbosity1,help,vers,end1};
void* argtable1[] = {cmd1,arg_log,arg_conf,arg_fps,arg_udp,arg_verbosity1,help,vers,end1};
int nerrors1;
struct arg_rex* cmd2a = arg_rex1(NULL, NULL, "config", NULL, REG_ICASE, NULL);
@@ -83,8 +121,32 @@ ConfigError getParameters(int argc, char** argv, Parameters* p)
if (nerrors1==0)
{
p->program_action = A_PLAY;
p->sim_string = arg_sim->sval[0];
p->verbosity_count = arg_verbosity1->count;
if(arg_conf->count > 0)
{
p->config_filepath = strdup(arg_conf->filename[0]);
p->user_specified_config_file = true;
}
if (arg_udp->count > 0)
{
p->udp = true;
}
if(arg_fps->count > 0)
{
p->fps = arg_fps->ival[0];
}
if(arg_log->count > 0)
{
char* filename = strdup(arg_log->filename[0]);
p->log_fullfilename_str = strdup(arg_log->filename[0]);
p->log_filename_str = strdup(arg_log->basename[0]);
char* dname;
dname = dirname(filename);
p->log_dirname_str = strdup(dname);
p->user_specified_log_file = true;
free(filename);
}
exitcode = E_SUCCESS_AND_DO;
}
else
+14 -1
View File
@@ -9,12 +9,24 @@ typedef struct
int program_action;
const char* sim_string;
const char* save_file;
int fps;
int max_revs;
int granularity;
int verbosity_count;
Simulator sim;
SimulatorAPI sim;
bool simon;
bool udp;
char* config_filepath;
char* config_dirpath;
bool user_specified_config_file;
bool user_specified_config_dir;
bool user_specified_log_file;
char* log_filename_str;
char* log_fullfilename_str;
char* log_dirname_str;
}
Parameters;
@@ -35,6 +47,7 @@ typedef enum
}
ConfigError;
int freeparams(Parameters* p);
ConfigError getParameters(int argc, char** argv, Parameters* p);
struct _errordesc
+126 -120
View File
@@ -2,8 +2,9 @@
#include <stdlib.h>
#include <sys/stat.h>
#include <string.h>
#include <basedir_fs.h>
#include <libconfig.h>
#include "gameloop/gameloop.h"
#include "gameloop/tachconfig.h"
#include "devices/simdevice.h"
@@ -14,27 +15,7 @@
#include "simulatorapi/simapi/simapi/simdata.h"
#include "slog/slog.h"
int create_dir(char* dir)
{
struct stat st = {0};
if (stat(dir, &st) == -1)
{
mkdir(dir, 0700);
}
}
char* create_user_dir(char* dirtype)
{
char* home_dir_str = gethome();
char* config_dir_str = ( char* ) malloc(1 + strlen(home_dir_str) + strlen(dirtype) + strlen("monocoque/"));
strcpy(config_dir_str, home_dir_str);
strcat(config_dir_str, dirtype);
strcat(config_dir_str, "monocoque");
create_dir(config_dir_str);
free(config_dir_str);
}
#define PROGRAM_NAME "monocoque"
void display_banner()
{
@@ -45,10 +26,60 @@ void display_banner()
printf("/_/ /_/ \\____/ /_/ |_/ \\____/ \\____/ \\____/ \\___\\_\\\\____/ /_____/ \n");
}
void SetSettingsFromParameters(Parameters* p, MonocoqueSettings* ms, char* configdir_str, char* cachedir_str)
{
if(p->user_specified_config_file == true && does_file_exist(p->config_filepath))
{
ms->config_str = strdup(p->config_filepath);
}
else
{
if(p->user_specified_config_dir == true && does_directory_exist(p->config_dirpath))
{
asprintf(&ms->config_str, "%s/%s", p->config_dirpath, "monocoque.config");
}
else
{
asprintf(&ms->config_str, "%s%s", configdir_str, "monocoque.config");
}
}
if(p->user_specified_log_file == true && does_file_exist(p->log_fullfilename_str))
{
ms->log_dirname_str = strdup(p->log_dirname_str);
ms->log_filename_str = strdup(p->log_filename_str);
}
else
{
ms->log_dirname_str = strdup(cachedir_str);
ms->log_filename_str = strdup("monocoque.log");
}
ms->fps = p->fps;
ms->verbosity_count = p->verbosity_count;
ms->program_action = A_TEST;
if (p->program_action == A_PLAY)
{
ms->program_action = A_PLAY;
}
if (p->program_action == A_CONFIG_TACH)
{
ms->program_action = A_CONFIG_TACH;
}
}
int main(int argc, char** argv)
{
display_banner();
char* home_dir_str = gethome();
if(home_dir_str == NULL)
{
fprintf(stderr, "You need a home directory");
return 0;
}
Parameters* p = malloc(sizeof(Parameters));
MonocoqueSettings* ms = malloc(sizeof(MonocoqueSettings));;
@@ -57,30 +88,47 @@ int main(int argc, char** argv)
{
goto cleanup_final;
}
ms->program_action = p->program_action;
char* home_dir_str = gethome();
create_user_dir("/.config/");
create_user_dir("/.cache/");
char* config_file_str = ( char* ) malloc(1 + strlen(home_dir_str) + strlen("/.config/") + strlen("monocoque/monocoque.config"));
size_t diameters_file_sz = 1 + strlen(home_dir_str) + strlen("/.config/") + strlen("monocoque/diameters.config");
char* diameters_file_str = ( char* ) malloc(1 + strlen(home_dir_str) + strlen("/.config/") + strlen("monocoque/diameters.json"));
xdgHandle xdg;
if(!xdgInitHandle(&xdg))
{
fprintf(stderr, "Function xdgInitHandle() failed, is $HOME unset?");
}
const char* config_home_str = xdgConfigHome(&xdg);
const char* cache_home_str = xdgCacheHome(&xdg);
char* cachedir_str = NULL;
char* configdir_str = NULL;
if(p->user_specified_config_file == false && p->user_specified_config_dir == false)
{
create_xdg_dir(config_home_str);
configdir_str = create_user_dir(home_dir_str, ".config", PROGRAM_NAME);
}
if(p->user_specified_log_file == false)
{
create_xdg_dir(cache_home_str);
cachedir_str = create_user_dir(home_dir_str, ".cache", PROGRAM_NAME);
}
SetSettingsFromParameters(p, ms, configdir_str, cachedir_str);
freeparams(p);
free(p);
//char* config_file_str = ( char* ) malloc(1 + strlen(home_dir_str) + strlen("/.config/") + strlen("monocoque/monocoque.config"));
size_t diameters_file_sz = snprintf(NULL, 0, "%s/.config/monocoque/diameters.config", home_dir_str);
diameters_file_sz += 1;
char* diameters_file_str = ( char* ) malloc(diameters_file_sz);
snprintf(diameters_file_str, diameters_file_sz, "%s/.config/monocoque/diameters.config", home_dir_str);
char* cache_dir_str = ( char* ) malloc(1 + strlen(home_dir_str) + strlen("/.cache/monocoque/"));
strcpy(config_file_str, home_dir_str);
strcat(config_file_str, "/.config/");
strcpy(cache_dir_str, home_dir_str);
strcat(cache_dir_str, "/.cache/monocoque/");
strcat(config_file_str, "monocoque/monocoque.config");
slog_config_t slgCfg;
slog_config_get(&slgCfg);
slgCfg.eColorFormat = SLOG_COLORING_TAG;
slgCfg.eDateControl = SLOG_TIME_ONLY;
strcpy(slgCfg.sFileName, "monocoque.log");
strcpy(slgCfg.sFilePath, cache_dir_str);
strcpy(slgCfg.sFileName, ms->log_filename_str);
strcpy(slgCfg.sFilePath, ms->log_dirname_str);
slgCfg.nTraceTid = 0;
slgCfg.nToScreen = 1;
slgCfg.nUseHeap = 0;
@@ -88,37 +136,38 @@ int main(int argc, char** argv)
slgCfg.nFlush = 0;
slgCfg.nFlags = SLOG_FLAGS_ALL;
slog_config_set(&slgCfg);
if (p->verbosity_count < 2)
if (ms->verbosity_count < 2)
{
slog_disable(SLOG_TRACE);
}
if (p->verbosity_count < 1)
if (ms->verbosity_count < 1)
{
slog_disable(SLOG_DEBUG);
}
ms->tyre_diameter_config = strdup(diameters_file_str);
ms->useconfig = 1;
ms->useconfig = 0;
ms->configcheck = 0;
free(diameters_file_str);
slogi("Loading configuration file: %s", config_file_str);
slogi("Testing monocoque config file: %s", ms->config_str);
slogd("using diameters file %s %i", ms->tyre_diameter_config, ms->configcheck);
config_t cfg;
config_init(&cfg);
config_setting_t* config_devices = NULL;
if (!config_read_file(&cfg, config_file_str))
if (!config_read_file(&cfg, ms->config_str))
{
fprintf(stderr, "%s:%d - %s\n", config_error_file(&cfg), config_error_line(&cfg), config_error_text(&cfg));
goto cleanup_final;
}
else
{
slogi("Openend monocoque configuration file");
config_devices = config_lookup(&cfg, "devices");
}
free(config_file_str);
free(cache_dir_str);
if (p->program_action == A_CONFIG_TACH)
if (ms->program_action == A_CONFIG_TACH)
{
int error = 0;
SimDevice* tachdev = malloc(sizeof(SimDevice));
@@ -165,65 +214,21 @@ int main(int argc, char** argv)
{
int error = 0;
int configureddevices = config_setting_length(config_devices);
int numdevices = 0;
DeviceSettings ds[configureddevices];
slogi("found %i devices in configuration", configureddevices);
int i = 0;
error = MONOCOQUE_ERROR_NONE;
while (i<configureddevices)
{
DeviceSettings settings;
config_setting_t* config_device = config_setting_get_elem(config_devices, i);
const char* device_type;
const char* device_subtype;
const char* device_config_file;
config_setting_lookup_string(config_device, "device", &device_type);
config_setting_lookup_string(config_device, "type", &device_subtype);
config_setting_lookup_string(config_device, "config", &device_config_file);
//slogt("device type: %s", device_type);
//slogt("device sub type: %s", device_subtype);
//slogt("device config file: %s", device_config_file);
if (error == MONOCOQUE_ERROR_NONE)
{
error = devsetup(device_type, device_subtype, device_config_file, ms, &settings, config_device);
}
if (error == MONOCOQUE_ERROR_NONE)
{
numdevices++;
}
ds[i] = settings;
i++;
}
i = 0;
int j = 0;
error = MONOCOQUE_ERROR_NONE;
setupsound();
SimDevice* devices = malloc(numdevices * sizeof(SimDevice));
int initdevices = devinit(devices, configureddevices, ds, ms);
bool pulseaudio = false;
if (p->program_action == A_PLAY)
if (ms->program_action == A_PLAY)
{
ms->useconfig = 1;
slogi("running monocoque in gameloop mode..");
//error = strtogame(p->sim_string, ms);
//if (error != MONOCOQUE_ERROR_NONE)
//{
// goto cleanup_final;
//}
#ifdef USE_PULSEAUDIO
pa_threaded_mainloop_unlock(mainloop);
pulseaudio = true;
#endif
error = looper(devices, numdevices, p);
//error = looper(devices, numdevices, p);
error = monocoque_mainloop(ms);
if (error == MONOCOQUE_ERROR_NONE)
{
slogi("Game loop exited succesfully with error code: %i", error);
@@ -242,7 +247,25 @@ int main(int argc, char** argv)
pulseaudio = true;
#endif
error = tester(devices, numdevices);
ms->useconfig = 0;
int configs = getNumberOfConfigs(ms->config_str);
int confignum = getconfigtouse(ms->config_str, "default", configs-1);
int configureddevices;
configcheck(ms->config_str, confignum, &configureddevices);
DeviceSettings* ds = malloc(configureddevices * sizeof(DeviceSettings));
slogd("loading confignum %i, with %i devices.", confignum, configureddevices);
int numdevices = uiloadconfig(ms->config_str, confignum, configureddevices, ms, ds);
SimDevice* simdevices = malloc(numdevices * sizeof(SimDevice));
int initdevices = devinit(simdevices, configureddevices, ds, ms);
for( int i = 0; i < configureddevices; i++)
{
settingsfree(ds[i]);
}
free(ds);
error = tester(simdevices, numdevices);
if (error == MONOCOQUE_ERROR_NONE)
{
slogi("Test exited succesfully with error code: %i", error);
@@ -251,43 +274,26 @@ int main(int argc, char** argv)
{
sloge("Test exited with error code: %i", error);
}
}
for (int x = 0; x < numdevices; x++)
{
if (devices[x].initialized == true)
for (int x = 0; x < numdevices; x++)
{
devices[x].free(&devices[x]);
if (simdevices[x].initialized == true)
{
simdevices[x].free(&simdevices[x]);
}
}
}
if(pulseaudio == true)
{
freesound();
}
i = 0;
// improve the api around the config helper
// i don't like that i stack allocated but hid a malloc inside
for( i = 0; i < configureddevices; i++)
{
settingsfree(ds[i]);
}
}
configcleanup:
config_destroy(&cfg);
cleanup_final:
if(ms->tyre_diameter_config != NULL)
{
free(ms->tyre_diameter_config);
}
monocoquesettingsfree(ms);
free(ms);
free(p);
exit(0);
}
@@ -5,11 +5,17 @@ set(simulatorapi_source_files
simapi/simapi/test.h
simapi/include/acdata.h
simapi/include/rf2data.h
simapi/include/pcars2data.h
simapi/include/scs2data.h
simapi/simmap/basicmap.h
simapi/simmap/mapacdata.c
simapi/simmap/mapacdata.h
simapi/simapi/ac.h
simapi/simapi/rf2.h
simapi/simapi/pcars2.h
simapi/simapi/scs2.h
simapi/simapi/getpid.c
simapi/simapi/getpid.h
)
add_library(simulatorapi STATIC ${simulatorapi_source_files})
+20
View File
@@ -0,0 +1,20 @@
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <sys/shm.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <errno.h>
void display(char* prog, char* bytes, int n);
int main(void)
{
const char* name = "acpmf_physics"; // file name
shm_unlink(name);
}
+87 -32
View File
@@ -2,21 +2,15 @@
#include <stdlib.h>
#include <unistd.h>
#include <libserialport.h>
#include "../src/monocoque/simulatorapi/simapi/simapi/simdata.h"
#include "../src/arduino/shiftlights/shiftlights.h"
/* Helper function for error handling. */
int check(enum sp_return result);
int main()
{
SimData sd;
sd.maxrpm = 6500;
sd.rpms = 0;
sd.altitude = 10;
sd.gear = 1;
sd.velocity = 74;
char* port_name = "/dev/ttyACM0";
char* port_name = "/dev/simdev0";
/* The ports we will use. */
struct sp_port* port;
@@ -28,50 +22,111 @@ int main()
printf("Opening port.\n");
check(sp_open(port, SP_MODE_READ_WRITE));
printf("Setting port to 9600 8N1, no flow control.\n");
check(sp_set_baudrate(port, 9600));
printf("Setting port to 115200 8N1, no flow control.\n");
check(sp_set_baudrate(port, 115200));
check(sp_set_bits(port, 8));
check(sp_set_parity(port, SP_PARITY_NONE));
check(sp_set_stopbits(port, 1));
check(sp_set_flowcontrol(port, SP_FLOWCONTROL_NONE));
while ( sd.rpms <= sd.maxrpm )
ShiftLightsData sd;
size_t bufsize1 = 11;
size_t recv_bufsize1 = 5;
char recv_buf1[recv_bufsize1];
char bytes1[bufsize1];
for(int j = 0; j < bufsize1; j++)
{
bytes1[j] = 0x00;
}
bytes1[0] = 0xff;
bytes1[1] = 0xff;
bytes1[2] = 0xff;
bytes1[3] = 0xff;
bytes1[4] = 0xff;
bytes1[5] = 0xff;
bytes1[6] = 0x6c;
bytes1[7] = 0x65;
bytes1[8] = 0x64;
bytes1[9] = 0x73;
bytes1[10] = 0x63;
int result = 0;
unsigned int timeout = 2000;
result = check(sp_blocking_write(port, &bytes1, bufsize1, timeout));
result = check(sp_blocking_read(port, &recv_buf1, recv_bufsize1, timeout));
char numstr[recv_bufsize1];
for(int j = 0; j < recv_bufsize1; j++)
{
numstr[j] = '\0';
}
for(int j = 0; j < recv_bufsize1; j++)
{
printf("%02x\n", recv_buf1[j]);
if(recv_buf1[j] != 0 && recv_buf1[j] != 0x0d && recv_buf1[j] != 0x0a)
{
numstr[j] = recv_buf1[j];
}
}
int numlights = atoi(numstr);
printf("numlights is %s %i\n", numstr, numlights);
//printf("%x\n", recv_buf[0]);
//printf("%x\n", recv_buf[1]);
//printf("%x\n", recv_buf[2]);
//printf("%x\n", recv_buf[3]);
//printf("%x\n", recv_buf[4]);
size_t bufsize = (numlights * 3) + 14;
char bytes[bufsize];
for(int j = 0; j < bufsize; j++)
{
bytes[j] = 0x00;
}
bytes[0] = 0xff;
bytes[1] = 0xff;
bytes[2] = 0xff;
bytes[3] = 0xff;
bytes[4] = 0xff;
bytes[5] = 0xff;
bytes[6] = 0x73;
bytes[7] = 0x6c;
bytes[8] = 0x65;
bytes[9] = 0x64;
bytes[10] = 0x73;
bytes[bufsize-1] = 0xfd;
bytes[bufsize-2] = 0xfe;
bytes[bufsize-3] = 0xff;
unsigned int timeout = 2000;
/* On success, sp_blocking_write() and sp_blocking_read()
* return the number of bytes sent/received before the
* timeout expired. We'll store that result here. */
int result;
int size = sizeof(SimData);
for( int i = 0; i < numlights; i++)
{
bytes[(i * 3) + 11 + 1] = 0xff;
/* Send data. */
result = check(sp_blocking_write(port, &sd, size, timeout));
result = check(sp_blocking_write(port, &bytes, bufsize, timeout));
/* Check whether we sent all of the data. */
if (result == size)
if (result == bufsize)
{
printf("Sent %d bytes successfully, %i rpm.\n", size, sd.rpms);
printf("Sent %d bytes successfully, %i lit leds.\n", bufsize, numlights);
}
else
{
printf("Timed out, %d/%d bytes sent.\n", result, size);
printf("Timed out, %d/%d bytes sent.\n", result, bufsize);
}
sd.rpms += 1000;
if ( sd.rpms == sd.maxrpm + 1000 )
{
sd.rpms = 0;
}
if ( sd.rpms > sd.maxrpm )
{
sd.rpms = sd.maxrpm;
}
sleep(1);
sleep(2);
}
for( int i = 0; i < numlights; i++)
{
bytes[(i * 3) + 11 + 1] = 0x00;
}
result = check(sp_blocking_write(port, &bytes, bufsize, timeout));
check(sp_close(port));
sp_free_port(port);
+47
View File
@@ -0,0 +1,47 @@
# Maintainer: Paul Jones <paul@spacefreak18.xyz>
_reponame=monocoque
pkgname=monocoque-git
pkgver=0.1.0r94
pkgrel=2
pkgdesc="Device Manager for Racing Sims"
arch=('x86_64')
url="https://github.com/spacefreak18/monocoque"
license=('GPL3')
depends=(
hidapi
libserialport
libxml2
argtable
libconfig
libpulse
libxdg-basedir
libuv
)
makedepends=(
git
cmake
)
source=(
git+https://github.com/spacefreak18/monocoque
)
sha256sums=(
'SKIP'
)
pkgver() {
cd "$srcdir/$_reponame"
git describe --long --tags | cut -d "-" -f 1-2 | tr "-" "r"
}
package() {
cd "$srcdir/$_reponame" || exit 1
git submodule sync --recursive
git submodule update --init --recursive
mkdir -p build
cd build
cmake -DUSE_PULSEAUDIO=yes ..
make
mkdir -p "${pkgdir}/usr/bin/"
cp "$srcdir/$_reponame"/build/$_reponame "${pkgdir}/usr/bin/$_reponame"
}
+44
View File
@@ -0,0 +1,44 @@
# Maintainer: Paul Jones <paul@spacefreak18.xyz>
_reponame=monocoque
pkgname=monocoque
pkgver=0.2.0
pkgrel=4
pkgdesc="Device Manager for Racing Sims"
arch=('x86_64')
url="https://github.com/spacefreak18/monocoque"
license=('GPL3')
_commit=12509e9709871afcb3ae264823b4a7d3c3b71bf7
depends=(
hidapi
libserialport
libxml2
argtable
libconfig
libpulse
libxdg-basedir
libuv
)
makedepends=(
git
cmake
)
source=("git+https://github.com/spacefreak18/monocoque.git#commit=$_commit")
sha256sums=(
'SKIP'
)
package() {
cd "$srcdir/$_reponame" || exit 1
git submodule sync --recursive
git submodule update --init --recursive
mkdir -p build
cd build
cmake -Wno-dev -DUSE_PULSEAUDIO=yes ..
make
mkdir -p "${pkgdir}/usr/bin/"
cp "$srcdir/$_reponame"/build/monocoque "${pkgdir}/usr/bin/monocoque"
install -D -m644 "$srcdir/$_reponame"/LICENSE.rst -t "${pkgdir}/usr/share/licenses/$_reponame"
}