How to store constants / unclear exception

#1

Hello,

I have to store a list of constants (font for NeoPixel display). The array is not extremely long. I wonder if there is a better way than just defining an array? Especially a way saving memory.

let LETTERS = [
  [0x0033333f, 0x33331e0c],
  [0x003f6666, 0x3e66663f],
  [0x003c6603, 0x0303663c],
  ...
  [0x0063361c, 0x36630000],
  [0x1f303e33, 0x33330000],
  [0x003f260c, 0x193f0000]
];

In a stand-alone application everything works fine. But when adding AWS + Shadow libs my application crashes. Probably an OOM exception?

The array should not use more than 400 bytes - so not a really huge amount. But perhaps there is a better approach?

Thanks!

[May 19 22:56:23.372] Exception 29 @ 0x4000e1b2, vaddr 0x00000000
[May 19 22:56:23.377]  A0: 0x40288c23  A1: 0x3ffff220  A2: 0x00000000  A3: 0x00000000
[May 19 22:56:23.383]  A4: 0x0000020c  A5: 0x00000000  A6: 0x00000200  A7: 0x00000020
[May 19 22:56:23.388]  A8: 0x3ffe83cc  A9: 0x00000190 A10: 0x00000000 A11: 0x0000007c
[May 19 22:56:23.394] A12: 0x00000000 A13: 0x0000020c A14: 0x00000000 A15: 0x3fffae7c
[May 19 22:56:23.400] 
[May 19 22:56:23.400] (exc SP: 0x3ffff080)
[May 19 22:56:23.400] 
[May 19 22:56:23.402] --- BEGIN CORE DUMP ---
[May 19 22:56:23.402] mos: catching core dump
[May 19 22:56:26.247] ....
[May 19 22:56:34.953] ---- END CORE DUMP ----
[May 19 22:56:34.961] mos: wrote to /Users/xxx/Projects/MongooseOS/neopixel/core-neopixel-esp8266-20190519-225634.035405636 (133113 bytes)
[May 19 22:56:34.961] mos: analyzing core dump
Core dump by neopixel/esp8266 1.0 20190519-205546
Using ELF file at: /Users/xxx/Projects/MongooseOS/neopixel/build/objs/neopixel.elf
Using Docker image: docker.io/mgos/esp8266-build:2.2.1-1.5.0-r4
Running docker run --rm -v /Users/xxx/Projects/MongooseOS/neopixel/build/objs/neopixel.elf:/fw.elf -v /Users/xxx/Projects/MongooseOS/neopixel/core-neopixel-esp8266-20190519-225634.035405636:/core -v /Users/xxx/Projects/MongooseOS/neopixel:/Users/xxx/Projects/MongooseOS/neopixel docker.io/mgos/esp8266-build:2.2.1-1.5.0-r4 bash -c /usr/local/bin/serve_core.py --rom=/opt/Espressif/rom/rom.bin --rom_addr=0x40000000 /fw.elf /core & $MGOS_TARGET_GDB /fw.elf -ex 'target remote 127.0.0.1:1234' -ex 'set confirm off' -ex bt -ex quit
GNU gdb (crosstool-NG crosstool-ng-1.22.0-60-g37b07f6f) 7.10
Copyright (C) 2015 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "--host=x86_64-build_pc-linux-gnu --target=xtensa-lx106-elf".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from /fw.elf...done.
Found core at 23 - 133140
Mapping DRAM: 98304 @ 0x3ffe8000
Mapping /opt/Espressif/rom/rom.bin at 0x40000000
Mapping /fw.elf .data: 2660 @ 0x3ffe8000
Mapping /fw.elf .rodata: 8 @ 0x3ffe8a64
Mapping /fw.elf .bss: 27056 @ 0x3ffe8a70
Mapping /fw.elf .text: 30129 @ 0x40100000
Mapping /fw.elf .irom0.text: 690387 @ 0x40200010
Loaded core dump from last snippet in  /core
Remote debugging using 127.0.0.1:1234
0x4000e1b2 in ?? ()
#0  0x4000e1b2 in ?? ()
#1  0x40288c23 in umm_calloc (num=num@entry=131, item_size=item_size@entry=4)
    at /mongoose-os/common/umm_malloc/umm_malloc.c:1732
#2  0x40284994 in calloc (num=num@entry=131, size=size@entry=4)
    at /mongoose-os/fw/platforms/esp8266/src/esp_libc.c:80
#3  0x40266595 in mbedtls_mpi_grow (X=X@entry=0x3ffff2b0, 
    nblimbs=nblimbs@entry=131)
    at /data/tmp/mos_prebuild/tmp/mos_libs/mbedtls/mbedtls/library/bignum.c:130
#4  0x40265939 in mbedtls_mpi_copy (X=X@entry=0x3ffff2b0, 
    Y=Y@entry=0x3ffff944)
    at /data/tmp/mos_prebuild/tmp/mos_libs/mbedtls/mbedtls/library/bignum.c:216
