Pages

Sunday, 25 March 2018

Overall Experience with D Language

The D language, more than anything, is addictive. Since embarking on D in December 2017, I have come to enjoy the language. There is no doubt that languages come and go, but for me, D will remain an important part of my programming tool sets.


To date, I have managed to achieve the following applications in D:
  • A REST server with MySQL backend (vibe.d)
  • A vibe.d based webserver with Diet templating
  • A SMTP based email sending script (CLI)
  • A PDF based report engine (CLI)

Developing all the above was as fun as programming in GoLang, Dart and even Lazarus Pascal. Incidentally, all these languages now command almost equal attention and most projects make use 2 of the languages. The language that has taken a bit of  knock is PHP - by all account D will gradually substitute PHP the codebase going forward.

Sofar all code has been developed targeting the Linux platform, in particular Ubuntu. However, some of the code is developed on Windows but compiled on Linux.

The initial challenges have been as follows:
  • Identifying a suitable IDE.
  • Figuring out the array of struct feature
  • Setting up Vibe-d environment
  • Finding information on the internet (The D Lang forums are a little difficult to follow)
  • Some unusually arcane if not painful language expressions, eg conversion of an integer to a string: to!string
Most of the coding was done in text editors. I have also made use of the Mono D plugin in the MonoDevelop IDE. Lately I am assessing the Coedit IDE (developed with object Pascal based Lazarus).

Learning D and understanding its strengths has not been always plain sailing. Having said that, the effort taken to solve any D related challenge end up being rewarding both in terms understanding its innards and as an indirect way to gain experience.
 

Friday, 29 December 2017

Making Time for the D Language

The D programming language has been an itch for a little while, to the best of my collection, it has been somewhat like for the last four years or so. Being an itch that was never properly remedied in the sense of programmatically exploring the language, it was time to put an effective scratch on the proverbial itch.

I must concede upfront that in terms of severity of an itch, the Rust language generated almost the same level of attention as D, however, after glancing through both written and video material on the internals of Rust, I determined that D would be a more appropriate programming environment to explore at this point.
With this understanding, this blog is really more about trying to understand the D Language from the perspective of someone who enjoys taking a language or two per year for a test spin.

My first impressions of D reminded me of how similar the language is to Object Pascal. Being a Go developer, I also noted some conceptual similarities in how certain features are implemented. My primary attraction to D was defined by what was being presented as relatively easy features to web application, database integration, email management as well as threading application development.

Installing the D environment on the Ubuntu 16.04 laptop was a breeze. D seems to have a couple of compiler applications, each optmised for specific application types - I limited my exploration to the DMD and DUB compilers for now. DUB, though seemingly a compiler, is really more of a package management application. I have used DUB to download and compile a vibe.d web test application environment. The same was also used for a mysql based back end test application.

I consider vibe.d as a pretty advanced and powerful web application framework. The small test application I developed suggests that I may in the future consider creating web backend applications in D. The DIET webpage templating concept was of particular interest.

The next step was to trial an application that communicates with a mysql server. This is where in my opinion similarities between D and Object Pascal come to an abrupt end. So far I managed to select only a single row whereas I am expecting more than a thousand. I need to put more effort and research in understanding the mysql-native package before I can make productive use of mysql integration.

In comparison to other languages I have taken for a spin, finding simple and easy to find examples seems to be a huge  challenge. As much as this is frustrating, I am careful not to cast doubt on the strength and relevance of the D language as part of my software development toolsets.

The next few weeks and possibly months will require a focused approach in learning some of the basics of the D language ecosystem - I like what I have experienced so far.

Wednesday, 30 November 2016

Coding in Go

In one of my previous posts I may have commented about Google's programming language called Go, also referred to as Golang. Its origins, evolution and historical background is very well documented in a number of website, so I will not spend to much effort on it in this post.

I became aware of Golang while I was learning to code in Google's other programming language cold Dart. Having primarily been a Pascal and PHP programmer, Golang's conspicuous C like syntax initially was a mild concern. Fortunately this concern was short-lived and generously offset by Golang's extensive list of features such as (to mention a few):
  • Cross-Platform compatibility.
  • Native support for concurrency paradigms.
  • Develop executables.
