Compare commits

..
218 Commits
Author SHA1 Message Date
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
Paul Dino Jones 5dcc69b2a2 Updated slog dependency 2024-07-17 17:30:00 -04:00
spikerguy f56bf19d17 Add Arduino upload, Test cmd and log location (#6)
* add log, arduino upload and Test

* use correct path

* add haptic nodes

* readme: add haptic and arduino motor connection
2024-07-17 10:14:28 -04:00
Paul Dino Jones dea445cafa Added log statement for ampfactor 2024-07-13 14:46:36 -04:00
Paul Dino Jones db83fc9aca Add ampfactor to control final motor power 2024-07-13 14:21:35 -04:00
Paul Dino Jones 234cf064a3 Add abs brake test 2024-07-13 12:48:05 -04:00
Paul Dino Jones b4742a2a8a Cleanup and fix issue that could cause abs to not work. 2024-07-13 11:36:21 -04:00
Paul Dino Jones befe49fd5c Set the fallback threshold for tyre slip effects to zero 2024-07-13 09:40:27 -04:00
Paul Dino Jones 67e04257ba Update so multiple defined serial haptic effects do not conflict with eachother. 2024-07-13 09:38:00 -04:00
Paul Dino Jones 813308c20f Fix issues with data not being correctly sent to motors for sim haptic. 2024-07-12 20:42:55 -04:00
Paul Dino Jones bfcb578bb1 Fix dumb issues with haptic arduino code. Add tyre slip vibrations to test script. 2024-07-09 17:14:40 -04:00
Paul Dino Jones 793d5b6f16 Add sim haptic arduino logic and config variables 2024-07-09 15:46:51 -04:00
Paul Dino Jones 411c8c5340 Move haptic effect data into it's own structure. 2024-07-03 19:18:39 +00:00
Paul Dino Jones f8237798a7 Add haptic effect to serial haptic device type 2024-07-01 22:45:54 +00:00
Paul Dino Jones dfbd2542b4 Add basic support for arduino haptic motors 2024-07-01 15:23:46 +00:00
Paul Dino Jones 8acd05f4c7 Improve handling of devices referenced in config but not actually able to be used for some reason 2024-06-27 20:20:13 +00:00
Paul Dino Jones 0df46cff76 Refactor diameter save file into libconfig to save a dependency. 2024-06-11 16:42:29 -04:00
Paul Dino Jones 1e1dbb9f2e Updated config file example 2024-06-11 10:53:26 -04:00
Paul Dino Jones 16b81fcc98 Send string around for diameters file 2024-06-11 14:41:30 +00:00
Paul Dino Jones 92f48d3bb0 Fix some issues with pulseaudio not stopping properly. 2024-06-11 14:29:09 +00:00
Paul Dino Jones 9a576ed19d Add support for save file for tyre diameters 2024-06-10 00:46:11 +00:00
Paul Dino Jones 424c691b2a Update to latest simapi 2024-06-10 00:45:21 +00:00
Paul Dino Jones 676fb8047f Initialize tyre diameters 2024-06-10 00:44:51 +00:00
Paul Dino Jones 1d49673804 Remove need to specify values for usb pedal rumble effects. 2024-06-07 17:40:53 +00:00
Paul Dino Jones c846e7517b Add attempt at ABS effect. Small refactorings 2024-06-07 04:21:08 +00:00
Paul Dino Jones 4c3318bfe8 Use correct sysfs path for csl elite v3 pedals 2024-06-07 03:02:53 +00:00
Paul Dino Jones fdf06503db Refactor implementation of CSL Elite V3 Pedals 2024-06-06 21:42:08 +00:00
Paul Dino Jones 0e4bac6885 Refactor tyre effects to take threshold input from config file. Spell threshold correctly. 2024-06-05 04:21:39 +00:00
Paul Dino Jones 5744276a94 Update valgrindrc to ignore libs outside project 2024-06-05 04:20:23 +00:00
Paul Dino Jones f393327a87 Refactor effects into separate module 2024-06-05 03:43:48 +00:00
Paul Dino Jones 2f8b40be9f Refactored tyre slip calculations 2024-06-03 18:42:16 -04:00
Paul Dino Jones 05da884e6b Update to latest simapi to support new tyre slip calculations. 2024-06-03 18:40:50 -04:00
Paul Dino Jones bd6176fbcb Cleanup tyre locking implementation 2024-06-01 18:07:37 +00:00
Paul Dino Jones 7ca5371bf2 Implement tyre locking. Cleanup test gameloop 2024-05-30 20:39:47 +00:00
Paul Dino Jones f62a67c778 Update to latest submodule 2024-05-30 18:27:41 +00:00
Paul Dino Jones 364d4be558 Fix tachometer config error handling 2024-05-30 18:25:47 +00:00
Paul Dino Jones d7498e86cb Fix wheel slip calculations 2024-05-30 18:03:26 +00:00
Paul Dino Jones e3a98b6284 Fix compilation error on portaudio codepath 2024-05-30 17:25:07 +00:00
Paul Dino Jones 1b2256abce Add usbhaptic support 2024-05-30 17:07:44 +00:00
Paul Dino Jones 30f34a5d8f Add wheelslip and abs to test loop 2024-05-28 16:12:48 +00:00
Paul Dino Jones d6ef631d06 Updated to latest simapi 2024-03-09 13:39:12 -05:00
Paul Dino Jones d4f32881ab Updated to latest simapi 2024-03-09 13:36:18 -05:00
Paul Dino Jones 3863acde71 Fix wrong data type for velocity 2024-03-05 17:23:29 -05:00
Paul Dino Jones fb1925be2d Fix compilation issue for wheel slip 2024-03-05 00:36:34 -05:00
Paul Dino Jones 83ffb32a2d Fix compilation issues for arduino devices 2024-03-05 00:34:29 -05:00
Paul Dino Jones 6963c377dc Refactored serial arduino devices. Created custom structs for sending data to arduino devices. 2024-03-05 04:51:49 +00:00
Paul Dino Jones 4cb5ecf4f4 Added preliminary support for tyre slip and abs vibrations 2024-02-29 19:19:57 +00:00
Paul Dino Jones 0ca123d027 Fixed simapi version 2024-02-28 14:10:13 -05:00
Paul Dino Jones 3acf5eb716 Add makefiles for arduino and related documentation 2024-02-27 17:36:02 -05:00
Paul Dino Jones 44d954ca2d Fixed signal handleing 2024-02-26 22:05:41 +00:00
Paul Dino Jones a2ede0d210 Add more user variables in arduino code 2024-02-17 18:50:57 +00:00
Paul Dino Jones eb28208eb1 Updated to latest simapi for wheel slip and abs 2024-02-16 16:16:26 +00:00
Paul Dino Jones b6bd2659d0 Slight refactor of detecting running sim 2024-01-02 19:25:11 +00:00
Paul Dino Jones c79e0a557f Fix latency on pulseaudio backend 2023-11-14 15:31:44 +00:00
Paul Dino Jones cd1e56f70e Add basic info for pulseaudio backend into readme 2023-11-13 07:50:10 +00:00
Paul Dino Jones 215a25df06 Updated config for new pulseaudio backend 2023-11-13 07:46:04 +00:00
Paul Dino Jones f81972fbb1 Fix possible causes of leaks and segfaults 2023-11-12 13:27:17 -05:00
Paul Dino Jones 22a72d4b0c Adding pulseaudio backend 2023-11-11 18:19:39 +00:00
Paul Dino Jones c673bb128d Improve game detection in gameloop 2023-10-12 05:26:55 +00:00
Paul Dino Jones 8705f76f61 Update to latest simapi to fix compilation issue 2023-10-11 15:57:55 +00:00
Paul Dino Jones 3e71340dd8 Updated to latest simapi for ACC Support and more RFactor2 support 2023-10-07 19:38:03 +00:00
Paul Dino Jones d2378eed35 Updating to latest simapi for RFactor2 fixes. 2023-10-01 15:03:19 +00:00
Paul Dino Jones ed0900024e Updating to latest simapi to support RFactor2 detection. 2023-09-29 21:26:03 +00:00
condaatje 2b2ca79875 Update README.md
remove workaround in favour of default success
2023-09-29 12:14:08 -04:00
condaatje d76df2f3d3 Update .gitmodules
ssh -> https gitmodule
2023-09-29 12:12:47 -04:00
condaatje 79bbfcc70e add workaround for microsoft ssh clone requirements 2023-09-21 10:06:48 -04:00
Paul Dino Jones 96f59417ab Updating to latest simapi. Updating arduino sketches. Creating simlinks to simdata accordingly. 2023-07-17 03:42:34 +00:00
Paul Dino Jones 0d904a30da Use new simapi to get sim automatically. Use light version of simapi 2023-07-14 22:11:01 +00:00
Paul Dino Jones 3a3e1f9932 Updated to simapi fix for simstatus 2023-07-14 20:36:27 +00:00
Paul Dino Jones 1c8417552a Updated to new release of simapi 2023-07-14 20:18:24 +00:00
Paul Dino Jones 87f83999f6 Updated README 2023-05-17 16:00:26 +00:00
Paul Dino Jones 62790e4a65 Major refactor. Adding sim wind 2023-05-17 15:56:57 +00:00
Paul Dino Jones 5baadb43e2 Added static analysis 2022-12-23 22:43:37 +00:00
Paul Dino Jones 87d7552779 Moved to GPLv3 2022-12-23 22:42:37 +00:00
Paul Dino Jones 0ae55221a5 Updated README 2022-12-19 15:02:41 -05:00
Paul Dino Jones fa91c97ae8 Removed memcpy calls for better performance 2022-12-19 15:01:55 -05:00
Paul Dino Jones 9c195c87ac Initial RFactor support 2022-12-01 21:36:55 +00:00
Paul Dino Jones 1a79c6b7b4 Updated readme 2022-12-01 21:27:57 +00:00
Paul Dino Jones 6335e6dbe1 Display zeros and cleanup gameloop output 2022-12-01 21:25:26 +00:00
Paul Dino Jones 1d8a23c491 monocoque initial commit 2022-10-31 15:11:02 +00:00
89 changed files with 6311 additions and 1347 deletions
+2
View File
@@ -1,3 +1,5 @@
/build
/src/monocoque/tags
/src/monocoque/simulatorapi/simapi
.vscode
+1
View File
@@ -1,3 +1,4 @@
[submodule "src/monocoque/simulatorapi/simapi"]
path = src/monocoque/simulatorapi/simapi
url = https://github.com/spacefreak18/simapi
# url = git@github.com:spacefreak18/simapi # ssh is better but Microsoft requires an account
+12
View File
@@ -107,3 +107,15 @@
...
...
}
{
ignore_unversioned_libs
Memcheck:Leak
...
obj:*/lib*/lib*.so
}
{
ignore_versioned_libs
Memcheck:Leak
...
obj:*/lib*/lib*.so.*
}
+66 -58
View File
@@ -20,74 +20,82 @@ 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 hidapi-hidraw pulse serialport xml2 argtable2 config gameloop helper devices slog simulatorapi uv xdg-basedir)
else()
message("Using portaudio backend...")
target_link_libraries(monocoque m hidapi-hidraw portaudio serialport xml2 argtable2 config gameloop helper devices slog simulatorapi uv xdg-basedir)
endif()
target_include_directories(monocoque PUBLIC config ${LIBXML_INCLUDE_DIR})
add_subdirectory(src/monocoque/gameloop)
add_subdirectory(src/monocoque/simulatorapi)
add_subdirectory(src/monocoque/helper)
add_subdirectory(src/monocoque/devices)
add_subdirectory(src/monocoque/slog)
add_executable(monocoque src/monocoque/monocoque.c)
target_include_directories(monocoque PUBLIC config ${LIBUSB_INCLUDE_DIR} ${LIBXML_INCLUDE_DIR})
target_link_libraries(monocoque m ${LIBUSB_LIBRARY} hidapi-libusb portaudio serialport xml2 argtable2 config gameloop helper devices slog simulatorapi)
#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(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(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)
+109 -9
View File
@@ -9,26 +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.
- 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)
- 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)
- [wine-linux-shm-adapter](https://github.com/spacefreak18/wine-linux-shm-adapter)
- [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:
@@ -36,13 +59,81 @@ This code depends on the shared memory data headers in the simapi [repo](https:/
git submodule sync --recursive
git submodule update --init --recursive
```
Then to compile simply:
```
mkdir build; cd build
cmake ..
make
```
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
Currently Monocoque supports simwind and shiftlights through the included arduino sketches which have been tested on Uno boards. The simwind controller requires a Motor shield.
There are included Makefiles for each controller. For now, the makefiles expect the device to be attached at /dev/ttyACM0. So unplug both controllers, and then plug in just the
controller you're updating to ensure the correct controller is at /dev/ttyACM0.
To compile and upload these sketches, the Makefiles use arduino-cli. Unfortunately it seems some distributions such as debian do not include this in the repositories. If this is
the case follow the install instructions here:
```
https://arduino.github.io/arduino-cli/0.35/installation/
```
You may have to download the core libraries, it will prompt you to do so if you do not have them and you go further
```
arduino-cli core install arduino:avr
```
Then for shiftlights navigate to included shiftlight directory ( be sure only the shiftlight controller is plugged into the machine and is available at /dev/ttyACM0 ) and
```
arduino-cli lib install FastLED
make
```
Then for simwind navigate to the included simwind directory ( be sure only the simwind controller is plugged into the machine and is available at /dev/ttyACM0 ) and
```
ARDUINO_LIBRARY_ENABLE_UNSAFE_INSTALL=true arduino-cli lib install --git-url https://github.com/adafruit/Adafruit_Motor_Shield_V2_Library.git
ARDUINO_LIBRARY_ENABLE_UNSAFE_INSTALL=true arduino-cli lib install --git-url https://github.com/adafruit/Adafruit_BusIO.git
make
```
### Uploading sketch to Arduino Uno
```
cd ../src/arduino/{simwind/shiftlights/simhaptic} # Depending on the controller you have.
make # Make sure serial connection is the same as on the host pc and it have the right group permission to access the device without root
```
### 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
```
./monocoque test -vv # Make sure that ~/.config/monocque/monocoque.config only contains the devices you have connected.
```
### Static Analysis
```
@@ -51,16 +142,25 @@ make
cmake -Danalyze=on ..
make
```
### Valgrind
```
cd build
valgrind -v --leak-check=full --show-leak-kinds=all --suppressions=../.valgrindrc ./monocoque play
```
### 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
- handling null mallocs
- move config code around
- cleanup tests which are basically just copies of the example from their respective projects
- much, much more
+68 -15
View File
@@ -1,15 +1,68 @@
devices = ( { device = "USB";
type = "Tachometer";
devid = "98FD:83AC";
subtype = "Revburner";
granularity = 4;
config = "/home/paul/.config/monocoque/revburner1.xml"; },
{ device = "Sound";
type = "Shaker"
devid = "98FD:83AC";
config = "shaker1.config"; },
{ device = "Serial";
type = "ShiftLights";
config = "None";
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";}
);
});
-95
View File
@@ -1,95 +0,0 @@
#include <FastLED.h>
#include "../../monocoque/simulatorapi/simdata.h"
#define BYTE_SIZE sizeof(SimData)
#define LED_PIN 7
#define NUM_LEDS 6
#define BRIGHTNESS 40
CRGB leds[NUM_LEDS];
SimData sd;
int maxrpm = 0;
int rpm = 0;
int numlights = NUM_LEDS;
int pin = LED_PIN;
int lights[6];
void setup()
{
Serial.begin(9600);
FastLED.addLeds<WS2812, LED_PIN, GRB>(leds, NUM_LEDS);
FastLED.setMaxPowerInVoltsAndMilliamps(5, 500);
FastLED.setBrightness(BRIGHTNESS);
for (int i = 0; i < numlights; i++)
{
leds[i] = CRGB ( 0, 0, 0);
lights[i] = 0;
}
FastLED.clear();
sd.rpms = 0;
sd.maxrpm = 6500;
sd.altitude = 10;
sd.pulses = 40000;
sd.velocity = 10;
}
void loop()
{
int l = 0;
char buff[BYTE_SIZE];
if (Serial.available() >= BYTE_SIZE)
{
Serial.readBytes(buff, BYTE_SIZE);
memcpy(&sd, &buff, BYTE_SIZE);
rpm = sd.rpms;
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));
}
l = 0;
FastLED.clear();
while (l < numlights)
{
if (l >= numlights / 2)
{
leds[l] = CRGB ( 0, 0, 255);
}
if (l < numlights / 2)
{
leds[l] = CRGB ( 0, 255, 0);
}
if (l == numlights - 1)
{
leds[l] = CRGB ( 255, 0, 0);
}
if (lights[l] <= 0)
{
leds[l] = CRGB ( 0, 0, 0);
}
FastLED.show();
l++;
}
}
@@ -1,93 +0,0 @@
#include <FastLED.h>
#include "../../monocoque/simulatorapi/simdata.h"
#define BYTE_SIZE sizeof(SimData)
#define LED_PIN 7
#define NUM_LEDS 6
CRGB leds[NUM_LEDS];
SimData sd;
int maxrpm = 0;
int rpm = 0;
int numlights = NUM_LEDS;
int pin = LED_PIN;
int lights[6];
void setup() {
Serial.begin(9600);
FastLED.addLeds<WS2812, LED_PIN, GRB>(leds, NUM_LEDS);
FastLED.setMaxPowerInVoltsAndMilliamps(5, 500);
FastLED.setBrightness(40);
for (int i = 0; i < numlights; i++)
{
leds[i] = CRGB ( 0, 0, 0);
lights[i] = 0;
}
FastLED.clear();
sd.rpms = 0;
sd.maxrpm = 6500;
sd.altitude = 10;
sd.pulses = 40000;
sd.velocity = 10;
}
void loop() {
int l = 0;
char buff[BYTE_SIZE];
if (Serial.available() >= BYTE_SIZE) {
Serial.readBytes(buff, BYTE_SIZE);
memcpy(&sd, &buff, BYTE_SIZE);
rpm = sd.rpms;
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));
}
l = 0;
FastLED.clear();
while (l < numlights)
{
if (l >= numlights / 2)
{
leds[l] = CRGB ( 0, 0, 255);
}
if (l < numlights / 2)
{
leds[l] = CRGB ( 0, 255, 0);
}
if (l == numlights - 1)
{
leds[l] = CRGB ( 255, 0, 0);
}
if (lights[l] <= 0)
{
leds[l] = CRGB ( 0, 0, 0);
}
FastLED.show();
l++;
}
}
+166
View File
@@ -0,0 +1,166 @@
# Makefile for Arduino based scketches
#
# Copyright 2020 Valerio Di Giampietro http://va.ler.io v@ler.io
# MIT License - see License.txt file
#
# This Makefile uses the arduino-cli, the Arduino command line interface
# and has been designed and tested to run on Linux, not on Windows.
# Probably it will run on a Mac, but it has not been tested.
#
# Please note that:
#
# 1. each sketch must reside in his own folder with this Makefile
#
# 2. the main make targets are:
# - all compiles and upload
# - compile compiles only
# - upload upload via serial port, compile if the binary file is
# not available
# - ota upload Over The Air, automatically find the device
# IP address using the IOT_NAME (device hostname)
# - clean clean the build directory
# - find find OTA updatable devices on the local subnet
# - requirements it the file "requirements.txt" exists it will
# install the libraries listed in this file
#
# default is "all"
#
# 3. it gets the name of the sketch using the wildcard make command;
# the name is *.ino; this means that you must have ONLY a file
# with .ino extension, otherwise this makefile will break. This
# also means that you can use this Makefile, almost unmodified,
# for any sketch as long as you keep a single .ino file in each
# folder
#
# 4. you can split your project in multiple files, if you wish,
# using a single .ino file and multiple .h files, that you can
# include in the .ino file with an '#include "myfile.h"'
# directive
#
# Optionally some environment variables can be set:
#
# FQBN Fully Qualified Board Name; if not set in the environment
# it will be assigned a value in this makefile
#
# SERIAL_DEV Serial device to upload the sketch; if not set in the
# environment it will be assigned:
# /dev/ttyUSB0 if it exists, or
# /dev/ttyACM0 if it exists, or
# unknown
#
# IOT_NAME Name of the IOT device; if not set in the environment
# it will be assigned a value in this makefile. This is
# very useful for OTA update, the device will be searched
# on the local subnet using this name
#
# OTA_PORT Port used by OTA update; if not set in the environment
# it will be assigned the default value of 8266 in this
# makefile
#
# OTA_PASS Password used for OTA update; if not set in the environment
# it will be assigned the default value of an empty string
#
# V verbose flag; can be 0 (quiet) or 1 (verbose); if not set
# in the environment it will be assigned a default value
# in this makefile
MAKE_DIR := $(PWD)
#
# ----- setup wor Wemos D1 mini -----
#FQBN ?= esp8266:esp8266:d1_mini
#IOT_NAME ?= esp8266-meteo
#OTA_PORT ?= 8266
#OTA_PASS ?=
# ----- setup for Arduino Uno
FQBN ?= arduino:avr:uno
# ----- ---------------------
V ?= 0
VFLAG =
ifeq "$(V)" "1"
VFLAG =-v
endif
ifndef SERIAL_DEV
ifneq (,$(wildcard /dev/ttyUSB0))
SERIAL_DEV = /dev/ttyUSB0
else ifneq (,$(wildcard /dev/ttyACM0))
SERIAL_DEV = /dev/ttyACM0
else
SERIAL_DEV = unknown
endif
endif
BUILD_DIR := $(subst :,.,build/$(FQBN))
SRC := $(wildcard *.ino)
HDRS := $(wildcard *.h)
BIN := $(BUILD_DIR)/$(SRC).bin
ELF := $(BUILD_DIR)/$(SRC).elf
$(info FQBN is [${FQBN}])
$(info IOT_NAME is [${IOT_NAME}])
$(info OTA_PORT is [${OTA_PORT}])
$(info OTA_PASS is [${OTA_PASS}])
$(info V is [${V}])
$(info VFLAG is [${VFLAG}])
$(info MAKE_DIR is [${MAKE_DIR}])
$(info BUILD_DIR is [${BUILD_DIR}])
$(info SRC is [${SRC}])
$(info HDRS is [${HDRS}])
$(info BIN is [${BIN}])
$(info SERIAL_DEV is [${SERIAL_DEV}])
all: $(ELF) upload
.PHONY: all
compile: $(ELF)
.PHONY: compile
$(ELF): $(SRC) $(HDRS)
arduino-cli compile -b $(FQBN) $(VFLAG)
@if which arduino-manifest.pl; \
then echo "---> Generating manifest.txt"; \
arduino-manifest.pl -b $(FQBN) $(SRC) $(HDRS) > manifest.txt; \
else echo "---> If you want to generate manifest.txt, listing used libraries and their versions,"; \
echo "---> please install arduino-manifest, see https://github.com/digiampietro/arduino-manifest"; \
fi
upload:
@if [ ! -c $(SERIAL_DEV) ] ; \
then echo "---> ERROR: Serial Device not available, please set the SERIAL_DEV environment variable" ; \
else echo "---> Uploading sketch\n"; \
arduino-cli upload -b $(FQBN) -p $(SERIAL_DEV) $(VFLAG); \
fi
ota:
@PLAT_PATH=`arduino-cli compile -b $(FQBN) --show-properties | grep '^runtime.platform.path' | awk -F= '{print $$2}'` ; \
PY_PATH=`arduino-cli compile -b $(FQBN) --show-properties | grep '^runtime.tools.python3.path' | awk -F= '{print $$2}'` ; \
IOT_IP=`avahi-browse _arduino._tcp --resolve --parsable --terminate|grep -i ';$(IOT_NAME);'|grep ';$(OTA_PORT);'| awk -F\; '{print $$8}'|head -1`; \
BINFILE=$(wildcard $(BUILD_DIR)/$(SRC)*bin); \
echo "PLAT_PATH is [$$PLAT_PATH]" ; \
echo "PY_PATH: is [$$PY_PATH]" ; \
echo "IOT_IP: is [$$IOT_IP]" ; \
echo "BINFILE: is [$$BINFILE]" ; \
if [ "$$IOT_IP" = "" ] ; \
then echo "Unable to find device IP. Check that the IOT_NAME environment variable is correctly set. Use 'make find' to search devices"; \
else echo "---> Uploading Over The Air"; \
$$PY_PATH/python3 $$PLAT_PATH/tools/espota.py -i $$IOT_IP -p $(OTA_PORT) --auth=$(OTA_PASS) -f $$BINFILE ;\
fi
clean:
@echo "---> Cleaning the build directory"
rm -rf build
find:
avahi-browse _arduino._tcp --resolve --parsable --terminate
requirements:
@if [ -e requirements.txt ]; \
then while read -r i ; do echo ; \
echo "---> Installing " '"'$$i'"' ; \
arduino-cli lib install "$$i" ; \
done < requirements.txt ; \
else echo "---> MISSING requirements.txt file"; \
fi
+28
View File
@@ -0,0 +1,28 @@
#ifndef _SHIFTLIGHTSDATA_H
#define _SHIFTLIGHTSDATA_H
#include <stdint.h>
#include <stdbool.h>
typedef struct
{
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;
#endif
+84
View File
@@ -0,0 +1,84 @@
#include <FastLED.h>
#include "shiftlights.h"
#define SIMDATA_SIZE sizeof(ShiftLightsData)
#define LED_PIN 7
#define NUM_LEDS 6
#define BRIGHTNESS 40
#define STARTLED 1
#define COLOR1R 0
#define COLOR1G 255
#define COLOR1B 0
#define COLOR2R 255
#define COLOR2G 255
#define COLOR2B 0
#define COLOR3R 255
#define COLOR3G 0
#define COLOR3B 0
CRGB leds[NUM_LEDS];
ShiftLightsData sd;
int maxrpm = 0;
int rpm = 0;
int numlights = NUM_LEDS;
int pin = LED_PIN;
int lights[NUM_LEDS];
void setup()
{
Serial.begin(115200);
FastLED.addLeds<WS2812, LED_PIN, GRB>(leds, NUM_LEDS);
FastLED.setMaxPowerInVoltsAndMilliamps(5, 500);
FastLED.setBrightness(BRIGHTNESS);
for (int i = 0; i < numlights; i++)
{
leds[i] = CRGB ( 0, 0, 0);
lights[i] = 0;
}
FastLED.clear();
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);
lit = sd.litleds;
}
l = 0;
FastLED.clear();
while (l < lit)
{
if (l >= numlights / 2)
{
leds[l+STARTLED-1] = CRGB ( COLOR2R, COLOR2G, COLOR2B);
}
if (l < numlights / 2)
{
leds[l+STARTLED-1] = CRGB ( COLOR1R, COLOR1G, COLOR1B);
}
if (l == numlights - 1)
{
leds[l+STARTLED-1] = CRGB ( COLOR3R, COLOR3G, COLOR3B);
}
//if (lights[l] <= 0)
//{
// leds[l] = CRGB ( 0, 0, 0);
//}
l++;
}
FastLED.show();
}
+1
View File
@@ -0,0 +1 @@
../../monocoque/simulatorapi/simapi/simapi/simdata.h
+166
View File
@@ -0,0 +1,166 @@
# Makefile for Arduino based scketches
#
# Copyright 2020 Valerio Di Giampietro http://va.ler.io v@ler.io
# MIT License - see License.txt file
#
# This Makefile uses the arduino-cli, the Arduino command line interface
# and has been designed and tested to run on Linux, not on Windows.
# Probably it will run on a Mac, but it has not been tested.
#
# Please note that:
#
# 1. each sketch must reside in his own folder with this Makefile
#
# 2. the main make targets are:
# - all compiles and upload
# - compile compiles only
# - upload upload via serial port, compile if the binary file is
# not available
# - ota upload Over The Air, automatically find the device
# IP address using the IOT_NAME (device hostname)
# - clean clean the build directory
# - find find OTA updatable devices on the local subnet
# - requirements it the file "requirements.txt" exists it will
# install the libraries listed in this file
#
# default is "all"
#
# 3. it gets the name of the sketch using the wildcard make command;
# the name is *.ino; this means that you must have ONLY a file
# with .ino extension, otherwise this makefile will break. This
# also means that you can use this Makefile, almost unmodified,
# for any sketch as long as you keep a single .ino file in each
# folder
#
# 4. you can split your project in multiple files, if you wish,
# using a single .ino file and multiple .h files, that you can
# include in the .ino file with an '#include "myfile.h"'
# directive
#
# Optionally some environment variables can be set:
#
# FQBN Fully Qualified Board Name; if not set in the environment
# it will be assigned a value in this makefile
#
# SERIAL_DEV Serial device to upload the sketch; if not set in the
# environment it will be assigned:
# /dev/ttyUSB0 if it exists, or
# /dev/ttyACM0 if it exists, or
# unknown
#
# IOT_NAME Name of the IOT device; if not set in the environment
# it will be assigned a value in this makefile. This is
# very useful for OTA update, the device will be searched
# on the local subnet using this name
#
# OTA_PORT Port used by OTA update; if not set in the environment
# it will be assigned the default value of 8266 in this
# makefile
#
# OTA_PASS Password used for OTA update; if not set in the environment
# it will be assigned the default value of an empty string
#
# V verbose flag; can be 0 (quiet) or 1 (verbose); if not set
# in the environment it will be assigned a default value
# in this makefile
MAKE_DIR := $(PWD)
#
# ----- setup wor Wemos D1 mini -----
#FQBN ?= esp8266:esp8266:d1_mini
#IOT_NAME ?= esp8266-meteo
#OTA_PORT ?= 8266
#OTA_PASS ?=
# ----- setup for Arduino Uno
FQBN ?= arduino:avr:uno
# ----- ---------------------
V ?= 0
VFLAG =
ifeq "$(V)" "1"
VFLAG =-v
endif
ifndef SERIAL_DEV
ifneq (,$(wildcard /dev/ttyUSB0))
SERIAL_DEV = /dev/ttyUSB0
else ifneq (,$(wildcard /dev/ttyACM0))
SERIAL_DEV = /dev/ttyACM0
else
SERIAL_DEV = unknown
endif
endif
BUILD_DIR := $(subst :,.,build/$(FQBN))
SRC := $(wildcard *.ino)
HDRS := $(wildcard *.h)
BIN := $(BUILD_DIR)/$(SRC).bin
ELF := $(BUILD_DIR)/$(SRC).elf
$(info FQBN is [${FQBN}])
$(info IOT_NAME is [${IOT_NAME}])
$(info OTA_PORT is [${OTA_PORT}])
$(info OTA_PASS is [${OTA_PASS}])
$(info V is [${V}])
$(info VFLAG is [${VFLAG}])
$(info MAKE_DIR is [${MAKE_DIR}])
$(info BUILD_DIR is [${BUILD_DIR}])
$(info SRC is [${SRC}])
$(info HDRS is [${HDRS}])
$(info BIN is [${BIN}])
$(info SERIAL_DEV is [${SERIAL_DEV}])
all: $(ELF) upload
.PHONY: all
compile: $(ELF)
.PHONY: compile
$(ELF): $(SRC) $(HDRS)
arduino-cli compile -b $(FQBN) $(VFLAG)
@if which arduino-manifest.pl; \
then echo "---> Generating manifest.txt"; \
arduino-manifest.pl -b $(FQBN) $(SRC) $(HDRS) > manifest.txt; \
else echo "---> If you want to generate manifest.txt, listing used libraries and their versions,"; \
echo "---> please install arduino-manifest, see https://github.com/digiampietro/arduino-manifest"; \
fi
upload:
@if [ ! -c $(SERIAL_DEV) ] ; \
then echo "---> ERROR: Serial Device not available, please set the SERIAL_DEV environment variable" ; \
else echo "---> Uploading sketch\n"; \
arduino-cli upload -b $(FQBN) -p $(SERIAL_DEV) $(VFLAG); \
fi
ota:
@PLAT_PATH=`arduino-cli compile -b $(FQBN) --show-properties | grep '^runtime.platform.path' | awk -F= '{print $$2}'` ; \
PY_PATH=`arduino-cli compile -b $(FQBN) --show-properties | grep '^runtime.tools.python3.path' | awk -F= '{print $$2}'` ; \
IOT_IP=`avahi-browse _arduino._tcp --resolve --parsable --terminate|grep -i ';$(IOT_NAME);'|grep ';$(OTA_PORT);'| awk -F\; '{print $$8}'|head -1`; \
BINFILE=$(wildcard $(BUILD_DIR)/$(SRC)*bin); \
echo "PLAT_PATH is [$$PLAT_PATH]" ; \
echo "PY_PATH: is [$$PY_PATH]" ; \
echo "IOT_IP: is [$$IOT_IP]" ; \
echo "BINFILE: is [$$BINFILE]" ; \
if [ "$$IOT_IP" = "" ] ; \
then echo "Unable to find device IP. Check that the IOT_NAME environment variable is correctly set. Use 'make find' to search devices"; \
else echo "---> Uploading Over The Air"; \
$$PY_PATH/python3 $$PLAT_PATH/tools/espota.py -i $$IOT_IP -p $(OTA_PORT) --auth=$(OTA_PASS) -f $$BINFILE ;\
fi
clean:
@echo "---> Cleaning the build directory"
rm -rf build
find:
avahi-browse _arduino._tcp --resolve --parsable --terminate
requirements:
@if [ -e requirements.txt ]; \
then while read -r i ; do echo ; \
echo "---> Installing " '"'$$i'"' ; \
arduino-cli lib install "$$i" ; \
done < requirements.txt ; \
else echo "---> MISSING requirements.txt file"; \
fi
+1
View File
@@ -0,0 +1 @@
../../monocoque/simulatorapi/simapi/simapi/simdata.h
+21
View File
@@ -0,0 +1,21 @@
#ifndef _SIMHAPTICDATA_H
#define _SIMHAPTICDATA_H
#include <stdint.h>
#include <stdbool.h>
typedef struct
{
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;
#endif
+81
View File
@@ -0,0 +1,81 @@
#include <Adafruit_MotorShield.h>
#include "simhaptic.h"
#define BYTE_SIZE sizeof(SimHapticData)
#define POWER .6
Adafruit_MotorShield AFMS = Adafruit_MotorShield();
Adafruit_DCMotor *myMotor1 = AFMS.getMotor(1);
//Adafruit_DCMotor *myMotor2 = AFMS.getMotor(2);
Adafruit_DCMotor *myMotor3 = AFMS.getMotor(3);
//Adafruit_DCMotor *myMotor4 = AFMS.getMotor(4);
SimHapticData sd;
int motor1 = 0;
int motor2 = 0;
int motor3 = 0;
int motor4 = 0;
int effect1 = 0;
int effect2 = 0;
int effect3 = 0;
int effect4 = 0;
void setup() {
Serial.begin(9600);
if (!AFMS.begin()) {
Serial.println("Could not find Motor Shield. Check wiring.");
while (1);
}
sd.motor1 = 0;
sd.motor2 = 0;
sd.motor3 = 0;
sd.motor4 = 0;
myMotor1->setSpeed(0);
myMotor1->run(FORWARD);
//myMotor2->setSpeed(0);
//myMotor2->run(FORWARD);
myMotor3->setSpeed(0);
myMotor3->run(FORWARD);
//myMotor4->setSpeed(0);
//myMotor4->run(FORWARD);
}
void loop() {
char buff[BYTE_SIZE];
if (Serial.available() >= BYTE_SIZE)
{
Serial.readBytes(buff, BYTE_SIZE);
memcpy(&sd, &buff, BYTE_SIZE);
motor1 = sd.motor1;
motor2 = sd.motor2;
motor3 = sd.motor3;
motor4 = sd.motor4;
effect1 = sd.effect1;
effect2 = sd.effect2;
effect3 = sd.effect3;
effect4 = sd.effect4;
}
if (motor1 >= 1)
{
myMotor1->setSpeed(effect1);
}
//if (motor2 >= 1)
//{
// myMotor2->setSpeed(effect2);
//}
if (motor3 >= 1)
{
myMotor3->setSpeed(effect3);
}
//if (motor4 >= 1)
//{
// myMotor4->setSpeed(effect4);
//}
}
+166
View File
@@ -0,0 +1,166 @@
# Makefile for Arduino based scketches
#
# Copyright 2020 Valerio Di Giampietro http://va.ler.io v@ler.io
# MIT License - see License.txt file
#
# This Makefile uses the arduino-cli, the Arduino command line interface
# and has been designed and tested to run on Linux, not on Windows.
# Probably it will run on a Mac, but it has not been tested.
#
# Please note that:
#
# 1. each sketch must reside in his own folder with this Makefile
#
# 2. the main make targets are:
# - all compiles and upload
# - compile compiles only
# - upload upload via serial port, compile if the binary file is
# not available
# - ota upload Over The Air, automatically find the device
# IP address using the IOT_NAME (device hostname)
# - clean clean the build directory
# - find find OTA updatable devices on the local subnet
# - requirements it the file "requirements.txt" exists it will
# install the libraries listed in this file
#
# default is "all"
#
# 3. it gets the name of the sketch using the wildcard make command;
# the name is *.ino; this means that you must have ONLY a file
# with .ino extension, otherwise this makefile will break. This
# also means that you can use this Makefile, almost unmodified,
# for any sketch as long as you keep a single .ino file in each
# folder
#
# 4. you can split your project in multiple files, if you wish,
# using a single .ino file and multiple .h files, that you can
# include in the .ino file with an '#include "myfile.h"'
# directive
#
# Optionally some environment variables can be set:
#
# FQBN Fully Qualified Board Name; if not set in the environment
# it will be assigned a value in this makefile
#
# SERIAL_DEV Serial device to upload the sketch; if not set in the
# environment it will be assigned:
# /dev/ttyUSB0 if it exists, or
# /dev/ttyACM0 if it exists, or
# unknown
#
# IOT_NAME Name of the IOT device; if not set in the environment
# it will be assigned a value in this makefile. This is
# very useful for OTA update, the device will be searched
# on the local subnet using this name
#
# OTA_PORT Port used by OTA update; if not set in the environment
# it will be assigned the default value of 8266 in this
# makefile
#
# OTA_PASS Password used for OTA update; if not set in the environment
# it will be assigned the default value of an empty string
#
# V verbose flag; can be 0 (quiet) or 1 (verbose); if not set
# in the environment it will be assigned a default value
# in this makefile
MAKE_DIR := $(PWD)
#
# ----- setup wor Wemos D1 mini -----
#FQBN ?= esp8266:esp8266:d1_mini
#IOT_NAME ?= esp8266-meteo
#OTA_PORT ?= 8266
#OTA_PASS ?=
# ----- setup for Arduino Uno
FQBN ?= arduino:avr:uno
# ----- ---------------------
V ?= 0
VFLAG =
ifeq "$(V)" "1"
VFLAG =-v
endif
ifndef SERIAL_DEV
ifneq (,$(wildcard /dev/ttyUSB0))
SERIAL_DEV = /dev/ttyUSB0
else ifneq (,$(wildcard /dev/ttyACM0))
SERIAL_DEV = /dev/ttyACM0
else
SERIAL_DEV = unknown
endif
endif
BUILD_DIR := $(subst :,.,build/$(FQBN))
SRC := $(wildcard *.ino)
HDRS := $(wildcard *.h)
BIN := $(BUILD_DIR)/$(SRC).bin
ELF := $(BUILD_DIR)/$(SRC).elf
$(info FQBN is [${FQBN}])
$(info IOT_NAME is [${IOT_NAME}])
$(info OTA_PORT is [${OTA_PORT}])
$(info OTA_PASS is [${OTA_PASS}])
$(info V is [${V}])
$(info VFLAG is [${VFLAG}])
$(info MAKE_DIR is [${MAKE_DIR}])
$(info BUILD_DIR is [${BUILD_DIR}])
$(info SRC is [${SRC}])
$(info HDRS is [${HDRS}])
$(info BIN is [${BIN}])
$(info SERIAL_DEV is [${SERIAL_DEV}])
all: $(ELF) upload
.PHONY: all
compile: $(ELF)
.PHONY: compile
$(ELF): $(SRC) $(HDRS)
arduino-cli compile -b $(FQBN) $(VFLAG)
@if which arduino-manifest.pl; \
then echo "---> Generating manifest.txt"; \
arduino-manifest.pl -b $(FQBN) $(SRC) $(HDRS) > manifest.txt; \
else echo "---> If you want to generate manifest.txt, listing used libraries and their versions,"; \
echo "---> please install arduino-manifest, see https://github.com/digiampietro/arduino-manifest"; \
fi
upload:
@if [ ! -c $(SERIAL_DEV) ] ; \
then echo "---> ERROR: Serial Device not available, please set the SERIAL_DEV environment variable" ; \
else echo "---> Uploading sketch\n"; \
arduino-cli upload -b $(FQBN) -p $(SERIAL_DEV) $(VFLAG); \
fi
ota:
@PLAT_PATH=`arduino-cli compile -b $(FQBN) --show-properties | grep '^runtime.platform.path' | awk -F= '{print $$2}'` ; \
PY_PATH=`arduino-cli compile -b $(FQBN) --show-properties | grep '^runtime.tools.python3.path' | awk -F= '{print $$2}'` ; \
IOT_IP=`avahi-browse _arduino._tcp --resolve --parsable --terminate|grep -i ';$(IOT_NAME);'|grep ';$(OTA_PORT);'| awk -F\; '{print $$8}'|head -1`; \
BINFILE=$(wildcard $(BUILD_DIR)/$(SRC)*bin); \
echo "PLAT_PATH is [$$PLAT_PATH]" ; \
echo "PY_PATH: is [$$PY_PATH]" ; \
echo "IOT_IP: is [$$IOT_IP]" ; \
echo "BINFILE: is [$$BINFILE]" ; \
if [ "$$IOT_IP" = "" ] ; \
then echo "Unable to find device IP. Check that the IOT_NAME environment variable is correctly set. Use 'make find' to search devices"; \
else echo "---> Uploading Over The Air"; \
$$PY_PATH/python3 $$PLAT_PATH/tools/espota.py -i $$IOT_IP -p $(OTA_PORT) --auth=$(OTA_PASS) -f $$BINFILE ;\
fi
clean:
@echo "---> Cleaning the build directory"
rm -rf build
find:
avahi-browse _arduino._tcp --resolve --parsable --terminate
requirements:
@if [ -e requirements.txt ]; \
then while read -r i ; do echo ; \
echo "---> Installing " '"'$$i'"' ; \
arduino-cli lib install "$$i" ; \
done < requirements.txt ; \
else echo "---> MISSING requirements.txt file"; \
fi
+1
View File
@@ -0,0 +1 @@
../../monocoque/simulatorapi/simapi/simapi/simdata.h
+15
View File
@@ -0,0 +1,15 @@
#ifndef _SIMWINDDATA_H
#define _SIMWINDDATA_H
#include <stdint.h>
#include <stdbool.h>
typedef struct
{
uint8_t velocity;
uint8_t fanpower;
}
SimWindData;
#endif
+43
View File
@@ -0,0 +1,43 @@
#include <Adafruit_MotorShield.h>
#include "simwind.h"
#define BYTE_SIZE sizeof(SimWindData)
#define KPHTOMPH .621317
#define FANPOWER .6
Adafruit_MotorShield AFMS = Adafruit_MotorShield();
Adafruit_DCMotor *myMotor1 = AFMS.getMotor(1);
Adafruit_DCMotor *myMotor2 = AFMS.getMotor(3);
SimWindData sd;
int velocity = 0;
void setup() {
Serial.begin(9600);
if (!AFMS.begin()) {
Serial.println("Could not find Motor Shield. Check wiring.");
while (1);
}
sd.velocity = 10;
myMotor1->setSpeed(0);
myMotor1->run(FORWARD);
myMotor2->setSpeed(0);
myMotor2->run(FORWARD);
}
void loop() {
char buff[BYTE_SIZE];
if (Serial.available() >= BYTE_SIZE)
{
Serial.readBytes(buff, BYTE_SIZE);
memcpy(&sd, &buff, BYTE_SIZE);
velocity = sd.velocity;
}
myMotor1->setSpeed(velocity*FANPOWER);
myMotor2->setSpeed(velocity*FANPOWER);
}
+21
View File
@@ -7,14 +7,35 @@ 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
hapticeffect.c
sound.h
sound.c
usb/revburner.h
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/moza.h
serial/moza.c
)
include_directories("." "usb" "sound" "serial")
+393
View File
@@ -0,0 +1,393 @@
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.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
#define minspeedinms 0.5
#define minvelocity 50
#define maxbrake 0
#define maxthrottle 0
#define maxXvelocity 0.001
bool hasTyreDiameter(SimData* simdata)
{
if (simdata->tyrediameter[0] == -1 || simdata->tyrediameter[1] == -1 || simdata->tyrediameter[2] == -1 || simdata->tyrediameter[3] == -1)
{
slogt("failed to find tyre diameter data");
return false;
}
slogt("tyre diameter data found");
return true;
}
int loadtyreconfig(SimData* simdata, char* configfile)
{
config_t cfg;
config_init(&cfg);
config_setting_t* config_cars = NULL;
if (!config_read_file(&cfg, configfile))
{
slogw("Could not open diameters save file.");
config_destroy(&cfg);
return 1;
}
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);
if(config_car != NULL)
{
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)
{
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;
}
int savetyreconfig(SimData* simdata, char* configfile)
{
config_t cfg;
config_setting_t* root;
config_setting_t* array;
config_setting_t* carobject;
config_setting_t* setting;
config_init(&cfg);
if (!config_read_file(&cfg, configfile))
{
slogw("Could not open diameters save file, creating new.");
root = config_root_setting(&cfg);
array = config_setting_add(root, "cars", CONFIG_TYPE_LIST);
}
else
{
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);
config_setting_set_float(setting, simdata->tyrediameter[1]);
setting = config_setting_add(carobject, "tyre2", CONFIG_TYPE_FLOAT);
config_setting_set_float(setting, simdata->tyrediameter[2]);
setting = config_setting_add(carobject, "tyre3", CONFIG_TYPE_FLOAT);
config_setting_set_float(setting, simdata->tyrediameter[3]);
/* Write out the new configuration. */
if(! config_write_file(&cfg, configfile))
{
slogi("Error while writing file.");
config_destroy(&cfg);
}
slogi("New configuration successfully written to: %s\n", configfile);
config_destroy(&cfg);
return 0;
}
void getTyreDiameter(SimData* simdata)
{
if(simdata->velocity > minvelocity && simdata->brake <= maxbrake && simdata->gas <= maxthrottle)
{
double Speedms = kmhtoms * simdata->velocity;
if (simdata->Xvelocity/Speedms < maxXvelocity)
{
for(int i = 0; i < 4; i++)
{
simdata->tyrediameter[i] = Speedms / simdata->tyreRPS[i] * 2;
}
slogi("Successfully set tyre diameters for wheel slip effects.");
}
}
}
double slipeffect(SimData* simdata, int effecttype, int tyre, double threshold, int useconfig, int* configcheck, char* configfile)
{
double play = 0;
double wheelslip[4];
wheelslip[0] = 0;
wheelslip[1] = 0;
wheelslip[2] = 0;
wheelslip[3] = 0;
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(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
int error = 0;
if(hasTyreDiameter(simdata)==false && *configcheck == 0)
{
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(hasTyreDiameter(simdata)==true)
{
slogi("saving tyre config");
error = savetyreconfig(simdata, configfile);
}
}
}
if(hasTyreDiameter(simdata)==true)
{
double Speedms = kmhtoms * simdata->velocity;
slogt("attempting wheel slip calculation");
if (Speedms > minspeedinms)
{
for(int i = 0; i < 4; i++)
{
wheelslip[i] = (Speedms - simdata->tyrediameter[i] * simdata->tyreRPS[i] / 2) / Speedms;
}
}
else
{
for(int i = 0; i < 4; i++)
{
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:
slogd("Unknown effect type");
}
if(simdata->Yvelocity <= 0)
{
return 0;
}
if(simdata->Zvelocity > 1 || simdata->Zvelocity < -1)
{
return 0;
}
switch (effecttype)
{
case (EFFECT_TYRESLIP):
if (tyre == FRONTLEFT || tyre == FRONTS || tyre == ALLFOUR)
{
if(wheelslip[0] < -threshold)
{
play += fabs(wheelslip[0]) - fabs(threshold);
slogt("slip is %f", play);
}
}
if (tyre == FRONTRIGHT || tyre == FRONTS || tyre == ALLFOUR)
{
if(wheelslip[1] < -threshold)
{
play += fabs(wheelslip[1]) - fabs(threshold);
slogt("slip is %f", play);
}
}
if (tyre == REARLEFT || tyre == REARS || tyre == ALLFOUR)
{
if(wheelslip[2] < -threshold)
{
play += fabs(wheelslip[2]) - fabs(threshold);
slogt("slip is %f", play);
}
}
if (tyre == REARRIGHT || tyre == REARS || tyre == ALLFOUR)
{
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)
{
if(wheelslip[1] > threshold)
{
play += wheelslip[1] - threshold;
slogt("lock is %f", play);
}
}
if (tyre == REARLEFT || tyre == REARS || tyre == ALLFOUR)
{
if(wheelslip[2] > threshold)
{
play += wheelslip[2] - threshold;
slogt("lock is %f", play);
}
}
if (tyre == REARRIGHT || tyre == REARS || tyre == ALLFOUR)
{
if(wheelslip[3] > threshold)
{
play += wheelslip[3] - threshold;
slogt("lock is %f", play);
}
}
break;
case (EFFECT_ABSBRAKES):
threshold = simdata->abs + threshold;
if (tyre == FRONTLEFT || tyre == FRONTS || tyre == ALLFOUR)
{
if(wheelslip[0] > threshold)
{
play += wheelslip[0] - threshold;
slogt("abs is %f", play);
}
}
if (tyre == FRONTRIGHT || tyre == FRONTS || tyre == ALLFOUR)
{
if(wheelslip[1] > threshold)
{
play += wheelslip[1] - threshold;
slogt("abs is %f", play);
}
}
if (tyre == REARLEFT || tyre == REARS || tyre == ALLFOUR)
{
if(wheelslip[2] > threshold)
{
play += wheelslip[2] - threshold;
slogt("abs is %f", play);
}
}
if (tyre == REARRIGHT || tyre == REARS || tyre == ALLFOUR)
{
if(wheelslip[3] > threshold)
{
play += wheelslip[3] - threshold;
slogt("abs is %f", play);
}
}
if(simdata->abs <= 0)
{
play = 0;
}
break;
}
return play;
}
+21
View File
@@ -0,0 +1,21 @@
#ifndef _HAPTICEFFECT_H
#define _HAPTICEFFECT_H
#include <stdio.h>
#include "../helper/confighelper.h"
#include "../simulatorapi/simapi/simapi/simdata.h"
typedef struct
{
double threshold;
VibrationEffectType effecttype;
MonocoqueTyreIdentifier tyre;
int useconfig;
int* configcheck;
char* tyrediameterconfig;
}
HapticEffect;
double slipeffect(SimData* simdata, int effecttype, int tyre, double threshold, int useconfig, int* configcheck, char* configfile);
#endif
+10 -64
View File
@@ -1,79 +1,25 @@
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include "arduino.h"
#include "../slog/slog.h"
#include "../serialadapter.h"
#include "../../slog/slog.h"
#define arduino_timeout 2000
#define arduino_timeout 5000
int arduino_update(SerialDevice* serialdevice, SimData* simdata)
int arduino_update(SerialDevice* serialdevice, void* data, size_t size)
{
int result = 1;
if (serialdevice->port)
{
result = check(sp_blocking_write(serialdevice->port, simdata, sizeof(SimData), arduino_timeout));
}
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)
int arduino_init(SerialDevice* serialdevice, const char* portdev)
{
slogi("initializing arduino serial device...");
int error = 0;
char* port_name = "/dev/ttyACM0";
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));
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);
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;
}
serialdevice->id = monocoque_serial_open(serialdevice, portdev);
return serialdevice->id;
}
+4 -3
View File
@@ -1,11 +1,12 @@
#ifndef _ARDUINO_H
#define _ARDUINO_H
#include "../simdevice.h"
#include "../serialdevice.h"
int arduino_update(SerialDevice* serialdevice, SimData* simdata);
int arduino_init(SerialDevice* serialdevice);
int arduino_update(SerialDevice* serialdevice, void* data, size_t size);
int arduino_init(SerialDevice* serialdevice, const char* portdev);
int arduino_free(SerialDevice* serialdevice);
int check(enum sp_return result);
#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
+205
View File
@@ -0,0 +1,205 @@
#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_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)
{
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;
}
+28
View File
@@ -0,0 +1,28 @@
#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_open(SerialDevice* serialdevice, const char* port);
int monocoque_serial_free(SerialDevice* serialdevice);
#endif
+351 -10
View File
@@ -2,34 +2,375 @@
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <math.h>
#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/simdata.h"
#include "../simulatorapi/simapi/simapi/simdata.h"
#include "../slog/slog.h"
int serialdev_update(SerialDevice* serialdevice, SimData* simdata)
#define KPHTOMPH .621317
int serial_wheel_update(SimDevice* this, SimData* simdata)
{
arduino_update(serialdevice, simdata);
SerialDevice* serialdevice = (void *) this->derived;
moza_update(serialdevice, simdata->maxrpm, simdata->rpms);
return 0;
}
int serialdev_free(SerialDevice* serialdevice)
int serialdev_update(SimDevice* this, SimData* simdata)
{
arduino_free(serialdevice);
SerialDevice* serialdevice = (void *) this->derived;
arduino_update(serialdevice, simdata, sizeof(SimData));
return 0;
}
int serialdev_init(SerialDevice* serialdevice)
int arduino_shiftlights_update(SimDevice* this, SimData* simdata)
{
slogi("initializing serial device...");
SerialDevice* serialdevice = (void *) this->derived;
int result = 1;
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);
arduino_update(serialdevice, &serialdevice->u.shiftlightsdata, size);
return result;
}
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);
arduino_update(serialdevice, &bytes, size);
return result;
}
int arduino_simwind_update(SimDevice* this, SimData* simdata)
{
SerialDevice* serialdevice = (void *) this->derived;
int result = 1;
// 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 = (int)0.6 * 255;
size_t size = sizeof(SimWindData);
arduino_update(serialdevice, &serialdevice->u.simwinddata, size);
return result;
}
int arduino_simhaptic_update(SimDevice* this, SimData* simdata)
{
SerialDevice* serialdevice = (void *) this->derived;
int result = 1;
slogt("arduino haptic device updating");
double play = slipeffect(simdata, this->hapticeffect.effecttype, this->hapticeffect.tyre, this->hapticeffect.threshold, this->hapticeffect.useconfig, this->hapticeffect.configcheck, this->hapticeffect.tyrediameterconfig);
double rplay = play;
play = play * serialdevice->ampfactor;
if(play > 1.0)
{
play = 1.0;
}
int effectspeed = ceil(255 * play);
int motor = serialdevice->motorsposition;
if (play != serialdevice->state)
{
if (motor == 0 || motor == 4 || motor == 7 || motor == 8 || motor == 10 || motor == 11 || motor == 13 || motor == 14)
{
serialdevice->u.simhapticdata.effect1 = effectspeed;
serialdevice->u.simhapticdata.motor1 = 1;
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 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;
}
size_t size = sizeof(SimHapticData);
arduino_update(serialdevice, &serialdevice->u.simhapticdata, size);
return result;
}
int serialdev_free(SimDevice* this)
{
SerialDevice* serialdevice = (void *) this->derived;
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");
}
monocoque_serial_free(serialdevice);
free(serialdevice);
return 0;
}
int serial_wheel_free(SimDevice* this)
{
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;
error = arduino_init(serialdevice);
serialdevice->motorsposition = ds->serialdevsettings.motorsposition;
serialdevice->baudrate = ds->serialdevsettings.baud;
switch (serialdevice->type)
{
case SERIALDEV_WHEEL:
// the wheel stuff assumed it was a usb
//error = wheeldev_init(&serialdevice->u.wheeldevice, ds);
error = moza_init(serialdevice, ds->serialdevsettings.portdev);
break;
default:
error = arduino_init(serialdevice, ds->serialdevsettings.portdev );
break;
}
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_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) {
SerialDevice* this = (SerialDevice*) malloc(sizeof(SerialDevice));
this->m.update = &update;
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):
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;
slogi("Initializing arduino devices for sim wind.");
break;
case (SIMDEVTYPE_SERIALHAPTIC):
this->devicetype = ARDUINODEV__HAPTIC;
this->m.vtable = &arduino_simhaptic_vtable;
this->u.simhapticdata.motor1 = 0;
this->u.simhapticdata.motor2 = 0;
this->u.simhapticdata.motor3 = 0;
this->u.simhapticdata.motor4 = 0;
this->u.simhapticdata.effect1 = 0;
this->u.simhapticdata.effect2 = 0;
this->u.simhapticdata.effect3 = 0;
this->u.simhapticdata.effect4 = 0;
this->state = 0;
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)
{
this->m.hapticeffect.threshold = ds->threshold;
this->m.hapticeffect.effecttype = ds->effect_type;
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;
}
int error = serialdev_init(this, ds);
if (error < 0)
{
free(this);
return NULL;
}
return this;
}
+7 -17
View File
@@ -2,26 +2,16 @@
#define _SERIALDEVICE_H
#include <libserialport.h>
#include "../helper/parameters.h"
#include "../simulatorapi/simdata.h"
#include "wheeldevice.h"
typedef enum
{
SERIALDEV_UNKNOWN = 0,
SERIALDEV_ARDUINO = 1
ARDUINODEV__SHIFTLIGHTS = 0,
ARDUINODEV__SIMWIND = 1,
ARDUINODEV__HAPTIC = 2,
SERIALDEV__MOZAR5 = 3,
ARDUINODEV__SIMLED = 4
}
SerialType;
typedef struct
{
int id;
SerialType type;
struct sp_port* port;
}
SerialDevice;
int serialdev_update(SerialDevice* serialdevice, SimData* simdata);
int serialdev_init(SerialDevice* serialdevice);
int serialdev_free(SerialDevice* serialdevice);
SerialDeviceType;
#endif
+74 -69
View File
@@ -1,85 +1,90 @@
#include <stdio.h>
#include <stdlib.h>
#include "simdevice.h"
#include "../helper/parameters.h"
#include "../helper/confighelper.h"
#include "../simulatorapi/simdata.h"
#include "../simulatorapi/simapi/simapi/simdata.h"
#include "../slog/slog.h"
int devupdate(SimDevice* simdevice, SimData* simdata)
int update(SimDevice* this, SimData* simdata)
{
if (simdevice->initialized==false)
{
return 0;
}
switch ( simdevice->type )
{
case SIMDEV_USB :
usbdev_update(&simdevice->d.usbdevice, simdata);
break;
case SIMDEV_SOUND :
sounddev_update(&simdevice->d.sounddevice, simdata);
break;
case SIMDEV_SERIAL :
serialdev_update(&simdevice->d.serialdevice, simdata);
break;
}
((vtable*)this->vtable)->update(this, simdata);
}
int simdevfree(SimDevice* this)
{
((vtable*)this->vtable)->free(this);
}
int devupdate(SimDevice* this, SimData* simdata)
{
return 0;
}
int devfree(SimDevice* simdevice)
int devinit(SimDevice* simdevices, int numdevices, DeviceSettings* ds, MonocoqueSettings* ms)
{
slogi("initializing simdevices...");
int devices = 0;
if (simdevice->initialized==false)
for (int j = 0; j < numdevices; j++)
{
slogw("Attempt to free an uninitialized device");
return MONOCOQUE_ERROR_INVALID_DEV;
simdevices[j].initialized = false;
if (ds[j].dev_type == SIMDEV_USB) {
USBDevice* sim = new_usb_device(&ds[j], ms);
if (sim != NULL)
{
simdevices[j] = sim->m;
simdevices[j].initialized = true;
simdevices[j].type = SIMDEV_USB;
simdevices[j].fps = ds[j].fps;
devices++;
}
else
{
slogw("Could not initialize USB Device");
}
}
if (ds[j].dev_type == SIMDEV_SOUND) {
SoundDevice* sim = new_sound_device(&ds[j], ms);
if (sim != NULL)
{
simdevices[j] = sim->m;
simdevices[j].initialized = true;
simdevices[j].type = SIMDEV_SOUND;
simdevices[j].fps = ds[j].fps;
devices++;
}
else
{
slogw("Could not initialize Sound Device");
}
}
if (ds[j].dev_type == SIMDEV_SERIAL) {
SerialDevice* sim = new_serial_device(&ds[j], ms);
if (sim != NULL)
{
simdevices[j] = sim->m;
simdevices[j].initialized = true;
simdevices[j].type = SIMDEV_SERIAL;
simdevices[j].fps = ds[j].fps;
devices++;
}
else
{
slogw("Could not initialize Serial Device");
}
}
}
switch ( simdevice->type )
{
case SIMDEV_USB :
usbdev_free(&simdevice->d.usbdevice);
break;
case SIMDEV_SOUND :
sounddev_free(&simdevice->d.sounddevice);
break;
case SIMDEV_SERIAL :
serialdev_free(&simdevice->d.serialdevice);
break;
}
return 0;
}
int devinit(SimDevice* simdevice, DeviceSettings* ds)
{
slogi("initializing simdevice...");
simdevice->initialized = false;
int err = 0;
switch ( ds->dev_type )
{
case SIMDEV_USB :
simdevice->type = SIMDEV_USB;
simdevice->d.usbdevice.type = USBDEV_UNKNOWN;
err = usbdev_init(&simdevice->d.usbdevice, ds);
break;
case SIMDEV_SOUND :
simdevice->type = SIMDEV_SOUND;
err = sounddev_init(&simdevice->d.sounddevice);
break;
case SIMDEV_SERIAL :
simdevice->type = SIMDEV_SERIAL;
err = serialdev_init(&simdevice->d.serialdevice);
break;
default :
sloge("Unknown device type");
err = MONOCOQUE_ERROR_UNKNOWN_DEV;
break;
}
if (err==0)
{
simdevice->initialized = true;
}
return err;
return devices;
}
+122 -11
View File
@@ -6,29 +6,140 @@
#include "usbdevice.h"
#include "sounddevice.h"
#include "serialdevice.h"
#include "hapticeffect.h"
#include "../helper/confighelper.h"
#include "../simulatorapi/simdata.h"
#include "../simulatorapi/simapi/simapi/simdata.h"
#include "../../arduino/simwind/simwind.h"
#include "../../arduino/simhaptic/simhaptic.h"
#include "../../arduino/shiftlights/shiftlights.h"
typedef struct SimDevice SimDevice;
struct SimDevice
{
const void* vtable;
int (*update)(SimDevice*, SimData*);
int (*free)(SimDevice*);
void* derived;
int id;
int fps;
bool initialized;
DeviceType type;
HapticEffect hapticeffect;
};
typedef struct {
int (*update)(SimDevice*, SimData*);
int (*free)(SimDevice*);
} vtable;
/********* Serial Devices *****/
typedef enum
{
SERIALDEV_UNKNOWN = 0,
SERIALDEV_ARDUINO = 1,
SERIALDEV_WHEEL = 2,
}
SerialType;
typedef struct
{
SimDevice m;
int id;
bool initialized;
DeviceType type;
SerialType type;
struct sp_port* port;
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
{
USBDevice usbdevice;
SoundDevice sounddevice;
SerialDevice serialdevice;
} d;
SimWindData simwinddata;
SimHapticData simhapticdata;
ShiftLightsData shiftlightsdata;
WheelDevice wheeldevice;
} u;
}
SimDevice;
SerialDevice;
int arduino_shiftlights_update(SimDevice* this, SimData* simdata);
int arduino_simwind_update(SimDevice* this, SimData* simdata);
int arduino_simhaptic_update(SimDevice* this, SimData* simdata);
int serialdev_free(SimDevice* this);
SerialDevice* new_serial_device(DeviceSettings* ds, MonocoqueSettings* ms);
/********* USB HID Devices *****/
typedef enum
{
USBDEV_UNKNOWN = 0,
USBDEV_TACHOMETER = 1,
USBDEV_GENERICHAPTIC = 2,
USBDEV_WHEEL = 3
}
USBType;
typedef struct
{
SimDevice m;
int id;
USBType type;
union
{
TachDevice tachdevice;
WheelDevice wheeldevice;
USBGenericHapticDevice hapticdevice;
} u;
}
USBDevice;
int usbdev_update(SimDevice* this, SimData* simdata);
int usbdev_free(SimDevice* this);
USBDevice* new_usb_device(DeviceSettings* ds, MonocoqueSettings* ms);
/********* Sound Devices *****/
typedef struct
{
SimDevice m;
int id;
int configcheck;
SoundEffectModulationType modulationType;
SoundData sounddata;
#ifdef USE_PULSEAUDIO
pa_stream *stream;
#else
PaStreamParameters outputParameters;
PaStream* stream;
#endif
}
SoundDevice;
int sounddev_engine_update(SimDevice* this, SimData* simdata);
int sounddev_gearshift_update(SimDevice* this, SimData* simdata);
int sounddev_tyreslip_update(SimDevice* this, SimData* simdata);
int sounddev_free(SimDevice* this);
SoundDevice* new_sound_device(DeviceSettings* ds, MonocoqueSettings* ms);
/***** Generic Methods *********/
int update(SimDevice* simdevice, SimData* simdata);
int devupdate(SimDevice* simdevice, SimData* simdata);
int devinit(SimDevice* simdevice, DeviceSettings* ds);
int devinit(SimDevice* simdevices, int numdevices, DeviceSettings* ds, MonocoqueSettings* ms);
int devfree(SimDevice* simdevice);
int devfree(SimDevice* simdevices, int numdevices);
int simdevfree(SimDevice* this);
#endif
+79
View File
@@ -0,0 +1,79 @@
#include "sound.h"
#include "../slog/slog.h"
#ifdef USE_PULSEAUDIO
pa_threaded_mainloop* mainloop;
pa_context* context;
void context_state_cb(pa_context* context, void* mainloop) {
pa_threaded_mainloop_signal(mainloop, 0);
}
int setupsound()
{
pa_mainloop_api *mainloop_api;
slogi("connecting pulseaudio...");
// Get a mainloop and its context
mainloop = pa_threaded_mainloop_new();
assert(mainloop);
mainloop_api = pa_threaded_mainloop_get_api(mainloop);
context = pa_context_new(mainloop_api, "Monocoque");
assert(context);
pa_context_set_state_callback(context, &context_state_cb, mainloop);
// Lock the mainloop so that it does not run and crash before the context is ready
pa_threaded_mainloop_lock(mainloop);
// Start the mainloop
assert(pa_threaded_mainloop_start(mainloop) == 0);
assert(pa_context_connect(context, NULL, PA_CONTEXT_NOAUTOSPAWN, NULL) == 0);
// Wait for the context to be ready
for(;;) {
pa_context_state_t context_state = pa_context_get_state(context);
assert(PA_CONTEXT_IS_GOOD(context_state));
if (context_state == PA_CONTEXT_READY) break;
pa_threaded_mainloop_wait(mainloop);
}
slogi("successfully connected pulseaudio...");
return 1;
}
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...");
}
int freesound()
{
}
#endif
+13
View File
@@ -0,0 +1,13 @@
#ifndef _SOUND_H
#define _SOUND_H
#include <pulse/pulseaudio.h>
extern pa_threaded_mainloop* mainloop;
extern pa_context* context;
int setupsound();
int freesound();
#endif
@@ -1,3 +1,5 @@
#ifndef USE_PULSEAUDIO
#include <stdio.h>
#include <string.h>
#include <math.h>
@@ -10,65 +12,82 @@
#define SAMPLE_RATE (48000)
#define DURATION 4.0
#define AMPLITUDE .5
#ifndef M_PI
#define M_PI (3.14159265)
#endif
int patestCallback(const void* inputBuffer,
int patestCallbackEngineRPM(const void* inputBuffer,
void* outputBuffer,
unsigned long framesPerBuffer,
const PaStreamCallbackTimeInfo* timeInfo,
PaStreamCallbackFlags statusFlags,
void* userData)
{
PATestData* data = (PATestData*)userData;
SoundData* data = (SoundData*)userData;
float* out = (float*)outputBuffer;
memset(out, 0, framesPerBuffer * 2 * sizeof(float));
unsigned int i;
unsigned int n;
n = data->n;
//n = data->n;
(void) inputBuffer; /* Prevent unused argument warning. */
for( i=0; i<framesPerBuffer; i++,n++ )
{
float v = 0;
v = data->amp * sin (2 * M_PI * ((float) n) / (float) SAMPLE_RATE);
static double t = 0.0;
double sample = AMPLITUDE * 32767.0 * sin(2.0 * M_PI * data->curr_frequency * t);
if ( data->gear_sound_data > 0 )
{
if (n>=1764)
{
n=0;
}
}
else
{
if (n>=data->table_size)
{
n=0;
}
}
if ( data->gear_sound_data > 0 )
{
// right channel only?
// i have my butt hooked up to right channel... make this configurable?
*out++ = v;
}
else
{
*out++ = v;
*out++ = v;
t += 1.0 / SAMPLE_RATE;
if (t >= DURATION) {
t = 0.0;
}
*out++ = sample;
*out++ = sample;
}
data->n=n;
return 0;
}
int patestCallbackGearShift(const void* inputBuffer,
void* outputBuffer,
unsigned long framesPerBuffer,
const PaStreamCallbackTimeInfo* timeInfo,
PaStreamCallbackFlags statusFlags,
void* userData)
{
SoundData* data = (SoundData*)userData;
float* out = (float*)outputBuffer;
memset(out, 0, framesPerBuffer * 2 * sizeof(float));
unsigned int i;
unsigned int n;
//n = data->n;
(void) inputBuffer; /* Prevent unused argument warning. */
for( i=0; i<framesPerBuffer; i++,n++ )
{
static double t = 0.0;
double sample = 0;
if (data->frequency>0)
{
sample = AMPLITUDE * 32767.0 * sin(2.0 * M_PI * data->curr_frequency * data->curr_duration);
}
data->curr_duration += 1.0 / SAMPLE_RATE;
if (data->curr_duration >= data->duration) {
data->curr_duration = 0.0;
data->curr_frequency = 0;
}
*out++ = sample;
*out++ = sample;
}
}
int usb_generic_shaker_free(SoundDevice* sounddevice)
{
int err = 0;
@@ -97,14 +116,28 @@ int usb_generic_shaker_init(SoundDevice* sounddevice)
sounddevice->outputParameters.suggestedLatency = Pa_GetDeviceInfo( sounddevice->outputParameters.device )->defaultLowOutputLatency;
sounddevice->outputParameters.hostApiSpecificStreamInfo = NULL;
err = Pa_OpenStream( &sounddevice->stream,
NULL, /* No input. */
&sounddevice->outputParameters, /* As above. */
SAMPLE_RATE,
440, /* Frames per buffer. */
paClipOff, /* No out of range samples expected. */
patestCallback,
&sounddevice->sounddata );
if (sounddevice->m.hapticeffect.effecttype == EFFECT_GEARSHIFT)
{
err = Pa_OpenStream( &sounddevice->stream,
NULL, /* No input. */
&sounddevice->outputParameters, /* As above. */
SAMPLE_RATE,
440, /* Frames per buffer. */
paClipOff, /* No out of range samples expected. */
patestCallbackGearShift,
&sounddevice->sounddata );
}
else
{
err = Pa_OpenStream( &sounddevice->stream,
NULL, /* No input. */
&sounddevice->outputParameters, /* As above. */
SAMPLE_RATE,
440, /* Frames per buffer. */
paClipOff, /* No out of range samples expected. */
patestCallbackEngineRPM,
&sounddevice->sounddata );
}
if( err != paNoError )
{
goto error;
@@ -121,8 +154,7 @@ int usb_generic_shaker_init(SoundDevice* sounddevice)
error:
Pa_Terminate();
//fprintf( stderr, "An error occured while using the portaudio stream\n" );
//fprintf( stderr, "Error number: %d\n", err );
//fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
return err;
}
#endif
@@ -1,9 +1,14 @@
#ifndef _USB_GENERIC_SHAKER_H
#define _USB_GENERIC_SHAKER_H
#include "../sounddevice.h"
#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, int channels, const char* streamname);
int usb_generic_shaker_free(SoundDevice* sounddevice, pa_threaded_mainloop* mainloop);
#else
int usb_generic_shaker_init(SoundDevice* sounddevice);
int usb_generic_shaker_free(SoundDevice* sounddevice);
#endif
#endif
@@ -0,0 +1,197 @@
#ifdef USE_PULSEAUDIO
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <unistd.h>
#include "usb_generic_shaker.h"
#include "../sounddevice.h"
#define FORMAT PA_SAMPLE_S16LE
#define SAMPLE_RATE (44100)
#define AMPLITUDE .5
#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;
size_t num_samples = length / sizeof(int16_t);
int16_t buffer[num_samples];
for (size_t i = 0; i < num_samples; i++) {
static double t = 0.0;
double sample = 0;
if (data->frequency>0)
{
sample = AMPLITUDE * 32767.0 * sin(2.0 * M_PI * data->curr_frequency * data->curr_duration);
}
buffer[i] = (int16_t)sample;
data->curr_duration += 1.0 / SAMPLE_RATE;
if (data->curr_duration >= data->duration) {
data->curr_duration = 0.0;
data->curr_frequency = 0;
}
}
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++) {
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 >= 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;
}
void stream_state_cb(pa_stream *s, void *mainloop) {
pa_threaded_mainloop_signal(mainloop, 0);
}
int usb_generic_shaker_free(SoundDevice* sounddevice, pa_threaded_mainloop* mainloop)
{
pa_threaded_mainloop_lock(mainloop);
int err = 0;
if (sounddevice->stream)
{
pa_stream_disconnect(sounddevice->stream);
pa_stream_unref(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, 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 = channels;
pa_channel_map channel_map;
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);
}
else
{
pa_stream_set_write_callback(stream, engine_sound_stream, &sounddevice->sounddata);
}
// recommended settings, i.e. server uses sensible values
pa_buffer_attr buffer_attr;
buffer_attr.maxlength = (uint32_t) 32767;
buffer_attr.tlength = (uint32_t) -1;
buffer_attr.prebuf = (uint32_t) -1;
buffer_attr.minreq = (uint32_t) -1;
pa_cvolume cv;
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;
// 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);
// Wait for the stream to be ready
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;
pa_threaded_mainloop_wait(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;
}
#endif
+259 -16
View File
@@ -1,38 +1,281 @@
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <stdio.h>
#include <unistd.h>
#include "sound.h"
#include "simdevice.h"
#include "sounddevice.h"
#include "hapticeffect.h"
#include "sound/usb_generic_shaker.h"
#include "../simulatorapi/simdata.h"
#include "../simulatorapi/simapi/simapi/simdata.h"
#include "../helper/parameters.h"
#include "../slog/slog.h"
int sounddev_update(SoundDevice* sounddevice, SimData* simdata)
int gear_sound_set(SoundDevice* sounddevice, SimData* simdata)
{
sounddevice->sounddata.table_size = 44100/(simdata->rpms/60);
sounddevice->sounddata.gear_sound_data = 0;
if (sounddevice->sounddata.last_gear != simdata->gear)
if (sounddevice->sounddata.last_gear != simdata->gear && simdata->gear > 1)
{
sounddevice->sounddata.gear_sound_data = sounddevice->sounddata.amp;
//sounddevice->sounddata.gear_sound_data = 3.14;
sounddevice->sounddata.curr_frequency = sounddevice->sounddata.frequency;
sounddevice->sounddata.curr_duration = 0;
}
sounddevice->sounddata.last_gear = simdata->gear;
slogt("set gear frequency to %i", sounddevice->sounddata.frequency);
}
int sounddev_free(SoundDevice* sounddevice)
// we could make a vtable for these different effects too
int sounddev_engine_update(SimDevice* this, SimData* simdata)
{
return usb_generic_shaker_free(sounddevice);
SoundDevice* sounddevice = (void *) this->derived;
sounddevice->sounddata.curr_frequency = simdata->rpms/60;
//sounddevice->sounddata.table_size = 48000/(sounddevice->sounddata.frequency);
slogt("set engine frequency to %i", sounddevice->sounddata.frequency);
}
int sounddev_init(SoundDevice* sounddevice)
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;
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 (effect > 0)
{
effect = modulate(sounddevice, effect, sounddevice->modulationType);
sounddevice->sounddata.curr_frequency = sounddevice->sounddata.frequency;
sounddevice->sounddata.curr_duration = sounddevice->sounddata.duration;
}
else
{
sounddevice->sounddata.curr_frequency = 0;
sounddevice->sounddata.curr_duration = 0;
}
}
int sounddev_tyrelock_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 tyre lock effect %f", play);
if (play > 0)
{
sounddevice->sounddata.curr_frequency = sounddevice->sounddata.frequency;
sounddevice->sounddata.curr_duration = sounddevice->sounddata.duration;
}
else
{
sounddevice->sounddata.curr_frequency = 0;
sounddevice->sounddata.curr_duration = 0;
}
}
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 (play > 0)
{
sounddevice->sounddata.curr_frequency = sounddevice->sounddata.frequency;
sounddevice->sounddata.curr_duration = sounddevice->sounddata.duration;
}
else
{
sounddevice->sounddata.curr_frequency = 0;
sounddevice->sounddata.curr_duration = 0;
}
}
int sounddev_gearshift_update(SimDevice* this, SimData* simdata)
{
SoundDevice* sounddevice = (void *) this->derived;
gear_sound_set(sounddevice, simdata);
}
#ifdef USE_PULSEAUDIO
int sounddev_free(SimDevice* this)
{
SoundDevice* sounddevice = (void *) this->derived;
usb_generic_shaker_free(sounddevice, mainloop);
free(sounddevice);
return 0;
}
#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...");
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 = 44100/(100/60);
sounddevice->sounddata.last_gear = 0;
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->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.duration = sds.duration;
streamname = "Gear";
break;
case (EFFECT_TYRESLIP):
streamname = "TyreSlip";
break;
case (EFFECT_TYRELOCK):
streamname = "TyreLock";
break;
case (EFFECT_ABSBRAKES):
streamname = "ABS";
break;
}
#ifdef USE_PULSEAUDIO
//pa_threaded_mainloop* mainloop;
//pa_context* context;
usb_generic_shaker_init(sounddevice, mainloop, context, devname, sds.volume, sds.pan, sds.channels, streamname);
#else
usb_generic_shaker_init(sounddevice);
#endif
}
static const vtable engine_sound_simdevice_vtable = { &sounddev_engine_update, &sounddev_free };
static const vtable gear_sound_simdevice_vtable = { &sounddev_gearshift_update, &sounddev_free };
static const vtable tyreslip_sound_simdevice_vtable = { &sounddev_tyreslip_update, &sounddev_free };
static const vtable tyrelock_sound_simdevice_vtable = { &sounddev_tyrelock_update, &sounddev_free };
static const vtable absbrakes_sound_simdevice_vtable = { &sounddev_absbrakes_update, &sounddev_free };
SoundDevice* new_sound_device(DeviceSettings* ds, MonocoqueSettings* ms) {
SoundDevice* this = (SoundDevice*) malloc(sizeof(SoundDevice));
this->m.update = &update;
this->m.free = &simdevfree;
this->m.derived = this;
slogt("Attempting to configure sound device with subtype: %i", ds->effect_type);
switch (ds->effect_type) {
case (EFFECT_ENGINERPM):
this->m.hapticeffect.effecttype = EFFECT_ENGINERPM;
this->m.vtable = &engine_sound_simdevice_vtable;
slogi("Initializing sound device for engine vibrations.");
break;
case (EFFECT_GEARSHIFT):
this->m.hapticeffect.effecttype = EFFECT_GEARSHIFT;
this->m.vtable = &gear_sound_simdevice_vtable;
slogi("Initializing sound device for gear shift vibrations.");
break;
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 sound device %s", ds->sounddevsettings.dev);
int error = sounddev_init(this, ds->sounddevsettings.dev, ds->tyre, ds->sounddevsettings);
if (error != 0)
{
free(this);
return NULL;
}
return this;
}
+16 -28
View File
@@ -1,45 +1,33 @@
#ifndef _SOUNDDEVICE_H
#define _SOUNDDEVICE_H
#ifdef USE_PULSEAUDIO
#include <pulse/pulseaudio.h>
#else
#include "portaudio.h"
#endif
#include "../simulatorapi/simdata.h"
#include "../helper/parameters.h"
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
{
float sine[MAX_TABLE_SIZE];
float pitch;
int last_gear;
int left_phase;
int right_phase;
int n;
int table_size;
int amp;
int gear_sound_data;
int volume;
uint32_t frequency;
uint32_t frequencyMax;
double duration;
int curr_frequency;
double curr_duration;
double phase;
}
PATestData;
typedef struct
{
int id;
SoundType type;
PATestData sounddata;
PaStreamParameters outputParameters;
PaStream* stream;
}
SoundDevice;
int sounddev_update(SoundDevice* sounddevice, SimData* simdata);
int sounddev_init(SoundDevice* sounddevice);
int sounddev_free(SoundDevice* sounddevice);
SoundData;
#endif
+1 -1
View File
@@ -5,7 +5,7 @@
#include "tachdevice.h"
#include "revburner.h"
#include "../../helper/confighelper.h"
#include "../../simulatorapi/simdata.h"
#include "../../simulatorapi/simapi/simapi/simdata.h"
#include "../../slog/slog.h"
int tachdev_update(TachDevice* tachdevice, SimData* simdata)
+1 -1
View File
@@ -3,7 +3,7 @@
#include <hidapi/hidapi.h>
#include "../helper/confighelper.h"
#include "../simulatorapi/simdata.h"
#include "../simulatorapi/simapi/simapi/simdata.h"
//typedef int (*tachdev_update)(int revs);
+105
View File
@@ -0,0 +1,105 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <glob.h>
#include "usbhapticdevice.h"
#include "../../helper/confighelper.h"
#include "../slog/slog.h"
const char* SYSFSRUMBLEPATH = "/sys/module/hid_fanatec/drivers/hid:f*/0003:0EB7:183B.*/rumble";
int cslelitev3_update(USBGenericHapticDevice* usbhapticdevice, int effecttype, int play)
{
int res = 0;
int value = 0;
if (play > 0)
{
switch (effecttype)
{
case (EFFECT_TYRESLIP):
value = 0xff0000;
break;
case (EFFECT_TYRELOCK):
value = 0xff00;
break;
case (EFFECT_ABSBRAKES):
value = 0xffff00;
break;
}
}
fprintf(usbhapticdevice->filehandle, "%i\n", value);
fflush(usbhapticdevice->filehandle);
return res;
}
int cslelitev3_free(USBGenericHapticDevice* usbhapticdevice)
{
int res = 0;
free(usbhapticdevice->dev);
fflush(usbhapticdevice->filehandle);
fclose(usbhapticdevice->filehandle);
return res;
}
int cslelitev3_init(USBGenericHapticDevice* usbhapticdevice)
{
slogi("initializing CSL Elite V3 Pedals...");
int res = 0;
glob_t globlist;
int i = 0;
if (glob(SYSFSRUMBLEPATH, GLOB_PERIOD, NULL, &globlist) == GLOB_NOSPACE || glob(SYSFSRUMBLEPATH, GLOB_PERIOD, NULL, &globlist) == GLOB_NOMATCH)
{
res = 1;
}
if (glob(SYSFSRUMBLEPATH, GLOB_PERIOD, NULL, &globlist) == GLOB_ABORTED)
{
res = 2;
}
if (res == 0)
{
while (globlist.gl_pathv[i])
{
if (i == 0)
{
usbhapticdevice->dev = strdup(globlist.gl_pathv[i]);
}
i++;
}
}
globfree(&globlist);
if (res == 1) {
sloge("Could not find attach Club Sport Elite V3 Pedals");
return res;
}
if (res == 2) {
sloge("Permissions issue finding Club Sport Elite V3 Pedals");
return res;
}
usbhapticdevice->filehandle = fopen(usbhapticdevice->dev, "w");
if (!usbhapticdevice->filehandle)
{
sloge("Could not open pedal device...");
return res;
}
slogd("CSL Elite V3 Pedals Successfully initialized...");
return res;
}
+8
View File
@@ -0,0 +1,8 @@
#ifndef _CSLELITEV3_H
#define _CSLELITEV3_H
int cslelitev3_update(USBGenericHapticDevice* usbhapticdevice, int effecttype, int play);
int cslelitev3_init(USBGenericHapticDevice* usbhapticdevice);
int cslelitev3_free(USBGenericHapticDevice* usbhapticdevice);
#endif
+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
+79 -3
View File
@@ -1,35 +1,56 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdlib.h>
#include "usbdevice.h"
#include "simdevice.h"
#include "../helper/parameters.h"
#include "../simulatorapi/simdata.h"
#include "../simulatorapi/simapi/simapi/simdata.h"
#include "../slog/slog.h"
int usbdev_update(USBDevice* usbdevice, SimData* simdata)
int usbdev_update(SimDevice* this, SimData* simdata)
{
USBDevice* usbdevice = (void *) this->derived;
switch ( usbdevice->type )
{
case USBDEV_UNKNOWN :
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;
}
return 0;
}
int usbdev_free(USBDevice* usbdevice)
int usbdev_free(SimDevice* this)
{
USBDevice* usbdevice = (void *) this->derived;
slogt("Usb device free");
switch ( usbdevice->type )
{
case USBDEV_UNKNOWN :
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;
}
free(usbdevice);
return 0;
}
@@ -37,13 +58,68 @@ int usbdev_init(USBDevice* usbdevice, DeviceSettings* ds)
{
slogi("initializing usb device...");
int error = 0;
//usbdevice->type = USBDEV_TACHOMETER;
switch ( usbdevice->type )
{
case USBDEV_UNKNOWN :
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;
}
return error;
}
static const vtable usb_simdevice_vtable = { &usbdev_update, &usbdev_free };
USBDevice* new_usb_device(DeviceSettings* ds, MonocoqueSettings* ms) {
USBDevice* this = (USBDevice*) malloc(sizeof(USBDevice));
this->m.update = &update;
this->m.free = &simdevfree;
this->m.derived = this;
this->m.vtable = &usb_simdevice_vtable;
// 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;
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->type = USBDEV_GENERICHAPTIC;
}
int error = usbdev_init(this, ds);
if (error != 0)
{
free(this);
return NULL;
}
this->m.initialized = true;
return this;
}
+2 -24
View File
@@ -2,29 +2,7 @@
#define _USBDEVICE_H
#include "tachdevice.h"
#include "../helper/confighelper.h"
#include "../simulatorapi/simdata.h"
typedef enum
{
USBDEV_UNKNOWN = 0,
USBDEV_TACHOMETER = 1
}
USBType;
typedef struct
{
int id;
USBType type;
union
{
TachDevice tachdevice;
} u;
}
USBDevice;
int usbdev_update(USBDevice* usbdevice, SimData* simdata);
int usbdev_init(USBDevice* usbdevice, DeviceSettings* ds);
int usbdev_free(USBDevice* usbdevice);
#include "wheeldevice.h"
#include "usbhapticdevice.h"
#endif
+115
View File
@@ -0,0 +1,115 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#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"
int usbhapticdev_update(USBGenericHapticDevice* usbhapticdevice, SimData* simdata, int tyre, int useconfig, int* configcheck, char* configfile)
{
double play = slipeffect(simdata, usbhapticdevice->effecttype, tyre, usbhapticdevice->threshold, useconfig, configcheck, configfile);
if (play != usbhapticdevice->state)
{
int rplay = 0;
if(play > 0)
{
rplay = 1;
switch ( usbhapticdevice->type )
{
case USBHAPTIC_CSLELITEV3PEDALS:
cslelitev3_update(usbhapticdevice, usbhapticdevice->effecttype, rplay);
break;
case USBHAPTIC_SIMAGICP1000PEDALS:
simagicp1000_update(usbhapticdevice, usbhapticdevice->effecttype, rplay);
break;
}
}
else
{
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;
}
return 0;
}
int usbhapticdev_free(USBGenericHapticDevice* usbhapticdevice)
{
slogt("closing usb haptic device");
switch ( usbhapticdevice->type )
{
case USBHAPTIC_CSLELITEV3PEDALS:
cslelitev3_free(usbhapticdevice);
break;
case USBHAPTIC_SIMAGICP1000PEDALS:
simagicp1000_free(usbhapticdevice);
break;
}
return 0;
}
int usbhapticdev_init(USBGenericHapticDevice* usbhapticdevice, DeviceSettings* ds)
{
int error = 0;
usbhapticdevice->state = 0;
usbhapticdevice->value0 = ds->usbdevsettings.value0;
usbhapticdevice->value1 = ds->usbdevsettings.value1;
usbhapticdevice->state = usbhapticdevice->value0;
usbhapticdevice->effecttype = ds->effect_type;
usbhapticdevice->threshold = ds->threshold;
if(ds->effect_type == EFFECT_TYRESLIP)
{
usbhapticdevice->effecttype = EFFECT_TYRESLIP;
}
if(ds->effect_type == EFFECT_TYRELOCK)
{
usbhapticdevice->effecttype = EFFECT_TYRELOCK;
}
if(ds->effect_type == EFFECT_ABSBRAKES)
{
usbhapticdevice->effecttype = EFFECT_ABSBRAKES;
}
slogi("initializing standalone usb haptic device...");
// detection of usb device model
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");
}
if(usbhapticdevice->handle == 0)
{
error = MONOCOQUE_ERROR_INVALID_DEV;
return error;
}
return error;
}
+37
View File
@@ -0,0 +1,37 @@
#ifndef _USBHAPTICDEVICE_H
#define _USBHAPTICDEVICE_H
#include <hidapi/hidapi.h>
#include "../helper/confighelper.h"
#include "../simulatorapi/simapi/simapi/simdata.h"
typedef enum
{
USBHAPTIC_UNKNOWN = 0,
USBHAPTIC_CSLELITEV3PEDALS = 1,
USBHAPTIC_SIMAGICP1000PEDALS = 2
}
HapticType;
typedef struct
{
int id;
HapticType type;
double state;
double threshold;
int value0;
int value1;
VibrationEffectType effecttype;
FILE* filehandle;
hid_device* handle;
char* dev;
}
USBGenericHapticDevice;
int usbhapticdev_update(USBGenericHapticDevice* hapticdevice, SimData* simdata, int tyre, int useconfig, int* configcheck, char* configfile);
int usbhapticdev_init(USBGenericHapticDevice* hapticdevice, DeviceSettings* ds);
int usbhapticdev_free(USBGenericHapticDevice* hapticdevice);
#endif
+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)
+714 -52
View File
@@ -1,3 +1,4 @@
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -5,16 +6,38 @@
#include <sys/stat.h>
#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 "../simulatorapi/simdata.h"
#include "../simulatorapi/simmapper.h"
#include "../devices/serialadapter.h"
#include "../simulatorapi/simapi/simapi/simdata.h"
#include "../simulatorapi/simapi/simapi/simmapper.h"
#include "../slog/slog.h"
#define DEFAULT_UPDATE_RATE 120.0
#define DEFAULT_UPDATE_RATE 240.0
#define SIM_CHECK_RATE 1.0
bool go = false;
bool go2 = false;
struct sigaction act;
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)
{
@@ -165,19 +188,400 @@ int showstats(SimData* simdata)
fflush(stdout);
}
int looper(SimDevice* devices[], int numdevices, Simulator simulator)
void simapilib_loginfo(char* message)
{
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)
{
slogi("preparing game loop with %i devices...", numdevices);
SimData* simdata = malloc(sizeof(SimData));
SimMap* simmap = malloc(sizeof(SimMap));
int error = siminit(simdata, simmap, simulator);
if (error != MONOCOQUE_ERROR_NONE)
if (doui == true)
{
return error;
slogi("looking for ui config %s pass 1", ms->config_str);
int confignum = getconfigtouse2(ms->config_str, simdata->car, f->sim);
if(confignum == -1)
{
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)
{
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);
}
}
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);
}
if (f->simstate == false || simdata->simstatus <= 1 || appstate <= 1)
{
if(f->releasing == false)
{
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;
}
}
}
slogt("udp free :%lu %p\n",rcvbuf->len,rcvbuf->base);
free(rcvbuf->base);
}
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)
{
SimData* simdata = malloc(sizeof(SimData));
SimMap* simmap = createSimMap();
struct termios newsettings, canonicalmode;
tcgetattr(0, &canonicalmode);
@@ -189,52 +593,310 @@ int looper(SimDevice* devices[], int numdevices, Simulator simulator)
char ch;
struct pollfd mypoll = { STDIN_FILENO, POLLIN|POLLPRI };
double update_rate = DEFAULT_UPDATE_RATE;
int t=0;
int go = true;
while (go == true)
{
simdatamap(simdata, simmap, simulator);
showstats(simdata);
t++;
if(simdata->rpms<250)
{
simdata->rpms=250;
}
for (int x = 0; x < numdevices; x++)
{
if (devices[x]->type == SIMDEV_SERIAL)
{
if(t>=update_rate)
{
devupdate(devices[x], simdata);
}
}
else
{
devupdate(devices[x], simdata);
}
uv_poll_t* poll = (uv_poll_t*) malloc(uv_handle_size(UV_POLL));
}
if(t>=update_rate)
{
t=0;
}
if( poll(&mypoll, 1, 1000.0/update_rate) )
{
scanf("%c", &ch);
if(ch == 'q')
{
go = false;
}
}
}
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");
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))
{
return 1;
};
if (0 != uv_poll_start(poll, UV_READABLE, cb))
{
return 2;
};
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);
freesimmap(simmap, false);
return 0;
}
int tester(SimDevice* devices, int numdevices)
{
slogi("preparing test with %i devices...", numdevices);
SimData* simdata = malloc(sizeof(SimData));
struct termios newsettings, canonicalmode;
tcgetattr(0, &canonicalmode);
newsettings = canonicalmode;
newsettings.c_lflag &= (~ICANON & ~ECHO);
newsettings.c_cc[VMIN] = 1;
newsettings.c_cc[VTIME] = 0;
tcsetattr(0, TCSANOW, &newsettings);
fprintf(stdout, "\n");
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;
simdata->abs = 0;
simdata->tyrediameter[0] = -1;
simdata->tyrediameter[1] = -1;
simdata->tyrediameter[2] = -1;
simdata->tyrediameter[3] = -1;
simdata->Xvelocity = 0;
simdata->Yvelocity = 100;
simdata->Zvelocity = 0;
sleep(3);
fprintf(stdout, "Setting rpms to 1000\n");
simdata->rpms = 1000;
for (int x = 0; x < numdevices; x++)
{
if (devices[x].initialized == true)
{
devices[x].update(&devices[x], simdata);
}
}
sleep(3);
fprintf(stdout, "Shifting into first gear\n");
simdata->gear = 2;
for (int x = 0; x < numdevices; x++)
{
if (devices[x].initialized == true)
{
devices[x].update(&devices[x], simdata);
}
}
sleep(3);
fprintf(stdout, "Setting speed to 100\n");
simdata->velocity = 100;
for (int x = 0; x < numdevices; x++)
{
if (devices[x].initialized == true)
{
devices[x].update(&devices[x], simdata);
}
}
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;
for (int x = 0; x < numdevices; x++)
{
if (devices[x].initialized == true)
{
devices[x].update(&devices[x], simdata);
}
}
sleep(3);
fprintf(stdout, "Testing wheel Lock\n");
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)
{
devices[x].update(&devices[x], simdata);
}
}
sleep(3);
fprintf(stdout, "Shifting into second gear\n");
simdata->tyreRPS[0] = 0;
simdata->tyreRPS[1] = 0;
simdata->tyreRPS[2] = 0;
simdata->tyreRPS[3] = 0;
simdata->tyrediameter[0] = -1;
simdata->tyrediameter[1] = -1;
simdata->tyrediameter[2] = -1;
simdata->tyrediameter[3] = -1;
simdata->abs = 0;
simdata->gear = 3;
for (int x = 0; x < numdevices; x++)
{
if (devices[x].initialized == true)
{
devices[x].update(&devices[x], simdata);
}
}
sleep(3);
fprintf(stdout, "Testing abs brake lock Lock\n");
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->abs = .11;
for (int x = 0; x < numdevices; x++)
{
if (devices[x].initialized == true)
{
devices[x].update(&devices[x], simdata);
}
}
sleep(3);
fprintf(stdout, "Setting speed to 200\n");
simdata->tyreRPS[0] = 0;
simdata->tyreRPS[1] = 0;
simdata->tyreRPS[2] = 0;
simdata->tyreRPS[3] = 0;
simdata->tyrediameter[0] = -1;
simdata->tyrediameter[1] = -1;
simdata->tyrediameter[2] = -1;
simdata->tyrediameter[3] = -1;
simdata->abs = 0;
simdata->velocity = 200;
for (int x = 0; x < numdevices; x++)
{
if (devices[x].initialized == true)
{
devices[x].update(&devices[x], simdata);
}
}
sleep(3);
fprintf(stdout, "Shifting into third gear\n");
simdata->gear = 4;
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 2000\n");
simdata->rpms = 2000;
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 4000\n");
simdata->rpms = 4000;
for (int x = 0; x < numdevices; x++)
{
if (devices[x].initialized == true)
{
devices[x].update(&devices[x], simdata);
}
}
sleep(3);
fprintf(stdout, "Shifting into fourth gear\n");
simdata->gear = 5;
for (int x = 0; x < numdevices; x++)
{
if (devices[x].initialized == true)
{
devices[x].update(&devices[x], simdata);
}
}
sleep(3);
fprintf(stdout, "Setting speed to 300\n");
simdata->velocity = 300;
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 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++)
{
if (devices[x].initialized == true)
{
devices[x].update(&devices[x], simdata);
}
}
sleep(3);
simdata->velocity = 0;
simdata->rpms = 100;
simdata->gear = MONOCOQUE_GEAR_NEUTRAL;
for (int x = 0; x < numdevices; x++)
{
if (devices[x].initialized == true)
{
devices[x].update(&devices[x], simdata);
}
}
sleep(1);
fflush(stdout);
tcsetattr(0, TCSANOW, &canonicalmode);
free(simdata);
free(simmap);
return 0;
}
+4 -1
View File
@@ -1,4 +1,7 @@
#include "../devices/simdevice.h"
#include "../helper/parameters.h"
int looper (SimDevice* devices[], int numdevices, Simulator simulator);
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
+2 -2
View File
@@ -15,7 +15,7 @@
#include <libxml/tree.h>
#include "../devices/simdevice.h"
#include "../simulatorapi/simdata.h"
#include "../simulatorapi/simapi/simapi/simdata.h"
#include "../slog/slog.h"
#define DEFAULT_UPDATE_RATE 30.0
@@ -183,7 +183,7 @@ int config_tachometer(int max_revs, int granularity, const char* save_file, SimD
WriteXmlFromArrays(nodes, rpm_array, values_array, max_revs, save_file);
sleep(2);
simdata->pulses = 0;
devupdate(simdevice, simdata);
simdevice->update(simdevice, simdata);
fflush(stdout);
return 0;
+1 -1
View File
@@ -2,7 +2,7 @@
#define _TACHCONFIG_H
#include "../devices/simdevice.h"
#include "../simulatorapi/simdata.h"
#include "../simulatorapi/simapi/simapi/simdata.h"
int config_tachometer(int max_revs, int granularity, const char* save_file, SimDevice* simdevice, SimData* simdata);
+698 -56
View File
@@ -1,7 +1,9 @@
#include <dirent.h>
#include <stdio.h>
#include <stdbool.h>
#include <string.h>
#include <stdint.h>
#include <ctype.h>
#include <libxml/parser.h>
#include <libxml/xmlreader.h>
@@ -9,51 +11,192 @@
#include "confighelper.h"
#include "../slog/slog.h"
int strtogame(const char* game, MonocoqueSettings* ms)
#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)
{
slogd("Checking for %s in list of supported simulators.", game);
if (strcmp(game, "ac") == 0)
{
slogd("Setting simulator to Assetto Corsa");
ms->sim_name = SIMULATOR_ASSETTO_CORSA;
for (;; a++, b++) {
int d = tolower((unsigned char)*a) - tolower((unsigned char)*b);
if (d != 0 || !*a)
return d;
}
else if (strcmp(game, "rf2") == 0)
}
int strtoeffecttype(const char* effect, DeviceSettings* ds)
{
ds->is_valid = false;
if (strcicmp(effect, "Engine") == 0)
{
slogd("Setting simulator to RFactor 2");
ms->sim_name = SIMULATOR_RFACTOR2;
ds->is_valid = true;
ds->effect_type = EFFECT_ENGINERPM;
}
else
if (strcmp(game, "test") == 0)
{
slogd("Setting simulator to Test Data");
ms->sim_name = SIMULATOR_MONOCOQUE_TEST;
}
else
{
slogi("%s does not appear to be a supported simulator.", game);
return MONOCOQUE_ERROR_INVALID_SIM;
}
if (strcicmp(effect, "Gear") == 0)
{
ds->is_valid = true;
ds->effect_type = EFFECT_GEARSHIFT;
}
if (strcicmp(effect, "ABS") == 0)
{
ds->is_valid = true;
slogt("found abas effect set");
ds->effect_type = EFFECT_ABSBRAKES;
}
if ((strcicmp(effect, "SLIP") == 0) || (strcicmp(effect, "TYRESLIP") == 0) || (strcicmp(effect, "TIRESLIP") == 0))
{
ds->is_valid = true;
slogt("found tyreslip effect set");
ds->effect_type = EFFECT_TYRESLIP;
}
if ((strcicmp(effect, "LOCK") == 0) || (strcicmp(effect, "TYRELOCK") == 0) || (strcicmp(effect, "TIRELOCK") == 0))
{
ds->is_valid = true;
slogt("found tyreslock effect set");
ds->effect_type = EFFECT_TYRELOCK;
}
if (ds->is_valid == false)
{
slogw("effect %s is not a valid effect", effect);
}
ds->is_valid = true;
return MONOCOQUE_ERROR_NONE;
}
int strtodev(const char* device_type, DeviceSettings* ds)
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;
if (strcmp(device_type, "USB") == 0)
ds->dev_subtype = SIMDEVTYPE_UNKNOWN;
switch (simdev) {
case SIMDEV_USB:
if (strcicmp(device_subtype, "Tachometer") == 0)
{
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;
break;
}
case SIMDEV_SERIAL:
if (strcicmp(device_subtype, "ShiftLights") == 0)
{
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;
break;
}
if (strcicmp(device_subtype, "SerialHaptic") == 0 || strcicmp(device_subtype, "Haptic") == 0)
{
slogt("found serial haptic device settings");
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;
default:
ds->is_valid = false;
slogw("%s does not appear to be a valid device sub type, but attempting to continue with other devices", device_subtype);
return MONOCOQUE_ERROR_INVALID_DEV;
}
ds->is_valid = true;
return MONOCOQUE_ERROR_NONE;
}
int strtodev(const char* device_type, const char* device_subtype, DeviceSettings* ds)
{
ds->is_valid = false;
if (strcicmp(device_type, "USB") == 0)
{
ds->dev_type = SIMDEV_USB;
strtodevsubtype(device_subtype, ds, SIMDEV_USB);
}
else
if (strcmp(device_type, "Sound") == 0)
if (strcicmp(device_type, "Sound") == 0)
{
ds->dev_type = SIMDEV_SOUND;
strtodevsubtype(device_subtype, ds, SIMDEV_SOUND);
}
else
if (strcmp(device_type, "Serial") == 0)
if (strcicmp(device_type, "Serial") == 0)
{
ds->dev_type = SIMDEV_SERIAL;
strtodevsubtype(device_subtype, ds, SIMDEV_SERIAL);
}
else
{
@@ -65,33 +208,233 @@ int strtodev(const char* device_type, DeviceSettings* ds)
return MONOCOQUE_ERROR_NONE;
}
int strtodevtype(const char* device_subtype, DeviceSettings* ds)
int getsimfromconfig(config_setting_t* c)
{
ds->is_valid = false;
if (strcmp(device_subtype, "Tachometer") == 0)
int sim = 0;
const char* simstr = NULL;
int found = config_setting_lookup_string(c, "sim", &simstr);
if(found == 0)
{
ds->dev_subtype = SIMDEVTYPE_TACHOMETER;
int found = config_setting_lookup_int(c, "sim", &sim);
}
else
if (strcmp(device_subtype, "ShiftLights") == 0)
{
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)
{
ds->dev_subtype = SIMDEVTYPE_SHIFTLIGHTS;
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
if (strcmp(device_subtype, "Shaker") == 0)
{
ds->dev_subtype = SIMDEVTYPE_SHAKER;
}
else
{
ds->is_valid = false;
slogi("%s does not appear to be a valid device sub type, but attempting to continue with other devices", device_subtype);
return MONOCOQUE_ERROR_INVALID_DEV;
}
ds->is_valid = true;
return MONOCOQUE_ERROR_NONE;
{
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)
{
@@ -131,7 +474,7 @@ int loadtachconfig(const char* config_file, DeviceSettings* ds)
{
slogt("Xml Element name %s", cursubsubnode->name);
}
if (strcmp(cursubsubnode->name, "SettingsItem") == 0)
if (strcicmp(cursubsubnode->name, "SettingsItem") == 0)
{
arraysize++;
}
@@ -153,13 +496,13 @@ int loadtachconfig(const char* config_file, DeviceSettings* ds)
{
for (cursubsubsubnode = cursubsubnode->children; cursubsubsubnode; cursubsubsubnode = cursubsubsubnode->next)
{
if (strcmp(cursubsubsubnode->name, "Value") == 0)
if (strcicmp(cursubsubsubnode->name, "Value") == 0)
{
xmlChar* a = xmlNodeGetContent(cursubsubsubnode);
rpms_array[i] = strtol((char*) a, &buf, 10);
xmlFree(a);
}
if (strcmp(cursubsubsubnode->name, "TimeValue") == 0)
if (strcicmp(cursubsubsubnode->name, "TimeValue") == 0)
{
xmlChar* a = xmlNodeGetContent(cursubsubsubnode);
pulses_array[i] = strtol((char*) a, &buf, 10);
@@ -185,6 +528,40 @@ int loadtachconfig(const char* config_file, DeviceSettings* ds)
return 0;
}
int gettyre(config_setting_t* device_settings, DeviceSettings* ds) {
const char* temp;
int found = config_setting_lookup_string(device_settings, "tyre", &temp);
ds->tyre = ALLFOUR;
if (strcicmp(temp, "FRONTS") == 0)
{
ds->tyre = FRONTS;
}
if (strcicmp(temp, "REARS") == 0)
{
ds->tyre = REARS;
}
if (strcicmp(temp, "FRONTLEFT") == 0)
{
ds->tyre = FRONTLEFT;
}
if (strcicmp(temp, "FRONTRIGHT") == 0)
{
ds->tyre = FRONTRIGHT;
}
if (strcicmp(temp, "REARLEFT") == 0)
{
ds->tyre = REARLEFT;
}
if (strcicmp(temp, "REARRIGHT") == 0)
{
ds->tyre = REARRIGHT;
}
}
int loadconfig(const char* config_file, DeviceSettings* ds)
{
if (ds->dev_subtype == SIMDEVTYPE_TACHOMETER)
@@ -194,23 +571,42 @@ 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;
slogi("Called device setup with %s %s %s", device_type, device_subtype, config_file);
//slogt("Called device setup with %s %s %s", device_type, device_subtype, config_file);
ds->dev_type = SIMDEV_UNKNOWN;
ds->dev_subtype = SIMDEVTYPE_UNKNOWN;
error = strtodev(device_type, ds);
error = strtodev(device_type, device_subtype, ds);
if (error != MONOCOQUE_ERROR_NONE)
{
return error;
}
error = strtodevtype(device_subtype, ds);
if (error != MONOCOQUE_ERROR_NONE)
{
return error;
}
if (ms->program_action == A_PLAY)
if (ms->program_action == A_PLAY || ms->program_action == A_TEST)
{
error = loadconfig(config_file, ds);
}
@@ -219,6 +615,10 @@ int devsetup(const char* device_type, const char* device_subtype, const char* co
return error;
}
ds->fps = 60;
config_setting_lookup_int(device_settings, "fps", &ds->fps);
if (ds->dev_subtype == SIMDEVTYPE_TACHOMETER)
{
if (device_settings != NULL)
@@ -232,11 +632,253 @@ int devsetup(const char* device_type, const char* device_subtype, const char* co
slogi("Tachometer granularity set to %i", ds->tachsettings.granularity);
}
ds->tachsettings.use_pulses = true;
if (ms->program_action == A_PLAY)
if (ms->program_action == A_PLAY || ms->program_action == A_TEST)
{
ds->tachsettings.use_pulses = false;
}
}
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)
{
slogt("analysing haptic effect settings");
const char* effect;
config_setting_lookup_string(device_settings, "effect", &effect);
strtoeffecttype(effect, ds);
if (ds->effect_type == EFFECT_TYRESLIP || ds->effect_type == EFFECT_TYRELOCK || ds->effect_type == EFFECT_ABSBRAKES)
{
gettyre(device_settings, ds);
ds->threshold = 0;
int found = config_setting_lookup_float(device_settings, "threshold", &ds->threshold);
}
if (ds->dev_type == SIMDEV_SOUND)
{
slogi("reading configured sound device settings");
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)
{
ds->sounddevsettings.duration = .125;
}
if (device_settings != NULL)
{
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;
int found = 0;
found = config_setting_lookup_string(device_settings, "devid", &temp);
if (found == 0)
{
ds->sounddevsettings.dev = NULL;
}
else
{
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_type == SIMDEV_SERIAL)
{
if (device_settings != NULL)
{
const char* temp;
config_setting_lookup_string(device_settings, "devpath", &temp);
ds->serialdevsettings.portdev = strdup(temp);
int motorposition = 8;
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);
ds->serialdevsettings.ampfactor = ampfactor;
slogt("set port baud rate to %i, ampfactor %f", baud, ampfactor);
}
}
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 || ds.dev_subtype == SIMDEVTYPE_SIMLED)
{
if (ds.serialdevsettings.portdev != NULL)
{
free(ds.serialdevsettings.portdev);
}
}
if (ds.dev_type == SIMDEV_SOUND)
{
if (ds.sounddevsettings.dev != NULL)
{
free(ds.sounddevsettings.dev);
}
}
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);
}
}
+148 -8
View File
@@ -1,6 +1,7 @@
#ifndef _CONFIGHELPER_H
#define _CONFIGHELPER_H
#include <pulse/channelmap.h>
#include <stdbool.h>
#include <stdint.h>
@@ -8,6 +9,8 @@
#include "parameters.h"
#include "../devices/sounddevice.h"
typedef enum
{
SIMDEV_UNKNOWN = 0,
@@ -21,19 +24,27 @@ typedef enum
{
SIMDEVTYPE_UNKNOWN = 0,
SIMDEVTYPE_TACHOMETER = 1,
SIMDEVTYPE_SHAKER = 2,
SIMDEVTYPE_SHIFTLIGHTS = 3
SIMDEVTYPE_USBHAPTIC = 2,
SIMDEVTYPE_SHIFTLIGHTS = 3,
SIMDEVTYPE_SIMWIND = 4,
SIMDEVTYPE_SERIALHAPTIC = 5,
SIMDEVTYPE_USBWHEEL = 6,
SIMDEVTYPE_SERIALWHEEL = 7,
SIMDEVTYPE_SIMLED = 8
}
DeviceSubType;
typedef enum
{
SIMULATOR_MONOCOQUE_TEST = 0,
SIMULATOR_ASSETTO_CORSA = 1,
SIMULATOR_RFACTOR = 2,
SIMULATOR_RFACTOR2 = 3
SIMDEVSUBTYPE_UNKNOWN = 0,
SIMDEVSUBTYPE_CAMMUSC5 = 1,
SIMDEVSUBTYPE_CAMMUSC12 = 2,
SIMDEVSUBTYPE_MOZAR5 = 3,
SIMDEVSUBTYPE_CSLELITEV3PEDALS = 4,
SIMDEVSUBTYPE_SIMAGICP1000PEDALS =5
}
Simulator;
DeviceSubSubType;
typedef enum
{
@@ -46,6 +57,51 @@ typedef enum
}
SimulatorUpdate;
typedef enum
{
EFFECT_ENGINERPM = 0,
EFFECT_GEARSHIFT = 1,
EFFECT_ABSBRAKES = 2,
EFFECT_TYRESLIP = 3,
EFFECT_TYRELOCK = 4
}
VibrationEffectType;
typedef enum
{
MOTOR_1 = 0,
MOTOR_2 = 1,
MOTOR_3 = 2,
MOTOR_4 = 3,
MOTOR_1_4 = 4,
MOTOR_2_4 = 5,
MOTOR_3_4 = 6,
MOTOR_1_2 = 7,
MOTOR_1_3 = 8,
MOTOR_2_3 = 9,
MOTOR_1_2_3_4 = 10,
MOTOR_1_2_3 = 11,
MOTOR_2_3_4 = 12,
MOTOR_1_2_4 = 13,
MOTOR_1_3_4 = 14
}
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,
@@ -57,10 +113,31 @@ typedef enum
}
MonocoqueError;
typedef enum
{
FRONTLEFT = 0,
FRONTRIGHT = 1,
REARLEFT = 2,
REARRIGHT = 3,
FRONTS = 4,
REARS = 5,
ALLFOUR = 6
}
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;
@@ -74,12 +151,60 @@ typedef struct
}
TachometerSettings;
typedef struct
{
char* portdev;
MotorPosition motorsposition;
int numlights;
int numleds;
int startled;
int endled;
float ampfactor;
int baud;
}
SerialDeviceSettings;
typedef struct
{
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;
typedef struct
{
int value0;
int value1;
char* dev;
}
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;
// union?
TachometerSettings tachsettings;
SerialDeviceSettings serialdevsettings;
SoundDeviceSettings sounddevsettings;
USBDeviceSettings usbdevsettings;
}
DeviceSettings;
@@ -87,4 +212,19 @@ int strtogame(const char* game, MonocoqueSettings* ms);
int devsetup(const char* device_type, const char* device_subtype, const char* config_files, MonocoqueSettings* ms, DeviceSettings* ds, config_setting_t* device_settings);
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
+86 -5
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,19 +44,31 @@ 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";
struct arg_lit* arg_verbosity1 = arg_litn("v","verbose", 0, 2, "increase logging verbosity");
struct arg_lit* arg_verbosity2 = arg_litn("v","verbose", 0, 2, "increase logging verbosity");
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);
@@ -43,6 +82,13 @@ ConfigError getParameters(int argc, char** argv, Parameters* p)
void* argtable2[] = {cmd2a,cmd2b,arg_max_revs,arg_granularity,arg_save,arg_verbosity2,help2,vers2,end2};
int nerrors2;
struct arg_rex* cmd3 = arg_rex1(NULL, NULL, "test", NULL, REG_ICASE, NULL);
struct arg_lit* help3 = arg_litn(NULL,"help", 0, 1, "print this help and exit");
struct arg_lit* vers3 = arg_litn(NULL,"version", 0, 1, "print version information and exit");
struct arg_end* end3 = arg_end(20);
void* argtable3[] = {cmd3,arg_verbosity3,help3,vers3,end3};
int nerrors3;
struct arg_lit* help0 = arg_lit0(NULL,"help", "print this help and exit");
struct arg_lit* version0 = arg_lit0(NULL,"version", "print version information and exit");
struct arg_end* end0 = arg_end(20);
@@ -70,12 +116,37 @@ ConfigError getParameters(int argc, char** argv, Parameters* p)
nerrors0 = arg_parse(argc,argv,argtable0);
nerrors1 = arg_parse(argc,argv,argtable1);
nerrors2 = arg_parse(argc,argv,argtable2);
nerrors3 = arg_parse(argc,argv,argtable3);
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
@@ -92,6 +163,12 @@ ConfigError getParameters(int argc, char** argv, Parameters* p)
p->verbosity_count = arg_verbosity2->count;
exitcode = E_SUCCESS_AND_DO;
}
else if (nerrors3==0)
{
p->program_action = A_TEST;
p->verbosity_count = arg_verbosity3->count;
exitcode = E_SUCCESS_AND_DO;
}
else
{
if (cmd1->count > 0)
@@ -111,12 +188,13 @@ ConfigError getParameters(int argc, char** argv, Parameters* p)
{
if (help->count==0 && vers->count==0)
{
printf("%s: missing <play|config> command.\n",progname);
printf("%s: missing <play|config|test> command.\n",progname);
printf("Usage 1: %s ", progname);
arg_print_syntax(stdout,argtable1,"\n");
printf("Usage 2: %s ", progname);
arg_print_syntax(stdout,argtable2,"\n");
printf("Usage 3: %s ", progname);
arg_print_syntax(stdout,argtable3,"\n");
}
}
exitcode = E_SUCCESS_AND_EXIT;
@@ -131,6 +209,8 @@ ConfigError getParameters(int argc, char** argv, Parameters* p)
arg_print_syntax(stdout,argtable1,"\n");
printf("Usage 2: %s ", progname);
arg_print_syntax(stdout,argtable2,"\n");
printf("Usage 3: %s ", progname);
arg_print_syntax(stdout,argtable3,"\n");
printf("\nReport bugs on the github github.com/spacefreak18/monocoque.\n");
exitcode = E_SUCCESS_AND_EXIT;
goto cleanup;
@@ -148,6 +228,7 @@ cleanup:
arg_freetable(argtable0,sizeof(argtable0)/sizeof(argtable0[0]));
arg_freetable(argtable1,sizeof(argtable1)/sizeof(argtable1[0]));
arg_freetable(argtable2,sizeof(argtable2)/sizeof(argtable2[0]));
arg_freetable(argtable3,sizeof(argtable3)/sizeof(argtable3[0]));
return exitcode;
}
+22 -2
View File
@@ -1,22 +1,41 @@
#ifndef _PARAMETERS_H
#define _PARAMETERS_H
#include <stdbool.h>
#include "../simulatorapi/simapi/simapi/simapi.h"
typedef struct
{
int program_action;
const char* sim_string;
const char* save_file;
int fps;
int max_revs;
int granularity;
int verbosity_count;
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;
typedef enum
{
A_PLAY = 0,
A_CONFIG_TACH = 1,
A_CONFIG_SHAKER = 2
A_TEST = 1,
A_CONFIG_TACH = 2,
A_CONFIG_SHAKER = 3
}
ProgramAction;
@@ -28,6 +47,7 @@ typedef enum
}
ConfigError;
int freeparams(Parameters* p);
ConfigError getParameters(int argc, char** argv, Parameters* p);
struct _errordesc
+191 -124
View File
@@ -2,37 +2,20 @@
#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"
#include "devices/sound.h"
#include "helper/parameters.h"
#include "helper/dirhelper.h"
#include "helper/confighelper.h"
#include "simulatorapi/simdata.h"
#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()
{
@@ -43,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));;
@@ -55,25 +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"));
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");
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);
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;
@@ -81,41 +136,45 @@ 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);
}
slogi("Loading configuration file: %s", config_file_str);
ms->tyre_diameter_config = strdup(diameters_file_str);
ms->useconfig = 0;
ms->configcheck = 0;
free(diameters_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));
SimData* sdata = malloc(sizeof(SimData));
DeviceSettings* ds = malloc(sizeof(DeviceSettings));
error = devsetup("USB", "Tachometer", "None", ms, ds, NULL);
error = devinit(tachdev, ds);
slogi("configuring tachometer with max revs: %i, granularity: %i, saving to %s", p->max_revs, p->granularity, p->save_file);
if (error != MONOCOQUE_ERROR_NONE)
{
@@ -123,110 +182,118 @@ int main(int argc, char** argv)
}
else
{
int devices = 0;
devices = devinit(tachdev, 1, ds, ms);
if(devices < 1)
{
error = MONOCOQUE_ERROR_INVALID_DEV;
}
}
if (error != MONOCOQUE_ERROR_NONE)
{
sloge("Could not proceed with tachometer configuration due to error: %i", error);
}
else
{
slogi("configuring tachometer with max revs: %i, granularity: %i, saving to %s", p->max_revs, p->granularity, p->save_file);
config_tachometer(p->max_revs, p->granularity, p->save_file, tachdev, sdata);
}
devfree(tachdev);
free(tachdev);
slogt("freeing devices if necessary");
if(tachdev->initialized == true)
{
slogt("freeing tachmoeter device");
tachdev->free(tachdev);
}
//free(tachdev);
free(sdata);
free(ds);
}
else
{
slogi("running monocoque in gameloop mode..");
int error = 0;
error = strtogame(p->sim_string, ms);
if (error != MONOCOQUE_ERROR_NONE)
{
goto cleanup_final;
}
int configureddevices = config_setting_length(config_devices);
int numdevices = 0;
DeviceSettings* ds[configureddevices];
slogi("found %i devices in configuration", configureddevices);
int i = 0;
while (i<configureddevices)
{
error = MONOCOQUE_ERROR_NONE;
DeviceSettings* settings = malloc(sizeof(DeviceSettings));
ds[i] = 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);
if (error == MONOCOQUE_ERROR_NONE)
{
error = devsetup(device_type, device_subtype, device_config_file, ms, ds[i], config_device);
}
if (error == MONOCOQUE_ERROR_NONE)
{
numdevices++;
}
i++;
}
i = 0;
int j = 0;
error = MONOCOQUE_ERROR_NONE;
SimDevice* devices[numdevices];
while (i<configureddevices)
{
if (ds[i]->is_valid == true)
{
SimDevice* device = malloc(sizeof(SimDevice));
devinit(device, ds[i]);
devices[j] = device;
j++;
}
i++;
}
setupsound();
bool pulseaudio = false;
error = looper(devices, numdevices, ms->sim_name);
if (error == MONOCOQUE_ERROR_NONE)
if (ms->program_action == A_PLAY)
{
slogi("Game loop exited succesfully with error code: %i", error);
ms->useconfig = 1;
slogi("running monocoque in gameloop mode..");
#ifdef USE_PULSEAUDIO
pa_threaded_mainloop_unlock(mainloop);
pulseaudio = true;
#endif
//error = looper(devices, numdevices, p);
error = monocoque_mainloop(ms);
if (error == MONOCOQUE_ERROR_NONE)
{
slogi("Game loop exited succesfully with error code: %i", error);
}
else
{
sloge("Game loop exited with error code: %i", error);
}
}
else
{
sloge("Game loop exited with error code: %i", error);
}
slogi("running monocoque in test mode...");
i = 0;
while (i<configureddevices)
{
if(ds[i]->dev_subtype == SIMDEV_USB)
#ifdef USE_PULSEAUDIO
pa_threaded_mainloop_unlock(mainloop);
pulseaudio = true;
#endif
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++)
{
free(ds[i]->tachsettings.pulses_array);
free(ds[i]->tachsettings.rpms_array);
settingsfree(ds[i]);
}
free(ds);
error = tester(simdevices, numdevices);
if (error == MONOCOQUE_ERROR_NONE)
{
slogi("Test exited succesfully with error code: %i", error);
}
else
{
sloge("Test exited with error code: %i", error);
}
for (int x = 0; x < numdevices; x++)
{
if (simdevices[x].initialized == true)
{
simdevices[x].free(&simdevices[x]);
}
}
free(ds[i]);
i++;
}
i = 0;
while (i<numdevices)
if(pulseaudio == true)
{
devfree(devices[i]);
free(devices[i]);
i++;
freesound();
}
}
configcleanup:
config_destroy(&cfg);
cleanup_final:
monocoquesettingsfree(ms);
free(ms);
free(p);
exit(0);
}
+17 -6
View File
@@ -1,10 +1,21 @@
set(simulatorapi_source_files
simmapper.c
simmapper.h
simdata.h
test.h
simapi/acdata.h
ac.h
simapi/simapi/simmapper.c
simapi/simapi/simmapper.h
simapi/simapi/simdata.h
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})
-21
View File
@@ -1,21 +0,0 @@
#ifndef _AC_H
#define _AC_H
#include <stdbool.h>
#include "simapi/acdata.h"
#define AC_PHYSICS_FILE "acpmf_physics"
#define AC_STATIC_FILE "acpmf_static"
typedef struct
{
bool has_physics;
bool has_static;
void* physics_map_addr;
void* static_map_addr;
struct SPageFilePhysics ac_physics;
struct SPageFileStatic ac_static;
}
ACMap;
#endif
-21
View File
@@ -1,21 +0,0 @@
#ifndef _RF2_H
#define _RF2_H
#include <stdbool.h>
#include "simapi/rf2data.h"
#define RF2_TELEMETRY_FILE "rFactor2SMMP_Telemetry"
#define RF2_SCORING_FILE "rFactor2SMMP_Scoring"
typedef struct
{
bool has_telemetry;
bool has_scoring;
void* telemetry_map_addr;
void* scoring_map_addr;
struct rF2Telemetry rf2_telemetry;
//struct rF2Scoring rf2_scoring;
}
RF2Map;
#endif
-17
View File
@@ -1,17 +0,0 @@
#ifndef _SIMDATA_H
#define _SIMDATA_H
#include <stdint.h>
typedef struct
{
uint32_t velocity;
uint32_t rpms;
uint32_t gear;
uint32_t pulses;
uint32_t maxrpm;
uint32_t altitude;
}
SimData;
#endif
-136
View File
@@ -1,136 +0,0 @@
#include <stdio.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <string.h>
#include <stdlib.h>
#include <stddef.h>
#include <math.h>
#include "simmapper.h"
#include "simdata.h"
#include "test.h"
#include "ac.h"
#include "rf2.h"
#include "../helper/confighelper.h"
#include "../slog/slog.h"
#include "simapi/acdata.h"
#include "simapi/rf2data.h"
int simdatamap(SimData* simdata, SimMap* simmap, Simulator simulator)
{
char* a;
char* b;
switch ( simulator )
{
case SIMULATOR_MONOCOQUE_TEST :
memcpy(simdata, simmap->addr, sizeof(SimData));
break;
case SIMULATOR_ASSETTO_CORSA :
a = simmap->d.ac.physics_map_addr;
if (simmap->d.ac.has_static == true )
{
b = simmap->d.ac.static_map_addr;
simdata->maxrpm = *(uint32_t*) (char*) (b + offsetof(struct SPageFileStatic, maxRpm));
}
simdata->rpms = *(uint32_t*) (char*) (a + offsetof(struct SPageFilePhysics, rpms));
simdata->gear = *(uint32_t*) (char*) (a + offsetof(struct SPageFilePhysics, gear));
simdata->velocity = ceil( *(float*) (char*) (a + offsetof(struct SPageFilePhysics, speedKmh)));
simdata->altitude = 1;
break;
case SIMULATOR_RFACTOR2 :
a = simmap->d.rf2.telemetry_map_addr;
simdata->velocity = ceil(3.6 * ( *(double*) (char*) (a + offsetof(struct rF2Telemetry, mVehicles[0].mLocalVel.z))));
simdata->rpms = ceil( *(double*) (char*) (a + offsetof(struct rF2Telemetry, mVehicles[0].mEngineRPM)));
simdata->maxrpm = ceil( *(double*) (char*) (a + offsetof(struct rF2Telemetry, mVehicles[0].mEngineMaxRPM)));
simdata->gear = *(uint32_t*) (char*) (a + offsetof(struct rF2Telemetry, mVehicles[0].mGear));
break;
}
}
int siminit(SimData* simdata, SimMap* simmap, Simulator simulator)
{
slogi("searching for simulator data...");
int error = MONOCOQUE_ERROR_NONE;
void* a;
switch ( simulator )
{
case SIMULATOR_MONOCOQUE_TEST :
simmap->fd = shm_open(TEST_MEM_FILE_LOCATION, O_RDONLY, S_IRUSR | S_IWUSR);
if (simmap->fd == -1)
{
return 10;
}
simmap->addr = mmap(NULL, sizeof(SimData), PROT_READ, MAP_SHARED, simmap->fd, 0);
if (simmap->addr == MAP_FAILED)
{
return 30;
}
slogi("found data for monocoque test...");
break;
case SIMULATOR_ASSETTO_CORSA :
simmap->d.ac.has_physics=false;
simmap->d.ac.has_static=false;
simmap->fd = shm_open(AC_PHYSICS_FILE, O_RDONLY, S_IRUSR | S_IWUSR);
if (simmap->fd == -1)
{
slogd("could not open Assetto Corsa physics engine");
return MONOCOQUE_ERROR_NODATA;
}
simmap->d.ac.physics_map_addr = mmap(NULL, sizeof(simmap->d.ac.ac_physics), PROT_READ, MAP_SHARED, simmap->fd, 0);
if (simmap->d.ac.physics_map_addr == MAP_FAILED)
{
slogd("could not retrieve Assetto Corsa physics data");
return 30;
}
simmap->d.ac.has_physics=true;
simmap->fd = shm_open(AC_STATIC_FILE, O_RDONLY, S_IRUSR | S_IWUSR);
if (simmap->fd == -1)
{
slogd("could not open Assetto Corsa static data");
return 10;
}
simmap->d.ac.static_map_addr = mmap(NULL, sizeof(simmap->d.ac.ac_static), PROT_READ, MAP_SHARED, simmap->fd, 0);
if (simmap->d.ac.static_map_addr == MAP_FAILED)
{
slogd("could not retrieve Assetto Corsa static data");
return 30;
}
simmap->d.ac.has_static=true;
slogi("found data for Assetto Corsa...");
break;
case SIMULATOR_RFACTOR2 :
simmap->d.rf2.has_telemetry=false;
simmap->d.rf2.has_scoring=false;
simmap->fd = shm_open(RF2_TELEMETRY_FILE, O_RDONLY, S_IRUSR | S_IWUSR);
if (simmap->fd == -1)
{
slogd("could not open RFactor2 Telemetry engine");
return MONOCOQUE_ERROR_NODATA;
}
simmap->d.rf2.telemetry_map_addr = mmap(NULL, sizeof(simmap->d.rf2.rf2_telemetry), PROT_READ, MAP_SHARED, simmap->fd, 0);
if (simmap->d.rf2.telemetry_map_addr == MAP_FAILED)
{
slogd("could not retrieve RFactor2 telemetry data");
return 30;
}
simmap->d.rf2.has_telemetry=true;
slogi("found data for RFactor2...");
break;
}
return error;
}
-28
View File
@@ -1,28 +0,0 @@
#ifndef _SIMMAPPER_H
#define _SIMMAPPER_H
#include "ac.h"
#include "rf2.h"
#include "simdata.h"
#include "../helper/confighelper.h"
#include "simapi/acdata.h"
#include "simapi/rf2data.h"
typedef struct
{
void* addr;
int fd;
union
{
ACMap ac;
RF2Map rf2;
} d;
}
SimMap;
int siminit(SimData* simdata, SimMap* simmap, Simulator simulator);
int simdatamap(SimData* simdata, SimMap* simmap, Simulator simulator);
#endif
-6
View File
@@ -1,6 +0,0 @@
#ifndef _TEST_H
#define _TEST_H
#define TEST_MEM_FILE_LOCATION "/monocoque_test"
#endif
+215 -184
View File
@@ -1,7 +1,7 @@
/*
* The MIT License (MIT)
*
* Copyleft (C) 2015-2020 Sun Dro (f4tb0y@protonmail.com)
* Copyleft (C) 2015-2023 Sun Dro (s.kalatoz@gmail.com)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -27,7 +27,6 @@
#endif
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
@@ -37,86 +36,89 @@
#include <time.h>
#include "slog.h"
#if !defined(__APPLE__) && !defined(DARWIN) && !defined(WIN32)
#ifdef __linux__
#include <syscall.h>
#endif
#include <sys/time.h>
#ifdef WIN32
#include <windows.h>
#endif
#ifndef PTHREAD_MUTEX_RECURSIVE
#ifndef PTHREAD_MUTEX_RECURSIVE
#define PTHREAD_MUTEX_RECURSIVE PTHREAD_MUTEX_RECURSIVE_NP
#endif
typedef struct slog
{
unsigned int nTdSafe:1;
typedef struct slog_file {
uint8_t nCurrDay;
FILE *pHandle;
} slog_file_t;
typedef struct slog {
pthread_mutex_t mutex;
slog_config_t config;
slog_file_t logFile;
uint8_t nTdSafe;
} slog_t;
typedef struct XLogCtx
{
const char* pFormat;
typedef struct slog_context {
const char *pFormat;
slog_flag_t eFlag;
slog_date_t date;
uint8_t nFullColor;
uint8_t nNewLine;
} slog_context_t;
static volatile int g_nHaveSlogVerShort = 0;
static volatile int g_nHaveSlogVerLong = 0;
static char g_slogVerShort[128];
static char g_slogVerLong[256];
static slog_t g_slog;
static void slog_sync_init(slog_t* pSlog)
static void slog_sync_init(slog_t *pSlog)
{
if (!pSlog->nTdSafe)
{
return;
}
if (!pSlog->nTdSafe) return;
pthread_mutexattr_t mutexAttr;
if (pthread_mutexattr_init(&mutexAttr) ||
pthread_mutexattr_settype(&mutexAttr, PTHREAD_MUTEX_RECURSIVE) ||
pthread_mutex_init(&pSlog->mutex, &mutexAttr) ||
pthread_mutexattr_destroy(&mutexAttr))
pthread_mutexattr_settype(&mutexAttr, PTHREAD_MUTEX_RECURSIVE) ||
pthread_mutex_init(&pSlog->mutex, &mutexAttr) ||
pthread_mutexattr_destroy(&mutexAttr))
{
printf("<%s:%d> %s: [ERROR] Can not initialize mutex: %d\n",
__FILE__, __LINE__, __FUNCTION__, errno);
printf("<%s:%d> %s: [ERROR] Can not initialize mutex: %d\n",
__FILE__, __LINE__, __func__, errno);
exit(EXIT_FAILURE);
}
}
static void slog_lock(slog_t* pSlog)
static void slog_lock(slog_t *pSlog)
{
if (pSlog->nTdSafe && pthread_mutex_lock(&pSlog->mutex))
{
printf("<%s:%d> %s: [ERROR] Can not lock mutex: %d\n",
__FILE__, __LINE__, __FUNCTION__, errno);
printf("<%s:%d> %s: [ERROR] Can not lock mutex: %d\n",
__FILE__, __LINE__, __func__, errno);
exit(EXIT_FAILURE);
}
}
static void slog_unlock(slog_t* pSlog)
static void slog_unlock(slog_t *pSlog)
{
if (pSlog->nTdSafe && pthread_mutex_unlock(&pSlog->mutex))
{
printf("<%s:%d> %s: [ERROR] Can not unlock mutex: %d\n",
__FILE__, __LINE__, __FUNCTION__, errno);
printf("<%s:%d> %s: [ERROR] Can not unlock mutex: %d\n",
__FILE__, __LINE__, __func__, errno);
exit(EXIT_FAILURE);
}
}
static const char* slog_get_indent(slog_flag_t eFlag)
static const char *slog_get_indent(slog_flag_t eFlag)
{
slog_config_t* pCfg = &g_slog.config;
if (!pCfg->nIndent)
{
return SLOG_EMPTY;
}
slog_config_t *pCfg = &g_slog.config;
if (!pCfg->nIndent) return SLOG_EMPTY;
switch (eFlag)
{
@@ -125,13 +127,12 @@ static const char* slog_get_indent(slog_flag_t eFlag)
case SLOG_NOTE:
case SLOG_INFO:
case SLOG_WARN:
return SLOG_SPACE;
return SLOG_SPACE;
case SLOG_DEBUG:
case SLOG_TRACE:
case SLOG_FATAL:
case SLOG_ERROR:
default:
break;
default: break;
}
return SLOG_EMPTY;
@@ -141,22 +142,14 @@ static const char* slog_get_tag(slog_flag_t eFlag)
{
switch (eFlag)
{
case SLOG_NOTE:
return "note";
case SLOG_INFO:
return "info";
case SLOG_WARN:
return "warn";
case SLOG_DEBUG:
return "debug";
case SLOG_ERROR:
return "error";
case SLOG_TRACE:
return "trace";
case SLOG_FATAL:
return "fatal";
default:
break;
case SLOG_NOTE: return "note";
case SLOG_INFO: return "info";
case SLOG_WARN: return "warn";
case SLOG_DEBUG: return "debug";
case SLOG_ERROR: return "error";
case SLOG_TRACE: return "trace";
case SLOG_FATAL: return "fatal";
default: break;
}
return NULL;
@@ -167,38 +160,62 @@ static const char* slog_get_color(slog_flag_t eFlag)
switch (eFlag)
{
case SLOG_NOTAG:
case SLOG_NOTE:
return SLOG_EMPTY;
case SLOG_INFO:
return SLOG_COLOR_GREEN;
case SLOG_WARN:
return SLOG_COLOR_YELLOW;
case SLOG_DEBUG:
return SLOG_COLOR_BLUE;
case SLOG_ERROR:
return SLOG_COLOR_RED;
case SLOG_TRACE:
return SLOG_COLOR_CYAN;
case SLOG_FATAL:
return SLOG_COLOR_MAGENTA;
default:
break;
case SLOG_NOTE: return SLOG_EMPTY;
case SLOG_INFO: return SLOG_COLOR_GREEN;
case SLOG_WARN: return SLOG_COLOR_YELLOW;
case SLOG_DEBUG: return SLOG_COLOR_BLUE;
case SLOG_ERROR: return SLOG_COLOR_RED;
case SLOG_TRACE: return SLOG_COLOR_CYAN;
case SLOG_FATAL: return SLOG_COLOR_MAGENTA;
default: break;
}
return SLOG_EMPTY;
}
uint8_t slog_get_usec()
static void slog_close_file(slog_file_t *pFile)
{
struct timeval tv;
if (gettimeofday(&tv, NULL) < 0)
if (pFile->pHandle != NULL)
{
return 0;
fclose(pFile->pHandle);
pFile->pHandle = NULL;
}
return (uint8_t)(tv.tv_usec / 10000);
}
void slog_get_date(slog_date_t* pDate)
static uint8_t slog_open_file(slog_file_t *pFile, const slog_config_t *pCfg, const slog_date_t *pDate)
{
slog_close_file(pFile);
char sFilePath[SLOG_PATH_MAX + SLOG_NAME_MAX + SLOG_DATE_MAX];
snprintf(sFilePath, sizeof(sFilePath), "%s/%s-%04d-%02d-%02d.log",
pCfg->sFilePath, pCfg->sFileName, pDate->nYear, pDate->nMonth, pDate->nDay);
#ifdef _WIN32
if (fopen_s(&pFile->pHandle, sFilePath, "a")) pFile->pHandle = NULL;
#else
pFile->pHandle = fopen(sFilePath, "a");
#endif
if (pFile->pHandle == NULL)
{
printf("<%s:%d> %s: [ERROR] Failed to open file: %s (%s)\n",
__FILE__, __LINE__, __func__, sFilePath, strerror(errno));
return 0;
}
pFile->nCurrDay = pDate->nDay;
return 1;
}
uint16_t slog_get_usec()
{
struct timeval tv;
if (gettimeofday(&tv, NULL) < 0) return 0;
return (uint16_t)(tv.tv_usec / 1000);
}
void slog_get_date(slog_date_t *pDate)
{
struct tm timeinfo;
time_t rawtime = time(NULL);
@@ -217,70 +234,68 @@ void slog_get_date(slog_date_t* pDate)
pDate->nUsec = slog_get_usec();
}
static uint32_t slog_get_tid()
static size_t slog_get_tid()
{
#if defined(__APPLE__) || defined(DARWIN) || defined(WIN32)
return (uint32_t)pthread_self();
#ifdef __linux__
return (size_t)syscall(__NR_gettid);
#else
return syscall(__NR_gettid);
return (size_t)pthread_self();
#endif
}
static void slog_create_tag(char* pOut, size_t nSize, slog_flag_t eFlag, const char* pColor)
static void slog_create_tag(char *pOut, size_t nSize, slog_flag_t eFlag, const char *pColor)
{
slog_config_t* pCfg = &g_slog.config;
slog_config_t *pCfg = &g_slog.config;
pOut[0] = SLOG_NUL;
const char* pIndent = slog_get_indent(eFlag);
const char* pTag = slog_get_tag(eFlag);
const char *pIndent = slog_get_indent(eFlag);
const char *pTag = slog_get_tag(eFlag);
if (pTag == NULL)
{
snprintf(pOut, nSize, pIndent);
snprintf(pOut, nSize, "%s", pIndent);
return;
}
if (pCfg->eColorFormat != SLOG_COLORING_TAG)
{
snprintf(pOut, nSize, "<%s>%s", pTag, pIndent);
}
else
{
snprintf(pOut, nSize, "%s<%s>%s%s", pColor, pTag, SLOG_COLOR_RESET, pIndent);
}
if (pCfg->eColorFormat != SLOG_COLORING_TAG) snprintf(pOut, nSize, "<%s>%s", pTag, pIndent);
else snprintf(pOut, nSize, "%s<%s>%s%s", pColor, pTag, SLOG_COLOR_RESET, pIndent);
}
static void slog_create_tid(char* pOut, int nSize, uint8_t nTraceTid)
static void slog_create_tid(char *pOut, int nSize, uint8_t nTraceTid)
{
if (!nTraceTid)
{
pOut[0] = SLOG_NUL;
}
else
{
snprintf(pOut, nSize, "(%u) ", slog_get_tid());
}
if (!nTraceTid) pOut[0] = SLOG_NUL;
else snprintf(pOut, nSize, "(%zu) ", slog_get_tid());
}
static void slog_display_message(const slog_context_t* pCtx, const char* pInfo, int nInfoLen, const char* pInput)
static void slog_display_message(const slog_context_t *pCtx, const char *pInfo, int nInfoLen, const char *pInput)
{
slog_config_t* pCfg = &g_slog.config;
slog_config_t *pCfg = &g_slog.config;
slog_file_t *pFile = &g_slog.logFile;
int nCbVal = 1;
const char* pSeparator = nInfoLen > 0 ? pCfg->sSeparator : SLOG_EMPTY;
const char* pReset = pCtx->nFullColor ? SLOG_COLOR_RESET : SLOG_EMPTY;
const char* pNewLine = pCtx->nNewLine ? SLOG_NEWLINE : SLOG_EMPTY;
const char* pMessage = pInput != NULL ? pInput : SLOG_EMPTY;
uint8_t nFullColor = pCfg->eColorFormat == SLOG_COLORING_FULL ? 1 : 0;
const char *pSeparator = nInfoLen > 0 ? pCfg->sSeparator : SLOG_EMPTY;
const char *pNewLine = pCtx->nNewLine ? SLOG_NEWLINE : SLOG_EMPTY;
const char *pMessage = pInput != NULL ? pInput : SLOG_EMPTY;
const char *pReset = nFullColor ? SLOG_COLOR_RESET : SLOG_EMPTY;
if (pCfg->logCallback != NULL)
{
size_t nLength = 0;
char* pLog = NULL;
char *pLog = NULL;
nLength += asprintf(&pLog, "%s%s%s%s%s", pInfo,
pSeparator, pMessage, pReset, pNewLine);
nLength += asprintf(&pLog, "%s%s%s%s%s", pInfo, pSeparator, pMessage, pReset, pNewLine);
if (pLog != NULL)
{
nCbVal = pCfg->logCallback(pLog, nLength, pCtx->eFlag, pCfg->pCallbackCtx);
nCbVal = pCfg->logCallback (
pLog,
nLength,
pCtx->eFlag,
pCfg->pCallbackCtx
);
free(pLog);
}
}
@@ -288,36 +303,26 @@ static void slog_display_message(const slog_context_t* pCtx, const char* pInfo,
if (pCfg->nToScreen && nCbVal > 0)
{
printf("%s%s%s%s%s", pInfo, pSeparator, pMessage, pReset, pNewLine);
if (pCfg->nFlush)
{
fflush(stdout);
}
if (pCfg->nFlush) fflush(stdout);
}
if (!pCfg->nToFile || nCbVal < 0)
{
return;
}
const slog_date_t* pDate = &pCtx->date;
if (!pCfg->nToFile || nCbVal < 0) return;
const slog_date_t *pDate = &pCtx->date;
char sFilePath[SLOG_PATH_MAX + SLOG_NAME_MAX + SLOG_DATE_MAX];
snprintf(sFilePath, sizeof(sFilePath), "%s/%s-%04d-%02d-%02d.log",
pCfg->sFilePath, pCfg->sFileName, pDate->nYear, pDate->nMonth, pDate->nDay);
if (pFile->nCurrDay != pDate->nDay && pCfg->nRotate) slog_close_file(pFile);
if (pFile->pHandle == NULL && !slog_open_file(pFile, pCfg, pDate)) return;
FILE* pFile = fopen(sFilePath, "a");
if (pFile == NULL)
{
return;
}
fprintf(pFile->pHandle, "%s%s%s%s%s", pInfo,
pSeparator, pMessage, pReset, pNewLine);
fprintf(pFile, "%s%s%s%s%s", pInfo, pSeparator, pMessage, pReset, pNewLine);
fclose(pFile);
if (pCfg->nFlush) fflush(pFile->pHandle);
if (!pCfg->nKeepOpen) slog_close_file(pFile);
}
static int slog_create_info(const slog_context_t* pCtx, char* pOut, size_t nSize)
static int slog_create_info(const slog_context_t *pCtx, char* pOut, size_t nSize)
{
slog_config_t* pCfg = &g_slog.config;
const slog_date_t* pDate = &pCtx->date;
slog_config_t *pCfg = &g_slog.config;
const slog_date_t *pDate = &pCtx->date;
char sDate[SLOG_DATE_MAX + SLOG_NAME_MAX];
sDate[0] = SLOG_NUL;
@@ -325,29 +330,30 @@ static int slog_create_info(const slog_context_t* pCtx, char* pOut, size_t nSize
if (pCfg->eDateControl == SLOG_TIME_ONLY)
{
snprintf(sDate, sizeof(sDate), "%02d:%02d:%02d.%03d ",
pDate->nHour,pDate->nMin, pDate->nSec, pDate->nUsec);
pDate->nHour, pDate->nMin, pDate->nSec, pDate->nUsec);
}
else if (pCfg->eDateControl == SLOG_DATE_FULL)
{
snprintf(sDate, sizeof(sDate), "%04d.%02d.%02d-%02d:%02d:%02d.%03d ",
pDate->nYear, pDate->nMonth, pDate->nDay, pDate->nHour,
pDate->nMin, pDate->nSec, pDate->nUsec);
}
else
if (pCfg->eDateControl == SLOG_DATE_FULL)
{
snprintf(sDate, sizeof(sDate), "%04d.%02d.%02d-%02d:%02d:%02d.%03d ",
pDate->nYear, pDate->nMonth, pDate->nDay, pDate->nHour,
pDate->nMin, pDate->nSec, pDate->nUsec);
}
char sTid[SLOG_TAG_MAX], sTag[SLOG_TAG_MAX];
const char* pColorCode = slog_get_color(pCtx->eFlag);
const char* pColor = pCtx->nFullColor ? pColorCode : SLOG_EMPTY;
uint8_t nFullColor = pCfg->eColorFormat == SLOG_COLORING_FULL ? 1 : 0;
const char *pColorCode = slog_get_color(pCtx->eFlag);
const char *pColor = nFullColor ? pColorCode : SLOG_EMPTY;
slog_create_tid(sTid, sizeof(sTid), pCfg->nTraceTid);
slog_create_tag(sTag, sizeof(sTag), pCtx->eFlag, pColorCode);
return snprintf(pOut, nSize, "%s%s%s%s", pColor, sTid, sDate, sTag);
}
static void slog_display_heap(const slog_context_t* pCtx, va_list args)
static void slog_display_heap(const slog_context_t *pCtx, va_list args)
{
size_t nBytes = 0;
char* pMessage = NULL;
char *pMessage = NULL;
char sLogInfo[SLOG_INFO_MAX];
nBytes += vasprintf(&pMessage, pCtx->pFormat, args);
@@ -355,21 +361,18 @@ static void slog_display_heap(const slog_context_t* pCtx, va_list args)
if (pMessage == NULL)
{
printf("<%s:%d> %s<error>%s %s: Can not allocate memory for input: errno(%d)\n",
__FILE__, __LINE__, SLOG_COLOR_RED, SLOG_COLOR_RESET, __FUNCTION__, errno);
printf("<%s:%d> %s<error>%s %s: Can not allocate memory for input: errno(%d)\n",
__FILE__, __LINE__, SLOG_COLOR_RED, SLOG_COLOR_RESET, __func__, errno);
return;
}
int nLength = slog_create_info(pCtx, sLogInfo, sizeof(sLogInfo));
slog_display_message(pCtx, sLogInfo, nLength, pMessage);
if (pMessage != NULL)
{
free(pMessage);
}
if (pMessage != NULL) free(pMessage);
}
static void slog_display_stack(const slog_context_t* pCtx, va_list args)
static void slog_display_stack(const slog_context_t *pCtx, va_list args)
{
char sMessage[SLOG_MESSAGE_MAX];
char sLogInfo[SLOG_INFO_MAX];
@@ -379,13 +382,13 @@ static void slog_display_stack(const slog_context_t* pCtx, va_list args)
slog_display_message(pCtx, sLogInfo, nLength, sMessage);
}
void slog_display(slog_flag_t eFlag, uint8_t nNewLine, const char* pFormat, ...)
void slog_display(slog_flag_t eFlag, uint8_t nNewLine, char *pFormat, ...)
{
slog_lock(&g_slog);
slog_config_t* pCfg = &g_slog.config;
slog_config_t *pCfg = &g_slog.config;
if ((SLOG_FLAGS_CHECK(g_slog.config.nFlags, eFlag)) &&
(g_slog.config.nToScreen || g_slog.config.nToFile))
(g_slog.config.nToScreen || g_slog.config.nToFile))
{
slog_context_t ctx;
slog_get_date(&ctx.date);
@@ -393,9 +396,8 @@ void slog_display(slog_flag_t eFlag, uint8_t nNewLine, const char* pFormat, ...)
ctx.eFlag = eFlag;
ctx.pFormat = pFormat;
ctx.nNewLine = nNewLine;
ctx.nFullColor = pCfg->eColorFormat == SLOG_COLORING_FULL ? 1 : 0;
void(*slog_display_args)(const slog_context_t* pCtx, va_list args);
void(*slog_display_args)(const slog_context_t *pCtx, va_list args);
slog_display_args = pCfg->nUseHeap ? slog_display_heap : slog_display_stack;
va_list args;
@@ -407,33 +409,50 @@ void slog_display(slog_flag_t eFlag, uint8_t nNewLine, const char* pFormat, ...)
slog_unlock(&g_slog);
}
size_t slog_version(char* pDest, size_t nSize, uint8_t nMin)
const char* slog_version(uint8_t nShort)
{
size_t nLength = 0;
if (nShort)
{
if (!g_nHaveSlogVerShort)
{
snprintf(g_slogVerShort, sizeof(g_slogVerShort), "%d.%d.%d",
SLOG_VERSION_MAJOR, SLOG_VERSION_MINOR, SLOG_BUILD_NUMBER);
/* Version short */
if (nMin)
nLength = snprintf(pDest, nSize, "%d.%d.%d",
SLOG_VERSION_MAJOR, SLOG_VERSION_MINOR, SLOG_BUILD_NUM);
g_nHaveSlogVerShort = 1;
}
/* Version long */
else
nLength = snprintf(pDest, nSize, "%d.%d build %d (%s)",
SLOG_VERSION_MAJOR, SLOG_VERSION_MINOR, SLOG_BUILD_NUM, __DATE__);
return g_slogVerShort;
}
return nLength;
if (!g_nHaveSlogVerLong)
{
snprintf(g_slogVerLong, sizeof(g_slogVerLong), "%d.%d build %d (%s)",
SLOG_VERSION_MAJOR, SLOG_VERSION_MINOR, SLOG_BUILD_NUMBER, __DATE__);
g_nHaveSlogVerLong = 1;
}
return g_slogVerLong;
}
void slog_config_get(slog_config_t* pCfg)
void slog_config_get(slog_config_t *pCfg)
{
slog_lock(&g_slog);
*pCfg = g_slog.config;
slog_unlock(&g_slog);
}
void slog_config_set(slog_config_t* pCfg)
void slog_config_set(slog_config_t *pCfg)
{
slog_lock(&g_slog);
slog_config_t *pOldCfg = &g_slog.config;
slog_file_t *pFile = &g_slog.logFile;
if (!pCfg->nToFile ||
strncmp(pOldCfg->sFilePath, pCfg->sFilePath, sizeof(pOldCfg->sFilePath)) ||
strncmp(pOldCfg->sFileName, pCfg->sFileName, sizeof(pOldCfg->sFileName)))
slog_close_file(pFile); /* Log function will open it again if required */
g_slog.config = *pCfg;
slog_unlock(&g_slog);
}
@@ -441,11 +460,11 @@ void slog_config_set(slog_config_t* pCfg)
void slog_enable(slog_flag_t eFlag)
{
slog_lock(&g_slog);
slog_config_t *pCfg = &g_slog.config;
if (!SLOG_FLAGS_CHECK(g_slog.config.nFlags, eFlag))
{
g_slog.config.nFlags |= eFlag;
}
if (eFlag == SLOG_FLAGS_ALL) pCfg->nFlags = SLOG_FLAGS_ALL;
else if (!SLOG_FLAGS_CHECK(pCfg->nFlags, eFlag)) pCfg->nFlags |= eFlag;
slog_unlock(&g_slog);
}
@@ -453,19 +472,18 @@ void slog_enable(slog_flag_t eFlag)
void slog_disable(slog_flag_t eFlag)
{
slog_lock(&g_slog);
slog_config_t *pCfg = &g_slog.config;
if (SLOG_FLAGS_CHECK(g_slog.config.nFlags, eFlag))
{
g_slog.config.nFlags &= ~eFlag;
}
if (eFlag == SLOG_FLAGS_ALL) pCfg->nFlags = 0;
else if (SLOG_FLAGS_CHECK(pCfg->nFlags, eFlag)) pCfg->nFlags &= ~eFlag;
slog_unlock(&g_slog);
}
void slog_separator_set(const char* pFormat, ...)
void slog_separator_set(const char *pFormat, ...)
{
slog_lock(&g_slog);
slog_config_t* pCfg = &g_slog.config;
slog_config_t *pCfg = &g_slog.config;
va_list args;
va_start(args, pFormat);
@@ -487,10 +505,10 @@ void slog_indent(uint8_t nEnable)
slog_unlock(&g_slog);
}
void slog_callback_set(slog_cb_t callback, void* pContext)
void slog_callback_set(slog_cb_t callback, void *pContext)
{
slog_lock(&g_slog);
slog_config_t* pCfg = &g_slog.config;
slog_config_t *pCfg = &g_slog.config;
pCfg->pCallbackCtx = pContext;
pCfg->logCallback = callback;
slog_unlock(&g_slog);
@@ -498,8 +516,10 @@ void slog_callback_set(slog_cb_t callback, void* pContext)
void slog_init(const char* pName, uint16_t nFlags, uint8_t nTdSafe)
{
slog_config_t *pCfg = &g_slog.config;
slog_file_t *pFile = &g_slog.logFile;
/* Set up default values */
slog_config_t* pCfg = &g_slog.config;
pCfg->eColorFormat = SLOG_COLORING_TAG;
pCfg->eDateControl = SLOG_TIME_ONLY;
pCfg->pCallbackCtx = NULL;
@@ -508,19 +528,24 @@ void slog_init(const char* pName, uint16_t nFlags, uint8_t nTdSafe)
pCfg->sSeparator[1] = '\0';
pCfg->sFilePath[0] = '.';
pCfg->sFilePath[1] = '\0';
pCfg->nKeepOpen = 0;
pCfg->nTraceTid = 0;
pCfg->nToScreen = 1;
pCfg->nUseHeap = 0;
pCfg->nToFile = 0;
pCfg->nIndent = 0;
pCfg->nRotate = 1;
pCfg->nFlush = 0;
pCfg->nFlags = nFlags;
const char* pFileName = (pName != NULL) ? pName : SLOG_NAME_DEFAULT;
const char *pFileName = (pName != NULL) ? pName : SLOG_NAME_DEFAULT;
snprintf(pCfg->sFileName, sizeof(pCfg->sFileName), "%s", pFileName);
pFile->pHandle = NULL;
pFile->nCurrDay = 0;
#ifdef WIN32
// Enable color support
/* Enable color support */
HANDLE hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
DWORD dwMode = 0;
GetConsoleMode(hOutput, &dwMode);
@@ -535,8 +560,14 @@ void slog_init(const char* pName, uint16_t nFlags, uint8_t nTdSafe)
void slog_destroy()
{
slog_lock(&g_slog);
memset(&g_slog.config, 0, sizeof(g_slog.config));
g_slog.config.pCallbackCtx = NULL;
g_slog.config.logCallback = NULL;
slog_close_file(&g_slog.logFile);
slog_unlock(&g_slog);
if (g_slog.nTdSafe)
{
+55 -52
View File
@@ -31,11 +31,12 @@ extern "C" {
#include <inttypes.h>
#include <pthread.h>
#include <stdint.h>
/* SLog version information */
#define SLOG_VERSION_MAJOR 1
#define SLOG_VERSION_MINOR 8
#define SLOG_BUILD_NUM 26
#define SLOG_BUILD_NUMBER 37
/* Supported colors */
#define SLOG_COLOR_NORMAL "\x1B[0m"
@@ -73,19 +74,18 @@ extern "C" {
#define SLOG_EMPTY ""
#define SLOG_NUL '\0'
typedef struct SLogDate
{
typedef struct slog_date {
uint16_t nYear;
uint8_t nMonth;
uint8_t nDay;
uint8_t nHour;
uint8_t nMin;
uint8_t nSec;
uint8_t nUsec;
uint16_t nUsec;
} slog_date_t;
uint8_t slog_get_usec();
void slog_get_date(slog_date_t* pDate);
uint16_t slog_get_usec();
void slog_get_date(slog_date_t *pDate);
/* Log level flags */
typedef enum
@@ -100,7 +100,7 @@ typedef enum
SLOG_FATAL = (1 << 7)
} slog_flag_t;
typedef int(*slog_cb_t)(const char* pLog, size_t nLength, slog_flag_t eFlag, void* pCtx);
typedef int(*slog_cb_t)(const char *pLog, size_t nLength, slog_flag_t eFlag, void *pCtx);
/* Output coloring control flags */
typedef enum
@@ -117,32 +117,25 @@ typedef enum
SLOG_DATE_FULL
} slog_date_ctrl_t;
#define slog(...) \
slog_display(SLOG_NOTAG, 1, __VA_ARGS__)
/* Slog function definitions */
#define slog(...) slog_display(SLOG_NOTAG, 1, __VA_ARGS__)
#define slog_note(...) slog_display(SLOG_NOTE, 1, __VA_ARGS__)
#define slog_info(...) slog_display(SLOG_INFO, 1, __VA_ARGS__)
#define slog_warn(...) slog_display(SLOG_WARN, 1, __VA_ARGS__)
#define slog_debug(...) slog_display(SLOG_DEBUG, 1, __VA_ARGS__)
#define slog_error(...) slog_display(SLOG_ERROR, 1, __VA_ARGS__)
#define slog_trace(...) slog_display(SLOG_TRACE, 1, SLOG_THROW_LOCATION __VA_ARGS__)
#define slog_fatal(...) slog_display(SLOG_FATAL, 1, SLOG_THROW_LOCATION __VA_ARGS__)
#define slogwn(...) \
slog_display(SLOG_NOTAG, 0, __VA_ARGS__)
#define slog_note(...) \
slog_display(SLOG_NOTE, 1, __VA_ARGS__)
#define slog_info(...) \
slog_display(SLOG_INFO, 1, __VA_ARGS__)
#define slog_warn(...) \
slog_display(SLOG_WARN, 1, __VA_ARGS__)
#define slog_debug(...) \
slog_display(SLOG_DEBUG, 1, __VA_ARGS__)
#define slog_error(...) \
slog_display(SLOG_ERROR, 1, __VA_ARGS__)
#define slog_trace(...) \
slog_display(SLOG_TRACE, 1, SLOG_THROW_LOCATION __VA_ARGS__)
#define slog_fatal(...) \
slog_display(SLOG_FATAL, 1, SLOG_THROW_LOCATION __VA_ARGS__)
/* No new line definitions */
#define slog_wn(...) slog_display(SLOG_NOTAG, 0, __VA_ARGS__)
#define slog_note_wn(...) slog_display(SLOG_NOTE, 0, __VA_ARGS__)
#define slog_info_wn(...) slog_display(SLOG_INFO, 0, __VA_ARGS__)
#define slog_warn_wn(...) slog_display(SLOG_WARN, 0, __VA_ARGS__)
#define slog_debug_wn(...) slog_display(SLOG_DEBUG, 0, __VA_ARGS__)
#define slog_error_wn(...) slog_display(SLOG_ERROR, 0, __VA_ARGS__)
#define slog_trace_wn(...) slog_display(SLOG_TRACE, 0, SLOG_THROW_LOCATION __VA_ARGS__)
#define slog_fatal_wn(...) slog_display(SLOG_FATAL, 0, SLOG_THROW_LOCATION __VA_ARGS__)
/* Short name definitions */
#define slogn(...) slog_note(__VA_ARGS__)
@@ -153,40 +146,50 @@ typedef enum
#define slogt(...) slog_trace(__VA_ARGS__)
#define slogf(...) slog_fatal(__VA_ARGS__)
typedef struct SLogConfig
{
slog_date_ctrl_t eDateControl; // Display output with date format
slog_coloring_t eColorFormat; // Output color format control
slog_cb_t logCallback; // Log callback to collect logs
void* pCallbackCtx; // Data pointer passed to log callback
/* Short name definitions without new line */
#define slogn_wn(...) slog_note_wn(__VA_ARGS__)
#define slogi_wn(...) slog_info_wn(__VA_ARGS__)
#define slogw_wn(...) slog_warn_wn(__VA_ARGS__)
#define slogd_wn(...) slog_debug_wn( __VA_ARGS__)
#define sloge_wn(...) slog_error_wn( __VA_ARGS__)
#define slogt_wn(...) slog_trace_wn(__VA_ARGS__)
#define slogf_wn(...) slog_fatal_wn(__VA_ARGS__)
uint8_t nTraceTid; // Trace thread ID and display in output
uint8_t nToScreen; // Enable screen logging
uint8_t nUseHeap; // Use dynamic allocation
uint8_t nToFile; // Enable file logging
uint8_t nIndent; // Enable indentations
uint8_t nFlush; // Flush stdout after screen log
uint16_t nFlags; // Allowed log level flags
typedef struct SLogConfig {
slog_date_ctrl_t eDateControl; // Display output with date format
slog_coloring_t eColorFormat; // Output color format control
slog_cb_t logCallback; // Log callback to collect logs
void* pCallbackCtx; // Data pointer passed to log callback
uint8_t nKeepOpen; // Keep file handle open for next file writes
uint8_t nTraceTid; // Trace thread ID and display in output
uint8_t nToScreen; // Enable screen logging
uint8_t nUseHeap; // Use dynamic allocation
uint8_t nToFile; // Enable file logging
uint8_t nIndent; // Enable indentations
uint8_t nRotate; // Enable log rotation
uint8_t nFlush; // Flush stdout after screen log
uint16_t nFlags; // Allowed log level flags
char sSeparator[SLOG_NAME_MAX]; // Separator between info and log
char sFileName[SLOG_NAME_MAX]; // Output file name for logs
char sFilePath[SLOG_PATH_MAX]; // Output file path for logs
} slog_config_t;
size_t slog_version(char* pDest, size_t nSize, uint8_t nMin);
void slog_config_get(slog_config_t* pCfg);
void slog_config_set(slog_config_t* pCfg);
const char* slog_version(uint8_t nShort);
void slog_config_get(slog_config_t *pCfg);
void slog_config_set(slog_config_t *pCfg);
void slog_separator_set(const char* pFormat, ...);
void slog_callback_set(slog_cb_t callback, void* pContext);
void slog_separator_set(const char *pFormat, ...);
void slog_callback_set(slog_cb_t callback, void *pContext);
void slog_indent(uint8_t nEnable);
void slog_enable(slog_flag_t eFlag);
void slog_disable(slog_flag_t eFlag);
void slog_init(const char* pName, uint16_t nFlags, uint8_t nTdSafe);
void slog_display(slog_flag_t eFlag, uint8_t nNewLine, const char* pFormat, ...);
void slog_destroy(); // Needed only if the slog_init() function argument nTdSafe > 0
void slog_display(slog_flag_t eFlag, uint8_t nNewLine, char *pFormat, ...);
void slog_destroy(); // Required only if (nTdSafe > 0 || nKeepOpen > 0)
#ifdef __cplusplus
}
+2 -2
View File
@@ -5,8 +5,8 @@
#include <unistd.h>
#include <string.h>
#include "../src/monocoque/simulatorapi/simdata.h"
#include "../src/monocoque/simulatorapi/test.h"
#include "../src/monocoque/simulatorapi/simapi/simapi/simdata.h"
#include "../src/monocoque/simulatorapi/simapi/simapi/test.h"
int main(int argc, char* argv[])
{
+2 -2
View File
@@ -6,8 +6,8 @@
#include <string.h>
#include <termios.h>
#include "../src/monocoque/simulatorapi/simdata.h"
#include "../src/monocoque/simulatorapi/test.h"
#include "../src/monocoque/simulatorapi/simapi/simapi/simdata.h"
#include "../src/monocoque/simulatorapi/simapi/simapi/test.h"
#define DATA "Hello, World! From PID %d"
+2 -2
View File
@@ -5,8 +5,8 @@
#include <unistd.h>
#include <string.h>
#include "../src/monocoque/simulatorapi/simdata.h"
#include "../src/monocoque/simulatorapi/test.h"
#include "../src/monocoque/simulatorapi/simapi/simapi/simdata.h"
#include "../src/monocoque/simulatorapi/simapi/simapi/test.h"
#define DATA "Hello, World! From PID %d"
+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);
}
+86 -32
View File
@@ -2,21 +2,15 @@
#include <stdlib.h>
#include <unistd.h>
#include <libserialport.h>
#include "../src/monocoque/simulatorapi/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,110 @@ 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[4];
for(int j = 0; j < 4; 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);
printf("numlights is %i\n", 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);
BIN
View File
Binary file not shown.
+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"
}
+4
View File
@@ -1 +1,5 @@
SUBSYSTEMS=="usb",ATTRS{product}=="Rev Burner",GROUP="input",TAG+="uaccess"
SUBSYSTEM=="tty", ATTRS{idVendor}=="2341", ATTRS{idProduct}=="0043", ATTRS{serial}=="75033303335351A080F0", SYMLINK+="simdev0", GROUP="input", TAG+="uaccess"
SUBSYSTEM=="tty", ATTRS{idVendor}=="2341", ATTRS{idProduct}=="0043", ATTRS{serial}=="242303138313514131F1", SYMLINK+="simdev1", GROUP="input", TAG+="uaccess"