Added a GPIO to power on/off for external I2C sensor(s) (with LEDs)

Dependencies:   UniGraphic mbed vt100

18-Jun-2018 外部センサの電源オン・オフ機能は下位互換の為に無効になっていました。 この版で再度有効にしました。

edge_utils/edge_mgr.cpp

Committer:
Rhyme
Date:
2018-06-18
Revision:
1:8d65cfc3a2e2
Parent:
0:846e2321c637

File content as of revision 1:8d65cfc3a2e2:

#include "mbed.h"
#include "edge_mgr.h"
#include "af_attributes.h"

#include "edge_time.h"
#include "edge_pin.h"
#include "MMA8451Q.h"
#include "VEML6040.h"
#include "LM75B.h"
#include "SMTC502AT.h"
#include "PSE530.h"
#include <ILI9341.h>
#include "Arial12x12.h"
#include "Arial24x23.h"
#include "Arial28x28.h"

#include "edge_sensor.h"
#include "edge_accel.h"
#include "edge_color.h"
#include "edge_temp.h"
#include "edge_pressure.h"
#include "edge_reset_mgr.h"
#include "edge_chart.h"

#define MMA8451Q_I2C_ADDRESS 0x1C
#define VEML6040_I2C_ADDRESS 0x10
#define LM75B_I2C_ADDRESS    0x48
#define SO1602A_I2C_ADDRESS  0x3C

#define NUM_MAX_SENSOR 5

uint16_t attr_to_set[] = {
ATTR_ACCEL_PRESENT,
ATTR_COLOR0_PRESENT,
ATTR_COLOR1_PRESENT,
ATTR_TEMP0_PRESENT,
ATTR_GAS_PRESENT,
} ;

uint16_t attr_to_get[] = {
// accel
ATTR_ACCEL_ENABLE,
ATTR_ACCEL_INTERVAL,
// Color0
ATTR_COLOR0_ENABLE,
ATTR_COLOR0_INTERVAL,
ATTR_COLOR0_ITIME,
ATTR_COLOR0_PWM_PERIOD,
ATTR_COLOR0_PWM_TARGET,
ATTR_COLOR0_PWM_R,
ATTR_COLOR0_PWM_G,
ATTR_COLOR0_PWM_B,
// Color1
ATTR_COLOR1_ENABLE,
ATTR_COLOR1_INTERVAL,
ATTR_COLOR1_ITIME,
ATTR_COLOR1_PWM_PERIOD,
ATTR_COLOR1_PWM_TARGET,
ATTR_COLOR1_PWM_R,
ATTR_COLOR1_PWM_G,
ATTR_COLOR1_PWM_B,
// Temp
ATTR_TEMP0_INTERVAL,
ATTR_TEMP0_ENABLE,
// Gas Pressure
ATTR_GAS_ENABLE,
ATTR_GAS_INTERVAL,
ATTR_GAS_THR_MODE,
ATTR_GAS_THR_HIGH,
ATTR_GAS_THR_LOW,
0 } ;

bool            verbos = true ;
edge_sensor     *sensor[NUM_MAX_SENSOR] ;
int             num_sensor   = 0 ;

edge_accel      *accel       = 0 ;
edge_color      *color[2]    = {0, 0} ;
edge_temp       *temp        = 0 ;
edge_pressure   *pressure    = 0 ;

PwmOut          *led[3]      = {0, 0, 0} ;
uint16_t        pwm[3]       = { 0x5FA2, 0xB09B, 0x83DF } ;
I2C             *edge_i2c0   = 0 ;
I2C             *edge_i2c1   = 0 ;
ILI9341         *display     = 0 ;
MMA8451Q        *mma8451q    = 0 ;
VEML6040        *veml6040[2] = { 0, 0 } ;
LM75B           *lm75b0      = 0 ; /* for temp1 */
AnalogIn        *an0         = 0 ; /* for temp2 */
SMTC502AT       *smtc502at0  = 0 ;
AnalogIn        *an1         = 0 ; /* for temp3 */
SMTC502AT       *smtc502at1  = 0 ;
LM75B           *lm75b1      = 0 ; /* for temp4 */
AnalogIn        *an2         = 0 ; /* for gas pressure */
PSE530          *pse530      = 0 ; /* gas pressure sensor */

DigitalOut      *tft_reset   = 0 ;
DigitalOut      *tft_backlight = 0 ;
DigitalOut      *tft_cs       = 0 ;
DigitalOut      *pse530_en    = 0 ;
DigitalOut      *color_en     = 0 ;

