I2C hang recover function added

Dependencies:   UniGraphic mbed vt100

In this version, check_i2c_pins function was added in edge_mgr.cpp.

プログラムの起動時、I2Cモジュールを初期化する前に、I2Cに使用するピンの電位を確認し
もし一方でも Low に張り付いていた場合、SCL を GPIO 出力に設定して 
所定回数 (I2C_UNLOCK_TRIAL_CYCLE) 反転させることにより、疑似リセットクロックを生成します。

その後は、通常の起動手順に復帰し、以降はこれまでと同様の動作をします。

Revision:
0:d895cd1cd897
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/af_utils/af_attriburtes.cpp	Tue Apr 03 08:30:29 2018 +0000
@@ -0,0 +1,692 @@
+#include "mbed.h"
+#include <ctype.h>
+#include "af_attributes.h"
+#include "edge_time.h"
+#include "edge_sensor.h"
+#include "edge_accel.h"
+#include "edge_color.h"
+#include "edge_temp.h"
+#include "edge_pressure.h"
+#include "edge_mgr.h"
+#include "edge_reset_mgr.h"
+// #include "SO1602A.h"
+#include <ILI9341.h>
+#include "pending.h"
+
+// extern SO1602A *display ;
+extern ILI9341 *display ;
+extern pending_class *pending ;
+
+static const af_attribute_type af_attr[] = {
+/*     ID,                     Description,                Type,                Size */
+    {  ATTR_SENSE_VAL,         "Sensor Value",             ATTRIBUTE_TYPE_UTF8S, 255 },
+    {  ATTR_ACCEL_PRESENT,     "Accel Present",            ATTRIBUTE_TYPE_BOOLEAN, 1 },
+    {  ATTR_ACCEL_ENABLE,      "Accel Enable",             ATTRIBUTE_TYPE_BOOLEAN, 1 },
+    {  ATTR_ACCEL_INTERVAL,    "Accel Interval",           ATTRIBUTE_TYPE_SINT16,  2 },
+    {  ATTR_ACCEL_VALUE,       "Accel Value",              ATTRIBUTE_TYPE_FIXED_15_16, 4},
+/* first color sensor (VEML6040) and LED set */    
+    {  ATTR_COLOR0_PRESENT,    "Color1 Present",           ATTRIBUTE_TYPE_BOOLEAN, 1 },
+    {  ATTR_COLOR0_ENABLE,     "Color1 Enable",            ATTRIBUTE_TYPE_BOOLEAN, 1 },
+    {  ATTR_COLOR0_INTERVAL,   "Color1 Interval",          ATTRIBUTE_TYPE_SINT16,  2 },
+    {  ATTR_COLOR0_TRIGMODE,   "Color1 Trigger Mode",      ATTRIBUTE_TYPE_SINT8,   1 },
+    {  ATTR_COLOR0_ITIME,      "Color1 Integration Time",  ATTRIBUTE_TYPE_SINT8,   1 },    
+    {  ATTR_COLOR0_CALIBRATE,  "Color1 Calibrate",         ATTRIBUTE_TYPE_BOOLEAN, 1 },
+    {  ATTR_COLOR0_PWM_R,      "Color1 PWM R",             ATTRIBUTE_TYPE_SINT32,  4 },
+    {  ATTR_COLOR0_PWM_G,      "Color1 PWM G",             ATTRIBUTE_TYPE_SINT32,  4 },
+    {  ATTR_COLOR0_PWM_B,      "Color1 PWM B",             ATTRIBUTE_TYPE_SINT32,  4 },
+    {  ATTR_COLOR0_PWM_PERIOD, "Color1 PWM Period",        ATTRIBUTE_TYPE_SINT16,  2 },
+    {  ATTR_COLOR0_PWM_TARGET, "Color1 PWM Target",        ATTRIBUTE_TYPE_SINT16,  2 },
+    {  ATTR_COLOR0_R_VALUE,    "Color1 R",                 ATTRIBUTE_TYPE_SINT16,  2 },
+    {  ATTR_COLOR0_G_VALUE,    "Color1 G",                 ATTRIBUTE_TYPE_SINT16,  2 },
+    {  ATTR_COLOR0_B_VALUE,    "Color1 B",                 ATTRIBUTE_TYPE_SINT16,  2 },
+/* second color sensor (VEML6040) and LED set */ 
+    {  ATTR_COLOR1_PRESENT,    "Color2 Present",           ATTRIBUTE_TYPE_BOOLEAN, 1 },
+    {  ATTR_COLOR1_ENABLE,     "Color2 Enable",            ATTRIBUTE_TYPE_BOOLEAN, 1 },
+    {  ATTR_COLOR1_INTERVAL,   "Color2 Interval",          ATTRIBUTE_TYPE_SINT16,  2 },
+    {  ATTR_COLOR1_TRIGMODE,   "Color2 Trigger Mode",      ATTRIBUTE_TYPE_SINT8,   1 },
+    {  ATTR_COLOR1_ITIME,      "Color2 Integration Time",  ATTRIBUTE_TYPE_SINT8,   1 },
+    {  ATTR_COLOR1_CALIBRATE,  "Color2 Calibrate",         ATTRIBUTE_TYPE_BOOLEAN, 1 },
+    {  ATTR_COLOR1_PWM_R,      "Color2 PWM R",             ATTRIBUTE_TYPE_SINT32,  4 },
+    {  ATTR_COLOR1_PWM_G,      "Color2 PWM G",             ATTRIBUTE_TYPE_SINT32,  4 },
+    {  ATTR_COLOR1_PWM_B,      "Color2 PWM B",             ATTRIBUTE_TYPE_SINT32,  4 },
+    {  ATTR_COLOR1_PWM_PERIOD, "Color2 PWM Period",        ATTRIBUTE_TYPE_SINT16,  2 },
+    {  ATTR_COLOR1_PWM_TARGET, "Color2 PWM Target",        ATTRIBUTE_TYPE_SINT16,  2 },
+    {  ATTR_COLOR1_R_VALUE,    "Color2 R",                 ATTRIBUTE_TYPE_SINT16,  2 },
+    {  ATTR_COLOR1_G_VALUE,    "Color2 G",                 ATTRIBUTE_TYPE_SINT16,  2 },
+    {  ATTR_COLOR1_B_VALUE,    "Color2 B",                 ATTRIBUTE_TYPE_SINT16,  2 },
+/* first temperature sensor (LM75B) */    
+    {  ATTR_TEMP0_PRESENT,    "Temp0 Present",             ATTRIBUTE_TYPE_BOOLEAN, 1 },
+    {  ATTR_TEMP0_ENABLE,     "Temp0 Enable",              ATTRIBUTE_TYPE_BOOLEAN, 1 },
+    {  ATTR_TEMP0_INTERVAL,   "Temp0 Interval",            ATTRIBUTE_TYPE_SINT16,  2 },
+    {  ATTR_TEMP0_VALUE,      "Temp0 Value",               ATTRIBUTE_TYPE_FIXED_15_16, 4},
+/* second temperature sensor (SMTC502AT/Before) */    
+    {  ATTR_TEMP1_PRESENT,    "Temp1 Present",             ATTRIBUTE_TYPE_BOOLEAN, 1 },
+    {  ATTR_TEMP1_ENABLE,     "Temp1 Enable",              ATTRIBUTE_TYPE_BOOLEAN, 1 },
+    {  ATTR_TEMP1_INTERVAL,   "Temp1 Interval",            ATTRIBUTE_TYPE_SINT16,  2 },
+    {  ATTR_TEMP1_VALUE,      "Temp1 Value",               ATTRIBUTE_TYPE_FIXED_15_16, 4},
+/* third temperature sensor (SMTC502AT/After) */    
+    {  ATTR_TEMP2_PRESENT,    "Temp2 Present",             ATTRIBUTE_TYPE_BOOLEAN, 1 },
+    {  ATTR_TEMP2_ENABLE,     "Temp2 Enable",              ATTRIBUTE_TYPE_BOOLEAN, 1 },
+    {  ATTR_TEMP2_INTERVAL,   "Temp2 Interval",            ATTRIBUTE_TYPE_SINT16,  2 },
+    {  ATTR_TEMP2_VALUE,      "Temp2 Value",               ATTRIBUTE_TYPE_FIXED_15_16, 4},
+/* fouth temperateure sensor (LM75B) */
+    {  ATTR_TEMP3_PRESENT,    "Temp3 Present",             ATTRIBUTE_TYPE_BOOLEAN, 1 },
+    {  ATTR_TEMP3_ENABLE,     "Temp3 Enable",              ATTRIBUTE_TYPE_BOOLEAN, 1 },
+    {  ATTR_TEMP3_INTERVAL,   "Temp3 Interval",            ATTRIBUTE_TYPE_SINT16,  2 },
+    {  ATTR_TEMP3_VALUE,      "Temp3 Value",               ATTRIBUTE_TYPE_FIXED_15_16, 4}, 
+/* Gas Pressure sensor (PSE530) */    
+    {  ATTR_GAS_PRESENT,      "Gas Pressure Present",      ATTRIBUTE_TYPE_BOOLEAN, 1 },
+    {  ATTR_GAS_ENABLE,       "Gas Pressure Enable",       ATTRIBUTE_TYPE_BOOLEAN, 1 },
+    {  ATTR_GAS_INTERVAL,     "Gas Pressure Interval",     ATTRIBUTE_TYPE_SINT16,  2 },
+    {  ATTR_GAS_VALUE,        "Gas Pressure Value",        ATTRIBUTE_TYPE_FIXED_15_16, 4}, 
+    {  ATTR_GAS_THR_MODE,     "Gas Press Threshold Mode",  ATTRIBUTE_TYPE_SINT8,   1 },
+    {  ATTR_GAS_THR_HIGH,     "Gas Press High Thresh",     ATTRIBUTE_TYPE_SINT16,  2 },
+    {  ATTR_GAS_THR_LOW,      "Gas Press Low Thresh",      ATTRIBUTE_TYPE_SINT16,  2 },
+/* Software Reset Request */    
+    {  ATTR_SOFTWARE_RESET,   "Software Reset",            ATTRIBUTE_TYPE_BOOLEAN, 1 },
+    {  ATTR_DISPLAY_MODE,     "Display Mode",              ATTRIBUTE_TYPE_SINT8,   1 },
+    {  ATTR_MCU_RESET_REASON, "MCU Reset Reason",          ATTRIBUTE_TYPE_UTF8S,  64 },
+                   
+    { ATTR_LED,               "LED",                       ATTRIBUTE_TYPE_SINT16,  2 },
+    { ATTR_IO0,               "I/O 0",                     ATTRIBUTE_TYPE_SINT64,  8 },
+    { ATTR_IO1,               "I/O 1",                     ATTRIBUTE_TYPE_SINT64,  8 },
+    { ATTR_IO2,               "I/O 2",                     ATTRIBUTE_TYPE_SINT64,  8 },
+    { ATTR_BUTTON,            "BUTTON",                    ATTRIBUTE_TYPE_BOOLEAN, 2 },
+    { ATTR_IO3,               "I/O 3",                     ATTRIBUTE_TYPE_SINT64,  8 },
+    { ATTR_BOOT_LOADER_VER,   "Bootloader Version",        ATTRIBUTE_TYPE_SINT64,  8 },
+    { ATTR_BLE_STACK_VER,     "BLE Stack Version",         ATTRIBUTE_TYPE_SINT64,  8 },
+    { ATTR_FW_APP_VER,        "FW Application Version",    ATTRIBUTE_TYPE_SINT64,  8 },
+    { ATTR_DEVICE_DESC,       "Device Description",        ATTRIBUTE_TYPE_SINT64,  8 },
+    { ATTR_WIFI_VER,          "Wi-Fi chip",                ATTRIBUTE_TYPE_SINT64,  8 },
+    { ATTR_OFFLINE_SCHED,     "Offline Schedules enable",  ATTRIBUTE_TYPE_SINT16,  2 }, 
+    { ATTR_SECURITY_ENABLED,  "Security Enabled",          ATTRIBUTE_TYPE_SINT8,   1 }, /* ? */
+    { ATTR_UTC_OFFSET,        "UTC offset data",           ATTRIBUTE_TYPE_BYTES,   8 },
+    { ATTR_CONFIGURES_SSID,   "Configured SSID",           ATTRIBUTE_TYPE_UTF8S,  10 }, /* ? */
+    { ATTR_WIFI_BARS,         "Wi-Fi Bars",                ATTRIBUTE_TYPE_SINT8,   1 },
+    { ATTR_WIFI_STDY_STATE,   "Wi-Fi Steady State",        ATTRIBUTE_TYPE_SINT8,   1 },
+    { ATTR_COMMAND,           "Command",                   ATTRIBUTE_TYPE_BYTES,   8 }, /* ? */   
+    { ATTR_ASR_STATE,         "ASR State",                 ATTRIBUTE_TYPE_SINT8,   1 },
+    { ATTR_LOW_BATTERY,       "Low Battery Warning",       ATTRIBUTE_TYPE_SINT8,   1 },
+    { ATTR_LINKED_TIMESTAMP,  "Linked Timestamp",          ATTRIBUTE_TYPE_SINT32,  4 },
+    { ATTR_ATTR_ACK,          "Attribute ACK",             ATTRIBUTE_TYPE_SINT16,  8 },
+    { ATTR_REBOOT_REASON,     "Reboot Reason",             ATTRIBUTE_TYPE_UTF8S, 100 },
+    { ATTR_BLE_COMMS,         "BLE Comms",                 ATTRIBUTE_TYPE_BYTES,  12 },
+    { ATTR_MCU_INTERFACE,     "MCU Interface",             ATTRIBUTE_TYPE_SINT8,   1 },
+    { 0,                      0,                           0,                      0 }
+} ;
+
+int get_af_attr(uint16_t id) 
+{
+    int i ;
+    for (i = 0 ; af_attr[i].id != 0 ; i++ ) {
+        if (id == af_attr[i].id) {
+            break ;
+        }
+    }
+    return (i) ;
+}
+
+void print_af_error(int resultCode) 
+{
+    switch(resultCode) {
+    case afSUCCESS:
+        printf("Operation completed successfully\n") ;
+        break ;
+    case afERROR_NO_SUCH_ATTRIBUTE:
+        printf("Request was made for unknown attribute id\n") ;
+        break ;
+    case afERROR_BUSY:
+        printf("Request already in progress, try again\n") ;
+        break ;
+    case afERROR_INVALID_COMMAND:
+        printf("Command could not be parsed\n") ;
+        break ;
+    case afERROR_QUEUE_OVERFLOW:
+        printf("Queue is full\n") ;
+        break ;
+    case afERROR_QUEUE_UNDERFLOW:
+        printf("Queue is empty\n") ;
+        break ;
+    case afERROR_INVALID_PARAM:
+        printf("Bad input parameter\n") ;
+        break ;
+    default:
+        printf("Unknown error code %d\n", resultCode) ;
+        break ;
+    }
+}
+
+void af_print_values(
+    const uint8_t   requestId, 
+    const uint16_t  attributeId,
+    const uint16_t  valueLen,
+    const uint8_t   *value
+) 
+{
+    int i, id ;
+
+    id = get_af_attr(attributeId) ;
+
+    if (af_attr[id].id  != 0) {
+        printf(af_attr[id].description) ;
+        printf(" : ") ;
+        switch(af_attr[id].attribute_type) {
+        case ATTRIBUTE_TYPE_BOOLEAN:
+        case ATTRIBUTE_TYPE_SINT8: 
+            if (valueLen >= 1) {
+                printf("%02X\n", value[0]) ;
+            }
+            break ;
+        case ATTRIBUTE_TYPE_SINT16:
+            if (valueLen >= 2) {
+                printf("%02X%02X\n", value[1], value[0]) ;
+            }
+            break ; 
+        case ATTRIBUTE_TYPE_SINT32:
+            if (valueLen >= 4) {
+                printf("%02X%02X%02X%02X\n",
+                    value[3],value[2],value[1],value[0]) ;
+            }
+            break ;
+        case ATTRIBUTE_TYPE_SINT64:
+            if (valueLen >= 8) {
+                printf("%02X%02X %02X%02X %02X%02X %02X%02X\n",
+                    value[7], value[6], value[5], value[4],
+                    value[3], value[2], value[1], value[0]) ;
+            }
+            break ;
+        case ATTRIBUTE_TYPE_UTF8S: 
+            if (valueLen > 0) {
+                for (i = 0 ; i < valueLen ; i++) {
+                    if (isprint(value[i])) {
+                        printf("%c", value[i]) ;
+                    } else if (value[i] == 0) { /* string terminator NULL */
+                        break ;
+                    } else {
+                        printf("\'%02X\'",value[i]) ;
+                    }
+                }
+                printf("\n") ;
+            }
+            break ;
+        case ATTRIBUTE_TYPE_BYTES:
+        default:
+            if (valueLen > 0) {
+                for (i = 0 ; i < valueLen ; i++ ) {
+                    printf("%02X ", value[i]) ;
+                }
+                printf("\n") ;
+            }
+            break ;
+        }
+    } else {
+        if (valueLen > 0) {
+            for (i = 0 ; i < valueLen ; i++ ) {
+                printf("%02X ", value[i]) ;
+            }
+            printf("\n") ;
+        }
+    }
+//    printf("\n") ;
+}
+
+void assignAttribute(
+    const uint8_t   requestId, 
+    const uint16_t  attributeId,
+    const uint16_t  valueLen,
+    const uint8_t   *value,
+    bool fromRequest
+) 
+{
+    switch(attributeId) {
+    case ATTR_LINKED_TIMESTAMP: /* timestamp */  
+        set_time(valueLen, value) ; /* 68 us */
+        if (fromRequest) afero->setAttributeComplete(requestId, attributeId, valueLen, value) ;
+        printf("timestampe = ") ;
+        print_date_wd(&current_time) ;
+//        print_time(&current_time) ;
+        printf("\n") ;
+        break ;
+    case ATTR_SOFTWARE_RESET: /* software reset requested! */
+        if (value[0]) {
+            reset_watch_dog() ;
+            printf("Software Reset Requested!\n") ;
+            if (display != 0) {
+                display->cls() ;
+                display->locate(0,0) ;
+                display->printf("System Rebooting!") ;
+            }
+            reset_watch_dog() ;
+            if (fromRequest) afero->setAttributeComplete(requestId, attributeId, valueLen, value) ;
+            wait(0.5) ;
+            reset_watch_dog() ;
+            reboot_edge() ;
+        }
+        break ;
+    case ATTR_DISPLAY_MODE:
+        if (display_mode != value[0]) {
+            display_mode = value[0] ;
+            if (display) {
+                display->BusEnable(true) ;
+                display->cls() ;
+                display->BusEnable(false) ;
+            }
+        }
+        reset_watch_dog() ;
+        switch(value[0]) {
+        case DISPLAY_MODE_GAS: /* gas pressure monitor only */
+            break ;
+        case DISPLAY_MODE_SUMMARY: /* summary */
+            break ;
+        case DISPLAY_MODE_CHART: /* chart mode */
+            if (display) {
+                draw_all_chart_frame() ;
+            }
+            break ;
+        case DISPLAY_MODE_OFF: /* display off */
+        default:
+            display_mode = DISPLAY_MODE_OFF ;
+            break ;
+        }
+        if (fromRequest) afero->setAttributeComplete(requestId, attributeId, valueLen, value) ;
+        break ;
+    case ATTR_ACCEL_ENABLE: /* accel enable */
+        if (sensor[SENSOR_ID_ACCEL]) {
+            if (value[0]) {
+                sensor[SENSOR_ID_ACCEL]->reset() ;
+                sensor[SENSOR_ID_ACCEL]->enable() ;
+            } else if (sensor[SENSOR_ID_ACCEL]){
+                sensor[SENSOR_ID_ACCEL]->disable() ;
+            }
+            if (fromRequest) afero->setAttributeComplete(requestId, attributeId, valueLen, value) ;
+        }
+        break ;
+    case ATTR_ACCEL_INTERVAL:
+        if (sensor[SENSOR_ID_ACCEL]) {
+            sensor[SENSOR_ID_ACCEL]->setInterval((value[1] << 8) | value[0]) ;
+            if (fromRequest) afero->setAttributeComplete(requestId, attributeId, valueLen, value) ;
+        }
+        break ;
+    case ATTR_COLOR0_ENABLE: /* color0 enable */
+        if (sensor[SENSOR_ID_COLOR1]) {
+            if (value[0]) {
+                sensor[SENSOR_ID_COLOR1]->reset() ;
+                sensor[SENSOR_ID_COLOR1]->enable() ;
+            } else {
+                sensor[SENSOR_ID_COLOR1]->disable() ;
+            }
+            if (fromRequest) afero->setAttributeComplete(requestId, attributeId, valueLen, value) ;
+        }
+        break ;
+    case ATTR_COLOR0_INTERVAL:
+        if (sensor[SENSOR_ID_COLOR1]) {
+            sensor[SENSOR_ID_COLOR1]->setInterval((value[1] << 8) | value[0]) ;
+            if (fromRequest) afero->setAttributeComplete(requestId, attributeId, valueLen, value) ;
+        }
+        break ;    
+    case ATTR_COLOR0_TRIGMODE: /* color0 config */
+        if (sensor[SENSOR_ID_COLOR1]) {
+            uint8_t config = ((edge_color*)sensor[SENSOR_ID_COLOR1])->getConfig() & 0x70 ;
+            if (value[0]) {
+                config = config | 0x06 ;
+            } 
+            ((edge_color*)sensor[SENSOR_ID_COLOR1])->setConfig(config) ;
+            if (fromRequest) afero->setAttributeComplete(requestId, attributeId, valueLen, value) ;
+        }
+        break ;
+    case ATTR_COLOR0_ITIME: /* color0 config */
+        if (sensor[SENSOR_ID_COLOR1]) {
+            uint8_t config = ((edge_color*)sensor[SENSOR_ID_COLOR1])->getConfig() & 0x07 ;
+            config = (value[0] << 4) | config ;
+            ((edge_color*)sensor[SENSOR_ID_COLOR1])->setConfig(config) ;
+          if (fromRequest) afero->setAttributeComplete(requestId, attributeId, valueLen, value) ;
+        }
+        break ;    
+    case ATTR_COLOR0_PWM_PERIOD: /* color0 pwm period */
+        if (sensor[SENSOR_ID_COLOR1]) {
+            ((edge_color*)sensor[SENSOR_ID_COLOR1])->set_pwm_period((value[1] << 8) | value[0]) ;
+          if (fromRequest) afero->setAttributeComplete(requestId, attributeId, valueLen, value) ;
+        }            
+        break ;
+    case ATTR_COLOR0_PWM_TARGET: /* color0 pwm calibration target */
+        if (sensor[SENSOR_ID_COLOR1]) {
+            color0_target[0] = (value[1] << 8) | value[0] ;
+            color0_target[1] = color0_target[0] ;
+            color0_target[2] = color0_target[1] ;
+          if (fromRequest) afero->setAttributeComplete(requestId, attributeId, valueLen, value) ;
+        }            
+        break ;     
+#if 1 /* do not handle calibration twice */   
+    case ATTR_COLOR0_CALIBRATE: /* calibrate color0 */
+        if (sensor[SENSOR_ID_COLOR1] && value[0] && fromRequest) { /* do calibration */ 
+            ((edge_color*)sensor[SENSOR_ID_COLOR1])->request_calibration() ;
+        }
+        break ;
+#endif
+    case ATTR_COLOR0_PWM_R:
+        if (sensor[SENSOR_ID_COLOR1]) {
+            ((edge_color*)sensor[SENSOR_ID_COLOR1])->setPwmR( (value[1] << 8) | value[0] ) ;
+//            color0_pwm[0] = (value[1] << 8) | value[0] ;
+        }
+        if (fromRequest) afero->setAttributeComplete(requestId, attributeId, valueLen, value) ;       
+        break ;
+    case ATTR_COLOR0_PWM_G:
+        if (sensor[SENSOR_ID_COLOR1]) {
+            ((edge_color*)sensor[SENSOR_ID_COLOR1])->setPwmG( (value[1] << 8) | value[0] ) ;
+//            color0_pwm[1] = (value[1] << 8) | value[0] ;
+        }
+        if (fromRequest) afero->setAttributeComplete(requestId, attributeId, valueLen, value) ;       
+        break ;
+    case ATTR_COLOR0_PWM_B:
+        if (sensor[SENSOR_ID_COLOR1]) {
+            ((edge_color*)sensor[SENSOR_ID_COLOR1])->setPwmB( (value[1] << 8) | value[0] ) ;
+//            color0_pwm[2] = (value[1] << 8) | value[0] ;
+        }
+        if (fromRequest) afero->setAttributeComplete(requestId, attributeId, valueLen, value) ;       
+        break ;
+    case ATTR_COLOR1_ENABLE: /* color1 enable */
+        if (sensor[SENSOR_ID_COLOR2]) {
+            if (value[0]) {
+                sensor[SENSOR_ID_COLOR2]->reset() ;
+                sensor[SENSOR_ID_COLOR2]->enable() ;
+            } else {
+                sensor[SENSOR_ID_COLOR2]->disable() ;
+            }
+            if (fromRequest) afero->setAttributeComplete(requestId, attributeId, valueLen, value) ;
+        }
+        break ;
+    case ATTR_COLOR1_INTERVAL:
+        if (sensor[SENSOR_ID_COLOR2]) {
+            sensor[SENSOR_ID_COLOR2]->setInterval((value[1] << 8) | value[0]) ;
+            if (fromRequest) afero->setAttributeComplete(requestId, attributeId, valueLen, value) ;
+        }
+        break ;    
+    case ATTR_COLOR1_TRIGMODE: /* color0 config */
+        if (sensor[SENSOR_ID_COLOR2]) {
+            uint8_t config = ((edge_color*)sensor[SENSOR_ID_COLOR2])->getConfig() & 0x70 ;
+            if (value[0]) {
+                config = config | 0x06 ;
+            } 
+            ((edge_color*)sensor[SENSOR_ID_COLOR2])->setConfig(config) ;
+            if (fromRequest) afero->setAttributeComplete(requestId, attributeId, valueLen, value) ;
+        }
+        break ;
+    case ATTR_COLOR1_ITIME: /* color0 config */
+        if (sensor[SENSOR_ID_COLOR2]) {
+            uint8_t config = ((edge_color*)sensor[SENSOR_ID_COLOR2])->getConfig() & 0x07 ;
+            config = (value[0] << 4) | config ;
+            ((edge_color*)sensor[SENSOR_ID_COLOR2])->setConfig(config) ;
+            if (fromRequest) afero->setAttributeComplete(requestId, attributeId, valueLen, value) ;
+        }
+        break ;  
+    case ATTR_COLOR1_PWM_PERIOD: /* color0 pwm period */
+        if (sensor[SENSOR_ID_COLOR2]) {
+            ((edge_color*)sensor[SENSOR_ID_COLOR2])->set_pwm_period((value[1] << 8) | value[0]) ;
+            if (fromRequest) afero->setAttributeComplete(requestId, attributeId, valueLen, value) ;
+        }            
+        break ;
+    case ATTR_COLOR1_PWM_TARGET: /* color0 pwm calibration target */
+        if (sensor[SENSOR_ID_COLOR2]) {
+            color1_target[0] = (value[1] << 8) | value[0] ;
+            color1_target[1] = color1_target[0] ;
+            color1_target[2] = color1_target[1] ;
+            if (fromRequest) afero->setAttributeComplete(requestId, attributeId, valueLen, value) ;
+        }            
+        break ;   
+#if 1 /* do not handle calibration twice */
+    case ATTR_COLOR1_CALIBRATE: /* calibrate color1 */
+        if (sensor[SENSOR_ID_COLOR2] && value[0] && fromRequest) { /* do calibration! */
+            ((edge_color*)sensor[SENSOR_ID_COLOR2])->request_calibration() ;
+        }
+        break ;
+#endif
+    case ATTR_COLOR1_PWM_R:
+        if (sensor[SENSOR_ID_COLOR2]) {
+            ((edge_color*)sensor[SENSOR_ID_COLOR2])->setPwmR( (value[1] << 8) | value[0] ) ;
+//            color1_pwm[0] = (value[1] << 8) | value[0] ;
+        }
+        if (fromRequest) afero->setAttributeComplete(requestId, attributeId, valueLen, value) ;       
+        break ;
+    case ATTR_COLOR1_PWM_G:
+        if (sensor[SENSOR_ID_COLOR2]) {
+            ((edge_color*)sensor[SENSOR_ID_COLOR2])->setPwmG( (value[1] << 8) | value[0] ) ;
+//            color1_pwm[1] = (value[1] << 8) | value[0] ;
+        }
+        if (fromRequest) afero->setAttributeComplete(requestId, attributeId, valueLen, value) ;       
+        break ;
+    case ATTR_COLOR1_PWM_B:
+        if (sensor[SENSOR_ID_COLOR2]) {
+            ((edge_color*)sensor[SENSOR_ID_COLOR2])->setPwmB( (value[1] << 8) | value[0] ) ;
+//            color1_pwm[2] = (value[1] << 8) | value[0] ;
+        }
+        if (fromRequest) afero->setAttributeComplete(requestId, attributeId, valueLen, value) ;       
+        break ;
+    case ATTR_TEMP0_ENABLE: /* temp0 is used to control temp-sensors */
+        if (sensor[SENSOR_ID_TEMP]) {
+            if (value[0]) {
+                sensor[SENSOR_ID_TEMP]->reset() ;
+                sensor[SENSOR_ID_TEMP]->enable() ;
+            } else {
+                sensor[SENSOR_ID_TEMP]->disable() ;
+            }
+            if (fromRequest) afero->setAttributeComplete(requestId, attributeId, valueLen, value) ;
+        } 
+        break ;
+    case ATTR_TEMP0_INTERVAL:
+        if (sensor[SENSOR_ID_TEMP]) {
+            sensor[SENSOR_ID_TEMP]->setInterval((value[1] << 8) | value[0]) ;
+            if (fromRequest) afero->setAttributeComplete(requestId, attributeId, valueLen, value) ;
+        }
+        break ; 
+    case ATTR_TEMP3_ENABLE: /* temp3 enable */
+        break ;
+    case ATTR_GAS_ENABLE: /* pressure enable */
+        if (sensor[SENSOR_ID_PRESS]) {
+            if (value[0]) {
+                sensor[SENSOR_ID_PRESS]->reset() ;
+                sensor[SENSOR_ID_PRESS]->enable() ;
+            } else {
+                sensor[SENSOR_ID_PRESS]->disable() ;
+            }
+            if (fromRequest) afero->setAttributeComplete(requestId, attributeId, valueLen, value) ;
+        }   
+        break ;
+    case ATTR_GAS_INTERVAL:
+        if (sensor[SENSOR_ID_PRESS]) {
+            sensor[SENSOR_ID_PRESS]->setInterval((value[1] << 8) | value[0]) ;
+            if (fromRequest) afero->setAttributeComplete(requestId, attributeId, valueLen, value) ;
+        }
+        break ; 
+    case ATTR_GAS_THR_MODE:
+        if (sensor[SENSOR_ID_PRESS]) {
+            ((edge_pressure*)sensor[SENSOR_ID_PRESS])->set_thr_mode(value[0]) ;
+            if (fromRequest) afero->setAttributeComplete(requestId, attributeId, valueLen, value) ;
+        }
+        break ;
+    case ATTR_GAS_THR_HIGH:
+        if (sensor[SENSOR_ID_PRESS]) {
+            ((edge_pressure*)sensor[SENSOR_ID_PRESS])->set_thr_high((value[1] << 8) | value[0]) ;
+            if (fromRequest) afero->setAttributeComplete(requestId, attributeId, valueLen, value) ;
+        }
+        break ;
+    case ATTR_GAS_THR_LOW:
+        if (sensor[SENSOR_ID_PRESS]) {
+            ((edge_pressure*)sensor[SENSOR_ID_PRESS])->set_thr_low((value[1] << 8) | value[0]) ;
+            if (fromRequest) afero->setAttributeComplete(requestId, attributeId, valueLen, value) ;
+        }
+        break ;               
+    default:
+        break ;    
+    }
+}
+
+/*
+ * Callback that allows ASR to request an MCU attribute be changed. 
+ * You should define this function in your MCU firmware to perform application-specific actions 
+ * your code must take (e.g., updating the state of the hardware), 
+ * in light of the attribute value change.
+*/
+void attributeChangeRequest(
+    const uint8_t   requestId, 
+    const uint16_t  attributeId,
+    const uint16_t  valueLen,
+    const uint8_t   *value
+) 
+{ 
+    uint32_t timestamp = edge_time ;
+    if ((pending != 0)&&(pending->request->requestId == requestId)) {
+        pending->replied_time = timestamp ;
+
+    }
+    ts2time(timestamp, &current_time) ; /* 12 us */
+    if (verbos) {
+        print_time(&current_time) ;
+        printf(" %5d ASR requested [%d] : ", attributeId, requestId) ;
+        af_print_values(requestId, attributeId, valueLen, value) ;
+    }
+
+    assignAttribute(requestId, attributeId, valueLen, value, true) ;
+
+//    af_print_values(requestId, attributeId, valueLen, value) ;
+    if ((pending != 0)&&(pending->request->requestId == requestId)) {
+        printf("Request [%d] replied in %d sec!\n", requestId, pending->replied_time - pending->submit_time) ;
+        delete pending ;
+        pending = 0 ;
+    }
+}
+
+/*
+ * Application callback that allows afLib to notify that an attribute has changed. 
+ * This method will be called in response to a getAttribute call from the application 
+ * and whenever a ASR module attribute changes.
+ */
+void attributeUpdatedReport(
+    const uint8_t   requestId,
+    const uint16_t  attributeId,
+    const uint16_t  valueLen,
+    const uint8_t   *value
+) 
+{
+    uint32_t timestamp = edge_time ;
+    int result ;
+    if ((pending != 0)&&(pending->request->requestId == requestId)) {
+        pending->replied_time = timestamp ;
+    }   
+    ts2time(timestamp, &current_time) ; /* 12us */
+    if (verbos) {
+        print_time(&current_time) ;
+        printf(" %5d ASR reported [%d]: ", attributeId, requestId) ;
+        af_print_values(requestId, attributeId, valueLen, value) ;
+    }
+
+    switch(attributeId) {
+    case ATTR_LINKED_TIMESTAMP:
+        set_time(valueLen, value) ; /* 68 us */
+        printf("timestampe = ") ;
+        print_date_wd(&current_time) ;
+//        print_time(&current_time) ;
+        printf("\n") ;
+        break ;         
+    case ATTR_WIFI_STDY_STATE:
+        gConnected = false ;
+        printf("WiFi Steady State: ") ;
+        switch(value[0]) {
+        case 0: printf("Not Connected\n")      ; break ;
+        case 1: printf("Pending\n") ;            break ;
+        case 2: 
+            printf("Connected\n") ;       
+            gConnected = true ; // the only case Connected state is OK   
+            break ;
+        case 3: printf("Unknown Failure\n") ;    break ;
+        case 4: printf("Association Failed\n") ; break ;
+        case 5: printf("Handshake Failed\n") ;   break ;
+        case 6: printf("Echo Failed\n") ;        break ;
+        case 7: printf("SSID Not Found\n") ;     break ;
+        case 8: printf("NTP Failed\n") ;         break ;
+        default: printf("Unknown [%d]\n", value[0]) ; break ;
+        }
+        break ;
+    case ATTR_REBOOT_REASON:
+        printf("Reboot Reason: ") ;
+        switch(value[0]) {
+        case 1: printf("Reset pin asserted\n") ; break ;
+        case 2: printf("Watchdog reset\n") ;     break ;
+        case 4: printf("Software reset\n") ;     break ;
+        case 8: printf("CPU Lock up\n") ;        break ;
+        default: printf("Unknown [%d]\n", value[0]) ;     break ;
+        }
+        if (reboot_requested) {
+            printf("Unexpected ASR Reboot. Rebooting MCU.\n") ;
+            wait_ms(100) ;
+            reboot_edge() ;
+        }
+        break ; 
+    case ATTR_MCU_INTERFACE:
+        printf("MCU Interface: ") ;
+        switch(value[0]) {
+        case 0:  printf("No MCU\n") ;    break ;
+        case 1:  printf("SPI Slave\n") ; break ;
+        case 2:  printf("UART\n") ;      break ;
+        default: printf("Unknown\n") ;   break ; 
+        }
+        break ;
+    case AF_SYSTEM_ASR_STATE:
+        printf("ASR state: ") ;
+        switch(value[0]) {
+        case MODULE_STATE_REBOOTED:
+            gLinked = false ;
+            printf("Rebooted\n") ;
+//            wait_ms(100) ; /* */
+            if (edge_mgr_status == EDGE_MGR_RUNNING) {
+                result = afero->getAttribute(ATTR_REBOOT_REASON) ;
+                reboot_requested = true ;
+//                reboot_edge() ;
+            }
+            break ;
+        case MODULE_STATE_LINKED:
+            if (gLinked == false) { /* new link established */
+                result = afero->getAttribute(ATTR_LINKED_TIMESTAMP) ;
+                if (result != afSUCCESS) {
+                    printf("getAttriute for ATTR_LINKED_TIMESTAMP failed\n") ;
+                }
+            }
+            gLinked = true ;
+            printf("Linked\n") ;
+            break ;
+        case MODULE_STATE_UPDATING:
+            gLinked = true ; 
+            printf("Updating\n") ;
+            if (display) {
+                display->cls() ;
+                display->locate(5, 5) ;
+                display->printf("FW Updating...") ;
+            }
+            break ;
+        case MOUDLE_STATE_UPDATE_READY:
+            gLinked = false ;
+            printf("Update ready - rebooting\n") ;
+            if (display) {
+                display->cls() ;
+                display->locate(5, 5) ;
+                display->printf("Rebooting...") ;
+            }
+            while(afero->setAttribute32(AF_SYSTEM_COMMAND, MODULE_COMMAND_REBOOT) != afSUCCESS) {
+                afero->loop() ;
+                wait_us(100) ;
+            }
+            reboot_edge() ;
+            break ;
+        default:
+            break ;
+        }
+        break ;
+    default:
+        assignAttribute(requestId, attributeId, valueLen, value, false) ;
+        break ;
+    }      
+    if ((pending != 0)&&(pending->request->requestId == requestId)) {
+        printf("Request [%d] replied in %d sec!\n", requestId, pending->replied_time - pending->submit_time) ;
+        delete pending ;
+        pending = 0 ;
+    }      
+}
\ No newline at end of file