My taste for software development is inclined towards certain type of applications, each include some level of a relational database integration:
  • Web portals (60%)
  • Native Windows GUI (30%)
  • System administration scripts (10%)
Golang seems to fit very well for the first and last application types.  I have already developed a couple sample application, mainly for tutorial purposes and I must confess, the language is fun. Below is sample code that pings several IP addresses and displays the ping results in the command line window:

package main

import "os/exec"
import "strings"
import "time"
//import "log"
//import "errors"
import  "fmt"


func insertSection_TicketSummary() {
 // var mystr string
 //
 // mystr = ""
}

func pingHost(aHost string, aStatus chan bool) {
 var mystr string

 //fmt.Printf(" -->Pinging host with IP address: %s\n", aHost)

 output1, err := exec.Command("ping", "-n", "1", aHost).Output()

 if err != nil {
  //fmt.Printf("%s", err)
  }

 //fmt.Printf("%s\n", output1)
 mystr = string(output1)

 //fmt.Printf("%s\n", mystr)
 //i int

 i := strings.Index(mystr, "(0% loss)")

 if i > 0 {
  //fmt.Printf("%s\n", "Host is online")
  fmt.Println("-> Host " + aHost +" is online")
 } else {
  fmt.Println("-> Host " + aHost +" is offline")
 }

 aStatus <- true

 //time.Sleep(time.Second * 2)
}

func main() {
 t := time.Now().Local()

// fmt.Println(t)
 fmt.Println(t.Format("2006/01/02 15:04:05"))    // 31/12/2015 08:34:12

 //Create a new channel to follow excution status of goroutines:
 done := make (chan bool)

 // send two pings and send the ouput to STDOUT
 //Linux mode:
// output1, err := exec.Command("ping", "-c", "2", "8.8.8.8").Output()

 //Declare an array of hosts and associated ip addresses:
 hostsRouters := []string {"192.168.20.1",
       "192.168.21.1",
      "192.168.22.1"}

 hostsSwitches := []string {"192.168.20.3",
        "192.168.21.3",
                      "192.168.22.3"} 
 
 
        hostsPrinters := []string {"192.168.20.99",
              "192.168.21.99",
              "192.168.22.99"}
            "10.18.65.10"}

  hostsInternet := []string {"8.8.8.8"}

 //Quantify the number of nodes to be pinged:
 var nodeQty int
 nodeQty = len(hostsRouters)    +
    len(hostsSwitches)   +
    len(hostsPrinters)   +
    len(hostsInternet)

 //Windows mode:
 fmt.Println("Pinging MPLS WAN provincial routers:")
 for i := 0; i < len(hostsRouters); i++ {

  go pingHost(hostsRouters[i], done)
 }

 //var input string

 fmt.Println("Pinging MPLS WAN provincial switches:")
 for ps := 0; ps < len(hostsSwitches); ps++ {

  go pingHost(hostsSwitches[ps], done)
 }

 fmt.Println("Pinging MPLS WAN provincial MFP printers:")
 for pp := 0; pp < len(hostsPrinters); pp++ {

  go pingHost(hostsPrinters[pp], done)
 }

 fmt.Println("Pinging hosts internet:")
 for pi := 0; pi < len(hostsInternet); pi++ {

  go pingHost(hostsInternet[pi], done)
 }

 for fr := 0; fr < nodeQty; fr++ {
  <- done
 }

 //<- done

}
This simple code highlight  a few features of Golang (in no particular order):
  • date assignments.
  • array declaration.
  • for loop.
  • function declaration.
  • channel assignments.
  • go routines.
If you have never done any coding in Golang, I suggest you start right now and experiment for yourself the potential benefits of Google Go.

Sunday, 9 October 2016

Ubuntu Upgrade from 15.10 to 16.04

Almost three weeks ago, as per my previous post, I posted a blog on how I was prompted to upgrade the Ubuntu OS from 15.04 to 16.04. The decision then was upgrade based on the various dialogs that would pop up and basically suggest an upgrade.

