Copyright © https://mongoose-os.com

Mongoose OS Forum

frame

Arduino compat lib : implicit declaration of function 'pulseIn'

jameselseyjameselsey Melbourne, Australia

Hi folks!

Can someone please help me with the below?

Project:
ESP3 Lolin32 with a JSN SR04T (waterproof equivalent of HC SR04).

Issue:
Spent the morning searching forums / github examples but I'm a bit stuck, here's what I've done.

included the arduino compatability library in mos.yml

  - origin: https://github.com/mongoose-os-libs/arduino-compat

Added the build flag so the compat lib is loaded, couldn't see that mentioned in the docs, on a previous post here it was mentioned

build_vars:
  MGOS_ENABLE_ARDUINO_API: 1

Then in my main.c I have the following

#include <Arduino.h>

#define TRIGGER_PIN 16
#define ECHO_PIN 17

void setup(void) {
  pinMode(TRIGGER_PIN, OUTPUT); // Sets the TRIGGER_PIN as an Output
  pinMode(ECHO_PIN, INPUT); // Sets the ECHO_PIN as an Input
  printf("Starting up...\n");
}

void loop() {
  // Clears the TRIGGER_PIN
  digitalWrite(TRIGGER_PIN, LOW);
  delayMicroseconds(2);

  // Sets the TRIGGER_PIN on HIGH state for 10 micro seconds
  digitalWrite(TRIGGER_PIN, HIGH);
  delayMicroseconds(10);
  digitalWrite(TRIGGER_PIN, LOW);

  // Reads the ECHO_PIN, returns the sound wave travel time in microseconds
  unsigned long duration = pulseIn(ECHO_PIN, HIGH, 1000000L);

  // Calculating the distance
  double distance= duration*0.034/2;

  // Prints the distance on the Serial Monitor
  printf("Distance: %f\n", distance);
}

I try building and see the following error in the terminal

/fwbuild-volumes/1.23/apps/mongoose-os-apps-tank-sensor/esp32/build_contexts/build_ctx_587793180/src/main.c: In function 'loop':
/fwbuild-volumes/1.23/apps/mongoose-os-apps-tank-sensor/esp32/build_contexts/build_ctx_587793180/src/main.c:107:28: error: implicit declaration of function 'pulseIn' [-Werror=implicit-function-declaration]
   unsigned long duration = pulseIn(ECHO_PIN, HIGH, 1000000L);

Looks like it can't find the pulseIn function, however according to the Arduino.h mongoose docs it should be available, the same way that digitalWrite is, and I don't get errors on those.

Ultimately, I'm trying to wrap this Arduino tutorial in mongoose. Looks like pulseIn was requested about 6 months back, how can I get this working using arduino?

Thanks

