C/C++ Question [Solved] NewPing Wrapper

Johan Schoeman

Licensed User
Longtime User
I am trying to wrap the NewPing library (juts initialize and method ping_cm for now).

This is my rNewPing.f file:
#pragma once
#include "B4RDefines.h"
//~dependson: <NewPing.h>

namespace B4R {
//    ~Version: 1.00
//    ~ShortName: NewPing
    class B4RNewPing {
            uint8_t backend[sizeof(NewPing)];
            NewPing* np;
            *Initializes the object.
            void Initialize(Byte triggerpin, Byte echopin, UInt maxcmdistance);
            ULong ping_cm(UInt maxcmdistance);

This is my rNewPing.cpp file:
#include "B4RDefines.h"
namespace B4R {
    void B4RNewPing::Initialize(Byte triggerpin, Byte echopin, UInt maxcmdistance) {
            np =  new (backend) NewPing(triggerpin, echopin, maxcmdistance);
    ULong B4RNewPing::ping_cm(UInt maxcmdistance) {   
        return np->ping_cm(maxcmdistance);

This is my rNewPing.xml file:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>

            <name DesignerName="Initialize">Initialize</name>
            <comment>Initializes the object
TrigPin - Trigger Pin
EchoPin - Echo Pin
maxcmdistance - Maximum Distance in cm
np.Initialize(TrigPin, EchoPin, maxcmdistance)&lt;/code&gt;</comment>
            <name DesignerName="ping_cm">ping_cm</name>
            <comment>Return the ping distance in cm (max = maxcmdistance)</comment>

The constructor in NewPing.cpp is as follows:

NewPing::NewPing(uint8_t trigger_pin, uint8_t echo_pin, unsigned int max_cm_distance) {
//    ::Serial.println("aaa");
#if DO_BITWISE == true
    _triggerBit = digitalPinToBitMask(trigger_pin); // Get the port register bitmask for the trigger pin.
    _echoBit = digitalPinToBitMask(echo_pin);       // Get the port register bitmask for the echo pin.

    _triggerOutput = portOutputRegister(digitalPinToPort(trigger_pin)); // Get the output port register for the trigger pin.
    _echoInput = portInputRegister(digitalPinToPort(echo_pin));         // Get the input port register for the echo pin.

    _triggerMode = (uint8_t *) portModeRegister(digitalPinToPort(trigger_pin)); // Get the port mode register for the trigger pin.
    _triggerPin = trigger_pin;
    _echoPin = echo_pin;

    set_max_distance(max_cm_distance); // Call function to set the max sensor distance.

#if (defined (__arm__) && (defined (TEENSYDUINO) || defined(PARTICLE))) || DO_BITWISE != true
    pinMode(echo_pin, INPUT);     // Set echo pin to input (on Teensy 3.x (ARM), pins default to disabled, at least one pinMode() is needed for GPIO mode).
    pinMode(trigger_pin, OUTPUT); // Set trigger pin to output (on Teensy 3.x (ARM), pins default to disabled, at least one pinMode() is needed for GPIO mode).

#if defined (ARDUINO_AVR_YUN)
    pinMode(echo_pin, INPUT);     // Set echo pin to input for the Arduino Yun, not sure why it doesn't default this way.

#if ONE_PIN_ENABLED != true && DO_BITWISE == true
    *_triggerMode |= _triggerBit; // Set trigger pin to output.

The method that I am calling in NewPing.cpp is as follows:
unsigned long NewPing::ping_cm(unsigned int max_cm_distance) {
    unsigned long echoTime = NewPing::ping(max_cm_distance); // Calls the ping method and returns with the ping echo distance in uS.
//    ::Serial.println("bbb");
//    ::Serial.println(echoTime / US_ROUNDTRIP_CM);
    return (echoTime / US_ROUNDTRIP_CM);              // Call the ping method and returns the distance in centimeters (no rounding).
    return NewPingConvert(echoTime, US_ROUNDTRIP_CM); // Convert uS to centimeters.

I can see the wrapper in the B4R IDE (rNewPing version 1.00) and from the B4R project the library is initialized correctly (check it by adding ::Serial.println("xxx"). But I get a cast error when trying to return the "distance" from the the library method to B4R. My B4R code is as follows:
#Region Project Attributes
    #AutoFlushLogs: True
    #CheckArrayBounds: True
    #StackBufferSize: 300
#End Region

Sub Process_Globals
    'These global variables will be declared once when the application starts.
    'Public variables can be accessed from all modules.
    Public Serial1 As Serial
    Dim t As Timer
    Dim dst As UInt = 500
    Dim nbr As ULong
    Dim pin9 As Byte = 9
    Dim pin10 As Byte = 10
    Dim np As NewPing
End Sub

Private Sub AppStart
    t.Initialize("t_tick", 1000)
    np.Initialize(pin9, pin10, dst)
    nbr = 0
    t.Enabled = True

End Sub

Sub t_tick
    nbr = np.ping_cm(dst)                 'THIS GIVE A CAST ERROR
End Sub

Error in the IDE is as follows:


From what I can see it that the constructor expects a Byte, Byte, UInt and the method expects a UInt and should return a ULong.

Using ::Serial.println(echoTime / US_ROUNDTRIP_CM); inside the library prints/logs the correct value is the B4R log.

I have edited all the above (.h, .cpp, .xml) in Notepad++ so maybe I have an error in the .xml?

Will appreciate some advise to get the cast type error sored out.




  • upload_2019-6-1_7-22-3.png
    57.1 KB · Views: 344