Arduino: Change defines without edit library [solved, bug in compiler, workaround available]

牧云@^-^@ 提交于 2019-12-25 07:25:42

问题


edit: See my answer below


I'm fairly new to the Arduino platform and creating now an USB HID project with the attiny85 (Trinket) library of AdaFruit. See also my previous answered question about the options of this library: Change/Override Trinket (attiny85) USB identification name, device name

I'm stumped on a rare C-related limitation (see also latest comment at answer in link above to previous question), the separated late binding of binaries by separated compiling. If you want to change options of the USB device, you have to change the library itself, kinda weird to me because it's a library.

For example, if you include a header file with changed options before you loading the library, nothing is changed because it is unknown by the library because it must be included by this library either.

Example: This doesn't work:

#include "myUSBOptions.h"
#include "TrinketHidCombo.h"

Another approach:

So I need to change the library itself for each project, in this case the usbconfig.h file. That's sounds a kind of stupid to me because it's a library and can be used by other projects. Maybe this is a design error in the Adafruit library, such things like vendorname, devicename etc must be optional OUTSIDE this library and also your settings can be overwritten when there is an update of the library. And... you need to edit the file again for each separated project.

So I came up with the idea to include an optional header file in the usbconfig.h file, #include "user_usbconfig.h" that requires only one change. But that's not the only usbconfig.h file, at least three versions are available! Create one user_usbconfig.h file in the project directory, Wrote a batch file for to automate it and include it in the project directory so you can change the options by simply clicking on it when switching project.

Line added in usbconfig.h files:

.......

#include "cmdline_defs.h"

#ifndef __usbconfig_h_included__
#define __usbconfig_h_included__

#include "user_usbconfig.h" // <-- added this

.......

For example user_usbconfig.h included at the project

/* DEVICE SETTINGS */

/* Version number of the device: Minor number first, then major number. */
#define USB_CFG_DEVICE_VERSION  0x00, 0x01


/* VENDOR_NAME
 * These two values define the vendor name returned by the USB device. The name
 * must be given as a list of characters under single quotes. The characters
 * are interpreted as Unicode (UTF-16) entities.
 * If you don't want a vendor name string, undefine these macros.
 * ALWAYS define a vendor name containing your Internet domain name if you use
 * obdev's free shared VID/PID pair. See the file USB-IDs-for-free.txt for
 * details.
 */
#define USB_CFG_VENDOR_NAME     'm', 'y', 'C', 'o', 'm', 'p', 'a', 'n', 'y', 'n'
#define USB_CFG_VENDOR_NAME_LEN 10


/* DEVICE_NAME
 * Same as above for the device name. If you don't want a device name, undefine
 * the macros. See the file USB-IDs-for-free.txt before you assign a name if
 * you use a shared VID/PID.
 */
#define USB_CFG_DEVICE_NAME     'm', 'y', 'D', 'e', 'v', 'i', 'c', 'e'
#define USB_CFG_DEVICE_NAME_LEN 8


/* SERIAL_NUMBER
 * Same as above for the serial number. If you don't want a serial number,
 * undefine the macros.
 * It may be useful to provide the serial number through other means than at
 * compile time. See the section about descriptor properties below for how
 * to fine tune control over USB descriptors such as the string descriptor
 * for the serial number.
 */
/*#define USB_CFG_SERIAL_NUMBER   'N', 'o', 'n', 'e' */
/*#define USB_CFG_SERIAL_NUMBER_LEN   0 */

Example sourcecode myProject.ino, does nothing except activating USB:

#include "TrinketHidCombo.h"

void setup()
{
  TrinketHidCombo.begin(); 
}

void loop() // Main program - main()
{
  // do nothing, check if USB needs anything done
  TrinketHidCombo.poll();  
}

Batch file I create, added in the project directory:

@echo off
rem ********************************************************
rem * setTrinketUSBLibraryOptions.bat                      *
rem * ---------------------------------------------------- *
rem * Author       : Erwin Haantjes                        *
rem * Project      : Arduino Trinket USB                   * 
rem * Dev date     : 11-06-2016                            *
rem * Last changed : 11-06-2016                            *
rem * What it do   : 'Copy' (link) USB options project to  *
rem *                Trinket lib to make settings optional.* 
rem *                                                      *
rem ********************************************************


