Category Archives: Tutorial

B4A + B4J: Profile your apps ‘live’ with ABMonitor

ABMonitor2

It has been some time since I could give my donators a new goodie;), and this time it is a library/tool to profile and monitor your B4J + B4A (7.01+) apps (not limited to ABMaterial WebApps!) I’ve been needing something like this for some time for my own projects, but couldn’t find one that suited me.  This can be a very good asset to find Memory Leaks or to track which method takes up to much time.

Using a very simple API, you can track how long the code execution time is, the times hit, average time, memory usage etc for any block of code you want to investigate.  I deliberately gave you this API freedom, as profiling ALL your code (as most programming languages do) is just drowning you in to much information so you don’t see the wood for the trees anymore.

QUICK NOTE: Do not forget to set your DONATORKEY and the port in the Viewer params.txt . The same port and the IP of your Viewer have to be used in the apps you are monitoring!

How it works:
ABMonitor uses the Jamon library, which has a extremely low overhead on your code. Just by disabling it (using the SetActive method), you can actually leave it in your production apps if you want (or use B4Js conditional compiling if you want to get rid of it all together in a production app).

ABMonitor consists of two main parts:
1. The ‘live’ ABMonitor Viewer.

Instructions: Simply start the Viewer in a command prompt using: java -jar ABMonitor.jar

This Viewer shows all the stuff you are monitoring with the API. It shows e.g. how many times some part of your code was hit, how long it took, what the average time was, when it was last accessed, memory consumption etc… It is presented in a TreeView Table, so you can check every detail (depending on how deep you’ve coded your profiling).  At the bottom, the last 50 runs are presented in some line charts.

Because the IDE of B4X is ‘live’, so is the Viewer! Thanks to this unique feature of the B4X products, you can update your code and see the results in the Viewer immediately.

Little side note: This ‘live’ IDE part is a little-known/promoted feature (except within the B4X community of course, as for us this is normal), but it has a HUGE advantage over any other tool out there.  In similar market aimed tools, like Xojo for example, you have to compile and re-compile every single time you make the smallest of changes to your code (on bigger projects it takes up to 20 minutes, some users reported). In B4X, just change the code, and continue running.  Not happy with it? Change it again and see what gives. BIG production time-saver! Some of you who used to program in VB6 know what I mean…

2. The ABMonitorB4X libraries (ABMonitorB4A.jar/ABMonitorB4J.jar).

Install instructions: Copy the xml and jars (dont’t forget jamon-2.81.jar), to your B4A or B4J libraries folder. In the IDE select the ABMonitorB4X library, the RandomAccessFile library and the Network library.

This API connects your own apps with the monitor. It basically consists of a Start and a Stop method.

First, we have to make the connection with the Viewer. Thanks to Erels new Resumable Subs, doing this is a breeze:

In Main make some declarations:

Sub Process_Globals
   Public Monitor As ABMonitor

   Private port As Int = 10090 ' <-- Set your Viewers Port!
   Private ip As String = "127.0.0.1" ' <-- Set your Viewers IP!
   Private abmonitor As AsyncStreams
   Private client As Socket

   ' Useful to quickly activate/deactivate the monitoring
   Public TRACKMONITOR As Boolean = True
End Sub

Next add the following resumable sub:

Sub ConnectMonitor()
   Dim c As Socket
   c.Initialize("client")
   c.Connect(ip, port, 5000)
   Wait For Client_Connected (Successful As Boolean)
   If Successful Then
     client = c
     abmonitor.InitializePrefix(client.InputStream, False, client.OutputStream, "abmonitor")
     Log("ABMonitor connected")
     Monitor.SetActive("Template", True,abmonitor, 5)
   Else
     Log("ABMonitor disconnected")
   End If
End Sub

Sub abmonitor_Error
   Monitor.SetActive("Template", False,Null, 0)
   Log("ABMonitor disconnected")
End Sub

You can set the interval the data should be send to the Viewer, in seconds, with the last parameter in ‘Monitor.SetActive(“Template”, True,abmonitor, 5)’.  In this example, it is every 5 seconds.  Note: This does not mean it is tracked every 5 seconds! The library will continue tracking everything, but it will only send all the info over to the Viewer every 5 seconds.

Finally, Initialize the monitor and call the resumable sub when your app starts (a good place is e.g. before StartMessageLoop in a Server app):

...
Monitor.Initialize("YOURDONATORKEY")

ConnectMonitor

StartMessageLoop

Ready to do some monitoring!

As I said, there are basically only two commands: Start and Stop.

There are two ways to monitor/profile your code (you can mix the use of them):

a. Monitor some code:
You want to monitor a query, or a whole sub, … In general this is a complete block of code.

Good practice is using the class/module name as the Group parameter, and the method name as the Label, but you can put whatever you want. This will later be used in the Viewer to group stuff. (Group and Label are the first and second parameters in the calls).