static int error_tolerance   = 100 ;
static int loop_interval     = 100 ; // 1000 ; 
static int accel_interval    = 10 ;
int        edge_mgr_status   = EDGE_MGR_INIT ;
char       *reset_reason_str = 0 ;
int        display_mode      = 1 ;
bool       reboot_requested  = false ;

/* following two functions are for test power on/off of color sensor */
void   enable_color_sensor(void) 
{
    if (color_en == 0) {
        printf("Color Enable Pin is not initiated\n") ;
    } else {
        *color_en = 0 ;
    }
}   
    
void   disable_color_sensor(void) 
{
    if (color_en == 0) {
        printf("Color Enable Pin is not initiated\n") ;
    } else {
        *color_en = 1 ;
    }    
}

void init_display(void)
{
reset_watch_dog() ;
    printf("TFT Initializing\n") ;
    tft_reset = new DigitalOut(PIN_RESET_TFT, 1) ;
    tft_backlight = new DigitalOut(PIN_BL_TFT, 0) ;
    tft_cs = new DigitalOut(PIN_CS_TFT, 1) ;

reset_watch_dog() ;
    display = new ILI9341(SPI_8, 10000000,
                PIN_MOSI, PIN_MISO, PIN_SCK,
                PIN_CS_TFT, PIN_RESET_TFT, PIN_DC_TFT, "LaSuno") ;

reset_watch_dog() ;
    display->BusEnable(true) ;
    display->set_orientation(1) ;
    
reset_watch_dog() ;
    display->cls() ;
    *tft_backlight = 1 ;
    display->BusEnable(false) ;
    printf("TFT Initialized\n") ;
}

void   edge_splash(void) 
{
    printf("Sensor loop started!\n") ;
    if (display) {
        reset_watch_dog() ;
        display->BusEnable(true) ;
        display->cls() ;
        display->foreground(Green) ;
        display->locate(40, 20) ;
        display->printf("Sensor Loop") ;
        display->locate(40, 60) ;
        display->printf("  Started!") ;
        display->BusEnable(false) ;
        reset_watch_dog() ;
    }
}

int init_edge_attribute(void)
{
    static int sensor_index = 0 ;
    static int attr_index = 0 ;
    static int error_count = 0 ;
    int return_value = 1 ;
    int result ;
    
    reset_watch_dog() ;
    
    if (reset_reason_str) { 
        result = afero->setAttribute(ATTR_MCU_RESET_REASON, reset_reason_str) ;
        if (result == afSUCCESS) {
            error_count = 0 ;
            reset_reason_str = 0 ;
        } else {
            error_count++ ;
        }
        reset_watch_dog() ;
    }
    if (sensor_index < NUM_MAX_SENSOR) {// for each sensor send presence
// printf("Setting sensor[%d] presence\n", sensor_index) ;
        if (sensor_index == 3) { /* for temp lm75b0 is used */
            result = afero->setAttributeBool(attr_to_set[sensor_index], lm75b0) ;
        } else {
            result = afero->setAttributeBool(attr_to_set[sensor_index], sensor[sensor_index]) ;
        }
        if (result == afSUCCESS) {
            error_count = 0 ;
            sensor_index++ ;
        } else {
            error_count++ ;
        }
        reset_watch_dog() ;
    } else { // all sensor presence sent, now get attributes
        if (attr_to_get[attr_index] != 0) {
// printf("getting attribute [%d]\n", attr_index) ;
            result = afero->getAttribute(attr_to_get[attr_index]) ;
            if (result == afSUCCESS) {
                error_count = 0 ;
                attr_index++ ;
            } else {
                error_count++ ;
            }
        }
        reset_watch_dog() ;
    }
    
    if (error_count > error_tolerance) { // too many fails, trying reset
        reset_watch_dog() ;
        reboot_edge() ;
    }
 
    if ((sensor_index >= NUM_MAX_SENSOR)&&(attr_to_get[attr_index] == 0)) { /* all sensors attributes done */
        sensor_index = 0 ;
        attr_index = 0 ;
        return_value = 0 ;
    }
    return(return_value) ;
}

