B4R Tutorial Inline C / C++

As in the other B4X tools you can embed C or C++ code in the project.

Example:
B4X:
Sub Process_Globals
   Public Serial1 As Serial
   Private Result, N1, N2 As Int 'ignore
End Sub

Private Sub AppStart
   Serial1.Initialize(115200)
   Log("AppStart")
   N1 = 10
   N2 = 20
   RunNative("Add", Null)
   Log("Result: ", Result)
End Sub

#if C
void Add (B4R::Object* o) {
   //lower case variables
   b4r_main::_result = b4r_main::_n1 + b4r_main::_n2;
}
#End if
The native method signature must be as written above. It can optionally return a B4R::Object*.
In most cases it is simpler to work with global variables.

Note that the global variable names are lower cased and the name includes the current module in the following format b4r_<current module lower case>.

You can add #include commands as demonstrated in the next example.

In this example we will use an external library named Narcoleptic. With this library we can put the board in deep sleep to preserve battery.
The library is available here: https://github.com/chrisfeltman/Arduino/tree/master/libraries/Narcoleptic

You need to download the h and cpp files and put them under arduino\libraries\Narcoleptic.
B4X:
Private Sub AppStart
   Serial1.Initialize(115200)
   Log("AppStart")
   Log(Millis)
   RunNative("Delay", 5000)
   Log("after: ", Millis, " (the internal timer was not updated during the sleep)")
End Sub

#if C
#include <Narcoleptic.h>
void Delay (B4R::Object* o) {
   Narcoleptic.delay(o->toULong());
}
#End if
 

Cableguy

Expert
Licensed User
Longtime User
This means that, with this method we can use any existing arduini lib?
 

Cableguy

Expert
Licensed User
Longtime User
Hi EREL!

I'm trying to use a function I found, proven to work in the Arduino IDE, but my issue is, it expects 4 arguments, 1 integer and 3 bytes... ho do I use it with inline C?
 

Cableguy

Expert
Licensed User
Longtime User
So, I managed to solve the above problem, but am facing another one...

The function has a Byte definition, to which I am trying to pass a variable... But always getting the same error no matter how I try to work it around.

The definition is as follows:
B4X:
byte RGB[120];

and I am trying to pass an integer to the size of the array, like this:
B4X:
byte RGB[b4r_ws2812b::_ledarraysize];

ws2812B is my code module and ledarraysize is a variable defined to be an integer and set in the initialize sub
The ledarraysize is computed from a variable passed in to the initialize sub.

This is the error i'm getting:

B4X:
b4r_ws2812b.cpp:16: error: array bound is not an integer constant before ']' token
  byte RGB[b4r_ws2812b::_ledarraysize];//take your number of LEDs and multiply by 3
 

johndb

Active Member
Licensed User
Longtime User

atiaust

Active Member
Licensed User
Longtime User
Hi All,

How do you read an array return using RunNative C++ back into B4R?

results(6) as ULong is declared as an array in Process_Globals

B4X:
Sub Looper1
   'If Millis > lastRead + 1000 Then
        RunNative("read",Null)
     'If results(0) > 0 Then
       Log("Received 0: ", results(0))
       Log("Received 4: ", results(4))
     'End If
   'End If
   'Log("LastRead : ", lastRead,"  Millis : ", Millis)
End Sub

#if C
#include "RTClib.h"
    RTC_DS1307 RTC;
    // RTC.now =  return DateTime (y, m, d, hh, mm, ss) - all ULong values
    void read(B4R::Object* o) {
           b4r_main::_results = RTC.now();
    }
#end if

Keep getting error message

sketch\b4r_main.cpp: In function 'void read(B4R::Object*)':
b4r_main.cpp:15: error: cannot convert 'DateTime' to 'B4R::Array*' in assignment
b4r_main::_results = RTC.now();
Any ideas
Thanks
 

rbghongade

Active Member
Licensed User
Longtime User
Dear friends,
How to pass pin numbers to inline C/C++ code section? Please note that I want to pass the pin numbers for initialisation and not during function call.
 

rbghongade

Active Member
Licensed User
Longtime User
Here is the working code for Ultrasonic Distance sensor HC SR-04 with Wemos mini, employing a very stable and reliable Newping library.
B4X:
Sub Process_Globals
  Public Serial1 As Serial
  Private wemos As D1Pins
  Private trigPin, echoPin As Pin
  Private timer1 As Timer
  Public US As UInt
  Public DISTANCE As Long
  Public max_distance As ULong
End Sub

Private Sub AppStart
  Serial1.Initialize(115200)
  Log("AppStart")
  trigPin.Initialize(wemos.D6,trigPin.MODE_OUTPUT)
  echoPin.Initialize(wemos.D7,echoPin.MODE_INPUT)
  timer1.Initialize("timer1_Tick",50)
  timer1.Enabled = True
 
End Sub

Private Sub Timer1_Tick
  RunNative("read",Null)
   Log(DISTANCE)
End Sub


#if C
#include <NewPing.h>
NewPing sonar(12, 13, 500);

void read (B4R::Object* o) {
delay(50);
  b4r_main::_us = sonar.ping_median(20,500);
   b4r_main::_distance=sonar.convert_cm(b4r_main::_us);
}
#End if
Now in the c-code I wish to pass the pin declarations for trigPin and echoPin and max_distance (long int) like "NewPing sonar(trigPin,echoPin, max_distance)"
 
Last edited:

Erel

B4X founder
Staff member
Licensed User
Longtime User
Something like:
B4X:
#if C
#include <NewPing.h>
Byte beSonar[sizeof(NewPing)];
NewPing* sonar;
void initialize(B4R::Object* o) {
  sonar = new (beSonar) NewPing(b4r_main::_sonarpin1, b4r_main::_sonarpin2, 500);
}
void read (B4R::Object* o) {
delay(50);
  b4r_main::_us = sonar.ping_median(20,500);
   b4r_main::_distance=sonar->convert_cm(b4r_main::_us); //-> instead of .
}
#End if
You need to add the two variables (SonarPin1 and SonarPin2) and call initialize with RunNative.
 

iCAB

Well-Known Member
Licensed User
Longtime User
For larger Arduino libraries it is better to write a wrapper and provide a B4R API.

I am very comfortable with "C", but I would like to take advantage of my existing B4A code, and the fact that B4X tools work nicely together.

At the same time, I would like to use existing Arduino libraries as is without having to write wrappers. Would that be possible and if not can you please clarify, what doesn't work in this case.

Thanks
 
Top