main/co2meter.c

changeset 16
e38ffa806e84
parent 14
deaca7606e23
child 17
f9eca4a55911
--- a/main/co2meter.c	Sat Oct 26 14:05:17 2019 +0200
+++ b/main/co2meter.c	Wed Oct 30 23:21:46 2019 +0100
@@ -11,15 +11,14 @@
 #define ROT_ENC_A_GPIO		(CONFIG_ROT_ENC_A_GPIO)
 #define ROT_ENC_B_GPIO		(CONFIG_ROT_ENC_B_GPIO)
 #define ROT_ENC_SW_GPIO		(CONFIG_ROT_ENC_SW_GPIO)
+#define INACTIVITY		480					///< Time in 250 mSec units.
+
+#define RESET_AT		0		///< Set to a positive non-zero number to reset the position if this value is exceeded
 
 
-#define ENABLE_HALF_STEPS	false		///< Set to true to enable tracking of rotary encoder at half step resolution
-#define RESET_AT		0		///< Set to a positive non-zero number to reset the position if this value is exceeded
-#define FLIP_DIRECTION		false		///< Set to true to reverse the clockwise/counterclockwise sense
-
-
-int					Main_Loop1 = MAIN_LOOP1_INIT;	///< Loop 1 init
+int					Main_Loop1 = ML1_INIT;		///< Loop 1 init
 int					Main_Loop2 = -1;		///< Loop 2 invalid
+int					New_Loop2 = ML2_DONE;		///< Loop 2 new state
 bool                            	System_TimeOk = false;          ///< System time status
 time_t                          	now;                            ///< Current time
 struct tm                       	timeinfo;                       ///< Current time structure
@@ -29,9 +28,10 @@
 static TaskHandle_t			xTaskADC = NULL;
 static TaskHandle_t			xTaskWifi = NULL;
 static TaskHandle_t			xTaskMQTT = NULL;
-const esp_app_desc_t			*app_desc = NULL;
-u8g2_t					u8g2;				///<  A structure which will contain all the data for one display
-
+const esp_app_desc_t			*app_desc = NULL;		///< Application description
+u8g2_t					u8g2;				///< A structure which will contain all the data for one display
+rotary_encoder_info_t			rinfo = { 0 };			///< Rotary encoder record
+static int				PushDuration = 0;		///< Duration of the pushed button
 
 extern unit_t				units[3];			///< Pressure test units
 extern SemaphoreHandle_t		xSemaphoreUnits;		///< Units lock semaphore
@@ -39,12 +39,16 @@
 extern SemaphoreHandle_t        	xSemaphoreDS18B20;      	///< DS18B20 lock semaphore
 extern ADC_State                	*adc_state;             	///< ADC state
 extern SemaphoreHandle_t        	xSemaphoreADC;          	///< ADC lock semaphore
