monocoque initial commit

This commit is contained in:
Paul Dino Jones 2022-10-31 15:11:02 +00:00
commit 9325e207be
65 changed files with 6352 additions and 0 deletions

3
.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
/build
/src/monocoque/tags
/src/monocoque/simulatorapi/simapi

3
.gitmodules vendored Normal file
View File

@ -0,0 +1,3 @@
[submodule "src/monocoque/simulatorapi/simapi"]
path = src/monocoque/simulatorapi/simapi
url = https://github.com/spacefreak18/simapi

109
.valgrindrc Normal file
View File

@ -0,0 +1,109 @@
{
argtable arg_parse
Memcheck:Leak
...
...
...
fun:arg_parse
...
...
}
{
Portaudio clone1
Memcheck:Cond
...
...
...
...
...
fun:clone
}
{
Portaudio clone2
Memcheck:Cond
...
...
...
...
fun:clone
}
{
Portaudio start_thread
Memcheck:Cond
...
...
...
...
...
...
...
...
...
...
...
fun:start_thread
}
{
Portaudio Pa_Initialize
Memcheck:Cond
...
...
...
...
...
...
...
...
...
fun:Pa_Initialize
...
...
}
{
Portaudio Pa_OpenStream
Memcheck:Cond
...
...
...
...
...
...
...
...
...
fun:Pa_OpenStream
...
...
}
{
Portaudio Pa_OpenStream2
Memcheck:Cond
...
...
...
...
...
...
...
fun:Pa_OpenStream
...
...
...
...
}
{
Portaudio Pa_CloseStream
Memcheck:Cond
...
...
...
...
...
...
...
...
...
fun:usb_generic_shaker_free
...
...
}

156
CMakeLists.txt Normal file
View File