Unfortunately, the upgrade process never executed as I had expected - there was simply little to no action on the screen.I never had an opportunity to determine the root cause of the problem.

So, today I thought it was time again I resolved this upgrade issue. To ensure there was some level of success in doing so, I googled for some references on the internet. The link below seemed to be simple, straight forward and lightweight: http://www.tecmint.com/upgrade-ubuntu-15-10-to-ubuntu-16-04/

In summary, I followed all the steps and ended up with an upgraded laptop:


Regrettably I did not time the entire operation, suffice to mention that for internet connectivity I was using a wifi connection from an LTE router in LTE mode. The process was not too shabby time wise and effectively was smooth.

Upon completion I had a fully upgraded system as diaplayed below:




I do not foresee upgrading in the near future. Needless to say, I did not mention the merits of the new upgrade, I think there is enough material on the internet to refer to.  On that note, now I will enjoy the the new OS and experiment with some of its new features.

Saturday, 17 September 2016

Ubuntu OS Upgrade Message (15.10 to 16.04)

After an unusually long period of me visiting my study room, I decided today that it was time again to do find something worthwhile to do. Probably continue developing outstanding software code on existing projects. Alternatively I could also consider learning new programming concepts in Google Dart or Google Go.

I flipped open my beloved Lenovo powered laptop, connected the power adaptor cord, pressed the circular on/off button to switch it on and voila - there was the much accustomed, mundane but functional, Ubuntu OS trademark desktop on the screen. Up to this point I will admit that the outcome was pretty predictable.

Then suddenly I noticed an unusual icon in the top right notification bar. The icon was unusual both in terms of its colour and the symbol it portrayed. The icon is very similar to a breakpad alarm light in the dashboard off modern cars. Not being someone who panics easily, I decided to move the mouse cursor to the offending icon and determine what is going on here. Upon placing the cursor on the icon, I expected a hint message to offer some basic information about any alarming condition the Ubuntu may have picked up during the boot up process of the laptop.

To my disappointment, there was no hint message emerging. Naturally. but carefully I then decided to click on the icon and a dialog like object appeared with some lengthy message as depicted below:




Thereafter I clicked on "Show updates" and received another dialog appeared:



Evidently, this dialog has a very limited set of options. It was time to upgrade the current Ubuntu OS version from 15.10 to 16.04 LTS, so I did the honourable and prepared my self for a new OS environment.

Believe it or not, all the aforementioned experience prompted me to create this blog. I thought it was inspiring enough to a point of needing to share the experience with others. I have decided to proceed with the "proposed" upgrade and see how the entire process pans out. I expect another eventful experience during the actual upgrade process and who knows, it may prompt another another blog.

Clicked on "Upgrade" ...

For interests sake, the laptop technical details are as follows:
  • CPU: Intel i7.
  • RAM: 16GB.
  • HD: SSD 320GB.
  • OS: Linux Ubuntu 15.10 (prior to upgrade).

Saturday, 2 July 2016

Importing Custom Libraries in Dart

After several months of using Dart to develop virtually real solutions, I started experimenting with class object programming. I have used classes extensively in another favourite programming languages such as Free Pascal, so it was only a matter of time until I started implementing these in Dart.

In my code, I initially had the custom class definition together with the main application code. This simplified understanding and trialing the concepts involved. As the class definition increased both in size and complexity, it made perfect sense to move out the class definitions into a dedicated class file.
This was relatively easy and presented no challenges in having the resultant application code function as was required. In other words, the importing of the new class definition file into teh main code was rather straightforward.

Invariably the class definitions continue to evolve and adapt to the application development requirements of one or more projects. I had started to create two additional class, each code in its own .dart file. It should go without saying on the advantages of breaking class definitions into their own files:
  • Object oriented paradigm.
  • Inheritance
  • Interface