Example:

Private Sub WebSocket_Connected (WebSocket1 As WebSocket)
   If Main.TRACKMONITOR Then Main.Monitor.Start("ABMPageTemplate", "WebSocket_Connected", "")

   '   ... the code you want to monitor

   If Main.TRACKMONITOR Then Main.Monitor.Stop("ABMPageTemplate", "WebSocket_Connected", "")
End Sub

Or tracking a query:

..
If Main.TRACKMONITOR Then Main.Monitor.Start("ABMPageTemplate", "MySlowQuery", "")

Dim SQL_str As String
SQL_str = "SELECT cases.CaseID, cases.CaseUserID, cases.CaseType, cases.CaseSummary FROM tCases WHERE cases.CaseStatus=1;"
Dim cases As List = DBM.SQLSelect(SQL, SQL_str, Null)

If Main.TRACKMONITOR Then Main.Monitor.Stop("ABMPageTemplate", "MySlowQuery", "")
...

b. Monitor methods which are used in multiple places, and you want to know where it was called.
You have for example a page.Refresh method, which is called in multiple places. You can use the third parameter to set the ‘caller’. In general there will only be one line of code between the start() and stop().

This caller will later be used in the Viewer to build a call tree (or stack trace)

Example:

Private Sub WebSocket_Connected (WebSocket1 As WebSocket)
     ...
     If Main.TRACKMONITOR Then Main.Monitor.Start("ABMPageTemplate", "page.Refresh", "WebSocket_Connected")
     page.Refresh
     If Main.TRACKMONITOR Then Main.Monitor.Stop("ABMPageTemplate", "page.Refresh", "WebSocket_Connected")
     ...
End Sub

public Sub ConnectPage()
   ...
   ' refresh the page
   If Main.TRACKMONITOR Then Main.Monitor.Start("ABMPageTemplate", "page.Refresh", "ConnectPage")
   page.Refresh
   If Main.TRACKMONITOR Then Main.Monitor.Stop("ABMPageTemplate", "page.Refresh", "ConnectPage")
   ...
End Sub

As you can see, you are totally free to monitor anything you want.

Call for action: if anyone out there is a guru in making B4i libraries, please PM me!  The java library code is quite simple and it shouldn’t be to hard for an experienced B4i library coder to write one which can connect to the same Viewer.  If we got this one too, then we’ve covered all major platforms in B4X!

ABMonitor is part of a multi-pack on libraries, frameworks and tools all Donators to this blog receive.

Included are currently:

ABMaterial (B4J) A very powerful framework combining a tuned Materialize CSS with the free programming tool B4J. It allows creating Web Apps that not only look great thanks to Googles Material Design, but can be programmed with the powerful free tool from Anywhere Software without having to write a single line of HTML, CSS or Javascript code!

ABExchange (B4J) It can be used to sync the ABMCalendar control with your exchange server and outlook. It can also send a mail.

ABJasperReports (B4J) his is a little library that allows you to export reports created in Jasper Reports in your B4J applications. They can be exported to pdf, html and xls. You can use parameters defined in JasperReports.

ABPDFBox (B4J) With this library you can print PDF files (either by showing a dialogbox or directly to a specified printer). Works in UI and NON-UI apps.

ABMonitor (B4J + B4A) Tool to monitor/profile your B4A (7.01+) and B4J code! Includes the libraries for both platform + the ABMonitor Viewer. See the tutorial for more info.

ABCron (B4J + B4A) A more advanced timer library that can schedule more intelligently tasks using Cron expressions. You can also set a start and end datetime. I’ve added a method RestartApplicationNONUI() that should restart you .jar file when the Cron expression is met.

ABEvaluator (B4J + B4A) Evaluate mathematical expressions. You can also write your own functions in B4J/B4A.

ABPlugin (B4J) Create Live plugins for you own apps. This means you can create plugins that can be added/removed while your app is running. Note it is a little experiment that shows the power of B4J. The ‘compile to library’ feature of B4J is very handy to create plugins.

ABZXCVBN (B4J + B4A) Realistic password strength estimation.

ABTreeTableView (B4J) Custom B4J component which combines a TreeView with a TableView.

Until next time!

Alwaysbusy

Click here to Donation and support ABMaterial


B4J: New in ABMaterial 3.50: Drag and Drop about anything

ABMDragDrop

It may have been a bit silent the last few weeks around ABMaterial, but behind the scenes I have been working nights and weekends on maybe the biggest new feature since Chipmunk was introduced: Drag & Drop!

In 3.50, it will be possible to drag ABMContainers (and hence about anything in it) from one cell to another.

Let’s watch a video demonstration first:

Pretty cool hè!

