diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 0000000..bf5e415
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1,5 @@
+# Auto detect text files and perform LF normalization
+* text=auto
+
+# Never modify line endings of bash scripts
+*.sh text eol=lf
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..00cd112
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,11 @@
+# .gitignore
+.svn
+.objects
+build_no.h
+checker_*.txt
+Utilities/Driver
+Utilities/Binaries
+Utilities/can_moni/can_moni
+Utilities/can_test/can_test
+Utilities/can_moni/build_no.h
+Utilities/can_test/build_no.h
diff --git a/LICENSE.GPL-2.0-only b/LICENSE.GPL-2.0-only
new file mode 100644
index 0000000..9efa6fb
--- /dev/null
+++ b/LICENSE.GPL-2.0-only
@@ -0,0 +1,338 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+
+ 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.
+
+
+ Copyright (C)
+
+ 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, see .
+
+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.
+
+ , 1 April 1989
+ Moe Ghoul, 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.
diff --git a/LICENSE b/LICENSE.UVS-Freeware
similarity index 100%
rename from LICENSE
rename to LICENSE.UVS-Freeware
diff --git a/README.md b/README.md
index af80041..6c01a5c 100644
--- a/README.md
+++ b/README.md
@@ -1,15 +1,17 @@
-### macOS® Utilities for PCAN-USB Interfaces
+### macOS® Utilities for PEAK-System PCAN USB Interfaces
-*Copyright © 2012-2024 by UV Software, Berlin.*\
-*All rights reserved.*
+*Copyright © 2005-2010 by Uwe Vogt, UV Software, Friedrichshafen.* \
+*Copyright © 2012-2024 by Uwe Vogt, UV Software, Berlin.*
+
+
# Running CAN and CAN FD on Mac®
-The PCBUSB library realizes a CAN to USB user-space driver under macOS for PCAN-USB interfaces from PEAK-System Technik, Darmstadt.
+The PCBUSB library realizes a CAN to USB user-space driver under macOS for PCAN USB interfaces from PEAK-System Technik, Darmstadt.
It supports up to 8 PCAN-USB or PCAN-USB FD devices.
The dynamic library libPCBUSB is running under macOS 10.13 and later (x86_64 architecture).
-Since version 0.10.1 it is running under macOS Big Sur (11.x) or macOS Monterey (12.x) as Universal macOS Binary.
+Since version 0.10.1 it is running under macOS Big Sur (11.x) and later as Universal macOS Binary.
See the [MacCAN](https://www.mac-can.com/) website to learn more.
@@ -19,8 +21,6 @@ This repo offers two command line tools that are build upon the PCBUSB library:
- `can_moni` to view incoming CAN messages
- `can_test` to test CAN communication
-Both tools run as a standalone program, therefor it is not necessary to install the PCBUSB library to run them.
-
### can_moni
`can_moni` is a command line tool to view incoming CAN messages.
@@ -39,45 +39,68 @@ Type `can_test --help` to display all program options.
### Target Platform
-- macOS 12.0 and later (Intel and Apple silicon)
+- macOS 13.0 and later (Intel and Apple silicon)
### Development Environment
-#### macOS Sonoma
+#### macOS Sequoia
-- macOS Sonoma (14.5) on a Mac mini (M1, 2020)
-- Apple clang version 15.0.0 (clang-1500.3.9.4)
-- Xcode Version 15.4 (15F31d)
+- macOS Sequoia (15.2) on a Mac mini (M1, 2020)
+- Apple clang version 16.0.0 (clang-1600.0.26.6)
-#### macOS Monterey
+#### macOS Ventura
-- macOS Monterey (12.7.5) on a MacBook Pro (2019)
-- Apple clang version 13.0.0 (clang-1300.0.29.30)
-- Xcode Version 13.2.1 (13C100)
+- macOS Ventura (13.7.1) on a MacBook Pro (2019)
+- Apple clang version 14.0.3 (clang-1403.0.22.14.1)
### Supported Devices
Only the following devices from PEAK-System Technik are supported:
- PCAN-USB (product code: IPEH-002021, IPEH-002022)
- PCAN-USB FD (product code: IPEH-004022)
+- PCAN-USB Pro FD (item no. IPEH-004061), but only the first channel (CAN1)
### Known Bugs and Caveats
-For a list of known bugs and caveats in the underlying PCBUSB library read the documentation of the appropriated library version.
+- For a list of known bugs and caveats see tab [Issues](https://github.com/mac-can/PCBUSB-Utilities/issues) in the GitHub repo.
+- For a list of known bugs and caveats in the underlying PCBUSB library read the documentation of the appropriated library version.
+
+### Licenses
+
+This repository contains two versions of the PCBUSB utilities that are licensed under different licences:
+
+- **Standalone Version**:
+ This version of the utilities does not require the PCBUSB library to be installed.
+ The utilities are offered in binary form only.
+ This version can be found in the folder `$(PROJROOT)/Binaries`.
+- **Open-source Version**:
+ This version links the PCBUSB library at runtime.
+ The PCBUSB library itself is not part of this work.
+ See folder `$(PROJROOT)/Utilities`.
-PCAN-USB Pro FD devices are supported since version 0.10 of the PCBUSB library, but only the first channel (CAN1).
+#### Licence for the Standalone Version
-## This and That
+This program is freeware without any warranty or support! \
+Please note the copyright and license agreements.
-Since version 0.5.3 macOS 11 or newer is required to run the PCBUSB utilities as Universal macOS Binary.
+#### Licence for the Open-Source Version
-This repo contains only binaries files of the PCBUSB utilities.
+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.
-### License
+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.
-The PCBUSB utilities are freeware without any warranty or support!
+You should have received a copy of the GNU General Public License along
+with this program; if not, see .
-Please note the copyright and license agreement.
+Note: The libPCBUSB is licensed under a freeware license without any
+warranty or support. The libPCBUSB is not part of this program.
+It can be downloaded from .
### Trademarks
diff --git a/Utilities/Makefile b/Utilities/Makefile
new file mode 100644
index 0000000..19c99c0
--- /dev/null
+++ b/Utilities/Makefile
@@ -0,0 +1,45 @@
+#
+# CAN Utilities for PEAK-System PCAN USB Interfaces (macOS, x86_64 & arm64)
+#
+# Copyright (c) 2007-2010 Uwe Vogt, UV Software, Friedrichshafen
+# Copyright (c) 2012-2024 Uwe Vogt, UV Software, Berlin (info@mac-can.com)
+#
+# These utilities are 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 3 of the License, or
+# (at your option) any later version.
+#
+# These utilities 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 these utilities. If not, see .
+#
+all:
+ @rm -r build_no.h 2> /dev/null || true
+ @./build_no.sh
+ @echo "\033[1mBuilding my beloved CAN Utilities...\033[0m"
+ $(MAKE) -C can_test $@
+ $(MAKE) -C can_moni $@
+
+clean:
+ $(MAKE) -C can_test $@
+ $(MAKE) -C can_moni $@
+
+pristine:
+ $(MAKE) -C can_test $@
+ $(MAKE) -C can_moni $@
+
+install:
+# $(MAKE) -C can_test $@
+# $(MAKE) -C can_moni $@
+
+check:
+ $(MAKE) -C can_test $@ 2> checker_test.txt
+ $(MAKE) -C can_moni $@ 2> checker_moni.txt
+
+build_no:
+ @./build_no.sh
+ @cat ./build_no.h
diff --git a/Utilities/PCBUSB.c b/Utilities/PCBUSB.c
new file mode 100755
index 0000000..66ca140
--- /dev/null
+++ b/Utilities/PCBUSB.c
@@ -0,0 +1,263 @@
+//
+// PCBUSB.c
+// MacCAN Monitor
+// Wrapper for libPCBUSB
+//
+// Created by Uwe Vogt on 18.08.13.
+// Copyright (c) 2013-2024 UV Software. All rights reserved.
+//
+// This software is freeware without any warranty or support!
+//
+// NO WARRANTIES: You expressly acknowledge and agree that use of the
+// SOFTWARE PRODUCT is at your sole risk. The SOFTWARE PRODUCT is provided
+// "AS IS" and without warranty of any kind. UV Software hereby EXPRESSLY
+// DISCLAIMS ALL WARRANTIES OR CONDITIONS, EITHER EXPRESS OR IMPLIED,
+// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OR CONDITIONS OF
+// MERCHANTABILITY, NON INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE.
+// You are solely responsible for determining the appropriateness of using
+// this SOFTWARE PRODUCT and assume all risks associated with the use of
+// this SOFTWARE PRODUCT, including but not limited to the risks of program
+// errors, damage to or loss of data, programs or equipment, and
+// unavailability or interruption of operations.
+//
+// NO LIABILITY FOR DAMAGES: UNDER NO CIRCUMSTANCES, INCLUDING NEGLIGENCE,
+// SHALL UV Software BE LIABLE FOR ANY INCIDENTAL, SPECIAL, INDIRECT OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS
+// OF BUSINESS PROFITS, BUSINESS INTERRUPTION, LOSS OF BUSINESS INFORMATION,
+// OR ANY OTHER PECUNIARY LOSS) ARISING OUT OF OR RELATING TO THIS LICENSE,
+// EVEN IF UV Software HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+// In no event shall UV Software's total liability to you for all damages
+// exceed the amount paid for this license to the SOFTWARE PRODUCT. The
+// entire risk arising out of use or performance of the SOFTWARE PRODUCT
+// remains with you.
+//
+#if defined(__APPLE__)
+#include "PCBUSB.h"
+#define CAN_LIBRARY "libPCBUSB.dylib"
+#else
+#include "PCANBasic.h"
+#define CAN_LIBRARY "libpcanbasic.so"
+#endif
+#include
+#include
+#include
+#include
+
+typedef TPCANStatus (*CAN_Initialize_t)(TPCANHandle Channel, TPCANBaudrate Btr0Btr1, TPCANType HwType, DWORD IOPort, WORD Interrupt);
+typedef TPCANStatus (*CAN_Uninitialize_t)(TPCANHandle Channel);
+typedef TPCANStatus (*CAN_Reset_t)(TPCANHandle Channel);
+typedef TPCANStatus (*CAN_GetStatus_t)(TPCANHandle Channel);
+typedef TPCANStatus (*CAN_Read_t)(TPCANHandle Channel, TPCANMsg* MessageBuffer, TPCANTimestamp* TimestampBuffer);
+typedef TPCANStatus (*CAN_Write_t)(TPCANHandle Channel, TPCANMsg* MessageBuffer);
+typedef TPCANStatus (*CAN_FilterMessages_t)(TPCANHandle Channel, DWORD FromID, DWORD ToID, TPCANMode Mode);
+typedef TPCANStatus (*CAN_GetValue_t)(TPCANHandle Channel, TPCANParameter Parameter, void* Buffer, DWORD BufferLength);
+typedef TPCANStatus (*CAN_SetValue_t)(TPCANHandle Channel, TPCANParameter Parameter, void* Buffer, DWORD BufferLength);
+typedef TPCANStatus (*CAN_GetErrorText_t)(TPCANStatus Error, WORD Language, char* Buffer);
+typedef TPCANStatus (*CAN_InitializeFD_t)(TPCANHandle Channel, TPCANBitrateFD BitrateFD);
+typedef TPCANStatus (*CAN_ReadFD_t)(TPCANHandle Channel, TPCANMsgFD* MessageBuffer, TPCANTimestampFD* TimestampBuffer);
+typedef TPCANStatus (*CAN_WriteFD_t)(TPCANHandle Channel, TPCANMsgFD* MessageBuffer);
+typedef TPCANStatus (*CAN_LookUpChannel_t)(LPSTR Parameters, TPCANHandle* FoundChannel);
+
+static CAN_Initialize_t fpCAN_Initialize = NULL;
+static CAN_Uninitialize_t fpCAN_Uninitialize = NULL;
+static CAN_Reset_t fpCAN_Reset = NULL;
+static CAN_GetStatus_t fpCAN_GetStatus = NULL;
+static CAN_Read_t fpCAN_Read = NULL;
+static CAN_Write_t fpCAN_Write = NULL;
+static CAN_FilterMessages_t fpCAN_FilterMessages = NULL;
+static CAN_GetValue_t fpCAN_GetValue = NULL;
+static CAN_SetValue_t fpCAN_SetValue = NULL;
+static CAN_GetErrorText_t fpCAN_GetErrorText = NULL;
+static CAN_InitializeFD_t fpCAN_InitializeFD = NULL;
+static CAN_ReadFD_t fpCAN_ReadFD = NULL;
+static CAN_WriteFD_t fpCAN_WriteFD = NULL;
+static CAN_LookUpChannel_t fpCAN_LookUpChannel = NULL;
+
+static void *hLibrary = NULL;
+
+static int LoadLibrary(void) {
+ if (!hLibrary) {
+ errno = 0;
+ hLibrary = dlopen(CAN_LIBRARY, RTLD_LAZY);
+ if (!hLibrary)
+ return -1;
+ if ((fpCAN_Initialize = (CAN_Initialize_t)dlsym(hLibrary, "CAN_Initialize")) == NULL)
+ goto err;
+ if ((fpCAN_Uninitialize = (CAN_Uninitialize_t)dlsym(hLibrary, "CAN_Uninitialize")) == NULL)
+ goto err;
+ if ((fpCAN_Reset = (CAN_Reset_t)dlsym(hLibrary, "CAN_Reset")) == NULL)
+ goto err;
+ if ((fpCAN_GetStatus = (CAN_GetStatus_t)dlsym(hLibrary, "CAN_GetStatus")) == NULL)
+ goto err;
+ if ((fpCAN_Read = (CAN_Read_t)dlsym(hLibrary, "CAN_Read")) == NULL)
+ goto err;
+ if ((fpCAN_Write = (CAN_Write_t)dlsym(hLibrary, "CAN_Write")) == NULL)
+ goto err;
+ if ((fpCAN_FilterMessages = (CAN_FilterMessages_t)dlsym(hLibrary, "CAN_FilterMessages")) == NULL)
+ goto err;
+ if ((fpCAN_GetValue = (CAN_GetValue_t)dlsym(hLibrary, "CAN_GetValue")) == NULL)
+ goto err;
+ if ((fpCAN_SetValue = (CAN_SetValue_t)dlsym(hLibrary, "CAN_SetValue")) == NULL)
+ goto err;
+ if ((fpCAN_GetErrorText = (CAN_GetErrorText_t)dlsym(hLibrary, "CAN_GetErrorText")) == NULL)
+ goto err;
+ if ((fpCAN_InitializeFD = (CAN_InitializeFD_t)dlsym(hLibrary, "CAN_InitializeFD")) == NULL)
+ goto err;
+ if ((fpCAN_ReadFD = (CAN_ReadFD_t)dlsym(hLibrary, "CAN_ReadFD")) == NULL)
+ goto err;
+ if ((fpCAN_WriteFD = (CAN_WriteFD_t)dlsym(hLibrary, "CAN_WriteFD")) == NULL)
+ goto err;
+ if ((fpCAN_LookUpChannel = (CAN_LookUpChannel_t)dlsym(hLibrary, "CAN_LookUpChannel")) == NULL)
+ fpCAN_LookUpChannel = NULL; // New function w/o implementation: accept the NULL pointer!
+ }
+ return 0;
+err:
+ fpCAN_Initialize = NULL;
+ fpCAN_Uninitialize = NULL;
+ fpCAN_Reset = NULL;
+ fpCAN_GetStatus = NULL;
+ fpCAN_Read = NULL;
+ fpCAN_Write = NULL;
+ fpCAN_FilterMessages = NULL;
+ fpCAN_GetValue = NULL;
+ fpCAN_SetValue = NULL;
+ fpCAN_GetErrorText = NULL;
+#ifndef CAN_2_0_ONLY
+ fpCAN_InitializeFD = NULL;
+ fpCAN_ReadFD = NULL;
+ fpCAN_WriteFD = NULL;
+#endif
+ fpCAN_LookUpChannel = NULL;
+ dlclose(hLibrary);
+ hLibrary = NULL;
+ return -1;
+}
+
+TPCANStatus CAN_Initialize(TPCANHandle Channel, TPCANBaudrate Btr0Btr1, TPCANType HwType, DWORD IOPort, WORD Interrupt) {
+ if (LoadLibrary() != 0)
+ return PCAN_ERROR_NODRIVER;
+ if (fpCAN_Initialize)
+ return fpCAN_Initialize(Channel, Btr0Btr1, HwType, IOPort, Interrupt);
+ else
+ return PCAN_ERROR_UNKNOWN;
+}
+
+TPCANStatus CAN_Uninitialize(TPCANHandle Channel) {
+ //if (LoadLibrary() != 0)
+ // return PCAN_ERROR_NODRIVER;
+ if (fpCAN_Uninitialize)
+ return fpCAN_Uninitialize(Channel);
+ else
+ return PCAN_ERROR_UNKNOWN;
+}
+
+TPCANStatus CAN_Reset(TPCANHandle Channel) {
+ if (LoadLibrary() != 0)
+ return PCAN_ERROR_NODRIVER;
+ if (fpCAN_Reset)
+ return fpCAN_Reset(Channel);
+ else
+ return PCAN_ERROR_UNKNOWN;
+}
+
+TPCANStatus CAN_GetStatus(TPCANHandle Channel) {
+ if (LoadLibrary() != 0)
+ return PCAN_ERROR_NODRIVER;
+ if (fpCAN_GetStatus)
+ return fpCAN_GetStatus(Channel);
+ else
+ return PCAN_ERROR_UNKNOWN;
+}
+
+TPCANStatus CAN_Read(TPCANHandle Channel, TPCANMsg* MessageBuffer, TPCANTimestamp* TimestampBuffer) {
+ if (LoadLibrary() != 0)
+ return PCAN_ERROR_NODRIVER;
+ if (fpCAN_Read)
+ return fpCAN_Read(Channel, MessageBuffer, TimestampBuffer);
+ else
+ return PCAN_ERROR_UNKNOWN;
+}
+
+TPCANStatus CAN_Write(TPCANHandle Channel, TPCANMsg* MessageBuffer) {
+ if (LoadLibrary() != 0)
+ return PCAN_ERROR_NODRIVER;
+ if (fpCAN_Write)
+ return fpCAN_Write(Channel, MessageBuffer);
+ else
+ return PCAN_ERROR_UNKNOWN;
+}
+
+TPCANStatus CAN_FilterMessages(TPCANHandle Channel, DWORD FromID, DWORD ToID, TPCANMode Mode) {
+ if (LoadLibrary() != 0)
+ return PCAN_ERROR_NODRIVER;
+ if (fpCAN_FilterMessages)
+ return fpCAN_FilterMessages(Channel, FromID, ToID, Mode);
+ else
+ return PCAN_ERROR_UNKNOWN;
+}
+
+TPCANStatus CAN_GetValue(TPCANHandle Channel, TPCANParameter Parameter, void* Buffer, DWORD BufferLength) {
+ if (LoadLibrary() != 0)
+ return PCAN_ERROR_NODRIVER;
+ if (fpCAN_GetValue)
+ return fpCAN_GetValue(Channel, Parameter, Buffer, BufferLength);
+ else
+ return PCAN_ERROR_UNKNOWN;
+}
+
+TPCANStatus CAN_SetValue(TPCANHandle Channel, TPCANParameter Parameter, void* Buffer, DWORD BufferLength) {
+ if (LoadLibrary() != 0)
+ return PCAN_ERROR_NODRIVER;
+ if (fpCAN_SetValue)
+ return fpCAN_SetValue(Channel, Parameter, Buffer, BufferLength);
+ else
+ return PCAN_ERROR_UNKNOWN;
+}
+
+TPCANStatus CAN_GetErrorText(TPCANStatus Error, WORD Language, char* Buffer) {
+ if (LoadLibrary() != 0) {
+ if (Buffer)
+ strcpy(Buffer, "PCBUSB library could not be loaded");
+ return PCAN_ERROR_NODRIVER;
+ }
+ if (fpCAN_GetErrorText)
+ return fpCAN_GetErrorText(Error, Language, Buffer);
+ else
+ return PCAN_ERROR_UNKNOWN;
+}
+
+TPCANStatus CAN_InitializeFD(TPCANHandle Channel, TPCANBitrateFD BitrateFD) {
+ if (LoadLibrary() != 0)
+ return PCAN_ERROR_NODRIVER;
+ if (fpCAN_InitializeFD)
+ return fpCAN_InitializeFD(Channel, BitrateFD);
+ else
+ return PCAN_ERROR_UNKNOWN;
+}
+
+TPCANStatus CAN_ReadFD(TPCANHandle Channel, TPCANMsgFD* MessageBuffer, TPCANTimestampFD* TimestampBuffer) {
+ if (LoadLibrary() != 0)
+ return PCAN_ERROR_NODRIVER;
+ if (fpCAN_ReadFD)
+ return fpCAN_ReadFD(Channel, MessageBuffer, TimestampBuffer);
+ else
+ return PCAN_ERROR_UNKNOWN;
+}
+
+TPCANStatus CAN_WriteFD(TPCANHandle Channel, TPCANMsgFD* MessageBuffer) {
+ if (LoadLibrary() != 0)
+ return PCAN_ERROR_NODRIVER;
+ if (fpCAN_WriteFD)
+ return fpCAN_WriteFD(Channel, MessageBuffer);
+ else
+ return PCAN_ERROR_UNKNOWN;
+}
+
+TPCANStatus CAN_LookUpChannel(LPSTR Parameters, TPCANHandle* FoundChannel) {
+ if (LoadLibrary() != 0)
+ return PCAN_ERROR_NODRIVER;
+ if (fpCAN_LookUpChannel)
+ return fpCAN_LookUpChannel(Parameters, FoundChannel);
+ else
+ return PCAN_ERROR_UNKNOWN;
+}
diff --git a/Utilities/PCBUSB.h b/Utilities/PCBUSB.h
new file mode 100644
index 0000000..8bf3ce9
--- /dev/null
+++ b/Utilities/PCBUSB.h
@@ -0,0 +1,600 @@
+/* -- $HeadURL: https://uv-software.net/MacCAN/PCANUSB/Library/trunk/drv/pcan_api.h $ --
+ *
+ * project : CAN - Controller Area Network
+ *
+ * purpose : PCAN Application Programming Interface
+ *
+ * copyright : (C) 2012-2023 by UV Software, Berlin
+ *
+ * compiler : Apple clang version 15.0.0 (clang-1500.0.40.1)
+ *
+ * export : TPCANStatus CAN_Initialize(TPCANHandle Channel, TPCANBaudrate Btr0Btr1, TPCANType HwType, DWORD IOPort, WORD Interrupt);
+ * TPCANStatus CAN_Uninitialize(TPCANHandle Channel);
+ * TPCANStatus CAN_Reset(TPCANHandle Channel);
+ * TPCANStatus CAN_GetStatus(TPCANHandle Channel);
+ * TPCANStatus CAN_Read(TPCANHandle Channel, TPCANMsg* MessageBuffer, TPCANTimestamp* TimestampBuffer);
+ * TPCANStatus CAN_Write(TPCANHandle Channel, TPCANMsg* MessageBuffer);
+ * TPCANStatus CAN_FilterMessages(TPCANHandle Channel, DWORD FromID, DWORD ToID, TPCANMode Mode);
+ * TPCANStatus CAN_GetValue(TPCANHandle Channel, TPCANParameter Parameter, void* Buffer, DWORD BufferLength);
+ * TPCANStatus CAN_SetValue(TPCANHandle Channel, TPCANParameter Parameter, void* Buffer, DWORD BufferLength);
+ * TPCANStatus CAN_GetErrorText(TPCANStatus Error, WORD Language, LPSTR Buffer);
+ * *** CAN FD capable devices ***
+ * TPCANStatus CAN_InitializeFD(TPCANHandle Channel, TPCANBitrateFD BitrateFD);
+ * TPCANStatus CAN_ReadFD(TPCANHandle Channel, TPCANMsgFD* MessageBuffer, TPCANTimestampFD* TimestampBuffer);
+ * TPCANStatus CAN_WriteFD(TPCANHandle Channel, TPCANMsgFD* MessageBuffer);
+ *
+ * includes : (none)
+ *
+ * author : Uwe Vogt, UV Software
+ *
+ * e-mail : uwe.vogt@uv-software.de
+ *
+ *
+ * ----------- description --------------------------------------------
+ *
+ * PCAN API - PEAK CAN Application Programming Interface
+ *
+ * This Application Programming Interface (API) is an almost compatible
+ * implementation of the PEAK PCANBasic DLL on macOS (x86_64 and arm64).
+ *
+ * Supported CAN Interfaces:
+ * - PCAN-USB (item no. IPEH-002021/002022)
+ * - PCAN-USB FD (item no. IPEH-004022)
+ * Up to 8 channel handles are supported.
+ *
+ * Version of PCAN API:
+ * - Based on PEAK's version of 2023-08-28
+ */
+
+#ifndef PCAN_API_H_INCLUDED
+#define PCAN_API_H_INCLUDED
+
+/* ----------- includes -----------------------------------------------
+ */
+
+#ifdef __APPLE__
+#include // To map Windows integer types
+#endif
+
+/* ----------- defines ------------------------------------------------
+ */
+
+#ifdef __APPLE__
+#ifndef BYTE
+#define BYTE UInt8
+#endif
+#ifndef WORD
+#define WORD UInt16
+#endif
+#ifndef DWORD
+#define DWORD UInt32
+#endif
+#ifndef UINT64
+#define UINT64 UInt64
+#endif
+#ifndef LPSTR
+#define LPSTR char*
+#endif
+#define __T(s) s
+#endif
+
+/* Currently defined and supported PCAN channels
+ */
+#define PCAN_NONEBUS 0x00U //!< Undefined/default value for a PCAN bus
+
+#define PCAN_USBBUS1 0x51U //!< PCAN-USB interface, channel 1
+#define PCAN_USBBUS2 0x52U //!< PCAN-USB interface, channel 2
+#define PCAN_USBBUS3 0x53U //!< PCAN-USB interface, channel 3
+#define PCAN_USBBUS4 0x54U //!< PCAN-USB interface, channel 4
+#define PCAN_USBBUS5 0x55U //!< PCAN-USB interface, channel 5
+#define PCAN_USBBUS6 0x56U //!< PCAN-USB interface, channel 6
+#define PCAN_USBBUS7 0x57U //!< PCAN-USB interface, channel 7
+#define PCAN_USBBUS8 0x58U //!< PCAN-USB interface, channel 8
+#ifndef __APPLE__
+#define PCAN_USBBUS9 0x509U //!< PCAN-USB interface, channel 9
+#define PCAN_USBBUS10 0x50AU //!< PCAN-USB interface, channel 10
+#define PCAN_USBBUS11 0x50BU //!< PCAN-USB interface, channel 11
+#define PCAN_USBBUS12 0x50CU //!< PCAN-USB interface, channel 12
+#define PCAN_USBBUS13 0x50DU //!< PCAN-USB interface, channel 13
+#define PCAN_USBBUS14 0x50EU //!< PCAN-USB interface, channel 14
+#define PCAN_USBBUS15 0x50FU //!< PCAN-USB interface, channel 15
+#define PCAN_USBBUS16 0x510U //!< PCAN-USB interface, channel 16
+#endif
+
+
+/* Represent the PCAN error and status codes
+ */
+#define PCAN_ERROR_OK 0x00000U //!< No error
+#define PCAN_ERROR_XMTFULL 0x00001U //!< Transmit buffer in CAN controller is full
+#define PCAN_ERROR_OVERRUN 0x00002U //!< CAN controller was read too late
+#define PCAN_ERROR_BUSLIGHT 0x00004U //!< Bus error: an error counter reached the 'light' limit
+#define PCAN_ERROR_BUSHEAVY 0x00008U //!< Bus error: an error counter reached the 'heavy' limit
+#define PCAN_ERROR_BUSWARNING PCAN_ERROR_BUSHEAVY //!< Bus error: an error counter reached the 'warning' limit
+#define PCAN_ERROR_BUSPASSIVE 0x40000U //!< Bus error: the CAN controller is error passive
+#define PCAN_ERROR_BUSOFF 0x00010U //!< Bus error: the CAN controller is in bus-off state
+#define PCAN_ERROR_ANYBUSERR (PCAN_ERROR_BUSWARNING | PCAN_ERROR_BUSLIGHT | PCAN_ERROR_BUSHEAVY | PCAN_ERROR_BUSOFF | PCAN_ERROR_BUSPASSIVE) //!< Mask for all bus errors
+#define PCAN_ERROR_QRCVEMPTY 0x00020U //!< Receive queue is empty
+#define PCAN_ERROR_QOVERRUN 0x00040U //!< Receive queue was read too late
+#define PCAN_ERROR_QXMTFULL 0x00080U //!< Transmit queue is full
+#define PCAN_ERROR_REGTEST 0x00100U //!< Test of the CAN controller hardware registers failed (no hardware found)
+#define PCAN_ERROR_NODRIVER 0x00200U //!< Driver not loaded
+#define PCAN_ERROR_HWINUSE 0x00400U //!< Hardware already in use by a Net
+#define PCAN_ERROR_NETINUSE 0x00800U //!< A Client is already connected to the Net
+#define PCAN_ERROR_ILLHW 0x01400U //!< Hardware handle is invalid
+#define PCAN_ERROR_ILLNET 0x01800U //!< Net handle is invalid
+#define PCAN_ERROR_ILLCLIENT 0x01C00U //!< Client handle is invalid
+#define PCAN_ERROR_ILLHANDLE (PCAN_ERROR_ILLHW | PCAN_ERROR_ILLNET | PCAN_ERROR_ILLCLIENT) //!< Mask for all handle errors
+#define PCAN_ERROR_RESOURCE 0x02000U //!< Resource (FIFO, Client, timeout) cannot be created
+#define PCAN_ERROR_ILLPARAMTYPE 0x04000U //!< Invalid parameter
+#define PCAN_ERROR_ILLPARAMVAL 0x08000U //!< Invalid parameter value
+#define PCAN_ERROR_UNKNOWN 0x10000U //!< Unknown error
+#define PCAN_ERROR_ILLDATA 0x20000U //!< Invalid data, function, or action
+#define PCAN_ERROR_ILLMODE 0x80000U //!< Driver object state is wrong for the attempted operation
+#define PCAN_ERROR_CAUTION 0x2000000U //!< An operation was successfully carried out, however, irregularities were registered
+#define PCAN_ERROR_INITIALIZE 0x4000000U //!< Channel is not initialized [Value was changed from 0x40000 to 0x4000000]
+#define PCAN_ERROR_ILLOPERATION 0x8000000U //!< Invalid operation [Value was changed from 0x80000 to 0x8000000]
+
+/* PCAN devices
+ */
+#define PCAN_NONE 0x00U //!< Undefined, unknown or not selected PCAN device value
+#define PCAN_PEAKCAN 0x01U //!< PCAN Non-PnP devices. NOT USED WITHIN PCAN-Basic API
+#define PCAN_ISA 0x02U //!< PCAN-ISA, PCAN-PC/104, and PCAN-PC/104-Plus
+#define PCAN_DNG 0x03U //!< PCAN-Dongle
+#define PCAN_PCI 0x04U //!< PCAN-PCI, PCAN-cPCI, PCAN-miniPCI, and PCAN-PCI Express
+#define PCAN_USB 0x05U //!< PCAN-USB and PCAN-USB Pro
+#define PCAN_PCC 0x06U //!< PCAN-PC Card
+#define PCAN_VIRTUAL 0x07U //!< PCAN Virtual hardware. NOT USED WITHIN PCAN-Basic API
+#define PCAN_LAN 0x08U //!< PCAN Gateway devices
+
+/* PCAN parameters
+ */
+#define PCAN_DEVICE_ID 0x01U //!< Device identifier parameter
+#define PCAN_5VOLTS_POWER 0x02U //!< 5-Volt power parameter
+#define PCAN_RECEIVE_EVENT 0x03U //!< PCAN receive event handler parameter
+#define PCAN_MESSAGE_FILTER 0x04U //!< PCAN message filter parameter
+#define PCAN_API_VERSION 0x05U //!< PCAN-Basic API version parameter
+#define PCAN_CHANNEL_VERSION 0x06U //!< PCAN device channel version parameter
+#define PCAN_BUSOFF_AUTORESET 0x07U //!< PCAN Reset-On-Busoff parameter
+#define PCAN_LISTEN_ONLY 0x08U //!< PCAN Listen-Only parameter
+#define PCAN_LOG_LOCATION 0x09U //!< Directory path for log files
+#define PCAN_LOG_STATUS 0x0AU //!< Debug-Log activation status
+#define PCAN_LOG_CONFIGURE 0x0BU //!< Configuration of the debugged information (LOG_FUNCTION_***)
+#define PCAN_LOG_TEXT 0x0CU //!< Custom insertion of text into the log file
+#define PCAN_CHANNEL_CONDITION 0x0DU //!< Availability status of a PCAN-Channel
+#define PCAN_HARDWARE_NAME 0x0EU //!< PCAN hardware name parameter
+#define PCAN_RECEIVE_STATUS 0x0FU //!< Message reception status of a PCAN-Channel
+#define PCAN_CONTROLLER_NUMBER 0x10U //!< CAN-Controller number of a PCAN-Channel
+#define PCAN_TRACE_LOCATION 0x11U //!< Directory path for PCAN trace files
+#define PCAN_TRACE_STATUS 0x12U //!< CAN tracing activation status
+#define PCAN_TRACE_SIZE 0x13U //!< Configuration of the maximum file size of a CAN trace
+#define PCAN_TRACE_CONFIGURE 0x14U //!< Configuration of the trace file storing mode (TRACE_FILE_***)
+#define PCAN_CHANNEL_IDENTIFYING 0x15U //!< Physical identification of a USB based PCAN-Channel by blinking its associated LED
+#define PCAN_CHANNEL_FEATURES 0x16U //!< Capabilities of a PCAN device (FEATURE_***)
+#define PCAN_BITRATE_ADAPTING 0x17U //!< Using of an existing bit rate (PCAN-View connected to a channel)
+#define PCAN_BITRATE_INFO 0x18U //!< Configured bit rate as Btr0Btr1 value
+#define PCAN_BITRATE_INFO_FD 0x19U //!< Configured bit rate as TPCANBitrateFD string
+#define PCAN_BUSSPEED_NOMINAL 0x1AU //!< Configured nominal CAN Bus speed as Bits per seconds
+#define PCAN_BUSSPEED_DATA 0x1BU //!< Configured CAN data speed as Bits per seconds
+#define PCAN_IP_ADDRESS 0x1CU //!< Remote address of a LAN channel as string in IPv4 format
+#define PCAN_LAN_SERVICE_STATUS 0x1DU //!< Status of the Virtual PCAN-Gateway Service
+#define PCAN_ALLOW_STATUS_FRAMES 0x1EU //!< Status messages reception status within a PCAN-Channel
+#define PCAN_ALLOW_RTR_FRAMES 0x1FU //!< RTR messages reception status within a PCAN-Channel
+#define PCAN_ALLOW_ERROR_FRAMES 0x20U //!< Error messages reception status within a PCAN-Channel
+#define PCAN_INTERFRAME_DELAY 0x21U //!< Delay, in microseconds, between sending frames
+#define PCAN_ACCEPTANCE_FILTER_11BIT 0x22U //!< Filter over code and mask patterns for 11-Bit messages
+#define PCAN_ACCEPTANCE_FILTER_29BIT 0x23U //!< Filter over code and mask patterns for 29-Bit messages
+#define PCAN_IO_DIGITAL_CONFIGURATION 0x24U //!< Output mode of 32 digital I/O pin of a PCAN-USB Chip. 1: Output-Active 0 : Output Inactive
+#define PCAN_IO_DIGITAL_VALUE 0x25U //!< Value assigned to a 32 digital I/O pins of a PCAN-USB Chip
+#define PCAN_IO_DIGITAL_SET 0x26U //!< Value assigned to a 32 digital I/O pins of a PCAN-USB Chip - Multiple digital I/O pins to 1 = High
+#define PCAN_IO_DIGITAL_CLEAR 0x27U //!< Clear multiple digital I/O pins to 0
+#define PCAN_IO_ANALOG_VALUE 0x28U //!< Get value of a single analog input pin
+#define PCAN_FIRMWARE_VERSION 0x29U //!< Get the version of the firmware used by the device associated with a PCAN-Channel
+#define PCAN_ATTACHED_CHANNELS_COUNT 0x2AU //!< Get the amount of PCAN channels attached to a system
+#define PCAN_ATTACHED_CHANNELS 0x2BU //!< Get information about PCAN channels attached to a system
+#define PCAN_ALLOW_ECHO_FRAMES 0x2CU //!< Echo messages reception status within a PCAN-Channel
+#define PCAN_DEVICE_PART_NUMBER 0x2DU //!< Get the part number associated to a device
+#define PCAN_HARD_RESET_STATUS 0x2EU //!< Activation status of hard reset processing via CAN_Reset calls
+#define PCAN_EXT_BTR0BTR1 0x80U //!< UVS: bit-timing register
+#define PCAN_EXT_TX_COUNTER 0x81U //!< UVS: number of transmitted frames
+#define PCAN_EXT_RX_COUNTER 0x82U //!< UVS: number of received frames
+#define PCAN_EXT_ERR_COUNTER 0x83U //!< UVS: number of error frames
+#define PCAN_EXT_RX_QUE_OVERRUN 0x84U //!< UVS: receive queue overrun counter
+#define PCAN_EXT_HARDWARE_VERSION 0x85U //!< UVS: version number of the interface firmware
+#define PCAN_EXT_SOFTWARE_VERSION 0x86U //!< UVS: version number of the driver respectively library
+#define PCAN_EXT_RECEIVE_CALLBACK 0x87U //!< UVS: callback function called on the reception of an URB
+#define PCAN_EXT_LOG_USB 0x8FU //!< UVS: Log USB communication (URB buffer <==> CAN messages)
+
+/* DEPRECATED parameters
+ */
+#define PCAN_DEVICE_NUMBER PCAN_DEVICE_ID //!< Deprecated parameter. Use PCAN_DEVICE_ID instead
+
+/* PCAN parameter values
+ */
+#define PCAN_PARAMETER_OFF 0x00U //!< The PCAN parameter is not set (inactive)
+#define PCAN_PARAMETER_ON 0x01U //!< The PCAN parameter is set (active)
+#define PCAN_FILTER_CLOSE 0x00U //!< The PCAN filter is closed. No messages will be received
+#define PCAN_FILTER_OPEN 0x01U //!< The PCAN filter is fully opened. All messages will be received
+#define PCAN_FILTER_CUSTOM 0x02U //!< The PCAN filter is custom configured. Only registered messages will be received
+#define PCAN_CHANNEL_UNAVAILABLE 0x00U //!< The PCAN-Channel handle is illegal, or its associated hardware is not available
+#define PCAN_CHANNEL_AVAILABLE 0x01U //!< The PCAN-Channel handle is available to be connected (PnP Hardware: it means furthermore that the hardware is plugged-in)
+#define PCAN_CHANNEL_OCCUPIED 0x02U //!< The PCAN-Channel handle is valid, and is already being used
+#define PCAN_CHANNEL_PCANVIEW (PCAN_CHANNEL_AVAILABLE | PCAN_CHANNEL_OCCUPIED) //!< The PCAN-Channel handle is already being used by a PCAN-View application, but is available to connect
+
+#define LOG_FUNCTION_DEFAULT 0x00U //!< Logs system exceptions / errors
+#define LOG_FUNCTION_ENTRY 0x01U //!< Logs the entries to the PCAN-Basic API functions
+#define LOG_FUNCTION_PARAMETERS 0x02U //!< Logs the parameters passed to the PCAN-Basic API functions
+#define LOG_FUNCTION_LEAVE 0x04U //!< Logs the exits from the PCAN-Basic API functions
+#define LOG_FUNCTION_WRITE 0x08U //!< Logs the CAN messages passed to the CAN_Write function
+#define LOG_FUNCTION_READ 0x10U //!< Logs the CAN messages received within the CAN_Read function
+#define LOG_FUNCTION_ALL 0xFFFFU //!< Logs all possible information within the PCAN-Basic API functions
+
+#define TRACE_FILE_SINGLE 0x00U //!< A single file is written until it size reaches PAN_TRACE_SIZE
+#define TRACE_FILE_SEGMENTED 0x01U //!< Traced data is distributed in several files with size PAN_TRACE_SIZE
+#define TRACE_FILE_DATE 0x02U //!< Includes the date into the name of the trace file
+#define TRACE_FILE_TIME 0x04U //!< Includes the start time into the name of the trace file
+#define TRACE_FILE_OVERWRITE 0x80U //!< Causes the overwriting of available traces (same name)
+#define TRACE_FILE_DATA_LENGTH 0x100U //!< Causes using the data length column ('l') instead of the DLC column ('L') in the trace file
+
+#define FEATURE_FD_CAPABLE 0x01U //!< Device supports flexible data-rate (CAN-FD)
+#define FEATURE_DELAY_CAPABLE 0x02U //!< Device supports a delay between sending frames (FPGA based USB devices)
+#define FEATURE_IO_CAPABLE 0x04U //!< Device supports I/O functionality for electronic circuits (USB-Chip devices)
+
+#define SERVICE_STATUS_STOPPED 0x01U //!< The service is not running
+#define SERVICE_STATUS_RUNNING 0x04U //!< The service is running
+
+/* Other constants
+ */
+#define MAX_LENGTH_HARDWARE_NAME 33 //!< Maximum length of the name of a device: 32 characters + terminator
+#define MAX_LENGTH_VERSION_STRING 256 //!< Maximum length of a version string: 255 characters + terminator
+
+/* PCAN message types
+ */
+#define PCAN_MESSAGE_STANDARD 0x00U //!< The PCAN message is a CAN Standard Frame (11-bit identifier)
+#define PCAN_MESSAGE_RTR 0x01U //!< The PCAN message is a CAN Remote-Transfer-Request Frame
+#define PCAN_MESSAGE_EXTENDED 0x02U //!< The PCAN message is a CAN Extended Frame (29-bit identifier)
+#define PCAN_MESSAGE_FD 0x04U //!< The PCAN message represents a FD frame in terms of CiA Specs
+#define PCAN_MESSAGE_BRS 0x08U //!< The PCAN message represents a FD bit rate switch (CAN data at a higher bit rate)
+#define PCAN_MESSAGE_ESI 0x10U //!< The PCAN message represents a FD error state indicator(CAN FD transmitter was error active)
+#define PCAN_MESSAGE_ECHO 0x20U //!< The PCAN message represents an echo CAN Frame
+#define PCAN_MESSAGE_ERRFRAME 0x40U //!< The PCAN message represents an error frame
+#define PCAN_MESSAGE_STATUS 0x80U //!< The PCAN message represents a PCAN status message
+
+/* LookUp Parameters
+ */
+#define LOOKUP_DEVICE_TYPE __T("devicetype") //!< Lookup channel by Device type (see PCAN devices e.g. PCAN_USB)
+#define LOOKUP_DEVICE_ID __T("deviceid") //!< Lookup channel by device id
+#define LOOKUP_CONTROLLER_NUMBER __T("controllernumber") //!< Lookup channel by CAN controller 0-based index
+#define LOOKUP_IP_ADDRESS __T("ipaddress") //!< Lookup channel by IP address (LAN channels only)
+
+/* Frame Type / Initialization Mode
+ */
+#define PCAN_MODE_STANDARD PCAN_MESSAGE_STANDARD
+#define PCAN_MODE_EXTENDED PCAN_MESSAGE_EXTENDED
+
+/* Baud rate codes = BTR0/BTR1 register values for the CAN controller.
+ * You can define your own Baud rate with the BTROBTR1 register.
+ * Take a look at www.peak-system.com for their free software "BAUDTOOL"
+ * to calculate the BTROBTR1 register for every bit rate and sample point.
+ */
+#define PCAN_BAUD_1M 0x0014U //!< 1 MBit/s
+#define PCAN_BAUD_800K 0x0016U //!< 800 kBit/s
+#define PCAN_BAUD_500K 0x001CU //!< 500 kBit/s
+#define PCAN_BAUD_250K 0x011CU //!< 250 kBit/s
+#define PCAN_BAUD_125K 0x031CU //!< 125 kBit/s
+#define PCAN_BAUD_100K 0x432FU //!< 100 kBit/s
+#define PCAN_BAUD_95K 0xC34EU //!< 95,238 kBit/s
+#define PCAN_BAUD_83K 0x852BU //!< 83,333 kBit/s
+#define PCAN_BAUD_50K 0x472FU //!< 50 kBit/s
+#define PCAN_BAUD_47K 0x1414U //!< 47,619 kBit/s
+#define PCAN_BAUD_33K 0x8B2FU //!< 33,333 kBit/s
+#define PCAN_BAUD_20K 0x532FU //!< 20 kBit/s
+#define PCAN_BAUD_10K 0x672FU //!< 10 kBit/s
+#define PCAN_BAUD_5K 0x7F7FU //!< 5 kBit/s
+
+/* Represents the configuration for a CAN bit rate
+ * Note:
+ * * Each parameter and its value must be separated with a '='.
+ * * Each pair of parameter/value must be separated using ','.
+ *
+ * Example:
+ * f_clock=80000000,nom_brp=10,nom_tseg1=5,nom_tseg2=2,nom_sjw=1,data_brp=4,data_tseg1=7,data_tseg2=2,data_sjw=1
+ */
+#define PCAN_BR_CLOCK __T("f_clock")
+#define PCAN_BR_CLOCK_MHZ __T("f_clock_mhz")
+#define PCAN_BR_NOM_BRP __T("nom_brp")
+#define PCAN_BR_NOM_TSEG1 __T("nom_tseg1")
+#define PCAN_BR_NOM_TSEG2 __T("nom_tseg2")
+#define PCAN_BR_NOM_SJW __T("nom_sjw")
+#define PCAN_BR_NOM_SAMPLE __T("nom_sam")
+#define PCAN_BR_DATA_BRP __T("data_brp")
+#define PCAN_BR_DATA_TSEG1 __T("data_tseg1")
+#define PCAN_BR_DATA_TSEG2 __T("data_tseg2")
+#define PCAN_BR_DATA_SJW __T("data_sjw")
+#define PCAN_BR_DATA_SAMPLE __T("data_ssp_offset")
+
+/* ----------- types --------------------------------------------------
+ */
+
+#define TPCANHandle WORD //!< Represents a PCAN hardware channel handle
+#define TPCANStatus DWORD //!< Represents a PCAN status/error code (ATTENTION: changed from 64-bit to 32-bit)
+#define TPCANParameter BYTE //!< Represents a PCAN parameter to be read or set
+#define TPCANDevice BYTE //!< Represents a PCAN device
+#define TPCANMessageType BYTE //!< Represents the type of a PCAN message
+#define TPCANType BYTE //!< Represents the type of PCAN hardware to be initialized
+#define TPCANMode BYTE //!< Represents a PCAN filter mode
+#define TPCANBaudrate WORD //!< Represents a PCAN Baud rate register value
+#define TPCANBitrateFD LPSTR //!< Represents a PCAN-FD bit rate string
+#define TPCANTimestampFD UINT64//!< Represents a timestamp of a received PCAN FD message
+
+/** Represents a PCAN message
+ */
+typedef struct tagTPCANMsg
+{
+ DWORD ID; //!< 11/29-bit message identifier
+ TPCANMessageType MSGTYPE; //!< Type of the message
+ BYTE LEN; //!< Data Length Code of the message (0..8)
+ BYTE DATA[8]; //!< Data of the message (DATA[0]..DATA[7])
+} TPCANMsg;
+
+/** Represents a timestamp of a received PCAN message
+ * Total Microseconds = micros + 1000 * millis + 0x100000000 * 1000 * millis_overflow
+ */
+typedef struct tagTPCANTimestamp
+{
+ DWORD millis; //!< Base-value: milliseconds: 0.. 2^32-1
+ WORD millis_overflow; //!< Roll-arounds of millis
+ WORD micros; //!< Microseconds: 0..999
+} TPCANTimestamp;
+
+/** Represents a PCAN message from a FD capable hardware
+ */
+typedef struct tagTPCANMsgFD
+{
+ DWORD ID; //!< 11/29-bit message identifier
+ TPCANMessageType MSGTYPE; //!< Type of the message
+ BYTE DLC; //!< Data Length Code of the message (0..15)
+ BYTE DATA[64];//!< Data of the message (DATA[0]..DATA[63])
+} TPCANMsgFD;
+
+/** Describes an available PCAN channel
+ */
+typedef struct tagTPCANChannelInformation
+{
+ TPCANHandle channel_handle; //!< PCAN channel handle
+ TPCANDevice device_type; //!< Kind of PCAN device
+ BYTE controller_number; //!< CAN-Controller number
+ DWORD device_features; //!< Device capabilities flag (see FEATURE_*)
+ char device_name[MAX_LENGTH_HARDWARE_NAME]; //!< Device name
+ DWORD device_id; //!< Device number
+ DWORD channel_condition; //!< Availability status of a PCAN-Channel
+}TPCANChannelInformation;
+
+
+/* ----------- variables ----------------------------------------------
+ */
+
+
+/* ----------- prototypes ---------------------------------------------
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#define _DEF_ARG =0
+#else
+#define _DEF_ARG
+#endif
+
+/** @brief Initializes a PCAN Channel.
+ *
+ * @param[in] Channel The handle of a PCAN Channel.
+ * @param[in] Btr0Btr1 The speed for the communication (BTR0BTR1 code).
+ * @param[in] HwType (not used with PCAN USB devices)
+ * @param[in] IOPort (not used with PCAN USB devices)
+ * @param[in] Interrupt (not used with PCAN USB devices)
+ *
+ * @returns A TPCANStatus error code.
+ */
+TPCANStatus CAN_Initialize(
+ TPCANHandle Channel,
+ TPCANBaudrate Btr0Btr1,
+ TPCANType HwType _DEF_ARG,
+ DWORD IOPort _DEF_ARG,
+ WORD Interrupt _DEF_ARG);
+
+/** @brief Initializes a FD capable PCAN Channel.
+ *
+ * @param[in] Channel The handle of a FD capable PCAN Channel.
+ * @param[in] BitrateFD The speed for the communication (FD bit rate string).
+ *
+ * @remarks See PCAN_BR_* values
+ *
+ * Parameter and values must be separated by '='.
+ * Couples of Parameter/value must be separated by ','.
+ * Following Parameter must be filled out: f_clock, nom_brp, nom_sjw, nom_tseg1, nom_tseg2,
+ * data_brp, data_sjw, data_tseg1, data_tseg2.
+ * Following Parameters are optional (not used yet): data_ssp_offset, nom_sam.
+ *
+ * @remarks Example:
+ * @verbatim
+ * f_clock=80000000,nom_brp=10,nom_tseg1=5,nom_tseg2=2,nom_sjw=1,data_brp=4,data_tseg1=7,data_tseg2=2,data_sjw=1
+ * @endverbatim
+ * @returns A TPCANStatus error code.
+ */
+TPCANStatus CAN_InitializeFD(
+ TPCANHandle Channel,
+ TPCANBitrateFD BitrateFD);
+
+/** @brief Uninitializes one or all PCAN Channels initialized by CAN_Initialize
+ *
+ * @remarks Giving the TPCANHandle value "PCAN_NONEBUS", uninitializes all initialized channels.
+ *
+ * @param[in] Channel The handle of a PCAN Channel.
+ *
+ * @returns A TPCANStatus error code.
+ */
+TPCANStatus CAN_Uninitialize(
+ TPCANHandle Channel);
+
+/** @brief Resets the receive and transmit queues of the PCAN Channel.
+ *
+ * @remarks A reset of the CAN controller is not performed.
+ *
+ * @param[in] Channel The handle of a PCAN Channel.
+ *
+ * @returns A TPCANStatus error code.
+ */
+TPCANStatus CAN_Reset(
+ TPCANHandle Channel);
+
+/** @brief Gets the current status of a PCAN Channel.
+ *
+ * @param[in] Channel The handle of a PCAN Channel.
+ *
+ * @returns A TPCANStatus error code.
+ */
+TPCANStatus CAN_GetStatus(
+ TPCANHandle Channel);
+
+/** @brief Reads a CAN message from the receive queue of a PCAN Channel.
+ *
+ * @param[in] Channel The handle of a PCAN Channel.
+ * @param[out] MessageBuffer A TPCANMsg structure buffer to store the CAN message.
+ * @param[out] TimestampBuffer A TPCANTimestamp structure buffer to get the reception time of the message.
+ * If this value is not desired, this parameter should be passed as NULL.
+ *
+ * @returns A TPCANStatus error code.
+ */
+TPCANStatus CAN_Read(
+ TPCANHandle Channel,
+ TPCANMsg* MessageBuffer,
+ TPCANTimestamp* TimestampBuffer);
+
+/** @brief Reads a CAN message from the receive queue of a FD capable PCAN Channel.
+ *
+ * @param[in] Channel The handle of a FD capable PCAN Channel.
+ * @param[out] MessageBuffer A TPCANMsgFD structure buffer to store the CAN message.
+ * @param[out] TimestampBuffer A TPCANTimestampFD buffer to get the reception time of the message.
+ * If this value is not desired, this parameter should be passed as NULL.
+ *
+ * @returns A TPCANStatus error code.
+ */
+TPCANStatus CAN_ReadFD(
+ TPCANHandle Channel,
+ TPCANMsgFD* MessageBuffer,
+ TPCANTimestampFD* TimestampBuffer);
+
+/** @brief Transmits a CAN message.
+ *
+ * @param[in] Channel The handle of a PCAN Channel.
+ * @param[in] MessageBuffer A TPCANMsg buffer with the message to be sent.
+ *
+ * @returns A TPCANStatus error code.
+ */
+TPCANStatus CAN_Write(
+ TPCANHandle Channel,
+ TPCANMsg* MessageBuffer);
+
+/** @brief Transmits a CAN message over a FD capable PCAN Channel.
+ *
+ * @param[in] Channel The handle of a FD capable PCAN Channel.
+ * @param[in] MessageBuffer A TPCANMsgFD buffer with the message to be sent.
+ *
+ * @returns A TPCANStatus error code.
+ */
+TPCANStatus CAN_WriteFD(
+ TPCANHandle Channel,
+ TPCANMsgFD* MessageBuffer);
+
+/** @brief Configures the reception filter.
+ *
+ * @remarks The message filter will be expanded with every call to this function.
+ * If it is desired to reset the filter, please use the CAN_SetValue function.
+ *
+ * @param[in] Channel The handle of a PCAN Channel.
+ * @param[in] FromID The lowest CAN ID to be received.
+ * @param[in] ToID The highest CAN ID to be received.
+ * @param[in] Mode Message type, Standard (11-bit identifier) or Extended (29-bit identifier).
+ *
+ * @returns A TPCANStatus error code.
+ */
+TPCANStatus CAN_FilterMessages(
+ TPCANHandle Channel,
+ DWORD FromID,
+ DWORD ToID,
+ TPCANMode Mode);
+
+/** @brief Retrieves a PCAN Channel value.
+ *
+ * @remarks Parameters can be present or not according with the kind of Hardware (PCAN Channel) being used.
+ * If a parameter is not available, a PCAN_ERROR_ILLPARAMTYPE error will be returned.
+ *
+ * @param[in] Channel The handle of a PCAN Channel.
+ * @param[in] Parameter The TPCANParameter parameter to get.
+ * @param[out] Buffer Buffer for the parameter value.
+ * @param[in] BufferLength Size in bytes of the buffer.
+ *
+ * @returns A TPCANStatus error code.
+ */
+TPCANStatus CAN_GetValue(
+ TPCANHandle Channel,
+ TPCANParameter Parameter,
+ void* Buffer,
+ DWORD BufferLength);
+
+
+/** @brief Configures or sets a PCAN Channel value.
+ *
+ * @remarks Parameters can be present or not according with the kind of Hardware (PCAN Channel) being used.
+ * If a parameter is not available, a PCAN_ERROR_ILLPARAMTYPE error will be returned.
+ *
+ * @param[in] Channel The handle of a PCAN Channel.
+ * @param[in] Parameter The TPCANParameter parameter to set.
+ * @param[in] Buffer Buffer with the value to be set.
+ * @param[in] BufferLength Size in bytes of the buffer.
+ *
+ * @returns A TPCANStatus error code.
+ */
+TPCANStatus CAN_SetValue(
+ TPCANHandle Channel,
+ TPCANParameter Parameter,
+ void* Buffer,
+ DWORD BufferLength);
+
+/** @brief Returns a descriptive text of a given TPCANStatus error code, in any desired language.
+ *
+ * @remarks The current languages available for translation are:
+ * Neutral (0x00), German (0x07), English (0x09), Spanish (0x0A), Italian (0x10) and French (0x0C).
+ *
+ * @param[in] Error A TPCANStatus error code.
+ * @param[in] Language Indicates a 'Primary language ID'.
+ * @param[out] Buffer Buffer for a null terminated char array.
+ *
+ * @returns A TPCANStatus error code.
+ */
+TPCANStatus CAN_GetErrorText(
+ TPCANStatus Error,
+ WORD Language,
+ LPSTR Buffer);
+
+/** @brief Finds a PCAN-Basic channel that matches with the given parameters
+ *
+ * @param[in] Parameters A comma separated string contained pairs of parameter-name/value
+ * to be matched within a PCAN-Basic channel
+ * @param[out] FoundChannel Buffer for returning the PCAN-Basic channel, when found
+ *
+ * @returns A TPCANStatus error code.
+ */
+TPCANStatus CAN_LookUpChannel(
+ LPSTR Parameters,
+ TPCANHandle* FoundChannel);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* PCAN_API_H_INCLUDED */
+
+/* ----------------------------------------------------------------------
+ * Uwe Vogt, UV Software, Chausseestrasse 33 A, 10115 Berlin, Germany
+ * Tel.: +49-30-46799872, Fax: +49-30-46799873, Mobile: +49-170-3801903
+ * E-Mail: uwe.vogt@uv-software.de, Homepage: http://www.uv-software.de/
+ */
diff --git a/Utilities/build_no.sh b/Utilities/build_no.sh
new file mode 100755
index 0000000..facccfc
--- /dev/null
+++ b/Utilities/build_no.sh
@@ -0,0 +1,32 @@
+echo "/* -- Do not commit this file --" > ./build_no.h
+echo " *" >> ./build_no.h
+echo " * project : CAN - Controller Area Network" >> ./build_no.h
+echo " *" >> ./build_no.h
+echo " * purpose : CAN Tester (based on macOS Library for PCAN-USB Interfaces)" >> ./build_no.h
+echo " *" >> ./build_no.h
+echo " * copyright : (C) 2019,2023 UV Software, Berlin" >> ./build_no.h
+echo " *" >> ./build_no.h
+echo " * author(s) : Uwe Vogt, UV Software" >> ./build_no.h
+echo " *" >> ./build_no.h
+echo " * e-mail : info@mac-can.com" >> ./build_no.h
+echo " *" >> ./build_no.h
+echo " */" >> ./build_no.h
+echo "#ifndef BUILD_NO_H_INCLUDED" >> ./build_no.h
+echo "#define BUILD_NO_H_INCLUDED" >> ./build_no.h
+git log -1 --pretty=format:%h > /dev/null 2> /dev/null
+if [ $? -eq 0 ]
+then
+ echo "#define BUILD_NO 0x"$(git log -1 --pretty=format:%h) >> ./build_no.h
+else
+ echo "#define BUILD_NO 0xDEADC0DE" >> ./build_no.h
+fi
+echo "#define STRINGIFY(X) #X" >> ./build_no.h
+echo "#define TOSTRING(X) STRINGIFY(X)" >> ./build_no.h
+echo "#define SVN_REV_INT (BUILD_NO)" >> ./build_no.h
+echo "#define SVN_REV_STR TOSTRING(BUILD_NO)" >> ./build_no.h
+echo "#endif" >> ./build_no.h
+echo "/* ----------------------------------------------------------------------" >> ./build_no.h
+echo " * Uwe Vogt, UV Software, Chausseestrasse 33 A, 10115 Berlin, Germany" >> ./build_no.h
+echo " * Tel.: +49-30-46799872, Fax: +49-30-46799873, Mobile: +49-170-3801903" >> ./build_no.h
+echo " * E-Mail: uwe.vogt@uv-software.de, Homepage: http://www.uv-software.de/" >> ./build_no.h
+echo " */" >> ./build_no.h
diff --git a/Utilities/can_moni/.gitignore b/Utilities/can_moni/.gitignore
new file mode 100644
index 0000000..b985485
--- /dev/null
+++ b/Utilities/can_moni/.gitignore
@@ -0,0 +1,11 @@
+# ignore all the old crap from svn
+.project
+.cproject
+build.sh
+build_no.h
+build_no.sh
+deploy.sh
+install.sh
+LICENSE
+COPYRIGHT
+IMPORTANT
diff --git a/Utilities/can_moni/COPYING b/Utilities/can_moni/COPYING
new file mode 100644
index 0000000..9efa6fb
--- /dev/null
+++ b/Utilities/can_moni/COPYING
@@ -0,0 +1,338 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+
+ 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.
+
+
+ Copyright (C)
+
+ 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, see .
+
+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.
+
+ , 1 April 1989
+ Moe Ghoul, 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.
diff --git a/Utilities/can_moni/Makefile b/Utilities/can_moni/Makefile
new file mode 100644
index 0000000..95e6068
--- /dev/null
+++ b/Utilities/can_moni/Makefile
@@ -0,0 +1,190 @@
+#
+# CAN Monitor for PEAK-System PCAN USB Interfaces (macOS, x86_64 & arm64)
+#
+# Copyright (c) 2007 by Uwe Vogt, UV Software, Friedrichshafen
+# Copyright (c) 2012-2024 Uwe Vogt, UV Software, Berlin (info@uv-software.com)
+#
+# 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 3 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, see .
+#
+current_OS := $(shell sh -c 'uname 2>/dev/null || echo Unknown OS')
+current_OS := $(patsubst CYGWIN%,Cygwin,$(current_OS))
+current_OS := $(patsubst MINGW%,MinGW,$(current_OS))
+current_OS := $(patsubst MSYS%,MinGW,$(current_OS))
+
+TARGET = can_moni
+
+INSTALL = ~/bin
+
+PROJ_DIR = ../..
+HOME_DIR = ..
+MAIN_DIR = .
+
+MISC_DIR = $(HOME_DIR)/misc
+DRIVER_DIR = $(HOME_DIR)/driver
+
+OBJECTS = $(OUTDIR)/main.o $(OUTDIR)/bitrates.o $(OUTDIR)/timer.o $(OUTDIR)/printmsg.o
+
+DEFINES =
+
+HEADERS = -I$(MAIN_DIR) \
+ -I$(HOME_DIR) \
+ -I$(MISC_DIR)
+
+ifneq ($(VARIANT),STANDALONE)
+ DEFINES += -DOPTION_PCBUSB_STANDALONE=0
+
+ HEADERS +=
+
+ OBJECTS += $(OUTDIR)/PCBUSB.o
+
+ BIN_DIR = $(HOME_DIR)/Binaries
+else
+ DEFINES += -DOPTION_PCBUSB_STANDALONE=1
+
+ HEADERS += -I$(DRIVER_DIR)
+
+ OBJECTS += $(OUTDIR)/pcan_api.o \
+ $(OUTDIR)/pcan_drv.o \
+ $(OUTDIR)/pcan_que.o \
+ $(OUTDIR)/pcan_flt.o \
+ $(OUTDIR)/pcan_trc.o \
+ $(OUTDIR)/pcan_btr.o \
+ $(OUTDIR)/pcan_log.o \
+ $(OUTDIR)/pcan_usb.o \
+ $(OUTDIR)/pcan_usbfd.o
+
+ BIN_DIR = $(HOME_DIR)/../Binaries/$(TARGET)
+endif
+
+CFLAGS += -O2 -Wall -Wextra -Wno-parentheses \
+ -fno-strict-aliasing \
+ $(DEFINES) \
+ $(HEADERS)
+
+CXXFLAGS += -O2 -g -Wall -Wextra -pthread \
+ $(DEFINES) \
+ $(HEADERS)
+
+LDFLAGS += -rpath /usr/local/lib
+
+LIBRARIES = -lpthread
+
+ifeq ($(VARIANT),STANDALONE)
+ LDFLAGS += -Wl,-framework -Wl,IOKit -Wl,-framework -Wl,CoreFoundation
+endif
+
+ifeq ($(BINARY),UNIVERSAL)
+CFLAGS += -arch arm64 -arch x86_64
+CXXFLAGS += -arch arm64 -arch x86_64
+LDFLAGS += -arch arm64 -arch x86_64
+endif
+
+CHECKER = warning,information
+IGNORE = -i tester.c -i dosopt.c
+
+CXX = clang++
+CC = clang
+LD = clang
+
+RM = rm -f
+CP = cp -f
+
+OUTDIR = .objects
+BINDIR = $(BIN_DIR)
+
+.PHONY: info outdir bindir
+
+
+all: info outdir bindir $(TARGET)
+
+info:
+ @echo $(CC)" on "$(current_OS)
+ @echo "target: "$(TARGET)
+ @echo "install: "$(INSTALL)
+
+outdir:
+ @mkdir -p $(OUTDIR)
+
+bindir:
+ @mkdir -p $(BINDIR)
+
+incdir:
+ @mkdir -p $(INCDIR)
+
+check:
+ cppcheck --enable=$(CHECKER) --suppressions-list=$(HOME_DIR)/suppress.txt \
+ -D__APPLE__ $(DEFINES) $(HEADERS) $(IGNORE) $(MAIN_DIR) $(MISC_DIR)
+
+clean:
+ @-$(RM) $(TARGET) $(OUTDIR)/*.o $(OUTDIR)/*.d
+
+pristine:
+ @-$(RM) $(TARGET) $(OUTDIR)/*.o $(OUTDIR)/*.d
+ @-$(RM) $(BINDIR)/$(TARGET)
+
+install:
+ @echo "Copying binary file..."
+ @-$(CP) $(TARGET) $(INSTALL)
+
+
+$(OUTDIR)/main.o: $(MAIN_DIR)/main.c
+ $(CC) $(CFLAGS) -MMD -MF $*.d -o $@ -c $<
+
+$(OUTDIR)/PCBUSB.o: $(HOME_DIR)/PCBUSB.c
+ $(CC) $(CFLAGS) -MMD -MF $*.d -o $@ -c $<
+
+$(OUTDIR)/bitrates.o: $(MISC_DIR)/bitrates.c
+ $(CC) $(CFLAGS) -MMD -MF $*.d -o $@ -c $<
+
+$(OUTDIR)/timer.o: $(MISC_DIR)/timer.c
+ $(CC) $(CFLAGS) -MMD -MF $*.d -o $@ -c $<
+
+$(OUTDIR)/printmsg.o: $(MISC_DIR)/printmsg.c
+ $(CC) $(CFLAGS) -MMD -MF $*.d -o $@ -c $<
+
+$(OUTDIR)/pcan_api.o: $(DRIVER_DIR)/pcan_api.c
+ $(CC) $(CFLAGS) -MMD -MF $*.d -o $@ -c $<
+
+$(OUTDIR)/pcan_drv.o: $(DRIVER_DIR)/pcan_drv.c
+ $(CC) $(CFLAGS) -MMD -MF $*.d -o $@ -c $<
+
+$(OUTDIR)/pcan_usb.o: $(DRIVER_DIR)/pcan_usb.c
+ $(CC) $(CFLAGS) -MMD -MF $*.d -o $@ -c $<
+
+$(OUTDIR)/pcan_usbfd.o: $(DRIVER_DIR)/pcan_usbfd.c
+ $(CC) $(CFLAGS) -MMD -MF $*.d -o $@ -c $<
+
+$(OUTDIR)/pcan_btr.o: $(DRIVER_DIR)/pcan_btr.c
+ $(CC) $(CFLAGS) -MMD -MF $*.d -o $@ -c $<
+
+$(OUTDIR)/pcan_flt.o: $(DRIVER_DIR)/pcan_flt.c
+ $(CC) $(CFLAGS) -MMD -MF $*.d -o $@ -c $<
+
+$(OUTDIR)/pcan_que.o: $(DRIVER_DIR)/pcan_que.c
+ $(CC) $(CFLAGS) -MMD -MF $*.d -o $@ -c $<
+
+$(OUTDIR)/pcan_trc.o: $(DRIVER_DIR)/pcan_trc.c
+ $(CC) $(CFLAGS) -MMD -MF $*.d -o $@ -c $<
+
+$(OUTDIR)/pcan_log.o: $(DRIVER_DIR)/pcan_log.c
+ $(CC) $(CFLAGS) -MMD -MF $*.d -o $@ -c $<
+
+
+$(TARGET): $(OBJECTS)
+ $(LD) $(LDFLAGS) -o $@ $(OBJECTS) $(LIBRARIES)
+ $(CP) $(TARGET) $(BINDIR)
+ifeq ($(current_OS),Darwin)
+ @lipo -archs $@
+endif
+ @echo "\033[1mTarget '"$@"' successfully build\033[0m"
diff --git a/Utilities/can_moni/README b/Utilities/can_moni/README
new file mode 100644
index 0000000..de796d7
--- /dev/null
+++ b/Utilities/can_moni/README
@@ -0,0 +1,122 @@
+CAN Monitor for PEAK-System PCAN USB Interfaces (macOS, x86_64 & arm64)
+
+Copyright (c) 2007,2012-2024 by Uwe Vogt, UV Software, Berlin.
+
+Usage: can_moni [...]
+Options:
+ -t, --time=(ZERO|ABS|REL) absolute or relative time (default=0)
+ -i --id=(HEX|DEC|OCT) display mode of CAN-IDs (default=HEX)
+ -d, --data=(HEX|DEC|OCT) display mode of data bytes (default=HEX)
+ -a, --ascii=(ON|OFF) display data bytes in ASCII (default=ON)
+ -x, --exclude=[~] exclude CAN-IDs: [-]{,[-]}
+ --code= acceptance code for 11-bit IDs (default=0x000)
+ --mask= acceptance mask for 11-bit IDs (default=0x7FF)
+ --xtd-code= acceptance code for 29-bit IDs (default=0x00000000)
+ --xtd-mask= acceptance mask for 29-bit IDs (default=0x1FFFFFFF)
+ -m, --mode=(2.0|FDF[+BRS]) CAN operation mode: CAN 2.0 or CAN FD format
+ --listen-only monitor mode (transmitter is off)
+ --no-status-frames suppress reception of status frames
+ --no-remote-frames suppress reception of remote frames
+ -b, --baudrate= CAN 2.0 bit timing in kbps (default=250)
+ --bitrate= CAN FD bit rate (as a string)
+ -v, --verbose show detailed bit rate settings
+ -y, --trace=(ON|OFF) write a trace file (default=OFF)
+ -L, --list-boards list all supported CAN interfaces and exit
+ -T, --test-boards list all available CAN interfaces and exit
+ -h, --help display this help screen and exit
+ --version show version information and exit
+Interfaces:
+ PCAN-USB1
+ PCAN-USB2
+ PCAN-USB3
+ PCAN-USB4
+ PCAN-USB5
+ PCAN-USB6
+ PCAN-USB7
+ PCAN-USB8
+CAN 2.0 baud rate index (default=3):
+ 0 = 1000 kbps
+ 1 = 800 kbps
+ 2 = 500 kbps
+ 3 = 250 kbps
+ 4 = 125 kbps
+ 5 = 100 kbps
+ 6 = 50 kbps
+ 7 = 20 kbps
+ 8 = 10 kbps
+CAN FD bit rate as comma-separeted =-list:
+ f_clock= frequency in Hz or
+ f_clock_mhz= frequency in MHz
+ nom_brp= bit-rate prescaler (nominal)
+ nom_tseg1= time segment 1 (nominal)
+ nom_tseg2= time segment 2 (nominal)
+ nom_sjw= sync. jump width (nominal)
+ nom_sam= sampling (only SJA1000)
+ data_brp= bit-rate prescaler (FD data)
+ data_tseg1= time segment 1 (FD data)
+ data_tseg2= time segment 2 (FD data)
+ data_sjw= sync. jump width (FD data)
+Examples:
+ 125kbps:1000kbps f_clock_mhz=80,nom_brp=2,nom_tseg1=255,nom_tseg2=64,nom_sjw=64,data_brp=2,data_tseg1=31,data_tseg2=8,data_sjw=8
+ 250kbps:2000kbps f_clock_mhz=80,nom_brp=2,nom_tseg1=127,nom_tseg2=32,nom_sjw=32,data_brp=2,data_tseg1=15,data_tseg2=4,data_sjw=4
+ 500kbps:4000kbps f_clock_mhz=80,nom_brp=2,nom_tseg1=63,nom_tseg2=16,nom_sjw=16,data_brp=2,data_tseg1=7,data_tseg2=2,data_sjw=2
+ 1000kbps:8000kbps f_clock_mhz=80,nom_brp=2,nom_tseg1=31,nom_tseg2=8,nom_sjw=8,data_brp=2,data_tseg1=3,data_tseg2=1,data_sjw=1
+ 2000kbps:10000kbps f_clock_mhz=80,nom_brp=1,nom_tseg1=31,nom_tseg2=8,nom_sjw=1,data_brp=2,data_tseg1=2,data_tseg2=1,data_sjw=1
+Hazard note:
+ If you connect your CAN device to a real CAN network when using this program,
+ you might damage your application.
+License type:
+ This software is freeware without any warranty or support!
+Change log:
+- Version 0.6 of July 29, 2024:
+ Realized new program options:
+ - '--no-status-frames' suppress reception of status frames (default=ON)
+ - '--no-remote-frames' suppress reception of remote frames (default=ON)
+ - '--code=' acceptance code for 11-bit IDs (default=0x000)
+ - '--mask=' acceptance mask for 11-bit IDs (default=0x7FF)
+ - '--xtd-code=' acceptance code for 29-bit IDs (default=0x00000000)
+ - '--xtd-mask=' acceptance mask for 29-bit IDs (default=0x1FFFFFFF)
+ - '--trace=(ON|OFF)' write a trace file (default=OFF)
+ Compiled against PCBUSB v0.13 sources as Universal macOS Binary
+- Version 0.5 SR8 of November 3, 2023:
+ Fixed a bug with new PCAN-USB FD product version (hardware 6.0)
+ Compiled against PCBUSB v0.12.2 sources as Universal macOS Binary
+- Version 0.5 SR7 of July 15, 2023:
+ Fixed some bugs with bit-rate string conversion (SAM issue among others)
+ Compiled against PCBUSB v0.12.1 sources as Universal macOS Binary
+- Version 0.5 SR6 of February 2, 2023:
+ Display device id. when listing available CAN interfaces (option -T)
+ Fixed a bug with default CAN FD bit-rate settings (250kbps:2000kbps)
+ Compiled against PCBUSB v0.12 sources as Universal macOS Binary
+- Version 0.5 SR5 of July 31, 2022:
+ Fixed the CAN FD URB issue ('Messages lost on high CAN FD bit-rates')
+ Compiled against PCBUSB v0.11.2 sources as Universal macOS Binary
+- Version 0.5 SR4 of February 5, 2022:
+ Fixed a bug with channel state 'occupied' when used by another process
+ Compiled against PCBUSB v0.11 sources as Universal macOS Binary
+- Version 0.5 SR3 of December 7, 2021:
+ Compiled against PCBUSB v0.10.1 sources as Universal macOS Binary
+- Version 0.5 SR2 of December 22, 2020:
+ Compiled against PCBUSB v0.9 sources (PCAN-USB Pro FD CAN1).
+- Version 0.5 SR1 of June 28, 2020:
+ Compiled against PCBUSB v0.9 sources ()
+- Version 0.5 of December 1, 2019:
+ Reworked command-line option handling:
+ --listen-only - monitor mode (transmitter is off)
+ --list-boards - list all supported CAN interfaces
+ --test boards - list all available CAN interfaces
+ Compiled against PCBUSB v0.8.1 sources.
+- Version 0.4 of September 22, 2017:
+ Support of PCAN-USB FD interfaces.
+- Version 0.3 of November 23, 2014:
+ Time-stamps are taken from CAN controller.
+- Version 0.2 of May 17, 2013:
+ Initial revision
+- Version 0.1 of July 6, 2012:
+ (reverted)
+Known bugs and caveats:
+- See documentation of PCBUSB library for known bugs and caveats
+ in the underlying library.
+Contact:
+ E-Mail: mailto:info@mac-can.com
+ Internet: https://www.mac-can.com
diff --git a/Utilities/can_moni/main.c b/Utilities/can_moni/main.c
new file mode 100644
index 0000000..5e8c192
--- /dev/null
+++ b/Utilities/can_moni/main.c
@@ -0,0 +1,1072 @@
+/* -- $HeadURL: https://uv-software.net/MacCAN/PCANUSB/Utilities/can_moni/trunk/main.c $ --
+ *
+ * project : CAN - Controller Area Network
+ *
+ * purpose : CAN Monitor goes macOS aka OS X
+ *
+ * copyright : (c) 2007,2012 by UV Software, Friedrichshafen
+ * (c) 2013-2024 by UV Software, Berlin
+ *
+ * revision : $Rev: 2061 $ of $Date: 2024-12-29 18:36:36 +0100 (So, 29 Dez 2024) $
+ *
+ * author(s) : Uwe Vogt, UV Software
+ *
+ * e-mail : uwe.vogt@uv-software.de
+ *
+ *
+ * ----------- description --------------------------------------------
+ *
+ * CAN Monitor (based on macOS Library for PCAN USB Interfaces)
+ *
+ * (1) Standalone version with compiled PCBUSB sources
+ *
+ * This program is freeware without any warranty or support!
+ * Please note the copyright and license agreements.
+ *
+ * (2) Open-source version with libPCBUSB support
+ *
+ * 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 3 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, see .
+ *
+ * Note: The libPCBUSB is licensed under a freeware license without any
+ * warranty or support. The libPCBUSB is not part of this program.
+ * It can be downloaded from .
+ *
+ */
+/* ----------- version ------------------------------------------------
+ */
+#include "build_no.h"
+#if (OPTION_PCBUSB_STANDALONE != 0)
+#define VERSION_MAJOR 0
+#define VERSION_MINOR 6
+#define VERSION_PATCH 1
+#else
+#define VERSION_MAJOR 1
+#define VERSION_MINOR 0
+#define VERSION_PATCH 0
+#endif
+#define VERSION_BUILD BUILD_NO
+#define VERSION_STRING TOSTRING(VERSION_MAJOR)"." TOSTRING(VERSION_MINOR) "." TOSTRING(VERSION_PATCH) " (" TOSTRING(BUILD_NO) ")"
+#if defined(__APPLE__)
+#define PLATFORM "macOS"
+#else
+#error Unsupported platform
+#endif
+static const char APPLICATION[] = "CAN Monitor for PEAK-System PCAN USB Interfaces, Version "VERSION_STRING;
+static const char COPYRIGHT[] = "Copyright (c) 2007,2012-2024 by Uwe Vogt, UV Software, Berlin";
+#if (OPTION_PCBUSB_STANDALONE != 0)
+static const char WARRANTY[] = "This program is freeware without any warranty or support!";
+static const char LICENSE[] = "This program is freeware without any warranty or support!\n\n" \
+ "Note: This program does not require the libPCBUSB to be installed.";
+#else
+static const char WARRANTY[] = "CAN Monitor comes with ABSOLUTELY NO WARRANTY; for details type `--version'.\n\n" \
+ "This is free software, and you are welcome to redistribute it\n" \
+ "under certain conditions; type `--version' for details.";
+static const char LICENSE[] = "This program is free software; you can redistribute it and/or modify\n" \
+ "it under the terms of the GNU General Public License as published by\n" \
+ "the Free Software Foundation; either version 2 of the License, or\n" \
+ "(at your option) any later version.\n\n" \
+ "This program is distributed in the hope that it will be useful,\n" \
+ "but WITHOUT ANY WARRANTY; without even the implied warranty of\n" \
+ "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" \
+ "GNU General Public License for more details.\n\n" \
+ "You should have received a copy of the GNU General Public License along\n" \
+ "with this program; if not, see .\n\n" \
+ "Note: The libPCBUSB is licensed under a freeware license without any\n" \
+ "warranty or support. The libPCBUSB is not part of this program.\n" \
+ "It can be downloaded from .";
+#endif
+
+/* ----------- includes -----------------------------------------------
+ */
+#if (OPTION_PCBUSB_STANDALONE != 0)
+#include "pcan_api.h"
+#else
+#include
+#endif
+#include "bitrates.h"
+#include "printmsg.h"
+#include "timer.h"
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+
+#include
+
+
+/* ----------- options ---------------------------------------------------
+ */
+#define BLOCKING_READ
+
+
+/* ----------- defines ---------------------------------------------------
+ */
+#define MAX_ID 2048
+
+#define TIME_ZERO 0
+#define TIME_ABS 1
+#define TIME_REL 2
+
+#define MODE_HEX 0
+#define MODE_DEC 1
+#define MODE_OCT 2
+
+#define ASCII_OFF 0
+#define ASCII_ON 1
+#ifndef BLOCKING_READ
+#define RxTIMEOUT 0 /* return immediately */
+#else
+#define RxTIMEOUT 65535 /* blocking read */
+#endif
+#define CODE_11BIT 0x000
+#define MASK_11BIT 0x7FF
+#define CODE_29BIT 0x00000000
+#define MASK_29BIT 0x1FFFFFFF
+
+
+/* ----------- types -----------------------------------------------------
+ */
+
+
+/* ----------- prototypes ------------------------------------------------
+ */
+static void sigterm(int signo);
+static void usage(FILE *stream, const char *program);
+static void version(FILE *stream, const char *program);
+
+static int list_interfaces(void);
+static int test_interfaces(void);
+
+static uint64_t receive(TPCANHandle channel, int mode_time, int mode_id, int mode_data, int mode_ascii);
+static uint64_t receive_fd(TPCANHandle channel, int mode_time, int mode_id, int mode_data, int mode_ascii);
+
+static int get_exclusion(const char *arg);
+
+
+/* ----------- variables ----------------------------------------------
+ */
+static int can_id[MAX_ID];
+static int can_id_xtd = 1;
+static const unsigned char dlc_table[16] = {
+ 0,1,2,3,4,5,6,7,8,12,16,20,24,32,48,64
+};
+static volatile int running = 1;
+
+/* - - - - - - from CAN API Defs - - - - - - - - - - - - - - - - - - - -
+ */
+#define PCAN_BOARDS (8)
+static struct _can_board_t
+{
+ unsigned long type; /**< board type */
+ char* name; /**< board name */
+} can_board[PCAN_BOARDS] = {
+ {PCAN_USBBUS1, "PCAN-USB1"},
+ {PCAN_USBBUS2, "PCAN-USB2"},
+ {PCAN_USBBUS3, "PCAN-USB3"},
+ {PCAN_USBBUS4, "PCAN-USB4"},
+ {PCAN_USBBUS5, "PCAN-USB5"},
+ {PCAN_USBBUS6, "PCAN-USB6"},
+ {PCAN_USBBUS7, "PCAN-USB7"},
+ {PCAN_USBBUS8, "PCAN-USB8"},
+};
+
+/* ----------- main ---------------------------------------------------
+ */
+int main(int argc, char *argv[])
+{
+ TPCANHandle channel = PCAN_USBBUS1;
+ TPCANStatus status;
+ SInt64 intarg;
+ int opt, i;
+ long board = -1; int b;
+ BYTE op_mode = PCAN_MESSAGE_STANDARD; int op = 0;
+ BYTE listenonly = PCAN_PARAMETER_OFF; int lo = 0;
+ BYTE allow_sts = PCAN_PARAMETER_ON; int sf = 0;
+ BYTE allow_rtr = PCAN_PARAMETER_ON; int rf = 0;
+ DWORD std_code = CODE_11BIT; int sc = 0;
+ DWORD std_mask = MASK_11BIT; int sm = 0;
+ DWORD xtd_code = CODE_29BIT; int xc = 0;
+ DWORD xtd_mask = MASK_29BIT; int xm = 0;
+ BYTE trace = PCAN_PARAMETER_OFF; int ts = 0;
+ long baudrate = PCAN_BAUD_250K; int bd = 0;
+ int mode_time = TIME_ZERO; int mt = 0;
+ int mode_id = MODE_HEX; int mi = 0;
+ int mode_data = MODE_HEX; int md = 0;
+ int mode_ascii = ASCII_ON; int ma = 0;
+ int exclude = 0;
+ int show_version = 0;
+ int verbose = 0;
+ int num_boards = 0;
+ BYTE buffer[256]; /* char *device, *firmware, *software, *library; */
+ DWORD device_id = 8472;
+ UINT64 filter = 0U;
+ /* Default Bit-rate */
+ TPCANBitrateFD bitrate = "f_clock_mhz=80,nom_brp=2,nom_tseg1=127,nom_tseg2=32,nom_sjw=32,data_brp=2,data_tseg1=15,data_tseg2=4,data_sjw=4";
+ long unsigned freq = 0; struct btr_bit_timing slow, fast;
+
+ struct option long_options[] = {
+ {"baudrate", required_argument, 0, 'b'},
+ {"bitrate", required_argument, 0, 'B'},
+ {"verbose", no_argument, 0, 'v'},
+ {"mode", required_argument, 0, 'm'},
+ {"shared", no_argument, 0, 'S'},
+ {"listen-only", no_argument, 0, 'M'},
+ {"no-status-frames", no_argument, 0, 'S'},
+ {"no-remote-frames", no_argument, 0, 'R'},
+ {"code", required_argument, 0, '1'},
+ {"mask", required_argument, 0, '2'},
+ {"xtd-code", required_argument, 0, '3'},
+ {"xtd-mask", required_argument, 0, '4'},
+ {"time", required_argument, 0, 't'},
+ {"id", required_argument, 0, 'i'},
+ {"data", required_argument, 0, 'd'},
+ {"ascii", required_argument, 0, 'a'},
+ {"exclude", required_argument, 0, 'x'},
+ {"trace", required_argument, 0, 'y'},
+ {"list-boards", no_argument, 0, 'L'},
+ {"test-boards", no_argument, 0, 'T'},
+ {"help", no_argument, 0, 'h'},
+ {"version", no_argument, &show_version, 1},
+ {0, 0, 0, 0}
+ };
+
+ /* exclude list (11-bit IDs only) */
+ for (i = 0; i < MAX_ID; i++) {
+ can_id[i] = 1;
+ }
+ /* signal handler */
+ if ((signal(SIGINT, sigterm) == SIG_ERR) ||
+#if !defined(_WIN32) && !defined(_WIN64)
+ (signal(SIGHUP, sigterm) == SIG_ERR) ||
+#endif
+ (signal(SIGTERM, sigterm) == SIG_ERR)) {
+ perror("+++ error");
+ return errno;
+ }
+ /* scan command-line */
+ while ((opt = getopt_long(argc, (char * const *)argv, "b:vm:t:i:d:a:x:s:y:LTh", long_options, &i)) != -1) {
+ switch (opt) {
+ /* option '--baudrate=' (-b) */
+ case 'b':
+ if (bd++) {
+ fprintf(stderr, "%s: duplicated option `--baudrate' (%c)\n", basename(argv[0]), opt);
+ return 1;
+ }
+ if (sscanf(optarg, "%li", &baudrate) != 1) {
+ fprintf(stderr, "%s: illegal argument for option `--baudrate' (%c)\n", basename(argv[0]), opt);
+ return 1;
+ }
+ switch (baudrate) {
+ case 0: case 1000: case 1000000: baudrate = PCAN_BAUD_1M; break;
+ case 1: case 800: case 800000: baudrate = PCAN_BAUD_800K; break;
+ case 2: case 500: case 500000: baudrate = PCAN_BAUD_500K; break;
+ case 3: case 250: case 250000: baudrate = PCAN_BAUD_250K; break;
+ case 4: case 125: case 125000: baudrate = PCAN_BAUD_125K; break;
+ case 5: case 100: case 100000: baudrate = PCAN_BAUD_100K; break;
+ case 6: case 50: case 50000: baudrate = PCAN_BAUD_50K; break;
+ case 7: case 20: case 20000: baudrate = PCAN_BAUD_20K; break;
+ case 8: case 10: case 10000: baudrate = PCAN_BAUD_10K; break;
+ default:
+ fprintf(stderr, "%s: illegal argument for option `--baudrate' (%c)\n", basename(argv[0]), opt);
+ return 1;
+ }
+ bitrate = NULL;
+ break;
+ /* option '--bitrate=' as string */
+ case 'B':
+ if (bd++) {
+ fprintf(stderr, "%s: duplicated option `--bitrate'\n", basename(argv[0]));
+ return 1;
+ }
+ if (!btr_string_to_bit_timing(optarg, &freq, &slow, &fast)) {
+ fprintf(stderr, "%s: illegal argument for option `--bitrate'\n", basename(argv[0]));
+ return 1;
+ }
+ bitrate = optarg;
+ baudrate = 0;
+ break;
+ /* option '--verbose' (-v) */
+ case 'v':
+ if (verbose) {
+ fprintf(stderr, "%s: duplicated option `--verbose' (%c)\n", basename(argv[0]), opt);
+ return 1;
+ }
+ verbose = 1;
+ break;
+ /* option '--mode=(2.0|FDF[+BRS])' (-m)*/
+ case 'm':
+ if (op++) {
+ fprintf(stderr, "%s: duplicated option `--mode' (%c)\n", basename(argv[0]), opt);
+ return 1;
+ }
+ if (!strcasecmp(optarg, "default") || !strcasecmp(optarg, "classic") ||
+ !strcasecmp(optarg, "CAN2.0") || !strcasecmp(optarg, "CAN20") || !strcasecmp(optarg, "2.0"))
+ op_mode = PCAN_MESSAGE_STANDARD;
+ else if (!strcasecmp(optarg, "CANFD") || !strcasecmp(optarg, "FDF") || !strcasecmp(optarg, "FD"))
+ op_mode = PCAN_MESSAGE_FD;
+ else if (!strcasecmp(optarg, "CANFD+BRS") || !strcasecmp(optarg, "FDF+BRS") || !strcasecmp(optarg, "FD+BRS"))
+ op_mode = PCAN_MESSAGE_FD | PCAN_MESSAGE_BRS;
+ else {
+ fprintf(stderr, "%s: illegal argument for option `--mode' (%c)\n", basename(argv[0]), opt);
+ return 1;
+ }
+ break;
+ /* option '--listen-only' */
+ case 'M':
+ if (lo++) {
+ fprintf(stderr, "%s: duplicated option `--listen-only'\n", basename(argv[0]));
+ return 1;
+ }
+ listenonly = PCAN_PARAMETER_ON;
+ break;
+ /* option '--no-status-frames' */
+ case 'S':
+ if (sf++) {
+ fprintf(stderr, "%s: duplicated option `--no-status-frames'\n", basename(argv[0]));
+ return 1;
+ }
+ allow_sts = PCAN_PARAMETER_OFF;
+ break;
+ /* option '--no-remote-frames' */
+ case 'R':
+ if (rf++) {
+ fprintf(stderr, "%s: duplicated option `--no-remote-frames'\n", basename(argv[0]));
+ return 1;
+ }
+ allow_rtr = PCAN_PARAMETER_OFF;
+ break;
+ /* option '--code=<11-bit-code>' */
+ case '1':
+ if (sc++) {
+ fprintf(stderr, "%s: duplicated option `--code'\n", basename(argv[0]));
+ return 1;
+ }
+ if (sscanf(optarg, "%" SCNx64, &intarg) != 1) {
+ fprintf(stderr, "%s: illegal argument for option `--code'\n", basename(argv[0]));
+ return 1;
+ }
+ if ((intarg & ~0x7FF) != 0) {
+ fprintf(stderr, "%s: illegal argument for option --code'\n", basename(argv[0]));
+ return 1;
+ }
+ std_code = (DWORD)intarg;
+ break;
+ /* option '--mask=<11-bit-mask>' */
+ case '2':
+ if (sm++) {
+ fprintf(stderr, "%s: duplicated option `--mask'\n", basename(argv[0]));
+ return 1;
+ }
+ if (sscanf(optarg, "%" SCNx64, &intarg) != 1) {
+ fprintf(stderr, "%s: illegal argument for option --mask'\n", basename(argv[0]));
+ return 1;
+ }
+ if ((intarg & ~0x7FF) != 0) {
+ fprintf(stderr, "%s: illegal argument for option --mask'\n", basename(argv[0]));
+ return 1;
+ }
+ std_mask = (DWORD)intarg;
+ break;
+ /* option '--xtd-code=<29-bit-code>' */
+ case '3':
+ if (xc++) {
+ fprintf(stderr, "%s: duplicated option `--xtd-code'\n", basename(argv[0]));
+ return 1;
+ }
+ if (sscanf(optarg, "%" SCNx64, &intarg) != 1) {
+ fprintf(stderr, "%s: illegal argument for option --xtd-code'\n", basename(argv[0]));
+ return 1;
+ }
+ if ((intarg & ~0x1FFFFFFF) != 0) {
+ fprintf(stderr, "%s: illegal argument for option --xtd-code'\n", basename(argv[0]));
+ return 1;
+ }
+ xtd_code = (DWORD)intarg;
+ break;
+ /* option '--xtd-mask=<29-bit-mask>' */
+ case '4':
+ if (xm++) {
+ fprintf(stderr, "%s: duplicated option `--xtd-mask'\n", basename(argv[0]));
+ return 1;
+ }
+ if (sscanf(optarg, "%" SCNx64, &intarg) != 1) {
+ fprintf(stderr, "%s: illegal argument for option --xtd-mask'\n", basename(argv[0]));
+ return 1;
+ }
+ if ((intarg & ~0x1FFFFFFF) != 0) {
+ fprintf(stderr, "%s: illegal argument for option --xtd-mask'\n", basename(argv[0]));
+ return 1;
+ }
+ xtd_mask = (DWORD)intarg;
+ break;
+ /* option '--trace=(ON|OFF)' (-y) */
+ case 'y':
+ if (ts++) {
+ fprintf(stderr, "%s: duplicated option `--trace'\n", basename(argv[0]));
+ return 1;
+ }
+ if (!strcasecmp(optarg, "OFF") || !strcasecmp(optarg, "NO") || !strcasecmp(optarg, "n") || !strcasecmp(optarg, "0"))
+ trace = PCAN_PARAMETER_OFF;
+ else if (!strcasecmp(optarg, "ON") || !strcasecmp(optarg, "YES") || !strcasecmp(optarg, "y") || !strcasecmp(optarg, "1"))
+ trace = PCAN_PARAMETER_ON;
+ else {
+ fprintf(stderr, "%s: illegal argument for option `--trace'\n", basename(argv[0]));
+ return 1;
+ }
+ break;
+ /* option '--time=(ABS|REL|ZERO)' (-t) */
+ case 't':
+ if (mt++) {
+ fprintf(stderr, "%s: duplicated option `--time' (%c)\n", basename(argv[0]), opt);
+ return 1;
+ }
+ if (!strcasecmp(optarg, "ABSOLUTE") || !strcasecmp(optarg, "ABS") || !strcasecmp(optarg, "a"))
+ mode_time = TIME_ABS;
+ else if (!strcasecmp(optarg, "RELATIVE") || !strcasecmp(optarg, "REL") || !strcasecmp(optarg, "r"))
+ mode_time = TIME_REL;
+ else if (!strcasecmp(optarg, "ZERO") || !strcasecmp(optarg, "0") || !strcasecmp(optarg, "z"))
+ mode_time = TIME_ZERO;
+ else {
+ fprintf(stderr, "%s: illegal argument for option `--time' (%c)\n", basename(argv[0]), opt);
+ return 1;
+ }
+ break;
+ /* option '--id=(HEX|DEC|OCT)' (-i) */
+ case 'i':
+ if (mi++) {
+ fprintf(stderr, "%s: duplicated option `--id' (%c)\n", basename(argv[0]), opt);
+ return 1;
+ }
+ if (!strcasecmp(optarg, "HEXADECIMAL") || !strcasecmp(optarg, "HEX") || !strcasecmp(optarg, "h") || !strcasecmp(optarg, "16"))
+ mode_id = MODE_HEX;
+ else if (!strcasecmp(optarg, "DECIMAL") || !strcasecmp(optarg, "DEC") || !strcasecmp(optarg, "d") || !strcasecmp(optarg, "10"))
+ mode_id = MODE_DEC;
+ else if (!strcasecmp(optarg, "OCTAL") || !strcasecmp(optarg, "OCT") || !strcasecmp(optarg, "o") || !strcasecmp(optarg, "8"))
+ mode_id = MODE_OCT;
+ else {
+ fprintf(stderr, "%s: illegal argument for option `--id' (%c)\n", basename(argv[0]), opt);
+ return 1;
+ }
+ break;
+ /* option '--data=(HEX|DEC|OCT)' (-d) */
+ case 'd':
+ if (md++) {
+ fprintf(stderr, "%s: duplicated option `--data' (%c)\n", basename(argv[0]), opt);
+ return 1;
+ }
+ if (!strcasecmp(optarg, "HEXADECIMAL") || !strcasecmp(optarg, "HEX") || !strcasecmp(optarg, "h") || !strcasecmp(optarg, "16"))
+ mode_data = MODE_HEX;
+ else if (!strcasecmp(optarg, "DECIMAL") || !strcasecmp(optarg, "DEC") || !strcasecmp(optarg, "d") || !strcasecmp(optarg, "10"))
+ mode_data = MODE_DEC;
+ else if (!strcasecmp(optarg, "OCTAL") || !strcasecmp(optarg, "OCT") || !strcasecmp(optarg, "o") || !strcasecmp(optarg, "8"))
+ mode_data = MODE_OCT;
+ else {
+ fprintf(stderr, "%s: illegal argument for option `--data' (%c)\n", basename(argv[0]), opt);
+ return 1;
+ }
+ break;
+ /* option '--ascii=(ON|OFF)' (-a) */
+ case 'a':
+ if (ma++) {
+ fprintf(stderr, "%s: duplicated option `--ascii' (%c)\n", basename(argv[0]), opt);
+ return 1;
+ }
+ if (!strcasecmp(optarg, "OFF") || !strcasecmp(optarg, "NO") || !strcasecmp(optarg, "n") || !strcasecmp(optarg, "0"))
+ mode_ascii = ASCII_OFF;
+ else if (!strcasecmp(optarg, "ON") || !strcasecmp(optarg, "YES") || !strcasecmp(optarg, "y") || !strcasecmp(optarg, "1"))
+ mode_ascii = ASCII_ON;
+ else {
+ fprintf(stderr, "%s: illegal argument for option `--ascii' (%c)\n", basename(argv[0]), opt);
+ return 1;
+ }
+ break;
+ /* option '--exclude=[~]' (-x) */
+ case 'x':
+ if (exclude++) {
+ fprintf(stderr, "%s: duplicated option `--exclude' (%c)\n", basename(argv[0]), opt);
+ return 1;
+ }
+ if (!get_exclusion(optarg)) {
+ fprintf(stderr, "%s: illegal argument for option `--exclude' (%c)\n", basename(argv[0]), opt);
+ return 1;
+ }
+ break;
+ /* option '--list-boards' (-L) */
+ case 'L':
+ fprintf(stdout, "%s\n%s\n\n%s\n\n", APPLICATION, COPYRIGHT, WARRANTY);
+ /* list all supported interfaces */
+ num_boards = list_interfaces();
+ fprintf(stdout, "Number of supported CAN interfaces=%i\n", num_boards);
+ return (num_boards >= 0) ? 0 : 1;
+ /* option '--test-boards' (-T) */
+ case 'T':
+ fprintf(stdout, "%s\n%s\n\n%s\n\n", APPLICATION, COPYRIGHT, WARRANTY);
+ /* list all available interfaces */
+ num_boards = test_interfaces();
+ fprintf(stdout, "Number of present CAN interfaces=%i\n", num_boards);
+ return (num_boards >= 0) ? 0 : 1;
+ /* option '--help' (-h) */
+ case 'h':
+ usage(stdout, basename(argv[0]));
+ return 0;
+ case '?':
+ if (!opterr)
+ usage(stderr, basename(argv[0]));
+ return 1;
+ default:
+ if (show_version) {
+ version(stdout, basename(argv[0]));
+ return 0;
+ }
+ else {
+ usage(stderr, basename(argv[0]));
+ return 1;
+ }
+ }
+ }
+ /* - check if one and only one is given */
+ if (optind + 1 != argc) {
+ if (optind == argc)
+ fprintf(stderr, "%s: no interface given\n", basename(argv[0]));
+ else
+ fprintf(stderr, "%s: too many arguments given\n", basename(argv[0]));
+ return 1;
+ }
+ /* - first search the by its name in the device list */
+ for (b = 0; b < PCAN_BOARDS; b++) {
+ if (strcasecmp(argv[optind], can_board[b].name) == 0) {
+ board = can_board[b].type;
+ break;
+ }
+ }
+ /* if not found, search the by its channel handle in the device list */
+ if (b >= PCAN_BOARDS) {
+ if (sscanf(argv[optind], "%li", &board) != 1) {
+ fprintf(stderr, "%s: illegal argument\n", basename(argv[0]));
+ return 1;
+ }
+ for (b = 0; b < PCAN_BOARDS; b++) {
+ if (board == (long)can_board[b].type)
+ break;
+ }
+ if (b >= PCAN_BOARDS) {
+ fprintf(stderr, "%s: illegal argument\n", basename(argv[0]));
+ return 1;
+ }
+ }
+ /* - check if a bit-rate string is given for CAN FD mode */
+ if ((op_mode & PCAN_MESSAGE_FD) && (bitrate == NULL)) {
+ fprintf(stderr, "%s: illegal combination of options `--mode' (m) and `--baudrate' (b)\n", basename(argv[0]));
+ return 1;
+ }
+ /* - check is a BTR0BTR1 value is given for CAN 2.0 mode */
+ if (!(op_mode & PCAN_MESSAGE_FD) && (baudrate == 0)) {
+ fprintf(stderr, "%s: illegal combination of options `--mode' (m) and `--bitrate'\n", basename(argv[0]));
+ return 1;
+ }
+ /* CAN Monitor for PCAN-USB Interfaces */
+ fprintf(stdout, "%s\n%s\n\n%s\n\n", APPLICATION, COPYRIGHT, WARRANTY);
+ /* - show operation mode and bit-rate settings */
+ if (verbose) {
+ fprintf(stdout, "Op.-Mode=%s", (op_mode & PCAN_MESSAGE_FD) ? "CANFD" : "CAN2.0");
+ if ((op_mode & PCAN_MESSAGE_BRS)) fprintf(stdout, "+BRS");
+ fprintf(stdout, " (op_mode=%02Xh)\n", op_mode);
+ if ((op_mode & PCAN_MESSAGE_FD)) {
+ (void)btr_string_to_bit_timing(bitrate, &freq, &slow, &fast);
+ fprintf(stdout, "Bit-rate=%lukbps@%.1f%%",
+ btr_calc_bit_rate_nominal(&slow, freq),
+ btr_calc_sample_point_nominal(&slow) * 100.);
+ if ((op_mode & PCAN_MESSAGE_BRS))
+ fprintf(stdout, ":%lukbps@%.1f%%",
+ btr_calc_bit_rate_data(&fast, freq),
+ btr_calc_sample_point_data(&fast) * 100.);
+ fprintf(stdout, " (%s)\n\n", bitrate);
+ }
+ else {
+ fprintf(stdout, "Baudrate=%skbps (BTR0BTR1=%04lx)\n\n",
+ baudrate == PCAN_BAUD_1M ? "1000" :
+ baudrate == PCAN_BAUD_800K ? "800" :
+ baudrate == PCAN_BAUD_500K ? "500" :
+ baudrate == PCAN_BAUD_250K ? "250" :
+ baudrate == PCAN_BAUD_125K ? "125" :
+ baudrate == PCAN_BAUD_100K ? "100" :
+ baudrate == PCAN_BAUD_50K ? "50" :
+ baudrate == PCAN_BAUD_20K ? "20" :
+ baudrate == PCAN_BAUD_10K ? "10" : "?", baudrate);
+ }
+ }
+ /* - initialization */
+ fprintf(stdout, "Hardware=%s...", can_board[b].name);
+ fflush (stdout);
+ channel = (TPCANHandle)can_board[b].type;
+ if ((status = CAN_SetValue(channel, PCAN_LISTEN_ONLY, (void*)&listenonly, sizeof(listenonly))) != PCAN_ERROR_OK) {
+ fprintf(stdout, "FAILED!\n");
+ fprintf(stderr, "+++ error: CAN_SetValue PCAN-USB%u (PCAN_LISTEN_ONLY=%u) returned 0x%X\n", (channel - 0x50), listenonly, status);
+ return (int)status;;
+ }
+ if (!(op_mode & PCAN_MESSAGE_FD)) {
+ if ((status = CAN_Initialize(channel, (TPCANBaudrate)baudrate, PCAN_USB, 0, 0)) != PCAN_ERROR_OK) {
+ fprintf(stdout, "FAILED!\n");
+ fprintf(stderr, "+++ error: CAN_Initialize PCAN-USB%u returned 0x%X\n", (channel - 0x50), status);
+ return (int)status;;
+ }
+ fprintf(stdout, "OK!\nBaudrate=%lukbps...",
+ btr_calc_bit_rate_sja1000((unsigned short)baudrate) / 1000);
+ }
+ else {
+ if (!btr_string_to_bit_timing(bitrate, &freq, &slow, &fast)) {
+ fprintf(stdout, "FAILED!\n");
+ fprintf(stderr, "+++ error: CAN_InitializeFD PCAN-USB%u with wrong bit-rate\n", (channel - 0x50));
+ return (int)-1;
+ }
+ if ((status = CAN_InitializeFD(channel, bitrate)) != PCAN_ERROR_OK) {
+ fprintf(stdout, "FAILED!\n");
+ fprintf(stderr, "+++ error: CAN_InitializeFD PCAN-USB%u returned 0x%X\n", (channel - 0x50), status);
+ return (int)status;;
+ }
+ fprintf(stdout, "OK!\nBit-rate=%lukbps",
+ btr_calc_bit_rate_nominal(&slow, freq) / 1000);
+ if ((op_mode & PCAN_MESSAGE_BRS))
+ fprintf(stdout, ":%lukbps",
+ btr_calc_bit_rate_data(&fast, freq) / 1000);
+ fprintf(stdout, "...");
+ }
+ if ((status = CAN_SetValue(channel, PCAN_ALLOW_STATUS_FRAMES, (void*)&allow_sts, sizeof(allow_sts))) != PCAN_ERROR_OK) {
+ fprintf(stdout, "FAILED!\n");
+ fprintf(stderr, "+++ error: CAN_SetValue PCAN-USB%u (PCAN_ALLOW_STATUS_FRAMES=%u) returned 0x%X\n", (channel - 0x50), allow_sts, status);
+ (void)CAN_Uninitialize(channel);
+ return (int)status;;
+ }
+ if ((status = CAN_SetValue(channel, PCAN_ALLOW_RTR_FRAMES, (void*)&allow_rtr, sizeof(allow_rtr))) != PCAN_ERROR_OK) {
+ fprintf(stdout, "FAILED!\n");
+ fprintf(stderr, "+++ error: CAN_SetValue PCAN-USB%u (PCAN_ALLOW_RTR_FRAMES=%u) returned 0x%X\n", (channel - 0x50), allow_rtr, status);
+ (void)CAN_Uninitialize(channel);
+ return (int)status;;
+ }
+ if ((std_code != CODE_11BIT) || (std_mask != MASK_11BIT)) {
+ filter = ((UINT64)std_code << 32) | (UINT64)std_mask;
+ if ((status = CAN_SetValue(channel, PCAN_ACCEPTANCE_FILTER_11BIT, (void*)&filter, sizeof(filter))) != PCAN_ERROR_OK) {
+ fprintf(stdout, "FAILED!\n");
+ fprintf(stderr, "+++ error: CAN_SetValue PCAN-USB%u (PCAN_ACCEPTANCE_FILTER_11BIT=%"PRIX64") returned 0x%X\n", (channel - 0x50), filter, status);
+ (void)CAN_Uninitialize(channel);
+ return (int)status;;
+ }
+ }
+ if ((xtd_code != CODE_29BIT) || (xtd_mask != MASK_29BIT)) {
+ filter = ((UINT64)xtd_code << 32) | (UINT64)xtd_mask;
+ if ((status = CAN_SetValue(channel, PCAN_ACCEPTANCE_FILTER_29BIT, (void*)&filter, sizeof(filter))) != PCAN_ERROR_OK) {
+ fprintf(stdout, "FAILED!\n");
+ fprintf(stderr, "+++ error: CAN_SetValue PCAN-USB%u (PCAN_ACCEPTANCE_FILTER_29BIT=%"PRIX64") returned 0x%X\n", (channel - 0x50), filter, status);
+ (void)CAN_Uninitialize(channel);
+ return (int)status;;
+ }
+ }
+ if (trace != PCAN_PARAMETER_OFF) {
+ if (getcwd((char*)buffer, 256) == NULL) {
+ fprintf(stdout, "FAILED!\n");
+ perror("+++ error");
+ (void)CAN_Uninitialize(channel);
+ return (int)status;;
+ }
+ if ((status = CAN_SetValue(channel, PCAN_TRACE_LOCATION, (void*)buffer, 256U)) != PCAN_ERROR_OK) {
+ fprintf(stdout, "FAILED!\n");
+ fprintf(stderr, "+++ error: CAN_SetValue PCAN-USB%u (PCAN_TRACE_LOCATION=%s) returned 0x%X\n", (channel - 0x50), (char*)buffer, status);
+ (void)CAN_Uninitialize(channel);
+ return (int)status;;
+ }
+ buffer[0] = TRACE_FILE_SINGLE | TRACE_FILE_DATE | TRACE_FILE_TIME | TRACE_FILE_OVERWRITE;
+ if ((status = CAN_SetValue(channel, PCAN_TRACE_CONFIGURE, (void*)&buffer[0], sizeof(BYTE))) != PCAN_ERROR_OK) {
+ fprintf(stdout, "FAILED!\n");
+ fprintf(stderr, "+++ error: CAN_SetValue PCAN-USB%u (PCAN_TRACE_CONFIGURE=%X) returned 0x%X\n", (channel - 0x50), buffer[0], status);
+ (void)CAN_Uninitialize(channel);
+ return (int)status;;
+ }
+ if ((status = CAN_SetValue(channel, PCAN_TRACE_STATUS, (void*)&trace, sizeof(trace))) != PCAN_ERROR_OK) {
+ fprintf(stdout, "FAILED!\n");
+ fprintf(stderr, "+++ error: CAN_SetValue PCAN-USB%u (PCAN_TRACE_STATUS=%X) returned 0x%u\n", (channel - 0x50), trace, status);
+ (void)CAN_Uninitialize(channel);
+ return (int)status;;
+ }
+ }
+ fprintf(stdout, "OK!\n");
+ /* - reception loop */
+ fprintf(stderr, "\nPress ^C to abort.\n\n");
+ if (!(op_mode & PCAN_MESSAGE_FD))
+ (void)receive(channel, mode_time, mode_id, mode_data, mode_ascii);
+ else
+ (void)receive_fd(channel, mode_time, mode_id, mode_data, mode_ascii);
+ /* - teardown */
+ if (CAN_GetValue(channel, PCAN_HARDWARE_NAME, buffer, 256) == PCAN_ERROR_OK) {
+ fprintf(stdout, "Hardware: %s", buffer);
+ if (CAN_GetValue(channel, PCAN_DEVICE_ID, (void*)&device_id, sizeof(DWORD)) == PCAN_ERROR_OK)
+ fprintf(stdout, " (DeviceId=0x%02"PRIx32")", device_id);
+ fprintf(stdout, "\n");
+ }
+ if (CAN_GetValue(channel, PCAN_CHANNEL_VERSION, buffer, 256) == PCAN_ERROR_OK) {
+ fprintf(stdout, "Firmware: %s\n", buffer);
+ }
+ if (CAN_GetValue(channel, PCAN_API_VERSION, buffer, 256) == PCAN_ERROR_OK) {
+ fprintf(stdout, "Software: API Version %s\n", buffer);
+ }
+ if ((status = CAN_Uninitialize(channel)) != PCAN_ERROR_OK) {
+ fprintf(stderr, "+++ error: CAN_Uninitialize PCAN-USB%u returned 0x%X\n", (channel - 0x50), status);
+ return (int)status;;
+ }
+ fprintf(stdout, "%s\n", COPYRIGHT);
+ return 0;
+}
+
+/* ----------- local functions ----------------------------------------
+ */
+static int list_interfaces(void)
+{
+ int i;
+
+ fprintf(stdout, "Supported hardware:\n");
+ for (i = 0; i < PCAN_BOARDS; i++) {
+ fprintf(stdout, "\"%s\" (VendorName=\"PEAK-System\", LibraryId=400, BoardType=%lxh)\n", can_board[i].name, can_board[i].type);
+ }
+ return i;
+}
+
+static int test_interfaces(void)
+{
+ TPCANStatus status;
+ int i, n = 0;
+ BYTE test;
+ DWORD device_id;
+
+ for (i = 0; i < PCAN_BOARDS; i++) {
+ if ((status = CAN_GetValue(PCAN_USBBUS1+i, PCAN_CHANNEL_CONDITION, &test, sizeof(BYTE))) == PCAN_ERROR_OK) {
+ if (test > PCAN_CHANNEL_UNAVAILABLE) {
+ fprintf(stdout, "Hardware=%s...", can_board[i].name);
+ fflush(stdout);
+ timer_delay(TIMER_MSEC(333));
+ fprintf(stdout, "%s", (test >= PCAN_CHANNEL_OCCUPIED) ? "occupied" : "available");
+ if (CAN_GetValue(PCAN_USBBUS1+i, PCAN_DEVICE_ID, (void*)&device_id, sizeof(DWORD)) == PCAN_ERROR_OK)
+ fprintf(stdout, " (DeviceId=0x%02"PRIx32")", device_id);
+ fprintf(stdout, "\n");
+ n++;
+ }
+ }
+ else {
+ fprintf(stderr, "+++ error: CAN_GetStatus PCAN_CHANNEL_CONDITION of PCAN-USB%i returned 0x%X\n", i+1, status);
+ return (-1);
+ }
+ }
+ if (n == 0) {
+ fprintf(stdout, "No hardware found!\n");
+ }
+ return n;
+}
+
+static uint64_t receive(TPCANHandle channel, int mode_time, int mode_id, int mode_data, int mode_ascii)
+{
+ TPCANStatus status;
+ TPCANMsg message;
+ TPCANTimestamp timestamp;
+
+ uint64_t frames = 0;
+ uint64_t msec;
+ struct msg_timestamp ts;
+ unsigned char len, row, col, end, idx;
+
+#ifdef BLOCKING_READ
+ int fdes = -1;
+
+ if ((status = CAN_GetValue(channel, PCAN_RECEIVE_EVENT, &fdes, sizeof(int))) != PCAN_ERROR_OK) {
+ fprintf(stderr, "+++ error: CAN_GetValue PCAN_RECEIVE_EVENT returned 0x%X\n", status);
+ return 0;
+ }
+ fd_set rdfs;
+ FD_ZERO(&rdfs);
+ FD_SET(fdes, &rdfs);
+#endif
+ while (running) {
+ if ((status = CAN_Read(channel, &message, ×tamp)) == PCAN_ERROR_OK) {
+ if (!(message.MSGTYPE & PCAN_MESSAGE_STATUS)) {
+ if (((message.ID < MAX_ID) && can_id[message.ID]) || ((message.ID >= MAX_ID) && can_id_xtd)) {
+ fprintf(stdout, "%-7llu ", frames++);
+ /* --- CAN 2. 0 time-stamp --- */
+ msec = ((unsigned long long)timestamp.millis_overflow << 32) + (unsigned long long)timestamp.millis;
+ ts.tv_sec = (long)(msec / 1000ull);
+ ts.tv_usec = (((long)(msec % 1000ull)) * 1000L) + (long)timestamp.micros;
+ /* --- output time-stamp --- */
+ msg_print_time(stdout, (struct msg_timestamp*)&ts, mode_time);
+ msg_print_id(stdout, message.ID, (message.MSGTYPE & PCAN_MESSAGE_RTR), (message.MSGTYPE & PCAN_MESSAGE_EXTENDED),
+ message.LEN, mode_id);
+ if (!(message.MSGTYPE & PCAN_MESSAGE_RTR)) {
+ len = message.LEN;
+ if (mode_ascii) {
+ row = 0;
+ while ((row * 8) < len) {
+ end = len - (row * 8);
+ if (end >= 8)
+ end = 8;
+ // data and space
+ for (col = 0, idx = (row *8); col < end; col++, idx++)
+ msg_print_data(stdout, message.DATA[idx], ((col + 1) == 8), mode_data);
+ for (; col < 8; col++)
+ msg_print_space(stdout, ((col + 1) == 8), mode_data);
+ // ascii characters
+ fprintf(stdout, " ");
+ for (col = 0, idx = (row *8); col < end; col++, idx++)
+ msg_print_ascii(stdout, message.DATA[idx], mode_ascii);
+ row += 1;
+ if ((row * 8) < len)
+ msg_print_indent(stdout, "\n\t", mode_id);
+ }
+ }
+ else {
+ for (idx = 0; idx < len; idx++)
+ msg_print_data(stdout, message.DATA[idx], ((idx + 1) == len), mode_data);
+ }
+ }
+ else {
+// switch (mode_data) {
+// case MODE_DEC: fprintf(stdout, "dlc=%d", message.DLC); break;
+// case MODE_OCT: fprintf(stdout, "dlc=\\%03o", message.DLC); break;
+// case MODE_HEX: fprintf(stdout, "dlc=%02X", message.DLC); break;
+// }
+ fprintf(stdout, "Remote Transmit Request");
+ }
+ fprintf(stdout, "\n");
+ }
+ }
+ }
+ else if (status == PCAN_ERROR_QRCVEMPTY)
+#ifdef BLOCKING_READ
+ select(fdes+1, &rdfs, NULL, NULL, NULL);
+#else
+ timer_delay(1);
+#endif
+ }
+ fprintf(stdout, "\n");
+ return frames;
+}
+
+static uint64_t receive_fd(TPCANHandle channel, int mode_time, int mode_id, int mode_data, int mode_ascii)
+{
+ TPCANStatus status;
+ TPCANMsgFD message;
+ TPCANTimestampFD timestamp;
+
+ uint64_t frames = 0;
+// uint64_t msec;
+ struct msg_timestamp ts;
+ unsigned char len, row, col, end, idx;
+
+#ifdef BLOCKING_READ
+ int fdes = -1;
+
+ if ((status = CAN_GetValue(channel, PCAN_RECEIVE_EVENT, &fdes, sizeof(int))) != PCAN_ERROR_OK) {
+ fprintf(stderr, "+++ error: CAN_GetValue PCAN_RECEIVE_EVENT returned 0x%X\n", status);
+ return 0;
+ }
+ fd_set rdfs;
+ FD_ZERO(&rdfs);
+ FD_SET(fdes, &rdfs);
+#endif
+ while (running) {
+ if ((status = CAN_ReadFD(channel, &message, ×tamp)) == PCAN_ERROR_OK) {
+ if (!(message.MSGTYPE & PCAN_MESSAGE_STATUS)) {
+ if (((message.ID < MAX_ID) && can_id[message.ID]) || ((message.ID >= MAX_ID) && can_id_xtd)) {
+ fprintf(stdout, "%-7llu ", frames++);
+ /* --- CAN FD time-stamp --- */
+ ts.tv_sec = (long)(timestamp / 1000000ull);
+ ts.tv_usec = (long)(timestamp % 1000000ull);
+ /* --- output time-stamp --- */
+ msg_print_time(stdout, (struct msg_timestamp*)&ts, mode_time);
+ msg_print_id_fd(stdout, message.ID, (message.MSGTYPE & PCAN_MESSAGE_RTR), (message.MSGTYPE & PCAN_MESSAGE_EXTENDED),
+ (message.MSGTYPE & PCAN_MESSAGE_FD), (message.MSGTYPE & PCAN_MESSAGE_BRS),
+ (message.MSGTYPE & PCAN_MESSAGE_ESI), dlc_table[message.DLC & 0xF], mode_id);
+ if (!(message.MSGTYPE & PCAN_MESSAGE_RTR)) {
+ len = dlc_table[message.DLC & 0xF];
+ if (mode_ascii) {
+ row = 0;
+ while ((row * 8) < len) {
+ end = len - (row * 8);
+ if (end >= 8)
+ end = 8;
+ // data and space
+ for (col = 0, idx = (row *8); col < end; col++, idx++)
+ msg_print_data(stdout, message.DATA[idx], ((col + 1) == 8), mode_data);
+ for (; col < 8; col++)
+ msg_print_space(stdout, ((col + 1) == 8), mode_data);
+ // ascii characters
+ fprintf(stdout, " ");
+ for (col = 0, idx = (row *8); col < end; col++, idx++)
+ msg_print_ascii(stdout, message.DATA[idx], mode_ascii);
+ row += 1;
+ if ((row * 8) < len)
+ msg_print_indent_fd(stdout, "\n\t", mode_id);
+ }
+ }
+ else {
+ for (idx = 0; idx < len; idx++)
+ msg_print_data(stdout, message.DATA[idx], ((idx + 1) == len), mode_data);
+ }
+ }
+ else {
+// switch (mode_data) {
+// case MODE_DEC: fprintf(stdout, "dlc=%d", message.DLC); break;
+// case MODE_OCT: fprintf(stdout, "dlc=\\%03o", message.DLC); break;
+// case MODE_HEX: fprintf(stdout, "dlc=%02X", message.DLC); break;
+// }
+ fprintf(stdout, "Remote Transmit Request");
+ }
+ fprintf(stdout, "\n");
+ }
+ }
+ }
+ else if (status == PCAN_ERROR_QRCVEMPTY)
+#ifdef BLOCKING_READ
+ select(fdes+1, &rdfs, NULL, NULL, NULL);
+#else
+ timer_delay(1);
+#endif
+ }
+ fprintf(stdout, "\n");
+ return frames;
+}
+
+static int get_exclusion(const char *arg)
+{
+ char *val, *end;
+ int i, inv = 0;
+ long id, last = -1;
+
+ if (!arg)
+ return 0;
+
+ val = (char *)arg;
+ if (*val == '~') {
+ inv = 1;
+ val++;
+ }
+ for (;;) {
+ errno = 0;
+ id = strtol(val, &end, 0);
+
+ if (errno == ERANGE && (id == LONG_MAX || id == LONG_MIN))
+ return 0;
+ if (errno != 0 && id == 0)
+ return 0;
+ if (val == end)
+ return 0;
+
+ if (id < MAX_ID)
+ can_id[id] = 0;
+
+ if (*end == '\0') {
+ if (last != -1) {
+ while (last != id) {
+ if (last < id)
+ last++;
+ else
+ last--;
+ can_id[last] = 0;
+ }
+ /*last = -1; <<< dead store */
+ }
+ break;
+ }
+ if (*end == ',') {
+ if (last != -1) {
+ while (last != id) {
+ if (last < id)
+ last++;
+ else
+ last--;
+ can_id[last] = 0;
+ }
+ last = -1;
+ }
+ }
+ else if (*end == '-')
+ last = id;
+ else
+ return 0;
+
+ val = ++end;
+ }
+ if (inv) {
+ for (i = 0; i < MAX_ID; i++)
+ can_id[i] = !can_id[i];
+ }
+ can_id_xtd = !inv;
+ return 1;
+}
+
+static void sigterm(int signo)
+{
+ //fprintf(stderr, "%s: got signal %d\n", __FILE__, signo);
+ running = 0;
+ (void)signo;
+}
+
+static void usage(FILE *stream, const char *program)
+{
+ fprintf(stdout, "%s\n%s\n\n%s\n\n", APPLICATION, COPYRIGHT, WARRANTY);
+ fprintf(stream, "Usage: %s [...]\n", program);
+ fprintf(stream, "Options:\n");
+ fprintf(stream, " -t, --time=(ZERO|ABS|REL) absolute or relative time (default=0)\n");
+ fprintf(stream, " -i --id=(HEX|DEC|OCT) display mode of CAN-IDs (default=HEX)\n");
+ fprintf(stream, " -d, --data=(HEX|DEC|OCT) display mode of data bytes (default=HEX)\n");
+ fprintf(stream, " -a, --ascii=(ON|OFF) display data bytes in ASCII (default=ON) \n");
+ fprintf(stream, " -x, --exclude=[~] exclude CAN-IDs: [-]{,[-]}\n");
+ fprintf(stream, " --code= acceptance code for 11-bit IDs (default=0x%03X)\n", CODE_11BIT);
+ fprintf(stream, " --mask= acceptance mask for 11-bit IDs (default=0x%03X)\n", MASK_11BIT);
+ fprintf(stream, " --xtd-code= acceptance code for 29-bit IDs (default=0x%08X)\n", CODE_29BIT);
+ fprintf(stream, " --xtd-mask= acceptance mask for 29-bit IDs (default=0x%08X)\n", MASK_29BIT);
+ fprintf(stream, " -m, --mode=(2.0|FDF[+BRS]) CAN operation mode: CAN 2.0 or CAN FD format\n");
+ fprintf(stream, " --listen-only monitor mode (transmitter is off)\n");
+ fprintf(stream, " --no-status-frames suppress reception of status frames\n");
+ fprintf(stream, " --no-remote-frames suppress reception of remote frames\n");
+ fprintf(stream, " -b, --baudrate= CAN 2.0 bit timing in kbps (default=250)\n");
+ fprintf(stream, " --bitrate= CAN FD bit rate (as a string)\n");
+ fprintf(stream, " -v, --verbose show detailed bit rate settings\n");
+ fprintf(stream, " -y, --trace=(ON|OFF) write a trace file (default=OFF)\n");
+ fprintf(stream, " -L, --list-boards list all supported CAN interfaces and exit\n");
+ fprintf(stream, " -T, --test-boards list all available CAN interfaces and exit\n");
+ fprintf(stream, " -h, --help display this help screen and exit\n");
+ fprintf(stream, " --version show version information and exit\n");
+ fprintf(stream, "Hazard note:\n");
+ fprintf(stream, " If you connect your CAN device to a real CAN network when using this program,\n");
+ fprintf(stream, " you might damage your application.\n");
+}
+
+static void version(FILE *stream, const char *program)
+{
+ fprintf(stdout, "%s\n%s\n\n%s\n\n", APPLICATION, COPYRIGHT, LICENSE);
+ (void)program;
+ fprintf(stream, "Written by Uwe Vogt, UV Software, Berlin \n");
+}
+
+/* ----------------------------------------------------------------------
+ * Uwe Vogt, UV Software, Chausseestrasse 33 A, 10115 Berlin, Germany
+ * Tel.: +49-30-46799872, Fax: +49-30-46799873, Mobile: +49-170-3801903
+ * E-Mail: uwe.vogt@uv-software.de, Homepage: http://www.uv-software.de/
+ */
diff --git a/Utilities/can_test/.gitignore b/Utilities/can_test/.gitignore
new file mode 100644
index 0000000..b985485
--- /dev/null
+++ b/Utilities/can_test/.gitignore
@@ -0,0 +1,11 @@
+# ignore all the old crap from svn
+.project
+.cproject
+build.sh
+build_no.h
+build_no.sh
+deploy.sh
+install.sh
+LICENSE
+COPYRIGHT
+IMPORTANT
diff --git a/Utilities/can_test/COPYING b/Utilities/can_test/COPYING
new file mode 100644
index 0000000..9efa6fb
--- /dev/null
+++ b/Utilities/can_test/COPYING
@@ -0,0 +1,338 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+
+ 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.
+
+
+ Copyright (C)
+
+ 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, see .
+
+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.
+
+ , 1 April 1989
+ Moe Ghoul, 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.
diff --git a/Utilities/can_test/Makefile b/Utilities/can_test/Makefile
new file mode 100644
index 0000000..7d77d94
--- /dev/null
+++ b/Utilities/can_test/Makefile
@@ -0,0 +1,190 @@
+#
+# CAN Tester for PEAK-System PCAN USB Interfaces (macOS, x86_64 & arm64)
+#
+# Copyright (c) 2005-2010 Uwe Vogt, UV Software, Friedrichshafen
+# Copyright (c) 2012-2024 Uwe Vogt, UV Software, Berlin (info@uv-software.com)
+#
+# 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 3 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, see .
+#
+current_OS := $(shell sh -c 'uname 2>/dev/null || echo Unknown OS')
+current_OS := $(patsubst CYGWIN%,Cygwin,$(current_OS))
+current_OS := $(patsubst MINGW%,MinGW,$(current_OS))
+current_OS := $(patsubst MSYS%,MinGW,$(current_OS))
+
+TARGET = can_test
+
+INSTALL = ~/bin
+
+PROJ_DIR = ../..
+HOME_DIR = ..
+MAIN_DIR = .
+
+MISC_DIR = $(HOME_DIR)/misc
+DRIVER_DIR = $(HOME_DIR)/driver
+
+OBJECTS = $(OUTDIR)/main.o $(OUTDIR)/bitrates.o $(OUTDIR)/timer.o
+
+DEFINES =
+
+HEADERS = -I$(MAIN_DIR) \
+ -I$(HOME_DIR) \
+ -I$(MISC_DIR)
+
+ifneq ($(VARIANT),STANDALONE)
+ DEFINES += -DOPTION_PCBUSB_STANDALONE=0
+
+ HEADERS +=
+
+ OBJECTS += $(OUTDIR)/PCBUSB.o
+
+ BIN_DIR = $(HOME_DIR)/Binaries
+else
+ DEFINES += -DOPTION_PCBUSB_STANDALONE=1
+
+ HEADERS += -I$(DRIVER_DIR)
+
+ OBJECTS += $(OUTDIR)/pcan_api.o \
+ $(OUTDIR)/pcan_drv.o \
+ $(OUTDIR)/pcan_que.o \
+ $(OUTDIR)/pcan_flt.o \
+ $(OUTDIR)/pcan_trc.o \
+ $(OUTDIR)/pcan_btr.o \
+ $(OUTDIR)/pcan_log.o \
+ $(OUTDIR)/pcan_usb.o \
+ $(OUTDIR)/pcan_usbfd.o
+
+ BIN_DIR = $(HOME_DIR)/../Binaries/$(TARGET)
+endif
+
+CFLAGS += -O2 -Wall -Wextra -Wno-parentheses \
+ -fno-strict-aliasing \
+ $(DEFINES) \
+ $(HEADERS)
+
+CXXFLAGS += -O2 -g -Wall -Wextra -pthread \
+ $(DEFINES) \
+ $(HEADERS)
+
+LDFLAGS += -rpath /usr/local/lib
+
+LIBRARIES = -lpthread
+
+ifeq ($(VARIANT),STANDALONE)
+ LDFLAGS += -Wl,-framework -Wl,IOKit -Wl,-framework -Wl,CoreFoundation
+endif
+
+ifeq ($(BINARY),UNIVERSAL)
+CFLAGS += -arch arm64 -arch x86_64
+CXXFLAGS += -arch arm64 -arch x86_64
+LDFLAGS += -arch arm64 -arch x86_64
+endif
+
+CHECKER = warning,information
+IGNORE = -i tester.c -i dosopt.c -i printmsg.c
+
+CXX = clang++
+CC = clang
+LD = clang
+
+RM = rm -f
+CP = cp -f
+
+OUTDIR = .objects
+BINDIR = $(BIN_DIR)
+
+.PHONY: info outdir bindir
+
+
+all: info outdir bindir $(TARGET)
+
+info:
+ @echo $(CC)" on "$(current_OS)
+ @echo "target: "$(TARGET)
+ @echo "install: "$(INSTALL)
+
+outdir:
+ @mkdir -p $(OUTDIR)
+
+bindir:
+ @mkdir -p $(BINDIR)
+
+incdir:
+ @mkdir -p $(INCDIR)
+
+check:
+ cppcheck --enable=$(CHECKER) --suppressions-list=$(HOME_DIR)/suppress.txt \
+ -D__APPLE__ $(DEFINES) $(HEADERS) $(IGNORE) $(MAIN_DIR) $(MISC_DIR)
+
+clean:
+ @-$(RM) $(TARGET) $(OUTDIR)/*.o $(OUTDIR)/*.d
+
+pristine:
+ @-$(RM) $(TARGET) $(OUTDIR)/*.o $(OUTDIR)/*.d
+ @-$(RM) $(BINDIR)/$(TARGET)
+
+install:
+ @echo "Copying binary file..."
+ @-$(CP) $(TARGET) $(INSTALL)
+
+
+$(OUTDIR)/main.o: $(MAIN_DIR)/main.c
+ $(CC) $(CFLAGS) -MMD -MF $*.d -o $@ -c $<
+
+$(OUTDIR)/PCBUSB.o: $(HOME_DIR)/PCBUSB.c
+ $(CC) $(CFLAGS) -MMD -MF $*.d -o $@ -c $<
+
+$(OUTDIR)/bitrates.o: $(MISC_DIR)/bitrates.c
+ $(CC) $(CFLAGS) -MMD -MF $*.d -o $@ -c $<
+
+$(OUTDIR)/timer.o: $(MISC_DIR)/timer.c
+ $(CC) $(CFLAGS) -MMD -MF $*.d -o $@ -c $<
+
+$(OUTDIR)/printmsg.o: $(MISC_DIR)/printmsg.c
+ $(CC) $(CFLAGS) -MMD -MF $*.d -o $@ -c $<
+
+$(OUTDIR)/pcan_api.o: $(DRIVER_DIR)/pcan_api.c
+ $(CC) $(CFLAGS) -MMD -MF $*.d -o $@ -c $<
+
+$(OUTDIR)/pcan_drv.o: $(DRIVER_DIR)/pcan_drv.c
+ $(CC) $(CFLAGS) -MMD -MF $*.d -o $@ -c $<
+
+$(OUTDIR)/pcan_usb.o: $(DRIVER_DIR)/pcan_usb.c
+ $(CC) $(CFLAGS) -MMD -MF $*.d -o $@ -c $<
+
+$(OUTDIR)/pcan_usbfd.o: $(DRIVER_DIR)/pcan_usbfd.c
+ $(CC) $(CFLAGS) -MMD -MF $*.d -o $@ -c $<
+
+$(OUTDIR)/pcan_btr.o: $(DRIVER_DIR)/pcan_btr.c
+ $(CC) $(CFLAGS) -MMD -MF $*.d -o $@ -c $<
+
+$(OUTDIR)/pcan_flt.o: $(DRIVER_DIR)/pcan_flt.c
+ $(CC) $(CFLAGS) -MMD -MF $*.d -o $@ -c $<
+
+$(OUTDIR)/pcan_que.o: $(DRIVER_DIR)/pcan_que.c
+ $(CC) $(CFLAGS) -MMD -MF $*.d -o $@ -c $<
+
+$(OUTDIR)/pcan_trc.o: $(DRIVER_DIR)/pcan_trc.c
+ $(CC) $(CFLAGS) -MMD -MF $*.d -o $@ -c $<
+
+$(OUTDIR)/pcan_log.o: $(DRIVER_DIR)/pcan_log.c
+ $(CC) $(CFLAGS) -MMD -MF $*.d -o $@ -c $<
+
+
+$(TARGET): $(OBJECTS)
+ $(LD) $(LDFLAGS) -o $@ $(OBJECTS) $(LIBRARIES)
+ $(CP) $(TARGET) $(BINDIR)
+ifeq ($(current_OS),Darwin)
+ @lipo -archs $@
+endif
+ @echo "\033[1mTarget '"$@"' successfully build\033[0m"
diff --git a/Utilities/can_test/README b/Utilities/can_test/README
new file mode 100644
index 0000000..3593a3d
--- /dev/null
+++ b/Utilities/can_test/README
@@ -0,0 +1,127 @@
+CAN Tester for PEAK-System PCAN USB Interfaces (macOS, x86_64 & arm64)
+
+Copyright (c) 2005-2010,2012-2024 by Uwe Vogt, UV Software, Berlin
+
+Usage: can_test [...]
+Options for receiver test (default):
+ -r, --receive count received messages until ^C is pressed
+ -n, --number= check up-counting numbers starting with
+ -s, --stop stop on error (with option --number)
+ -m, --mode=(2.0|FDF[+BRS]) CAN operation mode: CAN 2.0 or CAN FD format
+ --listen-only monitor mode (transmitter is off)
+ --no-status-frames suppress reception of status frames
+ --no-remote-frames suppress reception of remote frames
+ -b, --baudrate= CAN 2.0 bit timing in kbps (default=250)
+ --bitrate= CAN FD bit rate (as a string)
+ -v, --verbose show detailed bit rate settings
+ -y, --trace=(ON|OFF) write a trace file (default=OFF)
+Options for transmitter test:
+ -t, --transmit= send messages for the given time in seconds, or
+ -f, --frames=, alternatively send the given number of messages, or
+ --random= optionally with random cycle time and data length
+ -c, --cycle= cycle time in milliseconds (default=0) or
+ -u, --usec= cycle time in microseconds (default=0)
+ -d, --dlc= send messages of given length (default=8)
+ -i, --id= use given identifier (default=100h)
+ -n, --number= set first up-counting number (default=0)
+ -m, --mode=(2.0|FDF[+BRS]) CAN operation mode: CAN 2.0 or CAN FD format
+ -b, --baudrate= CAN 2.0 bit timing in kbps (default=250)
+ --bitrate= CAN FD bit rate (as a string)
+ -v, --verbose show detailed bit rate settings
+ -y, --trace=(ON|OFF) write a trace file (default=OFF)
+Options:
+ -L, --list-boards list all supported CAN interfaces and exit
+ -T, --test-boards list all available CAN interfaces and exit
+ -h, --help display this help screen and exit
+ --version show version information and exit
+Interfaces:
+ PCAN-USB1
+ PCAN-USB2
+ PCAN-USB3
+ PCAN-USB4
+ PCAN-USB5
+ PCAN-USB6
+ PCAN-USB7
+ PCAN-USB8
+CAN 2.0 baud rate index (default=3):
+ 0 = 1000 kbps
+ 1 = 800 kbps
+ 2 = 500 kbps
+ 3 = 250 kbps
+ 4 = 125 kbps
+ 5 = 100 kbps
+ 6 = 50 kbps
+ 7 = 20 kbps
+ 8 = 10 kbps
+CAN FD bit rate as comma-separated =-list:
+ f_clock= frequency in Hz or
+ f_clock_mhz= frequency in MHz
+ nom_brp= bit-rate prescaler (nominal)
+ nom_tseg1= time segment 1 (nominal)
+ nom_tseg2= time segment 2 (nominal)
+ nom_sjw= sync. jump width (nominal)
+ nom_sam= sampling (only SJA1000)
+ data_brp= bit-rate prescaler (FD data)
+ data_tseg1= time segment 1 (FD data)
+ data_tseg2= time segment 2 (FD data)
+ data_sjw= sync. jump width (FD data)
+Examples:
+ 125kbps:1000kbps f_clock_mhz=80,nom_brp=2,nom_tseg1=255,nom_tseg2=64,nom_sjw=64,data_brp=2,data_tseg1=31,data_tseg2=8,data_sjw=8
+ 250kbps:2000kbps f_clock_mhz=80,nom_brp=2,nom_tseg1=127,nom_tseg2=32,nom_sjw=32,data_brp=2,data_tseg1=15,data_tseg2=4,data_sjw=4
+ 500kbps:4000kbps f_clock_mhz=80,nom_brp=2,nom_tseg1=63,nom_tseg2=16,nom_sjw=16,data_brp=2,data_tseg1=7,data_tseg2=2,data_sjw=2
+ 1000kbps:8000kbps f_clock_mhz=80,nom_brp=2,nom_tseg1=31,nom_tseg2=8,nom_sjw=8,data_brp=2,data_tseg1=3,data_tseg2=1,data_sjw=1
+ 2000kbps:10000kbps f_clock_mhz=80,nom_brp=1,nom_tseg1=31,nom_tseg2=8,nom_sjw=1,data_brp=2,data_tseg1=2,data_tseg2=1,data_sjw=1
+Hazard note:
+ If you connect your CAN device to a real CAN network when using this program,
+ you might damage your application.
+License type:
+ This software is freeware without any warranty or support!
+Change log:
+- Version 0.6 of July 29, 2024:
+ Realized new program options:
+ - '--no-status-frames' suppress reception of status frames (default=ON)
+ - '--no-remote-frames' suppress reception of remote frames (default=ON)
+ - '--trace=(ON|OFF)' write a trace file (default=OFF)
+ Compiled against PCBUSB v0.13 sources as Universal macOS Binary
+- Version 0.6 SR8 of November 3, 2023:
+ Fixed a bug with new PCAN-USB FD product version (hardware 6.0)
+ Compiled against PCBUSB v0.12.2 sources as Universal macOS Binary
+- Version 0.6 SR7 of July 15, 2023:
+ Fixed some bugs with bit-rate string conversion (SAM issue among others)
+ Compiled against PCBUSB v0.12.1 sources as Universal macOS Binary
+- Version 0.5 SR6 of February 2, 2023:
+ Display device id. when listing available CAN interfaces (option -T)
+ Fixed a bug with default CAN FD bit-rate settings (250kbps:2000kbps)
+ Compiled against PCBUSB v0.12 sources as Universal macOS Binary
+- Version 0.5 SR5 of July 31, 2022:
+ Fixed the CAN FD URB issue ('Messages lost on high CAN FD bit-rates')
+ Compiled against PCBUSB v0.11.2 sources as Universal macOS Binary
+- Version 0.5 SR4 of February 5, 2022:
+ Fixed a bug with channel state 'occupied' when used by another process
+ Compiled against PCBUSB v0.11 sources as Universal macOS Binary
+- Version 0.5 SR3 of December 7, 2021:
+ Compiled against PCBUSB v0.10.1 sources as Universal macOS Binary
+- Version 0.5 SR2 of December 22, 2020:
+ Compiled against PCBUSB v0.9 sources (PCAN-USB Pro FD CAN1).
+- Version 0.5 SR1 of June 28, 2020:
+ Compiled against PCBUSB v0.9 sources ().
+- Version 0.5 of December 1, 2019:
+ Reworked command-line option handling:
+ --listen-only - monitor mode (transmitter is off)
+ --list-boards - list all supported CAN interfaces
+ --test boards - list all available CAN interfaces
+ Compiled against PCBUSB v0.8.1 sources
+- Version 0.4 of September 22, 2017:
+ Support of PCAN-USB FD interfaces
+- Version 0.3 of November 23, 2014:
+ Time-stamps are taken from CAN controller
+- Version 0.2 of May 17, 2013:
+ Initial revision
+- Version 0.1 of July 6, 2012:
+ (reverted)
+Known bugs and caveats:
+- See documentation of PCBUSB library for known bugs and caveats
+ in the underlying library.
+Contact:
+ E-Mail: mailto:info@mac-can.com
+ Internet: https://www.mac-can.com
diff --git a/Utilities/can_test/bitrates.sh b/Utilities/can_test/bitrates.sh
new file mode 100755
index 0000000..5dba806
--- /dev/null
+++ b/Utilities/can_test/bitrates.sh
@@ -0,0 +1,27 @@
+#!/bin/sh
+
+Channel=PCAN-USB1
+
+./Debug/can_test $Channel --frames 0 --mode FDF+BRS --verbose --bitrate f_clock_mhz=80,nom_brp=20,nom_tseg1=12,nom_tseg2=3,nom_sjw=1,data_brp=4,data_tseg1=7,data_tseg2=2,data_sjw=1
+./Debug/can_test $Channel --frames 0 --mode FDF+BRS --verbose --bitrate f_clock_mhz=80,nom_brp=2,nom_tseg1=255,nom_tseg2=64,nom_sjw=64,data_brp=2,data_tseg1=31,data_tseg2=8,data_sjw=8
+./Debug/can_test $Channel --frames 0 --mode FDF+BRS --verbose --bitrate f_clock_mhz=80,nom_brp=2,nom_tseg1=127,nom_tseg2=32,nom_sjw=32,data_brp=2,data_tseg1=15,data_tseg2=4,data_sjw=4
+./Debug/can_test $Channel --frames 0 --mode FDF+BRS --verbose --bitrate f_clock_mhz=80,nom_brp=2,nom_tseg1=63,nom_tseg2=16,nom_sjw=16,data_brp=2,data_tseg1=7,data_tseg2=2,data_sjw=2
+./Debug/can_test $Channel --frames 0 --mode FDF+BRS --verbose --bitrate f_clock_mhz=80,nom_brp=2,nom_tseg1=31,nom_tseg2=8,nom_sjw=8,data_brp=2,data_tseg1=3,data_tseg2=1,data_sjw=1
+./Debug/can_test $Channel --frames 0 --mode FDF --verbose --bitrate f_clock_mhz=80,nom_brp=2,nom_tseg1=255,nom_tseg2=64,nom_sjw=64
+./Debug/can_test $Channel --frames 0 --mode FDF --verbose --bitrate f_clock_mhz=80,nom_brp=2,nom_tseg1=127,nom_tseg2=32,nom_sjw=32
+./Debug/can_test $Channel --frames 0 --mode FDF --verbose --bitrate f_clock_mhz=80,nom_brp=2,nom_tseg1=63,nom_tseg2=16,nom_sjw=16
+./Debug/can_test $Channel --frames 0 --mode FDF --verbose --bitrate f_clock_mhz=80,nom_brp=2,nom_tseg1=31,nom_tseg2=8,nom_sjw=8
+echo
+echo ~~~ CANopen FD bit-rates ~~~
+echo
+./Debug/can_test $Channel --frames 0 --mode FDF+BRS --verbose --bitrate f_clock_mhz=80,nom_brp=4,nom_tseg1=127,nom_tseg2=32,nom_sjw=32,data_brp=4,data_tseg1=6,data_tseg2=3,data_sjw=3
+./Debug/can_test $Channel --frames 0 --mode FDF+BRS --verbose --bitrate f_clock_mhz=80,nom_brp=4,nom_tseg1=63,nom_tseg2=16,nom_sjw=16,data_brp=4,data_tseg1=6,data_tseg2=3,data_sjw=3
+./Debug/can_test $Channel --frames 0 --mode FDF+BRS --verbose --bitrate f_clock_mhz=80,nom_brp=2,nom_tseg1=63,nom_tseg2=16,nom_sjw=16,data_brp=2,data_tseg1=14,data_tseg2=5,data_sjw=5
+./Debug/can_test $Channel --frames 0 --mode FDF+BRS --verbose --bitrate f_clock_mhz=80,nom_brp=2,nom_tseg1=31,nom_tseg2=8,nom_sjw=8,data_brp=2,data_tseg1=5,data_tseg2=2,data_sjw=2
+echo
+echo ~~~ UV Software ~~~
+./Debug/can_test $Channel --frames 0 --mode FDF+BRS --verbose --bitrate f_clock_mhz=80,nom_speed=125000,nom_sp=80.0,data_speed=1000000,data_sp=80.0
+./Debug/can_test $Channel --frames 0 --mode FDF+BRS --verbose --bitrate f_clock_mhz=80,nom_speed=250000,nom_sp=80.0,data_speed=2000000,data_sp=80.0
+./Debug/can_test $Channel --frames 0 --mode FDF+BRS --verbose --bitrate f_clock_mhz=80,nom_speed=500000,nom_sp=80.0,data_speed=4000000,data_sp=80.0
+./Debug/can_test $Channel --frames 0 --mode FDF+BRS --verbose --bitrate f_clock_mhz=80,nom_speed=1000000,nom_sp=80.0,data_speed=8000000,data_sp=80.0
+./Debug/can_test $Channel --frames 0 --mode FDF+BRS --verbose --bitrate f_clock_mhz=80,nom_speed=2000000,nom_sp=80.0,data_speed=10000000,data_sp=80.0
diff --git a/Utilities/can_test/main.c b/Utilities/can_test/main.c
new file mode 100644
index 0000000..eb14a4a
--- /dev/null
+++ b/Utilities/can_test/main.c
@@ -0,0 +1,1468 @@
+/* -- $HeadURL: https://uv-software.net/MacCAN/PCANUSB/Utilities/can_test/trunk/main.c $ --
+ *
+ * project : CAN - Controller Area Network
+ *
+ * purpose : CAN Tester goes macOS aka OS X
+ *
+ * copyright : (c) 2005-2012 by UV Software, Friedrichshafen
+ * (c) 2013-2024 by UV Software, Berlin
+ *
+ * revision : $Rev: 2061 $ of $Date: 2024-12-29 18:36:36 +0100 (So, 29 Dez 2024) $
+ *
+ * author(s) : Uwe Vogt, UV Software
+ *
+ * e-mail : uwe.vogt@uv-software.de
+ *
+ *
+ * ----------- description --------------------------------------------
+ *
+ * CAN Tester (based on macOS Library for PCAN USB Interfaces)
+ *
+ * (1) Standalone version with compiled PCBUSB sources
+ *
+ * This program is freeware without any warranty or support!
+ * Please note the copyright and license agreements.
+ *
+ * Note: This version does not require the libPCBUSB to be installed.
+ *
+ * (2) Open-source version with libPCBUSB support
+ *
+ * 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, see .
+ *
+ * Note: The libPCBUSB is licensed under a freeware license without any
+ * warranty or support. The libPCBUSB is not part of this program.
+ * It can be downloaded from .
+ *
+ */
+/* ----------- version ------------------------------------------------
+ */
+#include "build_no.h"
+#if (OPTION_PCBUSB_STANDALONE != 0)
+#define VERSION_MAJOR 0
+#define VERSION_MINOR 6
+#define VERSION_PATCH 1
+#else
+#define VERSION_MAJOR 1
+#define VERSION_MINOR 0
+#define VERSION_PATCH 0
+#endif
+#define VERSION_BUILD BUILD_NO
+#define VERSION_STRING TOSTRING(VERSION_MAJOR)"." TOSTRING(VERSION_MINOR) "." TOSTRING(VERSION_PATCH) " (" TOSTRING(BUILD_NO) ")"
+#if defined(__APPLE__)
+#define PLATFORM "macOS"
+#else
+#error Unsupported platform
+#endif
+static const char APPLICATION[] = "CAN Tester for PEAK-System PCAN USB Interfaces, Version "VERSION_STRING;
+static const char COPYRIGHT[] = "Copyright (c) 2005-2010,2012-2024 by Uwe Vogt, UV Software, Berlin";
+#if (OPTION_PCBUSB_STANDALONE != 0)
+static const char WARRANTY[] = "This program is freeware without any warranty or support!";
+static const char LICENSE[] = "This program is freeware without any warranty or support!\n\n" \
+ "Note: This program does not require the libPCBUSB to be installed.";
+#else
+static const char WARRANTY[] = "CAN Tester comes with ABSOLUTELY NO WARRANTY; for details type `--version'.\n\n" \
+ "This is free software, and you are welcome to redistribute it\n" \
+ "under certain conditions; type `--version' for details.";
+static const char LICENSE[] = "This program is free software; you can redistribute it and/or modify\n" \
+ "it under the terms of the GNU General Public License as published by\n" \
+ "the Free Software Foundation; either version 2 of the License, or\n" \
+ "(at your option) any later version.\n\n" \
+ "This program is distributed in the hope that it will be useful,\n" \
+ "but WITHOUT ANY WARRANTY; without even the implied warranty of\n" \
+ "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" \
+ "GNU General Public License for more details.\n\n" \
+ "You should have received a copy of the GNU General Public License along\n" \
+ "with this program; if not, see .\n\n" \
+ "Note: The libPCBUSB is licensed under a freeware license without any\n" \
+ "warranty or support. The libPCBUSB is not part of this program.\n" \
+ "It can be downloaded from .";
+#endif
+
+/* ----------- includes -----------------------------------------------
+ */
+#if (OPTION_PCBUSB_STANDALONE != 0)
+#include "pcan_api.h"
+#else
+#include
+#endif
+#include "bitrates.h"
+#include "timer.h"
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+
+#include
+
+
+/* ----------- options ---------------------------------------------------
+ */
+#define BLOCKING_READ
+
+
+/* ----------- defines ---------------------------------------------------
+ */
+#define RxMODE (0)
+#define TxMODE (1)
+#define TxFRAMES (2)
+#define TxRANDOM (3)
+
+
+/* ----------- types -----------------------------------------------------
+ */
+
+
+/* ----------- prototypes ------------------------------------------------
+ */
+static void sigterm(int signo);
+static void usage(FILE *stream, const char *program);
+static void version(FILE *stream, const char *program);
+
+static int list_interfaces(void);
+static int test_interfaces(void);
+
+static uint64_t tx_random(TPCANHandle channel, BYTE mode, uint32_t can_id, uint8_t dlc, uint32_t delay, uint64_t number, uint64_t offset);
+static uint64_t tx_frames(TPCANHandle channel, BYTE mode, uint32_t can_id, uint8_t dlc, uint32_t delay, uint64_t number, uint64_t offset);
+static uint64_t tx_test(TPCANHandle channel, BYTE mode, uint32_t can_id, uint8_t dlc, uint32_t delay, time_t duration, uint64_t offset);
+static uint64_t rx_test(TPCANHandle channel, int check, uint64_t offset, int stop_on_error);
+
+static uint64_t tx_random_fd(TPCANHandle channel, BYTE mode, uint32_t can_id, uint8_t dlc, uint32_t delay, uint64_t number, uint64_t offset);
+static uint64_t tx_frames_fd(TPCANHandle channel, BYTE mode, uint32_t can_id, uint8_t dlc, uint32_t delay, uint64_t number, uint64_t offset);
+static uint64_t tx_test_fd(TPCANHandle channel, BYTE mode, uint32_t can_id, uint8_t dlc, uint32_t delay, time_t duration, uint64_t offset);
+static uint64_t rx_test_fd(TPCANHandle channel, int check, uint64_t offset, int stop_on_error);
+
+
+/* ----------- variables ----------------------------------------------
+ */
+static char *prompt[4] = {"-\b", "/\b", "|\b", "\\\b"};
+static volatile int running = 1;
+
+/* - - - - - - from CAN API Defs - - - - - - - - - - - - - - - - - - - -
+ */
+#define PCAN_BOARDS (8)
+static struct _can_board_t
+{
+ unsigned long type; /**< board type */
+ char* name; /**< board name */
+} can_board[PCAN_BOARDS] = {
+ {PCAN_USBBUS1, "PCAN-USB1"},
+ {PCAN_USBBUS2, "PCAN-USB2"},
+ {PCAN_USBBUS3, "PCAN-USB3"},
+ {PCAN_USBBUS4, "PCAN-USB4"},
+ {PCAN_USBBUS5, "PCAN-USB5"},
+ {PCAN_USBBUS6, "PCAN-USB6"},
+ {PCAN_USBBUS7, "PCAN-USB7"},
+ {PCAN_USBBUS8, "PCAN-USB8"},
+};
+
+/* ----------- main ---------------------------------------------------
+ */
+int main(int argc, char *argv[])
+{
+ TPCANHandle channel = PCAN_USBBUS1;
+ TPCANStatus status;
+
+ int opt;
+ int mode = RxMODE, m = 0;
+ time_t txtime = 0; long txframes = 0;
+ long board = -1; int b;
+ BYTE op_mode = PCAN_MESSAGE_STANDARD; int op = 0;
+ BYTE listenonly = PCAN_PARAMETER_OFF; int lo = 0;
+ BYTE allow_sts = PCAN_PARAMETER_ON; int sf = 0;
+ BYTE allow_rtr = PCAN_PARAMETER_ON; int rf = 0;
+ BYTE trace = PCAN_PARAMETER_OFF; int ts = 0;
+ long baudrate = PCAN_BAUD_250K; int bd = 0;
+ long delay = 0; int t = 0;
+ long data = 8; int d = 0;
+ long can_id = 0x100; int c = 0;
+ long number = 0; int n = 0;
+ int stop_on_error = 0;
+ int show_version = 0;
+ int verbose = 0;
+ int num_boards = 0;
+ BYTE buffer[256]; /* char *device, *firmware, *software, *library; */
+ DWORD device_id = 8472;
+ /* Default Bit-rate */
+ TPCANBitrateFD bitrate = "f_clock_mhz=80,nom_brp=2,nom_tseg1=127,nom_tseg2=32,nom_sjw=32,data_brp=2,data_tseg1=15,data_tseg2=4,data_sjw=4";
+ long unsigned freq = 0; struct btr_bit_timing slow, fast;
+
+ struct option long_options[] = {
+ {"baudrate", required_argument, 0, 'b'},
+ {"bitrate", required_argument, 0, 'B'},
+ {"verbose", no_argument, 0, 'v'},
+ {"mode", required_argument, 0, 'm'},
+ {"shared", no_argument, 0, 'S'},
+ {"listen-only", no_argument, 0, 'M'},
+ {"no-status-frames", no_argument, 0, 'S'},
+ {"no-remote-frames", no_argument, 0, 'R'},
+ {"receive", no_argument, 0, 'r'},
+ {"number", required_argument, 0, 'n'},
+ {"stop", no_argument, 0, 's'},
+ {"transmit", required_argument, 0, 't'},
+ {"frames", required_argument, 0, 'f'},
+ {"random", required_argument, 0, 'F'},
+ {"cycle", required_argument, 0, 'c'},
+ {"usec", required_argument, 0, 'u'},
+ {"data", required_argument, 0, 'd'},
+ {"dlc", required_argument, 0, 'd'},
+ {"id", required_argument, 0, 'i'},
+ {"trace", required_argument, 0, 'y'},
+ {"list-boards", no_argument, 0, 'L'},
+ {"test-boards", no_argument, 0, 'T'},
+ {"help", no_argument, 0, 'h'},
+ {"version", no_argument, &show_version, 1},
+ {0, 0, 0, 0}
+ };
+
+ /* signal handler */
+ if ((signal(SIGINT, sigterm) == SIG_ERR) ||
+#if !defined(_WIN32) && !defined(_WIN64)
+ (signal(SIGHUP, sigterm) == SIG_ERR) ||
+#endif
+ (signal(SIGTERM, sigterm) == SIG_ERR)) {
+ perror("+++ error");
+ return errno;
+ }
+ /* scan command-line */
+ while ((opt = getopt_long(argc, (char * const *)argv, "b:vm:rn:st:f:R:c:u:d:i:y:aLTvh", long_options, NULL)) != -1) {
+ switch (opt) {
+ /* option '--baudrate=' (-b) */
+ case 'b':
+ if (bd++) {
+ fprintf(stderr, "%s: duplicated option `--baudrate' (%c)\n", basename(argv[0]), opt);
+ return 1;
+ }
+ if (sscanf(optarg, "%li", &baudrate) != 1) {
+ fprintf(stderr, "%s: illegal argument for option `--baudrate' (%c)\n", basename(argv[0]), opt);
+ return 1;
+ }
+ switch (baudrate) {
+ case 0: case 1000: case 1000000: baudrate = PCAN_BAUD_1M; break;
+ case 1: case 800: case 800000: baudrate = PCAN_BAUD_800K; break;
+ case 2: case 500: case 500000: baudrate = PCAN_BAUD_500K; break;
+ case 3: case 250: case 250000: baudrate = PCAN_BAUD_250K; break;
+ case 4: case 125: case 125000: baudrate = PCAN_BAUD_125K; break;
+ case 5: case 100: case 100000: baudrate = PCAN_BAUD_100K; break;
+ case 6: case 50: case 50000: baudrate = PCAN_BAUD_50K; break;
+ case 7: case 20: case 20000: baudrate = PCAN_BAUD_20K; break;
+ case 8: case 10: case 10000: baudrate = PCAN_BAUD_10K; break;
+ default:
+ fprintf(stderr, "%s: illegal argument for option `--baudrate' (%c)\n", basename(argv[0]), opt);
+ return 1;
+ }
+ bitrate = NULL;
+ break;
+ /* option '--bitrate=' as string */
+ case 'B':
+ if (bd++) {
+ fprintf(stderr, "%s: duplicated option `--bitrate'\n", basename(argv[0]));
+ return 1;
+ }
+ if (!btr_string_to_bit_timing(optarg, &freq, &slow, &fast)) {
+ fprintf(stderr, "%s: illegal argument for option `--bitrate'\n", basename(argv[0]));
+ return 1;
+ }
+ bitrate = optarg;
+ baudrate = 0;
+ break;
+ /* option '--verbose' (-v) */
+ case 'v':
+ if (verbose) {
+ fprintf(stderr, "%s: duplicated option `--verbose' (%c)\n", basename(argv[0]), opt);
+ return 1;
+ }
+ verbose = 1;
+ break;
+ /* option '--mode=(2.0|FDF[+BRS])' (-m)*/
+ case 'm':
+ if (op++) {
+ fprintf(stderr, "%s: duplicated option `--mode' (%c)\n", basename(argv[0]), opt);
+ return 1;
+ }
+ if (!strcasecmp(optarg, "default") || !strcasecmp(optarg, "classic") ||
+ !strcasecmp(optarg, "CAN2.0") || !strcasecmp(optarg, "CAN20") || !strcasecmp(optarg, "2.0"))
+ op_mode = PCAN_MESSAGE_STANDARD;
+ else if (!strcasecmp(optarg, "CANFD") || !strcasecmp(optarg, "FDF") || !strcasecmp(optarg, "FD"))
+ op_mode = PCAN_MESSAGE_FD;
+ else if (!strcasecmp(optarg, "CANFD+BRS") || !strcasecmp(optarg, "FDF+BRS") || !strcasecmp(optarg, "FD+BRS"))
+ op_mode = PCAN_MESSAGE_FD | PCAN_MESSAGE_BRS;
+ else {
+ fprintf(stderr, "%s: illegal argument for option `--mode' (%c)\n", basename(argv[0]), opt);
+ return 1;
+ }
+ break;
+ /* option '--listen-only' */
+ case 'M':
+ if (lo++) {
+ fprintf(stderr, "%s: duplicated option `--listen-only'\n", basename(argv[0]));
+ return 1;
+ }
+ listenonly = PCAN_PARAMETER_ON;
+ break;
+ /* option '--no-status-frames' */
+ case 'S':
+ if (sf++) {
+ fprintf(stderr, "%s: duplicated option `--no-status-frames'\n", basename(argv[0]));
+ return 1;
+ }
+ allow_sts = PCAN_PARAMETER_OFF;
+ break;
+ /* option '--no-remote-frames' */
+ case 'R':
+ if (rf++) {
+ fprintf(stderr, "%s: duplicated option `--no-remote-frames'\n", basename(argv[0]));
+ return 1;
+ }
+ allow_rtr = PCAN_PARAMETER_OFF;
+ break;
+ case 'r': /* option '--receive' (-r) */
+ if (m++) {
+ fprintf(stderr, "%s: duplicated option `--receive' (%c)\n", basename(argv[0]), opt);
+ return 1;
+ }
+ mode = RxMODE;
+ break;
+ case 'n': /* option '--number=' (-n) */
+ if (n++) {
+ fprintf(stderr, "%s: duplicated option `--number' (%c)\n", basename(argv[0]), opt);
+ return 1;
+ }
+ if (sscanf(optarg, "%li", &number) != 1) {
+ fprintf(stderr, "%s: illegal argument for option `--number' (%c)\n", basename(argv[0]), opt);
+ return 1;
+ }
+ if (number < 0) {
+ fprintf(stderr, "%s: illegal argument for option `--number' (%c)\n", basename(argv[0]), opt);
+ return 1;
+ }
+ break;
+ case 's': /* option '--stop' (-s) */
+ if (stop_on_error) {
+ fprintf(stderr, "%s: duplicated option `--stop' (%c)\n", basename(argv[0]), opt);
+ return 1;
+ }
+ stop_on_error = 1;
+ break;
+ case 't': /* option '--transmit=' (-t) in [s] */
+ if (m++) {
+ fprintf(stderr, "%s: duplicated option `--transmit' (%c)\n", basename(argv[0]), opt);
+ return 1;
+ }
+ if (sscanf(optarg, "%li", &txtime) != 1) {
+ fprintf(stderr, "%s: illegal argument for option `--transmit' (%c)\n", basename(argv[0]), opt);
+ return 1;
+ }
+ if (txtime < 0) {
+ fprintf(stderr, "%s: illegal argument for option `--transmit' (%c)\n", basename(argv[0]), opt);
+ return 1;
+ }
+ mode = TxMODE;
+ break;
+ case 'f': /* option '--frames=' (-f) */
+ if (m++) {
+ fprintf(stderr, "%s: duplicated option `--frames' (%c)\n", basename(argv[0]), opt);
+ return 1;
+ }
+ if (sscanf(optarg, "%li", &txframes) != 1) {
+ fprintf(stderr, "%s: illegal argument for option `--frames' (%c)\n", basename(argv[0]), opt);
+ return 1;
+ }
+ if (txframes < 0) {
+ fprintf(stderr, "%s: illegal argument for option `--frames' (%c)\n", basename(argv[0]), opt);
+ return 1;
+ }
+ mode = TxFRAMES;
+ break;
+ case 'F': /* option '--random=' */
+ if (m++) {
+ fprintf(stderr, "%s: duplicated option `--random'\n", basename(argv[0]));
+ return 1;
+ }
+ if (sscanf(optarg, "%li", &txframes) != 1) {
+ fprintf(stderr, "%s: illegal argument for option `--random'\n", basename(argv[0]));
+ return 1;
+ }
+ if (txframes < 0) {
+ fprintf(stderr, "%s: illegal argument for option `--random' (%c)\n", basename(argv[0]), opt);
+ return 1;
+ }
+ if (!d) /* let the tester generate messages of arbitrary length */
+ data = 0;
+ mode = TxRANDOM;
+ break;
+ case 'c': /* option '--cycle=' (-c) */
+ if (t++) {
+ fprintf(stderr, "%s: duplicated option `--cycle' (%c)\n", basename(argv[0]), opt);
+ return 1;
+ }
+ if (sscanf(optarg, "%li", &delay) != 1) {
+ fprintf(stderr, "%s: illegal argument for option `--cycle' (%c)\n", basename(argv[0]), opt);
+ return 1;
+ }
+ if ((delay < 0) || (delay > (LONG_MAX / 1000l))) {
+ fprintf(stderr, "%s: illegal argument for option `--cycle' (%c)\n", basename(argv[0]), opt);
+ return 1;
+ }
+ delay *= 1000l;
+ break;
+ case 'u': /* option '--usec=' (-u) */
+ if (t++) {
+ fprintf(stderr, "%s: duplicated option `--usec' (%c)\n", basename(argv[0]), opt);
+ return 1;
+ }
+ if (sscanf(optarg, "%li", &delay) != 1) {
+ fprintf(stderr, "%s: illegal argument for option `--usec' (%c)\n", basename(argv[0]), opt);
+ return 1;
+ }
+ if (delay < 0) {
+ fprintf(stderr, "%s: illegal argument for option `--usec' (%c)\n", basename(argv[0]), opt);
+ return 1;
+ }
+ break;
+ case 'd': /* option '--dlc=' (-d) */
+ if (d++) {
+ fprintf(stderr, "%s: duplicated option `--dlc' (%c)\n", basename(argv[0]), opt);
+ return 1;
+ }
+ if (sscanf(optarg, "%li", &data) != 1) {
+ fprintf(stderr, "%s: illegal argument for option `--dlc' (%c)\n", basename(argv[0]), opt);
+ return 1;
+ }
+ if ((data < 0) || (64 < data)) {
+ fprintf(stderr, "%s: illegal argument for option `--dlc' (%c)\n", basename(argv[0]), opt);
+ return 1;
+ }
+ break;
+ case 'i': /* option '--id=' (-i) */
+ if (c++) {
+ fprintf(stderr, "%s: duplicated option `--id' (%c)\n", basename(argv[0]), opt);
+ return 1;
+ }
+ if (sscanf(optarg, "%li", &can_id) != 1) {
+ fprintf(stderr, "%s: illegal argument for option `--id' (%c)\n", basename(argv[0]), opt);
+ return 1;
+ }
+ if ((can_id < 0x000) || (0x1FFFFFFF < can_id)) { // TODO: to be checked with --mode=NXTD
+ fprintf(stderr, "%s: illegal argument for option `--id' (%c)\n", basename(argv[0]), opt);
+ return 1;
+ }
+ break;
+ /* option '--trace=(ON|OFF)' (-y) */
+ case 'y':
+ if (ts++) {
+ fprintf(stderr, "%s: duplicated option `--trace'\n", basename(argv[0]));
+ return 1;
+ }
+ if (!strcasecmp(optarg, "OFF") || !strcasecmp(optarg, "NO") || !strcasecmp(optarg, "n") || !strcasecmp(optarg, "0"))
+ trace = PCAN_PARAMETER_OFF;
+ else if (!strcasecmp(optarg, "ON") || !strcasecmp(optarg, "YES") || !strcasecmp(optarg, "y") || !strcasecmp(optarg, "1"))
+ trace = PCAN_PARAMETER_ON;
+ else {
+ fprintf(stderr, "%s: illegal argument for option `--trace'\n", basename(argv[0]));
+ return 1;
+ }
+ break;
+ case 'a': /* option '--list-boards' (-a, deprecated) */
+ case 'L': /* option '--list-boards' (-L) */
+ fprintf(stdout, "%s\n%s\n\n%s\n\n", APPLICATION, COPYRIGHT, WARRANTY);
+ /* list all supported interfaces */
+ num_boards = list_interfaces();
+ fprintf(stdout, "Number of supported CAN interfaces=%i\n", num_boards);
+ return (num_boards >= 0) ? 0 : 1;
+ /* option '--test-boards' (-T) */
+ case 'T':
+ fprintf(stdout, "%s\n%s\n\n%s\n\n", APPLICATION, COPYRIGHT, WARRANTY);
+ /* list all available interfaces */
+ num_boards = test_interfaces();
+ fprintf(stdout, "Number of present CAN interfaces=%i\n", num_boards);
+ return (num_boards >= 0) ? 0 : 1;
+ /* option '--help' (-h) */
+ case 'h':
+ usage(stdout, basename(argv[0]));
+ return 0;
+ case '?':
+ if (!opterr)
+ usage(stderr, basename(argv[0]));
+ return 1;
+ default:
+ if (show_version) {
+ version(stdout, basename(argv[0]));
+ return 0;
+ }
+ else {
+ usage(stderr, basename(argv[0]));
+ return 1;
+ }
+ }
+ }
+ /* - check if one and only one is given */
+ if (optind + 1 != argc) {
+ if (optind == argc)
+ fprintf(stderr, "%s: no interface given\n", basename(argv[0]));
+ else
+ fprintf(stderr, "%s: too many arguments given\n", basename(argv[0]));
+ return 1;
+ }
+ /* - first search the by its name in the device list */
+ for (b = 0; b < PCAN_BOARDS; b++) {
+ if (strcasecmp(argv[optind], can_board[b].name) == 0) {
+ board = can_board[b].type;
+ break;
+ }
+ }
+ /* if not found, search the by its channel handle in the device list */
+ if (b >= PCAN_BOARDS) {
+ if (sscanf(argv[optind], "%li", &board) != 1) {
+ fprintf(stderr, "%s: illegal argument\n", basename(argv[0]));
+ return 1;
+ }
+ for (b = 0; b < PCAN_BOARDS; b++) {
+ if (board == (long)can_board[b].type)
+ break;
+ }
+ if (b >= PCAN_BOARDS) {
+ fprintf(stderr, "%s: illegal argument\n", basename(argv[0]));
+ return 1;
+ }
+ }
+ /* - check if a bit-rate string is given for CAN FD mode */
+ if ((op_mode & PCAN_MESSAGE_FD) && (bitrate == NULL)) {
+ fprintf(stderr, "%s: illegal combination of options `--mode' (m) and `--baudrate' (b)\n", basename(argv[0]));
+ return 1;
+ }
+ /* - check is a BTR0BTR1 value is given for CAN 2.0 mode */
+ if (!(op_mode & PCAN_MESSAGE_FD) && (baudrate == 0)) {
+ fprintf(stderr, "%s: illegal combination of options `--mode' (m) and `--bitrate'\n", basename(argv[0]));
+ return 1;
+ }
+ /* - check if DLC is less or equal to 8 for CAN 2.0 mode */
+ if (!(op_mode & PCAN_MESSAGE_FD) && (data > 8)) {
+ fprintf(stderr, "%s: illegal combination of options `--mode' (m) and `--dlc' (d)\n", basename(argv[0]));
+ return 1;
+ }
+ else {
+ if (data > 48) data = 0xF;
+ else if (data > 32) data = 0xE;
+ else if (data > 24) data = 0xD;
+ else if (data > 20) data = 0xC;
+ else if (data > 16) data = 0xB;
+ else if (data > 12) data = 0xA;
+ else if (data > 8) data = 0x9;
+ }
+ /* - check if monitor mode is not set for transmitter tests (we want to say something) */
+ if ((mode != RxMODE) && (listenonly)) {
+ fprintf(stderr, "%s: illegal option `--listen-only' for transmitter test\n", basename(argv[0]));
+ return 1;
+ }
+ /* CAN Tester for PCAN-USB interfaces */
+ fprintf(stdout, "%s\n%s\n\n%s\n\n", APPLICATION, COPYRIGHT, WARRANTY);
+ /* - show operation mode and bit-rate settings */
+ if (verbose) {
+ fprintf(stdout, "Op.-Mode=%s", (op_mode & PCAN_MESSAGE_FD) ? "CANFD" : "CAN2.0");
+ if ((op_mode & PCAN_MESSAGE_BRS)) fprintf(stdout, "+BRS");
+ fprintf(stdout, " (op_mode=%02Xh)\n", op_mode);
+ if ((op_mode & PCAN_MESSAGE_FD)) {
+ (void)btr_string_to_bit_timing(bitrate, &freq, &slow, &fast);
+ fprintf(stdout, "Bit-rate=%lukbps@%.1f%%",
+ btr_calc_bit_rate_nominal(&slow, freq),
+ btr_calc_sample_point_nominal(&slow) * 100.);
+ if ((op_mode & PCAN_MESSAGE_BRS))
+ fprintf(stdout, ":%lukbps@%.1f%%",
+ btr_calc_bit_rate_data(&fast, freq),
+ btr_calc_sample_point_data(&fast) * 100.);
+ fprintf(stdout, " (%s)\n\n", bitrate);
+ }
+ else {
+ fprintf(stdout, "Baudrate=%skbps (BTR0BTR1=%04lx)\n\n",
+ baudrate == PCAN_BAUD_1M ? "1000" :
+ baudrate == PCAN_BAUD_800K ? "800" :
+ baudrate == PCAN_BAUD_500K ? "500" :
+ baudrate == PCAN_BAUD_250K ? "250" :
+ baudrate == PCAN_BAUD_125K ? "125" :
+ baudrate == PCAN_BAUD_100K ? "100" :
+ baudrate == PCAN_BAUD_50K ? "50" :
+ baudrate == PCAN_BAUD_20K ? "20" :
+ baudrate == PCAN_BAUD_10K ? "10" : "?", baudrate);
+ }
+ }
+ /* - initialization */
+ fprintf(stdout, "Hardware=%s...", can_board[b].name);
+ fflush (stdout);
+ channel = (TPCANHandle)can_board[b].type;
+ if ((status = CAN_SetValue(channel, PCAN_LISTEN_ONLY, (void*)&listenonly, sizeof(listenonly))) != PCAN_ERROR_OK) {
+ fprintf(stdout, "FAILED!\n");
+ fprintf(stderr, "+++ error: CAN_SetValue PCAN-USB%u (PCAN_LISTEN_ONLY=%u) returned 0x%X\n", (channel - 0x50), listenonly, status);
+ return (int)status;;
+ }
+ if (!(op_mode & PCAN_MESSAGE_FD)) {
+ if ((status = CAN_Initialize(channel, (TPCANBaudrate)baudrate, PCAN_USB, 0, 0)) != PCAN_ERROR_OK) {
+ fprintf(stdout, "FAILED!\n");
+ fprintf(stderr, "+++ error: CAN_Initialize PCAN-USB%u returned 0x%X\n", (channel - 0x50), status);
+ return (int)status;;
+ }
+ fprintf(stdout, "OK!\nBaudrate=%lukbps...",
+ btr_calc_bit_rate_sja1000((unsigned short)baudrate) / 1000);
+ }
+ else {
+ if (!btr_string_to_bit_timing(bitrate, &freq, &slow, &fast)) {
+ fprintf(stdout, "FAILED!\n");
+ fprintf(stderr, "+++ error: CAN_InitializeFD PCAN-USB%u with wrong bit-rate\n", (channel - 0x50));
+ return (int)-1;
+ }
+ if ((status = CAN_InitializeFD(channel, bitrate)) != PCAN_ERROR_OK) {
+ fprintf(stdout, "FAILED!\n");
+ fprintf(stderr, "+++ error: CAN_InitializeFD PCAN-USB%u returned 0x%X\n", (channel - 0x50), status);
+ return (int)status;;
+ }
+ fprintf(stdout, "OK!\nBit-rate=%lukbps",
+ btr_calc_bit_rate_nominal(&slow, freq) / 1000);
+ if ((op_mode & PCAN_MESSAGE_BRS))
+ fprintf(stdout, ":%lukbps",
+ btr_calc_bit_rate_data(&fast, freq) / 1000);
+ fprintf(stdout, "...");
+ }
+ if ((status = CAN_SetValue(channel, PCAN_ALLOW_STATUS_FRAMES, (void*)&allow_sts, sizeof(allow_sts))) != PCAN_ERROR_OK) {
+ fprintf(stdout, "FAILED!\n");
+ fprintf(stderr, "+++ error: CAN_SetValue PCAN-USB%u (PCAN_ALLOW_STATUS_FRAMES=%u) returned 0x%X\n", (channel - 0x50), allow_sts, status);
+ (void)CAN_Uninitialize(channel);
+ return (int)status;;
+ }
+ if ((status = CAN_SetValue(channel, PCAN_ALLOW_RTR_FRAMES, (void*)&allow_rtr, sizeof(allow_rtr))) != PCAN_ERROR_OK) {
+ fprintf(stdout, "FAILED!\n");
+ fprintf(stderr, "+++ error: CAN_SetValue PCAN-USB%u (PCAN_ALLOW_RTR_FRAMES=%u) returned 0x%X\n", (channel - 0x50), allow_rtr, status);
+ (void)CAN_Uninitialize(channel);
+ return (int)status;;
+ }
+ if (trace != PCAN_PARAMETER_OFF) {
+ if (getcwd((char*)buffer, 256) == NULL) {
+ fprintf(stdout, "FAILED!\n");
+ perror("+++ error");
+ (void)CAN_Uninitialize(channel);
+ return (int)status;;
+ }
+ if ((status = CAN_SetValue(channel, PCAN_TRACE_LOCATION, (void*)buffer, 256U)) != PCAN_ERROR_OK) {
+ fprintf(stdout, "FAILED!\n");
+ fprintf(stderr, "+++ error: CAN_SetValue PCAN-USB%u (PCAN_TRACE_LOCATION=%s) returned 0x%X\n", (channel - 0x50), (char*)buffer, status);
+ (void)CAN_Uninitialize(channel);
+ return (int)status;;
+ }
+ buffer[0] = TRACE_FILE_SINGLE | TRACE_FILE_DATE | TRACE_FILE_TIME | TRACE_FILE_OVERWRITE;
+ if ((status = CAN_SetValue(channel, PCAN_TRACE_CONFIGURE, (void*)&buffer[0], sizeof(BYTE))) != PCAN_ERROR_OK) {
+ fprintf(stdout, "FAILED!\n");
+ fprintf(stderr, "+++ error: CAN_SetValue PCAN-USB%u (PCAN_TRACE_CONFIGURE=%X) returned 0x%X\n", (channel - 0x50), buffer[0], status);
+ (void)CAN_Uninitialize(channel);
+ return (int)status;;
+ }
+ if ((status = CAN_SetValue(channel, PCAN_TRACE_STATUS, (void*)&trace, sizeof(trace))) != PCAN_ERROR_OK) {
+ fprintf(stdout, "FAILED!\n");
+ fprintf(stderr, "+++ error: CAN_SetValue PCAN-USB%u (PCAN_TRACE_STATUS=%X) returned 0x%u\n", (channel - 0x50), trace, status);
+ (void)CAN_Uninitialize(channel);
+ return (int)status;;
+ }
+ }
+ fprintf(stdout, "OK!\n");
+ /* - do your job well: */
+ switch (mode) {
+ case TxMODE: /* transmitter test (duration) */
+ if (!(op_mode & PCAN_MESSAGE_FD))
+ tx_test(channel, op_mode, (uint32_t)can_id, (uint8_t)data, (uint32_t)delay, (time_t)txtime, (uint64_t)number);
+ else
+ tx_test_fd(channel, op_mode, (uint32_t)can_id, (uint8_t)data, (uint32_t)delay, (time_t)txtime, (uint64_t)number);
+ break;
+ case TxFRAMES: /* transmitter test (frames) */
+ if (!(op_mode & PCAN_MESSAGE_FD))
+ tx_frames(channel, op_mode, (uint32_t)can_id, (uint8_t)data, (uint32_t)delay, (uint64_t)txframes, (uint64_t)number);
+ else
+ tx_frames_fd(channel, op_mode, (uint32_t)can_id, (uint8_t)data, (uint32_t)delay, (uint64_t)txframes, (uint64_t)number);
+ break;
+ case TxRANDOM: /* transmitter test (random) */
+ if (!(op_mode & PCAN_MESSAGE_FD))
+ tx_random(channel, op_mode, (uint32_t)can_id, (uint8_t)data, (uint32_t)delay, (uint64_t)txframes, (uint64_t)number);
+ else
+ tx_random_fd(channel, op_mode, (uint32_t)can_id, (uint8_t)data, (uint32_t)delay, (uint64_t)txframes, (uint64_t)number);
+ break;
+ default: /* receiver test (abort with Ctrl+C) */
+ if (!(op_mode & PCAN_MESSAGE_FD))
+ rx_test(channel, n, (uint64_t)number, stop_on_error);
+ else
+ rx_test_fd(channel, n, (uint64_t)number, stop_on_error);
+ break;
+ }
+ /* - teardown */
+ if (CAN_GetValue(channel, PCAN_HARDWARE_NAME, buffer, 256) == PCAN_ERROR_OK) {
+ fprintf(stdout, "Hardware: %s", buffer);
+ if (CAN_GetValue(channel, PCAN_DEVICE_ID, (void*)&device_id, sizeof(DWORD)) == PCAN_ERROR_OK)
+ fprintf(stdout, " (DeviceId=0x%02"PRIx32")", device_id);
+ fprintf(stdout, "\n");
+ }
+ if (CAN_GetValue(channel, PCAN_CHANNEL_VERSION, buffer, 256) == PCAN_ERROR_OK) {
+ fprintf(stdout, "Firmware: %s\n", buffer);
+ }
+ if (CAN_GetValue(channel, PCAN_API_VERSION, buffer, 256) == PCAN_ERROR_OK) {
+ fprintf(stdout, "Software: API Version %s\n", buffer);
+ }
+ if ((status = CAN_Uninitialize(channel)) != PCAN_ERROR_OK) {
+ fprintf(stderr, "+++ error: CAN_Uninitialize PCAN-USB%u returned 0x%X\n", (channel - 0x50), status);
+ return (int)status;;
+ }
+ fprintf(stdout, "%s\n", COPYRIGHT);
+ return 0;
+}
+
+/* ----------- local functions ----------------------------------------
+ */
+static int list_interfaces(void)
+{
+ int i;
+
+ fprintf(stdout, "Supported hardware:\n");
+ for (i = 0; i < PCAN_BOARDS; i++) {
+ fprintf(stdout, "\"%s\" (VendorName=\"PEAK\", LibraryId=400, BoardType=%lxh)\n", can_board[i].name, can_board[i].type);
+ }
+ return i;
+}
+
+static int test_interfaces(void)
+{
+ TPCANStatus status;
+ int i, n = 0;
+ BYTE test;
+ DWORD device_id;
+
+ for (i = 0; i < PCAN_BOARDS; i++) {
+ if ((status = CAN_GetValue(PCAN_USBBUS1+i, PCAN_CHANNEL_CONDITION, &test, sizeof(BYTE))) == PCAN_ERROR_OK) {
+ if (test > PCAN_CHANNEL_UNAVAILABLE) {
+ fprintf(stdout, "Hardware=%s...", can_board[i].name);
+ fflush(stdout);
+ timer_delay(TIMER_MSEC(333));
+ fprintf(stdout, "%s", (test >= PCAN_CHANNEL_OCCUPIED) ? "occupied" : "available");
+ if (CAN_GetValue(PCAN_USBBUS1+i, PCAN_DEVICE_ID, (void*)&device_id, sizeof(DWORD)) == PCAN_ERROR_OK)
+ fprintf(stdout, " (DeviceId=0x%02"PRIx32")", device_id);
+ fprintf(stdout, "\n");
+ n++;
+ }
+ }
+ else {
+ fprintf(stderr, "+++ error: CAN_GetStatus PCAN_CHANNEL_CONDITION of PCAN-USB%i returned 0x%X\n", i+1, status);
+ return (-1);
+ }
+ }
+ if (n == 0) {
+ fprintf(stdout, "No hardware found!\n");
+ }
+ return n;
+}
+
+static uint64_t tx_random(TPCANHandle channel, BYTE mode, uint32_t can_id, uint8_t dlc, uint32_t delay, uint64_t number, uint64_t offset)
+{
+ time_t start = time(NULL);
+
+ TPCANStatus status;
+ TPCANMsg message;
+
+ uint64_t frames = 0;
+ uint64_t errors = 0;
+ uint64_t calls = 0;
+
+ uint8_t random_dlc = dlc;
+ uint32_t random_delay = delay;
+ const struct {
+ uint32_t delay;
+ int counter;
+ } random_mess[13] = {
+ { TIMER_USEC(100), (385 * 10) },
+ { TIMER_USEC(250), (238 * 10) },
+ { TIMER_USEC(500), (147 * 10) },
+ { TIMER_USEC(714), (91 * 10) },
+ { TIMER_USEC(1000), (56 * 10) },
+ { TIMER_USEC(1667), (35 * 10) },
+ { TIMER_USEC(2500), (21 * 10) },
+ { TIMER_USEC(5000), (13 * 10) },
+ { TIMER_USEC(7143), (8 * 10) },
+ { TIMER_USEC(10000), (5 * 10) },
+ { TIMER_USEC(16667), (3 * 10) },
+ { TIMER_USEC(25000), (2 * 10) },
+ { TIMER_USEC(50000), (1 * 10) }
+ };
+ int index = 6, counter = 13;
+ srand((unsigned int)time(NULL));
+
+ fprintf(stderr, "\nPress ^C to abort.\n");
+ message.ID = (DWORD)can_id;
+ message.LEN = (BYTE)dlc;
+ message.MSGTYPE = (TPCANMessageType)mode;
+ fprintf(stdout, "\nTransmitting message(s)...");
+ fflush (stdout);
+ while (frames < number) {
+ message.DATA[0] = (BYTE)((frames + offset) >> 0);
+ message.DATA[1] = (BYTE)((frames + offset) >> 8);
+ message.DATA[2] = (BYTE)((frames + offset) >> 16);
+ message.DATA[3] = (BYTE)((frames + offset) >> 24);
+ message.DATA[4] = (BYTE)((frames + offset) >> 32);
+ message.DATA[5] = (BYTE)((frames + offset) >> 40);
+ message.DATA[6] = (BYTE)((frames + offset) >> 48);
+ message.DATA[7] = (BYTE)((frames + offset) >> 56);
+ //memset(&message.DATA[8], 0, 8 - 8);
+ message.LEN = (BYTE)(random_dlc < dlc) ? dlc : random_dlc;
+ /* transmit message (repeat when busy) */
+retry_tx_random:
+ calls++;
+ if ((status = CAN_Write(channel, &message)) == PCAN_ERROR_OK)
+ fprintf(stderr, "%s", prompt[(frames++ % 4)]);
+ else if ((status == PCAN_ERROR_QXMTFULL) && running)
+ goto retry_tx_random;
+ else
+ errors++;
+ /* pause between two messages, as you please */
+ if (random_delay < TIMER_MSEC(10)) {
+ timer_restart(TIMER_GPT0, random_delay);
+ while (!timer_timeout(TIMER_GPT0)) {
+ if (!running) {
+ fprintf(stderr, "\b");
+ fprintf(stdout, "STOP!\n\n");
+ fprintf(stdout, "Message(s)=%"PRIu64"\n", frames);
+ fprintf(stdout, "Error(s)=%"PRIu64"\n", errors);
+ fprintf(stdout, "Call(s)=%"PRIu64"\n", calls);
+ fprintf(stdout, "Time=%lisec\n\n", time(NULL) - start);
+ return frames;
+ }
+ }
+ }
+ else /* suspend our thread! */
+ timer_delay(random_delay);
+ if (!running) {
+ fprintf(stderr, "\b");
+ fprintf(stdout, "STOP!\n\n");
+ fprintf(stdout, "Message(s)=%"PRIu64"\n", frames);
+ fprintf(stdout, "Error(s)=%"PRIu64"\n", errors);
+ fprintf(stdout, "Call(s)=%"PRIu64"\n", calls);
+ fprintf(stdout, "Time=%lisec\n\n", time(NULL) - start);
+ return frames;
+ }
+ /* ramdom delay and length */
+ if (!counter--) {
+ index = rand() % 13; // index {0..12}
+ counter = random_mess[index].counter;
+ }
+ random_delay = (random_mess[index].delay < delay) ? delay : random_mess[index].delay;
+ random_dlc = (BYTE)(rand() % (8 + 1));
+ }
+ fprintf(stderr, "\b");
+ fprintf(stdout, "OK!\n\n");
+ fprintf(stdout, "Message(s)=%"PRIu64"\n", frames);
+ fprintf(stdout, "Error(s)=%"PRIu64"\n", errors);
+ fprintf(stdout, "Call(s)=%"PRIu64"\n", calls);
+ fprintf(stdout, "Time=%lisec\n\n", time(NULL) - start);
+
+ timer_delay(TIMER_SEC(1)); // afterburner
+ return frames;
+}
+
+static uint64_t tx_frames(TPCANHandle channel, BYTE mode, uint32_t can_id, uint8_t dlc, uint32_t delay, uint64_t number, uint64_t offset)
+{
+ time_t start = time(NULL);
+
+ TPCANStatus status;
+ TPCANMsg message;
+
+ uint64_t frames = 0;
+ uint64_t errors = 0;
+ uint64_t calls = 0;
+
+ fprintf(stderr, "\nPress ^C to abort.\n");
+ message.ID = (DWORD)can_id;
+ message.LEN = (BYTE)dlc;
+ message.MSGTYPE = (TPCANMessageType)mode;
+ fprintf(stdout, "\nTransmitting message(s)...");
+ fflush (stdout);
+ while (frames < number) {
+ message.DATA[0] = (BYTE)((frames + offset) >> 0);
+ message.DATA[1] = (BYTE)((frames + offset) >> 8);
+ message.DATA[2] = (BYTE)((frames + offset) >> 16);
+ message.DATA[3] = (BYTE)((frames + offset) >> 24);
+ message.DATA[4] = (BYTE)((frames + offset) >> 32);
+ message.DATA[5] = (BYTE)((frames + offset) >> 40);
+ message.DATA[6] = (BYTE)((frames + offset) >> 48);
+ message.DATA[7] = (BYTE)((frames + offset) >> 56);
+ //memset(&message.DATA[8], 0, 8 - 8);
+ /* transmit message (repeat when busy) */
+retry_tx_frames:
+ calls++;
+ if ((status = CAN_Write(channel, &message)) == PCAN_ERROR_OK)
+ fprintf(stderr, "%s", prompt[(frames++ % 4)]);
+ else if ((status == PCAN_ERROR_QXMTFULL) && running)
+ goto retry_tx_frames;
+ else
+ errors++;
+ /* pause between two messages, as you please */
+ timer_delay(TIMER_USEC(delay));
+ if (!running) {
+ fprintf(stderr, "\b");
+ fprintf(stdout, "STOP!\n\n");
+ fprintf(stdout, "Message(s)=%"PRIu64"\n", frames);
+ fprintf(stdout, "Error(s)=%"PRIu64"\n", errors);
+ fprintf(stdout, "Call(s)=%"PRIu64"\n", calls);
+ fprintf(stdout, "Time=%lisec\n\n", time(NULL) - start);
+ return frames;
+ }
+ }
+ fprintf(stderr, "\b");
+ fprintf(stdout, "OK!\n\n");
+ fprintf(stdout, "Message(s)=%"PRIu64"\n", frames);
+ fprintf(stdout, "Error(s)=%"PRIu64"\n", errors);
+ fprintf(stdout, "Call(s)=%"PRIu64"\n", calls);
+ fprintf(stdout, "Time=%lisec\n\n", time(NULL) - start);
+
+ timer_delay(TIMER_SEC(1)); // afterburner
+ return frames;
+}
+
+static uint64_t tx_test(TPCANHandle channel, BYTE mode, uint32_t can_id, uint8_t dlc, uint32_t delay, time_t duration, uint64_t offset)
+{
+ time_t start = time(NULL);
+
+ TPCANStatus status;
+ TPCANMsg message;
+
+ uint64_t frames = 0;
+ uint64_t errors = 0;
+ uint64_t calls = 0;
+
+ fprintf(stderr, "\nPress ^C to abort.\n");
+ message.ID = (DWORD)can_id;
+ message.LEN = (BYTE)dlc;
+ message.MSGTYPE = (TPCANMessageType)mode;
+ fprintf(stdout, "\nTransmitting message(s)...");
+ fflush (stdout);
+ while (time(NULL) < (start + duration)) {
+ message.DATA[0] = (BYTE)((frames + offset) >> 0);
+ message.DATA[1] = (BYTE)((frames + offset) >> 8);
+ message.DATA[2] = (BYTE)((frames + offset) >> 16);
+ message.DATA[3] = (BYTE)((frames + offset) >> 24);
+ message.DATA[4] = (BYTE)((frames + offset) >> 32);
+ message.DATA[5] = (BYTE)((frames + offset) >> 40);
+ message.DATA[6] = (BYTE)((frames + offset) >> 48);
+ message.DATA[7] = (BYTE)((frames + offset) >> 56);
+ //memset(&message.DATA[8], 0, 8 - 8);
+ /* transmit message (repeat when busy) */
+retry_tx_test:
+ calls++;
+ if ((status = CAN_Write(channel, &message)) == PCAN_ERROR_OK)
+ fprintf(stderr, "%s", prompt[(frames++ % 4)]);
+ else if ((status == PCAN_ERROR_QXMTFULL) && running)
+ goto retry_tx_test;
+ else
+ errors++;
+ /* pause between two messages, as you please */
+ timer_delay(TIMER_USEC(delay));
+ if (!running) {
+ fprintf(stderr, "\b");
+ fprintf(stdout, "STOP!\n\n");
+ fprintf(stdout, "Message(s)=%"PRIu64"\n", frames);
+ fprintf(stdout, "Error(s)=%"PRIu64"\n", errors);
+ fprintf(stdout, "Call(s)=%"PRIu64"\n", calls);
+ fprintf(stdout, "Time=%lisec\n\n", time(NULL) - start);
+ return frames;
+ }
+ }
+ fprintf(stderr, "\b");
+ fprintf(stdout, "OK!\n\n");
+ fprintf(stdout, "Message(s)=%"PRIu64"\n", frames);
+ fprintf(stdout, "Error(s)=%"PRIu64"\n", errors);
+ fprintf(stdout, "Call(s)=%"PRIu64"\n", calls);
+ fprintf(stdout, "Time=%lisec\n\n", time(NULL) - start);
+
+ timer_delay(TIMER_SEC(1)); // afterburner
+ return frames;
+}
+
+static uint64_t rx_test(TPCANHandle channel, int check, uint64_t number, int stop_on_error)
+{
+ time_t start = time(NULL);
+
+ TPCANStatus status;
+ TPCANMsg message;
+ TPCANTimestamp timestamp;
+
+ uint64_t frames = 0;
+ uint64_t errors = 0;
+ uint64_t calls = 0;
+ uint64_t data;
+
+#ifdef BLOCKING_READ
+ int fdes = -1;
+
+ if ((status = CAN_GetValue(channel, PCAN_RECEIVE_EVENT, &fdes, sizeof(int))) != PCAN_ERROR_OK) {
+ fprintf(stderr, "+++ error: CAN_GetValue PCAN_RECEIVE_EVENT returned 0x%X\n", status);
+ return 0;;
+ }
+ fd_set rdfs;
+ FD_ZERO(&rdfs);
+ FD_SET(fdes, &rdfs);
+#endif
+ fprintf(stderr, "\nPress ^C to abort.\n");
+ fprintf(stdout, "\nReceiving message(s)...");
+ fflush (stdout);
+ for (;;) {
+ if ((status = CAN_Read(channel, &message, ×tamp)) == PCAN_ERROR_OK) {
+ if (!(message.MSGTYPE & PCAN_MESSAGE_STATUS)) {
+ if (check) {
+ data = 0;
+ if (message.LEN > 0)
+ data |= (uint64_t)message.DATA[0] << 0;
+ if (message.LEN > 1)
+ data |= (uint64_t)message.DATA[1] << 8;
+ if (message.LEN > 2)
+ data |= (uint64_t)message.DATA[2] << 16;
+ if (message.LEN > 3)
+ data |= (uint64_t)message.DATA[3] << 24;
+ if (message.LEN > 4)
+ data |= (uint64_t)message.DATA[4] << 32;
+ if (message.LEN > 5)
+ data |= (uint64_t)message.DATA[5] << 40;
+ if (message.LEN > 6)
+ data |= (uint64_t)message.DATA[6] << 48;
+ if (message.LEN > 7)
+ data |= (uint64_t)message.DATA[7] << 56;
+ if (data != number) {
+ fprintf(stderr, "\b");
+ fprintf(stdout, "FAILED!\n\n");
+ fprintf(stderr, "+++ error: data inconsistent - %"PRIu64" received / %"PRIu64" expected\n", data, number);
+ if (stop_on_error) {
+ fprintf(stdout, "Message(s)=%"PRIu64"\n", frames);
+ fprintf(stdout, "Error(s)=%"PRIu64"\n", errors);
+ fprintf(stdout, "Call(s)=%"PRIu64"\n", calls);
+ fprintf(stdout, "Time=%lisec\n\n", time(NULL) - start);
+ return frames+1;
+ }
+ else {
+ fprintf(stderr, "... ");
+ number = data;
+ }
+ }
+ number++; // depending on DLC received data may wrap around while number is counting up!
+ }
+ fprintf(stderr, "%s", prompt[(frames++ % 4)]);
+ }
+ else
+ errors++;
+ }
+ else if (status != PCAN_ERROR_QRCVEMPTY)
+ errors++;
+ else
+#ifdef BLOCKING_READ
+ select(fdes+1, &rdfs, NULL, NULL, NULL);
+#else
+ timer_delay(1);
+#endif
+ calls++;
+ if (!running) {
+ fprintf(stderr, "\b");
+ fprintf(stdout, "OK!\n\n");
+ fprintf(stdout, "Message(s)=%"PRIu64"\n", frames);
+ fprintf(stdout, "Error(s)=%"PRIu64"\n", errors);
+ fprintf(stdout, "Call(s)=%"PRIu64"\n", calls);
+ fprintf(stdout, "Time=%lisec\n\n", time(NULL) - start);
+ return frames;
+ }
+ }
+ return frames;
+}
+
+static uint64_t tx_random_fd(TPCANHandle channel, BYTE mode, uint32_t can_id, uint8_t dlc, uint32_t delay, uint64_t number, uint64_t offset)
+{
+ time_t start = time(NULL);
+
+ TPCANStatus status;
+ TPCANMsgFD message;
+
+ uint64_t frames = 0;
+ uint64_t errors = 0;
+ uint64_t calls = 0;
+
+ uint8_t random_dlc = dlc;
+ uint32_t random_delay = delay;
+ const struct {
+ uint32_t delay;
+ int counter;
+ } random_mess[13] = {
+ { TIMER_USEC(100), (385 * 10) },
+ { TIMER_USEC(250), (238 * 10) },
+ { TIMER_USEC(500), (147 * 10) },
+ { TIMER_USEC(714), (91 * 10) },
+ { TIMER_USEC(1000), (56 * 10) },
+ { TIMER_USEC(1667), (35 * 10) },
+ { TIMER_USEC(2500), (21 * 10) },
+ { TIMER_USEC(5000), (13 * 10) },
+ { TIMER_USEC(7143), (8 * 10) },
+ { TIMER_USEC(10000), (5 * 10) },
+ { TIMER_USEC(16667), (3 * 10) },
+ { TIMER_USEC(25000), (2 * 10) },
+ { TIMER_USEC(50000), (1 * 10) }
+ };
+ int index = 6, counter = 13;
+ srand((unsigned int)time(NULL));
+
+ fprintf(stderr, "\nPress ^C to abort.\n");
+ message.ID = (DWORD)can_id;
+ message.DLC = (BYTE)dlc;
+ message.MSGTYPE = (TPCANMessageType)mode;
+ fprintf(stdout, "\nTransmitting message(s)...");
+ fflush (stdout);
+ while (frames < number) {
+ message.DATA[0] = (BYTE)((frames + offset) >> 0);
+ message.DATA[1] = (BYTE)((frames + offset) >> 8);
+ message.DATA[2] = (BYTE)((frames + offset) >> 16);
+ message.DATA[3] = (BYTE)((frames + offset) >> 24);
+ message.DATA[4] = (BYTE)((frames + offset) >> 32);
+ message.DATA[5] = (BYTE)((frames + offset) >> 40);
+ message.DATA[6] = (BYTE)((frames + offset) >> 48);
+ message.DATA[7] = (BYTE)((frames + offset) >> 56);
+ memset(&message.DATA[8], (frames & 1) ? 0x55 : 0xAA, 64 - 8);
+ message.DLC = (random_dlc < dlc) ? dlc : random_dlc;
+ /* transmit message (repeat when busy) */
+retry_tx_random_fd:
+ calls++;
+ if ((status = CAN_WriteFD(channel, &message)) == PCAN_ERROR_OK)
+ fprintf(stderr, "%s", prompt[(frames++ % 4)]);
+ else if ((status == PCAN_ERROR_QXMTFULL) && running)
+ goto retry_tx_random_fd;
+ else
+ errors++;
+ /* pause between two messages, as you please */
+ if (random_delay < TIMER_MSEC(10)) {
+ timer_restart(TIMER_GPT0, random_delay);
+ while (!timer_timeout(TIMER_GPT0)) {
+ if (!running) {
+ fprintf(stderr, "\b");
+ fprintf(stdout, "STOP!\n\n");
+ fprintf(stdout, "Message(s)=%"PRIu64"\n", frames);
+ fprintf(stdout, "Error(s)=%"PRIu64"\n", errors);
+ fprintf(stdout, "Call(s)=%"PRIu64"\n", calls);
+ fprintf(stdout, "Time=%lisec\n\n", time(NULL) - start);
+ return frames;
+ }
+ }
+ }
+ else /* suspend our thread! */
+ timer_delay(random_delay);
+ if (!running) {
+ fprintf(stderr, "\b");
+ fprintf(stdout, "STOP!\n\n");
+ fprintf(stdout, "Message(s)=%"PRIu64"\n", frames);
+ fprintf(stdout, "Error(s)=%"PRIu64"\n", errors);
+ fprintf(stdout, "Call(s)=%"PRIu64"\n", calls);
+ fprintf(stdout, "Time=%lisec\n\n", time(NULL) - start);
+ return frames;
+ }
+ /* ramdom delay and length */
+ if (!counter--) {
+ index = rand() % 13; // index {0..12}
+ counter = random_mess[index].counter;
+ }
+ random_delay = (random_mess[index].delay < delay) ? delay : random_mess[index].delay;
+ random_dlc = (BYTE)(rand() % (15 + 1));
+ }
+ fprintf(stderr, "\b");
+ fprintf(stdout, "OK!\n\n");
+ fprintf(stdout, "Message(s)=%"PRIu64"\n", frames);
+ fprintf(stdout, "Error(s)=%"PRIu64"\n", errors);
+ fprintf(stdout, "Call(s)=%"PRIu64"\n", calls);
+ fprintf(stdout, "Time=%lisec\n\n", time(NULL) - start);
+
+ timer_delay(TIMER_SEC(1)); // afterburner
+ return frames;
+}
+
+static uint64_t tx_frames_fd(TPCANHandle channel, BYTE mode, uint32_t can_id, uint8_t dlc, uint32_t delay, uint64_t number, uint64_t offset)
+{
+ time_t start = time(NULL);
+
+ TPCANStatus status;
+ TPCANMsgFD message;
+
+ uint64_t frames = 0;
+ uint64_t errors = 0;
+ uint64_t calls = 0;
+
+ fprintf(stderr, "\nPress ^C to abort.\n");
+ message.ID = (DWORD)can_id;
+ message.DLC = (BYTE)dlc;
+ message.MSGTYPE = (TPCANMessageType)mode;
+ fprintf(stdout, "\nTransmitting message(s)...");
+ fflush (stdout);
+ while (frames < number) {
+ message.DATA[0] = (BYTE)((frames + offset) >> 0);
+ message.DATA[1] = (BYTE)((frames + offset) >> 8);
+ message.DATA[2] = (BYTE)((frames + offset) >> 16);
+ message.DATA[3] = (BYTE)((frames + offset) >> 24);
+ message.DATA[4] = (BYTE)((frames + offset) >> 32);
+ message.DATA[5] = (BYTE)((frames + offset) >> 40);
+ message.DATA[6] = (BYTE)((frames + offset) >> 48);
+ message.DATA[7] = (BYTE)((frames + offset) >> 56);
+ memset(&message.DATA[8], 0, 64 - 8);
+ /* transmit message (repeat when busy) */
+retry_tx_frames_fd:
+ calls++;
+ if ((status = CAN_WriteFD(channel, &message)) == PCAN_ERROR_OK)
+ fprintf(stderr, "%s", prompt[(frames++ % 4)]);
+ else if ((status == PCAN_ERROR_QXMTFULL) && running)
+ goto retry_tx_frames_fd;
+ else
+ errors++;
+ /* pause between two messages, as you please */
+ timer_delay(TIMER_USEC(delay));
+ if (!running) {
+ fprintf(stderr, "\b");
+ fprintf(stdout, "STOP!\n\n");
+ fprintf(stdout, "Message(s)=%"PRIu64"\n", frames);
+ fprintf(stdout, "Error(s)=%"PRIu64"\n", errors);
+ fprintf(stdout, "Call(s)=%"PRIu64"\n", calls);
+ fprintf(stdout, "Time=%lisec\n\n", time(NULL) - start);
+ return frames;
+ }
+ }
+ fprintf(stderr, "\b");
+ fprintf(stdout, "OK!\n\n");
+ fprintf(stdout, "Message(s)=%"PRIu64"\n", frames);
+ fprintf(stdout, "Error(s)=%"PRIu64"\n", errors);
+ fprintf(stdout, "Call(s)=%"PRIu64"\n", calls);
+ fprintf(stdout, "Time=%lisec\n\n", time(NULL) - start);
+
+ timer_delay(TIMER_SEC(1)); // afterburner
+ return frames;
+}
+
+static uint64_t tx_test_fd(TPCANHandle channel, BYTE mode, uint32_t can_id, uint8_t dlc, uint32_t delay, time_t duration, uint64_t offset)
+{
+ time_t start = time(NULL);
+
+ TPCANStatus status;
+ TPCANMsgFD message;
+
+ uint64_t frames = 0;
+ uint64_t errors = 0;
+ uint64_t calls = 0;
+
+ fprintf(stderr, "\nPress ^C to abort.\n");
+ message.ID = (DWORD)can_id;
+ message.DLC = (BYTE)dlc;
+ message.MSGTYPE = (TPCANMessageType)mode;
+ fprintf(stdout, "\nTransmitting message(s)...");
+ fflush (stdout);
+ while (time(NULL) < (start + duration)) {
+ message.DATA[0] = (BYTE)((frames + offset) >> 0);
+ message.DATA[1] = (BYTE)((frames + offset) >> 8);
+ message.DATA[2] = (BYTE)((frames + offset) >> 16);
+ message.DATA[3] = (BYTE)((frames + offset) >> 24);
+ message.DATA[4] = (BYTE)((frames + offset) >> 32);
+ message.DATA[5] = (BYTE)((frames + offset) >> 40);
+ message.DATA[6] = (BYTE)((frames + offset) >> 48);
+ message.DATA[7] = (BYTE)((frames + offset) >> 56);
+ memset(&message.DATA[8], 0, 64 - 8);
+ /* transmit message (repeat when busy) */
+retry_tx_test_fd:
+ calls++;
+ if ((status = CAN_WriteFD(channel, &message)) == PCAN_ERROR_OK)
+ fprintf(stderr, "%s", prompt[(frames++ % 4)]);
+ else if ((status == PCAN_ERROR_QXMTFULL) && running)
+ goto retry_tx_test_fd;
+ else
+ errors++;
+ /* pause between two messages, as you please */
+ timer_delay(TIMER_USEC(delay));
+ if (!running) {
+ fprintf(stderr, "\b");
+ fprintf(stdout, "STOP!\n\n");
+ fprintf(stdout, "Message(s)=%"PRIu64"\n", frames);
+ fprintf(stdout, "Error(s)=%"PRIu64"\n", errors);
+ fprintf(stdout, "Call(s)=%"PRIu64"\n", calls);
+ fprintf(stdout, "Time=%lisec\n\n", time(NULL) - start);
+ return frames;
+ }
+ }
+ fprintf(stderr, "\b");
+ fprintf(stdout, "OK!\n\n");
+ fprintf(stdout, "Message(s)=%"PRIu64"\n", frames);
+ fprintf(stdout, "Error(s)=%"PRIu64"\n", errors);
+ fprintf(stdout, "Call(s)=%"PRIu64"\n", calls);
+ fprintf(stdout, "Time=%lisec\n\n", time(NULL) - start);
+
+ timer_delay(TIMER_SEC(1)); // afterburner
+ return frames;
+}
+
+static uint64_t rx_test_fd(TPCANHandle channel, int check, uint64_t number, int stop_on_error)
+{
+ time_t start = time(NULL);
+
+ TPCANStatus status;
+ TPCANMsgFD message;
+ TPCANTimestampFD timestamp;
+
+ uint64_t frames = 0;
+ uint64_t errors = 0;
+ uint64_t calls = 0;
+ uint64_t data;
+
+#ifdef BLOCKING_READ
+ int fdes = -1;
+
+ if ((status = CAN_GetValue(channel, PCAN_RECEIVE_EVENT, &fdes, sizeof(int))) != PCAN_ERROR_OK) {
+ fprintf(stderr, "+++ error: CAN_GetValue PCAN_RECEIVE_EVENT returned 0x%X\n", status);
+ return 0;;
+ }
+ fd_set rdfs;
+ FD_ZERO(&rdfs);
+ FD_SET(fdes, &rdfs);
+#endif
+ fprintf(stderr, "\nPress ^C to abort.\n");
+ fprintf(stdout, "\nReceiving message(s)...");
+ fflush (stdout);
+ for (;;) {
+ if ((status = CAN_ReadFD(channel, &message, ×tamp)) == PCAN_ERROR_OK) {
+ if (!(message.MSGTYPE & PCAN_MESSAGE_STATUS)) {
+ if (check) {
+ data = 0;
+ if (message.DLC > 0)
+ data |= (uint64_t)message.DATA[0] << 0;
+ if (message.DLC > 1)
+ data |= (uint64_t)message.DATA[1] << 8;
+ if (message.DLC > 2)
+ data |= (uint64_t)message.DATA[2] << 16;
+ if (message.DLC > 3)
+ data |= (uint64_t)message.DATA[3] << 24;
+ if (message.DLC > 4)
+ data |= (uint64_t)message.DATA[4] << 32;
+ if (message.DLC > 5)
+ data |= (uint64_t)message.DATA[5] << 40;
+ if (message.DLC > 6)
+ data |= (uint64_t)message.DATA[6] << 48;
+ if (message.DLC > 7)
+ data |= (uint64_t)message.DATA[7] << 56;
+ if (data != number) {
+ fprintf(stderr, "\b");
+ fprintf(stdout, "FAILED!\n\n");
+ fprintf(stderr, "+++ error: data inconsistent - %"PRIu64" received / %"PRIu64" expected\n", data, number);
+ if (stop_on_error) {
+ fprintf(stdout, "Message(s)=%"PRIu64"\n", frames);
+ fprintf(stdout, "Error(s)=%"PRIu64"\n", errors);
+ fprintf(stdout, "Call(s)=%"PRIu64"\n", calls);
+ fprintf(stdout, "Time=%lisec\n\n", time(NULL) - start);
+ return frames+1;
+ }
+ else {
+ fprintf(stderr, "... ");
+ number = data;
+ }
+ }
+ number++; // depending on DLC received data may wrap around while number is counting up!
+ }
+ fprintf(stderr, "%s", prompt[(frames++ % 4)]);
+ }
+ else
+ errors++;
+ }
+ else if (status != PCAN_ERROR_QRCVEMPTY)
+ errors++;
+ else
+#ifdef BLOCKING_READ
+ select(fdes+1, &rdfs, NULL, NULL, NULL);
+#else
+ timer_delay(1);
+#endif
+ calls++;
+ if (!running) {
+ fprintf(stderr, "\b");
+ fprintf(stdout, "OK!\n\n");
+ fprintf(stdout, "Message(s)=%"PRIu64"\n", frames);
+ fprintf(stdout, "Error(s)=%"PRIu64"\n", errors);
+ fprintf(stdout, "Call(s)=%"PRIu64"\n", calls);
+ fprintf(stdout, "Time=%lisec\n\n", time(NULL) - start);
+ return frames;
+ }
+ }
+ return frames;
+}
+
+static void sigterm(int signo)
+{
+ //fprintf(stderr, "%s: got signal %d\n", __FILE__, signo);
+ running = 0;
+ (void)signo;
+}
+
+static void usage(FILE *stream, const char *program)
+{
+ fprintf(stdout, "%s\n%s\n\n%s\n\n", APPLICATION, COPYRIGHT, WARRANTY);
+ fprintf(stream, "Usage: %s [...]\n", program);
+ fprintf(stream, "Options for receiver test (default):\n");
+ fprintf(stream, " -r, --receive count received messages until ^C is pressed\n");
+ fprintf(stream, " -n, --number= check up-counting numbers starting with \n");
+ fprintf(stream, " -s, --stop stop on error (with option --number)\n");
+ fprintf(stream, " -m, --mode=(2.0|FDF[+BRS]) CAN operation mode: CAN 2.0 or CAN FD format\n");
+ fprintf(stream, " --listen-only monitor mode (transmitter is off)\n");
+ fprintf(stream, " --no-status-frames suppress reception of status frames\n");
+ fprintf(stream, " --no-remote-frames suppress reception of remote frames\n");
+ fprintf(stream, " -b, --baudrate= CAN 2.0 bit timing in kbps (default=250)\n");
+ fprintf(stream, " --bitrate= CAN FD bit rate (as a string)\n");
+ fprintf(stream, " -v, --verbose show detailed bit rate settings\n");
+ fprintf(stream, " -y, --trace=(ON|OFF) write a trace file (default=OFF)\n");
+ fprintf(stream, "Options for transmitter test:\n");
+ fprintf(stream, " -t, --transmit= send messages for the given time in seconds, or\n");
+ fprintf(stream, " -f, --frames=, alternatively send the given number of messages, or\n");
+ fprintf(stream, " --random= optionally with random cycle time and data length\n");
+ fprintf(stream, " -c, --cycle= cycle time in milliseconds (default=0) or\n");
+ fprintf(stream, " -u, --usec= cycle time in microseconds (default=0)\n");
+ fprintf(stream, " -d, --dlc= send messages of given length (default=8)\n");
+ fprintf(stream, " -i, --id= use given identifier (default=100h)\n");
+ fprintf(stream, " -n, --number= set first up-counting number (default=0)\n");
+ fprintf(stream, " -m, --mode=(2.0|FDF[+BRS]) CAN operation mode: CAN 2.0 or CAN FD format\n");
+ fprintf(stream, " -b, --baudrate= CAN 2.0 bit timing in kbps (default=250)\n");
+ fprintf(stream, " --bitrate= CAN FD bit rate (as a string)\n");
+ fprintf(stream, " -v, --verbose show detailed bit rate settings\n");
+ fprintf(stream, " -y, --trace=(ON|OFF) write a trace file (default=OFF)\n");
+ fprintf(stream, "Options:\n");
+ fprintf(stream, " -L, --list-boards list all supported CAN interfaces and exit\n");
+ fprintf(stream, " -T, --test-boards list all available CAN interfaces and exit\n");
+ fprintf(stream, " -h, --help display this help screen and exit\n");
+ fprintf(stream, " --version show version information and exit\n");
+ fprintf(stream, "Hazard note:\n");
+ fprintf(stream, " If you connect your CAN device to a real CAN network when using this program,\n");
+ fprintf(stream, " you might damage your application.\n");
+}
+
+static void version(FILE *stream, const char *program)
+{
+ fprintf(stdout, "%s\n%s\n\n%s\n\n", APPLICATION, COPYRIGHT, LICENSE);
+ (void)program;
+ fprintf(stream, "Written by Uwe Vogt, UV Software, Berlin \n");
+}
+
+/* ----------------------------------------------------------------------
+ * Uwe Vogt, UV Software, Chausseestrasse 33 A, 10115 Berlin, Germany
+ * Tel.: +49-30-46799872, Fax: +49-30-46799873, Mobile: +49-170-3801903
+ * E-Mail: uwe.vogt@uv-software.de, Homepage: http://www.uv-software.de/
+ */
diff --git a/Utilities/misc/.gitignore b/Utilities/misc/.gitignore
new file mode 100644
index 0000000..0bc34d2
--- /dev/null
+++ b/Utilities/misc/.gitignore
@@ -0,0 +1,4 @@
+# ignore the unneeded stuff from svn
+dosopt.*
+tester.c
+update.xml
diff --git a/Utilities/misc/bitrates.c b/Utilities/misc/bitrates.c
new file mode 100644
index 0000000..4c40f51
--- /dev/null
+++ b/Utilities/misc/bitrates.c
@@ -0,0 +1,667 @@
+/* -- $HeadURL: https://svn.uv-software.net/projects/uv-software/CAN/I386/DRV/trunk/API/misc/bitrates.c $ --
+ *
+ * project : CAN - Controller Area Network
+ *
+ * purpose : CAN FD Bit-rates (Converter)
+ *
+ * copyright : (C) 2017-2023, UV Software, Berlin
+ *
+ * compiler : Microsoft Visual C/C++ Compiler
+ * Apple LLVM (clang) Compiler
+ * GNU C/C++ Compiler
+ *
+ * export : (see header file)
+ *
+ * includes : bitrates.h
+ *
+ * author : Uwe Vogt, UV Software
+ *
+ * e-mail : uwe.vogt@uv-software.de
+ *
+ *
+ * ----------- description --------------------------------------------
+ */
+/** @file bitrates.c
+ *
+ * @brief CAN FD Bit-rates (Converter)
+ *
+ * @author $Author: makemake $
+ *
+ * @version $Rev: 1089 $
+ *
+ * @addtogroup bit_rate
+ * @{
+ */
+
+/* ----------- includes -----------------------------------------------
+ */
+
+#include "bitrates.h"
+
+#include
+#include
+#include
+#include
+
+
+/* ----------- defines ------------------------------------------------
+ */
+
+#define BTR_FREQUENCY_MIN BTR_FREQUENCY_SJA1000
+#define BTR_FREQUENCY_MAX (1000000000ul)
+#define BTR_FREQUENCY_MHZ_MIN (BTR_FREQUENCY_MIN / 1000000ul)
+#define BTR_FREQUENCY_MHZ_MAX (BTR_FREQUENCY_MAX / 1000000ul)
+
+#define BTR_SJA1000_BRP_MIN (1u)
+#define BTR_SJA1000_BRP_MAX (64u)
+#define BTR_SJA1000_TSEG1_MIN (1u)
+#define BTR_SJA1000_TSEG1_MAX (16u)
+#define BTR_SJA1000_TSEG2_MIN (1u)
+#define BTR_SJA1000_TSEG2_MAX (8u)
+#define BTR_SJA1000_SJW_MIN (1u)
+#define BTR_SJA1000_SJW_MAX (4u)
+#define BTR_SJA1000_SAM_MIN (0u)
+#define BTR_SJA1000_SAM_MAX (1u)
+#define BTR_SJA1000_SP_MIN (0.20)
+#define BTR_SJA1000_SP_MAX (0.95)
+
+#define BTR_NOMINAL_BRP_MIN (1u)
+#define BTR_NOMINAL_BRP_MAX (1024u)
+#define BTR_NOMINAL_TSEG1_MIN (1u)
+#define BTR_NOMINAL_TSEG1_MAX (256u)
+#define BTR_NOMINAL_TSEG2_MIN (1u)
+#define BTR_NOMINAL_TSEG2_MAX (128u)
+#define BTR_NOMINAL_SJW_MIN (1u)
+#define BTR_NOMINAL_SJW_MAX (128u)
+#define BTR_NOMINAL_SAM_MIN (0u)
+#define BTR_NOMINAL_SAM_MAX (1u)
+#define BTR_NOMINAL_SP_MIN (0.05)
+#define BTR_NOMINAL_SP_MAX (1.00)
+#define BTR_NOMINAL_SPEED_MIN (1000)
+#define BTR_NOMINAL_SPEED_MAX (2000000)
+
+#define BTR_DATA_BRP_MIN BTR_NOMINAL_BRP_MIN
+#define BTR_DATA_BRP_MAX BTR_NOMINAL_BRP_MAX
+#define BTR_DATA_TSEG1_MIN (1u)
+#define BTR_DATA_TSEG1_MAX (32u)
+#define BTR_DATA_TSEG2_MIN (1u)
+#define BTR_DATA_TSEG2_MAX (16u)
+#define BTR_DATA_SJW_MIN (1u)
+#define BTR_DATA_SJW_MAX (16u)
+#define BTR_DATA_SP_MIN (0.1)
+#define BTR_DATA_SP_MAX (1.0)
+#define BTR_DATA_SPEED_MIN (1000)
+#define BTR_DATA_SPEED_MAX (12000000)
+
+/* - - - - - - helper macros - - - - - - - - - - - - - - - - - - - - - -
+ */
+#define BTR_SJW(btr0btr1) (((unsigned short)(btr0btr1) & 0xC000u) >> 14)
+#define BTR_BRP(btr0btr1) (((unsigned short)(btr0btr1) & 0x3F00u) >> 8)
+#define BTR_SAM(btr0btr1) (((unsigned short)(btr0btr1) & 0x0080u) >> 7)
+#define BTR_TSEG2(btr0btr1) (((unsigned short)(btr0btr1) & 0x0070u) >> 4)
+#define BTR_TSEG1(btr0btr1) (((unsigned short)(btr0btr1) & 0x000Fu) >> 0)
+#define BTR_BTR0BTR1(sjw,brp,sam,tseg2,tseg1) \
+ ((((unsigned short)(sjw) & 0x0003) << 14) | \
+ (((unsigned short)(brp) & 0x003F) << 8) | \
+ (((unsigned short)(sam) & 0x0001) << 7) | \
+ (((unsigned short)(tseg2) & 0x0007) << 4) | \
+ (((unsigned short)(tseg1) & 0x000F) << 0))
+#ifdef _MSC_VER
+//not #if defined(_WIN32) || defined(_WIN64) because we have strncasecmp in mingw
+#define strncasecmp _strnicmp
+#define strcasecmp _stricmp
+#endif
+
+/* ----------- types --------------------------------------------------
+ */
+
+
+/* ----------- prototypes ---------------------------------------------
+ */
+
+static unsigned long calc_bit_rate(unsigned long brp, unsigned long tseg1, unsigned long tseg2, unsigned long frequency);
+static float calc_sample_point(unsigned long tseg1, unsigned long tseg2);
+
+static char *scan_key(char *str);
+static char *scan_value(char *str);
+static char *skip_blanks(char *str);
+
+
+/* ----------- variables ----------------------------------------------
+ */
+
+static const unsigned short sja1000_btr0btr1[10] = {
+ 0x0014U, // 1 MBit/s (SP=75,0%, SJW=1)
+ 0x0016U, // 800 kBit/s (SP=80,0%, SJW=1)
+ 0x001CU, // 500 kBit/s (SP=87,5%, SJW=1)
+ 0x011CU, // 250 kBit/s (SP=87,5%, SJW=1)
+ 0x031CU, // 125 kBit/s (SP=87,5%, SJW=1)
+ 0x441CU, // 100 kBit/s (SP=87,5%, SJW=2)
+ 0x491CU, // 50 kBit/s (SP=87,5%, SJW=2)
+ 0x581CU, // 20 kBit/s (SP=87,5%, SJW=2)
+ 0x711CU, // 10 kBit/s (SP=87,5%, SJW=2)
+ 0x7F7FU // 5 kBit/s (SP=68,0%, SJW=2)
+};
+
+/* ----------- functions ----------------------------------------------
+ */
+
+int btr_index_to_bit_rate_sja1000(long index, unsigned short *btr0btr1)
+{
+ if (index < 0)
+ index *= -1;
+ if (index > 9)
+ return 0;
+ if (!btr0btr1)
+ return 0;
+ *btr0btr1 = sja1000_btr0btr1[index];
+ return 1;
+}
+
+int btr_index_to_bit_timing_sja1000(long index, unsigned long *frequency, struct btr_bit_timing *btr_timing)
+{
+ unsigned short btr0btr1 = 0x0000;
+
+ if (!btr_timing)
+ return 0;
+ if (!btr_index_to_bit_rate_sja1000(index, &btr0btr1))
+ return 0;
+ if (frequency)
+ *frequency = BTR_FREQUENCY_SJA1000;
+ btr_timing->brp = BTR_BRP(btr0btr1);
+ btr_timing->tseg1 = BTR_TSEG1(btr0btr1);
+ btr_timing->tseg2 = BTR_TSEG2(btr0btr1);
+ btr_timing->sjw = BTR_SJW(btr0btr1);
+ btr_timing->sam = BTR_SAM(btr0btr1);
+ return 1;
+}
+
+unsigned long btr_calc_bit_rate_sja1000(unsigned short btr0btr1)
+{
+ return calc_bit_rate((unsigned long)BTR_BRP(btr0btr1), (unsigned long)BTR_TSEG1(btr0btr1),
+ (unsigned long)BTR_TSEG2(btr0btr1), BTR_FREQUENCY_SJA1000);
+}
+
+float btr_calc_sample_point_sja1000(unsigned short btr0btr1)
+{
+ return calc_sample_point((unsigned long)BTR_TSEG1(btr0btr1), (unsigned long)BTR_TSEG2(btr0btr1));
+}
+
+int btr_find_bit_timing_sja1000(unsigned long bit_rate, float sample_point, struct btr_bit_timing *bit_timing)
+{
+ unsigned long frequency = BTR_FREQUENCY_SJA1000;
+ unsigned short btr0btr1, i;
+
+ if(!bit_timing)
+ return 0;
+
+ if((sample_point < BTR_SJA1000_SP_MIN) || (BTR_SJA1000_SP_MAX < sample_point))
+ return 0;
+
+ for(i = BTR_SJA1000_BRP_MIN; i <= BTR_SJA1000_BRP_MAX; i++) {
+ bit_timing->brp = i;
+ bit_timing->tseg1 = (unsigned long)(((float)frequency * sample_point) / (float)(bit_rate * i)) - 1u;
+ bit_timing->tseg2 = (unsigned long)(((float)(1u + bit_timing->tseg1) / sample_point) - (float)(2u + bit_timing->tseg1)) + 1u;
+ bit_timing->sjw = 1u;
+ bit_timing->sam = 0u;
+ btr0btr1 = BTR_BTR0BTR1((bit_timing->sjw - 1u),
+ (bit_timing->brp - 1u),
+ (bit_timing->sam),
+ (bit_timing->tseg2 - 1u),
+ (bit_timing->tseg1 - 1u));
+ if(bit_rate == btr_calc_bit_rate_sja1000(btr0btr1))
+ return 1;
+ }
+ return 0;
+}
+
+unsigned long btr_calc_bit_rate_nominal(const struct btr_bit_timing *bit_timing, unsigned long frequency)
+{
+ if(!bit_timing)
+ return 0;
+
+ if(((BTR_NOMINAL_BRP_MIN <= bit_timing->brp) && (bit_timing->brp <= BTR_NOMINAL_BRP_MAX)) &&
+ ((BTR_NOMINAL_TSEG1_MIN <= bit_timing->tseg1) && (bit_timing->tseg1 <= BTR_NOMINAL_TSEG1_MAX)) &&
+ ((BTR_NOMINAL_TSEG2_MIN <= bit_timing->tseg2) && (bit_timing->tseg2 <= BTR_NOMINAL_TSEG2_MAX)) &&
+#ifndef _BTR_FREQUENCY_PCANBasic
+ ((BTR_FREQUENCY_MIN <= frequency) && (frequency <= BTR_FREQUENCY_MAX)))
+#else
+ ((BTR_FREQUENCY_80MHz == frequency) ||
+ (BTR_FREQUENCY_60MHz == frequency) ||
+ (BTR_FREQUENCY_40MHz == frequency) ||
+ (BTR_FREQUENCY_30MHz == frequency) ||
+ (BTR_FREQUENCY_24MHz == frequency) ||
+ (BTR_FREQUENCY_20MHz == frequency)))
+#endif
+ return calc_bit_rate((bit_timing->brp - 1u), (bit_timing->tseg1 - 1u), (bit_timing->tseg2 - 1u), frequency);
+ else
+ return 0u;
+}
+
+float btr_calc_sample_point_nominal(const struct btr_bit_timing *bit_timing)
+{
+ if(!bit_timing)
+ return 0.0;
+
+ if(((BTR_NOMINAL_TSEG1_MIN <= bit_timing->tseg1) && (bit_timing->tseg1 <= BTR_NOMINAL_TSEG1_MAX)) &&
+ ((BTR_NOMINAL_TSEG2_MIN <= bit_timing->tseg2) && (bit_timing->tseg2 <= BTR_NOMINAL_TSEG2_MAX)))
+ return calc_sample_point((bit_timing->tseg1 - 1u), (bit_timing->tseg2 - 1u));
+ else
+ return 0.0;
+}
+
+int btr_find_bit_timing_nominal(unsigned long bit_rate, float sample_point, unsigned long frequency, struct btr_bit_timing *bit_timing, unsigned long options)
+{
+ unsigned short i;
+
+ if(!bit_timing)
+ return 0;
+
+ if((sample_point < BTR_NOMINAL_SP_MIN) || (BTR_NOMINAL_SP_MAX < sample_point))
+ return 0;
+ if((frequency < BTR_FREQUENCY_MIN) || (BTR_FREQUENCY_MAX < frequency))
+ return 0;
+
+ if((options & BTR_OPTION_TQ_MASK) == BTR_OPTION_TQ_MANY) {
+ for(i = BTR_NOMINAL_BRP_MAX; i >= BTR_NOMINAL_BRP_MIN; i--) {
+ bit_timing->brp = i;
+ bit_timing->tseg1 = (unsigned long)(((float)frequency * sample_point) / (float)(bit_rate * i)) - 1u;
+ bit_timing->tseg2 = (unsigned long)(((float)(1u + bit_timing->tseg1) / sample_point) - (float)(2u + bit_timing->tseg1)) + 1u;
+ bit_timing->sjw = BTR_NOMINAL_SJW_MIN;
+ bit_timing->sam = BTR_NOMINAL_SAM_MIN;
+ if(bit_rate == btr_calc_bit_rate_nominal(bit_timing, frequency))
+ return 1;
+ }
+ }
+ else {
+ for(i = BTR_NOMINAL_BRP_MIN; i <= BTR_NOMINAL_BRP_MAX; i++) {
+ bit_timing->brp = i;
+ bit_timing->tseg1 = (unsigned long)(((float)frequency * sample_point) / (float)(bit_rate * i)) - 1u;
+ bit_timing->tseg2 = (unsigned long)(((float)(1u + bit_timing->tseg1) / sample_point) - (float)(2u + bit_timing->tseg1)) + 1u;
+ bit_timing->sjw = BTR_NOMINAL_SJW_MIN;
+ bit_timing->sam = BTR_NOMINAL_SAM_MIN;
+ if(bit_rate == btr_calc_bit_rate_nominal(bit_timing, frequency))
+ return 1;
+ }
+ }
+ return 0;
+}
+
+unsigned long btr_calc_bit_rate_data(const struct btr_bit_timing *bit_timing, unsigned long frequency)
+{
+ if(!bit_timing)
+ return 0;
+
+ if(((BTR_DATA_BRP_MIN <= bit_timing->brp) && (bit_timing->brp <= BTR_DATA_BRP_MAX)) &&
+ ((BTR_DATA_TSEG1_MIN <= bit_timing->tseg1) && (bit_timing->tseg1 <= BTR_DATA_TSEG1_MAX)) &&
+ ((BTR_DATA_TSEG2_MIN <= bit_timing->tseg2) && (bit_timing->tseg2 <= BTR_DATA_TSEG2_MAX)) &&
+#ifndef _BTR_FREQUENCY_PCANBasic
+ ((BTR_FREQUENCY_MIN <= frequency) && (frequency <= BTR_FREQUENCY_MAX)))
+#else
+ ((BTR_FREQUENCY_80MHz == frequency) ||
+ (BTR_FREQUENCY_60MHz == frequency) ||
+ (BTR_FREQUENCY_40MHz == frequency) ||
+ (BTR_FREQUENCY_30MHz == frequency) ||
+ (BTR_FREQUENCY_24MHz == frequency) ||
+ (BTR_FREQUENCY_20MHz == frequency)))
+#endif
+ return calc_bit_rate((bit_timing->brp - 1u), (bit_timing->tseg1 - 1u), (bit_timing->tseg2 - 1u), frequency);
+ else
+ return 0u;
+}
+
+float btr_calc_sample_point_data(const struct btr_bit_timing *bit_timing)
+{
+ if(!bit_timing)
+ return 0.0;
+
+ if(((BTR_DATA_TSEG1_MIN <= bit_timing->tseg1) && (bit_timing->tseg1 <= BTR_DATA_TSEG1_MAX)) &&
+ ((BTR_DATA_TSEG2_MIN <= bit_timing->tseg2) && (bit_timing->tseg2 <= BTR_DATA_TSEG2_MAX)))
+ return calc_sample_point((bit_timing->tseg1 -1u), (bit_timing->tseg2 -1u));
+ else
+ return 0.0;
+}
+
+int btr_find_bit_timing_data(unsigned long bit_rate, float sample_point, unsigned long frequency, struct btr_bit_timing *bit_timing, unsigned long options)
+{
+ unsigned short i;
+
+ if(!bit_timing)
+ return 0;
+
+ if((sample_point < BTR_DATA_SP_MIN) || (BTR_DATA_SP_MAX < sample_point))
+ return 0;
+ if((frequency < BTR_FREQUENCY_MIN) || (BTR_FREQUENCY_MAX < frequency))
+ return 0;
+
+ if((options & BTR_OPTION_TQ_MASK) == BTR_OPTION_TQ_MANY) {
+ for(i = BTR_DATA_BRP_MAX; i >= BTR_DATA_BRP_MIN; i--) {
+ bit_timing->brp = i;
+ bit_timing->tseg1 = (unsigned long)(((float)frequency * sample_point) / (float)(bit_rate * i)) - 1u;
+ bit_timing->tseg2 = (unsigned long)(((float)(1u + bit_timing->tseg1) / sample_point) - (float)(2u + bit_timing->tseg1)) + 1u;
+ bit_timing->sjw = BTR_DATA_SJW_MIN;
+ bit_timing->sam = 0u;
+ if(bit_rate == btr_calc_bit_rate_data(bit_timing, frequency))
+ return 1;
+ }
+ }
+ else {
+ for(i = BTR_DATA_BRP_MIN; i <= BTR_DATA_BRP_MAX; i++) {
+ bit_timing->brp = i;
+ bit_timing->tseg1 = (unsigned long)(((float)frequency * sample_point) / (float)(bit_rate * i)) - 1u;
+ bit_timing->tseg2 = (unsigned long)(((float)(1u + bit_timing->tseg1) / sample_point) - (float)(2u + bit_timing->tseg1)) + 1u;
+ bit_timing->sjw = BTR_DATA_SJW_MIN;
+ bit_timing->sam = 0u;
+ if(bit_rate == btr_calc_bit_rate_data(bit_timing, frequency))
+ return 1;
+ }
+ }
+ return 0;
+}
+
+int btr_string_to_bit_timing(const char *bit_rate,
+ unsigned long *frequency,
+ struct btr_bit_timing *btr_nominal,
+ struct btr_bit_timing *btr_data)
+{
+ char str[1000], *ptr;
+ char *key, *value;
+ unsigned long tmp = 0u;
+#if (0)
+ unsigned long nom_speed = 0;
+ unsigned long data_speed = 0;
+ float nom_sample_point = 0.0;
+ float data_sample_point = 0.0;
+ float tmp_float = 0.0;
+#endif
+
+ if(!bit_rate)
+ return 0;
+ if(!frequency)
+ return 0;
+ if(!btr_nominal)
+ return 0;
+ if(!btr_data)
+ return 0;
+
+ *frequency = 0u;
+ memset(btr_nominal, 0, sizeof(struct btr_bit_timing));
+ memset(btr_data, 0, sizeof(struct btr_bit_timing));
+
+ if(strlen(bit_rate) > 999)
+ return 0;
+ strcpy(str, bit_rate);
+ ptr = str;
+
+ while(*ptr != '\0') {
+ // skip blanks and scan: '='
+ if(!(key = skip_blanks(ptr)))
+ return 0;
+ if(!(ptr = scan_key(key)))
+ return 0;
+ // skip blanks and scan: [',']
+ if(!(value = skip_blanks(ptr)))
+ return 0;
+ if(!(ptr = scan_value(value)))
+ return 0;
+ // evaluate '=' [',']
+ if(strlen(value) == 0 || strlen(value) > 8)
+ return 0;
+#if (1)
+ // convert = [0-9]+ and less or equal '99999999'
+ tmp = (unsigned long)strtol(value, NULL, 10);
+#else
+ if(strchr(value, '.') == NULL) {
+ tmp = (unsigned long)strtol(value, NULL, 10);
+ tmp_float = 0.0;
+ } else {
+ tmp_float = (float)strtof(value, NULL) / 100.0f;
+ tmp = 0;
+ }
+#endif
+ // f_clock: (80000000, 60000000, 40000000, 30000000, 24000000, 20000000)
+ if(!strcasecmp(key, "f_clock")) {
+#ifndef _BTR_FREQUENCY_PCANBasic
+ if((BTR_FREQUENCY_MIN <= tmp) && (tmp <= BTR_FREQUENCY_MAX))
+ *frequency = (unsigned long)tmp;
+ else
+ return 0;
+#else
+ switch(tmp) {
+ case 80000000ul: *frequency = 80000000ul; break;
+ case 60000000ul: *frequency = 60000000ul; break;
+ case 40000000ul: *frequency = 40000000ul; break;
+ case 30000000ul: *frequency = 30000000ul; break;
+ case 24000000ul: *frequency = 24000000ul; break;
+ case 20000000ul: *frequency = 20000000ul; break;
+ default: return 0;
+ }
+#endif
+ }
+ // f_clock_mhz: (80, 60, 40, 30, 24, 20)
+ else if(!strcasecmp(key, "f_clock_mhz")) {
+#ifndef _BTR_FREQUENCY_PCANBasic
+ if((BTR_FREQUENCY_MHZ_MIN <= tmp) && (tmp <= BTR_FREQUENCY_MHZ_MAX))
+ *frequency = (unsigned long)tmp * 1000000ul;
+ else
+ return 0;
+#else
+ switch(tmp) {
+ case 80ul: *frequency = 80000000ul; break;
+ case 60ul: *frequency = 60000000ul; break;
+ case 40ul: *frequency = 40000000ul; break;
+ case 30ul: *frequency = 30000000ul; break;
+ case 24ul: *frequency = 24000000ul; break;
+ case 20ul: *frequency = 20000000ul; break;
+ default: return 0;
+ }
+#endif
+ }
+ // nom_brp: 1..1024
+ else if(!strcasecmp(key, "nom_brp")) {
+ if((BTR_NOMINAL_BRP_MIN <= tmp) && (tmp <= BTR_NOMINAL_BRP_MAX))
+ btr_nominal->brp = (unsigned short)tmp;
+ else
+ return 0;
+ }
+ // nom_tseg1: 1..256
+ else if(!strcasecmp(key, "nom_tseg1")) {
+ if((BTR_NOMINAL_TSEG1_MIN <= tmp) && (tmp <= BTR_NOMINAL_TSEG1_MAX))
+ btr_nominal->tseg1 = (unsigned short)tmp;
+ else
+ return 0;
+ }
+ // nom_tseg2: 1..128
+ else if(!strcasecmp(key, "nom_tseg2")) {
+ if((BTR_NOMINAL_TSEG2_MIN <= tmp) && (tmp <= BTR_NOMINAL_TSEG2_MAX))
+ btr_nominal->tseg2 = (unsigned short)tmp;
+ else
+ return 0;
+ }
+ // nom_sjw: 1..128
+ else if(!strcasecmp(key, "nom_sjw")) {
+ if((BTR_NOMINAL_SJW_MIN <= tmp) && (tmp <= BTR_NOMINAL_SJW_MAX))
+ btr_nominal->sjw = (unsigned short)tmp;
+ else
+ return 0;
+ }
+ // nom_sam: (none)
+ else if(!strcasecmp(key, "nom_sam")) {
+ if(tmp >= BTR_NOMINAL_SAM_MAX) // not relevant for CAN FD
+ btr_nominal->sam = (unsigned char)1;
+ else
+ btr_nominal->sam = (unsigned char)0;
+ }
+ // data_brp: 1..1024
+ else if(!strcasecmp(key, "data_brp")) {
+ if((BTR_DATA_BRP_MIN <= tmp) && (tmp <= BTR_DATA_BRP_MAX))
+ btr_data->brp = (unsigned short)tmp;
+ else
+ return 0;
+ }
+ // data_tseg1: 1..32
+ else if(!strcasecmp(key, "data_tseg1")) {
+ if((BTR_DATA_TSEG1_MIN <= tmp) && (tmp <= BTR_DATA_TSEG1_MAX))
+ btr_data->tseg1 = (unsigned short)tmp;
+ else
+ return 0;
+ }
+ // data_tseg2: 1..16
+ else if(!strcasecmp(key, "data_tseg2")) {
+ if((BTR_DATA_TSEG2_MIN <= tmp) && (tmp <= BTR_DATA_TSEG2_MAX))
+ btr_data->tseg2 = (unsigned short)tmp;
+ else
+ return 0;
+ }
+ // data_sjw: 1..16
+ else if(!strcasecmp(key, "data_sjw")) {
+ if((BTR_DATA_SJW_MIN <= tmp) && (tmp <= BTR_DATA_SJW_MAX))
+ btr_data->sjw = (unsigned short)tmp;
+ else
+ return 0;
+ }
+ // data_ssp_offset: (none)
+ else if(!strcasecmp(key, "data_ssp_offset")) {
+ // not used
+ }
+#if (0)
+ // nom_speed: 1000..2000000
+ else if(!strcasecmp(key, "nom_speed")) {
+ if(tmp < 1000ul)
+ tmp *= 1000ul;
+ if((BTR_NOMINAL_SPEED_MIN <= tmp) && (tmp <= BTR_NOMINAL_SPEED_MAX))
+ nom_speed = (unsigned long)tmp;
+ else
+ return 0;
+ }
+ // nom_sp: 0.05..1.00
+ else if(!strcasecmp(key, "nom_sp")) {
+ if(tmp_float == 0.0)
+ tmp_float = (float)tmp / 100.0f;
+ if((BTR_NOMINAL_SP_MIN <= tmp_float) && (tmp_float <= BTR_NOMINAL_SP_MAX))
+ nom_sample_point = tmp_float;
+ else
+ return 0;
+ }
+ // data_speed: 1000..12000000
+ else if(!strcasecmp(key, "data_speed")) {
+ if(tmp < 100ul)
+ tmp *= 1000000ul;
+ if(tmp < 1000ul)
+ tmp *= 1000ul;
+ if((BTR_DATA_SPEED_MIN <= tmp) && (tmp <= BTR_DATA_SPEED_MAX))
+ data_speed = (unsigned long)tmp;
+ else
+ return 0;
+ }
+ // data_sp: 0.1..1.0
+ else if(!strcasecmp(key, "data_sp")) {
+ if(tmp_float == 0.0)
+ tmp_float = (float)tmp / 100.0f;
+ if((BTR_DATA_SP_MIN <= tmp_float) && (tmp_float <= BTR_DATA_SP_MAX))
+ data_sample_point = tmp_float;
+ else
+ return 0;
+ }
+#endif
+ else {
+ // unknown key
+ return 0;
+ }
+ }
+ if(*frequency) {
+#if (0)
+ /* f_clock=,nom_speed=,nom_sp=[,data_speed=,data_sp=] */
+ if((nom_speed && (nom_sample_point != 0.0)) &&
+ !((btr_nominal->brp || btr_nominal->tseg1 || btr_nominal->tseg2 || btr_nominal->sjw || btr_nominal->sam) ||
+ (btr_data->brp || btr_data->tseg1 || btr_data->tseg2 || btr_data->sjw))) {
+ if(!btr_find_bit_timing_nominal(nom_speed, nom_sample_point, *frequency, btr_nominal, BTR_OPTION_TQ_FEW))
+ return 0;
+ if(data_speed && (data_sample_point != 0.0)) {
+ if(!btr_find_bit_timing_data(data_speed, data_sample_point, *frequency, btr_data, BTR_OPTION_TQ_FEW))
+ return 0;
+ }
+ else if(data_speed || (data_sample_point != 0.0))
+ return 0;
+ }
+ else if(nom_speed || (nom_sample_point != 0.0))
+ return 0;
+#endif
+ /* f_clock=,nom_brp=,nom_tseg1=,nom_tseg2=,nom_sjw=[,nom_sam=]
+ [,data_brp=,data_tseg1=,data_tseg2=,data_sjw=] */
+ if((btr_nominal->brp && btr_nominal->tseg1 && btr_nominal->tseg2 && btr_nominal->sjw) &&
+ ((btr_data->brp && btr_data->tseg1 && btr_data->tseg2 && btr_data->sjw) ||
+ (!btr_data->brp && !btr_data->tseg1 && !btr_data->tseg2 && !btr_data->sjw)))
+ return 1;
+ }
+ return 0;
+}
+
+/* ----------- local functions ---------------------------------------
+ */
+
+static unsigned long calc_bit_rate(unsigned long brp, unsigned long tseg1, unsigned long tseg2, unsigned long frequency)
+{
+ return frequency / ((1u + brp) * (3u + tseg1 + tseg2));
+}
+
+static float calc_sample_point(unsigned long tseg1, unsigned long tseg2)
+{
+ return (float)(2u + tseg1)/(float)(3u + tseg1 + tseg2);
+}
+
+static char *scan_key(char *str)
+{
+ char *ptr = str;
+
+ while(('a' <= *ptr && *ptr <= 'z') || (*ptr == '_') || ('0' <= *ptr && *ptr <= '9') || ('A' <= *ptr && *ptr <= 'Z'))
+ ptr++;
+ while(*ptr == ' ')
+ *ptr++ = '\0';
+ if((*ptr != '='))
+ return NULL;
+ *ptr++ = '\0';
+ return ptr;
+}
+
+static char *scan_value(char *str)
+{
+ char *ptr = str;
+#if (0)
+ int dot = 0;
+
+ while(('0' <= *ptr && *ptr <= '9') || (*ptr == '.')) {
+ if((*ptr == '.') && (++dot > 1))
+ return ptr;
+ ptr++;
+ }
+#else
+ while(('0' <= *ptr && *ptr <= '9'))
+ ptr++;
+#endif
+ while(*ptr == ' ')
+ *ptr++ = '\0';
+ if((*ptr != ',') && (*ptr != '\0'))
+ return NULL;
+ if(*ptr != '\0')
+ *ptr++ = '\0';
+ return ptr;
+}
+
+static char *skip_blanks(char *str)
+{
+ char *ptr = str;
+
+ while(*ptr == ' ')
+ *ptr++ = '\0';
+ return ptr;
+}
+
+
+/** @}
+ */
+/* ----------------------------------------------------------------------
+ * Uwe Vogt, UV Software, Chausseestrasse 33 A, 10115 Berlin, Germany
+ * Tel.: +49-30-46799872, Fax: +49-30-46799873, Mobile: +49-170-3801903
+ * E-Mail: uwe.vogt@uv-software.de, Homepage: http://www.uv-software.de/
+ */
diff --git a/Utilities/misc/bitrates.h b/Utilities/misc/bitrates.h
new file mode 100644
index 0000000..46ed23d
--- /dev/null
+++ b/Utilities/misc/bitrates.h
@@ -0,0 +1,168 @@
+/* -- $HeadURL: https://svn.uv-software.net/projects/uv-software/CAN/I386/DRV/trunk/API/misc/bitrates.h $ --
+ *
+ * project : CAN - Controller Area Network
+ *
+ * purpose : CAN FD Bit-rates (Converter)
+ *
+ * copyright : (C) 2017-2023, UV Software, Berlin
+ *
+ * compiler : Microsoft Visual C/C++ Compiler
+ * Apple LLVM (clang) Compiler
+ * GNU C/C++ Compiler
+ *
+ * export : int btr_string_to_bit_timing(const char *bit_rate,
+ * unsigned long *frequency,
+ * struct btr_bit_timing *btr_nominal,
+ * struct btr_bit_timing *btr_data);
+ *
+ * includes : (none)
+ *
+ * author : Uwe Vogt, UV Software
+ *
+ * e-mail : uwe.vogt@uv-software.de
+ *
+ *
+ * ----------- description --------------------------------------------
+ */
+/** @file bitrates.h
+ *
+ * @brief CAN FD Bit-rates (Converter)
+ *
+ * @author $Author: makemake $
+ *
+ * @version $Rev: 1089 $
+ *
+ * @defgroup bit_rate CAN FD Bit-rates (Converter)
+ * @{
+ */
+#ifndef BITRATES_H_INCLUDED
+#define BITRATES_H_INCLUDED
+
+/* ----------- includes -----------------------------------------------
+ */
+
+
+/* ----------- defines ------------------------------------------------
+ */
+
+#define BTR_FREQUENCY_80MHz (80000000u)
+#define BTR_FREQUENCY_60MHz (60000000u)
+#define BTR_FREQUENCY_40MHz (40000000u)
+#define BTR_FREQUENCY_30MHz (30000000u)
+#define BTR_FREQUENCY_24MHz (24000000u)
+#define BTR_FREQUENCY_20MHz (20000000u)
+
+#define BTR_OPTION_TQ_MASK (0x00000001u)
+#define BTR_OPTION_TQ_MANY (0x00000001u)
+#define BTR_OPTION_TQ_FEW (0x00000000u)
+
+#define BTR_FREQUENCY_SJA1000 (8000000u)
+
+#define BTR_INDEX_1M (0)
+#define BTR_INDEX_800K (-1)
+#define BTR_INDEX_500K (-2)
+#define BTR_INDEX_250K (-3)
+#define BTR_INDEX_125K (-4)
+#define BTR_INDEX_100K (-5)
+#define BTR_INDEX_50K (-6)
+#define BTR_INDEX_20K (-7)
+#define BTR_INDEX_10K (-8)
+#define BTR_INDEX_5K (-9)
+
+
+/* ----------- types --------------------------------------------------
+ */
+
+/** bit-timing register
+ */
+struct btr_bit_timing
+{
+ unsigned long brp; /**< prescaler: 1..1024 (m_can) / 1..64 (sja1000) */
+ unsigned long tseg1; /**< tseg1: 1..256 (slow) / 1..32 (fast) / 1..16 (sja1000) */
+ unsigned long tseg2; /**< tseg2: 1..128 (slow) / 1..16 (fast) / 1..8 (sja1000) */
+ unsigned long sjw; /**< swj: 1..128 (slow) / 1..16 (fast) / 1..4 (sja1000) */
+ unsigned long sam; /**< sam: 0..1 (sja1000 only) */
+};
+
+
+/* ----------- variables ----------------------------------------------
+ */
+
+
+/* ----------- prototypes ---------------------------------------------
+ */
+
+/** @brief TBD
+ */
+int btr_string_to_bit_timing(const char *bit_rate,
+ unsigned long *frequency,
+ struct btr_bit_timing *btr_nominal,
+ struct btr_bit_timing *btr_data);
+
+
+/** @brief TBD
+ */
+unsigned long btr_calc_bit_rate_nominal(const struct btr_bit_timing *bit_timing,
+ unsigned long frequency);
+
+/** @brief TBD
+ */
+float btr_calc_sample_point_nominal(const struct btr_bit_timing *bit_timing);
+
+/** @brief TBD
+ */
+int btr_find_bit_timing_nominal(unsigned long bit_rate, float sample_point,
+ unsigned long frequency,
+ struct btr_bit_timing *bit_timing,
+ unsigned long options);
+
+/** @brief TBD
+ */
+unsigned long btr_calc_bit_rate_data(const struct btr_bit_timing *bit_timing,
+ unsigned long frequency);
+
+/** @brief TBD
+ */
+float btr_calc_sample_point_data(const struct btr_bit_timing *bit_timing);
+
+/** @brief TBD
+ */
+int btr_find_bit_timing_data(unsigned long bit_rate,
+ float sample_point,
+ unsigned long frequency,
+ struct btr_bit_timing *bit_timing,
+ unsigned long options);
+
+
+/** @brief TBD
+ */
+int btr_index_to_bit_rate_sja1000(long index, unsigned short *btr0btr1);
+
+/** @brief TBD
+ */
+int btr_index_to_bit_timing_sja1000(long index,
+ unsigned long *frequency,
+ struct btr_bit_timing *btr_timing);
+
+/** @brief TBD
+ */
+unsigned long btr_calc_bit_rate_sja1000(unsigned short btr0btr1);
+
+/** @brief TBD
+ */
+float btr_calc_sample_point_sja1000(unsigned short btr0btr1);
+
+/** @brief TBD
+ */
+int btr_find_bit_timing_sja1000(unsigned long bit_rate,
+ float sample_point,
+ struct btr_bit_timing *bit_timing);
+
+#endif /* BITRATES_H_INCLUDED */
+/** @}
+ */
+/* ----------------------------------------------------------------------
+ * Uwe Vogt, UV Software, Chausseestrasse 33 A, 10115 Berlin, Germany
+ * Tel.: +49-30-46799872, Fax: +49-30-46799873, Mobile: +49-170-3801903
+ * E-Mail: uwe.vogt@uv-software.de, Homepage: http://www.uv-software.de/
+ */
diff --git a/Utilities/misc/printmsg.c b/Utilities/misc/printmsg.c
new file mode 100644
index 0000000..c5fe100
--- /dev/null
+++ b/Utilities/misc/printmsg.c
@@ -0,0 +1,278 @@
+/* -- $HeadURL: https://svn.uv-software.net/projects/uv-software/CAN/I386/DRV/trunk/API/misc/printmsg.c $ --
+ *
+ * project : CAN - Controller Area Network
+ *
+ * purpose : Print CAN Messages (Monitor)
+ *
+ * copyright : (C) 2019, UV Software, Berlin
+ *
+ * compiler : Microsoft Visual C/C++ Compiler
+ * Apple LLVM Compiler (clang)
+ * GNU C/C++ Compiler (gcc)
+ *
+ * export : (see header file)
+ *
+ * includes : printmsg.h
+ *
+ * author : Uwe Vogt, UV Software
+ *
+ * e-mail : uwe.vogt@uv-software.de
+ *
+ *
+ * ----------- description --------------------------------------------
+ */
+/** @file printmsg.c
+ *
+ * @brief Print CAN Messages (Monitor)
+ *
+ * @author $Author: neptune $
+ *
+ * @version $Rev: 589 $
+ *
+ * @addtogroup print_msg
+ * @{
+ */
+
+/* ----------- includes -----------------------------------------------
+ */
+
+#include "printmsg.h"
+
+#include
+#include
+#include
+#include
+#ifndef _WIN32
+#include
+#else
+#include
+#endif
+
+/* ----------- options ------------------------------------------------
+ */
+
+#ifndef MSG_PRINT_USEC
+#define MSG_PRINT_USEC 0
+#endif
+
+/* ----------- defines ------------------------------------------------
+ */
+
+
+/* ----------- types --------------------------------------------------
+ */
+
+
+/* ----------- prototypes ---------------------------------------------
+ */
+
+
+/* ----------- variables ----------------------------------------------
+ */
+
+
+/* ----------- functions ----------------------------------------------
+ */
+
+void msg_print_id(FILE *stream, unsigned long id, int rtr, int ext, unsigned char dlc, int mode)
+{
+ switch (mode) {
+ case MSG_MODE_DEC:
+ fprintf(stream, "%-4lu ", id);
+ break;
+ case MSG_MODE_OCT:
+ fprintf(stream, "\\%04lo ", id);
+ break;
+ case MSG_MODE_HEX:
+ default:
+ fprintf(stream, "%03lX ", id);
+ break;
+ }
+ fprintf(stream, "%c%c [%u] ",
+ ext ? 'X' : ' ',
+ rtr ? 'R' : ' ',
+ dlc);
+}
+
+void msg_print_indent(FILE *stream, const char *prefix, int mode)
+{
+ switch(mode) {
+ case MSG_MODE_DEC:
+ /* format DEC: " HH:MM:SS.xxxx DDDD XR [DD] " */
+ fprintf(stream, "%s ", prefix);
+ break;
+ case MSG_MODE_OCT:
+ /* format OCT: " HH:MM:SS.xxxx \OOOO XR [DD] " */
+ fprintf(stream, "%s ", prefix);
+ break;
+ case MSG_MODE_HEX:
+ /* format HEX: " HH:MM:SS.xxxx XXX XR [DD] " */
+ fprintf(stream, "%s ", prefix);
+ break;
+ }
+}
+
+void msg_print_id_fd(FILE *stream, unsigned long id, int rtr, int ext, int fdf, int brs, int esi, int len, int mode)
+{
+ switch (mode) {
+ case MSG_MODE_DEC:
+ fprintf(stream, "%-4lu ", id);
+ break;
+ case MSG_MODE_OCT:
+ fprintf(stream, "\\%04lo ", id);
+ break;
+ case MSG_MODE_HEX:
+ default:
+ fprintf(stream, "%03lX ", id);
+ break;
+ }
+ fprintf(stream, "%c%c%c%c%c [%u] ",
+ ext ? 'X' : ' ',
+ rtr ? 'R' : ' ',
+ fdf ? 'F' : ' ',
+ brs ? 'B' : ' ',
+ esi ? 'E' : ' ',
+ len);
+}
+
+void msg_print_indent_fd(FILE *stream, const char *prefix, int mode)
+{
+ switch(mode) {
+ case MSG_MODE_DEC:
+ /* format DEC: " HH:MM:SS.xxxx DDDD XRFBE [DD] " */
+ fprintf(stream, "%s ", prefix);
+ break;
+ case MSG_MODE_OCT:
+ /* format OCT: " HH:MM:SS.xxxx \OOOO XRFBE [DD] " */
+ fprintf(stream, "%s ", prefix);
+ break;
+ case MSG_MODE_HEX:
+ /* format HEX: " HH:MM:SS.xxxx XXX XRFBE [DD] " */
+ fprintf(stream, "%s ", prefix);
+ break;
+ }
+}
+
+void msg_print_data(FILE *stream, unsigned char data, int last, int mode)
+{
+ switch (mode) {
+ case MSG_MODE_DEC:
+ if (!last)
+ fprintf(stream, "%-3u ", data);
+ else
+ fprintf(stream, "%-3u", data);
+ break;
+ case MSG_MODE_OCT:
+ if (!last)
+ fprintf(stream, "\\%03o ", data);
+ else
+ fprintf(stream, "\\%03o", data);
+ break;
+ case MSG_MODE_HEX:
+ default:
+ if (!last)
+ fprintf(stream, "%02X ", data);
+ else
+ fprintf(stream, "%02X", data);
+ break;
+ }
+}
+
+void msg_print_space(FILE *stream, int last, int mode)
+{
+ switch (mode) {
+ case MSG_MODE_DEC:
+ if (!last)
+ fprintf(stream, " ");
+ else
+ fprintf(stream, " ");
+ break;
+ case MSG_MODE_OCT:
+ if (!last)
+ fprintf(stream, " ");
+ else
+ fprintf(stream, " ");
+ break;
+ case MSG_MODE_HEX:
+ default:
+ if (!last)
+ fprintf(stream, " ");
+ else
+ fprintf(stream, " ");
+ break;
+ }
+}
+
+void msg_print_ascii(FILE *stream, unsigned char data, int mode)
+{
+ if (mode == MSG_ASCII_ON) {
+ if (isprint(data))
+ fprintf(stream, "%c", data);
+ else
+ fprintf(stream, ".");
+ }
+}
+void msg_print_time(FILE *stream, struct msg_timestamp *timestamp, int mode)
+{
+ static struct msg_timestamp laststamp = { 0, 0 };
+ struct timeval difftime;
+ struct tm tm; time_t t; char timestring[25];
+
+ switch (mode) {
+ case MSG_TIME_REL:
+ case MSG_TIME_ZERO:
+ if (laststamp.tv_sec == 0) /* first init */
+ laststamp = *timestamp;
+ difftime.tv_sec = timestamp->tv_sec - laststamp.tv_sec;
+ difftime.tv_usec = timestamp->tv_usec - laststamp.tv_usec;
+ if (difftime.tv_usec < 0) {
+ difftime.tv_sec -= 1;
+ difftime.tv_usec += 1000000;
+ }
+ if (difftime.tv_sec < 0) {
+ difftime.tv_sec = 0;
+ difftime.tv_usec = 0;
+ }
+ t = (time_t)difftime.tv_sec;
+ tm = *gmtime(&t);
+ strftime(timestring, 24, "%H:%M:%S", &tm);
+#if (MSG_PRINT_USEC == 0)
+ fprintf(stream, "%s.%04li ", timestring, difftime.tv_usec / 100L);
+#else
+ fprintf(stream, "%s.%06li ", timestring, difftime.tv_usec);
+#endif
+ if (mode == MSG_TIME_REL)
+ laststamp = *timestamp; /* update for delta calculation */
+ break;
+ case MSG_TIME_ABS:
+ default:
+ if (timestamp->tv_sec < 0)
+ timestamp->tv_sec = 0;
+ if (timestamp->tv_usec < 0)
+ timestamp->tv_usec = 0;
+
+ t = (time_t)timestamp->tv_sec;
+ tm = *localtime(&t);
+ strftime(timestring, 24, "%H:%M:%S", &tm);
+#if (MSG_PRINT_USEC == 0)
+ fprintf(stream, "%s.%04li ", timestring, timestamp->tv_usec / 100L);
+#else
+ fprintf(stream, "%s.%04li ", timestring, timestamp->tv_usec);
+#endif
+ break;
+ }
+}
+
+
+/* ----------- local functions ----------------------------------------
+ */
+
+
+/** @}
+ */
+/* ----------------------------------------------------------------------
+ * Uwe Vogt, UV Software, Chausseestrasse 33 A, 10115 Berlin, Germany
+ * Tel.: +49-30-46799872, Fax: +49-30-46799873, Mobile: +49-170-3801903
+ * E-Mail: uwe.vogt@uv-software.de, Homepage: http://www.uv-software.de/
+ */
+
diff --git a/Utilities/misc/printmsg.h b/Utilities/misc/printmsg.h
new file mode 100644
index 0000000..f143051
--- /dev/null
+++ b/Utilities/misc/printmsg.h
@@ -0,0 +1,102 @@
+/* -- $HeadURL: https://svn.uv-software.net/projects/uv-software/CAN/I386/DRV/trunk/API/misc/printmsg.h $ --
+ *
+ * project : CAN - Controller Area Network
+ *
+ * purpose : Print CAN Messages (Monitor)
+ *
+ * copyright : (C) 2019, UV Software, Berlin
+ *
+ * compiler : Microsoft Visual C/C++ Compiler
+ * Apple LLVM Compiler (clang)
+ * GNU C/C++ Compiler (gcc)
+ *
+ * export : void msg_print_id(FILE *stream, unsigned long id, int rtr, int ext, unsigned char dlc, int mode);
+ * void msg_print_id_fd(FILE *stream, unsigned long id, int rtr, int ext, int fdf, int brs, int esi, int len, int mode);
+ * void msg_print_data(FILE *stream, unsigned char data, int last, int mode);
+ * void msg_print_space(FILE *stream, int last, int mode);
+ * void msg_print_ascii(FILE *stream, unsigned char data, int mode);
+ * void msg_print_indent(FILE *stream, const char *prefix, int mode);
+ * void msg_print_indent_fd(FILE *stream, const char *prefix, int mode);
+ * void msg_print_time(FILE *stream, struct msg_timestamp *timestamp, int mode);
+ *
+ * includes : (none)
+ *
+ * author : Uwe Vogt, UV Software
+ *
+ * e-mail : uwe.vogt@uv-software.de
+ *
+ *
+ * ----------- description --------------------------------------------
+ */
+ /** @file bitrates.h
+ *
+ * @brief Print CAN Messages (Monitor)
+ *
+ * @author $Author: neptune $
+ *
+ * @version $Rev: 589 $
+ *
+ * @defgroup print_msg Print CAN Messages (Monitor)
+ * @{
+ */
+#ifndef PRINTMSG_H_INCLUDED
+#define PRINTMSG_H_INCLUDED
+
+/* ----------- includes -----------------------------------------------
+ */
+
+#include
+
+
+/* ----------- defines ------------------------------------------------
+ */
+
+#define MSG_TIME_ZERO (0)
+#define MSG_TIME_ABS (1)
+#define MSG_TIME_REL (2)
+
+#define MSG_MODE_HEX (0)
+#define MSG_MODE_DEC (1)
+#define MSG_MODE_OCT (2)
+
+#define MSG_ASCII_OFF (0)
+#define MSG_ASCII_ON (1)
+
+
+/* ----------- types --------------------------------------------------
+ */
+
+/** time-stamp of a CAN message
+ */
+struct msg_timestamp {
+ long tv_sec; /**< seconds */
+ long tv_usec; /**< microseconds */
+};
+
+/* ----------- variables ----------------------------------------------
+ */
+
+
+/* ----------- prototypes ---------------------------------------------
+ */
+
+/** @brief TBD
+ */
+void msg_print_id(FILE *stream, unsigned long id, int rtr, int ext, unsigned char dlc, int mode);
+void msg_print_id_fd(FILE *stream, unsigned long id, int rtr, int ext, int fdf, int brs, int esi, int len, int mode);
+void msg_print_data(FILE *stream, unsigned char data, int last, int mode);
+void msg_print_space(FILE *stream, int last, int mode);
+void msg_print_ascii(FILE *stream, unsigned char data, int mode);
+void msg_print_indent(FILE *stream, const char *prefix, int mode);
+void msg_print_indent_fd(FILE *stream, const char *prefix, int mode);
+void msg_print_time(FILE *stream, struct msg_timestamp *timestamp, int mode);
+
+
+#endif /* PRINTMSG_H_INCLUDED */
+/** @}
+ */
+/* ----------------------------------------------------------------------
+ * Uwe Vogt, UV Software, Chausseestrasse 33 A, 10115 Berlin, Germany
+ * Tel.: +49-30-46799872, Fax: +49-30-46799873, Mobile: +49-170-3801903
+ * E-Mail: uwe.vogt@uv-software.de, Homepage: http://www.uv-software.de/
+ */
diff --git a/Utilities/misc/timer.c b/Utilities/misc/timer.c
new file mode 100644
index 0000000..9b13b77
--- /dev/null
+++ b/Utilities/misc/timer.c
@@ -0,0 +1,221 @@
+/* -- $HeadURL: https://svn.uv-software.net/sourcemedley/library/trunk/c/timer.c $ --
+ *
+ * project : Industrial Communication.
+ *
+ * purpose : A high-resolution Timer.
+ *
+ * copyright : (C) 2013,2019 by UV Software, Berlin
+ *
+ * compiler : Microsoft Visual C/C++ Compiler (Version 15.16)
+ * Apple LLVM version 10.0.0 (clang-1000.11.45.5)
+ * GCC - GNU C Compiler (Debian 6.3.0-18+deb9u1)
+ * GCC - GNU C Compiler (MinGW.org GCC-8.2.0-3)
+ *
+ * export : (see header file)
+ *
+ * includes : timer.h ()
+ *
+ * author(s) : Uwe Vogt, UV Software
+ *
+ * e-mail : uwe.vogt@uv-software.de
+ *
+ *
+ * ----------- description -------------------------------------------
+ */
+/** @file timer.c
+ *
+ * @brief A high-resolution Timer.
+ *
+ * @author $Author: haumea $
+ *
+ * @version $Rev: 478 $
+ *
+ * @todo replace `gettimeofday' by `clock_gettime' and `usleep' by `clock_nanosleep'
+ *
+ * @addtogroup timer
+ * @{
+ */
+
+/*static const char _id[] = "$Id: timer.c 478 2019-12-10 21:03:29Z haumea $";*/
+
+
+/* ----------- includes ----------------------------------------------
+ */
+
+#include "timer.h" /* interface prototypes */
+
+#include /* standard I/O routines */
+#include /* system wide error numbers */
+#include /* string manipulation functions */
+#include /* commonly used library functions */
+#if defined(_WIN32) || defined(_WIN64)
+#include /* master include file for Windows */
+#else
+#include
+#include
+#endif
+
+
+/* ----------- defines -----------------------------------------------
+ */
+
+
+/* ----------- types -------------------------------------------------
+ */
+
+
+/* ----------- prototypes --------------------------------------------
+ */
+
+
+/* ----------- variables ---------------------------------------------
+ */
+
+static timer_obj_t gpt0 = 0; /**< general purpose timer (GPT0) */
+
+
+/* ----------- functions ---------------------------------------------
+ */
+
+timer_obj_t timer_new(uint32_t microseconds)
+{
+#if !defined(_WIN32) && !defined(_WIN64)
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+
+ uint64_t llUntilStop = ((uint64_t)tv.tv_sec * (uint64_t)1000000) + (uint64_t)tv.tv_usec \
+ + ((uint64_t)microseconds);
+#else
+ LARGE_INTEGER largeFrequency; // high-resolution timer frequency
+ LARGE_INTEGER largeCounter; // high-resolution performance counter
+
+ LONGLONG llUntilStop = 0; // counter value when to stop (time-out)
+
+ // retrieve the frequency of the high-resolution performance counter
+ if (!QueryPerformanceFrequency(&largeFrequency))
+ return 0;
+ // retrieve the current value of the high-resolution performance counter
+ if (!QueryPerformanceCounter(&largeCounter))
+ return 0;
+ // calculate the counter value for the desired time-out
+ llUntilStop = largeCounter.QuadPart + ((largeFrequency.QuadPart * (LONGLONG)microseconds)
+ / (LONGLONG)1000000);
+#endif
+ return (uint64_t)llUntilStop;
+}
+
+int timer_restart(timer_obj_t *self, uint32_t microseconds)
+{
+#if !defined(_WIN32) && !defined(_WIN64)
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+
+ uint64_t llUntilStop = ((uint64_t)tv.tv_sec * (uint64_t)1000000) + (uint64_t)tv.tv_usec \
+ + ((uint64_t)microseconds);
+#else
+ LARGE_INTEGER largeFrequency; // high-resolution timer frequency
+ LARGE_INTEGER largeCounter; // high-resolution performance counter
+
+ LONGLONG llUntilStop = 0; // counter value when to stop (time-out)
+
+ // retrieve the frequency of the high-resolution performance counter
+ if(!QueryPerformanceFrequency(&largeFrequency))
+ return 0;
+ // retrieve the current value of the high-resolution performance counter
+ if(!QueryPerformanceCounter(&largeCounter))
+ return 0;
+ // calculate the counter value for the desired time-out
+ llUntilStop = largeCounter.QuadPart + ((largeFrequency.QuadPart * (LONGLONG)microseconds)
+ / (LONGLONG)1000000);
+#endif
+ // update the timer instance or the general purpose timer (NULL)
+ if (self)
+ *self = (uint64_t)llUntilStop;
+ else
+ gpt0 = (uint64_t)llUntilStop;
+ return 1;
+}
+
+int timer_timeout(timer_obj_t *self)
+{
+#if !defined(_WIN32) && !defined(_WIN64)
+ uint64_t llNow;
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+
+ uint64_t llUntilStop = self ? (uint64_t)*self : (uint64_t)gpt0;
+
+ llNow = ((uint32_t)tv.tv_sec * (uint64_t)1000000) + (uint64_t)tv.tv_usec;
+
+ if(llNow < llUntilStop)
+ return 0;
+ else
+ return 1;
+#else
+ LARGE_INTEGER largeFrequency; // high-resolution timer frequency
+ LARGE_INTEGER largeCounter; // high-resolution performance counter
+
+ LONGLONG llUntilStop = self ? (LONGLONG)*self : (LONGLONG)gpt0;
+
+ // retrieve the frequency of the high-resolution performance counter
+ if (!QueryPerformanceFrequency(&largeFrequency))
+ return 0;
+ // retrieve the current value of the high-resolution performance counter
+ if (!QueryPerformanceCounter(&largeCounter))
+ return 0;
+ // a time-out occurred, if the counter overruns the time-out value
+ if (largeCounter.QuadPart < llUntilStop)
+ return 0;
+ else
+ return 1;
+#endif
+}
+
+int timer_delay(uint32_t microseconds)
+{
+#if !defined(_WIN32) && !defined(_WIN64)
+ return (usleep((useconds_t)microseconds) != 0) ? 0 : 1;
+#else
+# ifndef TIMER_WAITABLE_TIMER
+ timer_obj_t local = timer_new(microseconds);
+
+ while (!timer_timeout(&local)) {
+ Sleep(0);
+ }
+ return 1;
+# else
+ HANDLE timer;
+ LARGE_INTEGER ft;
+
+ ft.QuadPart = -(10 * (LONGLONG)microseconds); // Convert to 100 nanosecond interval, negative value indicates relative time
+
+ if (microseconds >= 100) { // FIXME: Who made this decision?
+ if ((timer = CreateWaitableTimer(NULL, TRUE, NULL)) != NULL) {
+ SetWaitableTimer(timer, &ft, 0, NULL, NULL, 0);
+ WaitForSingleObject(timer, INFINITE);
+ CloseHandle(timer);
+ }
+ }
+ else {
+ // According to MSDN's documentation for Sleep:
+ // | A value of zero causes the thread to relinquish the remainder of its time slice to any other
+ // | thread that is ready to run.If there are no other threads ready to run, the function returns
+ // | immediately, and the thread continues execution.
+ Sleep(0);
+ }
+ return 1;
+# endif
+#endif
+}
+
+/* ----------- local functions ---------------------------------------
+ */
+
+
+/** @}
+ */
+/* ----------------------------------------------------------------------
+ * Uwe Vogt, UV Software, Chausseestrasse 33 A, 10115 Berlin, Germany
+ * Tel.: +49-30-46799872, Fax: +49-30-46799873, Mobile: +49-170-3801903
+ * E-Mail: uwe.vogt@uv-software.de, Homepage: http://www.uv-software.de/
+ */
diff --git a/Utilities/misc/timer.h b/Utilities/misc/timer.h
new file mode 100644
index 0000000..c7d265c
--- /dev/null
+++ b/Utilities/misc/timer.h
@@ -0,0 +1,129 @@
+/* -- $HeadURL: https://svn.uv-software.net/sourcemedley/library/trunk/c/timer.h $ --
+ *
+ * project : Industrial Communication.
+ *
+ * purpose : A high-resolution Timer.
+ *
+ * copyright : (C) 2013,2019 by UV Software, Berlin
+ *
+ * compiler : Microsoft Visual C/C++ Compiler (Version 15.16)
+ * Apple LLVM version 10.0.0 (clang-1000.11.45.5)
+ * GCC - GNU C Compiler (Debian 6.3.0-18+deb9u1)
+ * GCC - GNU C Compiler (MinGW.org GCC-8.2.0-3)
+ *
+ * export : timer_obj_t timer_new(uint32_t timeout);
+ * int timer_restart(timer_obj_t *self, uint32_t timeout);
+ * int timer_timeout(timer_obj_t *self);
+ * int timer_delay(uint32_t delay);
+ *
+ * includes : ,
+ *
+ * author(s) : Uwe Vogt, UV Software
+ *
+ * e-mail : uwe.vogt@uv-software.de
+ *
+ *
+ * ----------- description -------------------------------------------
+ */
+/** @file timer.h
+ *
+ * @brief A high-resolution Timer.
+ *
+ * Including a general purpose timer (GPT0).
+ *
+ * @remark The name 'timer_t' is used in stdlih.h on Linux. Even
+ * if this name is not POSIX compliant, I renamed it.
+ *
+ * @author $Author: haumea $
+ *
+ * @version $Rev: 478 $
+ *
+ * @defgroup timer A high-resolution Timer
+ * @{
+ */
+#ifndef TIMER_H_INCLUDED
+#define TIMER_H_INCLUDED
+
+/* ----------- includes ----------------------------------------------
+ */
+
+#include
+#include
+
+
+/* ----------- options -----------------------------------------------
+ */
+
+#if defined(_WIN32) || defined(_WIN64)
+#define TIMER_WAITABLE_TIMER /**< Windows alternative for usleep() */
+#endif
+
+/* ----------- defines -----------------------------------------------
+ */
+
+#define TIMER_GPT0 NULL /**< general purpose timer */
+
+#define TIMER_USEC(x) (uint32_t)((uint32_t)(x) * (uint32_t)1)
+#define TIMER_MSEC(x) (uint32_t)((uint32_t)(x) * (uint32_t)1000)
+#define TIMER_SEC(x) (uint32_t)((uint32_t)(x) * (uint32_t)1000000)
+#define TIMER_MIN(x) (uint32_t)((uint32_t)(x) * (uint32_t)60000000)
+
+
+/* ----------- types -------------------------------------------------
+ */
+
+typedef uint64_t timer_obj_t; /**< timer object */
+
+
+/* ----------- variables ---------------------------------------------
+ */
+
+
+/* ----------- prototypes --------------------------------------------
+ */
+
+/** @brief creates and starts a new timer object.
+ *
+ * @param[in] microseconds in [usec]
+ *
+ * @returns a timer object on success, or zero otherwise
+ */
+timer_obj_t timer_new(uint32_t microseconds);
+
+
+/** @brief restarts an expired or running timer object.
+ *
+ * @param[in] self pointer to a timer object, or NULL (GPT0)
+ * @param[in] microseconds in [usec]
+ *
+ * @returns none-zero value on success, or zero otherwise
+ */
+int timer_restart(timer_obj_t *self, uint32_t microseconds);
+
+
+/** @brief returns True when the given timer object has expired.
+ *
+ * @param[in] self pointer to a timer object, or NULL (GPT0)
+ *
+ * @returns none-zero value when timed out, or zero otherwise
+ */
+int timer_timeout(timer_obj_t *self);
+
+
+/** @brief suspends the calling thread for the given time period.
+ *
+ * @param[in] microseconds in [usec]
+ *
+ * @returns none-zero value on success, or zero otherwise
+ */
+int timer_delay(uint32_t microseconds);
+
+
+#endif /* TIMER_H_INCLUDED */
+/** @}
+ */
+ /* ----------------------------------------------------------------------
+ * Uwe Vogt, UV Software, Chausseestrasse 33 A, 10115 Berlin, Germany
+ * Tel.: +49-30-46799872, Fax: +49-30-46799873, Mobile: +49-170-3801903
+ * E-Mail: uwe.vogt@uv-software.de, Homepage: http://www.uv-software.de/
+ */
diff --git a/Utilities/suppress.txt b/Utilities/suppress.txt
new file mode 100644
index 0000000..8b4c55b
--- /dev/null
+++ b/Utilities/suppress.txt
@@ -0,0 +1 @@
+missingIncludeSystem