C/C++ Question function with one or more parameters

candide

Active Member
Licensed User
in B4R we have "Log" working with a number of parameters not define
/**
*Logs one or more messages.
*This is a special method. It can accept any number of parameters.
*The data is sent through the Serial object.
*Each parameter can be a String, number or an array of bytes (which will be treated as a string).
*Example: <code>
*Log("x = ", x)</code>
*/
static void Log(Object* OneOrMoreMessages);


can we have in B4R similar process to manage a function in a class with multiple parameters ? (managed by va_list)

how a function with a not define list of parameters can be accepted at B4R user interface ?
 

emexes

Expert
Licensed User
This 2016 post looks like it's in the ballpark:

In the next update there will be two new keywords:
JoinStrings and JoinBytes.

JoinStrings takes an array of strings and concatenates them to a single string.

Dim s As String = JoinStrings(Array As String("Pi = ", cPI))
 

candide

Active Member
Licensed User
example of <MAKE_EmbAJAXPage> to handle in a wrapper :

first case, a function with 7 parameters :
B4X:
MAKE_EmbAJAXPage(page, "EmbAJAX example - Joystick control", "<style>canvas { background-color: grey; }</style>",
  new EmbAJAXStatic("<h1>Joystick demonstration.</h1><p><b>Note that the EmbAJAXJoystick class is not entirely finished, yet, and the API and behavior might be subject to change!</b></p><p>The upper joystick is confined to the 9 \"keypad\" positions, and snaps back to center on release / leave.</p>"),
  &joy1,
  new EmbAJAXStatic("<p>This lower joystick follows the position of the upper joystick (for no other purpose than to demonstrate a round-trip over the server). When moving it directly, it is not confined to the keypad positions, and does not snap back to center.</p>"),
  &joy2
)

and an other example of same function with 48 parameters :
B4X:
MAKE_EmbAJAXPage(page, "EmbAJAX example - Inputs", "",
    new EmbAJAXStatic("<table cellpadding=\"10\"><tr><td>"),
    &check,
    &nextCell,  // Static elements can safely be inserted into the same page more than once!
    &check_d,
    &nextRow,

    &radio,
    &nextCell,
    &radio_d,
    &nextRow,

    &optionselect,
    &nextCell,
    &optionselect_d,
    &nextRow,

    &slider,
    &nextCell,
    &slider_d,
    &nextRow,

    &color,
    &nextCell,
    &color_d,
    &nextRow,

    &text,
    &nextCell,
    &text_d,
    &nextRow,

    &valtext,
    &nextCell,
    &valtext_d,
    &nextRow,

    &button,
    &nextCell,
    &button_d,
    &nextRow,

    &m_button,
    &nextCell,
    &m_button_d,
    &nextRow,

    new EmbAJAXStatic("A client side script:"),
    &nextCell,
    &m_script_s,
    &nextRow,

    new EmbAJAXStatic("Server status:"),
    &nextCell,
    new EmbAJAXConnectionIndicator(),
    new EmbAJAXStatic("</b></td></tr></table>")
)

can we handle on B4R interface a function with a not fix number like it is accepted for Log(a,b,c,d,....)
 

Daestrum

Expert
Licensed User
Longtime User
Could you not pass the parameters in an array and split them inside the c code?
 

candide

Active Member
Licensed User
at last i have no solution to handle this variable list of parameters and an array don't solve issue on B4R interface :
  1. to manage a page of server, we have to manage a long list of parameters, we have to manage a long list of String, pointers to object running or to launch some objects.
  2. yes we can create an array in B4R , but after in wrapper to convert array to va_list dynamically before to launch function, not sure it is possible.
  3. after in my array i have to store String or pointer to an objet (multiple objects possible) or direct launch of object.
no, i don't know how to handle.... This one is too complex for me
 
Last edited:

emexes

Expert
Licensed User
i don't know how to handle
yes, to use an array of objects should be a way

Did this work? I don't know B4R, but the following worked in B4J:

Variable number of parameters:
Sub LogPar(O() As Object)
    For I = 0 To O.Length - 1
        If O(I) Is String Then
            Log("Hello " & O(I))
        Else If IsNumber(O(I)) Then    'might need to change to eg: If O(I) Is Int Or O(I) Is Double Then
            Log(NumberFormat2(O(I), 1, 1, 1, True))
        Else
            'something other than string or number
        End If
    Next   
End Sub
Test with:
LogPar(Array("world!!!"))
LogPar(Array(1, 2, 3, "Edwin", "Michael", "Neil", 1969.55026))
Log output:
Waiting for debugger to connect...
Program started.
Hello world!!!
1.0
2.0
3.0
Hello Edwin
Hello Michael
Hello Neil
1,969.6
Program terminated
 