All went well in creating the new class definition files when I suddenly could not proceed testing teh code due an unfamiliaar error in the editor:
The imported libraries 'libAdministration.dart' and 'libAdminReports.dart' cannot both be unnamed
Well, firstly I could not make sense of the message. Secondly, I did not know how to resolve this clearly phrased message, though a mouthful in some way. Thirdly, I asked myself - should I perhaps place all the class definition back into the main doe file?

Giving up easily is not in my nature, so after searching in google for a possible solution, I was excited that the solution was rather simple: at the top of each library file to be imported, add the following:
library libraryname;
 Thereafter my custom class definition file imports work without any problems.

Monday, 4 January 2016

Raspberry PI Temperature Sensor

The Raspberry Pi (PI) is pretty nifty little device. I have done various programming projects with it over the past seven to nine months. A few days ago a had a strong drive to experiment with the PI's GPIO interface and connect a heat sensors to measure temperatures.

This project comprises of three distinct phases namely: a) Electronics Circuitry, b) Software Development and c) Testing and Integration.

a) Electronics Circuitry (EC): The EC phase entails the assembly of the temperature components as a complete unit onto the breadboard. One of the Dallas sensor is placed directly on the breadboard, The second sensor is wired on the other end of the ethernet cable.
b) Software Development (SD): The SD phase entails preparing the suitable software application to control and manage the EC assembly. Various option exist which languages could be used to develop an application to read, process and store temperature readings. Python is an excellent choice and probably the easiest. However, I am Pascal kind of person both on Windows and Linux operating systems.
Bear in mins that in the absence of any form of a software package, the PI is not able to make any temperature readings, even if the sensors are connected correctly to the GPIO pins. My SD environment is as follows:
  • Free Pascal compiler in CLI mode to develop an executable that takes readings from the senors.
  • Sqlite 3 database to store the temperature readings as per the FPC CLI program.
  • A cron job to run the FPC program every 5 minutes.
c) Testing and Integration (T&I): TI in essence means integrating the EC and SD components into a single functional module.
My bill of materials was:
  • 1x Raspberry Pi 2 B (including PSU, card and box).
  • 2x Dallas DS18B20 temperature sensors.
  • 1x 4K7 Ω resistor.
  • 1x Breadboard.
  • A dozen male to female jumper wires.
  • 1x 3m long UTP ethernet cable.

The final assembly is illustrated in the image below:
Raspberry PI with Temperature sensors on a Breadboard
The sensor on the ethernet cable is temporarily placed outside a room to measure the outdoor temperatures while the breadboard is placed indoors. Below is an extract form the temperature log file (csv formatted with the temperature in celsius degrees being the last 3 characters): 
2016-01-04 00:00:01,28-000006df1322,27.5
2016-01-04 00:00:02,28-0000059a01ed,22.7
2016-01-04 00:05:02,28-000006df1322,27.5
2016-01-04 00:05:03,28-0000059a01ed,22.6
2016-01-04 00:10:02,28-000006df1322,27.5
2016-01-04 00:10:03,28-0000059a01ed,22.6
2016-01-04 00:15:02,28-000006df1322,27.5
2016-01-04 00:15:03,28-0000059a01ed,22.4
2016-01-04 00:20:02,28-000006df1322,27.4
2016-01-04 00:20:03,28-0000059a01ed,22.4
The listing below comprises the complete Pascal program used to read and store temperature readings into  Sqlite 3 database table:
program tempsensors;

{$mode objfpc}

uses Classes, SysUtils, db, sqlite3ds;

const appVersion = '0.1';

var sl       : TStringlist;
    rows     : integer;
    temp     : string;
    slDevs   : TStringlist; //devicesList
    i        : integer;
    devCount : integer;
    devFile  : string;

    logOutput : string;

    dsTempLog : TSqlite3Dataset;
    sqlstr  : string;

function parseTemperature(tempStr: string):string;
{*
 Function parses and returns a temperature value from the given string tempStr.
 tempStr = temperature string.
*}
var
    x : integer;   //index used to parse temperature value in a string.
    c : integer;   //temperature reading in celsius.
    f : real;      //temperature value / 1000.

