Android Question Nested Classes

max123

Well-Known Member
Licensed User
Longtime User
Hi all,

this question refers both to B4A and B4J languages,

I apologize for any errors, but English is not my native language.

I used several times classes with B4A and B4J making my code portable between various projects.

Now I need to use subclasses (or any other) inside classes and do not know if this can be done in any way.

Let me explain ...

For example, if I create a class with B4J or B4A simulating Arduino (let's call it ArduinoClass)
I use the class like this:
B4X:
Sub Class_Globals
   ' Private and Public variables
     Public const OUTPUT As Byte = 0
     Public const INPUT As Byte  = 1
     Public const INPUT_PULLUP As Byte  = 2  
     Public const LOW As Byte  = 0
     Public const HIGH As Byte  = 1  
End Sub

'Initializes the Arduino object. You can add parameters to this method if needed.
Public Sub Initialize()
    ' write here some initializations
End Sub

Public Sub pinMode(Pin As Byte, Value As Byte)
    ' write here some code for pinMode command
End Sub

Public Sub digitalWrite(Pin As Byte, Value As Byte)
    ' write here some code for digitalWrite command
End Sub

Then in the Main module I write this:
B4X:
Sub Process_Globals
    Private fx As JFX
    Private MainForm As Form
   
    Dim Arduino As ArduinoClass
End Sub

Sub AppStart (Form1 As Form, Args() As String)
    MainForm = Form1
    MainForm.SetFormStyle("UNIFIED")
    'MainForm.RootPane.LoadLayout("Layout1") 'Load the layout file.
    MainForm.Show
   
    Arduino.Initialize()
    Arduino.pinMode(13, Arduino.OUTPUT)
    Arduino.digitalWrite(13, HIGH)
End Sub
Up to this point everything is ok, but now I have 2 questions that I can't find answer reading the forum:

QUESTION 1
How would I write a nested class within another class?

What I need to do in the Main is something like this:
B4X:
Arduino.Serial.begin(115200)
Arduino.Serial.print("Hello")
Arduino.Serial.println("Hello")
where Serial should be a subclass of the class ArduinoClass and contain 3 methods (in this example, begin, print and println)

QUESTION 2
How would I write a class that can concatenate several commands how StringBuilder does where for example we can have this :
B4X:
Dim sb1 As StringBuilder
sb1.Initialize
sb1.Append("Hello ").Append("from ").Append(B4A)
Then it would be possible to do something like this?
B4X:
Dim Arduino as ArduinoClass
Arduino.Initialize()
Arduino.pinMode(13, Arduino.OUTPUT).digitalWrite(13, HIGH)

Thank you very much to anyone who will get out of these doubts from my mind.
 

max123

Well-Known Member
Licensed User
Longtime User
Many thanks Erel for your reply ;)

For Question 1, I don't sure I've completely understand you, so I need to add to a project a main class and then other subclass
and instantiate these in the main class? eg. Dim Serial as MySerial

For question 2, I've tried and seem to work well, i can do eg. ESP.Serial.print("Hello ").print("from ").println("B4X")
but I don't understand this way how i can call a Sub on main class

What i need to do is to write a B4J and B4A library that send/receive UDP messages to/from ESP8266 (NodeMCU in my first test)

With your suggestions I've created a simple example to reproduce it.

I'm starting this using B4J for now, but because this is B4A forum I've created a simple
example for B4A too, principally the code is same, I only used copy/paste.

Please, can you see if this is ok?

The main app code for B4A is this:
B4X:
Sub Process_Globals
    'These global variables will be declared once when the application starts.
    'These variables can be accessed from all modules.
    Private ESP As ESP8266
    Private Pin As Byte
    Private Timer1 As Timer
End Sub

Sub Globals
    'These global variables will be redeclared each time the activity is created.
    'These variables can only be accessed from this module.
End Sub

Sub Activity_Create(FirstTime As Boolean)
    'Do not forget to load the layout file created with the visual designer. For example:
    'Activity.LoadLayout("Layout1")
  
    ESP.Initialize(8888, 1024)  'LocalPort, BufferSize
  
    Pin = ESP.BUILTIN_LED
  
    ESP.pinMode(Pin, ESP.OUTPUT)
    ESP.digitalWrite(Pin, ESP.LOW)  'for now we sets as LOW but led is inverted on NodeMCU
  
    ESP.Serial.begin(115200)
    ESP.Serial.print("No Append Mode")
    ESP.Serial.print("Hello ").print("from ").println("B4X")
  
    Timer1.Initialize("Timer1", 1000)
    Timer1.Enabled = True