-extern int				count_pub;
+extern int				count_pub;			///< Published MQTT messages in transit
+static xQueueHandle			gpio_evt_queue = NULL;		///< Rotary pushbutton queue
+static int				usertimer = 0;			///< User inactive timeout
 
 
-void screen_main(float t, float p1, float p2, float p3)
+
+void screen_main()
 {
     char	buf[65];
+    int		i;
 
     u8g2_ClearBuffer(&u8g2);
     u8g2_DrawHLine(&u8g2, 0, 14, 128);
@@ -53,26 +57,99 @@
     u8g2_uint_t w = u8g2_GetStrWidth(&u8g2, buf);
     u8g2_DrawStr(&u8g2, (128 - w) / 2,12, buf);
 
-    u8g2_SetFont(&u8g2, u8g2_font_t0_22b_tf);
-    sprintf(buf, "%.1f °C", t);
-    w = u8g2_GetUTF8Width(&u8g2, buf);
-    u8g2_DrawUTF8(&u8g2, (128 - w) / 2,40, buf);
-    u8g2_SetFont(&u8g2, u8g2_font_t0_18b_tf);
+    if (xSemaphoreTake(xSemaphoreUnits, 25) == pdTRUE) {
+
+    	u8g2_SetFont(&u8g2, u8g2_font_t0_22b_tf);
+    	sprintf(buf, "%.1f °C", units[0].temperature / 1000.0);
+    	w = u8g2_GetUTF8Width(&u8g2, buf);
+    	u8g2_DrawUTF8(&u8g2, (128 - w) / 2,40, buf);
+    	u8g2_SetFont(&u8g2, u8g2_font_t0_18b_tf);
+
+	for (i = 0; i < 3; i++) {
+    	    sprintf(buf, "%.1f", units[i].pressure / 1000.0);
+    	    w = u8g2_GetUTF8Width(&u8g2, buf);
+    	    u8g2_DrawUTF8(&u8g2, ((42 - w) / 2) + i * 43,63, buf);
+	}
+	xSemaphoreGive(xSemaphoreUnits);
+    }
+    u8g2_SendBuffer(&u8g2);
+    u8g2_SetPowerSave(&u8g2, 0); // wake up display
+}
+
+
+
+void screen_unit(int no)
+{
+    char        buf[65];
+
+    u8g2_ClearBuffer(&u8g2);
+    u8g2_DrawHLine(&u8g2, 0, 14, 128);
+    u8g2_SetFont(&u8g2, u8g2_font_t0_15_tr);
+    sprintf(buf, "Unit %d", no + 1);
+    u8g2_uint_t w = u8g2_GetStrWidth(&u8g2, buf);
+    u8g2_DrawStr(&u8g2, (128 - w) / 2,12, buf);
+
+    if (xSemaphoreTake(xSemaphoreUnits, 25) == pdTRUE) {
+
+    	u8g2_SetFont(&u8g2, u8g2_font_t0_22b_tf);
+    	sprintf(buf, "%.1f °C", units[no].temperature / 1000.0);
+    	w = u8g2_GetUTF8Width(&u8g2, buf);
+    	u8g2_DrawUTF8(&u8g2, (128 - w) / 2,40, buf);
+//    	u8g2_SetFont(&u8g2, u8g2_font_t0_18b_tf);
+
+    	sprintf(buf, "%.2f bar", units[no].pressure / 1000.0);
+    	w = u8g2_GetUTF8Width(&u8g2, buf);
+    	u8g2_DrawUTF8(&u8g2, (128 - w) / 2,63, buf);
 
-    sprintf(buf, "%.1f", p1);
-    w = u8g2_GetUTF8Width(&u8g2, buf);
-    u8g2_DrawUTF8(&u8g2, ((42 - w) / 2),63, buf);
+	xSemaphoreGive(xSemaphoreUnits);
+    }
+    u8g2_SendBuffer(&u8g2);
+    u8g2_SetPowerSave(&u8g2, 0); // wake up display
+}
+
+
+
+void screen_unit_setup(int no, int sub)
+{
+    char        buf[65];
+
+    u8g2_ClearBuffer(&u8g2);
+    u8g2_DrawHLine(&u8g2, 0, 14, 128);
+    u8g2_SetFont(&u8g2, u8g2_font_t0_15_tr);
+    sprintf(buf, "Unit %d setup", no + 1);
+    u8g2_uint_t w = u8g2_GetStrWidth(&u8g2, buf);
+    u8g2_DrawStr(&u8g2, (128 - w) / 2,12, buf);
 
-    sprintf(buf, "%.1f", p2);
-    w = u8g2_GetUTF8Width(&u8g2, buf);
-    u8g2_DrawUTF8(&u8g2, ((42 - w) / 2) + 43,63, buf);
+    if (sub == 0)
+	u8g2_SetFont(&u8g2, u8g2_font_t0_15b_tr);
+    else
+	u8g2_SetFont(&u8g2, u8g2_font_t0_15_tr);
+    sprintf(buf, "Mode      %s", units[no].mode ? "ON":"OFF");
+    u8g2_DrawStr(&u8g2,2,28, buf);
+
+    if (sub == 1)
+        u8g2_SetFont(&u8g2, u8g2_font_t0_15b_tr);
+    else
+        u8g2_SetFont(&u8g2, u8g2_font_t0_15_tr);
+    sprintf(buf, "Calibrate");
+    u8g2_DrawStr(&u8g2,2,40, buf);
 
-    sprintf(buf, "%.1f", p3);
-    w = u8g2_GetUTF8Width(&u8g2, buf);
-    u8g2_DrawUTF8(&u8g2, ((42 - w) / 2) + 86,63, buf);
+    if (sub == 2)
+        u8g2_SetFont(&u8g2, u8g2_font_t0_15b_tr);
+    else
+        u8g2_SetFont(&u8g2, u8g2_font_t0_15_tr);
+    sprintf(buf, "T.sensor  ");
+    u8g2_DrawStr(&u8g2,2,52, buf);
+
+    if (sub == 3)
+        u8g2_SetFont(&u8g2, u8g2_font_t0_15b_tr);
+    else
+        u8g2_SetFont(&u8g2, u8g2_font_t0_15_tr);
+    sprintf(buf, "Return");
+    u8g2_DrawStr(&u8g2,2,64, buf);
 
     u8g2_SendBuffer(&u8g2);
-    u8g2_SetPowerSave(&u8g2, 0); // wake up display
+    u8g2_SetPowerSave(&u8g2, 0);
 }
 
 
