 	return ret;
 }
 
-static void neurite_child_worker(void)
+static void mqtt_callback(char *topic, byte *payload, unsigned int length)
+{
+	log_dbg("topic (%d): %s\n\r", strlen(topic), topic);
+	log_dbg("data (%d): ", length);
+	for (int i = 0; i < length; i++)
+		USE_SERIAL.print((char)payload[i]);
+	USE_SERIAL.println();
+}
+
+static inline bool mqtt_check_status(void)
+{
+	return mqtt_cli.connected();
+}
+
+static void mqtt_config(void)
+{
+	mqtt_cli.setServer(MQTT_SERVER, 1883);
+	mqtt_cli.setCallback(mqtt_callback);
+}
+
+static void mqtt_connect(struct neurite_data_s *nd)
+{
+	mqtt_config();
+	mqtt_cli.connect(nd->nmcfg.uid);
+}
+
+static void cmd_completed_cb(struct cmd_parser_s *cp)
+{
+	dbg_assert(cp);
+	if (cp->data_len > 0) {
+		log_dbg("msg launch(len %d): %s\n\r", cp->data_len, cp->buf);
+//		MQTT_Publish(&g_nd.mc, g_nd.nmcfg.topic_to, cp->buf, cp->data_len, 0, 0);
+	}
+	__bzero(cp->buf, cp->buf_size);
+	cp->data_len = 0;
+}
+
+int cmd_parser_init(struct cmd_parser_s *cp, char *buf, uint16_t buf_size)
+{
+	dbg_assert(cp);
+	cp->buf = buf;
+	cp->buf_size = buf_size;
+	cp->data_len = 0;
+	cp->callback = cmd_completed_cb;
+	return 0;
+}
+
+void neurite_child_worker(void)
 {
 	log_dbg("my time is: %d ms\n\r", millis());
 }


			if (digitalRead(NEURITE_BUTTON) == LOW) {
				ticker_led.detach();
				ota_over_http(ota_url);
			}
#if 0
			neurite_mqtt_connect(nd);
#endif
			update_worker_state(WORKER_ST_2);
			break;
		case WORKER_ST_2:
#if 0
			if (!nd->mqtt_connected)
				break;
			MQTT_Subscribe(&nd->mc, nd->nmcfg.topic_from, 1);
			uint8_t *payload_buf = (uint8_t *)os_malloc(32);
			dbg_assert(payload_buf);
			os_sprintf(payload_buf, "checkin: %s", nd->nmcfg.uid);
			MQTT_Publish(&nd->mc, nd->nmcfg.topic_to, payload_buf, strlen(payload_buf), 1, 0);
			os_free(payload_buf);
#endif
			ticker_led.detach();
			ticker_led.attach_ms(50, ticker_led_breath);
			start_child_worker();
			update_worker_state(WORKER_ST_3);
			break;
		case WORKER_ST_3:
			break;
		default:
			log_err("unknown worker state: %d\n\r", worker_st);

	ticker_worker.detach();
}

inline void neurite_worker(void)
{
	struct neurite_data_s *nd = &g_nd;
	switch (worker_st) {
		case WORKER_ST_0:
			ticker_led.attach_ms(50, ticker_led_blink);
			wifi_config();
			update_worker_state(WORKER_ST_1);
			break;
		case WORKER_ST_1:
			if (!wifi_check_status())
				break;

			log_dbg("WiFi connected\n\r");