End Sub

Sub Activity_Resume

End Sub

Sub Activity_Pause (UserClosed As Boolean)

End Sub

Sub Timer1_Tick
    ESP.digitalWrite(Pin, Not(ESP.digitalRead(Pin)))
End Sub

Many thanks.:)
 

Attachments

  • ESP8266_B4A.zip
    8.6 KB · Views: 279
  • ESP8266_B4J.zip
    2.5 KB · Views: 228
Last edited:
Upvote 0

Erel

B4X founder
Staff member
Licensed User
Longtime User
I'm sorry but it is difficult for me to review your code.

If you have any specific question then please post it.


For Question 1, I don't sure I've completely understand you, so I need to add to a project a main class and then other subclass
and instantiate these in the main class? eg. Dim Serial as MySerial
The term subclass is not accurate. MySerial is a regular class like any other class. The ESP class holds an instance of MySerial class.

B4X:
'ESP class
Sub Class_Globals
 Public Serial1 As MySerial
End Sub

Sub Initialize
 Serial1.Initialize(...)
End Sub
 
Upvote 0

max123

Well-Known Member
Licensed User
Longtime User
I wrote ESP8266 Class as Your advice:
B4X:
Private Sub Class_Globals
    Private root As String
    Private const CM As String = ", "

    Private UDP As UDPSocket   '<<<< Initializes UDP Socket

    Private tPortIn As Int
    Private tPortOut As Int
    Private tBufferSize As Int
    Private tRemoteIP As String
    Private tMillis,startTime As Long
    Private GlobalPinState As Boolean = False
    Private millisTimer As Timer
    Public Serial As MySerial   '<<<< declare Serial as MySerial Class
End Sub

'Initializes the ESP8266 object.
Public Sub Initialize(RemoteIP As String, PortOut As Int, PortIn As Int, RcvBufferSize As Int)
    tPortIn = PortIn
    tPortOut = PortOut
    tRemoteIP = RemoteIP
    tBufferSize = RcvBufferSize

    UDP.Initialize("UDP", tPortIn, tBufferSize)
    Serial.Initialize   '<<<< Initializes Serial Class
    millisTimer.Initialize("millisTimer",1)  'initializes millis() timer
    startTime = DateTime.Now
    millisTimer.Enabled = True
End Sub

Public Sub pinMode(Pin As Byte, Mode As Byte) As ESP8266
    root = "pinMode" & CM & Pin & CM & Mode
    sendCmd(root)
    Return Me
End Sub

' SEND ALL COMMANDS THRU UDP SOCKET
Private Sub sendCmd(s As String)
    Dim pkt As UDPPacket
    Dim buffer() As Byte = s.GetBytes("UTF8")
    pkt.Initialize(buffer, tRemoteIP, tPortOut)
    UDP.Send(pkt)
End Sub

Then I wrote a MySerial Class:
B4X:
Private Sub Class_Globals
    Private root As String
    Private const CM As String = ", "
End Sub

'Initializes the Serial object inside ESP8266 Class.
Public Sub Initialize

End Sub

Public Sub begin(Baud As Int) As MySerial
    root = "SerialBegin" & CM & Baud
    sendCmd(root)
    Return Me
End Sub

Public Sub print(txt As String) As MySerial
    root = "SerialPrint" & CM & txt
    sendCmd(root)
    Return Me
End Sub

Public Sub println(txt As String) As MySerial
    root = "SerialPrintln" & CM & txt
    sendCmd(root)
    Return Me
End Sub

Private Sub sendCmd(s As String) As MySerial
    ' THIS WAY HOW TO CALL sendCmd Sub in ESP8266 Class and pass 's' variable???
    Return Me
End Sub

This way i can do example :
B4X:
ESP.Serial.begin(115200)
ESP.Serial.print("No Append Mode")
ESP.Serial.print("Hello ").print("from ").println("B4X")

In sendCmd Sub inside MySerial Class if I do: Log(s) I can see my data.

But my answer is:

