elcritch / nesper

Program the ESP32 with Nim! Wrappers around ESP-IDF API's.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

esp_setup fails to execute?

girvo opened this issue · comments

Hey there, trying to set this up!

PS C:\Users\JoshGirvin\Code\firmware-nesper> nimble esp_setup
  Executing task esp_setup in C:\Users\JoshGirvin\Code\firmware-nesper\esp32_nim_example.nimble

[Nesper ESP] setting up project:
...create project source directory
...writing cmake lists
io.nim(853)              readFile
Error: unhandled exception: cannot open: C:\Users\JoshGirvin\.nimble\pkgs\nesper-0.6.0
\nesper\build_utils\templates\CMakeLists.txt [IOError]
     Error: Exception raised during nimble script execution

This is what I get following the process outlined in the README. Any ideas what could be causing it?

PS C:\Users\JoshGirvin\Code\firmware-nesper> ls C:\Users\JoshGirvin\.nimble\pkgs\nesper-0.6.0


    Directory: C:\Users\JoshGirvin\.nimble\pkgs\nesper-0.6.0


Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
d-----        18/02/2022   2:34 PM                nesper
-a----        18/02/2022   2:34 PM            537 nesper.nim
-a----        18/02/2022   2:34 PM           1661 nesper.nimble
-a----        18/02/2022   2:34 PM           3922 nimblemeta.json

Oh and the templates CMakeLists it's trying to open is definitely there:

PS C:\Users\JoshGirvin\Code\firmware-nesper> ls C:\Users\JoshGirvin\.nimble\pkgs\nesper-0.6.0\nesper\build_utils\templates\


    Directory: C:\Users\JoshGirvin\.nimble\pkgs\nesper-0.6.0\nesper\build_utils\templates


Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
d-----        18/02/2022   2:34 PM                app_templates
d-----        18/02/2022   2:34 PM                esp32_templates
-a----        18/02/2022   2:34 PM            932 CMakeLists.txt

This is all with v0.6.0 though I tried devel first and it had the same issue

It honestly looks like it's getting an extra newline in the filename for the setup task?

Error: unhandled exception: cannot open: C:\Users\JoshGirvin\.nimble\pkgs\nesper-0.6.0
\nesper\build_utils\templates\CMakeLists.txt [IOError]

Checking the task source:

    cmake_template = readFile(nopts.nesperpath / "nesper" / "build_utils" / "templates" / "CMakeLists.txt")

Is it possible that nopts.nesperpath has a newline on it due to me running this on Windows?

Checking the output of the gorgeEx command you run, yeah my nimble for whatever reason drops a newline in the output!

$ nimble --silent path nesper
C:\Users\JoshGirvin\.nimble\pkgs\nesper-0.6.0

Okay so I forked and added a removeSuffix into the nopts.nesperpath variable, and setup then worked, hooray!

I tried to run esp_build but again there seems to be some weird PATH error or something as it chokes with %1 is not a valid Windows executable -- when its trying to run idf.py it seems.

I changed the task to do this, and it works (modulo the errors I talk about below in the actual C compilation):

task esp_build, "Build esp-idf project":
  echo "\n[Nesper ESP] Building ESP-IDF project:"

  let idfpy = findExe("idf.py")
  if idfpy == "":
    echo "\nError: idf.py not found. Please run the esp-idf export commands: `. $IDF_PATH/export.sh` and try again.\n"
    quit(2)

  exec("python " &  idfpy & " reconfigure")
  exec("python " &  idfpy & " build")

No worries, I ran reconfigure (worked) and build (failed) myself.

Build failed with this output:

C:\Users\JoshGirvin\Code\firmware-nesper\main\setup_wifi.nim:26:55: error: incompatible type for argument 1 of 'dollar___setup95wifi_19'
   logi TAG, "event.ip_info.ip: %s", $(event.ip_info.ip)
                                       ~~~~~~~~~~~~~~~~^
../main/nimcache/@msetup_wifi.nim.c:130:74: note: expected 'ip4_addr_t' {aka 'struct ip4_addr'} but argument is of type 'esp_ip4_addr_t' {aka 'struct esp_ip4_addr'}
 N_LIB_PRIVATE N_NIMCALL(NimStringV2, dollar___setup95wifi_19)(ip4_addr_t x);
                                                               ~~~~~~~~~~~^
C:\Users\JoshGirvin\Code\firmware-nesper\main\setup_wifi.nim:28:176: error: incompatible type for argument 1 of 'toIpAddress__OOZOOZOOZOnimbleZpkgsZnesper4548O54O48ZnesperZnet95utils_72'
   networkIpAddr = toIpAddress(event.ip_info.ip)
                                                                                                                                                                                ^