@ -0,0 +1,156 @@
# minimum CMake version required for C++20 support, among other things
cmake_minimum_required(VERSION 3.15)
# detect if Monocoque is being used as a sub-project of another CMake project
if(NOT DEFINED PROJECT_NAME)
set(MONOCOQUE_SUBPROJECT OFF)
else()
set(MONOCOQUE_SUBPROJECT ON)
endif()
SET_SOURCE_FILES_PROPERTIES( src/monocoque.c PROPERTIES LANGUAGE C)
set(CMAKE_BUILD_TYPE Debug)
project(monocoque)
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
set(BUILD_SHARED_LIBS TRUE) # HIDAPI as static library on all platforms
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 ${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(simlighttest tests/simlighttest.c)
target_include_directories(simlighttest PUBLIC)
target_link_libraries(simlighttest serialport)
add_test(simlighttest simlighttest)
# used for enabling additional compiler options if supported
include(CheckCXXCompilerFlag)
function(enable_cxx_compiler_flag_if_supported flag)
message(STATUS "[monocoque] Checking if compiler supports warning flag '${flag}'")
check_cxx_compiler_flag("${flag}" flag_supported)
if(flag_supported)
message(STATUS "[monocoque] Enabling warning flag '${flag}'")
target_compile_options(monocoque INTERFACE "${flag}")
endif()
unset(flag_supported CACHE)
endfunction()
# enable a large amount of extra warnings, regardless of build mode
if (MSVC) # MSVC supports different warning options to GCC/Clang
enable_cxx_compiler_flag_if_supported("/W3") # set warning level 3
# if tests are enabled, enable converting all warnings to errors too
if (ENABLE_TESTS)
# add_compile_options(/WX)
enable_cxx_compiler_flag_if_supported("/WX")
endif()
else() # GCC/Clang warning option
# NOTE: GCC and Clang support most of the same options, but neither supports all
# of the others'. By only enabling them if supported, we get graceful failure
# when trying to enable unsupported flags
# e.g. at the time of writing, GCC does not support -Wdocumentation
#
# enable all warnings about 'questionable constructs'
enable_cxx_compiler_flag_if_supported("-Wall")
# issue 'pedantic' warnings for strict ISO compliance
enable_cxx_compiler_flag_if_supported("-pedantic")
# enable 'extra' strict warnings
enable_cxx_compiler_flag_if_supported("-Wextra")
# enable sign conversion warnings
enable_cxx_compiler_flag_if_supported("-Wsign-conversion")
# enable warnings about mistakes in Doxygen documentation
enable_cxx_compiler_flag_if_supported("-Wdocumentation")
# if tests are enabled, enable converting all warnings to errors too
if (ENABLE_TESTS)
enable_cxx_compiler_flag_if_supported("-Werror")
# exclude the following kinds of warnings from being converted into errors
# unknown-pragma is useful to have as a warning but not as an error, if you have
# pragmas which are for the consumption of one compiler only
enable_cxx_compiler_flag_if_supported("-Wno-error=unknown-pragmas")
# unused variable and function warnings are helpful but we don't need them as errors
enable_cxx_compiler_flag_if_supported("-Wno-error=unused-function")
enable_cxx_compiler_flag_if_supported("-Wno-error=unused-variable")
enable_cxx_compiler_flag_if_supported("-Wno-error=unused-parameter")
enable_cxx_compiler_flag_if_supported("-Wno-error=unused-private-field")
enable_cxx_compiler_flag_if_supported("-Wno-error=unused-but-set-variable")
endif()
endif()
# library
# unit tests --only enable if requested AND we're not building as a sub-project
if(ENABLE_TESTS AND NOT MONOCOQUE_SUBPROJECT)
message(STATUS "[monocoque] Unit Tests Enabled")
add_subdirectory(tests)
enable_testing()
endif()

339
LICENSE.rst Normal file
View File

@ -0,0 +1,339 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Lesser General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License.

65
README.md Normal file
View File

@ -0,0 +1,65 @@
# Monocoque
```
___ |/ /____________________________________ ____ ______
__ /|_/ /_ __ \_ __ \ __ \ ___/ __ \ __ `/ / / / _ \
_ / / / / /_/ / / / / /_/ / /__ / /_/ / /_/ // /_/ // __/
/_/ /_/ \____//_/ /_/\____/\___/ \____/\__, / \__,_/ \___/
/_/
```
Cross Platform device manager for driving and flight simulators, for use with common simulator software titles.
## Features
- Updates at 120 frames per seconds.
- Modular design for support with various titles and devices.
- Supports bass shakers, tachometers, 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.
## Dependencies
- libserialport - arduino serial devices
- hidapi - usb hid devices
- libusb - used by hidapi
- portaudio - sound devices (haptic bass shakers)
- libenet - UDP support
- libxml2
- argtable2
- libconfig
- slog (static)
- [wine-linux-shm-adapter](https://github.com/spacefreak18/wine-linux-shm-adapter)
- [simapi](https://github.com/spacefreak18/simapi)
## 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:
```
git submodule sync --recursive
git submodule update --init --recursive
```
Then to compile simply:
```
mkdir build; cd build
cmake ..
make
```
## Testing
### Static Analysis
```
mkdir build; cd build
make clean
CFLAGS=-fanalyzer cmake ..
make
```
### Valgrind
```
cd build
valgrind -v --leak-check=full --show-leak-kinds=all --suppressions=../.valgrindrc ./monocoque play
```
## ToDo
- 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

15
conf/monocoque.config Normal file
View File

@ -0,0 +1,15 @@
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"; } );

34
conf/revburner.xml Normal file
View File

@ -0,0 +1,34 @@
<?xml version="1.0" encoding="UTF-8"?>
<TachometerSettings>
<SettingsValues>
<SettingsItem>
<Value>300</Value>
<TimeValue>43600</TimeValue>
</SettingsItem>
<SettingsItem>
<Value>500</Value>
<TimeValue>48800</TimeValue>
</SettingsItem>
<SettingsItem>
<Value>1000</Value>
<TimeValue>54700</TimeValue>
</SettingsItem>
<SettingsItem>
<Value>1500</Value>
<TimeValue>58600</TimeValue>
</SettingsItem>
<SettingsItem>
<Value>2000</Value>
<TimeValue>60100</TimeValue>
</SettingsItem>
<SettingsItem>
<Value>2500</Value>
<TimeValue>61100</TimeValue>
</SettingsItem>
<SettingsItem>
<Value>3000</Value>
<TimeValue>61900</TimeValue>
</SettingsItem>
</SettingsValues>
<MaxDisplayValue>3000</MaxDisplayValue>
</TachometerSettings>

View File

@ -0,0 +1,95 @@
#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++;
}
}

View File

@ -0,0 +1,93 @@
#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++;
}
}

View File

@ -0,0 +1,22 @@
set(devices_source_files
simdevice.h
simdevice.c
usbdevice.h
usbdevice.c
sounddevice.h
sounddevice.c
serialdevice.h
serialdevice.c
tachdevice.h
tachdevice.c
usb/revburner.h
usb/revburner.c
sound/usb_generic_shaker.h
sound/usb_generic_shaker.c
serial/arduino.h
serial/arduino.c
)
include_directories("." "usb" "sound" "serial")
add_library(devices STATIC ${devices_source_files})

View File

@ -0,0 +1,79 @@
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include "arduino.h"
#include "../slog/slog.h"
#define arduino_timeout 2000
int arduino_update(SerialDevice* serialdevice, SimData* simdata)
{
int result = 1;
if (serialdevice->port)
{
result = check(sp_blocking_write(serialdevice->port, simdata, sizeof(SimData), arduino_timeout));
}
return result;
}
int arduino_init(SerialDevice* serialdevice)
{
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;
}
}

View File

@ -0,0 +1,11 @@
#ifndef _ARDUINO_H
#define _ARDUINO_H
#include "../serialdevice.h"
int arduino_update(SerialDevice* serialdevice, SimData* simdata);
int arduino_init(SerialDevice* serialdevice);
int arduino_free(SerialDevice* serialdevice);
int check(enum sp_return result);
#endif

View File

@ -0,0 +1,35 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "serialdevice.h"
#include "serial/arduino.h"
#include "../helper/parameters.h"
#include "../simulatorapi/simdata.h"
#include "../slog/slog.h"
int serialdev_update(SerialDevice* serialdevice, SimData* simdata)
{
arduino_update(serialdevice, simdata);
return 0;
}
int serialdev_free(SerialDevice* serialdevice)
{
arduino_free(serialdevice);
return 0;
}
int serialdev_init(SerialDevice* serialdevice)
{
slogi("initializing serial device...");
int error = 0;
serialdevice->type = SERIALDEV_UNKNOWN;
serialdevice->type = SERIALDEV_ARDUINO;
error = arduino_init(serialdevice);
return error;
}

View File

@ -0,0 +1,27 @@
#ifndef _SERIALDEVICE_H
#define _SERIALDEVICE_H
#include <libserialport.h>
#include "../helper/parameters.h"
#include "../simulatorapi/simdata.h"
typedef enum
{
SERIALDEV_UNKNOWN = 0,
SERIALDEV_ARDUINO = 1
}
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);
#endif

View File

@ -0,0 +1,85 @@
#include <stdio.h>
#include "simdevice.h"
#include "../helper/parameters.h"
#include "../helper/confighelper.h"
#include "../simulatorapi/simdata.h"
#include "../slog/slog.h"
int devupdate(SimDevice* simdevice, 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;
}
return 0;
}
int devfree(SimDevice* simdevice)
{
if (simdevice->initialized==false)
{
slogw("Attempt to free an uninitialized device");
return MONOCOQUE_ERROR_INVALID_DEV;
}
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;
}

View File

@ -0,0 +1,34 @@
#ifndef _SIMDEVICE_H
#define _SIMDEVICE_H
#include <stdbool.h>
#include "usbdevice.h"
#include "sounddevice.h"
#include "serialdevice.h"
#include "../helper/confighelper.h"
#include "../simulatorapi/simdata.h"
typedef struct
{
int id;
bool initialized;
DeviceType type;
union
{
USBDevice usbdevice;
SoundDevice sounddevice;
SerialDevice serialdevice;
} d;
}
SimDevice;
int devupdate(SimDevice* simdevice, SimData* simdata);
int devinit(SimDevice* simdevice, DeviceSettings* ds);
int devfree(SimDevice* simdevice);
#endif

View File

@ -0,0 +1,128 @@
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <unistd.h>
#include "portaudio.h"
#include "usb_generic_shaker.h"
#include "../sounddevice.h"
#define SAMPLE_RATE (48000)
#ifndef M_PI
#define M_PI (3.14159265)
#endif
int patestCallback(const void* inputBuffer,
void* outputBuffer,
unsigned long framesPerBuffer,
const PaStreamCallbackTimeInfo* timeInfo,
PaStreamCallbackFlags statusFlags,
void* userData)
{
PATestData* data = (PATestData*)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++ )
{
float v = 0;
v = data->amp * sin (2 * M_PI * ((float) n) / (float) SAMPLE_RATE);
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;
}
}
data->n=n;
return 0;
}
int usb_generic_shaker_free(SoundDevice* sounddevice)
{
int err = 0;
err = Pa_CloseStream( sounddevice->stream );
if( err != paNoError )
{
err = Pa_Terminate();
}
return err;
}
int usb_generic_shaker_init(SoundDevice* sounddevice)
{
PaError err;
err = paNoError;
err = Pa_Initialize();
if( err != paNoError )
{
goto error;
}
sounddevice->outputParameters.device = Pa_GetDefaultOutputDevice(); /* default output device */
sounddevice->outputParameters.channelCount = 2; /* stereo output */
sounddevice->outputParameters.sampleFormat = paFloat32; /* 32 bit floating point output */
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( err != paNoError )
{
goto error;
}
err = Pa_StartStream( sounddevice->stream );
if( err != paNoError )
{
goto error;
}
return err;
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;
}

View File

@ -0,0 +1,9 @@
#ifndef _USB_GENERIC_SHAKER_H
#define _USB_GENERIC_SHAKER_H
#include "../sounddevice.h"
int usb_generic_shaker_init(SoundDevice* sounddevice);
int usb_generic_shaker_free(SoundDevice* sounddevice);
#endif

View File

@ -0,0 +1,38 @@
#include <stdio.h>
#include "sounddevice.h"
#include "sound/usb_generic_shaker.h"
#include "../simulatorapi/simdata.h"
#include "../helper/parameters.h"
#include "../slog/slog.h"
int sounddev_update(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)
{
sounddevice->sounddata.gear_sound_data = sounddevice->sounddata.amp;
}
sounddevice->sounddata.last_gear = simdata->gear;
}
int sounddev_free(SoundDevice* sounddevice)
{
return usb_generic_shaker_free(sounddevice);
}
int sounddev_init(SoundDevice* sounddevice)
{
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;
usb_generic_shaker_init(sounddevice);
}

View File

@ -0,0 +1,45 @@
#ifndef _SOUNDDEVICE_H
#define _SOUNDDEVICE_H
#include "portaudio.h"
#include "../simulatorapi/simdata.h"
#include "../helper/parameters.h"
typedef enum
{
SOUNDDEV_UNKNOWN = 0,
SOUNDDEV_SHAKER = 1
}
SoundType;
#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;
}
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);
#endif

View File

@ -0,0 +1,80 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "tachdevice.h"
#include "revburner.h"
#include "../../helper/confighelper.h"
#include "../../simulatorapi/simdata.h"
#include "../../slog/slog.h"
int tachdev_update(TachDevice* tachdevice, SimData* simdata)
{
// current plan is to just use the revburner xml format for other possible tachometer devices
// with that assumption this same logic is assumed the same for other tachometer devices
// the only difference then being in communication to the physical device
int pulses = simdata->pulses;
switch ( tachdevice->type )
{
case TACHDEV_UNKNOWN :
case TACHDEV_REVBURNER :
if (tachdevice->tachsettings.use_pulses == false)
{
slogt("Getting pulses for current tachometer revs");
if (simdata->rpms < 500)
{
pulses = tachdevice->tachsettings.pulses_array[0];
}
else
{
slogt("Tach settings size %i",tachdevice->tachsettings.size);
int el = simdata->rpms / 1000;
if (tachdevice->tachsettings.granularity > 0)
{
el = simdata->rpms / (1000 / tachdevice->tachsettings.granularity);
}
if (el >= tachdevice->tachsettings.size - 1)
{
el = tachdevice->tachsettings.size - 1;
}
slogt("Retrieveing element %i", el);
pulses = tachdevice->tachsettings.pulses_array[el];
}
}
slogt("Settings tachometer pulses to %i", pulses);
revburner_update(tachdevice, pulses);
break;
}
return 0;
}
int tachdev_free(TachDevice* tachdevice)
{
switch ( tachdevice->type )
{
case TACHDEV_UNKNOWN :
case TACHDEV_REVBURNER :
revburner_update(tachdevice, 0);
revburner_free(tachdevice);
break;
}
return 0;
}
int tachdev_init(TachDevice* tachdevice, DeviceSettings* ds)
{
slogi("initializing tachometer device...");
int error = 0;
// detection of tach device model
tachdevice->type = TACHDEV_UNKNOWN;
tachdevice->type = TACHDEV_REVBURNER;
tachdevice->tachsettings = ds->tachsettings;
error = revburner_init(tachdevice);
return error;
}

View File

@ -0,0 +1,31 @@
#ifndef _TACHDEVICE_H
#define _TACHDEVICE_H
#include <hidapi/hidapi.h>
#include "../helper/confighelper.h"
#include "../simulatorapi/simdata.h"
//typedef int (*tachdev_update)(int revs);
typedef enum
{
TACHDEV_UNKNOWN = 0,
TACHDEV_REVBURNER = 1
}
TachType;
typedef struct
{
int id;
TachType type;
bool use_pulses;
hid_device* handle;
TachometerSettings tachsettings;
}
TachDevice;
int tachdev_update(TachDevice* tachdevice, SimData* simdata);
int tachdev_init(TachDevice* tachdevice, DeviceSettings* ds);
int tachdev_free(TachDevice* tachdevice);
#endif

View File

@ -0,0 +1,69 @@
#include <stdio.h>
#include <hidapi/hidapi.h>
#include "tachdevice.h"
#include "../slog/slog.h"
const int buf_size = 65;
int revburner_update(TachDevice* tachdevice, int pulses)
{
int res = 0;
unsigned char bytes[buf_size];
for (int x = 0; x < buf_size; x++)
{
bytes[x] = 0x00;
}
if ( pulses > 0 )
{
bytes[3] = (pulses >> 8) & 0xFF;
bytes[2] = pulses & 0xFF;
}
if (tachdevice->handle)
{
res = hid_write(tachdevice->handle, bytes, buf_size);
}
else
{
slogd("no handle");
}
return res;
}
int revburner_free(TachDevice* tachdevice)
{
int res = 0;
hid_close(tachdevice->handle);
res = hid_exit();
return res;
}
int revburner_init(TachDevice* tachdevice)
{
slogi("initializing revburner tachometer...");
//tachdevice->update_tachometer = revburner_device_update;
int res = 0;
res = hid_init();
tachdevice->handle = hid_open(0x4d8, 0x102, NULL);
if (!tachdevice->handle)
{
sloge("Could not find attached RevBurner tachometer");
res = hid_exit();
return 1;
}
slogd("Found RevBurner Tachometer...");
return res;
}

View File

@ -0,0 +1,8 @@
#ifndef _REVBURNER_H
#define _REVBURNER_H
int revburner_update(TachDevice* tachdevice, int pulses);
int revburner_init(TachDevice* tachdevice);
int revburner_free(TachDevice* tachdevice);
#endif

View File

@ -0,0 +1,49 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "usbdevice.h"
#include "../helper/parameters.h"
#include "../simulatorapi/simdata.h"
#include "../slog/slog.h"
int usbdev_update(USBDevice* usbdevice, SimData* simdata)
{
switch ( usbdevice->type )
{
case USBDEV_UNKNOWN :
case USBDEV_TACHOMETER :
tachdev_update(&usbdevice->u.tachdevice, simdata);
break;
}
return 0;
}
int usbdev_free(USBDevice* usbdevice)
{
switch ( usbdevice->type )
{
case USBDEV_UNKNOWN :
case USBDEV_TACHOMETER :
tachdev_free(&usbdevice->u.tachdevice);
break;
}
return 0;
}
int usbdev_init(USBDevice* usbdevice, DeviceSettings* ds)
{
slogi("initializing usb device...");
int error = 0;
switch ( usbdevice->type )
{
case USBDEV_UNKNOWN :
case USBDEV_TACHOMETER :
error = tachdev_init(&usbdevice->u.tachdevice, ds);
break;
}
return error;
}

View File

@ -0,0 +1,30 @@
#ifndef _USBDEVICE_H
#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);
#endif

View File

@ -0,0 +1,11 @@
set(gameloop_source_files
gameloop.c
gameloop.h
tachconfig.c
tachconfig.h
)
set(LIBXML_INCLUDE_DIR /usr/include/libxml2)
include_directories("." ${LIBXML_INCLUDE_DIR})
add_library(gameloop STATIC ${gameloop_source_files})

View File

@ -0,0 +1,218 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>
#include <poll.h>
#include <termios.h>
#include "gameloop.h"
#include "../helper/parameters.h"
#include "../helper/confighelper.h"
#include "../devices/simdevice.h"
#include "../simulatorapi/simdata.h"
#include "../simulatorapi/simmapper.h"
#include "../slog/slog.h"
#define DEFAULT_UPDATE_RATE 120.0
int showstats(SimData* simdata)
{
printf("\r");
for (int i=0; i<4; i++)
{
if (i==0)
{
fputc('s', stdout);
fputc('p', stdout);
fputc('e', stdout);
fputc('e', stdout);
fputc('d', stdout);
fputc(':', stdout);
fputc(' ', stdout);
int speed = simdata->velocity;
int digits = 0;
while (speed > 0)
{
int mod = speed % 10;
speed = speed / 10;
digits++;
}
speed = simdata->velocity;
int s[digits];
int digit = 0;
while (speed > 0)
{
int mod = speed % 10;
s[digit] = mod;
speed = speed / 10;
digit++;
}
speed = simdata->velocity;
digit = digits;
while (digit > 0)
{
fputc(s[digit-1]+'0', stdout);
digit--;
}
fputc(' ', stdout);
}
if (i==1)
{
fputc('r', stdout);
fputc('p', stdout);
fputc('m', stdout);
fputc('s', stdout);
fputc(':', stdout);
fputc(' ', stdout);
int rpms = simdata->rpms;
int digits = 0;
while (rpms > 0)
{
int mod = rpms % 10;
rpms = rpms / 10;
digits++;
}
rpms = simdata->rpms;
int s[digits];
int digit = 0;
while (rpms > 0)
{
int mod = rpms % 10;
s[digit] = mod;
rpms = rpms / 10;
digit++;
}
rpms = simdata->rpms;
digit = digits;
while (digit > 0)
{
fputc(s[digit-1]+'0', stdout);
digit--;
}
fputc(' ', stdout);
}
if (i==2)
{
fputc('g', stdout);
fputc('e', stdout);
fputc('a', stdout);
fputc('r', stdout);
fputc(':', stdout);
fputc(' ', stdout);
fputc(simdata->gear+'0', stdout);
fputc(' ', stdout);
}
if (i==3)
{
fputc('a', stdout);
fputc('l', stdout);
fputc('t', stdout);
fputc(':', stdout);
fputc(' ', stdout);
int alt = simdata->altitude;
int digits = 0;
while (alt > 0)
{
int mod = alt % 10;
alt = alt / 10;
digits++;
}
alt = simdata->altitude;
int s[digits];
int digit = 0;
while (alt > 0)
{
int mod = alt % 10;
s[digit] = mod;
alt = alt / 10;
digit++;
}
alt = simdata->altitude;
digit = digits;
while (digit > 0)
{
fputc(s[digit-1]+'0', stdout);
digit--;
}
fputc(' ', stdout);
}
}
fflush(stdout);
}
int looper(SimDevice* devices[], int numdevices, Simulator simulator)
{
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)
{
return error;
}
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);
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);
}
}
if(t>=update_rate)
{
t=0;
}
if( poll(&mypoll, 1, 1000.0/update_rate) )
{
scanf("%c", &ch);
if(ch == 'q')
{
go = false;
}
}
}
tcsetattr(0, TCSANOW, &canonicalmode);
free(simdata);
free(simmap);
return 0;
}

View File

@ -0,0 +1,4 @@
#include "../devices/simdevice.h"
#include "../helper/parameters.h"
int looper (SimDevice* devices[], int numdevices, Simulator simulator);

View File

@ -0,0 +1,190 @@
#include <stdio.h>
#include <unistd.h>
#include <sys/poll.h>
#include <sys/time.h>
#include <sys/select.h>
#include <fcntl.h>
#include <errno.h>
#include <linux/input.h>
#include <string.h>
#include <termios.h>
#include <poll.h>
#include <libxml/parser.h>
#include <libxml/xmlreader.h>
#include <libxml/tree.h>
#include "../devices/simdevice.h"
#include "../simulatorapi/simdata.h"
#include "../slog/slog.h"
#define DEFAULT_UPDATE_RATE 30.0
int WriteXmlFromArrays(int nodes, int rpm_array[], int values_array[], int maxrevs, const char* save_file)
{
xmlDocPtr doc = NULL;
xmlNodePtr rootnode = NULL, onenode = NULL, settingsvaluenode = NULL, maxdisplayvaluenode = NULL;
char buff[256];
int i, j;
doc = xmlNewDoc(BAD_CAST "1.0");
rootnode = xmlNewNode(NULL, BAD_CAST "TachometerSettings");
xmlDocSetRootElement(doc, rootnode);
settingsvaluenode = xmlNewNode(NULL, BAD_CAST "SettingsValues");
for(int i = 0; i< nodes; ++i)
{
onenode = xmlNewNode(NULL, BAD_CAST "SettingsItem");
char value[10];
sprintf(value, "%d", values_array[i]);
char rpm[10];
sprintf(rpm, "%d", rpm_array[i]);
xmlNewChild(onenode, NULL, BAD_CAST "Value", BAD_CAST value);
xmlNewChild(onenode, NULL, BAD_CAST "TimeValue", BAD_CAST rpm);
xmlAddChild(settingsvaluenode, onenode);
}
xmlAddChild(rootnode, settingsvaluenode);
char revs[10];
sprintf(revs, "%d", maxrevs);
maxdisplayvaluenode = xmlNewChild(rootnode, NULL, BAD_CAST "MaxDisplayValue", BAD_CAST revs);
xmlSaveFormatFileEnc(save_file, doc, "UTF-8", 1);
xmlFreeDoc(doc);
xmlCleanupParser();
return 0;
}
int config_tachometer(int max_revs, int granularity, const char* save_file, SimDevice* simdevice, SimData* simdata)
{
int pulses = 0;
int nodes = 0;
if (max_revs<2000)
{
fprintf(stderr, "revs must be at least 2000\n");
return 0;
}
int increment = 1000;
if (granularity == 2)
{
increment = 500;
}
if (granularity == 4)
{
increment = 250;
}
nodes = ((max_revs/1000)*granularity)+1;
if (granularity >= 4)
{
nodes--;
}
int rpm_array[nodes];
int values_array[nodes];
values_array[0]=250;
values_array[1]=increment;
if (granularity >= 4)
{
values_array[0] = increment;
values_array[1]= increment * 2;
}
for(int i=2; i<nodes; i++)
{
values_array[i]=values_array[i-1]+increment;
}
for(int i=0; i<nodes; i++)
{
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);
char ch = ' ';
if (i==0)
{
fprintf(stdout, "Press Return to continue...\n");
scanf("%c",&ch);
}
sleep(2);
fprintf(stdout, "Set tachometer revs to %i: Press > to increase, < to decrease, and Return to accept (m increases by 1000, n decreases by 1000, c increases by 100, z decreases by 100...\n", values_array[i]);
struct pollfd mypoll = { STDIN_FILENO, POLLIN|POLLPRI };
double update_rate = DEFAULT_UPDATE_RATE;
int go=1;
while (go>0)
{
simdata->pulses = pulses;
devupdate(simdevice, simdata);
if( poll(&mypoll, 1, 1000.0/update_rate) )
{
ch = ' ';
scanf("%c", &ch);
if (ch == 'n')
{
pulses=pulses-1000;
}
if (ch == 'm')
{
pulses=pulses+1000;
}
if (ch == 'z')
{
pulses=pulses-100;
}
if (ch == 'c')
{
pulses=pulses+100;
}
if (ch == '<')
{
pulses--;
}
if (ch == '>')
{
pulses++;
}
if (ch == '\n')
{
go=0;
fprintf(stdout, "set pulses to %i\n", pulses);
rpm_array[i]=pulses;
}
}
}
tcsetattr(0, TCSANOW, &canonicalmode);
}
WriteXmlFromArrays(nodes, rpm_array, values_array, max_revs, save_file);
sleep(2);
simdata->pulses = 0;
devupdate(simdevice, simdata);
fflush(stdout);
return 0;
}

View File

@ -0,0 +1,9 @@
#ifndef _TACHCONFIG_H
#define _TACHCONFIG_H
#include "../devices/simdevice.h"
#include "../simulatorapi/simdata.h"
int config_tachometer(int max_revs, int granularity, const char* save_file, SimDevice* simdevice, SimData* simdata);
#endif

View File

@ -0,0 +1,13 @@
set(helper_source_files
parameters.c
parameters.h
dirhelper.c
dirhelper.h
confighelper.c
confighelper.h
)
set(LIBXML_INCLUDE_DIR /usr/include/libxml2)
include_directories("." ${LIBXML_INCLUDE_DIR})
add_library(helper STATIC ${helper_source_files})

View File

@ -0,0 +1,237 @@
#include <stdio.h>
#include <stdbool.h>
#include <string.h>
#include <stdint.h>
#include <libxml/parser.h>
#include <libxml/xmlreader.h>
#include <libxml/tree.h>
#include "confighelper.h"
#include "../slog/slog.h"
int strtogame(const char* game, MonocoqueSettings* ms)
{
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;
}
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;
}
return MONOCOQUE_ERROR_NONE;
}
int strtodev(const char* device_type, DeviceSettings* ds)
{
ds->is_valid = false;
if (strcmp(device_type, "USB") == 0)
{
ds->dev_type = SIMDEV_USB;
}
else
if (strcmp(device_type, "Sound") == 0)
{
ds->dev_type = SIMDEV_SOUND;
}
else
if (strcmp(device_type, "Serial") == 0)
{
ds->dev_type = SIMDEV_SERIAL;
}
else
{
ds->is_valid = false;
slogi("%s does not appear to be a valid device type, but attempting to continue with other devices", device_type);
return MONOCOQUE_ERROR_INVALID_DEV;
}
ds->is_valid = true;
return MONOCOQUE_ERROR_NONE;
}
int strtodevtype(const char* device_subtype, DeviceSettings* ds)
{
ds->is_valid = false;
if (strcmp(device_subtype, "Tachometer") == 0)
{
ds->dev_subtype = SIMDEVTYPE_TACHOMETER;
}
else
if (strcmp(device_subtype, "ShiftLights") == 0)
{
ds->dev_subtype = SIMDEVTYPE_SHIFTLIGHTS;
}
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;
}
int loadtachconfig(const char* config_file, DeviceSettings* ds)
{
xmlNode* rootnode = NULL;
xmlNode* curnode = NULL;
xmlNode* cursubnode = NULL;
xmlNode* cursubsubnode = NULL;
xmlNode* cursubsubsubnode = NULL;
xmlDoc* doc = NULL;
char* buf;
doc = xmlParseFile(config_file);
if (doc == NULL)
{
sloge("Could not read revburner xml config file %s", config_file);
return 1;
}
rootnode = xmlDocGetRootElement(doc);
if (rootnode == NULL)
{
xmlFreeDoc(doc);
xmlCleanupParser();
sloge("Invalid rev burner xml");
return 1;
}
int arraysize = 0;
for (curnode = rootnode; curnode; curnode = curnode->next)
{
for (cursubnode = curnode->children; cursubnode; cursubnode = cursubnode->next)
{
for (cursubsubnode = cursubnode->children; cursubsubnode; cursubsubnode = cursubsubnode->next)
{
if (cursubsubnode->type == XML_ELEMENT_NODE)
{
slogt("Xml Element name %s", cursubsubnode->name);
}
if (strcmp(cursubsubnode->name, "SettingsItem") == 0)
{
arraysize++;
}
}
}
}
uint32_t pulses_array[arraysize];
uint32_t rpms_array[arraysize];
slogt("rev burner settings array size %i", arraysize);
int i = 0;
for (curnode = rootnode; curnode; curnode = curnode->next)
{
if (curnode->type == XML_ELEMENT_NODE)
for (cursubnode = curnode->children; cursubnode; cursubnode = cursubnode->next)
{
for (cursubsubnode = cursubnode->children; cursubsubnode; cursubsubnode = cursubsubnode->next)
{
for (cursubsubsubnode = cursubsubnode->children; cursubsubsubnode; cursubsubsubnode = cursubsubsubnode->next)
{
if (strcmp(cursubsubsubnode->name, "Value") == 0)
{
xmlChar* a = xmlNodeGetContent(cursubsubsubnode);
rpms_array[i] = strtol((char*) a, &buf, 10);
xmlFree(a);
}
if (strcmp(cursubsubsubnode->name, "TimeValue") == 0)
{
xmlChar* a = xmlNodeGetContent(cursubsubsubnode);
pulses_array[i] = strtol((char*) a, &buf, 10);
xmlFree(a);
i++;
}
}
}
}
}
ds->tachsettings.pulses_array = malloc(sizeof(pulses_array));
ds->tachsettings.rpms_array = malloc(sizeof(rpms_array));
ds->tachsettings.size = arraysize;
memcpy(ds->tachsettings.pulses_array, pulses_array, sizeof(pulses_array));
memcpy(ds->tachsettings.rpms_array, rpms_array, sizeof(rpms_array));
xmlFreeDoc(doc);
xmlCleanupParser();
return 0;
}
int loadconfig(const char* config_file, DeviceSettings* ds)
{
if (ds->dev_subtype == SIMDEVTYPE_TACHOMETER)
{
return loadtachconfig(config_file, ds);
}
return 0;
}
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);
ds->dev_type = SIMDEV_UNKNOWN;
ds->dev_subtype = SIMDEVTYPE_UNKNOWN;
error = strtodev(device_type, 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)
{
error = loadconfig(config_file, ds);
}
if (error != MONOCOQUE_ERROR_NONE)
{
return error;
}
if (ds->dev_subtype == SIMDEVTYPE_TACHOMETER)
{
if (device_settings != NULL)
{
config_setting_lookup_int(device_settings, "granularity", &ds->tachsettings.granularity);
if (ds->tachsettings.granularity < 0 || ds->tachsettings.granularity > 4 || ds->tachsettings.granularity == 3)
{
slogd("No or invalid valid set for tachometer granularity, setting to 1");
ds->tachsettings.granularity = 1;
}
slogi("Tachometer granularity set to %i", ds->tachsettings.granularity);
}
ds->tachsettings.use_pulses = true;
if (ms->program_action == A_PLAY)
{
ds->tachsettings.use_pulses = false;
}
}
return error;
}

View File

@ -0,0 +1,88 @@
#ifndef _CONFIGHELPER_H
#define _CONFIGHELPER_H
#include <stdbool.h>
#include <stdint.h>
#include <libconfig.h>
#include "parameters.h"
typedef enum
{
SIMDEV_UNKNOWN = 0,
SIMDEV_USB = 1,
SIMDEV_SOUND = 2,
SIMDEV_SERIAL = 3
}
DeviceType;
typedef enum
{
SIMDEVTYPE_UNKNOWN = 0,
SIMDEVTYPE_TACHOMETER = 1,
SIMDEVTYPE_SHAKER = 2,
SIMDEVTYPE_SHIFTLIGHTS = 3
}
DeviceSubType;
typedef enum
{
SIMULATOR_MONOCOQUE_TEST = 0,
SIMULATOR_ASSETTO_CORSA = 1
}
Simulator;
typedef enum
{
SIMULATOR_UPDATE_DEFAULT = 0,
SIMULATOR_UPDATE_RPMS = 1,
SIMULATOR_UPDATE_GEAR = 2,
SIMULATOR_UPDATE_PULSES = 3,
SIMULATOR_UPDATE_VELOCITY = 4,
SIMULATOR_UPDATE_ALTITUDE = 5
}
SimulatorUpdate;
typedef enum
{
MONOCOQUE_ERROR_NONE = 0,
MONOCOQUE_ERROR_UNKNOWN = 1,
MONOCOQUE_ERROR_INVALID_SIM = 2,
MONOCOQUE_ERROR_INVALID_DEV = 3,
MONOCOQUE_ERROR_NODATA = 4,
MONOCOQUE_ERROR_UNKNOWN_DEV = 5
}
MonocoqueError;
typedef struct
{
ProgramAction program_action;
Simulator sim_name;
}
MonocoqueSettings;
typedef struct
{
int size;
bool use_pulses;
int granularity;
uint32_t* rpms_array;
uint32_t* pulses_array;
}
TachometerSettings;
typedef struct
{
bool is_valid;
DeviceType dev_type;
DeviceSubType dev_subtype;
TachometerSettings tachsettings;
}
DeviceSettings;
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);
#endif

View File

@ -0,0 +1,202 @@
#include "dirhelper.h"
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <dirent.h>
#include <pwd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <time.h>
#include <string.h>
char* gethome()
{
char* homedir = getenv("HOME");
return homedir;
if (homedir != NULL)
{
printf("Home dir in enviroment");
printf("%s\n", homedir);
}
uid_t uid = getuid();
struct passwd* pw = getpwuid(uid);
if (pw == NULL)
{
printf("Failed\n");
exit(EXIT_FAILURE);
}
return pw->pw_dir;
}
time_t get_file_creation_time(char* path)
{
struct stat attr;
stat(path, &attr);
return attr.st_mtime;
}
void delete_dir(char* path)
{
struct dirent* de;
DIR* dr = opendir(path);
if (dr == NULL)
{
printf("Could not open current directory");
}
// Refer http://pubs.opengroup.org/onlinepubs/7990989775/xsh/readdir.html
while ((de = readdir(dr)) != NULL)
{
char* fullpath = ( char* ) malloc(1 + strlen(path) + strlen("/") + strlen(de->d_name));
strcpy(fullpath, path);
strcat(fullpath, "/");
strcat(fullpath, de->d_name);
unlink(fullpath);
free(fullpath);
}
closedir(dr);
rmdir(path);
}
void delete_oldest_dir(char* path)
{
char* oldestdir = path;
struct dirent* de;
DIR* dr = opendir(path);
if (dr == NULL)
{
printf("Could not open current directory");
}
// Refer http://pubs.opengroup.org/onlinepubs/7990989775/xsh/readdir.html
char filename_qfd[100] ;
char* deletepath = NULL;
time_t tempoldest = 0;
while ((de = readdir(dr)) != NULL)
{
struct stat stbuf;
if (strcmp(de->d_name, ".") == 0 || strcmp(de->d_name, "..") == 0)
{
continue;
}
char* fullpath = ( char* ) malloc(1 + strlen(path) + strlen(de->d_name));
strcpy(fullpath, path);
strcat(fullpath, de->d_name);
stat(fullpath, &stbuf);
if (S_ISDIR(stbuf.st_mode))
{
strcpy(fullpath, path);
strcat(fullpath, de->d_name);
if (tempoldest == 0)
{
tempoldest = get_file_creation_time(fullpath);
free(deletepath);
deletepath = strdup(fullpath);
}
else
{
time_t t = get_file_creation_time(fullpath);
double diff = tempoldest - t;
if (diff > 0)
{
tempoldest = t;
free(deletepath);
deletepath = strdup(fullpath);
}
}
}
free(fullpath);
}
closedir(dr);
delete_dir(deletepath);
free(deletepath);
}
void restrict_folders_to_cache(char* path, int cachesize)
{
int numfolders = 0;
struct dirent* de;
DIR* dr = opendir(path);
if (dr == NULL)
{
printf("Could not open current directory");
}
// Refer http://pubs.opengroup.org/onlinepubs/7990989775/xsh/readdir.html
while ((de = readdir(dr)) != NULL)
{
if (strcmp(de->d_name, ".") == 0 || strcmp(de->d_name, "..") == 0)
{
continue;
}
char* fullpath = ( char* ) malloc(1 + strlen(path) + strlen(de->d_name));
strcpy(fullpath, path);
strcat(fullpath, de->d_name);
strcat(fullpath, "/");
struct stat stbuf;
stat(fullpath,&stbuf);
if (S_ISDIR(stbuf.st_mode))
{
numfolders++;
}
free(fullpath);
}
while (numfolders >= cachesize)
{
delete_oldest_dir(path);
numfolders--;
}
closedir(dr);
}
bool does_directory_exist(char* path, char* dirname)
{
struct dirent* de;
DIR* dr = opendir(path);
if (dr == NULL)
{
printf("Could not open current directory");
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;
}

View File

@ -0,0 +1,12 @@
#ifndef _DIRHELPER_H
#define _DIRHELPER_H
#include <stdbool.h>
char* gethome();
char* str2md5(const char* str, int length);
bool does_directory_exist(char* path, char* dirname);
void restrict_folders_to_cache(char* path, int cachesize);
void delete_dir(char* path);
#endif

View File

@ -0,0 +1,153 @@
#include "parameters.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <libconfig.h>
#include <argtable2.h>
#include <regex.h>
ConfigError getParameters(int argc, char** argv, Parameters* p)
{
ConfigError exitcode = E_SOMETHING_BAD;
// set return structure defaults
p->program_action = 0;
p->max_revs = 0;
p->verbosity_count = 0;
// 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_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* 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};
int nerrors1;
struct arg_rex* cmd2a = arg_rex1(NULL, NULL, "config", NULL, REG_ICASE, NULL);
struct arg_rex* cmd2b = arg_rex1(NULL, NULL, "tachometer", NULL, REG_ICASE, NULL);
struct arg_int* arg_max_revs = arg_int1("m", "max_revs",NULL,"specify max revs of tachometer");
struct arg_int* arg_granularity = arg_int0("g", "granularity",NULL,"1 every 1000 revs, 2 every 500 revs, 4 every 250 revs, default 1");
struct arg_file* arg_save = arg_filen("s", "savefile", "<savefile>", 1, 1, NULL);
struct arg_lit* help2 = arg_litn(NULL,"help", 0, 1, "print this help and exit");
struct arg_lit* vers2 = arg_litn(NULL,"version", 0, 1, "print version information and exit");
struct arg_end* end2 = arg_end(20);
void* argtable2[] = {cmd2a,cmd2b,arg_max_revs,arg_granularity,arg_save,arg_verbosity2,help2,vers2,end2};
int nerrors2;
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);
void* argtable0[] = {help0,version0,end0};
int nerrors0;
if (arg_nullcheck(argtable0) != 0)
{
printf("%s: insufficient memory\n",progname);
goto cleanup;
}
if (arg_nullcheck(argtable1) != 0)
{
printf("%s: insufficient memory\n",progname);
goto cleanup;
}
if (arg_nullcheck(argtable2) != 0)
{
printf("%s: insufficient memory\n",progname);
goto cleanup;
}
arg_granularity->ival[0] = 1;
nerrors0 = arg_parse(argc,argv,argtable0);
nerrors1 = arg_parse(argc,argv,argtable1);
nerrors2 = arg_parse(argc,argv,argtable2);
if (nerrors1==0)
{
p->program_action = A_PLAY;
p->sim_string = arg_sim->sval[0];
p->verbosity_count = arg_verbosity1->count;
exitcode = E_SUCCESS_AND_DO;
}
else
if (nerrors2==0)
{
p->program_action = A_CONFIG_TACH;
p->max_revs = arg_max_revs->ival[0];
p->granularity = 1;
if (arg_granularity->ival[0] > 0 && arg_granularity->ival[0] < 5 && arg_granularity->ival[0] != 3)
{
p->granularity=arg_granularity->ival[0];
}
p->save_file = *arg_save->filename;
p->verbosity_count = arg_verbosity2->count;
exitcode = E_SUCCESS_AND_DO;
}
else
{
if (cmd1->count > 0)
{
arg_print_errors(stdout,end1,progname);
printf("Usage: %s ", progname);
arg_print_syntax(stdout,argtable1,"\n");
}
else
if (cmd2a->count > 0)
{
arg_print_errors(stdout,end2,progname);
printf("Usage: %s ", progname);
arg_print_syntax(stdout,argtable2,"\n");
}
else
{
if (help->count==0 && vers->count==0)
{
printf("%s: missing <play|config> 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");
}
}
exitcode = E_SUCCESS_AND_EXIT;
goto cleanup;
}
// interpret some special cases before we go through trouble of reading the config file
if (help->count > 0)
{
printf("Usage: %s\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("\nReport bugs on the github github.com/spacefreak18/monocoque.\n");
exitcode = E_SUCCESS_AND_EXIT;
goto cleanup;
}
if (vers->count > 0)
{
printf("%s Simulator Hardware Manager\n",progname);
printf("October 2022, Paul Dino Jones\n");
exitcode = E_SUCCESS_AND_EXIT;
goto cleanup;
}
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]));
return exitcode;
}

View File

@ -0,0 +1,44 @@
#ifndef _PARAMETERS_H
#define _PARAMETERS_H
typedef struct
{
int program_action;
const char* sim_string;
const char* save_file;
int max_revs;
int granularity;
int verbosity_count;
}
Parameters;
typedef enum
{
A_PLAY = 0,
A_CONFIG_TACH = 1,
A_CONFIG_SHAKER = 2
}
ProgramAction;
typedef enum
{
E_SUCCESS_AND_EXIT = 0,
E_SUCCESS_AND_DO = 1,
E_SOMETHING_BAD = 2
}
ConfigError;
ConfigError getParameters(int argc, char** argv, Parameters* p);
struct _errordesc
{
int code;
char* message;
} static errordesc[] =
{
{ E_SUCCESS_AND_EXIT, "No error and exiting" },
{ E_SUCCESS_AND_DO, "No error and continuing" },
{ E_SOMETHING_BAD, "Something bad happened" },
};
#endif

233
src/monocoque/monocoque.c Normal file
View File

@ -0,0 +1,233 @@
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <string.h>
#include <libconfig.h>
#include "gameloop/gameloop.h"
#include "gameloop/tachconfig.h"
#include "devices/simdevice.h"
#include "helper/parameters.h"
#include "helper/dirhelper.h"
#include "helper/confighelper.h"
#include "simulatorapi/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);
}
void display_banner()
{
printf("______ ______________ ___________________________________ ___________\n");
printf("___ |/ /_ __ \\__ | / /_ __ \\_ ____/_ __ \\_ __ \\_ / / /__ ____/\n");
printf("__ /|_/ /_ / / /_ |/ /_ / / / / _ / / / / / / / / /__ __/ \n");
printf("_ / / / / /_/ /_ /| / / /_/ // /___ / /_/ // /_/ // /_/ / _ /___ \n");
printf("/_/ /_/ \\____/ /_/ |_/ \\____/ \\____/ \\____/ \\___\\_\\\\____/ /_____/ \n");
}
int main(int argc, char** argv)
{
display_banner();
Parameters* p = malloc(sizeof(Parameters));
MonocoqueSettings* ms = malloc(sizeof(MonocoqueSettings));;
ConfigError ppe = getParameters(argc, argv, p);
if (ppe == E_SUCCESS_AND_EXIT)
{
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");
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);
slgCfg.nTraceTid = 0;
slgCfg.nToScreen = 1;
slgCfg.nUseHeap = 0;
slgCfg.nToFile = 1;
slgCfg.nFlush = 0;
slgCfg.nFlags = SLOG_FLAGS_ALL;
slog_config_set(&slgCfg);
if (p->verbosity_count < 2)
{
slog_disable(SLOG_TRACE);
}
if (p->verbosity_count < 1)
{
slog_disable(SLOG_DEBUG);
}
slogi("Loading configuration file: %s", config_file_str);
config_t cfg;
config_init(&cfg);
config_setting_t* config_devices = NULL;
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("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)
{
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)
{
sloge("Could not proceed with tachometer configuration due to error: %i", error);
}
else
{
config_tachometer(p->max_revs, p->granularity, p->save_file, tachdev, sdata);
}
devfree(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++;
}
error = looper(devices, numdevices, ms->sim_name);
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);
}
i = 0;
while (i<configureddevices)
{
if(ds[i]->dev_subtype == SIMDEV_USB)
{
free(ds[i]->tachsettings.pulses_array);
free(ds[i]->tachsettings.rpms_array);
}
free(ds[i]);
i++;
}
i = 0;
while (i<numdevices)
{
devfree(devices[i]);
free(devices[i]);
i++;
}
}
configcleanup:
config_destroy(&cfg);
cleanup_final:
free(ms);
free(p);
exit(0);
}

View File

@ -0,0 +1,10 @@
set(simulatorapi_source_files
simmapper.c
simmapper.h
simdata.h
test.h
simapi/acdata.h
ac.h
)
add_library(simulatorapi STATIC ${simulatorapi_source_files})

21
src/monocoque/simulatorapi/ac.h Executable file
View File

@ -0,0 +1,21 @@
#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

@ -0,0 +1 @@
Subproject commit 5faf120d84378cdbe3bd8a0347f38fb9d0e9a87e

View File

@ -0,0 +1,17 @@
#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

View File

@ -0,0 +1,97 @@
#include <stdio.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <string.h>
#include "simmapper.h"
#include "simdata.h"
#include "test.h"
#include "ac.h"
#include "../helper/confighelper.h"
#include "../slog/slog.h"
#include "simapi/acdata.h"
int simdatamap(SimData* simdata, SimMap* simmap, Simulator simulator)
{
switch ( simulator )
{
case SIMULATOR_MONOCOQUE_TEST :
memcpy(simdata, simmap->addr, sizeof(SimData));
break;
case SIMULATOR_ASSETTO_CORSA :
memcpy(&simmap->d.ac.ac_physics, simmap->d.ac.physics_map_addr, sizeof(simmap->d.ac.ac_physics));
if (simmap->d.ac.has_static == true )
{
memcpy(&simmap->d.ac.ac_static, simmap->d.ac.static_map_addr, sizeof(simmap->d.ac.ac_static));
simdata->maxrpm = simmap->d.ac.ac_static.maxRpm;
}
simdata->rpms = simmap->d.ac.ac_physics.rpms;
simdata->gear = simmap->d.ac.ac_physics.gear;
simdata->velocity = simmap->d.ac.ac_physics.speedKmh;
simdata->altitude = 1;
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;
}
return error;
}

View File

@ -0,0 +1,25 @@
#ifndef _SIMMAPPER_H
#define _SIMMAPPEE_H
#include "ac.h"
#include "simdata.h"
#include "../helper/confighelper.h"
#include "simapi/acdata.h"
typedef struct
{
void* addr;
int fd;
union
{
ACMap ac;
} d;
}
SimMap;
int siminit(SimData* simdata, SimMap* simmap, Simulator simulator);
int simdatamap(SimData* simdata, SimMap* simmap, Simulator simulator);
#endif

View File

@ -0,0 +1,6 @@
#ifndef _TEST_H
#define _TEST_H
#define TEST_MEM_FILE_LOCATION "/monocoque_test"
#endif

View File

@ -0,0 +1,6 @@
set(slog_source_files
slog.c
slog.h
)
add_library(slog STATIC ${slog_source_files})

546
src/monocoque/slog/slog.c Normal file
View File

@ -0,0 +1,546 @@
/*
* The MIT License (MIT)
*
* Copyleft (C) 2015-2020 Sun Dro (f4tb0y@protonmail.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
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE
*/
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <stdarg.h>
#include <limits.h>
#include <errno.h>
#include <time.h>
#include "slog.h"
#if !defined(__APPLE__) && !defined(DARWIN) && !defined(WIN32)
#include <syscall.h>
#endif
#include <sys/time.h>
#ifdef WIN32
#include <windows.h>
#endif
#ifndef PTHREAD_MUTEX_RECURSIVE
#define PTHREAD_MUTEX_RECURSIVE PTHREAD_MUTEX_RECURSIVE_NP
#endif
typedef struct slog
{
unsigned int nTdSafe:1;
pthread_mutex_t mutex;
slog_config_t config;
} slog_t;
typedef struct XLogCtx
{
const char* pFormat;
slog_flag_t eFlag;
slog_date_t date;
uint8_t nFullColor;
uint8_t nNewLine;
} slog_context_t;
static slog_t g_slog;
static void slog_sync_init(slog_t* pSlog)
{
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))
{
printf("<%s:%d> %s: [ERROR] Can not initialize mutex: %d\n",
__FILE__, __LINE__, __FUNCTION__, errno);
exit(EXIT_FAILURE);
}
}
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);
exit(EXIT_FAILURE);
}
}
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);
exit(EXIT_FAILURE);
}
}
static const char* slog_get_indent(slog_flag_t eFlag)
{
slog_config_t* pCfg = &g_slog.config;
if (!pCfg->nIndent)
{
return SLOG_EMPTY;
}
switch (eFlag)
{
case SLOG_NOTAG:
return SLOG_INDENT;
case SLOG_NOTE:
case SLOG_INFO:
case SLOG_WARN:
return SLOG_SPACE;
case SLOG_DEBUG:
case SLOG_TRACE:
case SLOG_FATAL:
case SLOG_ERROR:
default:
break;
}
return SLOG_EMPTY;
}
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;
}
return NULL;
}
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;
}
return SLOG_EMPTY;
}
uint8_t slog_get_usec()
{
struct timeval tv;
if (gettimeofday(&tv, NULL) < 0)
{
return 0;
}
return (uint8_t)(tv.tv_usec / 10000);
}
void slog_get_date(slog_date_t* pDate)
{
struct tm timeinfo;
time_t rawtime = time(NULL);
#ifdef WIN32
localtime_s(&timeinfo, &rawtime);
#else
localtime_r(&rawtime, &timeinfo);
#endif
pDate->nYear = timeinfo.tm_year + 1900;
pDate->nMonth = timeinfo.tm_mon + 1;
pDate->nDay = timeinfo.tm_mday;
pDate->nHour = timeinfo.tm_hour;
pDate->nMin = timeinfo.tm_min;
pDate->nSec = timeinfo.tm_sec;
pDate->nUsec = slog_get_usec();
}
static uint32_t slog_get_tid()
{
#if defined(__APPLE__) || defined(DARWIN) || defined(WIN32)
return (uint32_t)pthread_self();
#else
return syscall(__NR_gettid);
#endif
}
static void slog_create_tag(char* pOut, size_t nSize, slog_flag_t eFlag, const char* pColor)
{
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);
if (pTag == NULL)
{
snprintf(pOut, nSize, 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);
}
}
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());
}
}
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;
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;
if (pCfg->logCallback != NULL)
{
size_t nLength = 0;
char* pLog = NULL;
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);
free(pLog);
}
}
if (pCfg->nToScreen && nCbVal > 0)
{
printf("%s%s%s%s%s", pInfo, pSeparator, pMessage, pReset, pNewLine);
if (pCfg->nFlush)
{
fflush(stdout);
}
}
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);
FILE* pFile = fopen(sFilePath, "a");
if (pFile == NULL)
{
return;
}
fprintf(pFile, "%s%s%s%s%s", pInfo, pSeparator, pMessage, pReset, pNewLine);
fclose(pFile);
}
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;
char sDate[SLOG_DATE_MAX + SLOG_NAME_MAX];
sDate[0] = SLOG_NUL;
if (pCfg->eDateControl == SLOG_TIME_ONLY)
{
snprintf(sDate, sizeof(sDate), "%02d:%02d:%02d.%03d ",
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;
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)
{
size_t nBytes = 0;
char* pMessage = NULL;
char sLogInfo[SLOG_INFO_MAX];
nBytes += vasprintf(&pMessage, pCtx->pFormat, args);
va_end(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);
return;
}
int nLength = slog_create_info(pCtx, sLogInfo, sizeof(sLogInfo));
slog_display_message(pCtx, sLogInfo, nLength, pMessage);
if (pMessage != NULL)
{
free(pMessage);
}
}
static void slog_display_stack(const slog_context_t* pCtx, va_list args)
{
char sMessage[SLOG_MESSAGE_MAX];
char sLogInfo[SLOG_INFO_MAX];
vsnprintf(sMessage, sizeof(sMessage), pCtx->pFormat, args);
int nLength = slog_create_info(pCtx, sLogInfo, sizeof(sLogInfo));
slog_display_message(pCtx, sLogInfo, nLength, sMessage);
}
void slog_display(slog_flag_t eFlag, uint8_t nNewLine, const char* pFormat, ...)
{
slog_lock(&g_slog);
slog_config_t* pCfg = &g_slog.config;
if ((SLOG_FLAGS_CHECK(g_slog.config.nFlags, eFlag)) &&
(g_slog.config.nToScreen || g_slog.config.nToFile))
{
slog_context_t ctx;
slog_get_date(&ctx.date);
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);
slog_display_args = pCfg->nUseHeap ? slog_display_heap : slog_display_stack;
va_list args;
va_start(args, pFormat);
slog_display_args(&ctx, args);
va_end(args);
}
slog_unlock(&g_slog);
}
size_t slog_version(char* pDest, size_t nSize, uint8_t nMin)
{
size_t nLength = 0;
/* Version short */
if (nMin)
nLength = snprintf(pDest, nSize, "%d.%d.%d",
SLOG_VERSION_MAJOR, SLOG_VERSION_MINOR, SLOG_BUILD_NUM);
/* Version long */
else
nLength = snprintf(pDest, nSize, "%d.%d build %d (%s)",
SLOG_VERSION_MAJOR, SLOG_VERSION_MINOR, SLOG_BUILD_NUM, __DATE__);
return nLength;
}
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)
{
slog_lock(&g_slog);
g_slog.config = *pCfg;
slog_unlock(&g_slog);
}
void slog_enable(slog_flag_t eFlag)
{
slog_lock(&g_slog);
if (!SLOG_FLAGS_CHECK(g_slog.config.nFlags, eFlag))
{
g_slog.config.nFlags |= eFlag;
}
slog_unlock(&g_slog);
}
void slog_disable(slog_flag_t eFlag)
{
slog_lock(&g_slog);
if (SLOG_FLAGS_CHECK(g_slog.config.nFlags, eFlag))
{
g_slog.config.nFlags &= ~eFlag;
}
slog_unlock(&g_slog);
}
void slog_separator_set(const char* pFormat, ...)
{
slog_lock(&g_slog);
slog_config_t* pCfg = &g_slog.config;
va_list args;
va_start(args, pFormat);
if (vsnprintf(pCfg->sSeparator, sizeof(pCfg->sSeparator), pFormat, args) <= 0)
{
pCfg->sSeparator[0] = ' ';
pCfg->sSeparator[1] = '\0';
}
va_end(args);
slog_unlock(&g_slog);
}
void slog_indent(uint8_t nEnable)
{
slog_lock(&g_slog);
g_slog.config.nIndent = nEnable;
slog_unlock(&g_slog);
}
void slog_callback_set(slog_cb_t callback, void* pContext)
{
slog_lock(&g_slog);
slog_config_t* pCfg = &g_slog.config;
pCfg->pCallbackCtx = pContext;
pCfg->logCallback = callback;
slog_unlock(&g_slog);
}
void slog_init(const char* pName, uint16_t nFlags, uint8_t nTdSafe)
{
/* Set up default values */
slog_config_t* pCfg = &g_slog.config;
pCfg->eColorFormat = SLOG_COLORING_TAG;
pCfg->eDateControl = SLOG_TIME_ONLY;
pCfg->pCallbackCtx = NULL;
pCfg->logCallback = NULL;
pCfg->sSeparator[0] = ' ';
pCfg->sSeparator[1] = '\0';
pCfg->sFilePath[0] = '.';
pCfg->sFilePath[1] = '\0';
pCfg->nTraceTid = 0;
pCfg->nToScreen = 1;
pCfg->nUseHeap = 0;
pCfg->nToFile = 0;
pCfg->nIndent = 0;
pCfg->nFlush = 0;
pCfg->nFlags = nFlags;
const char* pFileName = (pName != NULL) ? pName : SLOG_NAME_DEFAULT;
snprintf(pCfg->sFileName, sizeof(pCfg->sFileName), "%s", pFileName);
#ifdef WIN32
// Enable color support
HANDLE hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
DWORD dwMode = 0;
GetConsoleMode(hOutput, &dwMode);
dwMode |= ENABLE_PROCESSED_OUTPUT | ENABLE_VIRTUAL_TERMINAL_PROCESSING;
SetConsoleMode(hOutput, dwMode);
#endif
/* Initialize mutex */
g_slog.nTdSafe = nTdSafe;
slog_sync_init(&g_slog);
}
void slog_destroy()
{
g_slog.config.pCallbackCtx = NULL;
g_slog.config.logCallback = NULL;
if (g_slog.nTdSafe)
{
pthread_mutex_destroy(&g_slog.mutex);
g_slog.nTdSafe = 0;
}
}

195
src/monocoque/slog/slog.h Normal file
View File

@ -0,0 +1,195 @@
/*
* The MIT License (MIT)
*
* Copyleft (C) 2015-2020 Sun Dro (f4tb0y@protonmail.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
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE
*/
#ifndef __SLOG_H__
#define __SLOG_H__
#ifdef __cplusplus
extern "C" {
#endif
#include <inttypes.h>
#include <pthread.h>
/* SLog version information */
#define SLOG_VERSION_MAJOR 1
#define SLOG_VERSION_MINOR 8
#define SLOG_BUILD_NUM 26
/* Supported colors */
#define SLOG_COLOR_NORMAL "\x1B[0m"
#define SLOG_COLOR_RED "\x1B[31m"
#define SLOG_COLOR_GREEN "\x1B[32m"
#define SLOG_COLOR_YELLOW "\x1B[33m"
#define SLOG_COLOR_BLUE "\x1B[34m"
#define SLOG_COLOR_MAGENTA "\x1B[35m"
#define SLOG_COLOR_CYAN "\x1B[36m"
#define SLOG_COLOR_WHITE "\x1B[37m"
#define SLOG_COLOR_RESET "\033[0m"
/* Trace source location helpers */
#define SLOG_TRACE_LVL1(LINE) #LINE
#define SLOG_TRACE_LVL2(LINE) SLOG_TRACE_LVL1(LINE)
#define SLOG_THROW_LOCATION "[" __FILE__ ":" SLOG_TRACE_LVL2(__LINE__) "] "
/* SLog limits (To be safe while avoiding dynamic allocations) */
#define SLOG_MESSAGE_MAX 8196
#define SLOG_VERSION_MAX 128
#define SLOG_PATH_MAX 2048
#define SLOG_INFO_MAX 512
#define SLOG_NAME_MAX 256
#define SLOG_DATE_MAX 64
#define SLOG_TAG_MAX 32
#define SLOG_COLOR_MAX 16
#define SLOG_FLAGS_CHECK(c, f) (((c) & (f)) == (f))
#define SLOG_FLAGS_ALL 255
#define SLOG_NAME_DEFAULT "slog"
#define SLOG_NEWLINE "\n"
#define SLOG_INDENT " "
#define SLOG_SPACE " "
#define SLOG_EMPTY ""
#define SLOG_NUL '\0'
typedef struct SLogDate
{
uint16_t nYear;
uint8_t nMonth;
uint8_t nDay;
uint8_t nHour;
uint8_t nMin;
uint8_t nSec;
uint8_t nUsec;
} slog_date_t;
uint8_t slog_get_usec();
void slog_get_date(slog_date_t* pDate);
/* Log level flags */
typedef enum
{
SLOG_NOTAG = (1 << 0),
SLOG_NOTE = (1 << 1),
SLOG_INFO = (1 << 2),
SLOG_WARN = (1 << 3),
SLOG_DEBUG = (1 << 4),
SLOG_TRACE = (1 << 5),
SLOG_ERROR = (1 << 6),
SLOG_FATAL = (1 << 7)
} slog_flag_t;
typedef int(*slog_cb_t)(const char* pLog, size_t nLength, slog_flag_t eFlag, void* pCtx);
/* Output coloring control flags */
typedef enum
{
SLOG_COLORING_DISABLE = 0,
SLOG_COLORING_TAG,
SLOG_COLORING_FULL
} slog_coloring_t;
typedef enum
{
SLOG_TIME_DISABLE = 0,
SLOG_TIME_ONLY,
SLOG_DATE_FULL
} slog_date_ctrl_t;
#define slog(...) \
slog_display(SLOG_NOTAG, 1, __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__)
/* Short name definitions */
#define slogn(...) slog_note(__VA_ARGS__)
#define slogi(...) slog_info(__VA_ARGS__)
#define slogw(...) slog_warn(__VA_ARGS__)
#define slogd(...) slog_debug( __VA_ARGS__)
#define sloge(...) slog_error( __VA_ARGS__)
#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
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
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);
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
#ifdef __cplusplus
}
#endif
#endif /* __SLOG_H__ */

45
tests/getmem.c Normal file
View File

@ -0,0 +1,45 @@
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include "../src/monocoque/simulatorapi/simdata.h"
#include "../src/monocoque/simulatorapi/test.h"
int main(int argc, char* argv[])
{
int res;
int fd;
pid_t pid;
void* addr;
SimData* data = malloc(sizeof(SimData));
pid = getpid();
// get shared memory file descriptor (NOT a file)
fd = shm_open(TEST_MEM_FILE_LOCATION, O_RDONLY, S_IRUSR | S_IWUSR);
if (fd == -1)
{
return 10;
}
// map shared memory to process address space
addr = mmap(NULL, sizeof(SimData), PROT_READ, MAP_SHARED, fd, 0);
if (addr == MAP_FAILED)
{
return 30;
}
// place data into memory
memcpy(data, addr, sizeof(SimData));
printf("PID %d: Read from shared memory: \"%s\"\n", pid, data);
printf("PID %d: velocity: %i\n", pid, data->velocity);
printf("PID %d: rpms: %i\n", pid, data->rpms);
printf("PID %d: gear: %i\n", pid, data->gear);
return 0;
}

233
tests/hidtest.c Normal file
View File

@ -0,0 +1,233 @@
#include <stdio.h> // printf
#include <wchar.h> // wprintf
#include <unistd.h>
#include <hidapi/hidapi.h>
#define MAX_STR 255
int buf_size = 64;
int main(int argc, char* argv[])
{
buf_size++;
int res;
unsigned char buf[65];
wchar_t wstr[MAX_STR];
hid_device* handle;
int i;
// Initialize the hidapi library
res = hid_init();
// Open the device using the VID, PID,
// and optionally the Serial number.
handle = hid_open(0x4d8, 0x102, NULL);
int num = 321;
char snum[5];
// convert 123 to string [buf]
sprintf(snum, "%d", num);
// print our string
printf("test%s\n", snum);
if (!handle)
{
printf("Could not find attached rev burner\n");
res = hid_exit();
return 0;
}
// Read the Manufacturer String
res = hid_get_manufacturer_string(handle, wstr, MAX_STR);
wprintf(L"Manufacturer String: %s\n", wstr);
// Read the Product String
res = hid_get_product_string(handle, wstr, MAX_STR);
wprintf(L"Product String: %s\n", wstr);
// Read the Serial Number String
res = hid_get_serial_number_string(handle, wstr, MAX_STR);
wprintf(L"Serial Number String: (%d) %s\n", wstr[0], wstr);
int rpm_array[21] = {41574, 48580, 54308, 58612, 60160, 61113, 61916, 62347, 62777, 63089, 63243, 63505, 63673, 63778, 63908, 64002, 64084, 64140, 64175, 64224, 64313};
buf[0] = 0x00;
buf[1] = 0x00;
buf[2] = 0x00;
buf[3] = 0x00;
res = hid_write(handle, buf, buf_size);
for (i = 0; i<21; i++)
{
int rpms = i * 500;
fprintf(stderr, "Setting RPM to %i hex as decimal %i\n", rpms, rpm_array[i]);
unsigned char bytes[buf_size];
unsigned long nnnnn = rpm_array[i];
unsigned long xlong = 0;
for (int x = 0; x < buf_size; x++)
{
bytes[x] = 0x00;
}
bytes[3] = (nnnnn >> 8) & 0xFF;
bytes[2] = nnnnn & 0xFF;
FILE* write_ptr;
if ( i == 0 )
{
write_ptr = fopen("test0.bin","wb");
}
if ( i == 1 )
{
write_ptr = fopen("test1.bin","wb");
}
if ( i == 2 )
{
write_ptr = fopen("test2.bin","wb");
}
if ( i == 3 )
{
write_ptr = fopen("test3.bin","wb");
}
if ( i == 4 )
{
write_ptr = fopen("test4.bin","wb");
}
if ( i == 5 )
{
write_ptr = fopen("test5.bin","wb");
}
if ( i == 6 )
{
write_ptr = fopen("test6.bin","wb");
}
if ( i == 7 )
{
write_ptr = fopen("test7.bin","wb");
}
if ( i == 8 )
{
write_ptr = fopen("test8.bin","wb");
}
if ( i == 9 )
{
write_ptr = fopen("test9.bin","wb");
}
if ( i == 10 )
{
write_ptr = fopen("test10.bin","wb");
}
if ( i == 11 )
{
write_ptr = fopen("test11.bin","wb");
}
if ( i == 12 )
{
write_ptr = fopen("test12.bin","wb");
}
if ( i == 13 )
{
write_ptr = fopen("test13.bin","wb");
}
if ( i == 14 )
{
write_ptr = fopen("test14.bin","wb");
}
if ( i == 15 )
{
write_ptr = fopen("test15.bin","wb");
}
if ( i == 16 )
{
write_ptr = fopen("test16.bin","wb");
}
if ( i == 17 )
{
write_ptr = fopen("test17.bin","wb");
}
if ( i == 18 )
{
write_ptr = fopen("test18.bin","wb");
}
if ( i == 19 )
{
write_ptr = fopen("test19.bin","wb");
}
if ( i == 20 )
{
write_ptr = fopen("test20.bin","wb");
}
if ( i == 21 )
{
write_ptr = fopen("test21.bin","wb");
}
if ( i == 22 )
{
write_ptr = fopen("test22.bin","wb");
}
if ( i == 23 )
{
write_ptr = fopen("test23.bin","wb");
}
if ( i == 24 )
{
write_ptr = fopen("test24.bin","wb");
}
fwrite(bytes,sizeof(bytes),1,write_ptr);
fclose(write_ptr);
if (handle)
{
res = hid_write(handle, bytes, buf_size);
}
sleep(4);
}
buf[0] = 0x00;
buf[1] = 0x00;
buf[2] = 0x00;
buf[3] = 0x00;
res = hid_write(handle, buf, buf_size);
sleep(2);
// Close the device
hid_close(handle);
// Finalize the hidapi library
res = hid_exit();
return 0;
}

269
tests/pa_devs.c Normal file
View File

@ -0,0 +1,269 @@
/** @file pa_devs.c
@ingroup examples_src
@brief List available devices, including device information.
@author Phil Burk http://www.softsynth.com
@note Define PA_USE_ASIO=0 to compile this code on Windows without
ASIO support.
*/
/*
* $Id: pa_devs.c 1891 2013-05-05 14:00:02Z rbencina $
*
* This program uses the PortAudio Portable Audio Library.
* For more information see: http://www.portaudio.com
* Copyright (c) 1999-2000 Ross Bencina and Phil Burk
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files
* (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/*
* The text above constitutes the entire PortAudio license; however,
* the PortAudio community also makes the following non-binding requests:
*
* Any person wishing to distribute modifications to the Software is
* requested to send the modifications to the original developer so that
* they can be incorporated into the canonical version. It is also
* requested that these non-binding requests be included along with the
* license above.
*/
#include <stdio.h>
#include <math.h>
#include "portaudio.h"
#ifdef WIN32
#include <windows.h>
#if PA_USE_ASIO
#include "pa_asio.h"
#endif
#endif
/*******************************************************************/
static void PrintSupportedStandardSampleRates(
const PaStreamParameters* inputParameters,
const PaStreamParameters* outputParameters )
{
static double standardSampleRates[] =
{
8000.0, 9600.0, 11025.0, 12000.0, 16000.0, 22050.0, 24000.0, 32000.0,
44100.0, 48000.0, 88200.0, 96000.0, 192000.0, -1 /* negative terminated list */
};
int i, printCount;
PaError err;
printCount = 0;
for( i=0; standardSampleRates[i] > 0; i++ )
{
err = Pa_IsFormatSupported( inputParameters, outputParameters, standardSampleRates[i] );
if( err == paFormatIsSupported )
{
if( printCount == 0 )
{
printf( "\t%8.2f", standardSampleRates[i] );
printCount = 1;
}
else
if( printCount == 4 )
{
printf( ",\n\t%8.2f", standardSampleRates[i] );
printCount = 1;
}
else
{
printf( ", %8.2f", standardSampleRates[i] );
++printCount;
}
}
}
if( !printCount )
{
printf( "None\n" );
}
else
{
printf( "\n" );
}
}
/*******************************************************************/
int main(void);
int main(void)
{
int i, numDevices, defaultDisplayed;
const PaDeviceInfo* deviceInfo;
PaStreamParameters inputParameters, outputParameters;
PaError err;
err = Pa_Initialize();
if( err != paNoError )
{
printf( "ERROR: Pa_Initialize returned 0x%x\n", err );
goto error;
}
printf( "PortAudio version number = %d\nPortAudio version text = '%s'\n",
Pa_GetVersion(), Pa_GetVersionText() );
numDevices = Pa_GetDeviceCount();
if( numDevices < 0 )
{
printf( "ERROR: Pa_GetDeviceCount returned 0x%x\n", numDevices );
err = numDevices;
goto error;
}
printf( "Number of devices = %d\n", numDevices );
for( i=0; i<numDevices; i++ )
{
deviceInfo = Pa_GetDeviceInfo( i );
printf( "--------------------------------------- device #%d\n", i );
/* Mark global and API specific default devices */
defaultDisplayed = 0;
if( i == Pa_GetDefaultInputDevice() )
{
printf( "[ Default Input" );
defaultDisplayed = 1;
}
else
if( i == Pa_GetHostApiInfo( deviceInfo->hostApi )->defaultInputDevice )
{
const PaHostApiInfo* hostInfo = Pa_GetHostApiInfo( deviceInfo->hostApi );
printf( "[ Default %s Input", hostInfo->name );
defaultDisplayed = 1;
}
if( i == Pa_GetDefaultOutputDevice() )
{
printf( (defaultDisplayed ? "," : "[") );
printf( " Default Output" );
defaultDisplayed = 1;
}
else
if( i == Pa_GetHostApiInfo( deviceInfo->hostApi )->defaultOutputDevice )
{
const PaHostApiInfo* hostInfo = Pa_GetHostApiInfo( deviceInfo->hostApi );
printf( (defaultDisplayed ? "," : "[") );
printf( " Default %s Output", hostInfo->name );
defaultDisplayed = 1;
}
if( defaultDisplayed )
{
printf( " ]\n" );
}
/* print device info fields */
#ifdef WIN32
{
/* Use wide char on windows, so we can show UTF-8 encoded device names */
wchar_t wideName[MAX_PATH];
MultiByteToWideChar(CP_UTF8, 0, deviceInfo->name, -1, wideName, MAX_PATH-1);
wprintf( L"Name = %s\n", wideName );
}
#else
printf( "Name = %s\n", deviceInfo->name );
#endif
printf( "Host API = %s\n", Pa_GetHostApiInfo( deviceInfo->hostApi )->name );
printf( "Max inputs = %d", deviceInfo->maxInputChannels );
printf( ", Max outputs = %d\n", deviceInfo->maxOutputChannels );
printf( "Default low input latency = %8.4f\n", deviceInfo->defaultLowInputLatency );
printf( "Default low output latency = %8.4f\n", deviceInfo->defaultLowOutputLatency );
printf( "Default high input latency = %8.4f\n", deviceInfo->defaultHighInputLatency );
printf( "Default high output latency = %8.4f\n", deviceInfo->defaultHighOutputLatency );
#ifdef WIN32
#if PA_USE_ASIO
/* ASIO specific latency information */
if( Pa_GetHostApiInfo( deviceInfo->hostApi )->type == paASIO )
{
long minLatency, maxLatency, preferredLatency, granularity;
err = PaAsio_GetAvailableLatencyValues( i,
&minLatency, &maxLatency, &preferredLatency, &granularity );
printf( "ASIO minimum buffer size = %ld\n", minLatency );
printf( "ASIO maximum buffer size = %ld\n", maxLatency );
printf( "ASIO preferred buffer size = %ld\n", preferredLatency );
if( granularity == -1 )
{
printf( "ASIO buffer granularity = power of 2\n" );
}
else
{
printf( "ASIO buffer granularity = %ld\n", granularity );
}
}
#endif /* PA_USE_ASIO */
#endif /* WIN32 */
printf( "Default sample rate = %8.2f\n", deviceInfo->defaultSampleRate );
/* poll for standard sample rates */
inputParameters.device = i;
inputParameters.channelCount = deviceInfo->maxInputChannels;
inputParameters.sampleFormat = paInt16;
inputParameters.suggestedLatency = 0; /* ignored by Pa_IsFormatSupported() */
inputParameters.hostApiSpecificStreamInfo = NULL;
outputParameters.device = i;
outputParameters.channelCount = deviceInfo->maxOutputChannels;
outputParameters.sampleFormat = paInt16;
outputParameters.suggestedLatency = 0; /* ignored by Pa_IsFormatSupported() */
outputParameters.hostApiSpecificStreamInfo = NULL;
if( inputParameters.channelCount > 0 )
{
printf("Supported standard sample rates\n for half-duplex 16 bit %d channel input = \n",
inputParameters.channelCount );
PrintSupportedStandardSampleRates( &inputParameters, NULL );
}
if( outputParameters.channelCount > 0 )
{
printf("Supported standard sample rates\n for half-duplex 16 bit %d channel output = \n",
outputParameters.channelCount );
PrintSupportedStandardSampleRates( NULL, &outputParameters );
}
if( inputParameters.channelCount > 0 && outputParameters.channelCount > 0 )
{
printf("Supported standard sample rates\n for full-duplex 16 bit %d channel input, %d channel output = \n",
inputParameters.channelCount, outputParameters.channelCount );
PrintSupportedStandardSampleRates( &inputParameters, &outputParameters );
}
}
Pa_Terminate();
printf("----------------------------------------------\n");
return 0;
error:
Pa_Terminate();
fprintf( stderr, "Error number: %d\n", err );
fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
return err;
}

282
tests/patest_longsine.c Normal file
View File

@ -0,0 +1,282 @@
/** @file patest_longsine.c
@ingroup test_src
@brief Play a sine wave until ENTER hit.
@author Phil Burk http://www.softsynth.com
*/
/*
* $Id: patest_longsine.c 1097 2006-08-26 08:27:53Z rossb $
*
* This program uses the PortAudio Portable Audio Library.
* For more information see: http://www.portaudio.com
* Copyright (c) 1999-2000 Ross Bencina and Phil Burk
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files
* (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/*
* The text above constitutes the entire PortAudio license; however,
* the PortAudio community also makes the following non-binding requests:
*
* Any person wishing to distribute modifications to the Software is
* requested to send the modifications to the original developer so that
* they can be incorporated into the canonical version. It is also
* requested that these non-binding requests be included along with the
* license above.
*/
#include <stdio.h>
#include <math.h>
#include <unistd.h>
#include "portaudio.h"
#define SAMPLE_RATE (44100)
#ifndef M_PI
#define M_PI (3.14159265)
#endif
#define MAX_TABLE_SIZE (6000)
//#define TABLE_SIZE (3200)
//#define HALF_TABLE (1600)
typedef struct
{
float sine[MAX_TABLE_SIZE];
float pitch;
int left_phase;
int right_phase;
int n;
int table_size;
int amp;
}
paTestData;
int x = 0;
int y = 0;
long n = 0;
//float note = 256;
float note = 60;
//float note = 161.626;
/* This routine will be called by the PortAudio engine when audio is needed.
** It may called at interrupt level on some machines so don't do anything
** that could mess up the system like calling malloc() or free().
*/
static int patestCallback(const void* inputBuffer,
void* outputBuffer,
unsigned long framesPerBuffer,
const PaStreamCallbackTimeInfo* timeInfo,
PaStreamCallbackFlags statusFlags,
void* userData)
{
paTestData* data = (paTestData*)userData;
float* out = (float*)outputBuffer;
unsigned int i;
unsigned int n;
n = data->n;
(void) inputBuffer; /* Prevent unused argument warning. */
for( i=0; i<framesPerBuffer; i++,n++ )
{
//data->sine[i] = (float) sin( ((double)i/(double) MAX_TABLE_SIZE) * ( ( M_PI * 2. ) ) );
//data->sine[n] = sin ( 2 * M_PI * ((float) n / (float) MAX_TABLE_SIZE) );
//data->right_phase = data->left_phase;
//data->left_phase = n;
//data->right_phase = n;
float v = data->amp * sin (2 * M_PI * ((float) n) / (float) SAMPLE_RATE);
//*out++ = data->sine[data->left_phase];
//*out++ = data->sine[data->right_phase];
if (n>=data->table_size)
{
n=0;
}
*out++ = v;
*out++ = v;
data->left_phase += 1;
data->right_phase += 1;
/*
float v = 800.81;
if (i>=512)
{
v = -v;
}
*out++ = v;
*out++ = v;
*/
//if( data->left_phase >= MAX_TABLE_SIZE ) data->left_phase -= MAX_TABLE_SIZE;
//if( data->right_phase >= MAX_TABLE_SIZE ) data->right_phase -= MAX_TABLE_SIZE;
if( data->left_phase >= data->table_size )
{
data->left_phase -= data->table_size;
}
if( data->right_phase >= data->table_size )
{
data->right_phase -= data->table_size;
}
}
data->n=n;
return 0;
}
void generatesamples(int table_size, int half_table, int datum, paTestData* data)
{
datum = 1;
int j;
for( j=data->n; j<MAX_TABLE_SIZE; j++)
{
for( int i=0; i<data->table_size; i++,j++ )
{
//data.sine[i] = (float) amp * sin( ((double)i/(double) TABLE_SIZE) * ( ( M_PI * 2. * freq) ) );
data->sine[j] = (float) datum * sin( ((double)i/(double) data->table_size) * ( ( M_PI * 2. ) ) );
/*
data->sine[i] = datum;
if (i>=half_table) {
data->sine[i] = -datum;
}
*/
data->n=j;
}
}
}
/*******************************************************************/
int main(void);
int main(void)
{
PaStreamParameters outputParameters;
PaStream* stream;
PaError err;
paTestData data;
int i;
printf("PortAudio Test: output sine wave.\n");
float amp = ((float)32);
amp = ((float)32);
//float freq = ((float) freq1/(SAMPLE_RATE/TABLE_SIZE));
int freq = 32;
// 500 rpms
int table_size = 5292;
int half_table = 2646;
table_size = 200;
half_table = 50;
data.pitch = 1;
data.pitch = 261.626;
data.amp = 2;
//data.pitch = 523.25;
//table_size = 2646;
//half_table = 1323;
//table_size = 3200;
//half_table = 1600;
/* initialise sinusoidal wavetable */
data.table_size=5292;
//generatesamples(table_size,half_table,5,&data);
data.left_phase = data.right_phase = 0;
err = Pa_Initialize();
if( err != paNoError )
{
goto error;
}
outputParameters.device = Pa_GetDefaultOutputDevice(); /* default output device */
outputParameters.channelCount = 2; /* stereo output */
outputParameters.sampleFormat = paFloat32; /* 32 bit floating point output */
outputParameters.suggestedLatency = Pa_GetDeviceInfo( outputParameters.device )->defaultLowOutputLatency;
outputParameters.hostApiSpecificStreamInfo = NULL;
err = Pa_OpenStream( &stream,
NULL, /* No input. */
&outputParameters, /* As above. */
SAMPLE_RATE,
440, /* Frames per buffer. */
paClipOff, /* No out of range samples expected. */
patestCallback,
&data );
if( err != paNoError )
{
goto error;
}
fprintf(stdout,"Revving to 500 rpm...\n");
err = Pa_StartStream( stream );
if( err != paNoError )
{
goto error;
}
//printf("Hit ENTER to stop program.\n");
//getchar();
sleep(10);
table_size = 2646;
half_table = 1323;
table_size = 100;
data.table_size = 2646;
half_table = 100;
fprintf(stdout,"Revving to 1000 rpm...\n");
//generatesamples(table_size,half_table,5,&data);
data.pitch = 523.25;
sleep(10);
table_size = 1764;
half_table = 882;
table_size = 400;
half_table = 200;
data.table_size = 1764;
fprintf(stdout,"Revving to 1500 rpm...\n");
//generatesamples(table_size,half_table,5,&data);
sleep(5);
table_size = 1323;
half_table = 661;
data.table_size = 1323;
fprintf(stdout,"Revving to 2000 rpm...\n");
//generatesamples(table_size,half_table,5,&data);
sleep(5);
err = Pa_CloseStream( stream );
if( err != paNoError )
{
goto error;
}
Pa_Terminate();
printf("Test finished.\n");
return err;
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;
}

View File

@ -0,0 +1,94 @@
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <libxml/xmlmemory.h>
#include <libxml/parser.h>
void parseStory (xmlDocPtr doc, xmlNodePtr cur)
{
xmlChar* key;
cur = cur->xmlChildrenNode;
while (cur != NULL)
{
if ((!xmlStrcmp(cur->name, (const xmlChar*)"Value")))
{
key = xmlNodeGetContent(cur);
printf("Revs x100: %s\n", (char*) key);
xmlFree(key);
}
if ((!xmlStrcmp(cur->name, (const xmlChar*)"TimerValue")))
{
key = xmlNodeGetContent(cur);
printf("Value to send to RevBurner: %s\n", (char*) key);
xmlFree(key);
}
cur = cur->next;
}
return;
}
static void parseDoc(char* docname)
{
xmlDocPtr doc;
xmlNodePtr cur;
doc = xmlParseFile(docname);
if (doc == NULL )
{
fprintf(stderr,"Document not parsed successfully. \n");
return;
}
cur = xmlDocGetRootElement(doc);
if (cur == NULL)
{
fprintf(stderr,"empty document\n");
xmlFreeDoc(doc);
return;
}
if (xmlStrcmp(cur->name, (const xmlChar*) "TachometerSettings"))
{
fprintf(stderr,"document of the wrong type, root node != TachometerSettings");
xmlFreeDoc(doc);
return;
}
cur = cur->xmlChildrenNode;
cur = cur->next;
cur = cur->xmlChildrenNode;
while (cur != NULL)
{
if (!(xmlStrcmp(cur->name, (const xmlChar*)"SettingsItem")))
{
parseStory (doc, cur);
}
cur = cur->next;
}
xmlFreeDoc(doc);
return;
}
int main(int argc, char** argv)
{
char* docname;
if (argc <= 1)
{
printf("Usage: %s docname\n", argv[0]);
return(0);
}
docname = argv[1];
parseDoc (docname);
return (1);
}

32
tests/runmemtest.sh Executable file
View File

@ -0,0 +1,32 @@
#!/bin/bash
function is_linux
{
if [[ "$(uname)" == "Linux" ]]; then
echo 1
return
fi
echo 0
}
SET="setmem"
GET="getmem"
CFLAGS=""
if [[ "$(is_linux)" == "1" ]]; then
CFLAGS="-lrt"
fi
cc ${CFLAGS} -o ${SET} ${SET}.c
cc ${CFLAGS} -o ${GET} ${GET}.c
./${SET} &
sleep 1
./${GET}
if [[ "$(is_linux)" == "1" ]]; then
echo "/dev/shm:"
ls -l /dev/shm
fi
sleep 1
rm ${SET} ${GET}

110
tests/setmem.c Normal file
View File

@ -0,0 +1,110 @@
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <termios.h>
#include "../src/monocoque/simulatorapi/simdata.h"
#include "../src/monocoque/simulatorapi/test.h"
#define DATA "Hello, World! From PID %d"
int main(int argc, char* argv[])
{
int res;
int fd;
int len;
pid_t pid;
void* addr;
pid = getpid();
fd = shm_open(TEST_MEM_FILE_LOCATION, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
if (fd == -1)
{
perror("open");
return 10;
}
SimData* data = malloc(sizeof(SimData));
data->gear=0;
data->rpms=0;
data->maxrpm=0;
data->velocity=0;
//SimData.pulses=0;
res = ftruncate(fd, sizeof(SimData));
if (res == -1)
{
perror("ftruncate");
return 20;
}
data->gear=1;
data->rpms=500;
data->maxrpm=6500;
data->velocity=25;
//SimData.pulses=38792;
// map .shared memory to process address space
addr = mmap(NULL, sizeof(SimData), PROT_WRITE, MAP_SHARED, fd, 0);
if (addr == MAP_FAILED)
{
perror("mmap");
return 30;
}
printf("size of int %i\n", sizeof(int));
printf("size of struct %i\n", sizeof(SimData));
memcpy(addr, data, sizeof(SimData));
//memcpy(addr, &SimData, sizeof(int)*3);
printf("PID %d: velocity: %i\n", pid, data->velocity);
printf("PID %d: rpms: %i\n", pid, data->rpms);
printf("PID %d: gear: %i\n", pid, data->gear);
sleep(4);
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);
char ch;
int go=1;
while (go>0)
{
struct termios info;
tcgetattr(0, &info);
info.c_lflag &= (~ICANON & ~ECHO);
info.c_cc[VMIN] = 1;
info.c_cc[VTIME] = 0;
tcsetattr(0, TCSANOW, &info);
char ch;
scanf("%c", &ch);
if (ch == 'q')
{
go=0;
}
}
tcsetattr(0, TCSANOW, &canonicalmode);
fd = shm_unlink(TEST_MEM_FILE_LOCATION);
if (fd == -1)
{
perror("unlink");
return 100;
}
return 0;
}

62
tests/setsimdata.c Normal file
View File

@ -0,0 +1,62 @@
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include "../src/monocoque/simulatorapi/simdata.h"
#include "../src/monocoque/simulatorapi/test.h"
#define DATA "Hello, World! From PID %d"
int main(int argc, char* argv[])
{
int res;
int fd;
int len;
pid_t pid;
void* addr;
pid = getpid();
// get shared memory file descriptor (NOT a file)
fd = shm_open(TEST_MEM_FILE_LOCATION, O_RDWR, S_IRUSR | S_IWUSR);
if (fd == -1)
{
perror("open");
return 10;
}
// extend shared memory object as by default it's initialized with size 0
//res = ftruncate(fd, STORAGE_SIZE);
SimData* data = malloc(sizeof(SimData));
data->velocity=1;
data->gear=4;
data->maxrpm=6500;
data->rpms=1000;
//SimData.pulses=398273;
res = ftruncate(fd, sizeof(SimData));
if (res == -1)
{
//perror("ftruncate");
//return 20;
}
data->velocity=atoi(argv[1]);
data->rpms=atoi(argv[2]);
data->gear=atoi(argv[3]);
//SimData.pulses=39993;
// map .shared memory to process address space
addr = mmap(NULL, sizeof(SimData), PROT_WRITE, MAP_SHARED, fd, 0);
if (addr == MAP_FAILED)
{
perror("mmap");
return 30;
}
memcpy(addr, data, sizeof(SimData));
return 0;
}

View File

@ -0,0 +1,87 @@
#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 = "/shm-example"; // file name
const int SIZE = 4096; // file size
const char* message0 = "Studying ";
const char* message1 = "Operating Systems ";
const char* message2 = "Is Fun!";
const char* msg_end = "\n";
int shm_fd; // file descriptor, from shm_open()
char* shm_base; // base address, from mmap()
char* ptr; // shm_base is fixed, ptr is movable
/* create the shared memory segment as if it was a file */
shm_fd = shm_open(name, O_CREAT | O_RDWR, 0666);
if (shm_fd == -1)
{
printf("prod: Shared memory failed: %s\n", strerror(errno));
exit(1);
}
/* configure the size of the shared memory segment */
ftruncate(shm_fd, SIZE);
/* map the shared memory segment to the address space of the process */
shm_base = mmap(0, SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0);
if (shm_base == MAP_FAILED)
{
printf("prod: Map failed: %s\n", strerror(errno));
// close and shm_unlink?
exit(1);
}
/**
* Write to the mapped shared memory region.
*
* We increment the value of ptr after each write, but we
* are ignoring the possibility that sprintf() fails.
*/
display("prod", shm_base, 64);
ptr = shm_base;
ptr += sprintf(ptr, "%s", message0);
ptr += sprintf(ptr, "%s", message1);
ptr += sprintf(ptr, "%s", message2);
ptr += sprintf(ptr, "%s", msg_end);
display("prod", shm_base, 64);
/* remove the mapped memory segment from the address space of the process */
if (munmap(shm_base, SIZE) == -1)
{
printf("prod: Unmap failed: %s\n", strerror(errno));
exit(1);
}
/* close the shared memory segment as if it was a file */
if (close(shm_fd) == -1)
{
printf("prod: Close failed: %s\n", strerror(errno));
exit(1);
}
return 0;
}
void display(char* prog, char* bytes, int n)
{
printf("display: %s\n", prog);
for (int i = 0; i < n; i++)
{
printf("%02x%c", bytes[i], ((i+1)%16) ? ' ' : '\n');
}
printf("\n");
}

106
tests/simlighttest.c Normal file
View File

@ -0,0 +1,106 @@
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <libserialport.h>
#include "../src/monocoque/simulatorapi/simdata.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";
/* The ports we will use. */
struct sp_port* port;
/* Open and configure each port. */
printf("Looking for port %s.\n", port_name);
check(sp_get_port_by_name(port_name, &port));
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));
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 )
{
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);
/* Send data. */
result = check(sp_blocking_write(port, &sd, size, timeout));
/* Check whether we sent all of the data. */
if (result == size)
{
printf("Sent %d bytes successfully, %i rpm.\n", size, sd.rpms);
}
else
{
printf("Timed out, %d/%d bytes sent.\n", result, size);
}
sd.rpms += 1000;
if ( sd.rpms == sd.maxrpm + 1000 )
{
sd.rpms = 0;
}
if ( sd.rpms > sd.maxrpm )
{
sd.rpms = sd.maxrpm;
}
sleep(1);
}
check(sp_close(port));
sp_free_port(port);
}
/* Helper function for error handling. */
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");
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;
}
}

BIN
tests/test.bin Normal file

Binary file not shown.

381
tests/testlibusb.c Normal file
View File

@ -0,0 +1,381 @@
/*
* Test suite program based of libusb-0.1-compat testlibusb
* Copyright (c) 2013 Nathan Hjelm <hjelmn@mac.ccom>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <stdio.h>
#include <string.h>
#include "libusb-1.0/libusb.h"
int verbose = 0;
static void print_endpoint_comp(const struct libusb_ss_endpoint_companion_descriptor* ep_comp)
{
printf(" USB 3.0 Endpoint Companion:\n");
printf(" bMaxBurst: %u\n", ep_comp->bMaxBurst);
printf(" bmAttributes: %02xh\n", ep_comp->bmAttributes);
printf(" wBytesPerInterval: %u\n", ep_comp->wBytesPerInterval);
}
static void print_endpoint(const struct libusb_endpoint_descriptor* endpoint)
{
int i, ret;
printf(" Endpoint:\n");
printf(" bEndpointAddress: %02xh\n", endpoint->bEndpointAddress);
printf(" bmAttributes: %02xh\n", endpoint->bmAttributes);
printf(" wMaxPacketSize: %u\n", endpoint->wMaxPacketSize);
printf(" bInterval: %u\n", endpoint->bInterval);
printf(" bRefresh: %u\n", endpoint->bRefresh);
printf(" bSynchAddress: %u\n", endpoint->bSynchAddress);
for (i = 0; i < endpoint->extra_length;)
{
if (LIBUSB_DT_SS_ENDPOINT_COMPANION == endpoint->extra[i + 1])
{
struct libusb_ss_endpoint_companion_descriptor* ep_comp;
ret = libusb_get_ss_endpoint_companion_descriptor(NULL, endpoint, &ep_comp);
if (LIBUSB_SUCCESS != ret)
{
continue;
}
print_endpoint_comp(ep_comp);
libusb_free_ss_endpoint_companion_descriptor(ep_comp);
}
i += endpoint->extra[i];
}
}
static void print_altsetting(const struct libusb_interface_descriptor* interface)
{
uint8_t i;
printf(" Interface:\n");
printf(" bInterfaceNumber: %u\n", interface->bInterfaceNumber);
printf(" bAlternateSetting: %u\n", interface->bAlternateSetting);
printf(" bNumEndpoints: %u\n", interface->bNumEndpoints);
printf(" bInterfaceClass: %u\n", interface->bInterfaceClass);
printf(" bInterfaceSubClass: %u\n", interface->bInterfaceSubClass);
printf(" bInterfaceProtocol: %u\n", interface->bInterfaceProtocol);
printf(" iInterface: %u\n", interface->iInterface);
for (i = 0; i < interface->bNumEndpoints; i++)
{
print_endpoint(&interface->endpoint[i]);
}
}
static void print_2_0_ext_cap(struct libusb_usb_2_0_extension_descriptor* usb_2_0_ext_cap)
{
printf(" USB 2.0 Extension Capabilities:\n");
printf(" bDevCapabilityType: %u\n", usb_2_0_ext_cap->bDevCapabilityType);
printf(" bmAttributes: %08xh\n", usb_2_0_ext_cap->bmAttributes);
}
static void print_ss_usb_cap(struct libusb_ss_usb_device_capability_descriptor* ss_usb_cap)
{
printf(" USB 3.0 Capabilities:\n");
printf(" bDevCapabilityType: %u\n", ss_usb_cap->bDevCapabilityType);
printf(" bmAttributes: %02xh\n", ss_usb_cap->bmAttributes);
printf(" wSpeedSupported: %u\n", ss_usb_cap->wSpeedSupported);
printf(" bFunctionalitySupport: %u\n", ss_usb_cap->bFunctionalitySupport);
printf(" bU1devExitLat: %u\n", ss_usb_cap->bU1DevExitLat);
printf(" bU2devExitLat: %u\n", ss_usb_cap->bU2DevExitLat);
}
static void print_bos(libusb_device_handle* handle)
{
struct libusb_bos_descriptor* bos;
uint8_t i;
int ret;
ret = libusb_get_bos_descriptor(handle, &bos);
if (ret < 0)
{
return;
}
printf(" Binary Object Store (BOS):\n");
printf(" wTotalLength: %u\n", bos->wTotalLength);
printf(" bNumDeviceCaps: %u\n", bos->bNumDeviceCaps);
for (i = 0; i < bos->bNumDeviceCaps; i++)
{
struct libusb_bos_dev_capability_descriptor* dev_cap = bos->dev_capability[i];
if (dev_cap->bDevCapabilityType == LIBUSB_BT_USB_2_0_EXTENSION)
{
struct libusb_usb_2_0_extension_descriptor* usb_2_0_extension;
ret = libusb_get_usb_2_0_extension_descriptor(NULL, dev_cap, &usb_2_0_extension);
if (ret < 0)
{
return;
}
print_2_0_ext_cap(usb_2_0_extension);
libusb_free_usb_2_0_extension_descriptor(usb_2_0_extension);
}
else
if (dev_cap->bDevCapabilityType == LIBUSB_BT_SS_USB_DEVICE_CAPABILITY)
{
struct libusb_ss_usb_device_capability_descriptor* ss_dev_cap;
ret = libusb_get_ss_usb_device_capability_descriptor(NULL, dev_cap, &ss_dev_cap);
if (ret < 0)
{
return;
}
print_ss_usb_cap(ss_dev_cap);
libusb_free_ss_usb_device_capability_descriptor(ss_dev_cap);
}
}
libusb_free_bos_descriptor(bos);
}
static void print_interface(const struct libusb_interface* interface)
{
int i;
for (i = 0; i < interface->num_altsetting; i++)
{
print_altsetting(&interface->altsetting[i]);
}
}
static void print_configuration(struct libusb_config_descriptor* config)
{
uint8_t i;
printf(" Configuration:\n");
printf(" wTotalLength: %u\n", config->wTotalLength);
printf(" bNumInterfaces: %u\n", config->bNumInterfaces);
printf(" bConfigurationValue: %u\n", config->bConfigurationValue);
printf(" iConfiguration: %u\n", config->iConfiguration);
printf(" bmAttributes: %02xh\n", config->bmAttributes);
printf(" MaxPower: %u\n", config->MaxPower);
for (i = 0; i < config->bNumInterfaces; i++)
{
print_interface(&config->interface[i]);
}
}
static void print_device(libusb_device* dev, libusb_device_handle* handle)
{
struct libusb_device_descriptor desc;
unsigned char string[256];
const char* speed;
int ret;
uint8_t i;
switch (libusb_get_device_speed(dev))
{
case LIBUSB_SPEED_LOW:
speed = "1.5M";
break;
case LIBUSB_SPEED_FULL:
speed = "12M";
break;
case LIBUSB_SPEED_HIGH:
speed = "480M";
break;
case LIBUSB_SPEED_SUPER:
speed = "5G";
break;
case LIBUSB_SPEED_SUPER_PLUS:
speed = "10G";
break;
default:
speed = "Unknown";
}
ret = libusb_get_device_descriptor(dev, &desc);
if (ret < 0)
{
fprintf(stderr, "failed to get device descriptor");
return;
}
printf("Dev (bus %u, device %u): %04X - %04X speed: %s\n",
libusb_get_bus_number(dev), libusb_get_device_address(dev),
desc.idVendor, desc.idProduct, speed);
if (!handle)
{
libusb_open(dev, &handle);
}
if (handle)
{
if (desc.iManufacturer)
{
ret = libusb_get_string_descriptor_ascii(handle, desc.iManufacturer, string, sizeof(string));
if (ret > 0)
{
printf(" Manufacturer: %s\n", (char*)string);
}
}
if (desc.iProduct)
{
ret = libusb_get_string_descriptor_ascii(handle, desc.iProduct, string, sizeof(string));
if (ret > 0)
{
printf(" Product: %s\n", (char*)string);
}
}
if (desc.iSerialNumber && verbose)
{
ret = libusb_get_string_descriptor_ascii(handle, desc.iSerialNumber, string, sizeof(string));
if (ret > 0)
{
printf(" Serial Number: %s\n", (char*)string);
}
}
}
if (verbose)
{
for (i = 0; i < desc.bNumConfigurations; i++)
{
struct libusb_config_descriptor* config;
ret = libusb_get_config_descriptor(dev, i, &config);
if (LIBUSB_SUCCESS != ret)
{
printf(" Couldn't retrieve descriptors\n");
continue;
}
print_configuration(config);
libusb_free_config_descriptor(config);
}
if (handle && desc.bcdUSB >= 0x0201)
{
print_bos(handle);
}
}
if (handle)
{
libusb_close(handle);
}
}
#ifdef __linux__
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
static int test_wrapped_device(const char* device_name)
{
libusb_device_handle* handle;
int r, fd;
fd = open(device_name, O_RDWR);
if (fd < 0)
{
printf("Error could not open %s: %s\n", device_name, strerror(errno));
return 1;
}
r = libusb_wrap_sys_device(NULL, fd, &handle);
if (r)
{
printf("Error wrapping device: %s: %s\n", device_name, libusb_strerror(r));
close(fd);
return 1;
}
print_device(libusb_get_device(handle), handle);
close(fd);
return 0;
}
#else
static int test_wrapped_device(const char* device_name)
{
(void)device_name;
printf("Testing wrapped devices is not supported on your platform\n");
return 1;
}
#endif
int main(int argc, char* argv[])
{
const char* device_name = NULL;
libusb_device** devs;
ssize_t cnt;
int r, i;
for (i = 1; i < argc; i++)
{
if (!strcmp(argv[i], "-v"))
{
verbose = 1;
}
else
if (!strcmp(argv[i], "-d") && (i + 1) < argc)
{
i++;
device_name = argv[i];
}
else
{
printf("Usage %s [-v] [-d </dev/bus/usb/...>]\n", argv[0]);
printf("Note use -d to test libusb_wrap_sys_device()\n");
return 1;
}
}
r = libusb_init(NULL);
if (r < 0)
{
return r;
}
if (device_name)
{
r = test_wrapped_device(device_name);
}
else
{
cnt = libusb_get_device_list(NULL, &devs);
if (cnt < 0)
{
libusb_exit(NULL);
return 1;
}
for (i = 0; devs[i]; i++)
{
print_device(devs[i], NULL);
}
libusb_free_device_list(devs, 1);
}
libusb_exit(NULL);
return r;
}

532
tests/testrevburner.c Normal file
View File

@ -0,0 +1,532 @@
/*
* Test suite program based of libusb-0.1-compat testlibusb
* Copyright (c) 2013 Nathan Hjelm <hjelmn@mac.ccom>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <stdio.h>
#include <string.h>
#include "libusb-1.0/libusb.h"
#define ENDPOINT_OUT 0x01
#define ENDPOINT_IN 0x81
int verbose = 0;
static void print_endpoint_comp(const struct libusb_ss_endpoint_companion_descriptor* ep_comp)
{
printf(" USB 3.0 Endpoint Companion:\n");
printf(" bMaxBurst: %u\n", ep_comp->bMaxBurst);
printf(" bmAttributes: %02xh\n", ep_comp->bmAttributes);
printf(" wBytesPerInterval: %u\n", ep_comp->wBytesPerInterval);
}
static void print_endpoint(const struct libusb_endpoint_descriptor* endpoint)
{
int i, ret;
printf(" Endpoint:\n");
printf(" bEndpointAddress: %02xh\n", endpoint->bEndpointAddress);
printf(" bmAttributes: %02xh\n", endpoint->bmAttributes);
printf(" wMaxPacketSize: %u\n", endpoint->wMaxPacketSize);
printf(" bInterval: %u\n", endpoint->bInterval);
printf(" bRefresh: %u\n", endpoint->bRefresh);
printf(" bSynchAddress: %u\n", endpoint->bSynchAddress);
for (i = 0; i < endpoint->extra_length;)
{
if (LIBUSB_DT_SS_ENDPOINT_COMPANION == endpoint->extra[i + 1])
{
struct libusb_ss_endpoint_companion_descriptor* ep_comp;
ret = libusb_get_ss_endpoint_companion_descriptor(NULL, endpoint, &ep_comp);
if (LIBUSB_SUCCESS != ret)
{
continue;
}
print_endpoint_comp(ep_comp);
libusb_free_ss_endpoint_companion_descriptor(ep_comp);
}
i += endpoint->extra[i];
}
}
static void print_altsetting(const struct libusb_interface_descriptor* interface)
{
uint8_t i;
printf(" Interface:\n");
printf(" bInterfaceNumber: %u\n", interface->bInterfaceNumber);
printf(" bAlternateSetting: %u\n", interface->bAlternateSetting);
printf(" bNumEndpoints: %u\n", interface->bNumEndpoints);
printf(" bInterfaceClass: %u\n", interface->bInterfaceClass);
printf(" bInterfaceSubClass: %u\n", interface->bInterfaceSubClass);
printf(" bInterfaceProtocol: %u\n", interface->bInterfaceProtocol);
printf(" iInterface: %u\n", interface->iInterface);
for (i = 0; i < interface->bNumEndpoints; i++)
{
print_endpoint(&interface->endpoint[i]);
}
}
static void print_2_0_ext_cap(struct libusb_usb_2_0_extension_descriptor* usb_2_0_ext_cap)
{
printf(" USB 2.0 Extension Capabilities:\n");
printf(" bDevCapabilityType: %u\n", usb_2_0_ext_cap->bDevCapabilityType);
printf(" bmAttributes: %08xh\n", usb_2_0_ext_cap->bmAttributes);
}
static void print_ss_usb_cap(struct libusb_ss_usb_device_capability_descriptor* ss_usb_cap)
{
printf(" USB 3.0 Capabilities:\n");
printf(" bDevCapabilityType: %u\n", ss_usb_cap->bDevCapabilityType);
printf(" bmAttributes: %02xh\n", ss_usb_cap->bmAttributes);
printf(" wSpeedSupported: %u\n", ss_usb_cap->wSpeedSupported);
printf(" bFunctionalitySupport: %u\n", ss_usb_cap->bFunctionalitySupport);
printf(" bU1devExitLat: %u\n", ss_usb_cap->bU1DevExitLat);
printf(" bU2devExitLat: %u\n", ss_usb_cap->bU2DevExitLat);
}
static void print_bos(libusb_device_handle* handle)
{
struct libusb_bos_descriptor* bos;
uint8_t i;
int ret;
ret = libusb_get_bos_descriptor(handle, &bos);
if (ret < 0)
{
return;
}
printf(" Binary Object Store (BOS):\n");
printf(" wTotalLength: %u\n", bos->wTotalLength);
printf(" bNumDeviceCaps: %u\n", bos->bNumDeviceCaps);
for (i = 0; i < bos->bNumDeviceCaps; i++)
{
struct libusb_bos_dev_capability_descriptor* dev_cap = bos->dev_capability[i];
if (dev_cap->bDevCapabilityType == LIBUSB_BT_USB_2_0_EXTENSION)
{
struct libusb_usb_2_0_extension_descriptor* usb_2_0_extension;
ret = libusb_get_usb_2_0_extension_descriptor(NULL, dev_cap, &usb_2_0_extension);
if (ret < 0)
{
return;
}
print_2_0_ext_cap(usb_2_0_extension);
libusb_free_usb_2_0_extension_descriptor(usb_2_0_extension);
}
else
if (dev_cap->bDevCapabilityType == LIBUSB_BT_SS_USB_DEVICE_CAPABILITY)
{
struct libusb_ss_usb_device_capability_descriptor* ss_dev_cap;
ret = libusb_get_ss_usb_device_capability_descriptor(NULL, dev_cap, &ss_dev_cap);
if (ret < 0)
{
return;
}
print_ss_usb_cap(ss_dev_cap);
libusb_free_ss_usb_device_capability_descriptor(ss_dev_cap);
}
}
libusb_free_bos_descriptor(bos);
}
static void print_interface(const struct libusb_interface* interface)
{
int i;
for (i = 0; i < interface->num_altsetting; i++)
{
print_altsetting(&interface->altsetting[i]);
}
}
static void print_configuration(struct libusb_config_descriptor* config)
{
uint8_t i;
printf(" Configuration:\n");
printf(" wTotalLength: %u\n", config->wTotalLength);
printf(" bNumInterfaces: %u\n", config->bNumInterfaces);
printf(" bConfigurationValue: %u\n", config->bConfigurationValue);
printf(" iConfiguration: %u\n", config->iConfiguration);
printf(" bmAttributes: %02xh\n", config->bmAttributes);
printf(" MaxPower: %u\n", config->MaxPower);
for (i = 0; i < config->bNumInterfaces; i++)
{
print_interface(&config->interface[i]);
}
}
static void set_rpms(libusb_device* dev, libusb_device_handle* handle)
{
int rpms = 0;
int i = 0;
for (i = 1; i<=10; i++)
{
int rpms = i * 1000;
printf("Setting RPM to %i\n", rpms);
//sleep(5);
}
}
static void print_device(libusb_device* dev, libusb_device_handle* handle)
{
struct libusb_device_descriptor desc;
unsigned char string[256];
const char* speed;
int ret;
uint8_t i;
switch (libusb_get_device_speed(dev))
{
case LIBUSB_SPEED_LOW:
speed = "1.5M";
break;
case LIBUSB_SPEED_FULL:
speed = "12M";
break;
case LIBUSB_SPEED_HIGH:
speed = "480M";
break;
case LIBUSB_SPEED_SUPER:
speed = "5G";
break;
case LIBUSB_SPEED_SUPER_PLUS:
speed = "10G";
break;
default:
speed = "Unknown";
}
ret = libusb_get_device_descriptor(dev, &desc);
if (ret < 0)
{
fprintf(stderr, "failed to get device descriptor");
return;
}
printf("Dev (bus %u, device %u): %04X - %04X speed: %s\n",
libusb_get_bus_number(dev), libusb_get_device_address(dev),
desc.idVendor, desc.idProduct, speed);
if (!handle)
{
libusb_open(dev, &handle);
}
if (handle)
{
if (desc.iManufacturer)
{
ret = libusb_get_string_descriptor_ascii(handle, desc.iManufacturer, string, sizeof(string));
if (ret > 0)
{
printf(" Manufacturer: %s\n", (char*)string);
}
}
if (desc.iProduct)
{
ret = libusb_get_string_descriptor_ascii(handle, desc.iProduct, string, sizeof(string));
if (ret > 0)
{
printf(" Product: %s\n", (char*)string);
}
}
if (desc.iSerialNumber && verbose)
{
ret = libusb_get_string_descriptor_ascii(handle, desc.iSerialNumber, string, sizeof(string));
if (ret > 0)
{
printf(" Serial Number: %s\n", (char*)string);
}
}
}
if (verbose)
{
for (i = 0; i < desc.bNumConfigurations; i++)
{
struct libusb_config_descriptor* config;
ret = libusb_get_config_descriptor(dev, i, &config);
if (LIBUSB_SUCCESS != ret)
{
printf(" Couldn't retrieve descriptors\n");
continue;
}
print_configuration(config);
libusb_free_config_descriptor(config);
}
if (handle && desc.bcdUSB >= 0x0201)
{
print_bos(handle);
}
}
if (handle)
{
libusb_close(handle);
}
}
/*
static void print_device(libusb_device *dev, libusb_device_handle *handle)
{
struct libusb_device_descriptor desc;
unsigned char string[256];
const char *speed;
int ret;
uint8_t i;
switch (libusb_get_device_speed(dev)) {
case LIBUSB_SPEED_LOW: speed = "1.5M"; break;
case LIBUSB_SPEED_FULL: speed = "12M"; break;
case LIBUSB_SPEED_HIGH: speed = "480M"; break;
case LIBUSB_SPEED_SUPER: speed = "5G"; break;
case LIBUSB_SPEED_SUPER_PLUS: speed = "10G"; break;
default: speed = "Unknown";
}
ret = libusb_get_device_descriptor(dev, &desc);
if (ret < 0) {
fprintf(stderr, "failed to get device descriptor");
return;
}
printf("Dev (bus %u, device %u): %04X - %04X speed: %s\n",
libusb_get_bus_number(dev), libusb_get_device_address(dev),
desc.idVendor, desc.idProduct, speed);
if (!handle)
libusb_open(dev, &handle);
if (handle) {
if (desc.iManufacturer) {
ret = libusb_get_string_descriptor_ascii(handle, desc.iManufacturer, string, sizeof(string));
if (ret > 0)
printf(" Manufacturer: %s\n", (char *)string);
}
if (desc.iProduct) {
ret = libusb_get_string_descriptor_ascii(handle, desc.iProduct, string, sizeof(string));
if (ret > 0)
printf(" Product: %s\n", (char *)string);
}
if (desc.iSerialNumber && verbose) {
ret = libusb_get_string_descriptor_ascii(handle, desc.iSerialNumber, string, sizeof(string));
if (ret > 0)
printf(" Serial Number: %s\n", (char *)string);
}
}
if (verbose) {
for (i = 0; i < desc.bNumConfigurations; i++) {
struct libusb_config_descriptor *config;
ret = libusb_get_config_descriptor(dev, i, &config);
if (LIBUSB_SUCCESS != ret) {
printf(" Couldn't retrieve descriptors\n");
continue;
}
print_configuration(config);
libusb_free_config_descriptor(config);
}
if (handle && desc.bcdUSB >= 0x0201)
print_bos(handle);
}
if (handle)
libusb_close(handle);
}
*/
#ifdef __linux__
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
static int test_wrapped_device(const char* device_name)
{
libusb_device_handle* handle;
int r, fd;
fd = open(device_name, O_RDWR);
if (fd < 0)
{
printf("Error could not open %s: %s\n", device_name, strerror(errno));
return 1;
}
r = libusb_wrap_sys_device(NULL, fd, &handle);
if (r)
{
printf("Error wrapping device: %s: %s\n", device_name, libusb_strerror(r));
close(fd);
return 1;
}
print_device(libusb_get_device(handle), handle);
close(fd);
return 0;
}
#else
static int test_wrapped_device(const char* device_name)
{
(void)device_name;
printf("Testing wrapped devices is not supported on your platform\n");
return 1;
}
#endif
int main(int argc, char* argv[])
{
const char* device_name = NULL;
libusb_device** devs;
libusb_device* dev;
ssize_t cnt;
int r, i;
r = libusb_init(NULL);
if (r < 0)
{
return r;
}
cnt = libusb_get_device_list(NULL, &devs);
if (cnt < 0)
{
libusb_exit(NULL);
return 1;
}
/*
}
*/
int devindx = 0;
for (i = 0; i<12; i++)
{
//int b = print_device(&devs[i], NULL);
//if (b == "9823") {
devindx = i;
//break;
//}
}
i = 0;
dev = devs[devindx];
print_device(dev, NULL);
int d = 99;
libusb_device_handle* handle = NULL;
if (!handle)
{
d=libusb_open(dev, &handle);
}
int len = 0;
if(libusb_kernel_driver_active(handle, 0) == 1)
{
d = libusb_detach_kernel_driver(handle, 0);
}
fprintf(stderr,"%i",d);
d = libusb_claim_interface(handle, 0);
fprintf(stderr,"%i",d);
//int rpm_array[20] = {41574, 48580, 54308, 58612, 60160, 61916, 62347, 62777, 63089, 63243, 63505, 63673, 63778, 63908, 64002, 64084, 64140, 64175, 64224, 64313};
//int rpm_array[20] = {41574, 48580, 54308, 58612, 60160, 61416, 61952, 62470, 62969, 63231, 63305, 63673, 63749, 63998, 64002, 64084, 64140, 64175, 64224, 64313};
//int rpm_array[10] = {58612, 62112, 63053, 63719, 64044, 64313, 64480, 64622, 64719, 64807};
//int rpm_array[10] = {24701, 42244, 54308, 54308, 64255, 64313, 64480, 64622, 64719, 64807};
int rpms = 0;
int iiii = 189;
unsigned char bytes[65];
int rpm_array[21] = {41574, 48580, 54308, 58612, 60160, 61113, 61916, 62347, 62777, 63089, 63243, 63505, 63673, 63778, 63908, 64002, 64084, 64140, 64175, 64224, 64313};
for (i = 0; i<21; i++)
{
int rpms = i * 500;
printf("Setting RPM to %i hex as decimal %i\n", rpms, rpm_array[i]);
//printf("Setting RPM to %i\n", i);
unsigned char bytes[65];
unsigned long nnnnn = rpm_array[i];
//unsigned long nnnnn = i;
unsigned long xlong = 0;
for (int x = 0; x < 64; x++)
{
bytes[x] = 0x00;
}
bytes[3] = (nnnnn >> 8) & 0xFF;
bytes[2] = nnnnn & 0xFF;
//bytes[0] = (nnnnn >> 24) & 0xFF;
//bytes[1] = (nnnnn >> 16) & 0xFF;
//bytes[2] = (nnnnn >> 8) & 0xFF;
//bytes[3] = nnnnn & 0xFF;
if (handle)
{
d = libusb_interrupt_transfer(handle, ENDPOINT_OUT, bytes, sizeof(bytes), &len, 0);
}
sleep(4);
}
for (int x = 0; x < 65; x++)
{
bytes[x] = 0x00;
}
if (handle)
{
d = libusb_interrupt_transfer(handle, ENDPOINT_OUT, bytes, sizeof(bytes), &len, 0);
}
if (handle)
{
libusb_close(handle);
}
//set_rpms(dev, NULL);
libusb_free_device_list(devs, 1);
libusb_exit(NULL);
return r;
}

88
tests/usesharedmemory.c Normal file
View File

@ -0,0 +1,88 @@
/**
* Simple program demonstrating shared memory in POSIX systems.
*
* This is the consumer process
*
* Figure 3.18
*
* @author Gagne, Galvin, Silberschatz
* Operating System Concepts - Ninth Edition
* Copyright John Wiley & Sons - 2013
*
* modifications by dheller@cse.psu.edu, 31 Jan. 2014
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/shm.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <errno.h>
#include <string.h>
void display(char* prog, char* bytes, int n);
int main(void)
{
const char* name = "/shm-example"; // file name
const int SIZE = 4096; // file size
int shm_fd; // file descriptor, from shm_open()
char* shm_base; // base address, from mmap()
/* open the shared memory segment as if it was a file */
shm_fd = shm_open(name, O_RDONLY, 0666);
if (shm_fd == -1)
{
printf("cons: Shared memory failed: %s\n", strerror(errno));
exit(1);
}
/* map the shared memory segment to the address space of the process */
shm_base = mmap(0, SIZE, PROT_READ, MAP_SHARED, shm_fd, 0);
if (shm_base == MAP_FAILED)
{
printf("cons: Map failed: %s\n", strerror(errno));
// close and unlink?
exit(1);
}
/* read from the mapped shared memory segment */
display("cons", shm_base, 64); // first as bytes, then as a string
printf("%s", shm_base);
/* remove the mapped shared memory segment from the address space of the process */
if (munmap(shm_base, SIZE) == -1)
{
printf("cons: Unmap failed: %s\n", strerror(errno));
exit(1);
}
/* close the shared memory segment as if it was a file */
if (close(shm_fd) == -1)
{
printf("cons: Close failed: %s\n", strerror(errno));
exit(1);
}
/* remove the shared memory segment from the file system */
if (shm_unlink(name) == -1)
{
printf("cons: Error removing %s: %s\n", name, strerror(errno));
exit(1);
}
return 0;
}
void display(char* prog, char* bytes, int n)
{
printf("display: %s\n", prog);
for (int i = 0; i < n; i++)
{
printf("%02x%c", bytes[i], ((i+1)%16) ? ' ' : '\n');
}
printf("\n");
}

1
udev/69-monocoque.rules Normal file
View File

@ -0,0 +1 @@
SUBSYSTEMS=="usb",ATTRS{product}=="Rev Burner",GROUP="input",TAG+="uaccess"