rem *** Config parts that can be modified if required
SET ARDUINO_LIB_DIR=F:\Program Files\Arduino\DigiSpark\Digispark-Arduino-1.0.4\libraries
SET USER_HEADER_FILE=user_usbconfig.h
SET ATU_HEADER_FILE=usbconfig.h
SET ATU_DIRNAME1=TrinketHidCombo
SET ATU_DIRNAME2=TrinketKeyboard
SET ATU_DIRNAME3=TrinketMouse

SET ATU_HEADER_FILE1=%ARDUINO_LIB_DIR%\%ATU_DIRNAME1%\%ATU_HEADER_FILE%
SET ATU_HEADER_FILE2=%ARDUINO_LIB_DIR%\%ATU_DIRNAME2%\%ATU_HEADER_FILE%
SET ATU_HEADER_FILE3=%ARDUINO_LIB_DIR%\%ATU_DIRNAME3%\%ATU_HEADER_FILE%
SET ATU_USER_HEADER_FILE1=%ARDUINO_LIB_DIR%\%ATU_DIRNAME1%\%USER_HEADER_FILE%
SET ATU_USER_HEADER_FILE2=%ARDUINO_LIB_DIR%\%ATU_DIRNAME2%\%USER_HEADER_FILE%
SET ATU_USER_HEADER_FILE3=%ARDUINO_LIB_DIR%\%ATU_DIRNAME3%\%USER_HEADER_FILE%

rem *** START
echo.
echo.
echo Set Thrinket USB Library options to match your project
echo ------------------------------------------------------
echo.
if "@%1"=="@/?" goto USAGE
if "@%1"=="@-?" goto USAGE
goto INTRO

:USAGE
SET USAGEMODE=true
echo Created by Erwin Haantjes 2016
echo.
echo USAGE:
echo %0 [/?,/C,-?,-C]
echo.
echo SWITCHES:
echo - ?   Shows this help
echo - C   Use copy command instead of symlink to hardcopy the "%USER_HEADER_FILE%" to it's targets
echo.

:INTRO
rem *** WARNING and NOTICE
echo WARNING:
echo - This batch changes/symlink options to be able to config the Trinket USB Library by project easily. Run this file once each time you work on a project to be sure you are using the right settings.
echo - If a physical %USER_HEADER_FILE% file exists in the library directory, it will be deleted!
echo.
echo NOTICE: 
echo - Each "%ATU_HEADER_FILE%" file in (parts/the) Trinket USB library must include the line: #include "%USER_HEADER_FILE%" at top of the file after #define __usbconfig_h_included__ .
echo - Once applying this 'patch', you can change USB settings in the "%USER_HEADER_FILE%" file in this directory on the fly without the need to run this batch again. Just compile it after a change and your changes will be 'visible'. 
echo.
echo.
echo Library directory is set to:
echo %ARDUINO_LIB_DIR%
echo.
echo. 
if "%USAGEMODE%"=="true" goto END
echo Do you want to continue? Press any key.
pause >NUL
echo.

rem *** Check destinations
if exist "%USER_HEADER_FILE%" goto NEXT1
goto ERROR_NO_USER_FILE
:NEXT1
if exist "%ATU_HEADER_FILE1%" goto NEXT2
goto ERROR_LIB_NOT_EXISTS
:NEXT2
if exist "%ATU_HEADER_FILE2%" goto NEXT3
goto ERROR_LIB_NOT_EXISTS
:NEXT3
if exist "%ATU_HEADER_FILE3%" goto NEXT4
goto ERROR_LIB_NOT_EXISTS
:NEXT4
goto APPLY

rem *** ERRORS
:ERROR_NO_USER_FILE
echo ERROR: Create a "%USER_HEADER_FILE%" in this directory first.
goto ABORTED
:ERROR_LIB_NOT_EXISTS
echo %ATU_HEADER_FILE1%
echo ERROR: Check the directory location match your Arduino IDE setup, see "ARDUINO_LIB_DIR" at top of this batch file. Check also if you have the Trinket USB Library currently installed.
goto ABORTED

:APPLY
echo All seems to be fine, applying patch (symlinks).....
echo Checking and removing target files....
if exist "%ATU_USER_HEADER_FILE1%" goto REMOVE1
goto APPLY_NEXT2
:REMOVE1
echo Remove symlink of "%ATU_USER_HEADER_FILE1%" ....
del "%ATU_USER_HEADER_FILE1%"

:APPLY_NEXT2
if exist "%ATU_USER_HEADER_FILE2%" goto REMOVE2
goto APPLY_NEXT3
:REMOVE2
echo Remove symlink of "%ATU_USER_HEADER_FILE2%" ....
del "%ATU_USER_HEADER_FILE2%"

:APPLY_NEXT3
if exist "%ATU_USER_HEADER_FILE3%" goto REMOVE3
goto APPLY_NEXT
:REMOVE3
echo Remove file/symlink of "%ATU_USER_HEADER_FILE3%" ....
del "%ATU_USER_HEADER_FILE3%"

:APPLY_NEXT
echo.
if "@%1"== "@/c" goto APPLY_COPY
if "@%1"== "@/C" goto APPLY_COPY
if "@%1"== "@-c" goto APPLY_COPY
if "@%1"== "@-C" goto APPLY_COPY
echo Applying symlinks....
mklink /H "%ATU_USER_HEADER_FILE1%" "%USER_HEADER_FILE%" 
mklink /H "%ATU_USER_HEADER_FILE2%" "%USER_HEADER_FILE%" 
mklink /H "%ATU_USER_HEADER_FILE3%" "%USER_HEADER_FILE%" 
goto SUCCESS

:APPLY_COPY
echo Copy file(s)....
copy "%USER_HEADER_FILE%" "%ATU_USER_HEADER_FILE1%"  
copy "%USER_HEADER_FILE%" "%ATU_USER_HEADER_FILE2%"  
copy "%USER_HEADER_FILE%" "%ATU_USER_HEADER_FILE3%"  
SET COPYMODE=true
goto SUCCESS

:ABORTED
echo Batch aborted due error.
goto END

:SUCCESS
echo.
echo SUCCESS!
echo NOTICE: 
echo - Patch succesfully applied when no error is visible on screen.
if "%COPYMODE%"=="true" echo - Because you specify the copymode switch, you have to take care of updates yourself. Run this batch file again when you have changed USB settings. 

:END
SET USAGEMODE=
SET COPYMODE=
echo.
echo Press any key to exit...
pause >NUL

:DIE
echo.

Conclusion and question:

Although this method is working fine, I'm still not satisfied and wonder if there is an easier way to this without changing any line of code of the library. A more "on the fly" solution so you don't have to think about this to avoid errors and other headaches.


回答1:


After a long time I discover how the Arduino compiler compiles the code. It is not a C/C++ issue, actually it is an error in the Arduino compiler, the combine and compile order. Also the compiler add some specific code before compiling.


Workaround:

Include your libraries/independencies with use of an exra project h-file. Defines before includes will not work because the compile method includes h-files before the defines (in your ino file) will be applied. When using defines, to change a library for example, requires a separated h-file. For example "myproject.inc.h" which includes all libraries you want to use.

Now all defines you specify before including a library will be applied.

Example:


myproject.ino


#include "myproject.inc.h"

void setup()
{
  TrinketHidCombo.begin(); 
}

void loop() // Main program - main()
{
  // do nothing, check if USB needs anything done
  TrinketHidCombo.poll();  
}

myproject.inc.h


#define USB_CFG_VENDOR_NAME     'm', 'y', 'C', 'o', 'm', 'p', 'a', 'n', 'y', 'n'
#define USB_CFG_VENDOR_NAME_LEN 10

#include "TrinketHidCombo.h"


来源:https://stackoverflow.com/questions/37769451/arduino-change-defines-without-edit-library-solved-bug-in-compiler-workaroun

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!