/*---------------------------------------------------------------------------*/ PROCESS_THREAD(mqtt_demo_process, ev, data) { PROCESS_BEGIN(); printf("MQTT Demo Process\n"); if(init_config() != 1) { PROCESS_EXIT(); } update_config(); def_rt_rssi = 0x8000000; uip_icmp6_echo_reply_callback_add(&echo_reply_notification, echo_reply_handler); etimer_set(&echo_request_timer, conf.def_rt_ping_interval); PUBLISH_TRIGGER->configure(SENSORS_ACTIVE, 1); /* Main loop */ while(1) { PROCESS_YIELD(); if(ev == sensors_event && data == PUBLISH_TRIGGER) { if(state == STATE_ERROR) { connect_attempt = 1; state = STATE_REGISTERED; } } if((ev == PROCESS_EVENT_TIMER && data == &publish_periodic_timer) || ev == PROCESS_EVENT_POLL || (ev == sensors_event && data == PUBLISH_TRIGGER && PUBLISH_TRIGGER->value(BUTTON_SENSOR_VALUE_STATE) == 0)) { state_machine(); } if(ev == PROCESS_EVENT_TIMER && data == &echo_request_timer) { ping_parent(); etimer_set(&echo_request_timer, conf.def_rt_ping_interval); } } PROCESS_END(); }
/*---------------------------------------------------------------------------*/ PROCESS_THREAD(mqtt_client_process, ev, data) { PROCESS_BEGIN(); printf("CC26XX MQTT Client Process\n"); conf = &cc26xx_web_demo_config.mqtt_config; if(init_config() != 1) { PROCESS_EXIT(); } register_http_post_handlers(); def_rt_rssi = 0x8000000; uip_icmp6_echo_reply_callback_add(&echo_reply_notification, echo_reply_handler); etimer_set(&echo_request_timer, conf->def_rt_ping_interval); /* Main loop */ while(1) { PROCESS_YIELD(); if(ev == sensors_event && data == CC26XX_WEB_DEMO_MQTT_PUBLISH_TRIGGER) { if(state == MQTT_CLIENT_STATE_ERROR) { connect_attempt = 1; state = MQTT_CLIENT_STATE_REGISTERED; } } if(ev == httpd_simple_event_new_config) { /* * Schedule next pass in a while. When HTTPD sends us this event, it is * also in the process of sending the config page. Wait a little before * reconnecting, so as to not cause congestion. */ etimer_set(&publish_periodic_timer, NEW_CONFIG_WAIT_INTERVAL); } if(ev == cc26xx_web_demo_config_loaded_event) { update_config(); } if((ev == PROCESS_EVENT_TIMER && data == &publish_periodic_timer) || ev == PROCESS_EVENT_POLL || ev == cc26xx_web_demo_publish_event || (ev == sensors_event && data == CC26XX_WEB_DEMO_MQTT_PUBLISH_TRIGGER)) { state_machine(); } if(ev == PROCESS_EVENT_TIMER && data == &echo_request_timer) { ping_parent(); etimer_set(&echo_request_timer, conf->def_rt_ping_interval); } if(ev == cc26xx_web_demo_load_config_defaults) { init_config(); etimer_set(&publish_periodic_timer, NEW_CONFIG_WAIT_INTERVAL); } } PROCESS_END(); }
/*---------------------------------------------------------------------------*/ static void state_machine(void) { switch(state) { case MQTT_CLIENT_STATE_INIT: /* If we have just been configured register MQTT connection */ mqtt_register(&conn, &mqtt_client_process, client_id, mqtt_event, MQTT_CLIENT_MAX_SEGMENT_SIZE); /* * Authentication: provide user name and password */ if(strlen(conf->auth_token) > 0) { mqtt_set_username_password(&conn, "use-token-auth", conf->auth_token); } /* _register() will set auto_reconnect. We don't want that. */ conn.auto_reconnect = 0; connect_attempt = 1; /* * Wipe out the default route so we'll republish it every time we switch to * a new broker */ memset(&def_route, 0, sizeof(def_route)); state = MQTT_CLIENT_STATE_REGISTERED; DBG("Init\n"); /* Continue */ case MQTT_CLIENT_STATE_REGISTERED: if(uip_ds6_get_global(ADDR_PREFERRED) != NULL) { /* Registered and with a public IP. Connect */ DBG("Registered. Connect attempt %u\n", connect_attempt); ping_parent(); connect_to_broker(); } etimer_set(&publish_periodic_timer, CC26XX_WEB_DEMO_NET_CONNECT_PERIODIC); return; break; case MQTT_CLIENT_STATE_CONNECTING: leds_on(CC26XX_WEB_DEMO_STATUS_LED); ctimer_set(&ct, CONNECTING_LED_DURATION, publish_led_off, NULL); /* Not connected yet. Wait */ DBG("Connecting (%u)\n", connect_attempt); break; case MQTT_CLIENT_STATE_CONNECTED: /* Don't subscribe unless we are a registered device if(strncasecmp(conf->org_id, QUICKSTART, strlen(conf->org_id)) == 0) { DBG("Using 'quickstart': Skipping subscribe\n"); state = MQTT_CLIENT_STATE_PUBLISHING; }*/ /* Continue */ case MQTT_CLIENT_STATE_PUBLISHING: /* If the timer expired, the connection is stable. */ if(timer_expired(&connection_life)) { /* * Intentionally using 0 here instead of 1: We want RECONNECT_ATTEMPTS * attempts if we disconnect after a successful connect */ connect_attempt = 0; } if(mqtt_ready(&conn) && conn.out_buffer_sent) { /* Connected. Publish */ if(state == MQTT_CLIENT_STATE_CONNECTED) { subscribe(); state = MQTT_CLIENT_STATE_PUBLISHING; } else { leds_on(CC26XX_WEB_DEMO_STATUS_LED); ctimer_set(&ct, PUBLISH_LED_ON_DURATION, publish_led_off, NULL); publish(); } etimer_set(&publish_periodic_timer, conf->pub_interval); DBG("Publishing\n"); /* Return here so we don't end up rescheduling the timer */ return; } else { /* * Our publish timer fired, but some MQTT packet is already in flight * (either not sent at all, or sent but not fully ACKd). * * This can mean that we have lost connectivity to our broker or that * simply there is some network delay. In both cases, we refuse to * trigger a new message and we wait for TCP to either ACK the entire * packet after retries, or to timeout and notify us. */ DBG("Publishing... (MQTT state=%d, q=%u)\n", conn.state, conn.out_queue_full); } break; case MQTT_CLIENT_STATE_DISCONNECTED: DBG("Disconnected\n"); if(connect_attempt < RECONNECT_ATTEMPTS || RECONNECT_ATTEMPTS == RETRY_FOREVER) { /* Disconnect and backoff */ clock_time_t interval; mqtt_disconnect(&conn); connect_attempt++; interval = connect_attempt < 3 ? RECONNECT_INTERVAL << connect_attempt : RECONNECT_INTERVAL << 3; DBG("Disconnected. Attempt %u in %lu ticks\n", connect_attempt, interval); etimer_set(&publish_periodic_timer, interval); state = MQTT_CLIENT_STATE_REGISTERED; return; } else { /* Max reconnect attempts reached. Enter error state */ state = MQTT_CLIENT_STATE_ERROR; DBG("Aborting connection after %u attempts\n", connect_attempt - 1); } break; case MQTT_CLIENT_STATE_NEWCONFIG: /* Only update config after we have disconnected */ if(conn.state == MQTT_CONN_STATE_NOT_CONNECTED) { update_config(); DBG("New config\n"); /* update_config() scheduled next pass. Return */ return; } break; case MQTT_CLIENT_STATE_CONFIG_ERROR: /* Idle away. The only way out is a new config */ printf("Bad configuration.\n"); return; case MQTT_CLIENT_STATE_ERROR: default: leds_on(CC26XX_WEB_DEMO_STATUS_LED); /* * 'default' should never happen. * * If we enter here it's because of some error. Stop timers. The only thing * that can bring us out is a new config event */ printf("Default case: State=0x%02x\n", state); return; } /* If we didn't return so far, reschedule ourselves */ etimer_set(&publish_periodic_timer, STATE_MACHINE_PERIODIC); }