@@ -84,32 +161,78 @@
     u8g2_DrawStr(&u8g2,2,24,e2);
     u8g2_SendBuffer(&u8g2);
     u8g2_SetPowerSave(&u8g2, 0);
+}
 
+
+
+/*
+ * Interrupt service routine for the rotary pushbutton.
+ */
+static void IRAM_ATTR gpio_isr_handler(void* arg)
+{
+    uint32_t gpio_num = (uint32_t) arg;
+    xQueueSendFromISR(gpio_evt_queue, &gpio_num, NULL);
 }
 
 
 
+/*
+ * GPIO queue task. See if there is a rotary pushbutton event in the queue.
+ */
+static void gpio_task(void* arg)
+{
+    uint32_t		io_num;
+    static int64_t	pushed = 0;
+
+    for(;;) {
+        if (xQueueReceive(gpio_evt_queue, &io_num, portMAX_DELAY)) {
+	    if (io_num == ROT_ENC_SW_GPIO) {
+		if (gpio_get_level(io_num) == 0) {
+		    pushed = esp_timer_get_time();
+		    PushDuration = 0;
+		} else if (gpio_get_level(io_num) == 1) {
+		    PushDuration = (esp_timer_get_time() - pushed) / 1000;
+		    ESP_LOGI(TAG, "GPIO rotary button intr, val: %d time: %d", gpio_get_level(io_num), PushDuration);
+		}
+	    } else {
+            	ESP_LOGE(TAG, "GPIO[%d] unknown intr, val: %d", io_num, gpio_get_level(io_num));
+	    }
+	    usertimer = INACTIVITY;
+        }
+    }
+}
+
+
+
+/*
+ * Select new menu number on a postitive or negative rotary position.
+ * Then reset the rotary position.
+ */
+static void rotate_to_menu(rotary_encoder_position_t pos, int next_menu, int prev_menu)
+{
+    if (pos > 0)
+	New_Loop2 = next_menu;
+    else if (pos < 0)
+	New_Loop2 = prev_menu;
+    ESP_ERROR_CHECK(rotary_encoder_reset(&rinfo));
+}
+
+
 
 void app_main()
 {
     struct timeval	now;
     gettimeofday(&now, NULL);
     int			sleep_time_ms = (now.tv_sec - sleep_enter_time.tv_sec) * 1000 + (now.tv_usec - sleep_enter_time.tv_usec) / 1000;
-    int			New_Loop2 = MAIN_LOOP2_INIT;
     esp_err_t           ret;
 
-    Main_Loop1 = MAIN_LOOP1_INIT;
+    Main_Loop1 = ML1_INIT;
     Main_Loop2 = -1;
 
     switch (esp_sleep_get_wakeup_cause()) {
         case ESP_SLEEP_WAKEUP_EXT1: {
-            uint64_t wakeup_pin_mask = esp_sleep_get_ext1_wakeup_status();
-            if (wakeup_pin_mask != 0) {
-                int pin = __builtin_ffsll(wakeup_pin_mask) - 1;
-                printf("Wake up from GPIO %d\n", pin);
-            } else {
-                printf("Wake up from GPIO\n");
-            }
+	    ESP_LOGI(TAG, "Starting from deep sleep, Rotary switch pressed");
+	    New_Loop2 = ML2_INIT;
             break;
         }
         case ESP_SLEEP_WAKEUP_TIMER: {
@@ -124,12 +247,10 @@
     const int wakeup_time_sec = 55;
     ESP_LOGI(TAG, "Enabling timer wakeup, %ds", wakeup_time_sec);
     esp_sleep_enable_timer_wakeup(wakeup_time_sec * 1000000);
+    const uint64_t ext_wakeup_pin_1_mask = 1ULL << ROT_ENC_SW_GPIO;
 
-//    const int ext_wakeup_pin_1 = ROT_ENC_SW_GPIO; // 25 in example, redefine to rotary name.
-//    const uint64_t ext_wakeup_pin_1_mask = 1ULL << ext_wakeup_pin_1;
-
-//    printf("Enabling EXT1 wakeup on pins GPIO%d\n", ext_wakeup_pin_1);
-//    esp_sleep_enable_ext1_wakeup(ext_wakeup_pin_1_mask, ESP_EXT1_WAKEUP_ANY_HIGH); // TODO: what is the logic of the rotary button.
+    ESP_LOGI(TAG, "Enabling EXT1 wakeup on pin GPIO%d", ROT_ENC_SW_GPIO);
+    esp_sleep_enable_ext1_wakeup(ext_wakeup_pin_1_mask, ESP_EXT1_WAKEUP_ALL_LOW);
 
     // Isolate GPIO12 pin from external circuits. This is needed for modules
     // which have an external pull-up resistor on GPIO12 (such as ESP32-WROVER)
@@ -159,7 +280,6 @@
 
     u8g2_Setup_sh1106_i2c_128x64_noname_f(&u8g2, U8G2_R0, u8g2_esp32_i2c_byte_cb, u8g2_esp32_gpio_and_delay_cb);  // init u8g2 structure
     u8x8_SetI2CAddress(&u8g2.u8x8, 0x78);
-    ESP_LOGI(TAG, "u8g2_InitDisplay");
     u8g2_InitDisplay(&u8g2); // send init sequence to the display, display is in sleep mode after this,
 
     /*
@@ -248,18 +368,24 @@
      * installed before calling rotary_encoder_register()
      */
     ESP_ERROR_CHECK(gpio_install_isr_service(0));
-    rotary_encoder_info_t rinfo = { 0 };
     ESP_ERROR_CHECK(rotary_encoder_init(&rinfo, ROT_ENC_A_GPIO, ROT_ENC_B_GPIO));
-//    ESP_ERROR_CHECK(rotary_encoder_enable_half_steps(&rinfo, ENABLE_HALF_STEPS));
-#ifdef FLIP_DIRECTION
-//    ESP_ERROR_CHECK(rotary_encoder_flip_direction(&rinfo));
-#endif
+    ESP_ERROR_CHECK(rotary_encoder_enable_half_steps(&rinfo, false));
+
+    gpio_config_t io_conf;
+    io_conf.intr_type = GPIO_PIN_INTR_ANYEDGE;
+    io_conf.pin_bit_mask = (1ULL << ROT_ENC_SW_GPIO);
+    io_conf.mode = GPIO_MODE_INPUT;
+    gpio_config(&io_conf);
+
+    gpio_evt_queue = xQueueCreate(10, sizeof(uint32_t));
+    xTaskCreate(gpio_task, "gpio_task", 2048, NULL, 10, NULL);
+
+    gpio_isr_handler_add(ROT_ENC_SW_GPIO, gpio_isr_handler, (void*) ROT_ENC_SW_GPIO);
 
     // Create a queue for events from the rotary encoder driver.
     // Tasks can read from this queue to receive up to date position information.
-//    QueueHandle_t event_queue = rotary_encoder_create_queue();
-//    ESP_ERROR_CHECK(rotary_encoder_set_queue(&rinfo, event_queue));
-
+    QueueHandle_t event_queue = rotary_encoder_create_queue();
+    ESP_ERROR_CHECK(rotary_encoder_set_queue(&rinfo, event_queue));
 
     /*
      * Main application loop.
@@ -267,35 +393,36 @@
     while (1) {
 
 	ESP_LOGI(TAG, "Entered app loop");
+	rotary_encoder_event_t event = { 0 };
+	int sub = 0;
 
 	/* Measure process or user input via rotary switch */
 	while (1) {
 	    switch (Main_Loop1) {
-		case MAIN_LOOP1_INIT:
+		case ML1_INIT:
 		    ESP_LOGI(TAG, "Loop timer: Init");
-		    // If configured do MAIN_LOOP1_CONNECT
-		    Main_Loop1 = MAIN_LOOP1_CONNECT;
+		    // If configured do ML1_CONNECT
+		    Main_Loop1 = ML1_CONNECT;
 		    requestWiFi_system(true);
 		    request_ds18b20();
 		    request_adc();
 		    break;
 
-		case MAIN_LOOP1_CONNECT:
+		case ML1_CONNECT:
                     if (ready_WiFi())
-                        Main_Loop1 = MAIN_LOOP1_MQTT_CONNECT;
+                        Main_Loop1 = ML1_MQTT_CONNECT;
                     break;
 
-		case MAIN_LOOP1_MQTT_CONNECT:
+		case ML1_MQTT_CONNECT:
 		    if (ready_ds18b20() && ready_adc()) {
 			connect_mqtt(true);
-			Main_Loop1 = MAIN_LOOP1_WAITCON;
+			Main_Loop1 = ML1_WAITCON;
 			ESP_LOGI(TAG, "Loop timer: Wait MQTT");
 
 			/* Get global temperature, use for all units. */
 			uint32_t temp = 0;
 			int state = 0;
 			char rom_code[17];
-			float t = 0, p1, p2, p3;
 			if (xSemaphoreTake(xSemaphoreDS18B20, 10) == pdTRUE) {
 			    temp = (ds18b20_state->sensor[0].temperature * 1000);
 			    state = (ds18b20_state->sensor[0].error == 0) ? 0:1;
@@ -303,13 +430,10 @@
 			    rom_code[16] = '\0';
         		    xSemaphoreGive(xSemaphoreDS18B20);
     			}
-			t = temp / 1000.0;
 
 			/* Copy measured data and calculate results */
 			if (xSemaphoreTake(xSemaphoreUnits, 25) == pdTRUE) {
 			    for (int i = 0; i < 3; i++) {
-				if (i == 0)
-				    units[i].mode = 1;
 			    	units[i].temperature = temp;
 			    	units[i].temperature_state = state;
 				units[i].alarm = 0;
@@ -327,12 +451,6 @@
 				    if (P < 0)
 				    	P = 0;
 				    units[i].pressure = P;
-				    if (i == 0)
-					p1 = P / 1000.0;
-				    else if (i == 1)
-					p2 = P / 1000.0;
-				    else if (i == 2)
-					p3 = P / 1000.0;
 printf("%d volt: %d batt: %d scale: %d  bar: %d\n", i, units[i].pressure_voltage, adc_state->Batt_voltage, 
 		units[i].pressure_voltage / (adc_state->Batt_voltage / 1000) - units[i].pressure_zero, P);
 // Moet die echt op 5 volt?
@@ -343,51 +461,56 @@
 			    }
 			    write_units();
 			    xSemaphoreGive(xSemaphoreUnits);
-			    screen_main(t, p1, p2, p3);
+			    switch (Main_Loop2) {
+				case ML2_USER:	screen_main(); break;
+				case ML2_UNIT1:	screen_unit(0); break;
+				case ML2_UNIT2: screen_unit(1); break;
+				case ML2_UNIT3: screen_unit(2); break;
+			    }
 			}
 		    }
 		    break;
 
-		case MAIN_LOOP1_WAITCON:
+		case ML1_WAITCON:
 		    if (ready_mqtt())
-			Main_Loop1 = MAIN_LOOP1_SEND;
+			Main_Loop1 = ML1_SEND;
 		    break;
 
-		case MAIN_LOOP1_SEND:
+		case ML1_SEND:
 		    ESP_LOGI(TAG, "Loop timer: Send MQTT");
 		    publishNode();
 		    publishUnits();
 		    publishLogs();
-		    Main_Loop1 = MAIN_LOOP1_WAITACK;
+		    Main_Loop1 = ML1_WAITACK;
 		    break;
 
-		case MAIN_LOOP1_WAITACK:
+		case ML1_WAITACK:
 		    if (count_pub == 0) // Wait until all published messages are sent.
-			Main_Loop1 = MAIN_LOOP1_MQTT_DISCONNECT;
+			Main_Loop1 = ML1_MQTT_DISCONNECT;
 		    break;
 
-		case MAIN_LOOP1_MQTT_DISCONNECT:
+		case ML1_MQTT_DISCONNECT:
 		    ESP_LOGI(TAG, "Loop timer: Disconnect MQTT");
 		    connect_mqtt(false); // Doesn't really disconnect.
-                    Main_Loop1 = MAIN_LOOP1_DISCONNECT;
+                    Main_Loop1 = ML1_DISCONNECT;
 		    break;
 
-		case MAIN_LOOP1_DISCONNECT:
+		case ML1_DISCONNECT:
 		    if (! ready_mqtt()) {
 			ESP_LOGI(TAG, "Loop timer: WiFi off");
 		    	requestWiFi_system(false);
-		    	Main_Loop1 = MAIN_LOOP1_WIFI_OFF;
+		    	Main_Loop1 = ML1_WIFI_OFF;
 		    }
 		    break;
 
-		case MAIN_LOOP1_WIFI_OFF:
+		case ML1_WIFI_OFF:
 		    if (! ready_WiFi()) {
 			ESP_LOGI(TAG, "Loop timer: Done");
-			Main_Loop1 = MAIN_LOOP1_DONE;
+			Main_Loop1 = ML1_DONE;
 		    }
 		    break;
 
-		case MAIN_LOOP1_DONE:
+		case ML1_DONE:
 		    break;
 	    }
 
@@ -399,17 +522,54 @@
 		Main_Loop2 = New_Loop2;
 
 		switch (Main_Loop2) {
-		    case MAIN_LOOP2_INIT:
+		    case ML2_INIT:
 			ESP_LOGI(TAG, "Loop user: Init");
 //			u8g2_SetPowerSave(&u8g2, 0); // wake up display
 //			u8g2_ClearBuffer(&u8g2);
-//			New_Loop2 = MAIN_LOOP2_INACTIVE;
-			New_Loop2 = MAIN_LOOP2_DONE;
+			New_Loop2 = ML2_USER;
+			usertimer = INACTIVITY;
+			break;
+
+		    case ML2_USER:
+			ESP_LOGI(TAG, "Loop user: User mainmenu");
+			screen_main();
+			break;
+
+		    case ML2_UNIT1:
+		    case ML2_UNIT2:
+		    case ML2_UNIT3:
+			ESP_LOGI(TAG, "Loop user: Unit %d", Main_Loop2 - ML2_UNIT1);
+			screen_unit(Main_Loop2 - ML2_UNIT1);
+			break;
+
+		    case ML2_SET_WIFI:
+			ESP_LOGI(TAG, "Loop user: Setup WiFi");
 			break;
 
-		    case MAIN_LOOP2_INACTIVE:
-//			u8g2_SetPowerSave(&u8g2, 1); // powersave display
-			New_Loop2 = MAIN_LOOP2_DONE;
+		    case ML2_SET_NETWORK:
+			ESP_LOGI(TAG, "Loop user: Setup Network");
+			break;
+
+		    case ML2_SET_MQTT:
+			ESP_LOGI(TAG, "Loop user: Setup MQTT");
+			break;
+
+		    case ML2_UPDATE:
+			ESP_LOGI(TAG, "Loop user: Update");
+			break;
+
+		    case ML2_SETUP_UNIT1:
+		    case ML2_SETUP_UNIT2:
+		    case ML2_SETUP_UNIT3:
+			ESP_LOGI(TAG, "Loop user: Setup Unit %d", Main_Loop2 - ML2_SETUP_UNIT1);
+			sub = 0;
+			screen_unit_setup(Main_Loop2 - ML2_SETUP_UNIT1, sub);
+			break;
+
+		    case ML2_INACTIVE:
+			ESP_LOGI(TAG, "Loop user: Inactive");
+			u8g2_SetPowerSave(&u8g2, 1); // powersave display
+			New_Loop2 = ML2_DONE;
 			break;
 
 		    default:
@@ -418,10 +578,10 @@
 	    }
 
 	    /*
-	     * Action process.
+	     * Main user processing. Handle the rotary encoder and pushbutton.
 	     */
-	    switch (Main_Loop2) {
-	    // If wakeup from GPIO -- state machine 2
+	    if (Main_Loop2 < ML2_INACTIVE) {
+	    	// If wakeup from GPIO -- state machine 2
 		// Init OLED
 		// If not configured, start configure
 		// If configured select first unit
@@ -443,12 +603,97 @@
 		// Sensors setup menu:	DS18B20 addr	Press is assign
 		//			DS18B20 addr
 
-	    // Break if all done and inactive.
-		default:
-		    break;
+		if (xQueueReceive(event_queue, &event, 250 / portTICK_PERIOD_MS) == pdTRUE) {
+		    usertimer = INACTIVITY;
+		    switch (Main_Loop2) {
+		    	case ML2_USER:		rotate_to_menu(event.state.position, ML2_UNIT1, ML2_USER); break;
+		    	case ML2_UNIT1:		rotate_to_menu(event.state.position, ML2_UNIT2, ML2_USER); break;
+		    	case ML2_UNIT2:		rotate_to_menu(event.state.position, ML2_UNIT3, ML2_UNIT1); break;
+		    	case ML2_UNIT3:		rotate_to_menu(event.state.position, ML2_SET_WIFI, ML2_UNIT2); break;
+		    	case ML2_SET_WIFI:	rotate_to_menu(event.state.position, ML2_SET_NETWORK, ML2_UNIT3); break;
+		    	case ML2_SET_NETWORK:	rotate_to_menu(event.state.position, ML2_SET_MQTT, ML2_SET_WIFI); break;
+		    	case ML2_SET_MQTT:	rotate_to_menu(event.state.position, ML2_UPDATE, ML2_SET_NETWORK); break;
+		    	case ML2_UPDATE:	rotate_to_menu(event.state.position, ML2_UPDATE, ML2_SET_MQTT); break;
+			case ML2_SETUP_UNIT1:
+			case ML2_SETUP_UNIT2:
+			case ML2_SETUP_UNIT3:	if (event.state.position > 0) {
+						    if (sub < 3) {
+							sub++;
+							screen_unit_setup(Main_Loop2 - ML2_SETUP_UNIT1, sub);
+						    }
+						    ESP_ERROR_CHECK(rotary_encoder_reset(&rinfo));
+						} else if (event.state.position < 0) {
+						    if (sub > 0) {
+							sub--;
+							screen_unit_setup(Main_Loop2 - ML2_SETUP_UNIT1, sub);
+						    }
+						    ESP_ERROR_CHECK(rotary_encoder_reset(&rinfo));
+						}
+						break;
+			default:
+		    				ESP_LOGI(TAG, "Event: position %d, direction %s", event.state.position,
+                                		event.state.direction ? (event.state.direction == ROTARY_ENCODER_DIRECTION_CLOCKWISE ? "CW":"CCW"):"NOT_SET");
+		    }
+                } else {
+                    // Poll current position and direction
+                    rotary_encoder_state_t state = { 0 };
+                    ESP_ERROR_CHECK(rotary_encoder_get_state(&rinfo, &state));
+
+//                    ESP_LOGI(TAG, "Poll: position %d, direction %s timer %d", state.position,
+//                    state.direction ? (state.direction == ROTARY_ENCODER_DIRECTION_CLOCKWISE ? "CW" : "CCW") : "NOT_SET", usertimer);
+		    if (usertimer)
+			usertimer--;
+		    else
+			New_Loop2 = ML2_INACTIVE;
+
+                            // Reset the device
+       //                     if (RESET_AT && (state.position >= RESET_AT || state.position <= -RESET_AT)) {
+       //                         ESP_LOGI(TAG, "Reset");
+       //                         ESP_ERROR_CHECK(rotary_encoder_reset(&rinfo));
+       //                     }
+                }
 	    }
 
-	    if (Main_Loop1 == MAIN_LOOP1_DONE && Main_Loop2 == MAIN_LOOP2_DONE) 
+	    switch (Main_Loop2) {
+	    // Break if all done and inactive.
+		case ML2_UNIT1:
+		case ML2_UNIT2:
+		case ML2_UNIT3:
+			if (PushDuration) {
+			    New_Loop2 = ML2_SETUP_UNIT1 + (Main_Loop2 - ML2_UNIT1);
+			    PushDuration = 0;
+			}
+			break;
+
+		case ML2_SETUP_UNIT1:
+		case ML2_SETUP_UNIT2:
+		case ML2_SETUP_UNIT3:
+			if (PushDuration) {
+			    if (sub == 0) {
+				if (xSemaphoreTake(xSemaphoreUnits, 25) == pdTRUE) {
+				    if (units[Main_Loop2 - ML2_SETUP_UNIT1].mode)
+					units[Main_Loop2 - ML2_SETUP_UNIT1].mode = 0;
+				    else
+					units[Main_Loop2 - ML2_SETUP_UNIT1].mode = 1;
+				    write_units();
+                            	    xSemaphoreGive(xSemaphoreUnits);
+				}
+				screen_unit_setup(Main_Loop2 - ML2_SETUP_UNIT1, sub);
+				if (Main_Loop1 == ML1_DONE)
+				    Main_Loop1 = ML1_INIT;
+			    }
+			    if (sub == 3)
+				New_Loop2 = ML2_UNIT1 + (Main_Loop2 - ML2_SETUP_UNIT1);
+			    printf("sub %d  new %d\n", sub, New_Loop2);
+			    PushDuration = 0;
+			}
+			break;
+
+		default:
+			break;
+	    }
+
+	    if (Main_Loop1 == ML1_DONE && Main_Loop2 == ML2_DONE)
 	    	break;
 
 	    vTaskDelay(10 / portTICK_PERIOD_MS);
@@ -465,8 +710,8 @@
     	gettimeofday(&sleep_enter_time, NULL);
 	esp_deep_sleep_start();
 
-	Main_Loop1 = MAIN_LOOP1_INIT;
-	New_Loop2 = MAIN_LOOP2_INIT;
+	Main_Loop1 = ML1_INIT;
+	New_Loop2 = ML2_INIT;
     }
 
 }

mercurial