../main/nimcache/@msetup_wifi.nim.c:132:154: note: expected 'ip4_addr_t' {aka 'struct ip4_addr'} but argument is of type 'esp_ip4_addr_t' {aka 'struct esp_ip4_addr'}
 N_LIB_PRIVATE N_NIMCALL(tyObject_IpAddress__t0yd6ha54oWXm7nwZ4QqfA, toIpAddress__OOZOOZOOZOnimbleZpkgsZnesper4548O54O48ZnesperZnet95utils_72)(ip4_addr_t ip_0);
                                                                                                                                               ~~~~~~~~~~~^~~~
C:\Users\JoshGirvin\.nimble\pkgs\nesper-0.6.0\nesper\events.nim: In function 'wifiStart__setup95wifi_61':
C:\Users\JoshGirvin\.nimble\pkgs\nesper-0.6.0\nesper\events.nim:39:164: warning: passing argument 3 of 'esp_event_handler_register' from incompatible pointer type [-Wincompatible-pointer-types]
             esp_event_handler_register(
                                                                                                                                                                    ^

Is this because Nesper was built against a different version of ESP-IDF? What version should I install that it works directly with?

EDIT: Ah, I see, I should be using v4.0 not v4.4?

Sorry for the comment spam here!

Okay so I got ESP-IDF v4.1 up-and-running, but there seems to be a version/typing mismatch between my Nim version (and its standard libraries output) Nesper + ESP-IDF?

What version of Nim should I be running? I have v1.6.4 currently.

C:\Users\JoshGirvin\Code\firmware-nesper\main\setup_wifi.nim: In function 'ipReceivedHandler__setup95wifi_13':
C:\Users\JoshGirvin\Code\firmware-nesper\main\setup_wifi.nim:26:55: error: incompatible type for argument 1 of 'dollar___setup95wifi_19'
   logi TAG, "event.ip_info.ip: %s", $(event.ip_info.ip)
                                       ~~~~~~~~~~~~~~~~^
../main/nimcache/@msetup_wifi.nim.c:130:74: note: expected 'ip4_addr_t' {aka 'struct ip4_addr'} but argument is of type 'esp_ip4_addr_t' {aka 'struct esp_ip4_addr'}
 N_LIB_PRIVATE N_NIMCALL(NimStringV2, dollar___setup95wifi_19)(ip4_addr_t x);
                                                               ~~~~~~~~~~~^
C:\Users\JoshGirvin\Code\firmware-nesper\main\setup_wifi.nim:28:176: error: incompatible type for argument 1 of 'toIpAddress__OOZOOZOOZOnimbleZpkgsZnesper4548O54O48ZnesperZnet95utils_72'
   networkIpAddr = toIpAddress(event.ip_info.ip)
                                                                                                                                                                                ^
../main/nimcache/@msetup_wifi.nim.c:132:154: note: expected 'ip4_addr_t' {aka 'struct ip4_addr'} but argument is of type 'esp_ip4_addr_t' {aka 'struct esp_ip4_addr'}
 N_LIB_PRIVATE N_NIMCALL(tyObject_IpAddress__t0yd6ha54oWXm7nwZ4QqfA, toIpAddress__OOZOOZOOZOnimbleZpkgsZnesper4548O54O48ZnesperZnet95utils_72)(ip4_addr_t ip_0);
                                                                                                                                               ~~~~~~~~~~~^~~~
C:\Users\JoshGirvin\.nimble\pkgs\nesper-0.6.0\nesper\events.nim: In function 'wifiStart__setup95wifi_61':
C:\Users\JoshGirvin\.nimble\pkgs\nesper-0.6.0\nesper\events.nim:39:164: warning: passing argument 3 of 'esp_event_handler_register' from incompatible pointer type [-Wincompatible-pointer-types]
             esp_event_handler_register(
                                                                                                                                                                    ^
In file included from C:/Espressif/frameworks/esp-idf-v4.1.2/components/esp_wifi/include/esp_wifi.h:64,
                 from ../main/nimcache/@msetup_wifi.nim.c:7:
C:/Espressif/frameworks/esp-idf-v4.1.2/components/esp_event/include/esp_event.h:146:61: note: expected 'esp_event_handler_t' {aka 'void (*)(void *, const char *, int,  void *)'} but argument is of type 'void (*)(void *, char *, NI32,  void *)' {aka 'void 
(*)(void *, char *, int,  void *)'}
                                         esp_event_handler_t event_handler,
                                         ~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~
C:\Users\JoshGirvin\.nimble\pkgs\nesper-0.6.0\nesper\events.nim:39:164: warning: passing argument 3 of 'esp_event_handler_register' from incompatible pointer type [-Wincompatible-pointer-types]
             esp_event_handler_register(
                                                                                                                                                                    ^
In file included from C:/Espressif/frameworks/esp-idf-v4.1.2/components/esp_wifi/include/esp_wifi.h:64,
                 from ../main/nimcache/@msetup_wifi.nim.c:7:
C:/Espressif/frameworks/esp-idf-v4.1.2/components/esp_event/include/esp_event.h:146:61: note: expected 'esp_event_handler_t' {aka 'void (*)(void *, const char *, int,  void *)'} but argument is of type 'void (*)(void *, char *, NI32,  void *)' {aka 'void 
(*)(void *, char *, int,  void *)'}
                                         esp_event_handler_t event_handler,
                                         ~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~
C:\Users\JoshGirvin\.nimble\pkgs\nesper-0.6.0\nesper\events.nim: In function 'wifiStop__setup95wifi_207':
C:\Users\JoshGirvin\.nimble\pkgs\nesper-0.6.0\nesper\events.nim:124:82: warning: passing argument 3 of 'esp_event_handler_unregister' from incompatible pointer type [-Wincompatible-pointer-types]
     let ret = esp_event_handler_unregister(
                                                                                  ^
In file included from C:/Espressif/frameworks/esp-idf-v4.1.2/components/esp_wifi/include/esp_wifi.h:64,
                 from ../main/nimcache/@msetup_wifi.nim.c:7:
C:/Espressif/frameworks/esp-idf-v4.1.2/components/esp_event/include/esp_event.h:197:107: note: expected 'esp_event_handler_t' {aka 'void (*)(void *, const char *, int,  void *)'} but argument is of type 'void (*)(void *, char *, NI32,  void *)' {aka 'void (*)(void *, char *, int,  void *)'}
 esp_err_t esp_event_handler_unregister(esp_event_base_t event_base, int32_t event_id, esp_event_handler_t event_handler);
                                                                                       ~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~
C:\Users\JoshGirvin\.nimble\pkgs\nesper-0.6.0\nesper\events.nim:124:82: warning: passing argument 3 of 'esp_event_handler_unregister' from incompatible pointer type [-Wincompatible-pointer-types]
     let ret = esp_event_handler_unregister(
                                                                                  ^

Thanks for following the above.

It looks like the esp 4.1+ library uses a custom esp_ip4_addr_t type. I've moved away from Nesper/esp-idf for Zephyr so I haven't followed up on this. It's still possible to directly copy the esp-idf examples to setup wifi without using the Nesper convenience wrappers. It works but is more verbose. The basic process is to copy the wifi example you want and use Nesper headers and/or c2nim to directly copy the esp-idf wifi examples.

@elcritch I've got a question for you around uarts.nim -- is it working/tested? I'm attempting to do a simple AT command to a modem, and as long as I send an incorrect AT, it works, but once its correct and a real response happens, urt1.read() causes a StoreError and crashes the whole thing.

Excuse my shitty code;

import nesper/general, nesper/uarts, nesper/gpios, nesper/tasks
import ./example

proc sendAT() =
    var conf = newUartConfig(
        stop_bits = UART_STOP_BITS_1, 
        data_bits = UART_DATA_8_BITS,
        parity = UART_PARITY_DISABLE)
    var urt1 = newUart(
        uart_num = UART_NUM_1,
        config = conf,
        tx_pin = gpios.GPIO_NUM_17, 
        rx_pin = gpios.GPIO_NUM_16, 
        buffer = 2048.SzBytes)

    while true:
        urt1.write("AT\r")
        var buff = urt1.read()
        # debugEcho $buff
        vTaskDelay(300)

app_main():
    debugEcho "Hello, world"

    example.run()

    sendAT()

    assert false, "Should never get here"

As a second broader question, FreeRTOS's xTaskCreate -- while I did technically manage to pass a proc to it with the right signature, it crashes with a Stack Overflow. Is there are better way of approaching it other than FreeRTOS's functions? Should I use pthreads instead for handling stuff like this, or Nim level task stuff?

Obviously std/tasks requires ORC instead of ARC, is that an issue?

@elcritch Okay so I was a moron for my second question and my stack size was too small for my task.

For my first question, I inlined the uarts/read proc with a heap of debug statements to see whats happening

And, weirdly, it appears its dying when crafting nb

    while true:
        echo "Writing to the uart..."
        urt1.write("AT\r")
        # var buff = urt1.read()
        # debugEcho $buff
        echo "Here is where I'd read it..."

        ##### TIME FOR SOME COPY-PASTE
        debugEcho "DEBUG: \tGetting buffered data length..."
        var bytes_avail = csize_t(0)
        check: uart_get_buffered_data_len(urt1.port, addr bytes_avail)

        debugEcho "DEBUG: \tChecking whether we got a result..."
        if bytes_avail == 0:
            echo "No bytes returned!"

        else:
            debugEcho "DEBUG: \tCreating a new buffer..."
            var buff = newSeq[byte](bytes_avail)
            debugEcho "DEBUG: \tReading into that buffer..."
            let
                bytes_read = uart_read_bytes(urt1.port, addr(buff[0]), 1024, 10)
            
            debugEcho "DEBUG: \tRead into buffer, now checking bytes read..."
            if bytes_read < 0:
                debugEcho "DEBUG: \tWe're in bytes read..."
                var bytes_read_str = $bytes_read
                raise newEspError[EspError]("uart error: " & $bytes_read_str, bytes_read)

            debugEcho "DEBUG: \tCrafting result..."
            var nb = buff[0..<bytes_read]
            echo $nb

        vTaskDelay(300)

Result:

Writing to the uart...
Here is where I'd read it...
DEBUG:  Getting buffered data length...
DEBUG:  Checking whether we got a result...
DEBUG:  Creating a new buffer...
DEBUG:  Reading into that buffer...
DEBUG:  Read into buffer, now checking bytes read...
DEBUG:  Crafting result...
@[13, 10, 79, 75, 13, 10]
Writing to the uart...
Here is where I'd read it...
DEBUG:  Getting buffered data length...
DEBUG:  Checking whether we got a result...
No bytes returned!
Writing to the uart...
Here is where I'd read it...
DEBUG:  Getting buffered data length...
DEBUG:  Checking whether we got a result...
DEBUG:  Creating a new buffer...
DEBUG:  Reading into that buffer...
DEBUG:  Read into buffer, now checking bytes read...
DEBUG:  Crafting result...
Guru Meditation Error: Core  0 panic'ed (StoreProhibited). Exception was unhandled.

Core  0 register dump:
PC      : 0x4008a505  PS      : 0x00060a33  A0      : 0x8008ae1a  A1      : 0x3ffb9ab0
A2      : 0x3ffb3404  A3      : 0xa5a5a5a5  A4      : 0x00000008  A5      : 0x3ffaf100
A6      : 0x00000001  A7      : 0x00000000  A8      : 0x3ffb6200  A9      : 0x3ffb6214
A10     : 0x00000008  A11     : 0x00000015  A12     : 0x0a0d4b3b  A13     : 0x3ffb6208
A14     : 0x0a0d4b4c  A15     : 0xfffffffc  SAR     : 0x00000016  EXCCAUSE: 0x0000001d
EXCVADDR: 0xa5a5a5b1  LBEG    : 0x4000c349  LEND    : 0x4000c36b  LCOUNT  : 0xffffffff

Backtrace:0x4008a502:0x3ffb9ab0 0x4008ae17:0x3ffb9ad0 0x40082281:0x3ffb9af0 0x400822b1:0x3ffb9b10 0x4008b270:0x3ffb9b30 0x4008b294:0x3ffb9b50 0x400d2eb9:0x3ffb9b70 
0x400d2ec9:0x3ffb9b90 0x400d49be:0x3ffb9bb0 0x400d4bb8:0x3ffb9bf0 0x400d4f38:0x3ffb9c10 0x400d65c4:0x3ffb9c60 0x400d65e1:0x3ffb9c80 0x400d686b:0x3ffb9ca0 0x400d2124:0x3ffb9d00 0x40088e25:0x3ffb9ef0

Lastly, it appears to work once! Then crash with that error above.

Hello, Nim!
␛[0;32mI (318) my own TAG: Done.␛[0m
Writing to the uart...
Here is where I'd read it...
DEBUG:  Getting buffered data length...
DEBUG:  Checking whether we got a result...
DEBUG:  Creating a new buffer...
DEBUG:  Reading into that buffer...
DEBUG:  Read into buffer, now checking bytes read...
DEBUG:  Crafting result...

OK

Writing to the uart...
Here is where I'd read it...
DEBUG:  Getting buffered data length...
DEBUG:  Checking whether we got a result...
No bytes returned!
Writing to the uart...
Here is where I'd read it...
DEBUG:  Getting buffered data length...
DEBUG:  Checking whether we got a result...
DEBUG:  Creating a new buffer...
DEBUG:  Reading into that buffer...
DEBUG:  Read into buffer, now checking bytes read...
DEBUG:  Crafting result...
Guru Meditation Error: Core  0 panic'ed (StoreProhibited). Exception was unhandled.

Core  0 register dump:
PC      : 0x4008a505  PS      : 0x00060a33  A0      : 0x8008ae1a  A1      : 0x3ffb9aa0
A2      : 0x3ffb3404  A3      : 0xa5a5a5a5  A4      : 0x00000008  A5      : 0x3ffaf100
A6      : 0x00000001  A7      : 0x00000000  A8      : 0x3ffb6200  A9      : 0x3ffb6214
A10     : 0x00000008  A11     : 0x00000015  A12     : 0x0a0d4b3b  A13     : 0x3ffb6208
A14     : 0x0a0d4b4c  A15     : 0xfffffffc  SAR     : 0x00000016  EXCCAUSE: 0x0000001d
EXCVADDR: 0xa5a5a5b1  LBEG    : 0x4000c349  LEND    : 0x4000c36b  LCOUNT  : 0xffffffff

Backtrace:0x4008a502:0x3ffb9aa0 0x4008ae17:0x3ffb9ac0 0x40082281:0x3ffb9ae0 0x400822b1:0x3ffb9b00 0x4008b270:0x3ffb9b20 0x4008b294:0x3ffb9b40 0x400d2d31:0x3ffb9b60 
0x400d2d41:0x3ffb9b80 0x400d4836:0x3ffb9ba0 0x400d4a30:0x3ffb9be0 0x400d4db0:0x3ffb9c00 0x400d643c:0x3ffb9c50 0x400d6459:0x3ffb9c70 0x400d66e3:0x3ffb9c90 0x400d214e:0x3ffb9cf0 0x40088e25:0x3ffb9ef0

That last error is a bit odd. There's a few possibilities.

            debugEcho "DEBUG: \tCrafting result..."
            var nb = buff[0..<bytes_read]

Perhaps you can try printing the part line:

            debugEcho "DEBUG: \tCrafting result...", repr(buff)

That'll print out the entire buffer. To get a better stack trace of the ESP32 stack trace you can use https://github.com/me-no-dev/EspExceptionDecoder which will let you select your firmware (binary). That'll let you see what's happening in ESP-IDF system.

Also you may need to check and handle the case where bytes_read == 0. That could cause a Nim exception.

@elcritch Yeah I do check bytes_read :)

So, interestingly, adding a vTaskDelay(1) after writing, but before reading, fixes the error it was throwing. Perhaps a race condition of some kind within the internal UART driver and how it integrates into Nim? Dunno, but either way that one is "solved" :)

A question for you: I'm attempting to move away from using FreeRTOS tasks (I wrapped the FreeRTOS.nim wrapper file with a more Nim-like interface) so I can use Nim's nice pthread integration, but no matter what I try I always get pthread: Failed to create task!

proc myMain() {.thread.} =
  echo "We're in the main thread"
  while true:
    discard sleep(10)

app_main():
  check: esp_pthread_init()

  # var cfg = esp_pthread_get_default_config()
  # cfg.stack_size = csize_t(1024 * 8)

  # check: esp_pthread_set_cfg(addr cfg)

  echo "Hello, Nim!"
  example.run()

  echo "Creating main thread..."
  var mainThread: Thread[void]
  createThread(mainThread, myMain)

  echo "Creating modemThread..."
  var modemThread: Thread[void]
  createThread(modemThread, sendAT)

  echo "Joining on them both..."
  joinThreads([mainThread, modemThread])

That esp_pthread_init is my wrapper over esp_pthread.h for the ESP-IDF specific extensions, but it still just won't work.

I have pthreads in the CMakeLists.txt file, it compiles no worries (both Nim and C) but it fails at runtime:

I (0) cpu_start: Starting scheduler on APP CPU.
Hello, Nim!
I (323) my own TAG: Done.
Creating main thread...
E (333) pthread: Failed to create task!

Ah... It's because I'm supposed to use import posix pthread procs, not Nim's threading support?

Not sure, I've only used xTaskCreate on FreeRTOS/esp-idf. The pthread integration might work, but requires the esp-idf pthread emulation layer to be enabled.