Close

Some Software - Very early test code

A project log for ESP8266 Interrupt Driven Meter Monitor

A network node that will sit in my meter box and read meter pulses. The node will store accumulated readings based on pulses/min.

stuart gogginstuart goggin 03/10/2015 at 13:250 Comments

Here is some sample code that seems to work OK. Need to test with a real pulse generator.

big thanks to http://www.limpkin.fr/index.php?post/2014/12/07/First-Steps-with-the-ESP8266-03-Development-Board

on which this code is based.

#include "c_types.h"
#include "ip_addr.h"
#include "ets_sys.h"
#include "espconn.h"
#include "osapi.h"
#include "mem.h"
#include "gpio.h"
#include "os_type.h"
#include "user_config.h"
#include "user_interface.h"
#include "driver/uart.h"

#define user_procTaskPrio        0
#define user_procTaskQueueLen    1

void ICACHE_FLASH_ATTR network_init();

os_event_t    user_procTaskQueue[user_procTaskQueueLen];
static void user_procTask(os_event_t *events);

static volatile os_timer_t pulse_timer;
static volatile os_timer_t debounce;
LOCAL os_timer_t network_timer;

static struct espconn global_udp_connect;                   // Connection struct (see espconn.h)
static esp_tcp global_tcp;                                  // TCP connect var (see espconn.h)
static struct espconn global_tcp_connect;                   // Connection struct (see espconn.h)
static uint8_t udp_conn_ok = FALSE;                         // Bool to know if udp connection set
static uint8_t tcp_conn_ok = FALSE;                         // Bool to know if tcp connection set
static uint16_t doppler_counter = 0;                        // Doppler counter
static uint16_t pulse_count =0;

char* itoa(int i, char b[])  // Convert Integer to ASCII!!
{
    char const digit[] = "0123456789";
    char* p = b;
    if(i<0){
        *p++ = '-';
        i *= -1;
    }
    int shifter = i;
    do{ //Move to where representation ends
        ++p;
        shifter = shifter/10;
    }while(shifter);
    *p = '\0';
    do{ //Move back, inserting digits as u go
        *--p = digit[i%10];
        i = i/10;
    }while(i);
    return b;
}

void debounce_func(void *arg)
//
// This routine is called on every INTERRUPT.  the idea is to increment a counter as many times as needed
// to record the pulse.  Due to noise, we need to implement a debounce algorithm.
// This is handled by the pulse timer func.
{
    ETS_GPIO_INTR_DISABLE();                        // Disable gpio interrupts
    uint16_t drop_copy = doppler_counter;           // copy doppler val
    doppler_counter = 0;                            // not good!
    ETS_GPIO_INTR_ENABLE();                         // Enable gpio interrupts
        
    if (drop_copy > 0)
    {
       pulse_count++;
    }
}

void pulse_timer_func(void *arg)
{
    uint16_t drop_copy = pulse_count;           // copy doppler val
    pulse_count = 0;                            // not good!

    if (GPIO_REG_READ(GPIO_OUT_ADDRESS) & BIT2)     // If GPIO2 high
    {
        gpio_output_set(0, BIT2, BIT2, 0);          // Set GPIO2 to LOW
    }
    else                                            // Else
    {
        gpio_output_set(BIT2, 0, BIT2, 0);          // Set GPIO2 to HIGH
    }

// Send pulse counter
    if (tcp_conn_ok == TRUE)
    {
        uint8_t data[10] = " \x00\x00\x00\x00\x00";
        itoa(drop_copy, data+1);
        espconn_sent(&global_tcp_connect, data, 10);
        os_printf("%u\n\r",drop_copy);

    }
}

void doppler_int_handler(int8_t key)
{
    // Increment counter
    doppler_counter++;
    
    //Not that sure what this does yet and where the register is used for
    uint32 gpio_status = GPIO_REG_READ(GPIO_STATUS_ADDRESS);

    //clear interrupt status
    GPIO_REG_WRITE(GPIO_STATUS_W1TC_ADDRESS, gpio_status & BIT(0));
}

static void ICACHE_FLASH_ATTR tcpNetworkRecvCb(void *arg, char *data, unsigned short len) 
{
    struct espconn *tcpconn=(struct espconn *)arg;
}

static void ICACHE_FLASH_ATTR tcpNetworkConnectedCb(void *arg) 
{
    struct espconn *tcpconn=(struct espconn *)arg;
    espconn_regist_recvcb(tcpconn, tcpNetworkRecvCb);
    
    os_printf("TCP connected\n\r"); 
    uint8_t data[20] = "Hello you!\r\n";
    espconn_sent(tcpconn, data, 20);
    tcp_conn_ok = TRUE;
}

static void ICACHE_FLASH_ATTR tcpNetworkReconCb(void *arg, sint8 err) 
{
    os_printf("TCP reconnect\n\r");
    tcp_conn_ok = FALSE;
    network_init();
}

static void ICACHE_FLASH_ATTR tcpNetworkDisconCb(void *arg) 
{
    os_printf("TCP disconnect\n\r");
    tcp_conn_ok = FALSE;
    network_init();
}