void edge_loop(uint32_t count_robin)
{
    static int sensor_index = 0 ;
    int result ;
    
    reset_watch_dog() ;
    
    if ((count_robin % accel_interval) == 0) {
        if (accel) {
            accel->accum() ; /* get and accum accel data */
        }
        reset_watch_dog() ;
    }

    if ((count_robin % loop_interval) == 0) {
        reset_watch_dog() ;
        loop_interval = 10 ;
        if ((sensor[sensor_index])&&(sensor[sensor_index]->isEnabled())) {
            switch(sensor_index) {
            case SENSOR_ID_COLOR1: /* color0 */
                if (((edge_color*)sensor[sensor_index])->calibration_requested()) {
                    ((edge_color*)sensor[sensor_index])->calibrate(color0_target, color0_pwm, 10) ;
                    reset_watch_dog() ;
                    while((result = afero->setAttribute32(ATTR_COLOR0_PWM_R, color0_pwm[0])) != afSUCCESS) { 
                        reset_watch_dog() ;
                        print_af_error(result) ;
                        wait_ms(10) ;
                    }
                    while((result = afero->setAttribute32(ATTR_COLOR0_PWM_G, color0_pwm[1])) != afSUCCESS) {
                        reset_watch_dog() ;
                        print_af_error(result) ;
                        wait_ms(10) ;
                    } 
                    while((result = afero->setAttribute32(ATTR_COLOR0_PWM_B, color0_pwm[2])) != afSUCCESS) {
                        reset_watch_dog() ;
                        print_af_error(result) ;
                        wait_ms(10) ;
                    }
                    while((afero->setAttributeBool(ATTR_COLOR0_CALIBRATE, false)) != afSUCCESS) {
                        reset_watch_dog() ;     
                        print_af_error(result) ;
                        wait_ms(10) ;
                    }
                } else { 
                    sensor[sensor_index]->runStateMachine() ;
                }
                break ;
            case SENSOR_ID_COLOR2: /* color1 */
                if (((edge_color*)sensor[sensor_index])->calibration_requested()) {
                    ((edge_color*)sensor[sensor_index])->calibrate(color1_target, color1_pwm, 10) ;
                    reset_watch_dog() ;
                    if ((result = afero->setAttribute32(ATTR_COLOR1_PWM_R, color1_pwm[0])) != afSUCCESS) {
                        reset_watch_dog() ;
                        print_af_error(result) ;
                        wait_ms(10) ;
                    }
                    if ((result = afero->setAttribute32(ATTR_COLOR1_PWM_G, color1_pwm[1])) != afSUCCESS) {
                        reset_watch_dog() ;
                        print_af_error(result) ;
                        wait_ms(10) ;
                    }
                    reset_watch_dog() ;
                    if ((result = afero->setAttribute32(ATTR_COLOR1_PWM_B, color1_pwm[2])) != afSUCCESS) {
                        reset_watch_dog() ;       
                        print_af_error(result) ;
                        wait_ms(10) ;
                    }
                    while((afero->setAttributeBool(ATTR_COLOR1_CALIBRATE, false)) != afSUCCESS) {
                        reset_watch_dog() ;     
                        print_af_error(result) ;
                        wait_ms(10) ;
                    }
                } else { 
                    sensor[sensor_index]->runStateMachine() ;
                }
                break ;
            default:
                sensor[sensor_index]->runStateMachine() ;
                break ;
            }
        }
        sensor_index = (sensor_index + 1) % NUM_MAX_SENSOR ;
    }
    reset_watch_dog() ;
}

int is_present(I2C *i2c, int address)
{
    char t[1] = { 0 } ;
    char data[2] = { 0, 0 } ;
    int result ;
    address <<= 1 ;
    result = i2c->write(address, t, 1, true) ;
    if (result == 0) {
        result = i2c->read(address, data, 2) ;
    }
    return((result == 0)) ;    
}

/**
 * check_i2c_pins
 * To avoid I2C dead-lock condition,
 * check status of SDA and SCL.
 * As they are supposed to be HIGH
 * in case one of them is/are LOW,
 * change SCL pin to a digital out pin and
 * generate forced clock for a several cycles.
 * and when SDA come back to High returns
 * or I2C_UNLOCK_TRIAL_CYCLE exceeds, give up.
 */ 
#define I2C_UNLOCK_TRIAL_CYCLE 50

void check_i2c_pins(PinName sda_pin, PinName scl_pin, int number)
{
    DigitalIn *sda_in = 0 ; 
    DigitalIn *scl_in = 0 ;
    DigitalOut *scl_out = 0 ;
    int count = 0 ;
    sda_in = new DigitalIn(sda_pin, PullUp) ;
    scl_in = new DigitalIn(scl_pin, PullUp) ;
    printf("I2C%d pin ", number) ;
    if ((*sda_in == 0) || (*scl_in == 0)) { /* bus hang! */
        printf("hang detected, trying to clear ... ") ;
        delete scl_in ;
        scl_in = 0 ;
        scl_out = new DigitalOut(scl_pin) ;
        while((*sda_in == 0)&&(count++ > I2C_UNLOCK_TRIAL_CYCLE)) {
            *scl_out = 0 ;
            wait(0.01) ;
            *scl_out = 1 ;
            wait(0.01) ;
        }
        if (*sda_in != 0) {
            printf("Cleared!\n") ;
        } else {
            printf("Failed to Clear, proceeding\n") ;
        }
    } else {
        printf("condition OK\n") ;
    }
    if (sda_in) { delete sda_in ; }
    if (scl_in) { delete scl_in ; }
    if (scl_out) { delete scl_out ; }
}