How it works in B4J:
I explain the basics here, the DragDrop demo project included in the ABMaterial 3.50 download will show all tricks shown in the demo video.

1. Page_ParseEvent() gets a little bit of extra code to sync the moves made in the browser with our server

...
If SubExists(Me, eventName) Then
     Params.Remove("eventname")
     Params.Remove("eventparams")
     ' BEGIN NEW DRAGDROP
     If eventName = "page_dropped" Then
       page.ProcessDroppedEvent(Params)
     End If
     ' END NEW DRAGDROP
     Select Case Params.Size
     ...

2. Next we define a ‘DRAG’ group:

' name, minimum height of a cell
page.DragDropCreateGroup("DRAG", 150)

3. We add cells to this ‘DRAG’ group we want to drag & drop between. The last ‘null’ parameter can be any ABMComponent you want to use a title of the cell (e.g. the COLUMN X ABMLabel in the demo).

page.DragDropAddZone("DRAG", "DRAGCELL1", page.Cell(3,1),null)
page.DragDropAddZone("DRAG", "DRAGCELL2", page.Cell(3,2),null)
page.DragDropAddZone("DRAG", "DRAGCELL3", page.Cell(3,3),null)

4. We add our draggable ABMContainers to the cells. Note: they MUST be added with AddArrayComponent!

Here we also enable them to be draggable with cont.EnableDragDropZone().  There is also a shortcut method to enable/disable all ‘Zones/Cells’ in a group with cont.EnableDragDropAllZonesFromGroup() in one go.

page.Cell(3,1).AddArrayComponent(CreateCard("1", True, True, True, "I may be dragged everywhere", "../images/list1.jpg"), "Cards")
...

Sub CreateCard(ID As String, AllowInCell1 As Boolean, AllowInCell2 As Boolean, AllowInCell3 As Boolean, Title As String, image As String) As ABMContainer
  Dim cont As ABMContainer
  cont.Initialize(page, ID, "")
  cont.AddRows(1,True,"").AddCells12(1, "")
  cont.BuildGrid

  cont.IsTextSelectable = False

  If AllowInCell1 Then
    ' can be dragged to zone 1 of 'DRAG'
    cont.EnableDragDropZone("DRAG","DRAGCELL1",True)
  End If
  If AllowInCell2 Then
    ' can be dragged to zone 2 of 'DRAG'
    cont.EnableDragDropZone("DRAG","DRAGCELL2",True)
  End If
  If AllowInCell3 Then
    ' can be dragged to zone 3 of 'DRAG'
    cont.EnableDragDropZone("DRAG","DRAGCELL3",True)
  End If
  cont.EnableDragDropZone("DRAG","DRAGCELL4",True) ' for the sidebar

  Dim card As ABMCard
  card.InitializeAsCard(page, "card", "MY CARD", Title, ABM.CARD_SMALL, "")
  card.Image = image
  card.AddAction("Press me")

  ' add the card to the page
  cont.Cell(1,1).AddComponent(card)
  Return cont
End Sub

5. There are three events you will receive (all on Page level):

Sub Page_DragStart(component As String, source As String)
  Log("Drag start: " & component)
End Sub

Sub Page_DragCancelled(component As String, source As String)
  Log("Drag cancelled: " & component)
End Sub

' there are four parameters: component, source , target, before
Sub Page_Dropped(Params As Map)
  Log("Dropped: " & Params.Get("component"))
End Sub

And this is basically it! Very simple without having to write any HTML, CSS, PHP or Javascript. All done in pure B4J!

I’m finishing up ABMaterial 3.50, ABMonitor (an upcoming article on this for B4J and B4A soon on the blog) and ABTreeTableView now and early next week I think I may be able to release it to the donators.

Cheers,

Alwaysbusy

Click here to Donation and support ABMaterial


B4J: New section and page navigation feature in ABMaterial (3.02)

PageNav2

ABMaterial 3.02 Maintenance Release will have a new feature, especially useful for ‘one page’ apps/websites to navigate. It intruduces ‘sections‘ within a page. A section is a logical grouping of rows, which can have its own background and a new extra navigation method/menu.

Sections must be declared at the BuildPage() stage, and are typically created right after the page.BuildGrid() method.

First, let me show you how it works and then I’ll explain how this is archieved with just 12 lines of B4J code!

Video:

Code (creating the Theme):

theme.Page.AddSection("section1", ABM.COLOR_BLACK, "", ABM.COLOR_WHITE, "")
theme.Page.AddSection("section2", ABM.COLOR_BLACK, "", ABM.COLOR_BROWN, ABM.INTENSITY_LIGHTEN4)
theme.Page.AddSection("section3", ABM.COLOR_WHITE, "", ABM.COLOR_BLUE, ABM.INTENSITY_LIGHTEN3)
theme.Page.AddSection("section4", ABM.COLOR_WHITE, "", ABM.COLOR_GREY, ABM.INTENSITY_DARKEN3)