static void ICACHE_FLASH_ATTR init_tcp_conn(void) 
{
    global_tcp_connect.type=ESPCONN_TCP;                                    // We want to make a TCP connection
    global_tcp_connect.state=ESPCONN_NONE;                                  // Set default state to none
    global_tcp_connect.proto.tcp=&global_tcp;                               // Give a pointer to our TCP var
    global_tcp_connect.proto.tcp->local_port=espconn_port();                // Ask a free local port to the API
    global_tcp_connect.proto.tcp->remote_port=888;                         // Set remote port (bcbcostam)
    global_tcp_connect.proto.tcp->remote_ip[0]=10;                          // Your computer IP
    global_tcp_connect.proto.tcp->remote_ip[1]=1;                           // Your computer IP
    global_tcp_connect.proto.tcp->remote_ip[2]=1;                         // Your computer IP
    global_tcp_connect.proto.tcp->remote_ip[3]=164;                         // Your computer IP

    espconn_regist_connectcb(&global_tcp_connect, tcpNetworkConnectedCb);   // Register connect callback
    espconn_regist_disconcb(&global_tcp_connect, tcpNetworkDisconCb);       // Register disconnect callback
    espconn_regist_reconcb(&global_tcp_connect, tcpNetworkReconCb);         // Register reconnection function
    espconn_connect(&global_tcp_connect);                                   // Start connection
}


void ICACHE_FLASH_ATTR network_start(void) 
{   
    init_tcp_conn();            // Init tcp connection
}

void ICACHE_FLASH_ATTR network_check_ip(void)
{
    struct ip_info ipconfig;

    os_timer_disarm(&network_timer);                // Disarm timer
    wifi_get_ip_info(STATION_IF, &ipconfig);        // Get Wifi info

    if (wifi_station_get_connect_status() == STATION_GOT_IP && ipconfig.ip.addr != 0) 
    {
        network_start();                            // Everything in order
    }
    else 
    {
        os_printf("Waiting for IP...\n\r");
        os_timer_setfn(&network_timer, (os_timer_func_t *)network_check_ip, NULL);
        os_timer_arm(&network_timer, 10000, 0);
    }         
}

//Do nothing function
static void ICACHE_FLASH_ATTR user_procTask(os_event_t *events)
{
    os_delay_us(10);
}

// network init function
void ICACHE_FLASH_ATTR network_init()
{       
    os_timer_disarm(&network_timer);
    os_timer_setfn(&network_timer, (os_timer_func_t *)network_check_ip, NULL);
    os_timer_arm(&network_timer, 1000, 0);
}

//Init function 
void ICACHE_FLASH_ATTR user_init()
{    
    uart_init(BIT_RATE_57600, BIT_RATE_57600);                          // Init UART @ 57600 bps    
    
    ETS_GPIO_INTR_DISABLE();                                            // Disable gpio interrupts
    gpio_init();                                                        // Initialize the GPIO subsystem.


    ETS_GPIO_INTR_ATTACH(doppler_int_handler, 0);                      // GPIO0 interrupt handler
    PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDI_U, FUNC_GPIO0);                // Set GPIO0 function
    gpio_output_set(0, 0, 0, GPIO_ID_PIN(0));                          // Set GPIO0 as input
    GPIO_REG_WRITE(GPIO_STATUS_W1TC_ADDRESS, BIT(0));                  // Clear GPIO0 status
    gpio_pin_intr_state_set(GPIO_ID_PIN(0), 1);                        // Interrupt on any GPIO0 edge



    PIN_PULLDWN_DIS(PERIPHS_IO_MUX_MTCK_U);                             // Disable pulldown
    PIN_PULLUP_EN(PERIPHS_IO_MUX_MTCK_U);                               // Enable pullup
    ETS_GPIO_INTR_ENABLE();                                             // Enable gpio interrupts
    
    os_timer_disarm(&pulse_timer);                                        // Disarm led timer
    os_timer_setfn(&pulse_timer, (os_timer_func_t *)pulse_timer_func, NULL); // Setup led timer
    os_timer_arm(&pulse_timer, 1000, 1);                                   // Arm led timer, 0.5sec, repeat

    os_timer_disarm(&debounce);                                        // Disarm led timer
    os_timer_setfn(&debounce, (os_timer_func_t *)debounce_func, NULL); // Setup led timer
    os_timer_arm(&debounce, 100, 1);                                   // Arm led timer, 0.5sec, repeat

    
    network_init();                                                     // Init network timer
    
    char ssid[32] = "LightningStrikesTwice";                                 // Wifi SSID
    char password[64] = "97379039";                                // Wifi Password
    struct station_config stationConf;                                  // Station conf struct    
    wifi_set_opmode(0x1);                                               // Set station mode
    os_memcpy(&stationConf.ssid, ssid, 32);                             // Set settings
    os_memcpy(&stationConf.password, password, 64);                     // Set settings
    wifi_station_set_config(&stationConf);                              // Set wifi conf
    //wifi_status_led_install(13, PERIPHS_IO_MUX_MTCK_U, FUNC_GPIO13);  // Wifi LED status  
    
    //Start os task
    system_os_task(user_procTask, user_procTaskPrio,user_procTaskQueue, user_procTaskQueueLen);
    os_printf("\n\rStartup done\n\r");                                  // Startup done
}

Discussions