Wednesday, August 1, 2018

HOW TO: Mongoose OS (mos) local build on Windows.

For those of you who are just getting started with mgos, you might have noticed that you would typically compile your app, or an example app, with a command like this:

mos build --arch <arch> 

For example to build the c_hello firmware example for the esp8266 arch, you would navigate to the c_hello app directory, and build it like so:

cd ~/mongoose-os/fw/examples/c_hello/
mos build --arch esp8266

The output will look like this:
$ mos build --arch esp8266
Connecting to https://mongoose.cloud, user test
Uploading sources (2331 bytes)
Firmware saved to build\fw.zip

fw.zip is the file ready to be flashed onto your device, but where did it come from?  How and where did it get built?  What's actually happening here is that it's connecting to the mongoose cloud, uploading your app's source files building it on the cloud (using their build environment, libraries and OS sources) and spitting it back to you when it's done.

But what if, say, you want to modify a driver or library to suit your needs, or insert some debug printouts to figure out why your device won't work?  Or what happens if you want to build your app without relying on someone else's cloud service?

Then you'll need local build.  Mongoose OS does facilitate this, and it's quite easy, but there are some little hiccups along the way for some users.

Step 1:  Docker CE for Windows
The first thing you're going to need to do is download and install Docker CE (Community Edition) for Windows.  It's free, but you're going to have to sign up (I know.... a pain...); and it's pretty hefty too at about 500MB or so.

Docker will probably ask you to enable the above features in Windows in order for Docker to work.  Keep in mind that if you enable these, VirtualBox will no longer work.


Open the Performance tab of Task Manager and check that Virtualization is enabled.  If it's not, enable it from your BIOS settings.  You may need to do a quick Google search to confirm that your CPU supports virtualization and how to enable it.

In my case I had to go to Windows Features, disable Hyper-V, restart, re-enable Hyper-V, and restart before it would show up as 'Enabled' in the Performance tab.  Some other users report having to do this too.

Step 2:  Install Go for Windows
This should be pretty easy.  Just go to https://golang.org/dl/ and select an x86 or x86_64 self-extracting installer for Windows.

To verify the installation:
> go version
go version go1.10.3 windows/amd64

If this doesn't work.  Add the go path to your environment.

Step 3: Run the local build command

mos build --local --arch --esp8266 --libs-dir ../../../libs/ --repo ../../../../mongoose-os/ --verbose

Verbose is optional.  I like to have it enabled so I can see what's going on.  --libs-dir and --repo are both compulsory.  --libs-dir needs to point to the "libs" directory where you have cloned all your Mongoose OS libs (click for a link to the github), and --repo just simply points to the source of your actual Mongoose OS source which you would clone from here.

You run this command from the root directory of the app that you want to compile.  To check that local build is truly working, you will want to disconnect yourself from the World Wide Web before running the command again.  Enjoy.

Saturday, June 30, 2018

Cronjobs on the ESP8266 with Mongoose OS

This is a copy of a post I made on StackOverflow helping another user getting a Cronjob up and going on mgos, but I thought it might be useful to add it here also, with a bit more info.  All it does is turn on an LED at a particular time of the day and turn it off at another time of the day.
There are 6 steps.  They're all pretty easy.  But if you're less experienced with Mongoose OS or experience a bug, please let me know the comments below.
Step 1: Add wifi setup to your mos.yml so it can connect to your wireless AP.  If you don't do this you won't be able to successfully pull the time from the NTP server using SNTP.
config_schema:
  - ["wifi.sta.enable", true]
  - ["wifi.sta.ssid", "MyAP"]
  - ["wifi.sta.pass", "Passwd"]
Step 2: Add these to your mos.yml. Leave off rpc-uart if you have no intention of making rpc calls over UART.  You'll notice there's a lib sntp in here.  There's nothing that needs to be done after adding it to your mos.yml. You don't need to add anything into your app code.  As soon as an internet connection is established it grabs the latest time.  It uses time.google.com by default.
libs:
  - origin: https://github.com/mongoose-os-libs/sntp
  - origin: https://github.com/mongoose-os-libs/crontab
  - origin: https://github.com/mongoose-os-libs/rpc-service-cron
  - origin: https://github.com/mongoose-os-libs/wifi
  - origin: https://github.com/mongoose-os-libs/rpc-uart
Step 3: In your application code, in the entry point for your app (mgos_app_init()), add crontab handlers.  In this case we're just going to add two cronjobs, one for LED on, and LED off. mgos_crontab_register_handler() takes three arguments, the name of the action (we will get to this in step 6), and the exact name of the callback function, which we will define in the next step.  The third argument is void *userdata. For now it's safe to leave this as NULL, because we don't intend of passing any extra data into our callback functions.
enum mgos_app_init_result mgos_app_init(void) {
  /* Set LED GPIOs as outputs */
  mgos_gpio_set_mode(YOUR_LED_GPIO, MGOS_GPIO_MODE_OUTPUT);

  /* Register crontab handler - LED OFF */
  mgos_crontab_register_handler(mg_mk_str("ledoff"), ledoff, NULL);

  /* Register crontab handler - LED ON */
  mgos_crontab_register_handler(mg_mk_str("ledon"), ledon, NULL);