Comments

  • jameselseyjameselsey Melbourne, Australia

    update:
    I've noticed that the mgos_arduino.cpp has digitalWrite function but not a pulseIn, I'm new to this but does that mean we don't have a mgos wrapper around it yet?

    How can I read a pulse on a GPIO pin then?

    Thanks

  • Yeah, it looks like pulseIn implementation is missing. Let me discuss the priority of that with the team.

  • jameselseyjameselsey Melbourne, Australia

    Thanks @dimonomid

    What do you think the ETA is likely to be on this feature?

    thanks

  • Sorry, can't be more specific than saying that it wasn't planned for the current week.

  • mtraxmtrax Canberra

    that would be great I was waiting for this for a while now, as I want to make a garage opener .

  • nliviunliviu Romania

    Quick port of pulseInLong inspired from https://github.com/arduino/Arduino/blob/8ffbe05437e4fa901eb32ae4e6e424f8402a75f1/hardware/arduino/avr/cores/arduino/wiring_pulse.c#L55

    uint32_t pulseInLong(uint8_t pin, uint8_t state, uint32_t timeout)
    {
        uint32_t startMicros = 1000000 * mgos_uptime();
    
        // wait for any previous pulse to end
        while (state == mgos_gpio_read(pin)) {
            if ((1000000 * mgos_uptime()) - startMicros > timeout) {
                return 0;
            }
        }
    
        // wait for the pulse to start
        while (state != mgos_gpio_read(pin)) {
            if ((1000000 * mgos_uptime()) - startMicros > timeout) {
                return 0;
            }
        }
    
        uint32_t start = 1000000 * mgos_uptime();
    
        // wait for the pulse to stop
        while (state == mgos_gpio_read(pin)) {
            if ((1000000 * mgos_uptime()) - startMicros > timeout) {
                return 0;
            }
        }
        return (1000000 * mgos_uptime())-start;
    }
    
    

    Did not test it, but it should work.

    Thanked by 1mtrax
  • mtraxmtrax Canberra

    thanks for the port we add this to our main.c correct?
    and then define FFI for function

    eg
    let f = ffi('long pulseInLong(int, int, int, long)');

    I haven't used these much just trying to confirm.

  • jameselseyjameselsey Melbourne, Australia

    Thanks nliviu,

    I've tried that but it's reporting 0 for pulseIn, quite possibly a timing issue on my side calling it, as I notice this from the link you referenced:

    Works on pulses from 2-3 microseconds
     to 3 minutes in length, but must be called at least a few dozen microseconds
     before the start of the pulse.
    

    This is my code:

    #include <stdio.h>
    #include "mgos.h"
    #include "mgos_app.h"
    #include "mgos_gpio.h"
    #include "mgos_timers.h"
    
    // // Define the GPIO pins 
    #define TRIGGER_PIN 16
    #define ECHO_PIN 17
    
    uint32_t pulseInLongLocal(uint8_t pin, uint8_t state, uint32_t timeout)
    {
        uint32_t startMicros = 1000000 * mgos_uptime();
    
        // wait for any previous pulse to end
        while (state == mgos_gpio_read(pin)) {
            printf("Waiting for previous pulse to end\n");
            if ((1000000 * mgos_uptime()) - startMicros > timeout) {
                return 0;
            }
        }
    
        // wait for the pulse to start
        while (state != mgos_gpio_read(pin)) {
            printf("Waiting for pulse to start\n");
            if ((1000000 * mgos_uptime()) - startMicros > timeout) {
                return 0;
            }
        }
    
        uint32_t start = 1000000 * mgos_uptime();
    
        // wait for the pulse to stop
        while (state == mgos_gpio_read(pin)) {
            printf("Waiting for pulse to end\n");
            if ((1000000 * mgos_uptime()) - startMicros > timeout) {
                return 0;
            }
        }
        return (1000000 * mgos_uptime())-start;
    }
    
    enum mgos_app_init_result mgos_app_init(void) {
      mgos_gpio_set_mode(TRIGGER_PIN, MGOS_GPIO_MODE_OUTPUT);
      mgos_gpio_set_mode(ECHO_PIN, MGOS_GPIO_MODE_INPUT);
    
      while(true){
        // Clears the trigPin
        mgos_gpio_write(TRIGGER_PIN, MGOS_GPIO_INT_LEVEL_LO);
        mgos_usleep(2);
        // Sets the trigPin on HIGH state for 10 micro seconds
        mgos_gpio_write(TRIGGER_PIN, MGOS_GPIO_INT_LEVEL_HI);
        mgos_usleep(10);
        mgos_gpio_write(TRIGGER_PIN, MGOS_GPIO_INT_LEVEL_LO);
        // Reads the echoPin, returns the sound wave travel time in microseconds
        // pulseInLongLocal(ECHO_PIN, HIGH, 1000000);
        unsigned long duration = pulseInLongLocal(ECHO_PIN, MGOS_GPIO_INT_LEVEL_HI, 1000000);
        printf("Duration from pulseIn was %lu\n", duration);
        // Calculating the distance
        double distance= duration*0.034/2;
        // Prints the distance on the Serial Monitor
        printf("Distance: %f\n", distance);
      }
    
      return MGOS_APP_INIT_SUCCESS;
    }
    
    

    The output I see is

    [Jan 25 19:32:50.499] Waiting for pulse to start
    [Jan 25 19:32:50.499] Waiting for pulse to start
    <snip...too many of these printed....>
    [Jan 25 19:32:51.499] Waiting for pulse to start
    [Jan 25 19:32:51.499] Waiting for pulse to start
    [Jan 25 19:32:51.499] Waiting for pulse to start
    [Jan 25 19:32:51.499] Duration from pulseIn was 0
    [Jan 25 19:32:51.499] Distance: 0.000000
    

    Could the pulse have already been received prior to checking for it?

  • nliviunliviu Romania

    It returns 0 because it reaches the timeout in the "// wait for the pulse to start loop.
    The printf in the loops is not a good idea. It takes a long time to execute.

    I wouln't run the sensor read in a while loop, but in a timer callback with at least a 60ms period as the datasheet recommends.

  • mtraxmtrax Canberra
    James, could you post code when you get it working, thanks
  • jameselseyjameselsey Melbourne, Australia

    A timer callback like this?

    #include <stdio.h>
    #include "mgos.h"
    #include "mgos_app.h"
    #include "mgos_gpio.h"
    #include "mgos_timers.h"
    
    // // Define the GPIO pins 
    #define TRIGGER_PIN 16
    #define ECHO_PIN 17
    
    uint32_t pulseInLongLocal(uint8_t pin, uint8_t state, uint32_t timeout)
    {
        uint32_t startMicros = 1000000 * mgos_uptime();
    
        // wait for any previous pulse to end
        while (state == mgos_gpio_read(pin)) {
            if ((1000000 * mgos_uptime()) - startMicros > timeout) {
                return 0;
            }
        }
    
        // wait for the pulse to start
        while (state != mgos_gpio_read(pin)) {
            if ((1000000 * mgos_uptime()) - startMicros > timeout) {
                return 0;
            }
        }
    
        uint32_t start = 1000000 * mgos_uptime();
    
        // wait for the pulse to stop
        while (state == mgos_gpio_read(pin)) {
            if ((1000000 * mgos_uptime()) - startMicros > timeout) {
                return 0;
            }
        }
        return (1000000 * mgos_uptime())-start;
    }
    
    
    static void timer_cb(void *arg) {
      // Clears the trigPin
      mgos_gpio_write(TRIGGER_PIN, MGOS_GPIO_INT_LEVEL_LO);
      mgos_usleep(2);
      // Sets the trigPin on HIGH state for 10 micro seconds
      mgos_gpio_write(TRIGGER_PIN, MGOS_GPIO_INT_LEVEL_HI);
      mgos_usleep(10);
      mgos_gpio_write(TRIGGER_PIN, MGOS_GPIO_INT_LEVEL_LO);
      // Reads the echoPin, returns the sound wave travel time in microseconds
      // timeout of 1 second
      unsigned long duration = pulseInLongLocal(ECHO_PIN, MGOS_GPIO_INT_LEVEL_HI, 1000000);
      // printf("Duration from pulseIn was %lu\n", duration);
      // Calculating the distance
      double distance= duration*0.034/2;
      // Prints the distance on the Serial Monitor
      printf("Distance: %f\n", distance);
      (void) arg;
    }
    
    enum mgos_app_init_result mgos_app_init(void) {
      // GPIO pins can work on input or output, as we're lighting LEDs, they
      // are all set to output
      mgos_gpio_set_mode(TRIGGER_PIN, MGOS_GPIO_MODE_OUTPUT);
      mgos_gpio_set_mode(ECHO_PIN, MGOS_GPIO_MODE_INPUT);
    
    
      // Every x second, invoke timer_cb. 2nd arg means repeat continuously
      mgos_set_timer(2000 , true , timer_cb, NULL);
    
      return MGOS_APP_INIT_SUCCESS;
    }
    

    I still get

    [Jan 25 20:34:02.477] Distance: 0.000000
    [Jan 25 20:34:04.477] Distance: 0.000000
    [Jan 25 20:34:06.477] Distance: 0.000000
    [Jan 25 20:34:08.477] Distance: 0.000000
    

    So the timer is running every 2 seconds, it tries to read the pulse with a 1 second timeout, that should be enough right?

  • nliviunliviu Romania
    edited January 25

    I don't have a HC-SR04 device, but I simulated it with a second ESP32 (slave).
    I send a 10 microseconds trigger pulse and 10 microseconds after the falling edge, the slave sends an impulse with a random period between 500 and 1000 microseconds.
    The code:

    static void hcInit(int triggerPin, int echoPin)
    {
        /*
         * Setup the trigger pin
         */
        mgos_gpio_set_mode(triggerPin, MGOS_GPIO_MODE_OUTPUT);
        mgos_gpio_write(triggerPin, 0);
    
        /*
         * Setup the echo pin
         */
        mgos_gpio_set_mode(echoPin, MGOS_GPIO_MODE_INPUT);
        mgos_gpio_set_pull(echoPin, MGOS_GPIO_PULL_UP);
    }
    
    static void hcRead(int triggerPin, int echoPin)
    {
        //send trigger
        mgos_gpio_write(triggerPin, 1);
        // wait 10 microseconds
        mgos_usleep(10);
        // stop the trigger
        mgos_gpio_write(triggerPin, 0);
    
        uint32_t t = pulseInLong(echoPin, 1, 1000000);
        LOG(LL_INFO, ("HS - t=%d", t));
    }
    

    Results:
    slave (delta is the duration of the pulse)

    [Jan 25 15:24:46.201] echo                 r=0.605348, delta=6250
    [Jan 25 15:24:56.197] echo                 r=0.101715, delta=1466
    [Jan 25 15:25:06.196] echo                 r=0.036162, delta=843
    [Jan 25 15:25:16.210] echo                 r=0.098999, delta=1440
    [Jan 25 15:25:26.199] echo                 r=0.100986, delta=1459
    [Jan 25 15:25:36.200] echo                 r=0.368493, delta=4000
    

    master (t is the read pulse width)

    [Jan 25 15:24:46.199] hcRead               HS - t=6255
    [Jan 25 15:24:56.195] hcRead               HS - t=1471
    [Jan 25 15:25:06.194] hcRead               HS - t=859
    [Jan 25 15:25:16.208] hcRead               HS - t=1441
    [Jan 25 15:25:26.197] hcRead               HS - t=1456
    [Jan 25 15:25:36.197] hcRead               HS - t=4008
    

    LE. Now I see you are using MGOS_GPIO_INT_LEVEL_HI and TRIGGER_PIN, MGOS_GPIO_INT_LEVEL_LO with mgos_gpio_write. You should use 1 and 0, or true and false.
    References:
    https://github.com/cesanta/mongoose-os/blob/255db7519a704ab8d0ce1728ccb9b7e99547f527/fw/include/mgos_gpio.h#L33
    https://github.com/cesanta/mongoose-os/blob/255db7519a704ab8d0ce1728ccb9b7e99547f527/fw/include/mgos_gpio.h#L54

  • nliviunliviu Romania

    Updated to avoid microseconds truncation to 32 bits after about 73 minutes uptime.

    static inline uint64_t uptime()
    {
        return (uint64_t) (1000000 * mgos_uptime());
    }
    
    uint32_t pulseInLong(uint8_t pin, uint8_t state, uint32_t timeout)
    {
        uint64_t startMicros = uptime();
    
        // wait for any previous pulse to end
        while (state == mgos_gpio_read(pin)) {
            if ((uptime() - startMicros) > timeout) {
                return 0;
            }
        }
    
        // wait for the pulse to start
        while (state != mgos_gpio_read(pin)) {
            if ((uptime() - startMicros) > timeout) {
                return 0;
            }
        }
    
        uint64_t start = uptime();
    
        // wait for the pulse to stop
        while (state == mgos_gpio_read(pin)) {
            if ((uptime() - startMicros) > timeout) {
                return 0;
            }
        }
        return (uint32_t) (uptime() - start);
    }
    
    
  • jameselseyjameselsey Melbourne, Australia

    haha I left it running overnight and wondered why it stopped reporting after an hour or so ;)

    Thanks for all your help nliviu, its now doing what I wanted. Any chance we might see that pulseIn added to the Mongoose OS?

    If anyone is interested, here's the full source, credits given to nliviu for the help

    https://github.com/jameselsey/mongoose-os-apps-tank-sensor

  • nliviunliviu Romania

    I filed a PR to include pulseInLong in the arduino-compat library https://github.com/mongoose-os-libs/arduino-compat/pull/4

    Thanked by 1mtrax
  • daviddavid india

    is the code same for esp8266?

Sign In or Register to comment.