An OpenStreetMap App written in PicoLisp (Pt. 2)

An OpenStreetMap App written in PicoLisp (Pt. 2)

ยท

5 min read

Now it's almost summer and definitely time to finish the blog post about the PicoLisp Ice Cream Finder! This is a continuation of this post, where we explained how to work with Google Maps and OpenStreetView.

The app's purpose is simple: It should pick up the current location via GPS and display all ice cream shops and supermarkets nearby, based on the results from the OpenStreetMap API.

grafik.png


Setting up the Working Environment

First of all, let's set up a working environment that allows us to test and modify our code in a fast and efficient way. In order to do this, we will use the PilBox Pseudo-Terminal.

First of all, let's create a simple template. It contains a file App.l which defines the app title as well as the app logo and some basic CSS files. You can find the template here as a reference. Compress the template folder to a .zip-File and send it to the PilBox app on your phone, for example via termux share (or email).

After opening the zip-file in the app it should look like this:

image.png


Next we expand the .zip-File in the working directory on our PC and start the pty from the same directory. This way we have the same relative paths and are able to use pbPut and pbGet to copy files.

$ cd <your favorite picolisp directory>
$ unzip iceCreamApp-Template.zip
$ pil ~/pil21/bin/pty <your phone's IP>
android:

If you have trouble with the tty, read here.

Note that PilBox should be open on the phone for the tty to work. After we got the connection, we can check the app folder on the phone:

android: (call "ls")
App.l    JAVA    PID      RPLY  Version  favicon.ico  lib      loc   src
BOSS     LISP    PIL-369  RQST  bin      icecreamPt1  lib.css  log   steps.rc
COPYING  Locale  Port     UUID  db       img          lib.l    log-  tls

This shows the folder icecreamPt1 which includes the template files of the app, as well as PIL-369 which is the internal app's name on my phone (unfortunately my Samsung smartphone seems to rename .zip-files before opening them in external apps).


Now for testing purposes, let's rename the app in App.l from "PicoLisp App Stub" to "Mia' Ice Cream Finder" on the PC and transfer it to the phone like this:

android: (pbPut "<appname>/App.l")

In this example, the appname is "icecreamPt1" because this is how I called it in the repository (link in the end).

Now the app title should be changed on your smartphone as well.


Defining the general app layout

I like starting with the easy things, like setting the header and main layout features. Let's define a function work that gets called. Inside work, we call pilbox, which allows us to define the App header by ourselves instead of the pre-defined "PilBox" text.

"Mias Ice Cream Finder (Pt. 1)" 

(de work ()
   (pilbox
      (<h5> "fh" "Mia's Ice Cream Finder") )
   (menu "Mia's Ice Cream Finder") )

(work)

Note: the CSS-class fh is defined in the pre-installed @lib/phone.css.

Next, we can define the background and styles with bootstrap (here for more info). We display a title called "Want ice cream?" and a search box with two buttons. The buttons can be pressed, but there is no function tied to it yet.

This is the PicoLisp code for that:

(de work ()
   (pilbox
      (<h5> "fh" "Mia's Ice Cream Finder") )
   (menu "Mia's Ice Cream Finder"
      (form NIL
         (<div> "bg-light container-sm border"
            (<div> "d-flex flex-column "
               (<h3> "mt-5 mb-4 d-flex justify-content-center" "Want ice cream?" )
               (<div> "mb-3 d-flex justify-content-center"
                  (<p> NIL "Find ice cream near your current location!") )
               (<div> "d-flex justify-content-center"
                  # Search button for ice cafe
                  (gui '(+Style +Button) "button-icon bg-white mb-5 mx-3"
                     T "icecreamPt1/img/ice.png" NIL)
                  # Search button for supermarket
                  (gui '(+Style +Button) "button-icon bg-white mb-5 mx-3"
                     T "icecreamPt1/img/supermarket.png" NIL) ) ) ) ) ) )

and this is how it looks like:

image.png


Getting the current location

Now comes the interesting point: Let's take our current position and display it on OpenStreetMap. First of all, we import the relevant name spaces, some global variables and the gis.l library:

"Mias Ice Cream Finder (Pt. 1)" "@lib/gis.l"

(symbols 'icecream 'gis 'android 'pico)

(local) (*Latitude *Longitude)

Now we can fetch the current position with the gps function, just like in the previous post on GPS. But this time we want to get the data in the background: let's refresh the location every 6 seconds. Periodic tasks can be realized with the task function (here you can more information on task).

(start
   (scl 6)
   (task -6000 1000
      (nond
         ((location?) NIL )
         ((gps) NIL )
         (NIL
            (setq *Latitude (car @)  *Longitude (cdr @)) ) ) ) )

What does this do?

  1. First, it sets the scale for integer calculations to 6 (if you don't know the scl function, check out this post).
  2. Then we define a periodic task, executed every 6 seconds. The first time it is executed one second after starting the app.
  3. nond is a multi-way conditional which executes if the argument evaluates to NIL. We distinguish three cases:
    • (location?) is false, i. e. GPS permissions are not given,
    • (gps) is NIL, i. e. GPS data is not (yet) available
    • NIL: the exit condition - GPS data is available and stored in the global variables *Latitude and *Longitude.

Let's test it: Now the app asks for GPS permissions at start up. If we confirm with "yes", we can execute (gps) in the tty and see the current location:

icecream: (gps)
-> (142520664 . 193401665)

side note: NOT my exact location ๐Ÿ˜„


Nice! So let's use this data and display it on the map.

(<div> "map"
   (<osm> *Latitude *Longitude 12)
   (<poi> *Latitude *Longitude
      "icecreamPt1/img/here.png" "0.1" "1.0"
      "" 0 "black" ) ) ) ) )

image.png


In the next post, we will see how to use the OpenStreetMap API to fetch the supermarket and ice cream shop position and display them in the map. Also, we will use ServerSideEvents to display some information.

You can find the source code up to this point here and the zip-File here.


Sources

ย