#5  0x40265a1d in mbedtls_mpi_div_mpi (Q=Q@entry=0x0, R=R@entry=0x3ffff944, 
    A=A@entry=0x3ffff944, B=B@entry=0x3fffae7c)
    at /data/tmp/mos_prebuild/tmp/mos_libs/mbedtls/mbedtls/library/bignum.c:1563
#6  0x40266a81 in mbedtls_mpi_mod_mpi (R=R@entry=0x3ffff944, 
    A=A@entry=0x3ffff944, B=B@entry=0x3fffae7c)
    at /data/tmp/mos_prebuild/tmp/mos_libs/mbedtls/mbedtls/library/bignum.c:1688
#7  0x40265ef9 in mbedtls_mpi_exp_mod (X=X@entry=0x3ffff9b0, 
    A=A@entry=0x3ffff9b0, E=E@entry=0x3fffae88, N=N@entry=0x3fffae7c, 
    _RR=_RR@entry=0x3fffaedc)
    at /data/tmp/mos_prebuild/tmp/mos_libs/mbedtls/mbedtls/library/bignum.c:1901
#2

Looking at that - it seems that the pre-built app is using too much RAM and OOMs when connected to AWS.

You can try to use mDash for now, as a temporary workaround.

#3

Sure, I can try… Have to check what is necessary for using mDash instead of AWS.

The whole app isn’t really fancy. NeoPixel display is working and I can update the status via AWS shawow. As soon as I additionally include the letters.js the ESP8266 crashes.

Is there a way to check how much memory is left? I already tried Sys.free_ram() - it was something about 14000 (at least more than the required 400 bytes).

Happy doing some further tests :wink:

load('api_config.js');
load('api_events.js');
load('api_net.js');
load('api_timer.js');
load('api_shadow.js');
load('api_gpio.js');
load('api_neopixel.js');

load('digits.js');
// load('letters.js');

let pin = 15, numPixels = 64, colorOrder = NeoPixel.GRB;
let strip = NeoPixel.create(pin, numPixels, colorOrder);
strip.clear();
strip.show();

let char = ' ';
let red = 0x0f;
let green = 0x0f;
let blue = 0x0f;

let deviceId = Cfg.get("aws.thing_name");
let connected = false;

let showState = function() {
  strip.clear();

  let high = 0x00000000;
  let low = 0x00000000;

  let code = char.charCodeAt(0);

  if (code >= 48 && code <= 57) {
    high = DIGITS[code - 48][0];
    low = DIGITS[code - 48][1];
  /* } else if (code >= 65 && code <= 90) {
    high = LETTERS[code - 65][0];
    low = LETTERS[code - 65][1]; */
  }

  for (let x = 0; x < 4; x++) {
    for (let y = 0; y < 8; y++) {
      let i = (high >> (x * 8)) & 0xff;
      let j = (i >> y) & 0x01;
      if (j) {
        strip.setPixel((x + 4) * 8 + y, red, green, blue);
      }
    }
  }

  for (let x = 0; x < 4; x++) {
    for (let y = 0; y < 8; y++) {
      let i = (low >> (x * 8)) & 0xff;
      let j = (i >> y) & 0x01;
      if (j) {
        strip.setPixel(x * 8 + y, red, green, blue);
      }
    }
  }

  strip.show();
};

let data = {};

let publishState = function() {
  print('Sending current state...');
  data = {DeviceId: deviceId, Char: char, Red: red, Green: green, Blue: blue};

  print(JSON.stringify(data));
  Shadow.update(0, data);

  showState();
};

let cloudconnect = Timer.set(60000, Timer.REPEAT, publishState, null);

// Monitor network connectivity.
Event.addGroupHandler(Net.EVENT_GRP, function(ev, evdata, arg) {
  let status = true && connected;
  let evs = '???';
  if (ev === Net.STATUS_DISCONNECTED) {
    evs = 'DISCONNECTED';
    connected = false;
  } else if (ev === Net.STATUS_CONNECTING) {
    evs = 'CONNECTING';
    connected = false;
  } else if (ev === Net.STATUS_CONNECTED) {
    evs = 'CONNECTED';
    connected = false;
  } else if (ev === Net.STATUS_GOT_IP) {
    evs = 'GOT_IP';
    connected = true;
  }
}, null);

Shadow.addHandler(function(event, obj) {
  if (event === 'CONNECTED') {
    // Connected to shadow - report our current state.
    publishState();
  } else if (event === 'UPDATE') {
    print(JSON.stringify(obj));
  } else if (event === 'UPDATE_ACCEPTED') {
    print(JSON.stringify(obj));
  } else if (event === 'UPDATE_DELTA') {
    // Got delta. Iterate over the delta keys, handle those we know about.
    for (let key in obj) {
      if (key === 'Char') {
        // Shadow wants us to change local state - do it.
        char = obj.Char;
      } else if (key === 'Red') {
        // Shadow wants us to change local state - do it.
        red = obj.Red;
      } else if (key === 'Green') {
        // Shadow wants us to change local state - do it.
        green = obj.Green;
      } else if (key === 'Blue') {
        // Shadow wants us to change local state - do it.
        blue = obj.Blue;
      } else {
        // ignore
      }
    }
    // Once we've done synchronising with the shadow, report our state.
    publishState();
  } else {
    print('Unhandled event', event);
  }
});
#5