Code (Adding the sections & the navigation)

page.CreateSection("section1", 1,1,ABM.COLOR_WHITE, "", "", "", "","calc(100vh - 56px)", 56, 500, ABM.VISIBILITY_ALL,"Section1")
page.SetSectionNavigation("section1", "section2", "Go to Section 2", ABM.SECTION_BUTTONTYPE_DOWN, "section1", "Section 1" )
page.CreateSection("section2", 2,2,ABM.COLOR_GREEN, "", "../images/bg-1.jpg", ABM.CONTAINERIMAGE_REPEAT_NOREPEAT, ABM.CONTAINERIMAGE_POSITION_COVER, "calc(100vh - 56px)", 56, 500, ABM.VISIBILITY_ALL, "Section2")
page.SetSectionNavigation("section2", "section3", "Go to Section 3", ABM.SECTION_BUTTONTYPE_DOWN, "section2", "Section 2")
page.CreateSection("section3", 3,3,ABM.COLOR_BLUE, "", "", "", "", "calc(100vh - 56px)", 56, 500, ABM.VISIBILITY_ALL,"Section3")
page.SetSectionNavigation("section3", "section4", "Go to Section 4", ABM.SECTION_BUTTONTYPE_DOWN, "section3", "Section 3")
page.CreateSection("section4", 4,4,ABM.COLOR_BLACK, "", "", "", "", "calc(100vh - 56px)", 56, 500, ABM.VISIBILITY_ALL, "Section4")
page.SetSectionNavigation("section4", "section1", "Back to Section 1", ABM.SECTION_BUTTONTYPE_UP, "section4", "Section 4")

In this example each section has only a height of 1 row (hence the from row 1 to row 1, from row 2 to row 2,…)

But, this can be any size, e.g. from row 5 to row 25. Something like:

page.CreateSection("section5", 5,25,ABM.COLOR_BLACK, "", "", "", "", "calc(100vh - 56px)", 56, 500, ABM.VISIBILITY_ALL, "Section4")

NOTE: Sections cannot be nested or overlapping!

The tricky part are the minHeight and scrollTop params. In the above examples, I’ve set the minHeight to the browsers height, minus the height of the TopBar: “calc(100vh – 56px)”.
For scrollTop, I’ve set it the the height of the TopBar so the top of the section is right under the navigation bar: 56

ABMaterial 3.02 Maintenance Release will go out in acouple of days to the donators with 25 bug fixes and implemented wishes!

Alwaysbusy

Click here to Donation and get the latest ABMaterial first!


B4J: ABMaterial Facebook-like timeline in less than 200 lines!

ABMFacebook50

I recently had a question if it was possible to create a Facebook-like WebApp with ABMaterial for B4J. I had some time to spare tonight (yeah right):rolleyes: and decided to give it a go…

All I needed were a couple of ABMContainers and the new CloseContent/OpenContent feature introduced in 3.02. The existing NextContent system would provide the infinite page.

It also uses a ABMCustomComponent for the ‘Like’ feature (I based it on this project), and you can find the source code of the class under the video:

About an hour, and 200 lines of B4J code later, I had a working timeline!  A real project would of course need some way to add an article, save them in the database, user management, etc but this is out of scope of this article.

Note: This example will be included in the upcoming 3.02 Maintenance Update, but I would like to share the source source code for the ‘Like’ functionality beforehand.

Source code for the ‘Like’ custom component.
You’ll need this zip file for the images and js/css files. Put the images and css in the /www/css/custom folder, the js file in the /www/js/custom/ folder.

The class LikeComponent:

'Class module
Sub Class_Globals
   Public ABMComp As ABMCustomComponent
   Public Counter As Int
End Sub

'Initializes the object. Countries and data are Json Strings
Public Sub Initialize(InternalPage As ABMPage, ID As String, AlreadyLiked As Int)
   ABMComp.Initialize("ABMComp", Me, InternalPage, ID)
   Counter = AlreadyLiked
End Sub

Sub ABMComp_Build(internalID As String) As String
   Return $"
<div id="${internalID} class="facebook-reaction"><!-- container div for reaction system -->
        <span class="like-btn"> <!-- Default like button -->
          <span class="like-btn-emo like-btn-default"></span> <!-- Default like button emotion-->
           <span class="like-btn-text">Like</span> <!-- Default like button text,(Like, wow, sad..) default:Like  -->
<ul class="reactions-box"> <!-- Reaction buttons container-->
	<li class="reaction reaction-like" data-reaction="Like"></li>
	<li class="reaction reaction-love" data-reaction="Love"></li>
	<li class="reaction reaction-haha" data-reaction="HaHa"></li>
	<li class="reaction reaction-wow" data-reaction="Wow"></li>
	<li class="reaction reaction-sad" data-reaction="Sad"></li>
	<li class="reaction reaction-angry" data-reaction="Angry"></li>