void init_sensors(void)
{
    printf("=== Initializing Sensor(s) ===\n") ;    
#if 1 
    color_en = new DigitalOut(PIN_COLOR_EN, 0) ;
    *color_en = 0 ; /* enable */
    *color_en = 1 ; /* disable */
    wait_ms(100) ;
    *color_en = 0 ; /* enable */
    wait_ms(10) ;
#endif
    
    check_i2c_pins(PIN_I2C0_SDA, PIN_I2C0_SCL, 0) ;
    edge_i2c0 = new I2C(PIN_I2C0_SDA, PIN_I2C0_SCL) ;
    
    check_i2c_pins(PIN_I2C1_SDA, PIN_I2C1_SCL, 1) ;
    edge_i2c1 = new I2C(PIN_I2C1_SDA, PIN_I2C1_SCL) ;
                
    if (display) {
reset_watch_dog() ;
printf("printing inital string to TFT\n") ;
        display->BusEnable(true) ;


    display->background(Black) ;
    display->foreground(White) ;
reset_watch_dog() ;
    display->cls() ;
reset_watch_dog() ;
        display->set_font((unsigned char*) Arial24x23);
        display->foreground(Green) ;
        display->locate(70, 5) ;
        display->printf("Suntory") ;
        display->locate(30, 30) ;
        display->printf("Server Monitor") ;
        display->set_font((unsigned char*) Arial28x28);
        display->foreground(White) ;
        display->locate(30, 60) ;
        display->printf("La Suno") ;
        display->locate(30, 100) ;
        display->foreground(Red) ;
        display->printf("Preparing...") ;
    display->BusEnable(true) ;
    printf("Done\n") ;
    wait(0.1) ;
reset_watch_dog() ;
    display->cls() ;
    display->foreground(Yellow) ;
    display->locate(40, 5) ;
    display->printf("Probing sensors...") ;
    display->foreground(Green) ;
    display->BusEnable(false) ;
    }
reset_watch_dog() ;
    if (is_present(edge_i2c1, MMA8451Q_I2C_ADDRESS)) {
        printf("MMA8451Q on I2C1 is present\n") ;
        if (display) {
            display->BusEnable(true) ;
            display->locate(30, num_sensor * 30 + 40) ;
            display->printf("ACCEL is present") ;
            display->BusEnable(false) ;
        }
        mma8451q = new MMA8451Q(edge_i2c1, MMA8451Q_I2C_ADDRESS) ;
        accel    = new edge_accel(mma8451q) ;
        sensor[SENSOR_ID_ACCEL] = accel ;
        sensor[SENSOR_ID_ACCEL]->setId(SENSOR_ID_ACCEL) ;
        num_sensor++ ;
    } else {
        sensor[SENSOR_ID_ACCEL] = 0 ;
        printf("MMA8451Q is absent\n") ;
    }
reset_watch_dog() ;   
    if (is_present(edge_i2c1, VEML6040_I2C_ADDRESS)) {
        printf("VEML6040 on I2C1 is present\n") ;  
        if (display) {
            display->BusEnable(true) ;
            display->locate(30, num_sensor * 30 + 40) ;
            display->printf("COLOR1 is present") ;
            display->BusEnable(false) ;
        }  
        veml6040[0] = new VEML6040(edge_i2c1, VEML6040_I2C_ADDRESS) ;
        led[0] = new PwmOut(PIN_LED_R) ; 
        led[1] = new PwmOut(PIN_LED_G) ; 
        led[2] = new PwmOut(PIN_LED_B) ; 
        color[0] = new edge_color(veml6040[0], led, pwm) ;
        sensor[SENSOR_ID_COLOR1] = color[0] ;
        sensor[SENSOR_ID_COLOR1]->setId(SENSOR_ID_COLOR1) ;
        num_sensor++ ;
    } else {
        sensor[SENSOR_ID_COLOR1] = 0 ;
        printf("VEML6040 on I2C1 is absent\n") ;
    }
reset_watch_dog() ;    
    if (is_present(edge_i2c0, VEML6040_I2C_ADDRESS)) {
        printf("VEML6040 on I2C0 is present\n") ;  
        if (display) {
            display->BusEnable(true) ;
            display->locate(30, num_sensor * 30 + 40) ;
            display->printf("COLOR2 is present") ;
            display->BusEnable(false) ;
        }   
        veml6040[1] = new VEML6040(edge_i2c0, VEML6040_I2C_ADDRESS) ;
        if (led[0] == 0) {
            led[0] = new PwmOut(PIN_LED_R) ;
            led[1] = new PwmOut(PIN_LED_G) ;
            led[2] = new PwmOut(PIN_LED_B) ;
        }
        color[1] = new edge_color(veml6040[1], led, pwm) ;
        sensor[SENSOR_ID_COLOR2] = color[1] ;
        sensor[SENSOR_ID_COLOR2]->setId(SENSOR_ID_COLOR2) ;
        num_sensor++ ;
    } else {
        sensor[SENSOR_ID_COLOR2] = 0 ;
        printf("VEML6040 on I2C0 is absent\n") ;
    }
reset_watch_dog() ;    
    if (is_present(edge_i2c1, LM75B_I2C_ADDRESS)) {
        printf("LM75B on I2C1 is present\n") ;
        if (display) {
            display->BusEnable(true) ;
            display->locate(30, num_sensor * 30 + 40) ;
            display->printf("TEMP1 is present") ;
            display->BusEnable(false) ;
        }   
        lm75b0 = new LM75B(edge_i2c1, LM75B_I2C_ADDRESS) ;
    } else {
        printf("LM75B on I2C1 is absent\n") ;
    }
#if 0    
    if (is_present(edge_i2c0, LM75B_I2C_ADDRESS)) {
        printf("LM75B on I2C0 is present\n") ;
        lm75b1 = new LM75B(edge_i2c0, LM75B_I2C_ADDRESS) ;
    } else {
        printf("LM75B on I2C0 is absent\n") ;
    }
#endif  
     if (display) { /* press is present anyway */
        display->BusEnable(true) ;
        if (lm75b0) {
            display->locate(30, (num_sensor+1) * 30 + 40) ;
        } else {
            display->locate(30, num_sensor * 30 + 40) ;
        }
        display->printf("PRESS is present") ;
        display->BusEnable(false) ;
    }  
reset_watch_dog() ;    
    an0        = new AnalogIn(PIN_AN0) ;
    smtc502at0 = new SMTC502AT(an0) ;
    an1        = new AnalogIn(PIN_AN1) ;
    smtc502at1 = new SMTC502AT(an1) ;
    temp       = new edge_temp(lm75b0, smtc502at0, smtc502at1, lm75b1) ;
    sensor[SENSOR_ID_TEMP]  = temp ;
    sensor[SENSOR_ID_TEMP]->setId(SENSOR_ID_TEMP) ;
    num_sensor++ ;
    

reset_watch_dog() ;    
    an2        = new AnalogIn(PIN_AN2) ;
    pse530_en  = new DigitalOut(PIN_PRESS_EN, 0) ;
    pse530     = new PSE530(an2) ;
    pressure   = new edge_pressure(pse530, pse530_en) ;
    sensor[SENSOR_ID_PRESS]  = pressure ;
    sensor[SENSOR_ID_PRESS]->setId(SENSOR_ID_PRESS) ;
    num_sensor++ ;
 
reset_watch_dog() ;
    if (num_sensor > 0) {
        printf("%d edge_sensor(s) registered\n", num_sensor) ;
        printf("Edge is waiting for ASR to link\n") ;
        if (display) {
            display->BusEnable(true) ;
            display->foreground(White) ;
            display->locate(40, 200) ;
            display->printf("Waiting for ASR") ;
            display->BusEnable(false) ;
        }
    }
reset_watch_dog() ;
}

void enable_sensors(void) 
{
    int i ;
    for (i = 0 ; i < NUM_MAX_SENSOR ; i++ ) {
        if (sensor[i]) {
            sensor[i]->enable() ;
        }
    }
}

void disable_sensors(void)
{
    int i ;
    for (i = 0 ; i < NUM_MAX_SENSOR ; i++ ) {
        if (sensor[i]) {
            sensor[i]->disable() ;
        }
    }
}

void   reboot_edge(void) 
{
    int i ;
    reset_watch_dog() ;
    disable_sensors() ;
    reset_watch_dog() ;
    if (display) {
        delete display ;
        display = 0 ;
    }
    for (i = 0 ; i < NUM_MAX_SENSOR ; i++ ) {
        if (sensor[i]) {
            reset_watch_dog() ;
            delete sensor[i] ;
            sensor[i] = 0 ;
        }
    }
    reset_watch_dog() ;
    software_reset() ;
}