  return MGOS_APP_INIT_SUCCESS;
}
Step 4: Add callbacks.  These callback functions need to match the name of the second argument of mgos_crontab_register_handler() in the previous step.  It's worth noting that the mos-tool build system is extremely pedantic and with error out if you pass a parameter into a function and don't utilize it.  This is why we use (void) parameter; to trick the compiler into letting us pass.
void ledoff(struct mg_str action, struct mg_str payload, void *userdata) {
  mgos_gpio_write(YOUR_LED_GPIO, 0);
  (void) payload;
  (void) userdata;
  (void) action;
}

void ledon(struct mg_str action, struct mg_str payload, void *userdata) {
  mgos_gpio_write(YOUR_LED_GPIO, 1);
  (void) payload;
  (void) userdata;
  (void) action;
}
Step 5: From your app's main directory, build the app as you normally would (eg. mos build --arch esp8266 --verbose).
Step 6: Add your cronjobs from the web UI or UART:
call Cron.Add '{"at":"0 0 10 00 * *, "action":"ledon"}'
call Cron.Add '{"at":"0 0 16 00 * *, "action":"ledoff"}'
The format of cronjob times on Unix-like systems typically looks like this:
# ┌───────────── minute (0 - 59)
# │ ┌───────────── hour (0 - 23)
# │ │ ┌───────────── day of month (1 - 31)
# │ │ │ ┌───────────── month (1 - 12)
# │ │ │ │ ┌───────────── day of week (0 - 6) (Sunday to Saturday;
# │ │ │ │ │                                  7 is also Sunday on some systems)
# │ │ │ │ │
# │ │ │ │ │
# * * * * *  command to execute
But Mongoose OS's cron lib specifies a slightly different format:
# ┌───────────── seconds (0 - 59)
# │ ┌───────────── minutes (0 - 59)
# │ │ ┌───────────── hours (0 - 23)
# │ │ │ ┌───────────── day of the month (1 - 31)
# │ │ │ │ ┌───────────── month 1-12 or JAN-DEC
# │ │ │ │ │ ┌───────────── day of week 0-6 or SUN-SAT
# │ │ │ │ │ │
# │ │ │ │ │ │ 
# * * * * * *

Wednesday, May 18, 2016

Acer Aspire Ubuntu "Freezing" Issue (Ubuntu 14.04, 16.04).

Starting from late last year, and continuing into the time of writing (May 2016), there have been several long threads on the kernel bug tracking system (bugzilla.kernel.org), the Ubuntu Forums and Launchpad with dozens of infuriated Acer Aspire users experiencing spontaneous, randomly-timed freezes which affect Ubuntu 14.04 (Trusty Tahr), Ubuntu 16.04 (Xenial Xerus), and perhaps earlier releases too (although I cannot find any evidence for this). 

One user tried downgrading his kernel; another upgrading his kernel; both to no avail.  Later another user reports it to be a "...horrible bug affecting BayTrail users", with "little activity from Intel or kernel devs to fix it".  Bay Trail is an an SoC architecture common on many Acer Aspire machines. 

The good news is that there's one solution which truly works; the bad news is that it will severely affect your battery life.  So don't chuck out your laptop, but remember to put that power supply into your bag before going to Uni or work.

Here's the fix.  Add the following parameter into Grub:


intel_idle.max_cstate=1

When altering kernel parameters you should always 'test' it out first before applying it permanently.

To 'test' out the kernel parameter enter into grub (press "SHIFT" repeatedly during your computer's POST (power-on-self-test) phase) to enter grub and you should enter a GRUB screen which looks something like this:

It might look different depending on your desktop environment.  I use Ubuntu Mate and mine looks like this:

As you can see the options are still the same; they just look different.

Select the option which your normally boot from and press 'e' to edit it.  Locate the line mentioned earlier beginning with 'linux', and add the new bootarg  intel_idle.max_cstate=1
(sometimes also called a "boot parameter" or bootparam) somewhere towards the end of the line.  Press ctrl+x or F10 to boot using this param.  If the kernel can boot successfully without any issues and you can login, you know this fix is safe to apply for good and for every time you reboot your system.

Type the following command into your terminal:
sudo vim /boot/grub/grub.cfg

Make the same modification that you made from the Grub screen, save and exit.  You will most likely need to save with "w!" because grub.cfg is a read-only file.

Now this bootarg will be set for the next time you reboot and every subsequent reboot; and hopefully for you, the freezing issue will be gone.  But at what cost?  We mentioned earlier that there was a power-consumption side effect to this fix.  It has to do with a CPUs "C-states" and "P-states".

"C-states" are "power consumption states" and can be thought of as different levels of "sleep".  A CPU, or any one of its individual cores, if it is not currently doing anything would effectively be "driving around in circles", which wastes power.  The solution to this is that CPUs have different "C-states" starting from C0 right up to Cn where n is the highest C-state.  The higher the C-state level and the higher the value of n, the lower the transistors' quiescent (resting) voltage is, and the lower the transistors' switching frequency is; both of which drastically affect power consumption.  CPUs enter high levels of "n", during longer periods of "doing nothing".

Looking back at the fix we applied, we have limited our Baytrail chip's C-state to "1" (intel_idle.max_cstate=1).  One could only deduct from this fix that entering into one of the higher C-states or exiting out of them is what is causing the kernel to freeze.

So-called "P-states" are to do with performance.  During periods where the CPU is executing tasks, but the CPU utilization is not 100%, the CPU may enter into high "P-states"  in order to further save power.