</ul>
</span>
<div class="like-stat"> <!-- Like statistic container-->
           <span class="like-emo"> <!-- like emotions container -->
             <span class="like-btn-like"></span> <!-- given emotions like, wow, sad (default:Like) -->
           </span>
           <span class="like-details">${Counter} others</span></div>
</div>
"$
End Sub

Sub ABMComp_FirstRun(InternalPage As ABMPage, internalID As String)
   Dim script As String = $"$("#${internalID} .reaction").on("click",function(){  // like click
     var data_reaction = $(this).attr("data-reaction");
     $("#${internalID} .like-details").html("You and ${Counter} others");
     $("#${internalID} .like-btn-emo").removeClass().addClass('like-btn-emo').addClass('like-btn-'+data_reaction.toLowerCase());
     $("#${internalID} .like-btn-text").text(data_reaction).removeClass().addClass('like-btn-text').addClass('like-btn-text-'+data_reaction.toLowerCase()).addClass("active");;

     if(data_reaction == "Like") {
         $("#${internalID} .like-emo").html('<span class="like-btn-like"></span>');
     } else {
         $("#${internalID} .like-emo").html('<span class="like-btn-like"></span><span class="like-btn-'+data_reaction.toLowerCase()+'"></span>');
     }
     var json = {'target': '${internalID}', 'like': data_reaction};
     b4j_raiseEvent('likecomponent_liked', json);
     });    

     $("#${internalID} .like-btn-text").on("click",function(){ // undo like click
     if($(this).hasClass("active")){
       $("#${internalID} .like-btn-text").text("Like").removeClass().addClass('like-btn-text');
       $("#${internalID} .like-btn-emo").removeClass().addClass('like-btn-emo').addClass("like-btn-default");
       $("#${internalID} .like-emo").html('<span class="like-btn-like"></span>');
       $("#${internalID} .like-details").html("${Counter} others");
       var json = {'target':'${internalID}'};
         b4j_raiseEvent('likecomponent_unliked', json);
       }
     })"$

   InternalPage.ws.Eval(script, Array As Object(ABMComp.ID))
   ' flush not needed, it's done in the refresh method in the lib
End Sub

Sub ABMComp_Refresh(InternalPage As ABMPage, internalID As String)

End Sub

' do the stuff needed when the object is removed
Sub ABMComp_CleanUp(InternalPage As ABMPage, internalID As String)

End Sub

Usage:

Sub Class_Globals
   ...
   Dim myLike As LikeComponent
   ...
End Sub

' adding the component
myLike.initialize(page, ID & "Like", Rnd(20, 500))
myContainer.Cell(4,1).AddComponent(myLike.ABMComp)