emexes

Expert
Licensed User
Or are you trying to call a C function that has a variable number of arguments, from B4R?

That might be easier done using inline C within B4R.

But inline Java within B4J seems to be compiled as though it's at the end of the source file rather than where the inline Java code actually is relative to surrounding B4J BASIC code, so if B4R does the same with inline C then... 🤔
 

XorAndOr

Active Member
Licensed User
Longtime User
hi @candide
I often use "Type" when I have many variables to pass to inline C
something similar to this...
B4R:
Type MyType (SSID As String, PASSW As String, IP As String, ID As Int, BOARD_ID As Int)
    
Public myData As MyType   
        
myData.SSID = "ESP_AP"
myData.PASSW = "12345678"
myData.IP = "192.168.4.1"
myData.ID = 01
myData.BOARD_ID = 01   
    
Log("SSID = ", myData.SSID,"PASSW = ",myData.PASSW, "IP = ",myData.IP,"ID = ",myData.ID,"BOARD_ID = ",myData.BOARD_ID)
    
RunNative("MY INLINE C CODE",myData)
 

Daestrum

Expert
Licensed User
Longtime User
Naughty example but ...
B4X:
Sub Process_Globals
    Public Serial1 As Serial
#if c
    const char* s[] = {"one","two","three","four","five"};
#End If
End Sub

Private Sub AppStart
    Serial1.Initialize(9600)
    Log("AppStart")
    RunNative("test",Null)
End Sub
#if c
void test(B4R::Object* o){
    int length = std::end(s) - std::begin(s);
    for(int a = 0; a < length; a++){
        Serial.println(s[a]);
    }   
}
#End If
 

candide

Active Member
Licensed User
example of code to recover data in inline C from an array of Object:
B4X:
    Dim xy() As Byte = Array As Byte(40,41,42,43,44)
    Dim tsts() As Object = Array(xx,"azerty",1000,"next".getbytes,105.00,"last","10")
    RunNative("myobject",tsts)

end sub

#if c
void myobject(B4R::Object* o) {
    byte Type = o->type;
    Serial.print("Object1 type : ");Serial.println(Type);  
    Long Long1; ULong ULong1; Double Double1; const char* cchar1; char* char1; B4R::Array* ar1;B4R::Array* ar2; B4R::Object** arrayOfPointers;
  

//Dim tsts() As Object = Array(xx,"azerty",1000,"next".getbytes,105.00,"last","10")
//RunNative("myobject",tsts)  
   if (Type == 100) { //case array of Objects      
        ar1 = (B4R::Array*)B4R::Object::toPointer(o);      
        Serial.print("Array length : ");Serial.println(ar1->length);
                  
        arrayOfPointers = (B4R::Object**) ar1->data;       
        B4R::Object* c[ar1->length];int i;
        for(i = 0; i <ar1->length; i++)
        {
            c[i]= arrayOfPointers[i];  
            Serial.print("Object c[");Serial.print(i);Serial.print("] type : ");Serial.println(c[i]->type);
            switch (c[i]->type) { //test Object type
            case 5 : // Long
                Serial.print("value Long: "); Serial.println(c[i]->toLong());
                break;          
            case 6 : // ULong
                Serial.print("value ULong: "); Serial.println(c[i]->toULong());
                break;              
            case 7 : // Double
                Serial.print("value Double: "); Serial.println(c[i]->toDouble());   
                break;      
            case 100 : //Pointer to char*
                ar2 = (B4R::Array*)B4R::Object::toPointer(c[i]);
                char1 = (char*)ar2->data;
                Serial.print("content : ");Serial.println(char1);
                break;      
            case 101 : //pointer to const char*      
                char2 = (const char  *)B4R::Object::toPointer(c[i]);  
                Serial.print("content : ");Serial.println(char2);       }    }          
};
#End If

2 issues on decoding of Object in inline C:
- for Object type 100 : it is a type of Object with pointer , but pointer can be to uint8_t*, char* , uint16_t* or array or pointer* (no indication in Object)
- for Array, it is same, we don't have indication on type of data
 
Last edited:

Daestrum

Expert
Licensed User
Longtime User
As an aside, in your code above (to save you typing Serial.print/Serial.println so often) use Serial.printf
eg,
B4X:
Serial.print("value ULong: "); Serial.println(c[i]->toULong());
becomes
B4X:
Serial.printf("value ULong: %d \n" , c[i]->toULong());
** dont forget the \n or it will not output a lf
 
Top