Follow https://forum.mdash.net/t/connect-mongoose-os-to-mdash/17 to change to mDash.

#6

When using mDash I do not get the OOM error. ESP8266 is sending data - however I do not see the right shadow on https://mdash.net.

Switching back to AWS and the error returns… Before the dump Sys.free_ram() shows something about 19000 bytes left. Not sure who is using all the memory.

As our project should run together with AWS Lambda moving to mDash is not really an option… Ok, just for testing.

I remember the Arduino IDE provides a feature storing constants out of RAM. Does Mongoose OS provide a similar approach? There should be a way storing some constants or structured data…

Btw. would be cool if this lib could be provided as well :slight_smile:

#7

If you’re using demo-js, I suggest to clone it, modify mos.yml by including an exact list of libraries you need - instead of demo bundle. The bundle has a lot of cruft you don’t need. You might solve your RAM issue.

#8

Thanks, I reduced the libs giving some more free memory…

libs:
    # common mgos libs
  - origin: https://github.com/mongoose-os-libs/boards
  - origin: https://github.com/mongoose-os-libs/wifi

    # libs necessary for the current app
  - origin: https://github.com/mongoose-os-libs/neopixel
  - origin: https://github.com/mongoose-os-libs/mjs
  - origin: https://github.com/mongoose-os-libs/aws

Unluckily the problem remains. After WiFi connection is establish the app crashes. Without loading the letters.js no crash. Following the “Free RAM” log I cannot really imagine an OOM error.

But no idea what else might go wrong?

[May 20 21:27:05.759] Free RAM: 30160 
[May 20 21:27:05.860] Free RAM: 30160 
[May 20 21:27:05.931] ip:172.23.56.212,mask:255.255.255.0,gw:172.23.56.1
[May 20 21:27:05.934] mgos_wifi.c:144         WiFi STA: New current config: 1
[May 20 21:27:05.951] mgos_sys_config.c:231   Loading conf0.json
[May 20 21:27:06.100] mgos_sys_config.c:173   Saved to conf9.json
[May 20 21:27:06.120] Free RAM: 30184 
[May 20 21:27:06.120] mgos_mongoose.c:66      New heap free LWM: 26096
[May 20 21:27:06.126] mgos_net.c:101          WiFi STA: ready, IP 172.23.56.212, GW 172.23.56.1, DNS 172.23.56.1
[May 20 21:27:06.167] mgos_mqtt.c:427         MQTT connecting to xxx-ats.iot.eu-central-1.amazonaws.com:8883
[May 20 21:27:06.200] mgos_mongoose.c:66      New heap free LWM: 22784
[May 20 21:27:06.219] Free RAM: 24888 
[May 20 21:27:06.241] mgos_mongoose.c:66      New heap free LWM: 22624
[May 20 21:27:06.324] Free RAM: 24540 
[May 20 21:27:06.324] mgos_mongoose.c:66      New heap free LWM: 19160
[May 20 21:27:06.334] mg_ssl_if_mbedtls.c:35  0x3fff0efc ciphersuite: TLS-ECDHE-RSA-WITH-AES-128-GCM-SHA256
[May 20 21:27:07.086] SW ECDH curve 3
[May 20 21:27:13.521] E:M 32 (5 blocks)
[May 20 21:27:13.521] 
[May 20 21:27:13.521] Exception 29 @ 0x4000e1b2, vaddr 0x00000000
[May 20 21:27:13.526]  A0: 0x4028788f  A1: 0x3ffff7e0  A2: 0x00000000  A3: 0x00000000
[May 20 21:27:13.532]  A4: 0x00000020  A5: 0x00000000  A6: 0x00000020  A7: 0x00000002
[May 20 21:27:13.538]  A8: 0x3ffe83cc  A9: 0x00000190 A10: 0x00000000 A11: 0x0000007c
[May 20 21:27:13.544] A12: 0x00000000 A13: 0x00000020 A14: 0x00000000 A15: 0x3ffffc94
[May 20 21:27:13.549] 
[May 20 21:27:13.549] (exc SP: 0x3ffff640)
[May 20 21:27:13.549] 
[May 20 21:27:13.549] --- BEGIN CORE DUMP ---
[May 20 21:27:13.551] mos: catching core dump
#9

Try to move your DIGITS and LETTERS in C, add 2 C functions eg. int char_get_high(int c) and int char_get_low(int c), ffi them in the mJS code and the pressure on the RAM will/might be lower.

1 Like