begin
 result := '';

 if tempStr = '' then
 exit;

 x := pos('=', tempStr) + 1;

 begin
   c := strtoint(copy(tempStr,x,5));
   f := c/1000;

   result := floatToStrF(f,ffFixed,2,1);
 end;
end;


function logDateStamp:string;
var current : TDateTime;
begin
 current := now;

 result := formatDateTime('YYYY/MM/DD hh:mm:ss', current);
end;


procedure logToTextFile(aFn, aLogdata: string);
var fh : TextFile;   //filename to log to.
begin
 assignFile(fh,aFn);

 if not fileExists(aFn) then
 begin
   rewrite(fh);
 end
 else
 begin
   append(fh);
 end;

 try
   writeln(fh,aLogData);
 finally
   closeFile(fh)
 end;
end;

begin {begin of main program.}

// writeln('Script started by user.');
// writeln('Hello Pascal on Raspberry Pi.');


 //Exit this program if prescribed file does not exists:
 if not fileExists('/home/pi/progs/pascal/sensorDevices.txt') then
 begin
   writeln('Alert: Error in opening the sensor devices descriptor file.');
   exit;
 end;


 //Load into the devces stringlist a text file that contains declared sensor devices:
 slDevs := TStringlist.create;

 dsTemplog := TSqlite3Dataset.create(nil);
 dsTemplog.Filename   := '/home/pi/progs/pascal/templog.db';
 dsTemplog.Tablename  := 'temps';
 dsTemplog.PrimaryKey := 'id';

 try
   slDevs.loadfromfile('/home/pi/progs/pascal/sensorDevices.txt');

   devCount := slDevs.count;

   //Declare String list that will hold conrtents of sensor device w1_slave file contents:
   sl := TStringlist.create;


   try
      //Iterate through each device file name
      for i := 0 to devCount-1 do
      begin
         logOutput := '';

         devFile := '/sys/bus/w1/devices/' + slDevs[i] + '/w1_slave';

         if not fileexists(devFile) then
         begin
            writeln('Alert: Sensor device system file not found.');
            exit;
         end;

         //Load fiel contents of w1_slave file to extract the temperature:
         sl.loadfromfile(devFile);

         rows := sl.count;

         //Display temperature log reading if prescribed conditions are met, else display error message.
         if (rows = 2) and (pos('YES', sl[0]) > 0)  then
         begin
            temp := sl[1];
            writeln('Processing  device with index : [' + inttostr(i) + ']. Row count: ' + inttostr(rows));
            logOutput := logDateStamp + ',' + slDevs[i] + ',' + parseTemperature(temp);

            writeln(logOutput);

            try
{               sqlstr := 'insert into temps (date_log,device_id,temp) ' +
                         'values ' +
                         '(%f, ''%s'', %f)';
}

               //Construct the SQL insert statement
               sqlstr := 'INSERT INTO temps ' +
                         '(date_log,device_id, temp) ' +
                         'VALUES '+
                         '('''+logDateStamp+''','+''''+slDevs[i]+''','+''''+parseTemperature(temp)+''')';

//               dsTemplog.sql := Format(sqlstr, [logDateStamp, slDevs[i], parseTemperature(temp)]);
//               dsTemplog.sql := Format(sqlstr, ['2016-01=03 10:00:00', slDevs[i], '28.0']);
               dsTemplog.sql := sqlstr;
               dsTemplog.ExecSql;
            except
              writeln('Alert: Error in inserting data to the DB table with sql statement:');
              writeln(sqlstr);
            end;

            logToTextFile('/home/pi/progs/pascal/tempreadings.log',logOutput);
         end
         else
         begin
            writeln('Alert: Temperature string not found');
          end;
      end;
   finally
      sl.free;
   end;
 finally
   dsTemplog.free;
   slDevs.free;
 end;

end.
Going forward my intention is to:
  • Duplicate the project on a Raspberry PI Zero.
  • Add a dozen more DS18B20 temperature sensors.
  • Provide environmental proofing of the sensors.
  • Develop a web portal that accesses the Sqlite table for display and control capabilities.