Events (the name LikeComponent is set in the FirstRun() method of the class:

public Sub LikeComponent_Liked(value As Map)
   Log(value.Get("like") & " ----> " & value.Get("target"))
End Sub

public Sub LikeComponent_UnLiked(value As Map)
   Log("Unliked ----> " & value.Get("target"))
End Sub

Et voila,  a nice little demonstration of what you can make using B4J and ABMaterial.

I’ll end with a little word of advice:

If you only plan to learn one programming language this year, B4X is definitely the one you should pick!  With ABMaterial, I give you the power to write responsive, professional WebApps, and with the other B4X tools you write native Android, iOS, Desktop (Mac, Windows, Linux), Raspberry Pi and Arduino apps.  All with the same language!  You’ll wonder why you ever bothered looking at all those other pricy programming tools out there…

Happy programming!

Alwaysbusy

Click here to Donation and get the latest ABMaterial first!


B4A: ABFlicB4A library for Flic buttons

cute-as-a-button-1

You probably have seen these nifty little IoT Flic buttons around. They are a fun and relative cheap BLE button that allows you to do something when the button is clicked, doubleclicked or hold.

I decided to write a wrapper for the Android SDK to use with B4A.

How to use:
1. Install the Flic app from the Google Play.
2. On their developer page, create a new app: you get a key and a secret.
3. Copy the ABFlicB4A library jar and xml to your library folder and select it in B4A

Here is a small video demonstrating the library.  You can the use the full power of B4A to do about, well, everything…

Example usage code:

Sub Process_Globals

End Sub

Sub Globals
   Private flic As ABFlic
   Private Button2 As Button
   Private Button3 As Button
   Private Button4 As Button
   Private Label1 As Label
   Private Button1 As Button

   Private MyFlicID As String

   Private FlicResults As List
End Sub

Sub Activity_Create(FirstTime As Boolean)
   Activity.LoadLayout("1")
   FlicResults.Initialize
   FlicResults.Add("RESULTACTION_HOLD")
   FlicResults.Add("RESULTACTION_SINGLECLICK")
   FlicResults.Add("RESULTACTION_DOUBLECLICK")
End Sub

Sub Activity_Resume
   ' your key and secret
   flic.Initialize("Flic", "d60d36a0-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", "db5c2b3d-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", "ABFlicTest")
End Sub

Sub Button1_Click
   flic.ForgetButton(MyFlicID)
End Sub

Sub Button2_Click
   flic.GrabButton
End Sub

Sub Button3_Click
   flic.StartListening
End Sub

Sub Button4_Click
   flic.StopListening
End Sub

Sub flic_Added(buttonID As String, Name As String)
   MyFlicID = buttonID
   Log("Added: " & buttonID)
   Label1.Text = "Added: " & buttonID & CRLF & Label1.Text
End Sub

Sub flic_Clicked(buttonID As String, wasQueued As Boolean, timeDiff As Int)
   MyFlicID = buttonID
   Log("Clicked: " & buttonID)
   Label1.Text = "Clicked: " & buttonID & CRLF & Label1.Text
End Sub

Sub flic_DoubleClicked(buttonID As String, wasQueued As Boolean, timeDiff As Int)
   MyFlicID = buttonID
   Log("DoubleClicked: " & buttonID)
   Label1.Text = "DoubleClicked: " & buttonID & CRLF & Label1.Text
End Sub

Sub flic_Holded(buttonID As String, wasQueued As Boolean, timeDiff As Int)
   MyFlicID = buttonID
   Log("Holded: " & buttonID)
   Label1.Text = "Holded: " & buttonID & CRLF & Label1.Text
End Sub

Sub flic_Removed(buttonID As String)
   MyFlicID = ""
   Log("Removed: " & buttonID)
   Label1.Text = "Removed: " & buttonID & CRLF & Label1.Text
End Sub

Sub flic_Error(err As Int)
   Log("Error: " & err)
   Label1.Text = "Error: " & err & CRLF & Label1.Text
End Sub

I’m currently working on a Desktop/Raspberry Pi version of this library, which I will share in the B4J forum later.

The library can be found at the B4A forum.

Happy programming!

Alwaysbusy


B4J:Programming LEGO Mindstorms EV3

b4lego

I was wondering if it would be possible to use B4J to program the Lego Mindstorms EV3 Brick for some time. So, some weeks ago, I finally spend a couple of evenings looking into it. And yes, B4J goes Robotics! It uses a modified LeJOS Firmware.

I upgraded LeJOS to support Java 1.8, which is probably the most technical part of the project.  I cannot provide it here, as it depends on your Java version but if you follow the next steps, you can build your own.  This is done on a Windows PC:


Upgrading the LeJOS Firmware to use Java 1.8

The following procedure will install the java 8 environment compatible with leJOS 9.0 from windows 7. The only extra tool needed is 7ZIP (a free tool) which can generate tar and gz format.  In the following I use a temporary directoyr as F:\temp. Replace it with your own temp directory wherever it appears.

  1. Go to java site http://www.oracle.com/technetwork/java/ … 82511.html
  2. Create an account if you dont have one then Accept Licensee agreement and download ejdk-8-xxxxxxx-linux-arm-sflt-xxxxxxxx.tar.gz or the latest java8 jre for EV3.
  3. Unzip this file in your F:\temp directory. For simpler process you may rename the extracted directory  as ejdk8. Run 7zip as administrator!
  4. Go to directory ejdk8\ejdk1.8.0\bin. Save the file jrecreate.bat. Now right click on jrecreate.bat and select “modify”.  Add one first line to the bat file as SET JAVA_HOME=C:\Progra~2\Java\jdk1.8.xxxx.  this is where java8 is installed on my system. Program~2 stand for Program Files (x86) but is easier to type.
  5. Start a command window: Start->All prog->Accessory->commands.
  6. In this window type in the following commands
    F:
    cd temp
    cd ejdk8\ejdk1.8.0\bin
    jrecreate.bat –dest newjre –profile compact2 –vm clientIt should start creating the new jre files in the directory “newjre” under ejdk8\ejdk1.8.0\bin
    Wait for the final message.
    Close the command window.
  7. With file explorer go to F:\temp\ejdk8\ejdk1.8.0\bin. Copy “newjre” directory back to F:\temp
  8. Rename the “newjre” directory as something expected by LeJOS such as
    ejre-8-b132-linux-arm-sflt
  9. Right click on it. Open with 7ZIP and add to archive. Select tar format. It will create ejre-8-b132-linux-arm-sflt.tar file.
  10. Right click on tar copy then add archive with gzip format. It will create ejre-8-b132-linux-arm-sflt.tar.gz. You have created the JRE file for java8 expected by EV3.
  11. Insert your SD card and format it.
  12. Copy the ejre-8-b132-linux-arm-sflt.tar.gz under the sd card top directory.
  13. Go to C:\Program Files\leJOS EV3
  14. Now remove the SD from PV and insert the card into the EV3 brick then power it. Wait for the end of the install (about 10mn).

If anything goes wrong, format again the SD, empty the F:\temp directory and restart at step 3.  if it persist try another SD card.

Your brick is ready!


Next I wrote a B4J wrapper for the basics like motors, sensors etc. This project is just a hobby and may grow in the future. But I just wanted to share this first video (badly directed so no Oscars here, unless…)

Obviously, I wanted to test out my code, but I had to build a bot first.  Well, I was in for a surprise! It took me over 3 hours to build EV3D4 and I can tell you, I’m not a very patient person so I may have taken some shortcuts in the construction.

What happens in the video:
1. I uploaded the B4J created .jar file to the brick via ssh and I’m ready to start it.
2. After some time, it runs (on the brick shows a disclamer and waits for a key).
3. I disconnect the brick, put it on the ground and press a button on the brick.
4. I programmed the IR sensor so if it sees a wall, it turns away, else it keeps going.

Fun fact is you can use B4J-Bridge.jar on the brick!

This is handy as debugging a Brick is a b*tch. You must have a lot of patience and prepared to restart your brick A LOT. This is not a B4J limitation, just to say how unstable programming a Brick is in general.

Coding is straightforward in B4J (this is all the code I wrote, including turning if it is about to hit a wall):

Sub Process_Globals
   Private StartTimer As Timer
   Public EV3 As ABLegoEV3
   Public LeftMotor As ABLLargeRegulatedMotor
   Public RightMotor As ABLLargeRegulatedMotor
   Public Sensor As ABLIRSensor
   Public sp As ABLSensorMode

   Public control As Int = 0
   Public distance As Int = 255
End Sub

Sub AppStart (Args() As String)
   LeftMotor.Initialize("B")
   RightMotor.Initialize("C")

   LeftMotor.ResetTachoCount
   RightMotor.resetTachoCount
   LeftMotor.rotateTo(0)
   RightMotor.rotateTo(0)
   LeftMotor.Speed = 400
   RightMotor.Speed = 400
   LeftMotor.Acceleration = 800
   RightMotor.Acceleration = 800

   Log("starting sensor")
   Sensor.Initialize("S4")
   sp = Sensor.DistanceMode 

   IntroMessage

   StartTimer.Initialize("StartTimer", 100)
   StartTimer.Enabled = True
   StartMessageLoop
End Sub

Sub StartTimer_Tick
   ' read the sensor
   Dim sample(sp.sampleSize) As Float
   control = Sensor.getRemoteCommand(0)
   sp.fetchSample(sample, 0)
   distance = sample(0)
   Log("Control: " & control & " Distance: " & distance) 

   If distance < 70 Then
     Log("A wall!")
     EV3.Button.LEDPattern(2)

     LeftMotor.rotate2(-180, True) ' start Motor.B rotating backward
     RightMotor.rotate(-180)  ' rotate C farther To make the turn
     If Bit.And(DateTime.Now, 1) <> 0 Then
         LeftMotor.rotate2(-180, True) ' start Motor.B rotating backward
         RightMotor.rotate(180)  ' rotate C farther To make the turn
     Else
         RightMotor.rotate2(-180, True) ' start Motor.B rotating backward
         LeftMotor.rotate(180) ' rotate C farther To make the turn
     End If
  Else
     Log("Let's walk")
     EV3.Button.LEDPattern(1)

     LeftMotor.Speed = 400
     RightMotor.Speed = 400
     LeftMotor.Backward ' my motors are installed inverted on this robot
     RightMotor.Backward
  End If
End Sub

Sub IntroMessage()
   Dim g As ABLGraphicsLCD = EV3.GraphicsLCD
   g.clear
   g.drawString("Bumper Car Demo", 5, 0, 0)
   g.Font = g.Font.SmallFont
   g.drawString("Demonstration of the Behavior", 2, 20, 0)
   g.drawString("subsumption classes. Requires", 2, 30, 0)
   g.drawString("a wheeled vehicle with two", 2, 40, 0)
   g.drawString("independently controlled", 2, 50, 0)
   g.drawString("motors connected to motor", 2, 60, 0)
   g.drawString("ports B and C, and an", 2, 70, 0)
   g.drawString("infrared sensor connected", 2, 80, 0)
   g.drawString("to port 4.", 2, 90, 0)

   ' Quit GUI button:
   g.Font = g.Font.SmallFont
   Dim y_quit As Int = 100
   Dim width_quit As Int = 45
   Dim height_quit As Int = width_quit/2
   Dim arc_diam As Int = 6
   g.drawString("QUIT", 9, y_quit+7, 0)
   g.drawLine(0, y_quit,  45, y_quit) ' top line
   g.drawLine(0, y_quit,  0, y_quit+height_quit-arc_diam/2) ' left line
   g.drawLine(width_quit, y_quit,  width_quit, y_quit+height_quit/2) ' right line
   g.drawLine(0+arc_diam/2, y_quit+height_quit,  width_quit-10, y_quit+height_quit) ' bottom line
   g.drawLine(width_quit-10, y_quit+height_quit, width_quit, y_quit+height_quit/2) ' diagonal
   g.drawArc(0, y_quit+height_quit-arc_diam, arc_diam, arc_diam, 180, 90)

   ' Enter GUI button:
   g.fillRect(width_quit+10, y_quit, height_quit, height_quit)
   g.drawString2("GO", width_quit+15, y_quit+7, 0,True)

   EV3.Button.WaitForAnyPress
   If (EV3.Button.ESCAPE.isDown()) Then
     ExitApplication2(0)
   End If
   g.clear
End Sub

As I said, this is just for fun. No idea how far this will go.  You can download the source code for the B4J library from my Github.

Cheers,

Alwaysbusy


B4J: Msgbox and Inputbox in ABMaterial 2.51

upload_2017-2-12_12-0-6Sometimes you just need to show a quick Msgbox or a single-field Inputbox to the user. In ABMaterial for B4J you have probably, just like me, already made a couple of modal sheets to do this.

But in 2.51 I’ve integrated the possibility for such cases just to do it in one line of code (like a normal msgbox/inputbox).

It replaces the default looking ‘alert’ box from JavaScript to a more modern looking box.  The SweetAlert2 library, which is build on the orginal SweetAlert one, has been extended for ABMaterial so you can ‘Theme’ about anything you want.

For example, to show the msgbox you see on top of this article, this is the code you need to write:

page.Msgbox("MSGBOX1", "This is a very simple msgbox", "Msgbox()", "OK", "")

Some more examples:

theme.AddMsgBoxTheme("image")
theme.MsgBox("image").ConfirmButtonColor = ABM.COLOR_GREEN
theme.MsgBox("image").CancelButtonColor = ABM.COLOR_RED
theme.MsgBox("image").SetImage("https://unsplash.it/400/200", 400, 200)
theme.MsgBox("image").BackColor = ABM.COLOR_BLUEGREY
theme.MsgBox("image").BackColorIntensity = ABM.INTENSITY_LIGHTEN5

page.Msgbox2("MSGBOX3", "This is an msgbox with an image using a {C:#00AA00}theme{/C}!", "Msgbox2() 2", "OK","CANCEL",True, ABM.MSGBOX_TYPE_WARNING, "image")

upload_2017-2-12_12-2-24

page.InputBox("INPUTBOX1", "This is an inputbox for text.","OK", "CANCEL", True, ABM.INPUTBOX_TYPE_QUESTION, ABM.INPUTBOX_QUESTIONTYPE_TEXT,"","Type some text...", "", "Please enter something!", "")

upload_2017-2-12_12-3-30

page.InputBox("INPUTBOX3", "This is an inputbox for a password.","OK", "CANCEL", True, ABM.INPUTBOX_TYPE_QUESTION, ABM.INPUTBOX_QUESTIONTYPE_PASSWORD,"","Type your password...", "", "Please enter a password", "")

upload_2017-2-12_12-3-43

page.InputBox("INPUTBOX6", "This is an inputbox with a radio selection.","OK", "CANCEL", True, ABM.INPUTBOX_TYPE_QUESTION, ABM.INPUTBOX_QUESTIONTYPE_RADIO,"#00ff00", "","{'#ff0000': 'Red','#00ff00': 'Green','#0000ff': 'Blue'}", "You must select a color", "")

upload_2017-2-12_12-4-43

page.InputBox("INPUTBOX7", "This is an inputbox with a checkbox.","OK", "CANCEL", True, ABM.INPUTBOX_TYPE_QUESTION, ABM.INPUTBOX_QUESTIONTYPE_CHECKBOX,"", "I agree with the terms and conditions","", "Please agree with the conditions", "")

upload_2017-2-12_12-5-51

Events:

Sub page_MsgboxResult(returnName As String, result As String)
   myToastId = myToastId + 1
   page.ShowToast("toast" & myToastId, "toastgreen", returnName & " " & result, 5000)
End Sub

Sub page_InputboxResult(returnName As String, result As String)
   myToastId = myToastId + 1
   page.ShowToast("toast" & myToastId, "toastred", returnName & " " & result, 5000)
End Sub

ABMaterial Mainenance Release 2.51 will be available for the donators in the following days.

Alwaysbusy

Click here to Donation and get the latest ABMaterial first!


%d bloggers like this: