B4R Tutorial Creating libraries for B4R

Libraries are written in C++.
Libraries are made of a single h file and one or more cpp files. Libraries can also include other h files which will not be exposed.

All the files should be in the same folder.
The attached h2xml jar reads the h file and creates the xml file that is used by the IDE.
It is a command line program.

You can run it with:
B4X:
java -jar B4Rh2xml.jar <path to h file> <output file>

As the IDE libraries source code is available, this is the best way to learn how to build libraries.

Start with a simple library such as rEEPROM.

Personally I'm using Notepad++ to write the libraries.
The IDE doesn't cache the libraries source (unlike in B4A). So you can save the file and run the project to test it.
If the signature was changed then you need to run the h2xml tool and then right click on the libraries tab and choose Refresh.

Metadata attributes (attribute case is not important):

//~Version - The library version.
//~DependsOn - Can appear multiple times. Adds a dependency on an external h file.
//~ShortName - Each exposed class should have this attribute. This is the name that will appear in the IDE.
//~Event - Can appear multiple times. Used by the IDE to autocomplete event subs.
//~Author - Library author

Rules, tips and notes

Libraries should avoid using the heap (malloc or new should not be used).

- Most libraries wrap another object. There are cases where you need to call the object constructor and you can only do it when the user calls the Initialize method.
This is the case for example in rLiquidCrystal library.
The solution is to create an array of bytes (named backend in this example) and then use placement new instead of new. This way we can generate a new object in the already allocated buffer.

- Polling. If you need to call a method every loop iteration then you can add it to the PollerList.
See Pin::AddListener for an example. Note that you can only add static methods. Pass a pointer to the class instance as the tag value.
It is possible to remove the "polling". It is a bit more complicated. You can see it in rMQTT implementation.

- Using the stack buffer.

How can your method return a new object if it cannot use the heap?
How can Common::NumberFormat return a string?

In many cases the solution is to let the user pass an array to your method and then your method will use the array. However this is not always convenient. This is why B4R maintains another stack.
You can use this stack for allocations. It will be popped when the calling sub ends.

Simple example: ByteConverter::convertBytesToArray. It is simple because it only creates the Array object on the B4R stack.

More complicated example: ByteConverter::HexToBytes. In this case the array with its data are created on the B4R stack.

- Interrupts - The B4R code should not be called from an interrupt. Instead you should call pollers.setInterrupt. See rWire library (WriteSlave::receiveEvent).

- Raising events - Any parameter with a type that starts with Sub will be treated as a "sub name". Practically the compiler will remove the quotes and lower case the string value. Your code will receive a function pointer.
You can use the types declared with typedef in rCore.h or use your own types.

- Pointers and objects - Only pointers to objects should be exposed to B4R.

Please use the libraries developers questions for any question: https://www.b4x.com/android/forum/forums/libraries-developers-questions.77/
 

Attachments

  • B4Rh2xml.jar
    98 KB · Views: 1,366
Last edited:

jarda

Member
Licensed User
Longtime User
Hi
How can I integrate this source code. For example, as a library. (B4R)
Can this be done?

Thanks

Jarek
 

Attachments

  • TFT.ZIP
    45.9 KB · Views: 667

Cableguy

Expert
Licensed User
Longtime User
Hi Erel,

I'm trying to build my first wrapper, but can't even create the xml from the .h file.

B4X:
D:\psapg\NeoPixelWrap>java -jar B4Rh2xml.jar Adafruit_NeoPixel.h B4R_NeoPixel
Error parsing: Adafruit_NeoPixel(void);
parser._parsemethod (java line: 527)
java.lang.NumberFormatException: For input string: "error"
        at sun.misc.FloatingDecimal.readJavaFormatString(Unknown Source)
        at sun.misc.FloatingDecimal.parseDouble(Unknown Source)
        at java.lang.Double.parseDouble(Unknown Source)
        at b4j.example.parser._parsemethod(parser.java:527)
        at b4j.example.parser._parseline(parser.java:464)
        at b4j.example.parser._parseh(parser.java:422)
        at b4j.example.parser._parse(parser.java:267)
        at b4j.example.main._appstart(main.java:46)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
        at java.lang.reflect.Method.invoke(Unknown Source)
        at anywheresoftware.b4a.BA.raiseEvent2(BA.java:93)
        at anywheresoftware.b4a.BA.raiseEvent(BA.java:84)
        at b4j.example.main.main(main.java:29)
 

Cableguy

Expert
Licensed User
Longtime User
So, how do I do that?
Perhaps not the easiest to start with?
Can it be done using a code module + inline c combo?
 

Buks

Member
Licensed User
Longtime User
Has anyone managed to use the Arduino Ciao Library? There is a special version of Arduino Uno (Arduino Uno WIFI) that can make use of this library for network interaction. It does not seem to work with inline C - no errors, but data does not update. It would really be very nice to access all the functionalities of the Uno WIFI from B4R.
 

Peter Simpson

Expert
Licensed User
Longtime User
It would be nice to have a tutorial video on creating more complicated B4R libraries, lets say it based on Adafruit_NeoPixel (which has already been wrapped by @Erel). I actually want to use B4R to create a project BUT no library, so I've just started it in Arduino instead which is a nightmare compared to B4R.

Basically I ran into the same issues as what's in post #4 :(

Untitled-2.png


The above looks Martian to me o_O
 
Last edited:
Top