Close

More about the software

A project log for SDA - The best new PDA

Do you miss those old small devices in your palm? Don't be sad, you can always build your own!

brtnstbrtnst 01/21/2018 at 22:034 Comments

SDA_OS

SDA is in its current form just mess of wires in nice 3D printed case, it works, but its not a great piece of hardware. All its value is in the SDA_OS software stack. SDA_OS is cooperative single tasking operating system (if the only task doesn't cooperate, the system hangs) and it can run its own applications. Its most powerful feature is that there are two supported platforms: STM32 and Linux (Windows version is also possible). I did not aimed for this in the beginning, but being able to debug new applications and add new features easily on my laptop is really convenient.

SDA_OS has the same code base for both platforms, only the drivers are different. The linux part are just standard libraries and SDL for graphics and input. On the STM32 I use HAL libraries to handle peripherals (with some optimisations where the HAL is too slow) and FatFs library for handling the SD card.

For the Linux version I use simply GCC, for STM32 I got Eclipse with some CodeSourcery plugins. (I got it working once and never touched it since.)

Graphical library

I use simple graphical library of my own design. It is written in C and can be used on top of simple functions that can draw points or fill rectangles on a LCD. (basic lcd_set_xy, lcd_draw_point etc.) On the SDA the library draws on its display, in the simulator it is using SDL. Most of the basic functions for drawing lines and rectangles are borrowed from library that came with the lcd.

The text drawing function is custom and draws text in pre-rendered variable-width font, it supports Czech character set encoded as UTF-8. It don't support all of the UTF characters and it can crash on some special ones. The graphics library also have functions to determine size of the rendered text, it can draw cursor on specific position and it can automatically break too long lines of the text.
As only supported image format I selected the binary PPM. Gimp can export to it and it is dead simple to read and draw. Also I don't like BMP.

Most basic block of my UI is a screen element, on screen you can add another elements (and also another screens), you can set the position of elements inside screen in a grid (you can set size of this grid) and also offset of all elements in the screen (useful for scrolling).

Supported UI elements are:

From those elements you can build a screen, and then draw it to lcd. The library can also receive user input for the screen, process it and set event in some element (if you click on button, the button will have EV_PRESSED in its event field). In the code to update the UI you can read and handle those events.

The library is written in a way that allows to redraw just the modified elements, so it's reasonably fast.

Downsides of this library are deep in its design, all elements sit in one big array and there are no barriers between applications, so they can rewrite each others elements. Also the array has fixed length, no dynamic memory allocation whatsoever, when you run out of elements, then you can't do much.

The scripting language

I wanted to be able to write applications for SDA on the SDA, in something like BASIC, but I was unable to find something like BASIC. I always wanted to learn how interpreters work and then I found this this awesome tutorial on how to write pascal interpreter in python. Python and C are somewhat different languages, but the concepts are the same and I started to design and implement my own simple blend of interpreted C, BASIC and maybe old GML (Game Maker Language). My goal was to do the high-level functionality in the script and the computation heavy things in a C framework.

I ended up with the SVS (SDA Virtuous Script maybe?). This is really the part of the software that took me the most time. After more than a year it supports functions, local and global variables, some operations with strings, statements like if-else, while, for and most importantly it is easy to connect it to C functions. It also can detect errors reasonably well and can print out the line of the code where the error most likely occurred. Enhanced command-line helloword looks something like this:

function main {
  a = "Result: ";
  hello();
  sys print(a + add(1, 1));
}

function hello {
  sys print("Hello World!");
}

function add {
  return arg0 + arg1;
}

This code outputs:

Hello World!
Result: 2

And again, there is no dynamic memory allocation, so number of functions is fixed, number of variables is fixed and number of characters in the string memory is fixed.

What did I learn? I learn that writing parsers, interpreters and eventually compilers is really hard job and the things that we take for granted are the hardest to implement (like error checking, coping with wrong input...).

Making the applications

Applications are written in the SVS language and they are using frameworks that enables them to use the graphics library, the sound and all the other things (speaker, direct draw to LCD, reading text files, parsing ini and csv files, setting the system alarm).


Code for example application:

function init {
  scr = sys pAddScreen();
  sys pSetMainScr(scr);
  sys pAddText(0, 0, 8, 1,"Graphical Hello World!", scr);
  btn = sys pAddButton(1, 1, 5, 2, "button", scr);
  chck = sys pAddCheckBox(6, 1, 10, 2, "Checkbox", scr);
  sliderVal = 50;
  sld = sys pAddSliderH(1, 3, 9, 4, 100, sliderVal, scr);
  bar = sys pAddBar(1, 6, 9, 7, 100, sliderVal, scr);
}

function update {
  # comment
  if (sys pGetEvent(btn) == EV_RELEASED) {
    a = a + 1;
    sys pSetStr(btn, "" + a);
  }
  sys pSetEvent(btn, EV_NONE);
  
  if (sys pGetEvent(sld)) {
    sys pSetValue(bar, sys pGetValue(sld));
  }
  sys pSetEvent(sld, EV_NONE);
  
  if (sys pGetEvent(chck) == EV_RELEASED) {
    sys pSetGrayout(btn, sys pGetValue(chck));
    sys pSetGrayout(sld, sys pGetValue(chck));
    sys pSetGrayout(bar, sys pGetValue(chck));
  }
  sys pSetEvent(chck, EV_NONE);
}

 And here is what it does:


As you can see, the language is a bit too verbose, but gets the job done. Still it's more programming exercise gone bad than something even remotely useful. I did it mostly to learn something in the design process. I am not forcing anyone to use it, I am showing it to inspire others to do weird things.

I am not showing the C side of things for purpose, it's really ugly and it's badly designed. Also I am the only one with the hardware (although there was version for the 32F769IDISCOVERY kit) and I don't think that anyone would be interested in running just the simulator, but if you want the sources, there is complete source tarball in the project files.

UPDATE: The SVS script interpreter is now available on GitHub.

Discussions

Anthony DiGirolamo wrote 01/26/2018 at 06:11 point

This is great! Very cool project, thank you for sharing. You're not alone in putting off making PCBs. I keep meaning to do that but just end up throwing projects together on a prototype board. I've been thinking of building a handheld game device and writing the firmware to interpret Lua scripts on a sdcard as apps/games. I'm planning on using a teensy 3.6 and a gameduino 3 as the screen. Getting a Lua interpreter running on the teensy will probably be the hardest part.

  Are you sure? yes | no

jaromir.sukuba wrote 01/24/2018 at 16:12 point

Please, release the sources, no matter how ugly it is. Those who are interested in uderstanding your work will have no problem reading it/adjusting for their own needs; the rest will not read it anyway.

  Are you sure? yes | no

brtnst wrote 01/24/2018 at 21:09 point

Thanks for your reply, I will clean the code a bit and post it on github in a few days.

  Are you sure? yes | no

jaromir.sukuba wrote 01/26/2018 at 12:18 point

Thanks for the sources. There is a lot of sources to digest, I really appreciate you decided to release it.

Fortunately, czech comments are readable just fine for me.

  Are you sure? yes | no