├── LICENSE ├── README.md ├── busMaster ├── DS401_Master.c ├── DS401_Master.h ├── Makefile ├── TestMaster.c ├── TestMaster.h ├── TestMaster.od ├── config.xml ├── configParser.c ├── configParser.h ├── getopt.c ├── getopt.h └── run.sh ├── pics ├── CAN-Open-RasberryPi.png ├── blockDiagram.png ├── blockDiagram.svg └── temp.xml └── runsocat.sh /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # canopen-raspberrypi 2 | ##Background 3 | Have you ever needed an inexpensive control system to control a water fountain or animated haunted house display? CAN-Bus 4 | and CAN-Open were designed for applications like this. While the most common place to find CAN-Bus is in your car's 5 | [OBDII interface](http://pinoutsguide.com/CarElectronics/car_obd2_pinout.shtml), it isn't used too much in low cost control systems 6 | because of the high cost hardware. 7 | 8 | [CAN-Open](http://www.can-cia.org/index.php?id=canopen) is protocol that sits above the [CAN-Bus Physical/Data layer](http://www.can-cia.org/index.php?id=systemdesign-can-physicallayer), 9 | but it can also sit above other data layers. By a using a clever tool such as [socat](http://linux.die.net/man/1/socat), 10 | we can route CAN-Bus data traffic onto a datagram port, allowing devices such as cell phones and tablets direct access to the 11 | CAN-Bus data layer. 12 | 13 | This project aims to create a low cost CAN-bus to wifi interface on a RaspberryPi, see the block diagram below. The Pi allows an Android apps to connect to the can bus and 14 | directly send and recieve messages. Additionally, a bus master application runs on the PI to configure nodes on a CAN-Open network. 15 | The project has been broken down into several sub projects; 16 | - Setup of socat to route a CAN-Bus interface to a UDP port 17 | - [A CANOpen java library](https://github.com/Awalrod/CanOpenJavaLibrary) 18 | - [An Android app](https://github.com/Awalrod/AndroidCanOpenDemo) 19 | - A CanFestival Bus master to configure slave nodes 20 | 21 | ![Block Diagram](pics/blockDiagram.png) 22 | The magic of the project is socat. This tool makes CAN-Bus interface available on a UDP port. Once the CAN-Bus is available 23 | on a UDP port, any number of devices may connect to it through any Internet style interface (Ethernet, Wifi,...). 24 | 25 | #Hardware you will need 26 | ##Raspberry Pi 3 27 | Other versions of Pi's can be made to work, but the magic bullet for us was the built 28 | in Wifi interface on the Pi 3. The wifi hotspot integration is picky about which wifi hardware is used. We were not able 29 | get it to work with a Edimax N150 USB dongle. We aren't saying it can't be done, it just worked when we used the Pi 3's internal 30 | Wifi interface. 31 | ## An SPI/CAN bus card 32 | We initially used the [PiCan2](http://skpang.co.uk/catalog/pican2-canbus-board-for-raspberry-pi-2-p-1475.html), which uses 33 | the [Microchip MCP2515](http://www.microchip.com/wwwproducts/en/MCP2515) "Stand-Alone CAN Controller with SPI Interface". 34 | During later development we used our own in-house boards with the same IC. This IC is pretty well supported with the 35 | RasberryPI linux distrobution. 36 | ## CAN-Open slave nodes 37 | These things are availble, but are pretty expensive. We rolled our own. Llook for blatent product plug here in the 38 | near future. Many embedded microcontrollers have CAN-Bus interfaces on them. There don't seem to be many CAN-Open 39 | stacks available that support them. Again, we rolled our own. Until we can support selling low cost nodes, good luck to you! 40 | ##An Android tablet with Wifi 41 | We developed our app with two different tablets, A Samsung Galaxy Tab 4, and a Boox e-ink device. The Boox e-ink device has a 42 | slow screen update rate and is B&W, but it works awesomely when using it in the full sun. 43 | 44 | 45 | # Setting up the Raspberry Pi Can Bus Interface 46 | From a fresh Raspberry Pi install, install the following packages 47 | 48 | sudo apt-get update 49 | sudo apt-get dist-upgrade 50 | sudo apt-get install joe can-utils hostapd udhcpd rsync socat git 51 | sudo raspi-config 52 | enable spi 53 | expand filesystem 54 | enable i2c 55 | set hostname 56 | 57 | 58 | to setup the can bus interface 59 | sudo joe /boot/config.txt 60 | 61 | Add these 3 lines to the end of file: 62 | 63 | # can-bus see interface http://skpang.co.uk/blog/archives/1165 for details 64 | dtoverlay=mcp2515-can0,oscillator=16000000,interrupt=25 65 | dtoverlay=spi-bcm2835 66 | 67 | This will install the basic packages to allow you to bring up a can0 interface on the mcp2515 spi-can interface chip. The 68 | can0 interface is used with socat to allow wifi connections to the canbus interace 69 | 70 | # Setting up the socat server 71 | run `./runsocat.sh` from ~/canopen-raspberrypi which will bring up the interface and start a session of 72 | socat to put can0 on port 2000. Verify that can0 is up with `ifconfig` 73 | 74 | # Wifi hotspot configuration 75 | Setting up the wifi hotspot on the rasberry pi is beyond the scope of this project. An excellent tutorial is 76 | given at [RPI-Wireless-Hotspot](http://elinux.org/RPI-Wireless-Hotspot). You can ignore setting up the dns tools 77 | if the Pi will not be connecte to the internet. 78 | 79 | #Packages needed to use CanFestival 80 | The bus master software uses CanFestival, it will need to be installed in order to compile. 81 | Other packages that you will need to edit and compile CanFestival applications 82 | - python-wxgtk2.8 python-wxglade, to use the python ObjDict editor in CanFestival 83 | - diffuse, a nice gui text diffing tool 84 | - libxml2-dev, required to compile the busMaster tool later on 85 | All of these packages can be installed with the standard `sudo apt-get install ` syntax 86 | 87 | # Installing canfestival socket drivers 88 | Get the [Canfestival code](https://github.com/cmjonze/canfestival). 89 | - git https://github.com/cmjonze/canfestival 90 | - cd canfestival 91 | - ./configure --arch=arm32 --can=socket 92 | - make 93 | - sudo make install 94 | 95 | # busMaster 96 | CAN-Open is a distributed internodal communications system. A master/slave relationship exists in CAN-Open parlance, but 97 | the master is more of a dynamic information repository and state transition tool than it is a true *master* 98 | even though it can act like one. This busMaster tool relies heavily on CanFestival for the underlying 99 | CAN-Open infrastructure. 100 | 101 | The busMaster software does a few things. 102 | - it configures the dynamic information on the system when a new node comes online. The dynamic information is contained in config.xml 103 | - it sends out periodic sync signals 104 | - it puts nodes into the operational state once configured 105 | 106 | To add nodes to the bus unfortunatly, busMaster must be edited and recompiled with the new node ID. This requires the 107 | use of wxWidgets to add the correct SDO parameters. 108 | 109 | #to start canopen bus master 110 | .../busMaster 111 | ./run.sh 112 | 113 | #Android app 114 | The Android app is used to control and monitor nodes on the can bus. It is a slave device which the busMaster configures when connected. 115 | This most excellent package is available at [Android CAN-Open Demo] (https://github.com/Awalrod/AndroidCanOpenDemo) 116 | 117 | #CAN-Open-Java 118 | This package is used by the android app, but is kept separate because it is usefull as a generic java package. 119 | This package can be found [here](https://github.com/Awalrod/CanOpenJavaLibrary) 120 | 121 | 122 | -------------------------------------------------------------------------------- /busMaster/DS401_Master.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of CanFestival, a library implementing CanOpen Stack. 3 | 4 | Copyright (C): Edouard TISSERANT and Francis DUPIN 5 | 6 | See COPYING file for copyrights details. 7 | 8 | This library is free software; you can redistribute it and/or 9 | modify it under the terms of the GNU Lesser General Public 10 | License as published by the Free Software Foundation; either 11 | version 2.1 of the License, or (at your option) any later version. 12 | 13 | This library is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 | Lesser General Public License for more details. 17 | 18 | You should have received a copy of the GNU Lesser General Public 19 | License along with this library; if not, write to the Free Software 20 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 21 | */ 22 | #ifdef USE_XENO 23 | #define eprintf(...) 24 | #else 25 | #define eprintf(...) printf (__VA_ARGS__) 26 | #endif 27 | 28 | #include "canfestival.h" 29 | 30 | -------------------------------------------------------------------------------- /busMaster/Makefile: -------------------------------------------------------------------------------- 1 | #! gmake 2 | 3 | # 4 | # Copyright (C) 2006 Laurent Bessard 5 | # 6 | # This file is part of canfestival, a library implementing the canopen 7 | # stack 8 | # 9 | # This library is free software; you can redistribute it and/or 10 | # modify it under the terms of the GNU Lesser General Public 11 | # License as published by the Free Software Foundation; either 12 | # version 2.1 of the License, or (at your option) any later version. 13 | # 14 | # This library is distributed in the hope that it will be useful, 15 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 | # Lesser General Public License for more details. 18 | # 19 | # You should have received a copy of the GNU Lesser General Public 20 | # License along with this library; if not, write to the Free Software 21 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 22 | # 23 | 24 | CC = gcc-9.1 25 | CXX = g++ 26 | LD = gcc-9.1 27 | OPT_CFLAGS = -O2 28 | CFLAGS = $(OPT_CFLAGS) 29 | PROG_CFLAGS = 30 | EXE_CFLAGS = -lpthread -lrt -ldl 31 | OS_NAME = Linux 32 | ARCH_NAME = arm 33 | PREFIX = /usr/local 34 | TARGET = unix 35 | CAN_DRIVER = can_virtual 36 | TIMERS_DRIVER = timers_unix 37 | DIST_INSTALL_PATH=/usr/local/include/canfestival 38 | LIB_PATH=/usr/local/lib 39 | XML_INCLUDE_PATH=/usr/include/libxml2 40 | SYSD_LIB=$(shell pkg-config --libs libsystemd) 41 | SYSD_FLAGS=$(shell pkg-config --cflags libsystemd) 42 | 43 | INCLUDES = -I$(XML_INCLUDE_PATH) -I$(DIST_INSTALL_PATH) -I$(DIST_INSTALL_PATH)/$(TARGET) -I$(DIST_INSTALL_PATH)/$(CAN_DRIVER) -I$(DIST_INSTALL_PATH)/$(TIMERS_DRIVER) 44 | INCLUDES += $(SYSD_FLAGS) 45 | 46 | GITHEAD := -D'GIT_REV="$(shell git rev-list --count --first-parent HEAD)"' 47 | 48 | MASTER_OBJS = TestMaster.o DS401_Master.o configParser.o 49 | 50 | OBJS = $(MASTER_OBJS) $(LIB_PATH)/libcanfestival.a $(LIB_PATH)/libcanfestival_$(TARGET).a 51 | 52 | all: DS401_Master 53 | 54 | #../../drivers/$(TARGET)/libcanfestival_$(TARGET).a: 55 | # $(MAKE) -C ../../drivers/$(TARGET) libcanfestival_$(TARGET).a 56 | 57 | 58 | DS401_Master: TestMaster.c $(OBJS) 59 | $(LD) $(CFLAGS) $(GITHEAD) $(PROG_CFLAGS) -lxml2 ${PROGDEFINES} $(INCLUDES) -o $@ $(OBJS) $(SYSD_LIB) $(EXE_CFLAGS) 60 | 61 | 62 | TestMaster.c: TestMaster.od 63 | # $(MAKE) -C ../../objdictgen gnosis 64 | ../../canfestival/objdictgen/objdictgen.py TestMaster.od TestMaster.c 65 | edit: 66 | ../../canfestival/objdictgen/objdictedit.py TestMaster.od 67 | 68 | %.o: %.c 69 | $(CC) $(GITHEAD) $(CFLAGS) $(PROG_CFLAGS) ${PROGDEFINES} $(INCLUDES) -o $@ -c $< 70 | 71 | clean: 72 | rm -f *~ 73 | rm -f $(MASTER_OBJS) 74 | rm -f DS401_Master 75 | 76 | mrproper: clean 77 | rm -f TestMaster.c 78 | 79 | install: DS401_Master 80 | # mkdir -p $(DESTDIR)$(PREFIX)/bin/ 81 | sudo cp $< $(DESTDIR)$(PREFIX)/bin/ 82 | 83 | uninstall: 84 | rm -f $(DESTDIR)$(PREFIX)/bin/DS401_Master 85 | 86 | -------------------------------------------------------------------------------- /busMaster/TestMaster.h: -------------------------------------------------------------------------------- 1 | 2 | /* File generated by gen_cfile.py. Should not be modified. */ 3 | 4 | #ifndef TESTMASTER_H 5 | #define TESTMASTER_H 6 | 7 | #include "data.h" 8 | 9 | /* Prototypes of function provided by object dictionnary */ 10 | UNS32 TestMaster_valueRangeTest (UNS8 typeValue, void * value); 11 | const indextable * TestMaster_scanIndexOD (CO_Data *d, UNS16 wIndex, UNS32 * errorCode); 12 | 13 | /* Master node data struct */ 14 | extern CO_Data TestMaster_Data; 15 | extern UNS8 DO; /* Mapped at index 0x2000, subindex 0x00*/ 16 | extern INTEGER16 AO1; /* Mapped at index 0x2001, subindex 0x00*/ 17 | extern INTEGER16 AO2; /* Mapped at index 0x2002, subindex 0x00*/ 18 | extern INTEGER16 AO3; /* Mapped at index 0x2003, subindex 0x00*/ 19 | extern INTEGER16 AO4; /* Mapped at index 0x2004, subindex 0x00*/ 20 | extern INTEGER16 AI1; /* Mapped at index 0x2005, subindex 0x00*/ 21 | extern INTEGER16 AI2; /* Mapped at index 0x2006, subindex 0x00*/ 22 | extern INTEGER16 AI3; /* Mapped at index 0x2007, subindex 0x00*/ 23 | extern INTEGER16 AI4; /* Mapped at index 0x2008, subindex 0x00*/ 24 | extern INTEGER16 AI5; /* Mapped at index 0x2009, subindex 0x00*/ 25 | extern INTEGER16 AI6; /* Mapped at index 0x200A, subindex 0x00*/ 26 | extern INTEGER16 AI7; /* Mapped at index 0x200B, subindex 0x00*/ 27 | extern INTEGER16 AI8; /* Mapped at index 0x200C, subindex 0x00*/ 28 | extern UNS8 DI1; /* Mapped at index 0x200F, subindex 0x00*/ 29 | extern UNS8 DI2; /* Mapped at index 0x2010, subindex 0x00*/ 30 | extern UNS8 DI3; /* Mapped at index 0x2011, subindex 0x00*/ 31 | extern UNS8 DI4; /* Mapped at index 0x2012, subindex 0x00*/ 32 | extern UNS8 DI5; /* Mapped at index 0x2013, subindex 0x00*/ 33 | extern UNS8 DI6; /* Mapped at index 0x2014, subindex 0x00*/ 34 | extern UNS8 DI7; /* Mapped at index 0x2015, subindex 0x00*/ 35 | extern UNS8 DI8; /* Mapped at index 0x2016, subindex 0x00*/ 36 | 37 | #endif // TESTMASTER_H 38 | -------------------------------------------------------------------------------- /busMaster/TestMaster.od: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | TestMaster 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | 349 | 350 | 351 | 352 | 353 | 354 | 355 | 356 | 357 | 358 | 359 | 360 | 361 | 362 | 363 | 364 | 365 | 366 | 367 | 368 | 369 | 370 | 371 | 372 | 373 | 374 | 375 | 376 | 377 | 378 | 379 | 380 | 381 | 382 | 383 | 384 | 385 | 386 | 387 | 388 | 389 | 390 | 391 | 392 | 393 | 394 | 395 | 396 | 397 | 398 | 399 | 400 | 401 | 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | DO 419 | 420 | 421 | 422 | 423 | 424 | 425 | DO 426 | 427 | 428 | 429 | 430 | 431 | 432 | 433 | 434 | 435 | 436 | 437 | 438 | 439 | 440 | 441 | 442 | 443 | 444 | 445 | 446 | 447 | 448 | 449 | 450 | 451 | 452 | 453 | 454 | 455 | 456 | 457 | 458 | AO1 459 | 460 | 461 | 462 | 463 | 464 | 465 | AO1 466 | 467 | 468 | 469 | 470 | 471 | 472 | 473 | 474 | 475 | 476 | 477 | 478 | 479 | 480 | 481 | 482 | 483 | 484 | 485 | 486 | 487 | 488 | 489 | 490 | 491 | 492 | 493 | 494 | 495 | 496 | 497 | 498 | AO2 499 | 500 | 501 | 502 | 503 | 504 | 505 | AO2 506 | 507 | 508 | 509 | 510 | 511 | 512 | 513 | 514 | 515 | 516 | 517 | 518 | 519 | 520 | 521 | 522 | 523 | 524 | 525 | 526 | 527 | 528 | 529 | 530 | 531 | 532 | 533 | 534 | 535 | 536 | 537 | 538 | AO3 539 | 540 | 541 | 542 | 543 | 544 | 545 | AO3 546 | 547 | 548 | 549 | 550 | 551 | 552 | 553 | 554 | 555 | 556 | 557 | 558 | 559 | 560 | 561 | 562 | 563 | 564 | 565 | 566 | 567 | 568 | 569 | 570 | 571 | 572 | 573 | 574 | 575 | 576 | 577 | 578 | AO4 579 | 580 | 581 | 582 | 583 | 584 | 585 | AO4 586 | 587 | 588 | 589 | 590 | 591 | 592 | 593 | 594 | 595 | 596 | 597 | 598 | 599 | 600 | 601 | 602 | 603 | 604 | 605 | 606 | 607 | 608 | 609 | 610 | 611 | 612 | 613 | 614 | 615 | 616 | 617 | 618 | AI1 619 | 620 | 621 | 622 | 623 | 624 | 625 | AI1 626 | 627 | 628 | 629 | 630 | 631 | 632 | 633 | 634 | 635 | 636 | 637 | 638 | 639 | 640 | 641 | 642 | 643 | 644 | 645 | 646 | 647 | 648 | 649 | 650 | 651 | 652 | 653 | 654 | 655 | 656 | 657 | 658 | AI2 659 | 660 | 661 | 662 | 663 | 664 | 665 | AI2 666 | 667 | 668 | 669 | 670 | 671 | 672 | 673 | 674 | 675 | 676 | 677 | 678 | 679 | 680 | 681 | 682 | 683 | 684 | 685 | 686 | 687 | 688 | 689 | 690 | 691 | 692 | 693 | 694 | 695 | 696 | 697 | 698 | AI3 699 | 700 | 701 | 702 | 703 | 704 | 705 | AI3 706 | 707 | 708 | 709 | 710 | 711 | 712 | 713 | 714 | 715 | 716 | 717 | 718 | 719 | 720 | 721 | 722 | 723 | 724 | 725 | 726 | 727 | 728 | 729 | 730 | 731 | 732 | 733 | 734 | 735 | 736 | 737 | 738 | AI4 739 | 740 | 741 | 742 | 743 | 744 | 745 | AI4 746 | 747 | 748 | 749 | 750 | 751 | 752 | 753 | 754 | 755 | 756 | 757 | 758 | 759 | 760 | 761 | 762 | 763 | 764 | 765 | 766 | 767 | 768 | 769 | 770 | 771 | 772 | 773 | 774 | 775 | 776 | 777 | 778 | AI5 779 | 780 | 781 | 782 | 783 | 784 | 785 | AI5 786 | 787 | 788 | 789 | 790 | 791 | 792 | 793 | 794 | 795 | 796 | 797 | 798 | 799 | 800 | 801 | 802 | 803 | 804 | 805 | 806 | 807 | 808 | 809 | 810 | 811 | 812 | 813 | 814 | 815 | 816 | 817 | 818 | AI6 819 | 820 | 821 | 822 | 823 | 824 | 825 | AI6 826 | 827 | 828 | 829 | 830 | 831 | 832 | 833 | 834 | 835 | 836 | 837 | 838 | 839 | 840 | 841 | 842 | 843 | 844 | 845 | 846 | 847 | 848 | 849 | 850 | 851 | 852 | 853 | 854 | 855 | 856 | 857 | 858 | AI7 859 | 860 | 861 | 862 | 863 | 864 | 865 | AI7 866 | 867 | 868 | 869 | 870 | 871 | 872 | 873 | 874 | 875 | 876 | 877 | 878 | 879 | 880 | 881 | 882 | 883 | 884 | 885 | 886 | 887 | 888 | 889 | 890 | 891 | 892 | 893 | 894 | 895 | 896 | 897 | 898 | AI8 899 | 900 | 901 | 902 | 903 | 904 | 905 | AI8 906 | 907 | 908 | 909 | 910 | 911 | 912 | 913 | 914 | 915 | 916 | 917 | 918 | 919 | 920 | 921 | 922 | 923 | 924 | 925 | 926 | 927 | 928 | 929 | 930 | 931 | 932 | 933 | 934 | 935 | 936 | 937 | 938 | DI1 939 | 940 | 941 | 942 | 943 | 944 | 945 | DI1 946 | 947 | 948 | 949 | 950 | 951 | 952 | 953 | 954 | 955 | 956 | 957 | 958 | 959 | 960 | 961 | 962 | 963 | 964 | 965 | 966 | 967 | 968 | 969 | 970 | 971 | 972 | 973 | 974 | 975 | 976 | 977 | 978 | DI2 979 | 980 | 981 | 982 | 983 | 984 | 985 | DI2 986 | 987 | 988 | 989 | 990 | 991 | 992 | 993 | 994 | 995 | 996 | 997 | 998 | 999 | 1000 | 1001 | 1002 | 1003 | 1004 | 1005 | 1006 | 1007 | 1008 | 1009 | 1010 | 1011 | 1012 | 1013 | 1014 | 1015 | 1016 | 1017 | 1018 | DI3 1019 | 1020 | 1021 | 1022 | 1023 | 1024 | 1025 | DI3 1026 | 1027 | 1028 | 1029 | 1030 | 1031 | 1032 | 1033 | 1034 | 1035 | 1036 | 1037 | 1038 | 1039 | 1040 | 1041 | 1042 | 1043 | 1044 | 1045 | 1046 | 1047 | 1048 | 1049 | 1050 | 1051 | 1052 | 1053 | 1054 | 1055 | 1056 | 1057 | 1058 | DI4 1059 | 1060 | 1061 | 1062 | 1063 | 1064 | 1065 | DI4 1066 | 1067 | 1068 | 1069 | 1070 | 1071 | 1072 | 1073 | 1074 | 1075 | 1076 | 1077 | 1078 | 1079 | 1080 | 1081 | 1082 | 1083 | 1084 | 1085 | 1086 | 1087 | 1088 | 1089 | 1090 | 1091 | 1092 | 1093 | 1094 | 1095 | 1096 | 1097 | 1098 | DI5 1099 | 1100 | 1101 | 1102 | 1103 | 1104 | 1105 | DI5 1106 | 1107 | 1108 | 1109 | 1110 | 1111 | 1112 | 1113 | 1114 | 1115 | 1116 | 1117 | 1118 | 1119 | 1120 | 1121 | 1122 | 1123 | 1124 | 1125 | 1126 | 1127 | 1128 | 1129 | 1130 | 1131 | 1132 | 1133 | 1134 | 1135 | 1136 | 1137 | 1138 | DI6 1139 | 1140 | 1141 | 1142 | 1143 | 1144 | 1145 | DI6 1146 | 1147 | 1148 | 1149 | 1150 | 1151 | 1152 | 1153 | 1154 | 1155 | 1156 | 1157 | 1158 | 1159 | 1160 | 1161 | 1162 | 1163 | 1164 | 1165 | 1166 | 1167 | 1168 | 1169 | 1170 | 1171 | 1172 | 1173 | 1174 | 1175 | 1176 | 1177 | 1178 | DI7 1179 | 1180 | 1181 | 1182 | 1183 | 1184 | 1185 | DI7 1186 | 1187 | 1188 | 1189 | 1190 | 1191 | 1192 | 1193 | 1194 | 1195 | 1196 | 1197 | 1198 | 1199 | 1200 | 1201 | 1202 | 1203 | 1204 | 1205 | 1206 | 1207 | 1208 | 1209 | 1210 | 1211 | 1212 | 1213 | 1214 | 1215 | 1216 | 1217 | 1218 | DI8 1219 | 1220 | 1221 | 1222 | 1223 | 1224 | 1225 | DI8 1226 | 1227 | 1228 | 1229 | 1230 | 1231 | 1232 | 1233 | 1234 | 1235 | 1236 | 1237 | master 1238 | 1239 | 1240 | -------------------------------------------------------------------------------- /busMaster/config.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | libcanfestival_can_socket.so 5 | can0 6 | 500K 7 | 8 | 9 | 10 | spray head #1 11 | 0x41 12 | 1000 13 | 14 | 0x1C1 15 | 2 16 | 17 | 4000 18 | 19 | 20 | 21 | spray head #2 22 | 0x33 23 | 24 | 25 | Master Monitor Node 26 | 0x66 27 | 0x1234 28 | 29 | 0x1E6 30 | 2 31 | 32 | 4000 33 | 34 | 35 | 0x2E6 36 | 0xff 37 | 1000 38 | 4000 39 | 40 | 41 | 0x800003E6 42 | 43 | 44 | 0x800004E6 45 | 46 | 47 | 0x266 48 | 1 49 | 52 | 53 | 54 | 55 | 0x6401116 56 | 0x6401216 57 | 0x6401316 58 | 59 | 0x62021int8 60 | 0x12 61 | 62 | 0x10162int32 63 | 0x12345678 64 | 65 | 69 | 70 | 71 | 72 | Java Test.class 73 | 0x23 74 | 0x1234 75 | 76 | 0x1A3 77 | 2 78 | 79 | 4000 80 | 81 | 82 | 0x2A3 83 | 0xff 84 | 1000 85 | 4000 86 | 87 | 88 | 0x800003E6 89 | 90 | 91 | 0x800004E6 92 | 93 | 94 | 0x266 95 | 1 96 | 99 | 100 | 101 | 102 | 0x6401116 103 | 106 | 107 | 0x62020int8 108 | 0x12 109 | 110 | Analog Output Scaling registers 111 | 0x64461int32 112 | -65535 113 | 114 | 0x64462int32 115 | 65535 116 | 117 | 0x64463int32 118 | 255 119 | 120 | 124 | 125 | 126 | 127 | -------------------------------------------------------------------------------- /busMaster/configParser.c: -------------------------------------------------------------------------------- 1 | /* 2 | This file based on an example from CanFestival, a library implementing CanOpen Stack. 3 | */ 4 | 5 | /*---------------------------------------------------------------------------- 6 | * Headers 7 | *----------------------------------------------------------------------------*/ 8 | #include "configParser.h" 9 | nodeManagment* lookupNode(uint8_t nodeId); 10 | nodeManagment* addNodeToManagmentQ(uint8_t nodeId, void (*configureSlaveNode)(CO_Data* d, UNS8 nodeId)); 11 | 12 | /*---------------------------------------------------------------------------- 13 | * Local variables 14 | *----------------------------------------------------------------------------*/ 15 | char configLib[MAX_LIBNAME]; 16 | char busName[MAX_BUSNAME]; 17 | char baudRate[MAX_BUSNAME]; 18 | 19 | /*---------------------------------------------------------------------------- 20 | * Local functions 21 | *----------------------------------------------------------------------------*/ 22 | static void ConfigureSlaveNode(CO_Data* d, UNS8 nodeId); 23 | UNS8 getNodeId(CO_Data* d); 24 | 25 | // parses the document fragment for canfestival specific parameters 26 | void cp_parseCanFest(xmlTextReaderPtr reader); 27 | // parses the document fragment for canfestival specific parameters 28 | struct s_pdo* cp_parsePdoNode(xmlTextReaderPtr reader); 29 | void cp_dumpSlaveNode(struct s_slaveNode* ssn); 30 | 31 | // parses the document fragment for canfestival specific parameters 32 | struct s_slaveNode* cp_parseSlaveNode(xmlTextReaderPtr reader); 33 | 34 | // parses the document fragment for canfestival specific parameters 35 | void cp_parseSlaves(xmlTextReaderPtr reader, int updateNow); 36 | struct s_pdo_map_entry* cp_parsePdoMapEntryNode(xmlTextReaderPtr reader); 37 | 38 | /*---------------------------------------------------------------------------- 39 | * Local functions 40 | *----------------------------------------------------------------------------*/ 41 | 42 | xmlChar* cp_getTextInNode(xmlTextReaderPtr reader) 43 | { 44 | xmlChar* value; 45 | if(xmlTextReaderNodeType(reader) == XML_READER_TYPE_END_ELEMENT) 46 | return(NULL); 47 | int ret = xmlTextReaderRead(reader); 48 | while (ret == 1) 49 | { 50 | if( xmlTextReaderNodeType(reader)== XML_READER_TYPE_TEXT) 51 | { 52 | value = xmlTextReaderValue(reader); 53 | return(value); 54 | } 55 | if(xmlTextReaderNodeType(reader) == XML_READER_TYPE_END_ELEMENT) 56 | return(NULL); 57 | ret = xmlTextReaderRead(reader); 58 | } 59 | return(NULL); 60 | } 61 | 62 | 63 | // parses the document fragment for canfestival specific parameters 64 | void cp_parseCanFest(xmlTextReaderPtr reader) 65 | { 66 | while(1) 67 | { 68 | xmlTextReaderRead(reader); 69 | if(xmlTextReaderNodeType(reader) == XML_READER_TYPE_END_ELEMENT) 70 | { 71 | char* nodeName = (char*)xmlTextReaderName(reader); 72 | 73 | if( xmlStrEqual(nodeName, "can_fest") ) 74 | { 75 | return; 76 | } 77 | continue; 78 | } 79 | if(xmlTextReaderNodeType(reader) == XML_READER_TYPE_SIGNIFICANT_WHITESPACE) 80 | continue; 81 | if(xmlTextReaderNodeType(reader) == XML_READER_TYPE_COMMENT) continue; 82 | 83 | 84 | char* nodeName = (char*)xmlTextReaderName(reader); 85 | char* str = (char*)cp_getTextInNode(reader); 86 | 87 | if(debugging>2) { printf("name: (%s) val: (%s)\n",nodeName, str); } 88 | if( xmlStrEqual(nodeName, "lib") ) 89 | { 90 | strncpy(configLib, str, MAX_LIBNAME); 91 | LibraryPath = configLib; 92 | } 93 | else if( xmlStrEqual(nodeName, "interface") ) 94 | { 95 | strncpy(busName, str, MAX_BUSNAME); 96 | MasterBoard.busname = busName; 97 | } 98 | else if( xmlStrEqual(nodeName, "baud") ) 99 | { 100 | strncpy(baudRate, str, MAX_BUSNAME); 101 | MasterBoard.baudrate = baudRate; 102 | } 103 | } 104 | } 105 | 106 | 107 | // parses the document fragment for canfestival specific parameters 108 | struct s_pdo* cp_parsePdoNode(xmlTextReaderPtr reader) 109 | { 110 | struct s_pdo* newPdo = NULL; 111 | xmlChar* type = xmlTextReaderGetAttribute(reader, "type"); 112 | xmlChar* num = xmlTextReaderGetAttribute(reader, "num"); 113 | if( (type == NULL) || (num == NULL)) 114 | { 115 | printf("WARNING: pdo element found without 'type' or 'num' attribute, ignoring\n"); 116 | return(newPdo); 117 | } 118 | if(debugging>2) { printf("pdo attribute type: (%s) num: (%s)\n",type,num); } 119 | newPdo = (struct s_pdo*)malloc(sizeof(struct s_pdo)); 120 | if( newPdo == NULL) 121 | { 122 | exit(-5); 123 | } 124 | memset(newPdo,0,sizeof(struct s_pdo)); 125 | newPdo->stype = type; 126 | newPdo->snum = num; 127 | 128 | while(1) 129 | { 130 | xmlTextReaderRead(reader); 131 | if(xmlTextReaderNodeType(reader) == XML_READER_TYPE_END_ELEMENT) 132 | { 133 | char* nodeName = (char*)xmlTextReaderName(reader); 134 | 135 | if( xmlStrEqual(nodeName, "pdo") ) 136 | { 137 | return(newPdo); 138 | } 139 | continue; 140 | } 141 | if(xmlTextReaderNodeType(reader) == XML_READER_TYPE_SIGNIFICANT_WHITESPACE) 142 | continue; 143 | if(xmlTextReaderNodeType(reader) == XML_READER_TYPE_COMMENT) 144 | continue; 145 | 146 | 147 | xmlChar* nodeName = xmlTextReaderName(reader); 148 | xmlChar* str = cp_getTextInNode(reader); 149 | 150 | if(debugging>2) { printf("pdo info name: (%s) val: (%s)\n",nodeName, str); } 151 | if( xmlStrEqual(nodeName, "cobid") ) 152 | { 153 | newPdo->scobid = str; 154 | } 155 | else if( xmlStrEqual(nodeName, "transmission_type") ) 156 | { 157 | newPdo->stransmission_type = str; 158 | } 159 | else if( xmlStrEqual(nodeName, "inhibit_time") ) 160 | { 161 | newPdo->sinhibit_time = str; 162 | } 163 | else if( xmlStrEqual(nodeName, "event_timer") ) 164 | { 165 | newPdo->sevent_timer = str; 166 | } 167 | } 168 | } 169 | 170 | 171 | // parses the document fragment for canfestival specific parameters 172 | struct s_pdo_map* cp_parsePdoMapNode(xmlTextReaderPtr reader) 173 | { 174 | struct s_pdo_map* newPdoMap = NULL; 175 | xmlChar* type = xmlTextReaderGetAttribute(reader, "type"); 176 | xmlChar* num = xmlTextReaderGetAttribute(reader, "num"); 177 | if( (type == NULL) || (num == NULL)) 178 | { 179 | printf("WARNING: pdo element found without 'type' or 'num' attribute, ignoring\n"); 180 | return(newPdoMap); 181 | } 182 | if(debugging>2){ printf("pdo map attribute type: (%s) num: (%s)\n",type,num); } 183 | newPdoMap = (struct s_pdo_map*)malloc(sizeof(struct s_pdo_map)); 184 | if( newPdoMap == NULL) 185 | { 186 | exit(-5); 187 | } 188 | memset(newPdoMap,0,sizeof(struct s_pdo_map)); 189 | newPdoMap->stype = type; 190 | newPdoMap->snum = num; 191 | struct s_pdo_map_entry**next = &(newPdoMap->mapping); 192 | 193 | while(1) 194 | { 195 | xmlTextReaderRead(reader); 196 | if(xmlTextReaderNodeType(reader) == XML_READER_TYPE_END_ELEMENT) 197 | { 198 | char* nodeName = (char*)xmlTextReaderName(reader); 199 | 200 | if( xmlStrEqual(nodeName, "pdo_map") ) 201 | { 202 | return(newPdoMap); 203 | } 204 | continue; 205 | } 206 | if(xmlTextReaderNodeType(reader) == XML_READER_TYPE_SIGNIFICANT_WHITESPACE) 207 | continue; 208 | if(xmlTextReaderNodeType(reader) == XML_READER_TYPE_COMMENT) 209 | continue; 210 | 211 | xmlChar* nodeName = xmlTextReaderName(reader); 212 | 213 | if(debugging>2){ printf("pdo map info name: (%s)\n",nodeName); } 214 | if( xmlStrEqual(nodeName, "map") ) 215 | { 216 | struct s_pdo_map_entry* newEntry = cp_parsePdoMapEntryNode(reader); 217 | if(newEntry) 218 | { 219 | *next = newEntry; 220 | next = &(newEntry->next); 221 | } 222 | } 223 | } 224 | } 225 | 226 | 227 | // parses the document fragment for pdo mapping specific parameters 228 | struct s_pdo_map_entry* cp_parsePdoMapEntryNode(xmlTextReaderPtr reader) 229 | { 230 | struct s_pdo_map_entry* newPdoMapEntry = NULL; 231 | newPdoMapEntry = (struct s_pdo_map_entry*)malloc(sizeof(struct s_pdo_map_entry)); 232 | if( newPdoMapEntry == NULL) 233 | { 234 | exit(-5); 235 | } 236 | memset(newPdoMapEntry,0,sizeof(struct s_pdo_map_entry)); 237 | 238 | while(1) 239 | { 240 | xmlTextReaderRead(reader); 241 | if(xmlTextReaderNodeType(reader) == XML_READER_TYPE_END_ELEMENT) 242 | { 243 | char* nodeName = (char*)xmlTextReaderName(reader); 244 | 245 | if( xmlStrEqual(nodeName, "map") ) 246 | { 247 | return(newPdoMapEntry); 248 | } 249 | continue; 250 | } 251 | if(xmlTextReaderNodeType(reader) == XML_READER_TYPE_SIGNIFICANT_WHITESPACE) 252 | continue; 253 | if(xmlTextReaderNodeType(reader) == XML_READER_TYPE_COMMENT) 254 | continue; 255 | 256 | 257 | xmlChar* nodeName = xmlTextReaderName(reader); 258 | xmlChar* str = cp_getTextInNode(reader); 259 | 260 | if(debugging>2){ printf("pdo map info name: (%s) val: (%s)\n",nodeName, str); } 261 | if( xmlStrEqual(nodeName, "index") ) 262 | { 263 | newPdoMapEntry->sindex = str; 264 | } 265 | else if( xmlStrEqual(nodeName, "subindex") ) 266 | { 267 | newPdoMapEntry->ssub = str; 268 | } 269 | else if( xmlStrEqual(nodeName, "num_bits") ) 270 | { 271 | newPdoMapEntry->snumBits = str; 272 | } 273 | } 274 | } 275 | 276 | #define NEW_INSTANCE(type, name) struct type* name = (struct type*)malloc(sizeof(struct type));\ 277 | if( name == NULL) exit(-5); \ 278 | memset(name,0,sizeof(struct type)); 279 | 280 | 281 | // parses the document fragment for pdo mapping specific parameters 282 | struct s_obj_dict* cp_parseObjDictNode(xmlTextReaderPtr reader) 283 | { 284 | // struct s_obj_dict* newObjDict = (struct s_obj_dict*)malloc(sizeof(struct s_obj_dict)); 285 | // if( newObjDict == NULL) 286 | // exit(-5); 287 | // memset(newObjDict,0,sizeof(struct s_obj_dict)); 288 | NEW_INSTANCE(s_obj_dict, newObjDict); 289 | 290 | while(1) 291 | { 292 | xmlTextReaderRead(reader); 293 | if(xmlTextReaderNodeType(reader) == XML_READER_TYPE_END_ELEMENT) 294 | { 295 | char* nodeName = (char*)xmlTextReaderName(reader); 296 | if( xmlStrEqual(nodeName, "obj_dict") ) 297 | { 298 | return(newObjDict); 299 | } 300 | continue; 301 | } 302 | if(xmlTextReaderNodeType(reader) == XML_READER_TYPE_SIGNIFICANT_WHITESPACE) 303 | continue; 304 | if(xmlTextReaderNodeType(reader) == XML_READER_TYPE_COMMENT) 305 | continue; 306 | 307 | 308 | xmlChar* nodeName = xmlTextReaderName(reader); 309 | xmlChar* str = cp_getTextInNode(reader); 310 | 311 | if(debugging>2){ printf("obj_dict info name: (%s) val: (%s)\n",nodeName, str); } 312 | 313 | if( xmlStrEqual(nodeName, "index") ) 314 | { 315 | newObjDict->sindex = str; 316 | } 317 | else if( xmlStrEqual(nodeName, "subindex") ) 318 | { 319 | newObjDict->ssub = str; 320 | } 321 | else if( xmlStrEqual(nodeName, "type") ) 322 | { 323 | newObjDict->stype = str; 324 | } 325 | else if( xmlStrEqual(nodeName, "val") ) 326 | { 327 | newObjDict->sval = str; 328 | } 329 | } 330 | } 331 | 332 | 333 | void dumpSlaveNode(struct s_slaveNode* ssn) 334 | { 335 | int i; 336 | if(debugging>2) 337 | { 338 | printf("slaveNode id(%s) name(%s)", ssn->sid, ssn->sname); 339 | printf(" nodeid(%s) hb(%s) \n", ssn->snodeId, ssn->sheartbeatTime); 340 | for(i=0; i<4; i++) 341 | { 342 | if(ssn->txPdo[i] != NULL) 343 | { 344 | printf("txpdo%d (%s) (%s) (%s)", i+1, ssn->txPdo[i]->stype,ssn->txPdo[i]->snum,ssn->txPdo[i]->scobid ); 345 | printf(" (%s) (%s) (%s)\n", ssn->txPdo[i]->stransmission_type, ssn->txPdo[i]->sinhibit_time, ssn->txPdo[i]->sevent_timer ); 346 | } 347 | } 348 | for(i=0; i<4; i++) 349 | { 350 | if(ssn->rxPdo[i] != NULL) 351 | { 352 | printf("rxpdo%d (%s) (%s) (%s)", i+1, ssn->txPdo[i]->stype,ssn->txPdo[i]->snum,ssn->txPdo[i]->scobid ); 353 | printf(" (%s) (%s) (%s)\n", ssn->txPdo[i]->stransmission_type, ssn->txPdo[i]->sinhibit_time, ssn->txPdo[i]->sevent_timer ); 354 | } 355 | } 356 | struct s_obj_dict* pobjdict = ssn->objDict; 357 | 358 | while(pobjdict!=NULL) 359 | { 360 | pobjdict = pobjdict->nextObjDict; 361 | } 362 | printf("\n"); 363 | } 364 | } 365 | 366 | // parses the document fragment for canfestival specific parameters 367 | struct s_slaveNode* cp_parseSlaveNode(xmlTextReaderPtr reader) 368 | { 369 | struct s_slaveNode* newSN = (struct s_slaveNode*)malloc(sizeof(struct s_slaveNode)); 370 | if( newSN == NULL) 371 | { 372 | exit(-5); 373 | } 374 | memset(newSN,0,sizeof(struct s_slaveNode)); 375 | newSN->sid = xmlTextReaderGetAttribute(reader, "id"); 376 | newSN->pdoMap = NULL; 377 | while(1) 378 | { 379 | 380 | xmlTextReaderRead(reader); 381 | if(xmlTextReaderNodeType(reader) == XML_READER_TYPE_END_ELEMENT) 382 | { 383 | char* nodeName = (char*)xmlTextReaderName(reader); 384 | 385 | if( xmlStrEqual(nodeName, "node") ) 386 | { 387 | return(newSN); 388 | } 389 | continue; 390 | } 391 | if(xmlTextReaderNodeType(reader) == XML_READER_TYPE_SIGNIFICANT_WHITESPACE) 392 | continue; 393 | if(xmlTextReaderNodeType(reader) == XML_READER_TYPE_COMMENT) 394 | continue; 395 | 396 | xmlChar* nodeName = xmlTextReaderName(reader); 397 | if( xmlStrEqual(nodeName, "pdo")) 398 | { 399 | struct s_pdo* spdo = cp_parsePdoNode(reader); 400 | if(spdo) 401 | { 402 | int num = strtol(spdo->snum, NULL, 0); 403 | if(num < 1 || num > 4) 404 | { 405 | printf("WARNING: pdo 'num' out of range %d ignoring\n",num); 406 | continue; 407 | } 408 | if(xmlStrcasecmp(spdo->stype, "rx") == 0) 409 | { 410 | newSN->rxPdo[num-1] = spdo; 411 | } 412 | else if(xmlStrcasecmp(spdo->stype, "tx") == 0) 413 | { 414 | newSN->txPdo[num-1] = spdo; 415 | } 416 | else 417 | { 418 | printf("WARNING: pdo 'type' out of range %x ignoring\n",spdo->stype); 419 | continue; 420 | } 421 | } 422 | 423 | } 424 | else if( xmlStrEqual(nodeName, "pdo_map")) 425 | { 426 | struct s_pdo_map* spdoMap = cp_parsePdoMapNode(reader); 427 | if(spdoMap) 428 | { 429 | int num = strtol(spdoMap->snum, NULL, 0); 430 | if(num < 1 || num > 4) 431 | { 432 | printf("WARNING: pdo 'num' out of range %d ignoring\n",num); 433 | continue; 434 | } 435 | if(xmlStrcasecmp(spdoMap->stype, "rx") == 0) 436 | { 437 | spdoMap->nextPdoMap = newSN->pdoMap; 438 | newSN->pdoMap = spdoMap; 439 | } 440 | else if(xmlStrcasecmp(spdoMap->stype, "tx") == 0) 441 | { 442 | spdoMap->nextPdoMap = newSN->pdoMap; 443 | newSN->pdoMap = spdoMap; 444 | } 445 | else 446 | { 447 | printf("WARNING: pdo 'type' out of range %x ignoring\n",spdoMap->stype); 448 | continue; 449 | } 450 | } 451 | 452 | } 453 | else if( xmlStrEqual(nodeName, "obj_dict")) 454 | { 455 | struct s_obj_dict* objDict = cp_parseObjDictNode(reader); 456 | if(objDict) 457 | { 458 | objDict->nextObjDict = newSN->objDict; 459 | newSN->objDict = objDict; 460 | } 461 | 462 | } 463 | else 464 | { 465 | char* str = (char*)cp_getTextInNode(reader); 466 | 467 | if(debugging>2) { printf("sn name: (%s) val: (%s)\n",nodeName, str); } 468 | if( xmlStrEqual(nodeName, "name") ) 469 | { 470 | newSN->sname = str; 471 | } 472 | else if( xmlStrEqual(nodeName, "nodeid") ) 473 | { 474 | newSN->snodeId = str; 475 | } 476 | else if( xmlStrEqual(nodeName, "heartbeat_time") ) 477 | { 478 | newSN->sheartbeatTime = str; 479 | } 480 | } 481 | } 482 | } 483 | 484 | int TMMM_ObjDictWrite( struct s_slaveNode* ci); 485 | 486 | // parses the document fragment for canfestival specific parameters 487 | void cp_parseSlaves(xmlTextReaderPtr reader, int updateNow) 488 | { 489 | while(1) 490 | { 491 | xmlTextReaderRead(reader); 492 | if(xmlTextReaderNodeType(reader) == XML_READER_TYPE_END_ELEMENT) 493 | { 494 | char* nodeName = (char*)xmlTextReaderName(reader); 495 | 496 | if( xmlStrEqual(nodeName, "slave_nodes") ) 497 | { 498 | return; 499 | } 500 | continue; 501 | } 502 | if(xmlTextReaderNodeType(reader) == XML_READER_TYPE_SIGNIFICANT_WHITESPACE) 503 | continue; 504 | if(xmlTextReaderNodeType(reader) == XML_READER_TYPE_COMMENT) 505 | continue; 506 | 507 | 508 | if(debugging>2) { printf("%s\n", (char*)xmlTextReaderName(reader)); } 509 | if(xmlStrEqual(xmlTextReaderName(reader), "node") ) 510 | { 511 | struct s_slaveNode* sn = cp_parseSlaveNode(reader); 512 | if(debugging) 513 | dumpSlaveNode(sn); 514 | 515 | if(sn->snodeId == NULL) 516 | { 517 | printf("WARNING: node config did not contain a nodeid, skiping\n"); 518 | continue; 519 | } 520 | 521 | if(updateNow) 522 | { 523 | // dumpSlaveNode(sn); 524 | TMMM_ObjDictWrite(sn); 525 | } 526 | else 527 | { 528 | int nodeid = strtol(sn->snodeId, NULL, 0); 529 | nodeManagment* nmp = lookupNode(nodeid); 530 | if(nmp == NULL) 531 | { 532 | if(debugging>2){ printf("node not found in queue, adding for 0x%02x\n",nodeid);} 533 | 534 | nmp = addNodeToManagmentQ(nodeid, NULL); 535 | } 536 | nmp->configInfo = sn; 537 | } 538 | } 539 | } 540 | } 541 | 542 | int cp_parseConfig(xmlTextReaderPtr reader, int updateNow) 543 | { //this method parses the xml document and populates a linked list called boundsValueList 544 | int ret = 1; 545 | struct valueNode* lastNode; 546 | 547 | while(ret == 1) 548 | { 549 | ret = xmlTextReaderRead(reader); 550 | if(xmlTextReaderNodeType(reader) == XML_READER_TYPE_SIGNIFICANT_WHITESPACE) continue; 551 | if(xmlTextReaderNodeType(reader) == XML_READER_TYPE_COMMENT) continue; 552 | 553 | if(xmlTextReaderNodeType(reader) == XML_READER_TYPE_END_ELEMENT) 554 | { 555 | if(xmlStrEqual(xmlTextReaderName(reader), "config") ) 556 | { 557 | ret = 0; 558 | break; 559 | } 560 | continue; 561 | } 562 | if(debugging>2) { printf("%s\n", (char*)xmlTextReaderName(reader)); } 563 | if(xmlStrEqual(xmlTextReaderName(reader), "can_fest") ) 564 | { 565 | cp_parseCanFest(reader); 566 | } 567 | if(xmlStrEqual(xmlTextReaderName(reader), "slave_nodes") ) 568 | { 569 | cp_parseSlaves(reader, updateNow); 570 | } 571 | } // end while 572 | xmlFreeTextReader(reader); 573 | return(ret); 574 | } 575 | 576 | /*---------------------------------------------------------------------------- 577 | * Exported functions 578 | *----------------------------------------------------------------------------*/ 579 | 580 | // opens and parses a config file for two specific documenet fragments 581 | // and 582 | int CP_parseConfigFile(char *filename) 583 | { //this method parses the xml document and populates a linked list called boundsValueList 584 | int ret = 1; 585 | struct valueNode* lastNode; 586 | xmlTextReaderPtr reader = xmlNewTextReaderFilename(filename); 587 | if(reader == NULL) 588 | { 589 | printf("ERROR: Unable to open <%s>\n", filename); 590 | return(-1); 591 | } 592 | 593 | ret = cp_parseConfig(reader, 0); 594 | if (ret == -1) 595 | { 596 | printf("ERROR %s : failed to parse %d\n", filename, ret); 597 | } 598 | return(ret); 599 | } 600 | 601 | int CP_ParseMemory(char* string) 602 | { 603 | int ret = 1; 604 | xmlTextReaderPtr reader = xmlReaderForMemory(string, strlen(string), "", NULL, 0); 605 | if(reader == NULL) 606 | { 607 | printf("ERROR: Unable to open reader for (%s)\n", string); 608 | return(-1); 609 | } 610 | 611 | ret = cp_parseConfig(reader, 1); 612 | if (ret == -1) 613 | { 614 | printf("ERROR failed to parse %d\n", ret); 615 | } 616 | return(ret); 617 | } 618 | -------------------------------------------------------------------------------- /busMaster/configParser.h: -------------------------------------------------------------------------------- 1 | #ifndef _CONFIG_PARSER 2 | #define _CONFIG_PARSER 3 | /*---------------------------------------------------------------------------- 4 | * Headers 5 | *----------------------------------------------------------------------------*/ 6 | #if defined(WIN32) && !defined(__CYGWIN__) 7 | #include 8 | #include "getopt.h" 9 | void pause(void) 10 | { 11 | system("PAUSE"); 12 | } 13 | #else 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #endif 23 | 24 | #include "canfestival.h" 25 | 26 | 27 | /*---------------------------------------------------------------------------- 28 | * definitions 29 | *----------------------------------------------------------------------------*/ 30 | #define MAX_FILENAME 0x200 31 | #define MAX_LIBNAME 0x200 32 | #define MAX_BUSNAME 0x20 33 | 34 | struct s_pdo 35 | { 36 | xmlChar* stype; 37 | xmlChar* snum; 38 | xmlChar* scobid; 39 | xmlChar* stransmission_type; 40 | xmlChar* sinhibit_time; 41 | xmlChar* sevent_timer; 42 | }; 43 | 44 | struct s_pdo_map_entry 45 | { 46 | xmlChar* sindex; 47 | xmlChar* ssub; 48 | xmlChar* snumBits; 49 | struct s_pdo_map_entry* next; 50 | }; 51 | 52 | struct s_pdo_map 53 | { 54 | xmlChar* stype; 55 | xmlChar* snum; 56 | struct s_pdo_map_entry* mapping; 57 | struct s_pdo_map* nextPdoMap; 58 | }; 59 | 60 | SLIST_HEAD(pdomapq, s_pdo_map); 61 | 62 | struct s_obj_dict 63 | { 64 | xmlChar* sindex; 65 | xmlChar* ssub; 66 | xmlChar* stype; 67 | xmlChar* sval; 68 | struct s_obj_dict* nextObjDict; 69 | }; 70 | 71 | struct s_slaveNode 72 | { 73 | xmlChar* sid; 74 | xmlChar* sname; 75 | xmlChar* snodeId; 76 | xmlChar* sheartbeatTime; 77 | struct s_pdo* rxPdo[4]; 78 | struct s_pdo* txPdo[4]; 79 | struct s_pdo_map* pdoMap; 80 | struct s_obj_dict* objDict; 81 | 82 | // these three parameters are used when supplying pdo maps to nodes during initialization 83 | struct s_pdo_map* currPdoMap; 84 | struct s_pdo_map_entry* currPdoMapEntry; 85 | UNS8 mapEntryIndex; 86 | 87 | int pdoInfoStep; 88 | UNS32 pdoCobId; 89 | int pdoIndex; 90 | }; 91 | 92 | //struct pdomapq nodeManQ; 93 | //struct td_nodeManagment* nextNode = NULL; 94 | 95 | 96 | typedef struct td_nodeManagment 97 | { 98 | uint8_t nodeId; 99 | uint16_t initStep; 100 | void (*configureSlaveNode)(CO_Data* d, UNS8 nodeId); 101 | struct s_slaveNode* configInfo; 102 | TAILQ_ENTRY(td_nodeManagment) tailq; 103 | } nodeManagment; 104 | 105 | 106 | /*---------------------------------------------------------------------------- 107 | * Local variables 108 | *----------------------------------------------------------------------------*/ 109 | extern UNS8 masterNodeId; 110 | extern s_BOARD MasterBoard; 111 | extern int debugging; 112 | extern char configLib[]; 113 | extern char busName[]; 114 | extern char baudRate[]; 115 | extern char* LibraryPath; 116 | 117 | // opens and parses a config file for two specific documenet fragments 118 | // and 119 | int CP_parseConfigFile(char *filename); 120 | 121 | // parses a document from a socket and updates immediatly 122 | int CP_ParseMemory(char* string); 123 | 124 | 125 | #endif 126 | -------------------------------------------------------------------------------- /busMaster/getopt.c: -------------------------------------------------------------------------------- 1 | /* from http://www.pwilson.net/getopt.html */ 2 | 3 | /* Getopt for GNU. 4 | NOTE: getopt is now part of the C library, so if you don't know what 5 | "Keep this file name-space clean" means, talk to drepper@gnu.org 6 | before changing it! 7 | Copyright (C) 1987,88,89,90,91,92,93,94,95,96,98,99,2000,2001 8 | Free Software Foundation, Inc. 9 | This file is part of the GNU C Library. 10 | 11 | The GNU C Library is free software; you can redistribute it and/or 12 | modify it under the terms of the GNU Lesser General Public 13 | License as published by the Free Software Foundation; either 14 | version 2.1 of the License, or (at your option) any later version. 15 | 16 | The GNU C Library is distributed in the hope that it will be useful, 17 | but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 19 | Lesser General Public License for more details. 20 | 21 | You should have received a copy of the GNU Lesser General Public 22 | License along with the GNU C Library; if not, write to the Free 23 | Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 24 | 02111-1307 USA. */ 25 | 26 | /* This tells Alpha OSF/1 not to define a getopt prototype in . 27 | Ditto for AIX 3.2 and . */ 28 | #ifndef _NO_PROTO 29 | # define _NO_PROTO 30 | #endif 31 | 32 | #ifdef HAVE_CONFIG_H 33 | # include 34 | #endif 35 | 36 | #if !defined __STDC__ || !__STDC__ 37 | /* This is a separate conditional since some stdc systems 38 | reject `defined (const)'. */ 39 | # ifndef const 40 | # define const 41 | # endif 42 | #endif 43 | 44 | #include 45 | 46 | /* Comment out all this code if we are using the GNU C Library, and are not 47 | actually compiling the library itself. This code is part of the GNU C 48 | Library, but also included in many other GNU distributions. Compiling 49 | and linking in this code is a waste when using the GNU C library 50 | (especially if it is a shared library). Rather than having every GNU 51 | program understand `configure --with-gnu-libc' and omit the object files, 52 | it is simpler to just do this in the source for each such file. */ 53 | 54 | #define GETOPT_INTERFACE_VERSION 2 55 | #if !defined _LIBC && defined __GLIBC__ && __GLIBC__ >= 2 56 | # include 57 | # if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION 58 | # define ELIDE_CODE 59 | # endif 60 | #endif 61 | 62 | #ifndef ELIDE_CODE 63 | 64 | 65 | /* This needs to come after some library #include 66 | to get __GNU_LIBRARY__ defined. */ 67 | #ifdef __GNU_LIBRARY__ 68 | /* Don't include stdlib.h for non-GNU C libraries because some of them 69 | contain conflicting prototypes for getopt. */ 70 | # include 71 | # include 72 | #endif /* GNU C library. */ 73 | 74 | #ifdef VMS 75 | # include 76 | # if HAVE_STRING_H - 0 77 | # include 78 | # endif 79 | #endif 80 | 81 | #ifndef _ 82 | /* This is for other GNU distributions with internationalized messages. */ 83 | # if (HAVE_LIBINTL_H && ENABLE_NLS) || defined _LIBC 84 | # include 85 | # ifndef _ 86 | # define _(msgid) gettext (msgid) 87 | # endif 88 | # else 89 | # define _(msgid) (msgid) 90 | # endif 91 | # if defined _LIBC && defined USE_IN_LIBIO 92 | # include 93 | # endif 94 | #endif 95 | 96 | /* This version of `getopt' appears to the caller like standard Unix `getopt' 97 | but it behaves differently for the user, since it allows the user 98 | to intersperse the options with the other arguments. 99 | 100 | As `getopt' works, it permutes the elements of ARGV so that, 101 | when it is done, all the options precede everything else. Thus 102 | all application programs are extended to handle flexible argument order. 103 | 104 | Setting the environment variable POSIXLY_CORRECT disables permutation. 105 | Then the behavior is completely standard. 106 | 107 | GNU application programs can use a third alternative mode in which 108 | they can distinguish the relative order of options and other arguments. */ 109 | 110 | #include "getopt.h" 111 | 112 | /* For communication from `getopt' to the caller. 113 | When `getopt' finds an option that takes an argument, 114 | the argument value is returned here. 115 | Also, when `ordering' is RETURN_IN_ORDER, 116 | each non-option ARGV-element is returned here. */ 117 | 118 | char *optarg; 119 | 120 | /* Index in ARGV of the next element to be scanned. 121 | This is used for communication to and from the caller 122 | and for communication between successive calls to `getopt'. 123 | 124 | On entry to `getopt', zero means this is the first call; initialize. 125 | 126 | When `getopt' returns -1, this is the index of the first of the 127 | non-option elements that the caller should itself scan. 128 | 129 | Otherwise, `optind' communicates from one call to the next 130 | how much of ARGV has been scanned so far. */ 131 | 132 | /* 1003.2 says this must be 1 before any call. */ 133 | int optind = 1; 134 | 135 | /* Formerly, initialization of getopt depended on optind==0, which 136 | causes problems with re-calling getopt as programs generally don't 137 | know that. */ 138 | 139 | int __getopt_initialized; 140 | 141 | /* The next char to be scanned in the option-element 142 | in which the last option character we returned was found. 143 | This allows us to pick up the scan where we left off. 144 | 145 | If this is zero, or a null string, it means resume the scan 146 | by advancing to the next ARGV-element. */ 147 | 148 | static char *nextchar; 149 | 150 | /* Callers store zero here to inhibit the error message 151 | for unrecognized options. */ 152 | 153 | int opterr = 1; 154 | 155 | /* Set to an option character which was unrecognized. 156 | This must be initialized on some systems to avoid linking in the 157 | system's own getopt implementation. */ 158 | 159 | int optopt = '?'; 160 | 161 | /* Describe how to deal with options that follow non-option ARGV-elements. 162 | 163 | If the caller did not specify anything, 164 | the default is REQUIRE_ORDER if the environment variable 165 | POSIXLY_CORRECT is defined, PERMUTE otherwise. 166 | 167 | REQUIRE_ORDER means don't recognize them as options; 168 | stop option processing when the first non-option is seen. 169 | This is what Unix does. 170 | This mode of operation is selected by either setting the environment 171 | variable POSIXLY_CORRECT, or using `+' as the first character 172 | of the list of option characters. 173 | 174 | PERMUTE is the default. We permute the contents of ARGV as we scan, 175 | so that eventually all the non-options are at the end. This allows options 176 | to be given in any order, even with programs that were not written to 177 | expect this. 178 | 179 | RETURN_IN_ORDER is an option available to programs that were written 180 | to expect options and other ARGV-elements in any order and that care about 181 | the ordering of the two. We describe each non-option ARGV-element 182 | as if it were the argument of an option with character code 1. 183 | Using `-' as the first character of the list of option characters 184 | selects this mode of operation. 185 | 186 | The special argument `--' forces an end of option-scanning regardless 187 | of the value of `ordering'. In the case of RETURN_IN_ORDER, only 188 | `--' can cause `getopt' to return -1 with `optind' != ARGC. */ 189 | 190 | static enum 191 | { 192 | REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER 193 | } ordering; 194 | 195 | /* Value of POSIXLY_CORRECT environment variable. */ 196 | static char *posixly_correct; 197 | 198 | #ifdef __GNU_LIBRARY__ 199 | /* We want to avoid inclusion of string.h with non-GNU libraries 200 | because there are many ways it can cause trouble. 201 | On some systems, it contains special magic macros that don't work 202 | in GCC. */ 203 | # include 204 | # define my_index strchr 205 | #else 206 | 207 | # if HAVE_STRING_H || WIN32 /* Pete Wilson mod 7/28/02 */ 208 | # include 209 | # else 210 | # include 211 | # endif 212 | 213 | /* Avoid depending on library functions or files 214 | whose names are inconsistent. */ 215 | 216 | #ifndef getenv 217 | extern char *getenv (); 218 | #endif 219 | 220 | static char * 221 | my_index (str, chr) 222 | const char *str; 223 | int chr; 224 | { 225 | while (*str) 226 | { 227 | if (*str == chr) 228 | return (char *) str; 229 | str++; 230 | } 231 | return 0; 232 | } 233 | 234 | /* If using GCC, we can safely declare strlen this way. 235 | If not using GCC, it is ok not to declare it. */ 236 | #ifdef __GNUC__ 237 | /* Note that Motorola Delta 68k R3V7 comes with GCC but not stddef.h. 238 | That was relevant to code that was here before. */ 239 | # if (!defined __STDC__ || !__STDC__) && !defined strlen 240 | /* gcc with -traditional declares the built-in strlen to return int, 241 | and has done so at least since version 2.4.5. -- rms. */ 242 | extern int strlen (const char *); 243 | # endif /* not __STDC__ */ 244 | #endif /* __GNUC__ */ 245 | 246 | #endif /* not __GNU_LIBRARY__ */ 247 | 248 | /* Handle permutation of arguments. */ 249 | 250 | /* Describe the part of ARGV that contains non-options that have 251 | been skipped. `first_nonopt' is the index in ARGV of the first of them; 252 | `last_nonopt' is the index after the last of them. */ 253 | 254 | static int first_nonopt; 255 | static int last_nonopt; 256 | 257 | #ifdef _LIBC 258 | /* Stored original parameters. 259 | XXX This is no good solution. We should rather copy the args so 260 | that we can compare them later. But we must not use malloc(3). */ 261 | extern int __libc_argc; 262 | extern char **__libc_argv; 263 | 264 | /* Bash 2.0 gives us an environment variable containing flags 265 | indicating ARGV elements that should not be considered arguments. */ 266 | 267 | # ifdef USE_NONOPTION_FLAGS 268 | /* Defined in getopt_init.c */ 269 | extern char *__getopt_nonoption_flags; 270 | 271 | static int nonoption_flags_max_len; 272 | static int nonoption_flags_len; 273 | # endif 274 | 275 | # ifdef USE_NONOPTION_FLAGS 276 | # define SWAP_FLAGS(ch1, ch2) \ 277 | if (nonoption_flags_len > 0) \ 278 | { \ 279 | char __tmp = __getopt_nonoption_flags[ch1]; \ 280 | __getopt_nonoption_flags[ch1] = __getopt_nonoption_flags[ch2]; \ 281 | __getopt_nonoption_flags[ch2] = __tmp; \ 282 | } 283 | # else 284 | # define SWAP_FLAGS(ch1, ch2) 285 | # endif 286 | #else /* !_LIBC */ 287 | # define SWAP_FLAGS(ch1, ch2) 288 | #endif /* _LIBC */ 289 | 290 | /* Exchange two adjacent subsequences of ARGV. 291 | One subsequence is elements [first_nonopt,last_nonopt) 292 | which contains all the non-options that have been skipped so far. 293 | The other is elements [last_nonopt,optind), which contains all 294 | the options processed since those non-options were skipped. 295 | 296 | `first_nonopt' and `last_nonopt' are relocated so that they describe 297 | the new indices of the non-options in ARGV after they are moved. */ 298 | 299 | #if defined __STDC__ && __STDC__ 300 | static void exchange (char **); 301 | #endif 302 | 303 | static void 304 | exchange (argv) 305 | char **argv; 306 | { 307 | int bottom = first_nonopt; 308 | int middle = last_nonopt; 309 | int top = optind; 310 | char *tem; 311 | 312 | /* Exchange the shorter segment with the far end of the longer segment. 313 | That puts the shorter segment into the right place. 314 | It leaves the longer segment in the right place overall, 315 | but it consists of two parts that need to be swapped next. */ 316 | 317 | #if defined _LIBC && defined USE_NONOPTION_FLAGS 318 | /* First make sure the handling of the `__getopt_nonoption_flags' 319 | string can work normally. Our top argument must be in the range 320 | of the string. */ 321 | if (nonoption_flags_len > 0 && top >= nonoption_flags_max_len) 322 | { 323 | /* We must extend the array. The user plays games with us and 324 | presents new arguments. */ 325 | char *new_str = malloc (top + 1); 326 | if (new_str == NULL) 327 | nonoption_flags_len = nonoption_flags_max_len = 0; 328 | else 329 | { 330 | memset (__mempcpy (new_str, __getopt_nonoption_flags, 331 | nonoption_flags_max_len), 332 | '\0', top + 1 - nonoption_flags_max_len); 333 | nonoption_flags_max_len = top + 1; 334 | __getopt_nonoption_flags = new_str; 335 | } 336 | } 337 | #endif 338 | 339 | while (top > middle && middle > bottom) 340 | { 341 | if (top - middle > middle - bottom) 342 | { 343 | /* Bottom segment is the short one. */ 344 | int len = middle - bottom; 345 | register int i; 346 | 347 | /* Swap it with the top part of the top segment. */ 348 | for (i = 0; i < len; i++) 349 | { 350 | tem = argv[bottom + i]; 351 | argv[bottom + i] = argv[top - (middle - bottom) + i]; 352 | argv[top - (middle - bottom) + i] = tem; 353 | SWAP_FLAGS (bottom + i, top - (middle - bottom) + i); 354 | } 355 | /* Exclude the moved bottom segment from further swapping. */ 356 | top -= len; 357 | } 358 | else 359 | { 360 | /* Top segment is the short one. */ 361 | int len = top - middle; 362 | register int i; 363 | 364 | /* Swap it with the bottom part of the bottom segment. */ 365 | for (i = 0; i < len; i++) 366 | { 367 | tem = argv[bottom + i]; 368 | argv[bottom + i] = argv[middle + i]; 369 | argv[middle + i] = tem; 370 | SWAP_FLAGS (bottom + i, middle + i); 371 | } 372 | /* Exclude the moved top segment from further swapping. */ 373 | bottom += len; 374 | } 375 | } 376 | 377 | /* Update records for the slots the non-options now occupy. */ 378 | 379 | first_nonopt += (optind - last_nonopt); 380 | last_nonopt = optind; 381 | } 382 | 383 | /* Initialize the internal data when the first call is made. */ 384 | 385 | #if defined __STDC__ && __STDC__ 386 | static const char *_getopt_initialize (int, char *const *, const char *); 387 | #endif 388 | static const char * 389 | _getopt_initialize (argc, argv, optstring) 390 | int argc; 391 | char *const *argv; 392 | const char *optstring; 393 | { 394 | /* Start processing options with ARGV-element 1 (since ARGV-element 0 395 | is the program name); the sequence of previously skipped 396 | non-option ARGV-elements is empty. */ 397 | 398 | first_nonopt = last_nonopt = optind; 399 | 400 | nextchar = NULL; 401 | 402 | posixly_correct = getenv ("POSIXLY_CORRECT"); 403 | 404 | /* Determine how to handle the ordering of options and nonoptions. */ 405 | 406 | if (optstring[0] == '-') 407 | { 408 | ordering = RETURN_IN_ORDER; 409 | ++optstring; 410 | } 411 | else if (optstring[0] == '+') 412 | { 413 | ordering = REQUIRE_ORDER; 414 | ++optstring; 415 | } 416 | else if (posixly_correct != NULL) 417 | ordering = REQUIRE_ORDER; 418 | else 419 | ordering = PERMUTE; 420 | 421 | #if defined _LIBC && defined USE_NONOPTION_FLAGS 422 | if (posixly_correct == NULL 423 | && argc == __libc_argc && argv == __libc_argv) 424 | { 425 | if (nonoption_flags_max_len == 0) 426 | { 427 | if (__getopt_nonoption_flags == NULL 428 | || __getopt_nonoption_flags[0] == '\0') 429 | nonoption_flags_max_len = -1; 430 | else 431 | { 432 | const char *orig_str = __getopt_nonoption_flags; 433 | int len = nonoption_flags_max_len = strlen (orig_str); 434 | if (nonoption_flags_max_len < argc) 435 | nonoption_flags_max_len = argc; 436 | __getopt_nonoption_flags = 437 | (char *) malloc (nonoption_flags_max_len); 438 | if (__getopt_nonoption_flags == NULL) 439 | nonoption_flags_max_len = -1; 440 | else 441 | memset (__mempcpy (__getopt_nonoption_flags, orig_str, len), 442 | '\0', nonoption_flags_max_len - len); 443 | } 444 | } 445 | nonoption_flags_len = nonoption_flags_max_len; 446 | } 447 | else 448 | nonoption_flags_len = 0; 449 | #endif 450 | 451 | return optstring; 452 | } 453 | 454 | /* Scan elements of ARGV (whose length is ARGC) for option characters 455 | given in OPTSTRING. 456 | 457 | If an element of ARGV starts with '-', and is not exactly "-" or "--", 458 | then it is an option element. The characters of this element 459 | (aside from the initial '-') are option characters. If `getopt' 460 | is called repeatedly, it returns successively each of the option characters 461 | from each of the option elements. 462 | 463 | If `getopt' finds another option character, it returns that character, 464 | updating `optind' and `nextchar' so that the next call to `getopt' can 465 | resume the scan with the following option character or ARGV-element. 466 | 467 | If there are no more option characters, `getopt' returns -1. 468 | Then `optind' is the index in ARGV of the first ARGV-element 469 | that is not an option. (The ARGV-elements have been permuted 470 | so that those that are not options now come last.) 471 | 472 | OPTSTRING is a string containing the legitimate option characters. 473 | If an option character is seen that is not listed in OPTSTRING, 474 | return '?' after printing an error message. If you set `opterr' to 475 | zero, the error message is suppressed but we still return '?'. 476 | 477 | If a char in OPTSTRING is followed by a colon, that means it wants an arg, 478 | so the following text in the same ARGV-element, or the text of the following 479 | ARGV-element, is returned in `optarg'. Two colons mean an option that 480 | wants an optional arg; if there is text in the current ARGV-element, 481 | it is returned in `optarg', otherwise `optarg' is set to zero. 482 | 483 | If OPTSTRING starts with `-' or `+', it requests different methods of 484 | handling the non-option ARGV-elements. 485 | See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above. 486 | 487 | Long-named options begin with `--' instead of `-'. 488 | Their names may be abbreviated as long as the abbreviation is unique 489 | or is an exact match for some defined option. If they have an 490 | argument, it follows the option name in the same ARGV-element, separated 491 | from the option name by a `=', or else the in next ARGV-element. 492 | When `getopt' finds a long-named option, it returns 0 if that option's 493 | `flag' field is nonzero, the value of the option's `val' field 494 | if the `flag' field is zero. 495 | 496 | The elements of ARGV aren't really const, because we permute them. 497 | But we pretend they're const in the prototype to be compatible 498 | with other systems. 499 | 500 | LONGOPTS is a vector of `struct option' terminated by an 501 | element containing a name which is zero. 502 | 503 | LONGIND returns the index in LONGOPT of the long-named option found. 504 | It is only valid when a long-named option has been found by the most 505 | recent call. 506 | 507 | If LONG_ONLY is nonzero, '-' as well as '--' can introduce 508 | long-named options. */ 509 | 510 | int 511 | _getopt_internal (argc, argv, optstring, longopts, longind, long_only) 512 | int argc; 513 | char *const *argv; 514 | const char *optstring; 515 | const struct option *longopts; 516 | int *longind; 517 | int long_only; 518 | { 519 | int print_errors = opterr; 520 | if (optstring[0] == ':') 521 | print_errors = 0; 522 | 523 | if (argc < 1) 524 | return -1; 525 | 526 | optarg = NULL; 527 | 528 | if (optind == 0 || !__getopt_initialized) 529 | { 530 | if (optind == 0) 531 | optind = 1; /* Don't scan ARGV[0], the program name. */ 532 | optstring = _getopt_initialize (argc, argv, optstring); 533 | __getopt_initialized = 1; 534 | } 535 | 536 | /* Test whether ARGV[optind] points to a non-option argument. 537 | Either it does not have option syntax, or there is an environment flag 538 | from the shell indicating it is not an option. The later information 539 | is only used when the used in the GNU libc. */ 540 | #if defined _LIBC && defined USE_NONOPTION_FLAGS 541 | # define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0' \ 542 | || (optind < nonoption_flags_len \ 543 | && __getopt_nonoption_flags[optind] == '1')) 544 | #else 545 | # define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0') 546 | #endif 547 | 548 | if (nextchar == NULL || *nextchar == '\0') 549 | { 550 | /* Advance to the next ARGV-element. */ 551 | 552 | /* Give FIRST_NONOPT and LAST_NONOPT rational values if OPTIND has been 553 | moved back by the user (who may also have changed the arguments). */ 554 | if (last_nonopt > optind) 555 | last_nonopt = optind; 556 | if (first_nonopt > optind) 557 | first_nonopt = optind; 558 | 559 | if (ordering == PERMUTE) 560 | { 561 | /* If we have just processed some options following some non-options, 562 | exchange them so that the options come first. */ 563 | 564 | if (first_nonopt != last_nonopt && last_nonopt != optind) 565 | exchange ((char **) argv); 566 | else if (last_nonopt != optind) 567 | first_nonopt = optind; 568 | 569 | /* Skip any additional non-options 570 | and extend the range of non-options previously skipped. */ 571 | 572 | while (optind < argc && NONOPTION_P) 573 | optind++; 574 | last_nonopt = optind; 575 | } 576 | 577 | /* The special ARGV-element `--' means premature end of options. 578 | Skip it like a null option, 579 | then exchange with previous non-options as if it were an option, 580 | then skip everything else like a non-option. */ 581 | 582 | if (optind != argc && !strcmp (argv[optind], "--")) 583 | { 584 | optind++; 585 | 586 | if (first_nonopt != last_nonopt && last_nonopt != optind) 587 | exchange ((char **) argv); 588 | else if (first_nonopt == last_nonopt) 589 | first_nonopt = optind; 590 | last_nonopt = argc; 591 | 592 | optind = argc; 593 | } 594 | 595 | /* If we have done all the ARGV-elements, stop the scan 596 | and back over any non-options that we skipped and permuted. */ 597 | 598 | if (optind == argc) 599 | { 600 | /* Set the next-arg-index to point at the non-options 601 | that we previously skipped, so the caller will digest them. */ 602 | if (first_nonopt != last_nonopt) 603 | optind = first_nonopt; 604 | return -1; 605 | } 606 | 607 | /* If we have come to a non-option and did not permute it, 608 | either stop the scan or describe it to the caller and pass it by. */ 609 | 610 | if (NONOPTION_P) 611 | { 612 | if (ordering == REQUIRE_ORDER) 613 | return -1; 614 | optarg = argv[optind++]; 615 | return 1; 616 | } 617 | 618 | /* We have found another option-ARGV-element. 619 | Skip the initial punctuation. */ 620 | 621 | nextchar = (argv[optind] + 1 622 | + (longopts != NULL && argv[optind][1] == '-')); 623 | } 624 | 625 | /* Decode the current option-ARGV-element. */ 626 | 627 | /* Check whether the ARGV-element is a long option. 628 | 629 | If long_only and the ARGV-element has the form "-f", where f is 630 | a valid short option, don't consider it an abbreviated form of 631 | a long option that starts with f. Otherwise there would be no 632 | way to give the -f short option. 633 | 634 | On the other hand, if there's a long option "fubar" and 635 | the ARGV-element is "-fu", do consider that an abbreviation of 636 | the long option, just like "--fu", and not "-f" with arg "u". 637 | 638 | This distinction seems to be the most useful approach. */ 639 | 640 | if (longopts != NULL 641 | && (argv[optind][1] == '-' 642 | || (long_only && (argv[optind][2] || !my_index (optstring, argv[optind][1]))))) 643 | { 644 | char *nameend; 645 | const struct option *p; 646 | const struct option *pfound = NULL; 647 | int exact = 0; 648 | int ambig = 0; 649 | int indfound = -1; 650 | int option_index; 651 | 652 | for (nameend = nextchar; *nameend && *nameend != '='; nameend++) 653 | /* Do nothing. */ ; 654 | 655 | /* Test all long options for either exact match 656 | or abbreviated matches. */ 657 | for (p = longopts, option_index = 0; p->name; p++, option_index++) 658 | if (!strncmp (p->name, nextchar, nameend - nextchar)) 659 | { 660 | if ((unsigned int) (nameend - nextchar) 661 | == (unsigned int) strlen (p->name)) 662 | { 663 | /* Exact match found. */ 664 | pfound = p; 665 | indfound = option_index; 666 | exact = 1; 667 | break; 668 | } 669 | else if (pfound == NULL) 670 | { 671 | /* First nonexact match found. */ 672 | pfound = p; 673 | indfound = option_index; 674 | } 675 | else if (long_only 676 | || pfound->has_arg != p->has_arg 677 | || pfound->flag != p->flag 678 | || pfound->val != p->val) 679 | /* Second or later nonexact match found. */ 680 | ambig = 1; 681 | } 682 | 683 | if (ambig && !exact) 684 | { 685 | if (print_errors) 686 | { 687 | #if defined _LIBC && defined USE_IN_LIBIO 688 | char *buf; 689 | 690 | __asprintf (&buf, _("%s: option `%s' is ambiguous\n"), 691 | argv[0], argv[optind]); 692 | 693 | if (_IO_fwide (stderr, 0) > 0) 694 | __fwprintf (stderr, L"%s", buf); 695 | else 696 | fputs (buf, stderr); 697 | 698 | free (buf); 699 | #else 700 | fprintf (stderr, _("%s: option `%s' is ambiguous\n"), 701 | argv[0], argv[optind]); 702 | #endif 703 | } 704 | nextchar += strlen (nextchar); 705 | optind++; 706 | optopt = 0; 707 | return '?'; 708 | } 709 | 710 | if (pfound != NULL) 711 | { 712 | option_index = indfound; 713 | optind++; 714 | if (*nameend) 715 | { 716 | /* Don't test has_arg with >, because some C compilers don't 717 | allow it to be used on enums. */ 718 | if (pfound->has_arg) 719 | optarg = nameend + 1; 720 | else 721 | { 722 | if (print_errors) 723 | { 724 | #if defined _LIBC && defined USE_IN_LIBIO 725 | char *buf; 726 | #endif 727 | 728 | if (argv[optind - 1][1] == '-') 729 | { 730 | /* --option */ 731 | #if defined _LIBC && defined USE_IN_LIBIO 732 | __asprintf (&buf, _("\ 733 | %s: option `--%s' doesn't allow an argument\n"), 734 | argv[0], pfound->name); 735 | #else 736 | fprintf (stderr, _("\ 737 | %s: option `--%s' doesn't allow an argument\n"), 738 | argv[0], pfound->name); 739 | #endif 740 | } 741 | else 742 | { 743 | /* +option or -option */ 744 | #if defined _LIBC && defined USE_IN_LIBIO 745 | __asprintf (&buf, _("\ 746 | %s: option `%c%s' doesn't allow an argument\n"), 747 | argv[0], argv[optind - 1][0], 748 | pfound->name); 749 | #else 750 | fprintf (stderr, _("\ 751 | %s: option `%c%s' doesn't allow an argument\n"), 752 | argv[0], argv[optind - 1][0], pfound->name); 753 | #endif 754 | } 755 | 756 | #if defined _LIBC && defined USE_IN_LIBIO 757 | if (_IO_fwide (stderr, 0) > 0) 758 | __fwprintf (stderr, L"%s", buf); 759 | else 760 | fputs (buf, stderr); 761 | 762 | free (buf); 763 | #endif 764 | } 765 | 766 | nextchar += strlen (nextchar); 767 | 768 | optopt = pfound->val; 769 | return '?'; 770 | } 771 | } 772 | else if (pfound->has_arg == 1) 773 | { 774 | if (optind < argc) 775 | optarg = argv[optind++]; 776 | else 777 | { 778 | if (print_errors) 779 | { 780 | #if defined _LIBC && defined USE_IN_LIBIO 781 | char *buf; 782 | 783 | __asprintf (&buf, 784 | _("%s: option `%s' requires an argument\n"), 785 | argv[0], argv[optind - 1]); 786 | 787 | if (_IO_fwide (stderr, 0) > 0) 788 | __fwprintf (stderr, L"%s", buf); 789 | else 790 | fputs (buf, stderr); 791 | 792 | free (buf); 793 | #else 794 | fprintf (stderr, 795 | _("%s: option `%s' requires an argument\n"), 796 | argv[0], argv[optind - 1]); 797 | #endif 798 | } 799 | nextchar += strlen (nextchar); 800 | optopt = pfound->val; 801 | return optstring[0] == ':' ? ':' : '?'; 802 | } 803 | } 804 | nextchar += strlen (nextchar); 805 | if (longind != NULL) 806 | *longind = option_index; 807 | if (pfound->flag) 808 | { 809 | *(pfound->flag) = pfound->val; 810 | return 0; 811 | } 812 | return pfound->val; 813 | } 814 | 815 | /* Can't find it as a long option. If this is not getopt_long_only, 816 | or the option starts with '--' or is not a valid short 817 | option, then it's an error. 818 | Otherwise interpret it as a short option. */ 819 | if (!long_only || argv[optind][1] == '-' 820 | || my_index (optstring, *nextchar) == NULL) 821 | { 822 | if (print_errors) 823 | { 824 | #if defined _LIBC && defined USE_IN_LIBIO 825 | char *buf; 826 | #endif 827 | 828 | if (argv[optind][1] == '-') 829 | { 830 | /* --option */ 831 | #if defined _LIBC && defined USE_IN_LIBIO 832 | __asprintf (&buf, _("%s: unrecognized option `--%s'\n"), 833 | argv[0], nextchar); 834 | #else 835 | fprintf (stderr, _("%s: unrecognized option `--%s'\n"), 836 | argv[0], nextchar); 837 | #endif 838 | } 839 | else 840 | { 841 | /* +option or -option */ 842 | #if defined _LIBC && defined USE_IN_LIBIO 843 | __asprintf (&buf, _("%s: unrecognized option `%c%s'\n"), 844 | argv[0], argv[optind][0], nextchar); 845 | #else 846 | fprintf (stderr, _("%s: unrecognized option `%c%s'\n"), 847 | argv[0], argv[optind][0], nextchar); 848 | #endif 849 | } 850 | 851 | #if defined _LIBC && defined USE_IN_LIBIO 852 | if (_IO_fwide (stderr, 0) > 0) 853 | __fwprintf (stderr, L"%s", buf); 854 | else 855 | fputs (buf, stderr); 856 | 857 | free (buf); 858 | #endif 859 | } 860 | nextchar = (char *) ""; 861 | optind++; 862 | optopt = 0; 863 | return '?'; 864 | } 865 | } 866 | 867 | /* Look at and handle the next short option-character. */ 868 | 869 | { 870 | char c = *nextchar++; 871 | char *temp = my_index (optstring, c); 872 | 873 | /* Increment `optind' when we start to process its last character. */ 874 | if (*nextchar == '\0') 875 | ++optind; 876 | 877 | if (temp == NULL || c == ':') 878 | { 879 | if (print_errors) 880 | { 881 | #if defined _LIBC && defined USE_IN_LIBIO 882 | char *buf; 883 | #endif 884 | 885 | if (posixly_correct) 886 | { 887 | /* 1003.2 specifies the format of this message. */ 888 | #if defined _LIBC && defined USE_IN_LIBIO 889 | __asprintf (&buf, _("%s: illegal option -- %c\n"), 890 | argv[0], c); 891 | #else 892 | fprintf (stderr, _("%s: illegal option -- %c\n"), argv[0], c); 893 | #endif 894 | } 895 | else 896 | { 897 | #if defined _LIBC && defined USE_IN_LIBIO 898 | __asprintf (&buf, _("%s: invalid option -- %c\n"), 899 | argv[0], c); 900 | #else 901 | fprintf (stderr, _("%s: invalid option -- %c\n"), argv[0], c); 902 | #endif 903 | } 904 | 905 | #if defined _LIBC && defined USE_IN_LIBIO 906 | if (_IO_fwide (stderr, 0) > 0) 907 | __fwprintf (stderr, L"%s", buf); 908 | else 909 | fputs (buf, stderr); 910 | 911 | free (buf); 912 | #endif 913 | } 914 | optopt = c; 915 | return '?'; 916 | } 917 | /* Convenience. Treat POSIX -W foo same as long option --foo */ 918 | if (temp[0] == 'W' && temp[1] == ';') 919 | { 920 | char *nameend; 921 | const struct option *p; 922 | const struct option *pfound = NULL; 923 | int exact = 0; 924 | int ambig = 0; 925 | int indfound = 0; 926 | int option_index; 927 | 928 | /* This is an option that requires an argument. */ 929 | if (*nextchar != '\0') 930 | { 931 | optarg = nextchar; 932 | /* If we end this ARGV-element by taking the rest as an arg, 933 | we must advance to the next element now. */ 934 | optind++; 935 | } 936 | else if (optind == argc) 937 | { 938 | if (print_errors) 939 | { 940 | /* 1003.2 specifies the format of this message. */ 941 | #if defined _LIBC && defined USE_IN_LIBIO 942 | char *buf; 943 | 944 | __asprintf (&buf, _("%s: option requires an argument -- %c\n"), 945 | argv[0], c); 946 | 947 | if (_IO_fwide (stderr, 0) > 0) 948 | __fwprintf (stderr, L"%s", buf); 949 | else 950 | fputs (buf, stderr); 951 | 952 | free (buf); 953 | #else 954 | fprintf (stderr, _("%s: option requires an argument -- %c\n"), 955 | argv[0], c); 956 | #endif 957 | } 958 | optopt = c; 959 | if (optstring[0] == ':') 960 | c = ':'; 961 | else 962 | c = '?'; 963 | return c; 964 | } 965 | else 966 | /* We already incremented `optind' once; 967 | increment it again when taking next ARGV-elt as argument. */ 968 | optarg = argv[optind++]; 969 | 970 | /* optarg is now the argument, see if it's in the 971 | table of longopts. */ 972 | 973 | for (nextchar = nameend = optarg; *nameend && *nameend != '='; nameend++) 974 | /* Do nothing. */ ; 975 | 976 | /* Test all long options for either exact match 977 | or abbreviated matches. */ 978 | for (p = longopts, option_index = 0; p->name; p++, option_index++) 979 | if (!strncmp (p->name, nextchar, nameend - nextchar)) 980 | { 981 | if ((unsigned int) (nameend - nextchar) == strlen (p->name)) 982 | { 983 | /* Exact match found. */ 984 | pfound = p; 985 | indfound = option_index; 986 | exact = 1; 987 | break; 988 | } 989 | else if (pfound == NULL) 990 | { 991 | /* First nonexact match found. */ 992 | pfound = p; 993 | indfound = option_index; 994 | } 995 | else 996 | /* Second or later nonexact match found. */ 997 | ambig = 1; 998 | } 999 | if (ambig && !exact) 1000 | { 1001 | if (print_errors) 1002 | { 1003 | #if defined _LIBC && defined USE_IN_LIBIO 1004 | char *buf; 1005 | 1006 | __asprintf (&buf, _("%s: option `-W %s' is ambiguous\n"), 1007 | argv[0], argv[optind]); 1008 | 1009 | if (_IO_fwide (stderr, 0) > 0) 1010 | __fwprintf (stderr, L"%s", buf); 1011 | else 1012 | fputs (buf, stderr); 1013 | 1014 | free (buf); 1015 | #else 1016 | fprintf (stderr, _("%s: option `-W %s' is ambiguous\n"), 1017 | argv[0], argv[optind]); 1018 | #endif 1019 | } 1020 | nextchar += strlen (nextchar); 1021 | optind++; 1022 | return '?'; 1023 | } 1024 | if (pfound != NULL) 1025 | { 1026 | option_index = indfound; 1027 | if (*nameend) 1028 | { 1029 | /* Don't test has_arg with >, because some C compilers don't 1030 | allow it to be used on enums. */ 1031 | if (pfound->has_arg) 1032 | optarg = nameend + 1; 1033 | else 1034 | { 1035 | if (print_errors) 1036 | { 1037 | #if defined _LIBC && defined USE_IN_LIBIO 1038 | char *buf; 1039 | 1040 | __asprintf (&buf, _("\ 1041 | %s: option `-W %s' doesn't allow an argument\n"), 1042 | argv[0], pfound->name); 1043 | 1044 | if (_IO_fwide (stderr, 0) > 0) 1045 | __fwprintf (stderr, L"%s", buf); 1046 | else 1047 | fputs (buf, stderr); 1048 | 1049 | free (buf); 1050 | #else 1051 | fprintf (stderr, _("\ 1052 | %s: option `-W %s' doesn't allow an argument\n"), 1053 | argv[0], pfound->name); 1054 | #endif 1055 | } 1056 | 1057 | nextchar += strlen (nextchar); 1058 | return '?'; 1059 | } 1060 | } 1061 | else if (pfound->has_arg == 1) 1062 | { 1063 | if (optind < argc) 1064 | optarg = argv[optind++]; 1065 | else 1066 | { 1067 | if (print_errors) 1068 | { 1069 | #if defined _LIBC && defined USE_IN_LIBIO 1070 | char *buf; 1071 | 1072 | __asprintf (&buf, _("\ 1073 | %s: option `%s' requires an argument\n"), 1074 | argv[0], argv[optind - 1]); 1075 | 1076 | if (_IO_fwide (stderr, 0) > 0) 1077 | __fwprintf (stderr, L"%s", buf); 1078 | else 1079 | fputs (buf, stderr); 1080 | 1081 | free (buf); 1082 | #else 1083 | fprintf (stderr, 1084 | _("%s: option `%s' requires an argument\n"), 1085 | argv[0], argv[optind - 1]); 1086 | #endif 1087 | } 1088 | nextchar += strlen (nextchar); 1089 | return optstring[0] == ':' ? ':' : '?'; 1090 | } 1091 | } 1092 | nextchar += strlen (nextchar); 1093 | if (longind != NULL) 1094 | *longind = option_index; 1095 | if (pfound->flag) 1096 | { 1097 | *(pfound->flag) = pfound->val; 1098 | return 0; 1099 | } 1100 | return pfound->val; 1101 | } 1102 | nextchar = NULL; 1103 | return 'W'; /* Let the application handle it. */ 1104 | } 1105 | if (temp[1] == ':') 1106 | { 1107 | if (temp[2] == ':') 1108 | { 1109 | /* This is an option that accepts an argument optionally. */ 1110 | if (*nextchar != '\0') 1111 | { 1112 | optarg = nextchar; 1113 | optind++; 1114 | } 1115 | else 1116 | optarg = NULL; 1117 | nextchar = NULL; 1118 | } 1119 | else 1120 | { 1121 | /* This is an option that requires an argument. */ 1122 | if (*nextchar != '\0') 1123 | { 1124 | optarg = nextchar; 1125 | /* If we end this ARGV-element by taking the rest as an arg, 1126 | we must advance to the next element now. */ 1127 | optind++; 1128 | } 1129 | else if (optind == argc) 1130 | { 1131 | if (print_errors) 1132 | { 1133 | /* 1003.2 specifies the format of this message. */ 1134 | #if defined _LIBC && defined USE_IN_LIBIO 1135 | char *buf; 1136 | 1137 | __asprintf (&buf, 1138 | _("%s: option requires an argument -- %c\n"), 1139 | argv[0], c); 1140 | 1141 | if (_IO_fwide (stderr, 0) > 0) 1142 | __fwprintf (stderr, L"%s", buf); 1143 | else 1144 | fputs (buf, stderr); 1145 | 1146 | free (buf); 1147 | #else 1148 | fprintf (stderr, 1149 | _("%s: option requires an argument -- %c\n"), 1150 | argv[0], c); 1151 | #endif 1152 | } 1153 | optopt = c; 1154 | if (optstring[0] == ':') 1155 | c = ':'; 1156 | else 1157 | c = '?'; 1158 | } 1159 | else 1160 | /* We already incremented `optind' once; 1161 | increment it again when taking next ARGV-elt as argument. */ 1162 | optarg = argv[optind++]; 1163 | nextchar = NULL; 1164 | } 1165 | } 1166 | return c; 1167 | } 1168 | } 1169 | 1170 | int 1171 | getopt (argc, argv, optstring) 1172 | int argc; 1173 | char *const *argv; 1174 | const char *optstring; 1175 | { 1176 | return _getopt_internal (argc, argv, optstring, 1177 | (const struct option *) 0, 1178 | (int *) 0, 1179 | 0); 1180 | } 1181 | 1182 | #endif /* Not ELIDE_CODE. */ 1183 | 1184 | 1185 | /* Compile with -DTEST to make an executable for use in testing 1186 | the above definition of `getopt'. */ 1187 | 1188 | /* #define TEST */ /* Pete Wilson mod 7/28/02 */ 1189 | #ifdef TEST 1190 | 1191 | #ifndef exit /* Pete Wilson mod 7/28/02 */ 1192 | int exit(int); /* Pete Wilson mod 7/28/02 */ 1193 | #endif /* Pete Wilson mod 7/28/02 */ 1194 | 1195 | int 1196 | main (argc, argv) 1197 | int argc; 1198 | char **argv; 1199 | { 1200 | int c; 1201 | int digit_optind = 0; 1202 | 1203 | while (1) 1204 | { 1205 | int this_option_optind = optind ? optind : 1; 1206 | 1207 | c = getopt (argc, argv, "abc:d:0123456789"); 1208 | if (c == -1) 1209 | break; 1210 | 1211 | switch (c) 1212 | { 1213 | case '0': 1214 | case '1': 1215 | case '2': 1216 | case '3': 1217 | case '4': 1218 | case '5': 1219 | case '6': 1220 | case '7': 1221 | case '8': 1222 | case '9': 1223 | if (digit_optind != 0 && digit_optind != this_option_optind) 1224 | printf ("digits occur in two different argv-elements.\n"); 1225 | digit_optind = this_option_optind; 1226 | printf ("option %c\n", c); 1227 | break; 1228 | 1229 | case 'a': 1230 | printf ("option a\n"); 1231 | break; 1232 | 1233 | case 'b': 1234 | printf ("option b\n"); 1235 | break; 1236 | 1237 | case 'c': 1238 | printf ("option c with value `%s'\n", optarg); 1239 | break; 1240 | 1241 | case '?': 1242 | break; 1243 | 1244 | default: 1245 | printf ("?? getopt returned character code 0%o ??\n", c); 1246 | } 1247 | } 1248 | 1249 | if (optind < argc) 1250 | { 1251 | printf ("non-option ARGV-elements: "); 1252 | while (optind < argc) 1253 | printf ("%s ", argv[optind++]); 1254 | printf ("\n"); 1255 | } 1256 | 1257 | exit (0); 1258 | } 1259 | 1260 | #endif /* TEST */ 1261 | -------------------------------------------------------------------------------- /busMaster/getopt.h: -------------------------------------------------------------------------------- 1 | /* from http://www.pwilson.net/getopt.html */ 2 | 3 | /* getopt.h */ 4 | /* Declarations for getopt. 5 | Copyright (C) 1989-1994, 1996-1999, 2001 Free Software 6 | Foundation, Inc. This file is part of the GNU C Library. 7 | 8 | The GNU C Library is free software; you can redistribute 9 | it and/or modify it under the terms of the GNU Lesser 10 | General Public License as published by the Free Software 11 | Foundation; either version 2.1 of the License, or 12 | (at your option) any later version. 13 | 14 | The GNU C Library is distributed in the hope that it will 15 | be useful, but WITHOUT ANY WARRANTY; without even the 16 | implied warranty of MERCHANTABILITY or FITNESS FOR A 17 | PARTICULAR PURPOSE. See the GNU Lesser General Public 18 | License for more details. 19 | 20 | You should have received a copy of the GNU Lesser General 21 | Public License along with the GNU C Library; if not, write 22 | to the Free Software Foundation, Inc., 59 Temple Place, 23 | Suite 330, Boston, MA 02111-1307 USA. */ 24 | 25 | 26 | 27 | 28 | 29 | #ifndef _GETOPT_H 30 | 31 | #ifndef __need_getopt 32 | # define _GETOPT_H 1 33 | #endif 34 | 35 | /* If __GNU_LIBRARY__ is not already defined, either we are being used 36 | standalone, or this is the first header included in the source file. 37 | If we are being used with glibc, we need to include , but 38 | that does not exist if we are standalone. So: if __GNU_LIBRARY__ is 39 | not defined, include , which will pull in for us 40 | if it's from glibc. (Why ctype.h? It's guaranteed to exist and it 41 | doesn't flood the namespace with stuff the way some other headers do.) */ 42 | #if !defined __GNU_LIBRARY__ 43 | # include 44 | #endif 45 | 46 | #ifdef __cplusplus 47 | extern "C" { 48 | #endif 49 | 50 | /* For communication from `getopt' to the caller. 51 | When `getopt' finds an option that takes an argument, 52 | the argument value is returned here. 53 | Also, when `ordering' is RETURN_IN_ORDER, 54 | each non-option ARGV-element is returned here. */ 55 | 56 | extern char *optarg; 57 | 58 | /* Index in ARGV of the next element to be scanned. 59 | This is used for communication to and from the caller 60 | and for communication between successive calls to `getopt'. 61 | 62 | On entry to `getopt', zero means this is the first call; initialize. 63 | 64 | When `getopt' returns -1, this is the index of the first of the 65 | non-option elements that the caller should itself scan. 66 | 67 | Otherwise, `optind' communicates from one call to the next 68 | how much of ARGV has been scanned so far. */ 69 | 70 | extern int optind; 71 | 72 | /* Callers store zero here to inhibit the error message `getopt' prints 73 | for unrecognized options. */ 74 | 75 | extern int opterr; 76 | 77 | /* Set to an option character which was unrecognized. */ 78 | 79 | extern int optopt; 80 | 81 | #ifndef __need_getopt 82 | /* Describe the long-named options requested by the application. 83 | The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector 84 | of `struct option' terminated by an element containing a name which is 85 | zero. 86 | 87 | The field `has_arg' is: 88 | no_argument (or 0) if the option does not take an argument, 89 | required_argument (or 1) if the option requires an argument, 90 | optional_argument (or 2) if the option takes an optional argument. 91 | 92 | If the field `flag' is not NULL, it points to a variable that is set 93 | to the value given in the field `val' when the option is found, but 94 | left unchanged if the option is not found. 95 | 96 | To have a long-named option do something other than set an `int' to 97 | a compiled-in constant, such as set a value from `optarg', set the 98 | option's `flag' field to zero and its `val' field to a nonzero 99 | value (the equivalent single-letter option character, if there is 100 | one). For long options that have a zero `flag' field, `getopt' 101 | returns the contents of the `val' field. */ 102 | 103 | struct option 104 | { 105 | # if (defined __STDC__ && __STDC__) || defined __cplusplus 106 | const char *name; 107 | # else 108 | char *name; 109 | # endif 110 | /* has_arg can't be an enum because some compilers complain about 111 | type mismatches in all the code that assumes it is an int. */ 112 | int has_arg; 113 | int *flag; 114 | int val; 115 | }; 116 | 117 | /* Names for the values of the `has_arg' field of `struct option'. */ 118 | 119 | # define no_argument 0 120 | # define required_argument 1 121 | # define optional_argument 2 122 | #endif /* need getopt */ 123 | 124 | 125 | /* Get definitions and prototypes for functions to process the 126 | arguments in ARGV (ARGC of them, minus the program name) for 127 | options given in OPTS. 128 | 129 | Return the option character from OPTS just read. Return -1 when 130 | there are no more options. For unrecognized options, or options 131 | missing arguments, `optopt' is set to the option letter, and '?' is 132 | returned. 133 | 134 | The OPTS string is a list of characters which are recognized option 135 | letters, optionally followed by colons, specifying that that letter 136 | takes an argument, to be placed in `optarg'. 137 | 138 | If a letter in OPTS is followed by two colons, its argument is 139 | optional. This behavior is specific to the GNU `getopt'. 140 | 141 | The argument `--' causes premature termination of argument 142 | scanning, explicitly telling `getopt' that there are no more 143 | options. 144 | 145 | If OPTS begins with `--', then non-option arguments are treated as 146 | arguments to the option '\0'. This behavior is specific to the GNU 147 | `getopt'. */ 148 | 149 | #if (defined __STDC__ && __STDC__) || defined __cplusplus 150 | # ifdef __GNU_LIBRARY__ 151 | /* Many other libraries have conflicting prototypes for getopt, with 152 | differences in the consts, in stdlib.h. To avoid compilation 153 | errors, only prototype getopt for the GNU C library. */ 154 | extern int getopt (int ___argc, char *const *___argv, const char *__shortopts); 155 | # else /* not __GNU_LIBRARY__ */ 156 | extern int getopt (); 157 | # endif /* __GNU_LIBRARY__ */ 158 | 159 | # ifndef __need_getopt 160 | extern int getopt_long (int ___argc, char *const *___argv, 161 | const char *__shortopts, 162 | const struct option *__longopts, int *__longind); 163 | extern int getopt_long_only (int ___argc, char *const *___argv, 164 | const char *__shortopts, 165 | const struct option *__longopts, int *__longind); 166 | 167 | /* Internal only. Users should not call this directly. */ 168 | extern int _getopt_internal (int ___argc, char *const *___argv, 169 | const char *__shortopts, 170 | const struct option *__longopts, int *__longind, 171 | int __long_only); 172 | # endif 173 | #else /* not __STDC__ */ 174 | extern int getopt (); 175 | # ifndef __need_getopt 176 | extern int getopt_long (); 177 | extern int getopt_long_only (); 178 | 179 | extern int _getopt_internal (); 180 | # endif 181 | #endif /* __STDC__ */ 182 | 183 | #ifdef __cplusplus 184 | } 185 | #endif 186 | 187 | /* Make sure we later can get all the definitions and declarations. */ 188 | #undef __need_getopt 189 | 190 | #endif /* getopt.h */ 191 | 192 | -------------------------------------------------------------------------------- /busMaster/run.sh: -------------------------------------------------------------------------------- 1 | 2 | 3 | # OPTIONS: * 4 | # * -l : Can library ["libcanfestival_can_virtual.so"] * 5 | # * * 6 | # * Slave: * 7 | # * -i : Slave Node id format [0x01 , 0x7F] * 8 | # * * 9 | # * Master: * 10 | # * -m : bus name ["1"] * 11 | # * -M : 1M,500K,250K,125K,100K,50K,20K,10K 12 | # 13 | ./DS401_Master -i0x66 -x config.xml -d -d 14 | #./DS401_Master -llibcanfestival_can_socket.so -m can0 -M500K -i0x66 15 | #./DS401_Master -llibcanfestival_can_socket.so -m can0 -M500K -i0x40 16 | #./DS401_Master -llibcanfestival_can_socket.so -m can0 -M500K -i0x20 17 | 18 | -------------------------------------------------------------------------------- /pics/CAN-Open-RasberryPi.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpcrowe/canopen-raspberrypi/a9674299364788d00b948c3c4874c5f4cca694c1/pics/CAN-Open-RasberryPi.png -------------------------------------------------------------------------------- /pics/blockDiagram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpcrowe/canopen-raspberrypi/a9674299364788d00b948c3c4874c5f4cca694c1/pics/blockDiagram.png -------------------------------------------------------------------------------- /pics/blockDiagram.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 20 | 22 | 23 | 25 | image/svg+xml 26 | 28 | 29 | 30 | 31 | 32 | 34 | 41 | 46 | 47 | 54 | 59 | 60 | 67 | 72 | 73 | 80 | 85 | 86 | 93 | 98 | 99 | 106 | 111 | 112 | 119 | 124 | 125 | 132 | 137 | 138 | 145 | 150 | 151 | 165 | 172 | 174 | 178 | 182 | 183 | 186 | 196 | 203 | 210 | 217 | 224 | 231 | 238 | 245 | 252 | 259 | 266 | 273 | 280 | 287 | 294 | 301 | 308 | 315 | 322 | 329 | 336 | 343 | 350 | 357 | 364 | 371 | 378 | 385 | 392 | 399 | 406 | 413 | 420 | 425 | 426 | 433 | 438 | 439 | 446 | 453 | 458 | 459 | 466 | 471 | 472 | 479 | 486 | 487 | 507 | 514 | 518 | 522 | 526 | 530 | 531 | 541 | 551 | 554 | 557 | 565 | CAN-Open Android App Block Diagram 570 | 571 | 574 | 583 | 591 | CAN-Open Demo Android App 596 | (Canopen-java package) 601 | 606 | 611 | 612 | 613 | 616 | 619 | 628 | 636 | Physical 641 | CANBus 646 | 647 | 650 | 659 | 667 | CAN-Open 672 | Slave Node 677 | 678 | 688 | 689 | 692 | 701 | 709 | CAN-Open 714 | Slave Node 719 | 720 | 730 | 731 | 734 | 743 | 751 | CAN-Open 756 | Slave Node 761 | 762 | 772 | 773 | 774 | 775 | 788 | 797 | MCP2515SPI-CANInterface 818 | 819 | 824 | 827 | 836 | 839 | 848 | 856 | Socat 861 | 862 | 863 | 871 | Rasberry Pi 3 876 | 881 | 886 | 887 | 890 | 893 | 902 | 903 | Built -in WiFiInterface 920 | 921 | 924 | 933 | SPI Interface 950 | 951 | 954 | 963 | 971 | CanFestival 976 | 977 | 978 | 981 | 990 | 998 | LibXML2 1003 | 1004 | 1005 | 1008 | 1017 | 1025 | busMaster 1030 | 1031 | 1032 | 1039 | 1044 | 1049 | 1053 | 1058 | 1062 | 1067 | 1068 | 1073 | SPI 1083 | 1088 | CAN Bus 1098 | 1103 | Wifi Connection 1114 | 1115 | 1116 | 1117 | -------------------------------------------------------------------------------- /pics/temp.xml: -------------------------------------------------------------------------------- 1 | hello 2 | -------------------------------------------------------------------------------- /runsocat.sh: -------------------------------------------------------------------------------- 1 | 2 | CAN_STATE=`ifconfig can0 2>&1 | grep UP` 3 | echo ${CAN_STATE} 4 | 5 | if [[ ${CAN_STATE} == *"UP"* ]]; then 6 | echo can bus is up 7 | else 8 | echo can0 not found, brining up ... 9 | sudo ip link set can0 up type can bitrate 500000 10 | fi 11 | 12 | #sudo socat -d -d -d -d INTERFACE:can0,pf=29,type=3,prototype=1 TCP-LISTEN:2000,fork,reuseaddr 13 | #sudo socat -d -d -d -d INTERFACE:can0,pf=29,type=3,prototype=1 UDP-LISTEN:2000,fork,reuseaddr 14 | sudo socat INTERFACE:can0,pf=29,type=3,prototype=1 UDP-LISTEN:2000,fork,reuseaddr 15 | #sudo socat INTERFACE:can0,pf=29,type=3,prototype=1 TCP-LISTEN:2000,fork,reuseaddr 16 | --------------------------------------------------------------------------------