from MySerial Class, how I can call sendCmd Sub inside ESP8266 Class to send UDP data?
UDP instance is declared inside ESP8266 Class.
 
Last edited:
Upvote 0

max123

Well-Known Member
Licensed User
Longtime User
Ok, many thanks!

Attached a start point of my class.
I'm sorry, but the project is for B4J, but for B4A I think is same.
 

Attachments

  • ESP8266.zip
    3.3 KB · Views: 250
Upvote 0

Erel

B4X founder
Staff member
Licensed User
Longtime User
I guess that in the future MySerial will be used with other classes, not just ESP8266, right? Otherwise it will be simpler to just remove it and move the code to ESP8266.

You can pass a reference to ESP8266 when you initialize MySerial.
B4X:
'My Serial
Private Sub Class_Globals
 Private mESP As ESP8266
End Sub

Sub Initialize(ESP As ESP8266)
 mESP = ESP
End Sub

Sub sendCmd(s As String) As MySerial
 mESP.sendCmd(s)
End Sub

This however is not good enough if you want to later use a different class that also has a sendCmd (Arduino).

So you need to change the code to:
B4X:
'My Serial
Private Sub Class_Globals
 Private mBoard As Object
End Sub

Sub Initialize(Board As Object)
 mBoard = Board
End Sub

Sub sendCmd(s As String) As MySerial
 CallSub2(Board, "sendCmd", s)
End Sub
 
Upvote 0

max123

Well-Known Member
Licensed User
Longtime User
Ok many thanks Erel, I'll study and try your solution and then post here my results.;)

Yes, you are right!

For now I wrote it for ESP8266, then as you can see on my project I've created a specific Class called Pins_NodeMCU, next I add some ESP8266 boards like Pins_Wemos_D1_R3, Pins_Wemos_D1_Mini and others and all uses MySerial class. Next I want to port it for Arduino + WiFi Shield and Arduino + Ethernet Shield, so I need to create a different class for Arduino and i think is useful to create it with another MySerial, I just import it in Arduino class because the serial class is same for ESP and Arduino.

On ESP and Arduino side I need to prepare one sketch to upload on microcontroller. I think this is not a problem, I've managed UDP protocol.

If you (and any user) like ESP8266, I've already created an ESP8266 library capable to use any Android or Desktop device like a graphic LCD over WiFi in a local and public network, so in B4A and B4J side I've created an app that wait UDP data and write on Canvas, and others, this works like a charm, i can send up 1000+ commands every second on local network and over Internet.

I've wrapped around entire Canvas class, tts class, sensor class and others. The ESP can draw points, lines, rectangles, text, images (from SD or HD) read all Android sensors, can even create a CSV file on remote Android SD or Desktop HD and write around 100+ times every second, it open file, write as append mode and close file every time.

ESP can draw some controls and has freeback on it, example draw some buttons and if I press any, ESP know what button I've pressed and it's state, draw some sliders and if i move any, ESP know what slider I've moved and it's value.

Any control is resizable and is ESP that draw it on remote device. The transfer even over Internet is device to device, no any server involved, so we have very low latency, around only ping time.

This is a simple example on Arduino IDE, on remote side just need to launch the VirtualDisplay app:
B4X:
#include <ESP8266WiFi.h>
#include <WiFiUDP.h>
#include <ESP8266VirtualDisplay.h>

ESP8266VirtualDisplay tft = ESP8266VirtualDisplay("YourSSID","YourPASS");

tft.begin(8889, IPAddress(192, 168, 0, 20), 8888); // initializes UDP

tft.setRotation(PORTRAIT);
tft.cls(BLACK);
tft.drawPixel(50, 50, GREEN);
tft.drawLine(300, 175, 600, 175, RED, 1);
tft.drawRect(300, 275, 50, 50, YELLOW, false, 1);
tft.drawRectRotated(300, 475, 50, 50, ARGB(128,45,50,80), false, 1, 45);
tft.drawCircle(500, 675, 10, RGB(80,80,80), false, 1);
tft.drawText("Hello", tft.percentX(50), tft.percentY(35), TYPE_BOLD, 30, BLUE, ALIGN_CENTER);

I explained this because next I want to convert this library (that required 1 age of work) to B4R library, so using B4A, B4J, B4R integration is complete.
 
Last edited:
Upvote 0
Top