/** * @brief Tcp client connect success callback function. * @param arg: contain the ip link information * @retval None */ void ICACHE_FLASH_ATTR mqtt_tcpclient_connect_cb(void *arg) { struct espconn *pCon = (struct espconn *)arg; MQTT_Client* client = (MQTT_Client *)pCon->reverse; espconn_regist_disconcb(client->pCon, mqtt_tcpclient_discon_cb); espconn_regist_recvcb(client->pCon, mqtt_tcpclient_recv);//////// espconn_regist_sentcb(client->pCon, mqtt_tcpclient_sent_cb);/////// INFO("MQTT: Connected to broker %s:%d\r\n", client->host, client->port); mqtt_msg_init(&client->mqtt_state.mqtt_connection, client->mqtt_state.out_buffer, client->mqtt_state.out_buffer_length); client->mqtt_state.outbound_message = mqtt_msg_connect(&client->mqtt_state.mqtt_connection, client->mqtt_state.connect_info); client->mqtt_state.pending_msg_type = mqtt_get_type(client->mqtt_state.outbound_message->data); client->mqtt_state.pending_msg_id = mqtt_get_id(client->mqtt_state.outbound_message->data, client->mqtt_state.outbound_message->length); client->sendTimeout = MQTT_SEND_TIMOUT; INFO("MQTT: Sending, type: %d, id: %04X\r\n",client->mqtt_state.pending_msg_type, client->mqtt_state.pending_msg_id); if(client->security){ espconn_secure_sent(client->pCon, client->mqtt_state.outbound_message->data, client->mqtt_state.outbound_message->length); } else{ espconn_sent(client->pCon, client->mqtt_state.outbound_message->data, client->mqtt_state.outbound_message->length); } client->mqtt_state.outbound_message = NULL; client->connState = MQTT_CONNECT_SENDING; system_os_post(MQTT_TASK_PRIO, 0, (os_param_t)client); }
static void mqtt_socket_connected(void *arg) { NODE_DBG("enter mqtt_socket_connected.\n"); struct espconn *pesp_conn = arg; if(pesp_conn == NULL) return; lmqtt_userdata *mud = (lmqtt_userdata *)pesp_conn->reverse; if(mud == NULL) return; mud->connected = true; espconn_regist_recvcb(pesp_conn, mqtt_socket_received); espconn_regist_sentcb(pesp_conn, mqtt_socket_sent); espconn_regist_disconcb(pesp_conn, mqtt_socket_disconnected); uint8_t temp_buffer[MQTT_BUF_SIZE]; // call mqtt_connect() to start a mqtt connect stage. mqtt_msg_init(&mud->mqtt_state.mqtt_connection, temp_buffer, MQTT_BUF_SIZE); mqtt_message_t* temp_msg = mqtt_msg_connect(&mud->mqtt_state.mqtt_connection, mud->mqtt_state.connect_info); NODE_DBG("Send MQTT connection infomation, data len: %d, d[0]=%d \r\n", temp_msg->length, temp_msg->data[0]); mud->event_timeout = MQTT_SEND_TIMEOUT; // not queue this message. should send right now. or should enqueue this before head. if(mud->secure) espconn_secure_sent(pesp_conn, temp_msg->data, temp_msg->length); else espconn_sent(pesp_conn, temp_msg->data, temp_msg->length); mud->keep_alive_tick = 0; mud->connState = MQTT_CONNECT_SENDING; NODE_DBG("leave mqtt_socket_connected.\n"); return; }
/** * @brief Tcp client connect success callback function. * @param arg: contain the ip link information * @retval None */ void ICACHE_FLASH_ATTR mqtt_tcpclient_connect_cb(void *arg) { struct espconn *pCon = (struct espconn *)arg; MQTT_Client* client = (MQTT_Client *)pCon->reserve; espconn_regist_disconcb(client->pCon, mqtt_tcpclient_discon_cb); espconn_regist_recvcb(client->pCon, mqtt_tcpclient_recv);//////// espconn_regist_sentcb(client->pCon, mqtt_tcpclient_sent_cb);/////// INFO("MQTT: Connected to broker %s:%d\r\n", client->host, client->port); mqtt_msg_init(&client->mqtt_state.mqtt_connection, client->mqtt_state.out_buffer, client->mqtt_state.out_buffer_length); client->mqtt_state.outbound_message = mqtt_msg_connect(&client->mqtt_state.mqtt_connection, client->mqtt_state.connect_info); client->mqtt_state.pending_msg_type = mqtt_get_type(client->mqtt_state.outbound_message->data); client->mqtt_state.pending_msg_id = mqtt_get_id(client->mqtt_state.outbound_message->data, client->mqtt_state.outbound_message->length); client->sendTimeout = MQTT_SEND_TIMOUT; INFO("MQTT: Sending, type: %d, id: %04X\r\n", client->mqtt_state.pending_msg_type, client->mqtt_state.pending_msg_id); if (client->security) { #ifdef MQTT_SSL_ENABLE espconn_secure_send(client->pCon, client->mqtt_state.outbound_message->data, client->mqtt_state.outbound_message->length); #else INFO("TCP: Do not support SSL\r\n"); #endif } else { espconn_send(client->pCon, client->mqtt_state.outbound_message->data, client->mqtt_state.outbound_message->length); } client->mqtt_state.outbound_message = NULL; client->connState = MQTT_CONNECT_SENDING; xSemaphoreGive(client->mqttTaskSem); }
void ICACHE_FLASH_ATTR MQTT_Task(os_event_t *e) { MQTT_Client* client = (MQTT_Client*)e->par; uint8_t dataBuffer[MQTT_BUF_SIZE]; uint16_t dataLen; sint8 res; switch(client->connState){ case TCP_RECONNECT_REQ: break; case TCP_RECONNECT: MQTT_Connect(client); //spam INFO("TCP:Reconect to: %s:%d\r\n", client->host, client->port); client->connState = TCP_CONNECTING; break; case MQTT_CONNECT_SEND: mqtt_msg_init(&client->mqtt_state.mqtt_connection, client->mqtt_state.out_buffer, client->mqtt_state.out_buffer_length); client->mqtt_state.outbound_message = mqtt_msg_connect(&client->mqtt_state.mqtt_connection, client->mqtt_state.connect_info); if(client->security){ res = espconn_secure_sent(client->pCon, client->mqtt_state.outbound_message->data, client->mqtt_state.outbound_message->length); } else { res = espconn_sent(client->pCon, client->mqtt_state.outbound_message->data, client->mqtt_state.outbound_message->length); } if (res != ESPCONN_OK) { //spam INFO("MQTT: espconn_sent returned %d at line %d\r\n", res, __LINE__); } //spam INFO("MQTT: Send mqtt connection info, to broker %s:%d\r\n", client->host, client->port); client->connState = MQTT_CONNECT_SENDING; client->mqtt_state.outbound_message = NULL; break; case MQTT_DATA: if(QUEUE_Gets(&client->msgQueue, dataBuffer, &dataLen, MQTT_BUF_SIZE) == 0){ //spam INFO("MQTT: Sending..\r\n"); if(client->security){ res = espconn_secure_sent(client->pCon, dataBuffer, dataLen); } else{ res = espconn_sent(client->pCon, dataBuffer, dataLen); } if (res != ESPCONN_OK) { //spam INFO("MQTT: espconn_sent returned %d at line %d\r\n", res, __LINE__); } client->mqtt_state.outbound_message = NULL; if(client->mqtt_state.pending_msg_type == MQTT_MSG_TYPE_PUBLISH && client->mqtt_state.pending_msg_id == 0) //spam INFO("MQTT: Publish message is done!\r\n"); break; } break; //spam default: //spam INFO("MQTT: Unhandled state %d!\r\n", client->connState); } }
/** * @brief MQTT initialization mqtt client function * @param client: MQTT_Client reference * @param clientid: MQTT client id * @param client_user:MQTT client user * @param client_pass:MQTT client password * @param client_pass:MQTT keep alive timer, in second * @retval None */ void ICACHE_FLASH_ATTR MQTT_InitClient(MQTT_Client *mqttClient, uint8_t* client_id, uint8_t* client_user, uint8_t* client_pass, uint32_t keepAliveTime, uint8_t cleanSession) { uint32_t temp; INFO("MQTT_InitClient\r\n"); memset(&mqttClient->connect_info, 0, sizeof(mqtt_connect_info_t)); temp = strlen(client_id); mqttClient->connect_info.client_id = (uint8_t*)calloc(1, temp + 1); strcpy(mqttClient->connect_info.client_id, client_id); mqttClient->connect_info.client_id[temp] = 0; if (client_user) { temp = strlen(client_user); mqttClient->connect_info.username = (uint8_t*)calloc(1, temp + 1); strcpy(mqttClient->connect_info.username, client_user); mqttClient->connect_info.username[temp] = 0; } if (client_pass) { temp = strlen(client_pass); mqttClient->connect_info.password = (uint8_t*)calloc(1, temp + 1); strcpy(mqttClient->connect_info.password, client_pass); mqttClient->connect_info.password[temp] = 0; } mqttClient->connect_info.keepalive = keepAliveTime; mqttClient->connect_info.clean_session = cleanSession; mqttClient->mqtt_state.in_buffer = (uint8_t *) calloc(1, MQTT_BUF_SIZE); mqttClient->mqtt_state.in_buffer_length = MQTT_BUF_SIZE; mqttClient->mqtt_state.out_buffer = (uint8_t *) calloc(1, MQTT_BUF_SIZE); mqttClient->mqtt_state.out_buffer_length = MQTT_BUF_SIZE; mqttClient->mqtt_state.connect_info = &mqttClient->connect_info; mqtt_msg_init(&mqttClient->mqtt_state.mqtt_connection, mqttClient->mqtt_state.out_buffer, mqttClient->mqtt_state.out_buffer_length); QUEUE_Init(&mqttClient->msgQueue, QUEUE_BUFFER_SIZE); vSemaphoreCreateBinary(mqttClient->mqttTaskSem); vSemaphoreCreateBinary(mqttClient->mqttExitSem); mqttClient->mqttTimer = xTimerCreate(NULL, configTICK_RATE_HZ, 1, (void *) mqttClient, mqtt_timer); mqttClient->mqttTask = xTaskCreate(MQTT_Task, NULL, configMINIMAL_STACK_SIZE, mqttClient->mqttTaskSem, MQTT_TASK_PRIO, NULL); xSemaphoreGive(mqttClient->mqttTaskSem); }
/** * @brief MQTT initialization mqtt client function * @param client: MQTT_Client reference * @param clientid: MQTT client id * @param client_user:MQTT client user * @param client_pass:MQTT client password * @param client_pass:MQTT keep alive timer, in second * @retval None */ void ICACHE_FLASH_ATTR MQTT_InitClient(MQTT_Client *mqttClient, uint8_t* client_id, uint8_t* client_user, uint8_t* client_pass, uint32_t keepAliveTime, uint8_t cleanSession) { uint32_t temp; INFO("MQTT_InitClient\r\n"); os_memset(&mqttClient->connect_info, 0, sizeof(mqtt_connect_info_t)); temp = os_strlen(client_id); mqttClient->connect_info.client_id = (uint8_t*)os_zalloc(temp + 1); os_strcpy(mqttClient->connect_info.client_id, client_id); mqttClient->connect_info.client_id[temp] = 0; if (client_user) { temp = os_strlen(client_user); mqttClient->connect_info.username = (uint8_t*)os_zalloc(temp + 1); os_strcpy(mqttClient->connect_info.username, client_user); mqttClient->connect_info.username[temp] = 0; } if (client_pass) { temp = os_strlen(client_pass); mqttClient->connect_info.password = (uint8_t*)os_zalloc(temp + 1); os_strcpy(mqttClient->connect_info.password, client_pass); mqttClient->connect_info.password[temp] = 0; } mqttClient->connect_info.keepalive = keepAliveTime; mqttClient->connect_info.clean_session = cleanSession; mqttClient->mqtt_state.in_buffer = (uint8_t *)os_zalloc(MQTT_BUF_SIZE); mqttClient->mqtt_state.in_buffer_length = MQTT_BUF_SIZE; mqttClient->mqtt_state.out_buffer = (uint8_t *)os_zalloc(MQTT_BUF_SIZE); mqttClient->mqtt_state.out_buffer_length = MQTT_BUF_SIZE; mqttClient->mqtt_state.connect_info = &mqttClient->connect_info; mqtt_msg_init(&mqttClient->mqtt_state.mqtt_connection, mqttClient->mqtt_state.out_buffer, mqttClient->mqtt_state.out_buffer_length); QUEUE_Init(&mqttClient->msgQueue, QUEUE_BUFFER_SIZE); system_os_task(MQTT_Task, MQTT_TASK_PRIO, mqtt_procTaskQueue, MQTT_TASK_QUEUE_SIZE); system_os_post(MQTT_TASK_PRIO, 0, (os_param_t)mqttClient); }
/** * @brief Tcp client connect success callback function. * @param arg: contain the ip link information * @retval None */ void ICACHE_FLASH_ATTR mqtt_tcpclient_connect_cb(void *arg) { struct espconn *pCon = (struct espconn *)arg; MQTT_Client* client = (MQTT_Client *)pCon->reverse; espconn_regist_disconcb(client->pCon, mqtt_tcpclient_discon_cb); espconn_regist_recvcb(client->pCon, mqtt_tcpclient_recv);//////// espconn_regist_sentcb(client->pCon, mqtt_tcpclient_sent_cb);/////// INFO("MQTT: Connected to broker %s:%d\r\n", client->host, client->port); mqtt_msg_init(&client->mqtt_state.mqtt_connection, client->mqtt_state.out_buffer, client->mqtt_state.out_buffer_length); client->mqtt_state.outbound_message = mqtt_msg_connect(&client->mqtt_state.mqtt_connection, client->mqtt_state.connect_info); if(QUEUE_Puts(&client->msgQueue, client->mqtt_state.outbound_message->data, client->mqtt_state.outbound_message->length) == -1){ INFO("MQTT: Exceed the amount of queues\r\n"); } client->mqtt_state.outbound_message = NULL; client->connState = MQTT_DATA; system_os_post(MQTT_TASK_PRIO, 0, (os_param_t)client); }
/** * @brief MQTT initialization mqtt client function * @param client: MQTT_Client reference * @param clientid: MQTT client id * @param client_user:MQTT client user * @param client_pass:MQTT client password * @param client_pass:MQTT keep alive timer, in second * @retval None */ void FUNCTION_ATTRIBUTE MQTT_InitClient(MQTT_Client *mqttClient, uint8_t* client_id, uint8_t* client_user, uint8_t* client_pass, uint32_t keepAliveTime, uint8_t cleanSession) { uint32_t temp; INFO("MQTT_InitClient\r\n"); pd_memset(&mqttClient->connect_info, 0, sizeof(mqtt_connect_info_t)); temp = pd_strlen(client_id); mqttClient->connect_info.client_id = (uint8_t*)pd_malloc(temp + 1); pd_memset(mqttClient->connect_info.client_id, 0, temp + 1); pd_strcpy(mqttClient->connect_info.client_id, client_id); mqttClient->connect_info.client_id[temp] = 0; temp = pd_strlen(client_user); mqttClient->connect_info.username = (uint8_t*)pd_malloc(temp + 1); pd_memset(mqttClient->connect_info.username, 0, temp + 1); pd_strcpy(mqttClient->connect_info.username, client_user); mqttClient->connect_info.username[temp] = 0; temp = pd_strlen(client_pass); mqttClient->connect_info.password = (uint8_t*)pd_malloc(temp + 1); pd_memset(mqttClient->connect_info.password, 0, temp + 1); pd_strcpy(mqttClient->connect_info.password, client_pass); mqttClient->connect_info.password[temp] = 0; mqttClient->connect_info.keepalive = keepAliveTime; mqttClient->connect_info.clean_session = cleanSession; mqttClient->mqtt_state.in_buffer = (uint8_t *)pd_malloc(MQTT_BUF_SIZE); pd_memset(mqttClient->mqtt_state.in_buffer, 0, MQTT_BUF_SIZE); mqttClient->mqtt_state.in_buffer_length = MQTT_BUF_SIZE; mqttClient->mqtt_state.out_buffer = (uint8_t *)pd_malloc(MQTT_BUF_SIZE); pd_memset(mqttClient->mqtt_state.out_buffer, 0, MQTT_BUF_SIZE); mqttClient->mqtt_state.out_buffer_length = MQTT_BUF_SIZE; mqttClient->mqtt_state.connect_info = &mqttClient->connect_info; mqttClient->mqtt_state.message_length_read = 0; mqtt_msg_init(&mqttClient->mqtt_state.mqtt_connection, mqttClient->mqtt_state.out_buffer, mqttClient->mqtt_state.out_buffer_length); QUEUE_Init(&mqttClient->msgQueue, QUEUE_BUFFER_SIZE); //MQTT_Task(mqttClient); }
/** * @brief MQTT initialization mqtt client function * @param client: MQTT_Client reference * @param host: Domain or IP string * @param port: Port to connect * @param security: 1 for ssl, 0 for none * @param clientid: MQTT client id * @param client_user: MQTT client user * @param client_pass: MQTT client password * @param keepAliveTime: MQTT keep alive timer, in second * @param cleanSession: On connection, a client sets the "clean session" flag, which is sometimes also known as the "clean start" flag. * If clean session is set to false, then the connection is treated as durable. This means that when the client * disconnects, any subscriptions it has will remain and any subsequent QoS 1 or 2 messages will be stored until * it connects again in the future. If clean session is true, then all subscriptions will be removed for the client * when it disconnects. * @retval None */ void ICACHE_FLASH_ATTR MQTT_Init(MQTT_Client* client, char* host, uint32 port, uint8_t security, uint8_t sendTimeout, char* client_id, char* client_user, char* client_pass, uint8_t keepAliveTime) { DBG_MQTT("MQTT_Init\n"); os_memset(client, 0, sizeof(MQTT_Client)); client->host = (char*)os_zalloc(os_strlen(host) + 1); os_strcpy(client->host, host); client->port = port; client->security = !!security; // timeouts with sanity checks client->sendTimeout = sendTimeout == 0 ? 1 : sendTimeout; client->reconTimeout = 1; // reset reconnect back-off os_memset(&client->connect_info, 0, sizeof(mqtt_connect_info_t)); client->connect_info.client_id = (char*)os_zalloc(os_strlen(client_id) + 1); os_strcpy(client->connect_info.client_id, client_id); client->connect_info.username = (char*)os_zalloc(os_strlen(client_user) + 1); os_strcpy(client->connect_info.username, client_user); client->connect_info.password = (char*)os_zalloc(os_strlen(client_pass) + 1); os_strcpy(client->connect_info.password, client_pass); client->connect_info.keepalive = keepAliveTime; client->connect_info.clean_session = 1; client->in_buffer = (uint8_t *)os_zalloc(MQTT_MAX_RCV_MESSAGE); client->in_buffer_size = MQTT_MAX_RCV_MESSAGE; uint8_t *out_buffer = (uint8_t *)os_zalloc(MQTT_MAX_SHORT_MESSAGE); mqtt_msg_init(&client->mqtt_connection, out_buffer, MQTT_MAX_SHORT_MESSAGE); }
/** * @brief Tcp client connect success callback function. * @param arg: contain the ip link information * @retval None */ void FUNCTION_ATTRIBUTE mqtt_tcpclient_connect_cb(void *arg, int8_t errno) { struct pando_tcp_conn *pCon = (struct pando_tcp_conn *)arg; MQTT_Client* client = (MQTT_Client *)pCon->reverse; struct data_buf buffer; net_tcp_register_disconnected_callback(pCon, mqtt_tcpclient_discon_cb); net_tcp_register_recv_callback(pCon, mqtt_tcpclient_recv); net_tcp_register_sent_callback(pCon, mqtt_tcpclient_sent_cb); INFO("MQTT: Connected to broker %s:%d\r\n", client->host, client->port); mqtt_msg_init(&client->mqtt_state.mqtt_connection, client->mqtt_state.out_buffer, client->mqtt_state.out_buffer_length); client->mqtt_state.outbound_message = mqtt_msg_connect(&client->mqtt_state.mqtt_connection, client->mqtt_state.connect_info); client->mqtt_state.pending_msg_type = mqtt_get_type(client->mqtt_state.outbound_message->data); client->mqtt_state.pending_msg_id = mqtt_get_id(client->mqtt_state.outbound_message->data, client->mqtt_state.outbound_message->length); client->sendTimeout = MQTT_SEND_TIMOUT; buffer.length = client->mqtt_state.outbound_message->length; buffer.data = client->mqtt_state.outbound_message->data; INFO("MQTT: Sending, type: %d, id: %04X\r\n",client->mqtt_state.pending_msg_type, client->mqtt_state.pending_msg_id); net_tcp_send(pCon, buffer, client->sendTimeout); client->mqtt_state.outbound_message = NULL; client->connState = MQTT_CONNECT_SENDING; MQTT_Task(client); }
static PT_THREAD(handle_mqtt_connection(mqtt_state_t* state)) { static struct etimer keepalive_timer; uint8_t msg_type; uint8_t msg_qos; uint16_t msg_id; PSOCK_BEGIN(&state->ps); // Initialise and send CONNECT message mqtt_msg_init(&state->mqtt_connection, state->out_buffer, state->out_buffer_length); state->outbound_message = mqtt_msg_connect(&state->mqtt_connection, state->connect_info); PSOCK_SEND(&state->ps, state->outbound_message->data, state->outbound_message->length); state->outbound_message = NULL; // Wait for CONACK message PSOCK_READBUF_LEN(&state->ps, 2); if(mqtt_get_type(state->in_buffer) != MQTT_MSG_TYPE_CONNACK) PSOCK_CLOSE_EXIT(&state->ps); // Tell the client we're connected mqtt_flags |= MQTT_FLAG_CONNECTED; complete_pending(state, MQTT_EVENT_TYPE_CONNECTED); // Setup the keep alive timer and enter main message processing loop etimer_set(&keepalive_timer, CLOCK_SECOND * state->connect_info->keepalive); while(1) { // Wait for something to happen: // new incoming data, // new outgoing data, // keep alive timer expired PSOCK_WAIT_UNTIL(&state->ps, PSOCK_NEWDATA(&state->ps) || state->outbound_message != NULL || etimer_expired(&keepalive_timer)); // If there's a new message waiting to go out, then send it if(state->outbound_message != NULL) { PSOCK_SEND(&state->ps, state->outbound_message->data, state->outbound_message->length); state->outbound_message = NULL; // If it was a PUBLISH message with QoS-0 then tell the client it's done if(state->pending_msg_type == MQTT_MSG_TYPE_PUBLISH && state->pending_msg_id == 0) complete_pending(state, MQTT_EVENT_TYPE_PUBLISHED); // Reset the keepalive timer as we've just sent some data etimer_restart(&keepalive_timer); continue; } // If the keep-alive timer expired then prepare a ping for sending // and reset the timer if(etimer_expired(&keepalive_timer)) { state->outbound_message = mqtt_msg_pingreq(&state->mqtt_connection); etimer_reset(&keepalive_timer); continue; } // If we get here we must have woken for new incoming data, // read and process it. PSOCK_READBUF_LEN(&state->ps, 2); state->message_length_read = PSOCK_DATALEN(&state->ps); state->message_length = mqtt_get_total_length(state->in_buffer, state->message_length_read); msg_type = mqtt_get_type(state->in_buffer); msg_qos = mqtt_get_qos(state->in_buffer); msg_id = mqtt_get_id(state->in_buffer, state->in_buffer_length); switch(msg_type) { case MQTT_MSG_TYPE_SUBACK: if(state->pending_msg_type == MQTT_MSG_TYPE_SUBSCRIBE && state->pending_msg_id == msg_id) complete_pending(state, MQTT_EVENT_TYPE_SUBSCRIBED); break; case MQTT_MSG_TYPE_UNSUBACK: if(state->pending_msg_type == MQTT_MSG_TYPE_UNSUBSCRIBE && state->pending_msg_id == msg_id) complete_pending(state, MQTT_EVENT_TYPE_UNSUBSCRIBED); break; case MQTT_MSG_TYPE_PUBLISH: if(msg_qos == 1) state->outbound_message = mqtt_msg_puback(&state->mqtt_connection, msg_id); else if(msg_qos == 2) state->outbound_message = mqtt_msg_pubrec(&state->mqtt_connection, msg_id); deliver_publish(state, state->in_buffer, state->message_length_read); break; case MQTT_MSG_TYPE_PUBACK: if(state->pending_msg_type == MQTT_MSG_TYPE_PUBLISH && state->pending_msg_id == msg_id) complete_pending(state, MQTT_EVENT_TYPE_PUBLISHED); break; case MQTT_MSG_TYPE_PUBREC: state->outbound_message = mqtt_msg_pubrel(&state->mqtt_connection, msg_id); break; case MQTT_MSG_TYPE_PUBREL: state->outbound_message = mqtt_msg_pubcomp(&state->mqtt_connection, msg_id); break; case MQTT_MSG_TYPE_PUBCOMP: if(state->pending_msg_type == MQTT_MSG_TYPE_PUBLISH && state->pending_msg_id == msg_id) complete_pending(state, MQTT_EVENT_TYPE_PUBLISHED); break; case MQTT_MSG_TYPE_PINGREQ: state->outbound_message = mqtt_msg_pingresp(&state->mqtt_connection); break; case MQTT_MSG_TYPE_PINGRESP: // Ignore break; } // NOTE: this is done down here and not in the switch case above // because the PSOCK_READBUF_LEN() won't work inside a switch // statement due to the way protothreads resume. if(msg_type == MQTT_MSG_TYPE_PUBLISH) { uint16_t len; // adjust message_length and message_length_read so that // they only account for the publish data and not the rest of the // message, this is done so that the offset passed with the // continuation event is the offset within the publish data and // not the offset within the message as a whole. len = state->message_length_read; mqtt_get_publish_data(state->in_buffer, &len); len = state->message_length_read - len; state->message_length -= len; state->message_length_read -= len; while(state->message_length_read < state->message_length) { PSOCK_READBUF_LEN(&state->ps, state->message_length - state->message_length_read); deliver_publish_continuation(state, state->message_length_read, state->in_buffer, PSOCK_DATALEN(&state->ps)); state->message_length_read += PSOCK_DATALEN(&state->ps); } } } PSOCK_END(&state->ps); }
/** * @brief MQTT initialization mqtt client function * @param client: MQTT_Client reference * @param clientid: MQTT client id * @param client_user:MQTT client user * @param client_pass:MQTT client password * @param client_pass:MQTT keep alive timer, in second * @retval None */ BOOL ICACHE_FLASH_ATTR MQTT_InitClient(MQTT_Client *mqttClient, uint8_t* client_id, uint8_t* client_user, uint8_t* client_pass, uint32_t keepAliveTime, uint8_t cleanSession) { uint32_t temp; MQTT_INFO("MQTT:InitClient\r\n"); os_memset(&mqttClient->connect_info, 0, sizeof(mqtt_connect_info_t)); if ( !client_id ) { /* Should be allowed by broker, but clean session flag must be set. */ #ifdef PROTOCOL_NAMEv311 if (cleanSession) { mqttClient->connect_info.client_id = zero_len_id; } else { MQTT_INFO("cleanSession must be set to use 0 length client_id\r\n"); return false; } /* Not supported. Return. */ #else MQTT_INFO("Client ID required for MQTT < 3.1.1!\r\n"); return false; #endif } /* If connect_info's client_id is still NULL and we get here, we can * * assume the passed client_id is non-NULL. */ if ( !(mqttClient->connect_info.client_id) ) { temp = os_strlen(client_id); mqttClient->connect_info.client_id = (uint8_t*)os_zalloc(temp + 1); os_strcpy(mqttClient->connect_info.client_id, client_id); mqttClient->connect_info.client_id[temp] = 0; } if (client_user) { temp = os_strlen(client_user); mqttClient->connect_info.username = (uint8_t*)os_zalloc(temp + 1); os_strcpy(mqttClient->connect_info.username, client_user); mqttClient->connect_info.username[temp] = 0; } if (client_pass) { temp = os_strlen(client_pass); mqttClient->connect_info.password = (uint8_t*)os_zalloc(temp + 1); os_strcpy(mqttClient->connect_info.password, client_pass); mqttClient->connect_info.password[temp] = 0; } mqttClient->connect_info.keepalive = keepAliveTime; mqttClient->connect_info.clean_session = cleanSession; mqttClient->mqtt_state.in_buffer = (uint8_t *)os_zalloc(MQTT_BUF_SIZE); mqttClient->mqtt_state.in_buffer_length = MQTT_BUF_SIZE; mqttClient->mqtt_state.out_buffer = (uint8_t *)os_zalloc(MQTT_BUF_SIZE); mqttClient->mqtt_state.out_buffer_length = MQTT_BUF_SIZE; mqttClient->mqtt_state.connect_info = &mqttClient->connect_info; mqtt_msg_init(&mqttClient->mqtt_state.mqtt_connection, mqttClient->mqtt_state.out_buffer, mqttClient->mqtt_state.out_buffer_length); QUEUE_Init(&mqttClient->msgQueue, QUEUE_BUFFER_SIZE); system_os_task(MQTT_Task, MQTT_TASK_PRIO, mqtt_procTaskQueue, MQTT_TASK_QUEUE_SIZE); system_os_post(MQTT_TASK_PRIO, 0, (os_param_t)mqttClient); return true; }
void mqtt_socket_timer(void *arg) { NODE_DBG("enter mqtt_socket_timer.\n"); lmqtt_userdata *mud = (lmqtt_userdata*) arg; if(mud == NULL) return; if(mud->pesp_conn == NULL){ NODE_DBG("mud->pesp_conn is NULL.\n"); os_timer_disarm(&mud->mqttTimer); return; } NODE_DBG("timer, queue size: %d\n", msg_size(&(mud->mqtt_state.pending_msg_q))); if(mud->event_timeout > 0){ NODE_DBG("event_timeout: %d.\n", mud->event_timeout); mud->event_timeout --; if(mud->event_timeout > 0){ return; } else { NODE_DBG("event timeout. \n"); if(mud->connState == MQTT_DATA) msg_destroy(msg_dequeue(&(mud->mqtt_state.pending_msg_q))); // should remove the head of the queue and re-send with DUP = 1 // Not implemented yet. } } if(mud->connState == MQTT_INIT){ // socket connect time out. NODE_DBG("Can not connect to broker.\n"); // Never goes here. } else if(mud->connState == MQTT_CONNECT_SENDING){ // MQTT_CONNECT send time out. NODE_DBG("sSend MQTT_CONNECT failed.\n"); mud->connState = MQTT_INIT; if(mud->secure) espconn_secure_disconnect(mud->pesp_conn); else espconn_disconnect(mud->pesp_conn); mud->keep_alive_tick = 0; // not need count anymore } else if(mud->connState == MQTT_CONNECT_SENT){ // wait for CONACK time out. NODE_DBG("MQTT_CONNECT failed.\n"); } else if(mud->connState == MQTT_DATA){ msg_queue_t *pending_msg = msg_peek(&(mud->mqtt_state.pending_msg_q)); if(pending_msg){ mud->event_timeout = MQTT_SEND_TIMEOUT; if(mud->secure) espconn_secure_sent(mud->pesp_conn, pending_msg->msg.data, pending_msg->msg.length); else espconn_sent(mud->pesp_conn, pending_msg->msg.data, pending_msg->msg.length); mud->keep_alive_tick = 0; NODE_DBG("id: %d - qos: %d, length: %d\n", pending_msg->msg_id, pending_msg->publish_qos, pending_msg->msg.length); } else { // no queued event. mud->keep_alive_tick ++; if(mud->keep_alive_tick > mud->mqtt_state.connect_info->keepalive){ mud->event_timeout = MQTT_SEND_TIMEOUT; uint8_t temp_buffer[MQTT_BUF_SIZE]; mqtt_msg_init(&mud->mqtt_state.mqtt_connection, temp_buffer, MQTT_BUF_SIZE); NODE_DBG("\r\nMQTT: Send keepalive packet\r\n"); mqtt_message_t* temp_msg = mqtt_msg_pingreq(&mud->mqtt_state.mqtt_connection); msg_queue_t *node = msg_enqueue( &(mud->mqtt_state.pending_msg_q), temp_msg, 0, MQTT_MSG_TYPE_PINGREQ, (int)mqtt_get_qos(temp_msg->data) ); // only one message in queue, send immediately. if(mud->secure) espconn_secure_sent(mud->pesp_conn, temp_msg->data, temp_msg->length); else espconn_sent(mud->pesp_conn, temp_msg->data, temp_msg->length); mud->keep_alive_tick = 0; } } } NODE_DBG("leave mqtt_socket_timer.\n"); }
static void mqtt_socket_received(void *arg, char *pdata, unsigned short len) { NODE_DBG("enter mqtt_socket_received.\n"); uint8_t msg_type; uint8_t msg_qos; uint16_t msg_id; msg_queue_t *node = NULL; int length = (int)len; // uint8_t in_buffer[MQTT_BUF_SIZE]; uint8_t *in_buffer = (uint8_t *)pdata; struct espconn *pesp_conn = arg; if(pesp_conn == NULL) return; lmqtt_userdata *mud = (lmqtt_userdata *)pesp_conn->reverse; if(mud == NULL) return; READPACKET: if(length > MQTT_BUF_SIZE || length <= 0) return; // c_memcpy(in_buffer, pdata, length); uint8_t temp_buffer[MQTT_BUF_SIZE]; mqtt_msg_init(&mud->mqtt_state.mqtt_connection, temp_buffer, MQTT_BUF_SIZE); mqtt_message_t *temp_msg = NULL; switch(mud->connState){ case MQTT_CONNECT_SENDING: case MQTT_CONNECT_SENT: if(mqtt_get_type(in_buffer) != MQTT_MSG_TYPE_CONNACK){ NODE_DBG("MQTT: Invalid packet\r\n"); mud->connState = MQTT_INIT; if(mud->secure) espconn_secure_disconnect(pesp_conn); else espconn_disconnect(pesp_conn); } else { mud->connState = MQTT_DATA; NODE_DBG("MQTT: Connected\r\n"); if(mud->cb_connect_ref == LUA_NOREF) break; if(mud->self_ref == LUA_NOREF) break; if(mud->L == NULL) break; lua_rawgeti(mud->L, LUA_REGISTRYINDEX, mud->cb_connect_ref); lua_rawgeti(mud->L, LUA_REGISTRYINDEX, mud->self_ref); // pass the userdata(client) to callback func in lua lua_call(mud->L, 1, 0); break; } break; case MQTT_DATA: mud->mqtt_state.message_length_read = length; mud->mqtt_state.message_length = mqtt_get_total_length(in_buffer, mud->mqtt_state.message_length_read); msg_type = mqtt_get_type(in_buffer); msg_qos = mqtt_get_qos(in_buffer); msg_id = mqtt_get_id(in_buffer, mud->mqtt_state.message_length); msg_queue_t *pending_msg = msg_peek(&(mud->mqtt_state.pending_msg_q)); NODE_DBG("MQTT_DATA: type: %d, qos: %d, msg_id: %d, pending_id: %d\r\n", msg_type, msg_qos, msg_id, (pending_msg)?pending_msg->msg_id:0); switch(msg_type) { case MQTT_MSG_TYPE_SUBACK: if(pending_msg && pending_msg->msg_type == MQTT_MSG_TYPE_SUBSCRIBE && pending_msg->msg_id == msg_id){ NODE_DBG("MQTT: Subscribe successful\r\n"); msg_destroy(msg_dequeue(&(mud->mqtt_state.pending_msg_q))); if (mud->cb_suback_ref == LUA_NOREF) break; if (mud->self_ref == LUA_NOREF) break; if(mud->L == NULL) break; lua_rawgeti(mud->L, LUA_REGISTRYINDEX, mud->cb_suback_ref); lua_rawgeti(mud->L, LUA_REGISTRYINDEX, mud->self_ref); lua_call(mud->L, 1, 0); } break; case MQTT_MSG_TYPE_UNSUBACK: if(pending_msg && pending_msg->msg_type == MQTT_MSG_TYPE_UNSUBSCRIBE && pending_msg->msg_id == msg_id){ NODE_DBG("MQTT: UnSubscribe successful\r\n"); msg_destroy(msg_dequeue(&(mud->mqtt_state.pending_msg_q))); } break; case MQTT_MSG_TYPE_PUBLISH: if(msg_qos == 1){ temp_msg = mqtt_msg_puback(&mud->mqtt_state.mqtt_connection, msg_id); node = msg_enqueue(&(mud->mqtt_state.pending_msg_q), temp_msg, msg_id, MQTT_MSG_TYPE_PUBACK, (int)mqtt_get_qos(temp_msg->data) ); } else if(msg_qos == 2){ temp_msg = mqtt_msg_pubrec(&mud->mqtt_state.mqtt_connection, msg_id); node = msg_enqueue(&(mud->mqtt_state.pending_msg_q), temp_msg, msg_id, MQTT_MSG_TYPE_PUBREC, (int)mqtt_get_qos(temp_msg->data) ); } if(msg_qos == 1 || msg_qos == 2){ NODE_DBG("MQTT: Queue response QoS: %d\r\n", msg_qos); } deliver_publish(mud, in_buffer, mud->mqtt_state.message_length); break; case MQTT_MSG_TYPE_PUBACK: if(pending_msg && pending_msg->msg_type == MQTT_MSG_TYPE_PUBLISH && pending_msg->msg_id == msg_id){ NODE_DBG("MQTT: Publish with QoS = 1 successful\r\n"); msg_destroy(msg_dequeue(&(mud->mqtt_state.pending_msg_q))); if(mud->cb_puback_ref == LUA_NOREF) break; if(mud->self_ref == LUA_NOREF) break; if(mud->L == NULL) break; lua_rawgeti(mud->L, LUA_REGISTRYINDEX, mud->cb_puback_ref); lua_rawgeti(mud->L, LUA_REGISTRYINDEX, mud->self_ref); // pass the userdata to callback func in lua lua_call(mud->L, 1, 0); } break; case MQTT_MSG_TYPE_PUBREC: if(pending_msg && pending_msg->msg_type == MQTT_MSG_TYPE_PUBLISH && pending_msg->msg_id == msg_id){ NODE_DBG("MQTT: Publish with QoS = 2 Received PUBREC\r\n"); // Note: actrually, should not destroy the msg until PUBCOMP is received. msg_destroy(msg_dequeue(&(mud->mqtt_state.pending_msg_q))); temp_msg = mqtt_msg_pubrel(&mud->mqtt_state.mqtt_connection, msg_id); node = msg_enqueue(&(mud->mqtt_state.pending_msg_q), temp_msg, msg_id, MQTT_MSG_TYPE_PUBREL, (int)mqtt_get_qos(temp_msg->data) ); NODE_DBG("MQTT: Response PUBREL\r\n"); } break; case MQTT_MSG_TYPE_PUBREL: if(pending_msg && pending_msg->msg_type == MQTT_MSG_TYPE_PUBREC && pending_msg->msg_id == msg_id){ msg_destroy(msg_dequeue(&(mud->mqtt_state.pending_msg_q))); temp_msg = mqtt_msg_pubcomp(&mud->mqtt_state.mqtt_connection, msg_id); node = msg_enqueue(&(mud->mqtt_state.pending_msg_q), temp_msg, msg_id, MQTT_MSG_TYPE_PUBCOMP, (int)mqtt_get_qos(temp_msg->data) ); NODE_DBG("MQTT: Response PUBCOMP\r\n"); } break; case MQTT_MSG_TYPE_PUBCOMP: if(pending_msg && pending_msg->msg_type == MQTT_MSG_TYPE_PUBREL && pending_msg->msg_id == msg_id){ NODE_DBG("MQTT: Publish with QoS = 2 successful\r\n"); msg_destroy(msg_dequeue(&(mud->mqtt_state.pending_msg_q))); if(mud->cb_puback_ref == LUA_NOREF) break; if(mud->self_ref == LUA_NOREF) break; if(mud->L == NULL) break; lua_rawgeti(mud->L, LUA_REGISTRYINDEX, mud->cb_puback_ref); lua_rawgeti(mud->L, LUA_REGISTRYINDEX, mud->self_ref); // pass the userdata to callback func in lua lua_call(mud->L, 1, 0); } break; case MQTT_MSG_TYPE_PINGREQ: temp_msg = mqtt_msg_pingresp(&mud->mqtt_state.mqtt_connection); node = msg_enqueue(&(mud->mqtt_state.pending_msg_q), temp_msg, msg_id, MQTT_MSG_TYPE_PINGRESP, (int)mqtt_get_qos(temp_msg->data) ); NODE_DBG("MQTT: Response PINGRESP\r\n"); break; case MQTT_MSG_TYPE_PINGRESP: // Ignore NODE_DBG("MQTT: PINGRESP received\r\n"); break; } // NOTE: this is done down here and not in the switch case above // because the PSOCK_READBUF_LEN() won't work inside a switch // statement due to the way protothreads resume. if(msg_type == MQTT_MSG_TYPE_PUBLISH) { length = mud->mqtt_state.message_length_read; if(mud->mqtt_state.message_length < mud->mqtt_state.message_length_read) { length -= mud->mqtt_state.message_length; in_buffer += mud->mqtt_state.message_length; NODE_DBG("Get another published message\r\n"); goto READPACKET; } } break; } if(node && (1==msg_size(&(mud->mqtt_state.pending_msg_q))) && mud->event_timeout == 0){ mud->event_timeout = MQTT_SEND_TIMEOUT; NODE_DBG("Sent: %d\n", node->msg.length); if( mud->secure ) espconn_secure_sent( pesp_conn, node->msg.data, node->msg.length ); else espconn_sent( pesp_conn, node->msg.data, node->msg.length ); } mud->keep_alive_tick = 0; NODE_DBG("receive, queue size: %d\n", msg_size(&(mud->mqtt_state.pending_msg_q))); NODE_DBG("leave mqtt_socket_received.\n"); return; }
// Lua: bool = mqtt:publish( topic, payload, qos, retain, function() ) static int mqtt_socket_publish( lua_State* L ) { NODE_DBG("enter mqtt_socket_publish.\n"); struct espconn *pesp_conn = NULL; lmqtt_userdata *mud; size_t l; uint8_t stack = 1; uint16_t msg_id = 0; mud = (lmqtt_userdata *)luaL_checkudata(L, stack, "mqtt.socket"); luaL_argcheck(L, mud, stack, "mqtt.socket expected"); stack++; if(mud==NULL){ NODE_DBG("userdata is nil.\n"); lua_pushboolean(L, 0); return 1; } if(mud->pesp_conn == NULL){ NODE_DBG("mud->pesp_conn is NULL.\n"); lua_pushboolean(L, 0); return 1; } if(!mud->connected){ luaL_error( L, "not connected" ); lua_pushboolean(L, 0); return 1; } const char *topic = luaL_checklstring( L, stack, &l ); stack ++; if (topic == NULL){ luaL_error( L, "need topic" ); lua_pushboolean(L, 0); return 1; } const char *payload = luaL_checklstring( L, stack, &l ); stack ++; uint8_t qos = luaL_checkinteger( L, stack); stack ++; uint8_t retain = luaL_checkinteger( L, stack); stack ++; uint8_t temp_buffer[MQTT_BUF_SIZE]; mqtt_msg_init(&mud->mqtt_state.mqtt_connection, temp_buffer, MQTT_BUF_SIZE); mqtt_message_t *temp_msg = mqtt_msg_publish(&mud->mqtt_state.mqtt_connection, topic, payload, l, qos, retain, &msg_id); if (lua_type(L, stack) == LUA_TFUNCTION || lua_type(L, stack) == LUA_TLIGHTFUNCTION){ lua_pushvalue(L, stack); // copy argument (func) to the top of stack if(mud->cb_puback_ref != LUA_NOREF) luaL_unref(L, LUA_REGISTRYINDEX, mud->cb_puback_ref); mud->cb_puback_ref = luaL_ref(L, LUA_REGISTRYINDEX); } msg_queue_t *node = msg_enqueue(&(mud->mqtt_state.pending_msg_q), temp_msg, msg_id, MQTT_MSG_TYPE_PUBLISH, (int)qos ); if(node && (1==msg_size(&(mud->mqtt_state.pending_msg_q))) && mud->event_timeout == 0){ mud->event_timeout = MQTT_SEND_TIMEOUT; NODE_DBG("Sent: %d\n", node->msg.length); if( mud->secure ) espconn_secure_sent( mud->pesp_conn, node->msg.data, node->msg.length ); else espconn_sent( mud->pesp_conn, node->msg.data, node->msg.length ); mud->keep_alive_tick = 0; } if(!node){ lua_pushboolean(L, 0); } else { lua_pushboolean(L, 1); // enqueued succeed. } NODE_DBG("publish, queue size: %d\n", msg_size(&(mud->mqtt_state.pending_msg_q))); NODE_DBG("leave mqtt_socket_publish.\n"); return 1; }
// Lua: bool = mqtt:subscribe(topic, qos, function()) static int mqtt_socket_subscribe( lua_State* L ) { NODE_DBG("enter mqtt_socket_subscribe.\n"); uint8_t stack = 1, qos = 0; uint16_t msg_id = 0; const char *topic; size_t il; lmqtt_userdata *mud; mud = (lmqtt_userdata *) luaL_checkudata( L, stack, "mqtt.socket" ); luaL_argcheck( L, mud, stack, "mqtt.socket expected" ); stack++; if(mud==NULL){ NODE_DBG("userdata is nil.\n"); lua_pushboolean(L, 0); return 1; } if(mud->pesp_conn == NULL){ NODE_DBG("mud->pesp_conn is NULL.\n"); lua_pushboolean(L, 0); return 1; } if(!mud->connected){ luaL_error( L, "not connected" ); lua_pushboolean(L, 0); return 1; } uint8_t temp_buffer[MQTT_BUF_SIZE]; mqtt_msg_init(&mud->mqtt_state.mqtt_connection, temp_buffer, MQTT_BUF_SIZE); mqtt_message_t *temp_msg = NULL; if( lua_istable( L, stack ) ) { NODE_DBG("subscribe table\n"); lua_pushnil( L ); /* first key */ uint8_t temp_buf[MQTT_BUF_SIZE]; uint32_t temp_pos = 0; while( lua_next( L, stack ) != 0 ) { topic = luaL_checkstring( L, -2 ); qos = luaL_checkinteger( L, -1 ); temp_msg = mqtt_msg_subscribe( &mud->mqtt_state.mqtt_connection, topic, qos, &msg_id ); NODE_DBG("topic: %s - qos: %d, length: %d\n", topic, qos, temp_msg->length); if (temp_pos + temp_msg->length > MQTT_BUF_SIZE){ lua_pop(L, 1); break; // too long message for the outbuffer. } c_memcpy( temp_buf + temp_pos, temp_msg->data, temp_msg->length ); temp_pos += temp_msg->length; lua_pop( L, 1 ); } if (temp_pos == 0){ luaL_error( L, "invalid data" ); lua_pushboolean(L, 0); return 1; } c_memcpy( temp_buffer, temp_buf, temp_pos ); temp_msg->data = temp_buffer; temp_msg->length = temp_pos; stack++; } else { NODE_DBG("subscribe string\n"); topic = luaL_checklstring( L, stack, &il ); stack++; if( topic == NULL ){ luaL_error( L, "need topic name" ); lua_pushboolean(L, 0); return 1; } qos = luaL_checkinteger( L, stack ); temp_msg = mqtt_msg_subscribe( &mud->mqtt_state.mqtt_connection, topic, qos, &msg_id ); stack++; } if( lua_type( L, stack ) == LUA_TFUNCTION || lua_type( L, stack ) == LUA_TLIGHTFUNCTION ) { // TODO: this will overwrite the previous one. lua_pushvalue( L, stack ); // copy argument (func) to the top of stack if( mud->cb_suback_ref != LUA_NOREF ) luaL_unref( L, LUA_REGISTRYINDEX, mud->cb_suback_ref ); mud->cb_suback_ref = luaL_ref( L, LUA_REGISTRYINDEX ); } msg_queue_t *node = msg_enqueue( &(mud->mqtt_state.pending_msg_q), temp_msg, msg_id, MQTT_MSG_TYPE_SUBSCRIBE, (int)mqtt_get_qos(temp_msg->data) ); NODE_DBG("topic: %s - id: %d - qos: %d, length: %d\n", topic, node->msg_id, node->publish_qos, node->msg.length); if(node && (1==msg_size(&(mud->mqtt_state.pending_msg_q))) && mud->event_timeout == 0){ mud->event_timeout = MQTT_SEND_TIMEOUT; NODE_DBG("Sent: %d\n", node->msg.length); if( mud->secure ) espconn_secure_sent( mud->pesp_conn, node->msg.data, node->msg.length ); else espconn_sent( mud->pesp_conn, node->msg.data, node->msg.length ); mud->keep_alive_tick = 0; } if(!node){ lua_pushboolean(L, 0); } else { lua_pushboolean(L, 1); // enqueued succeed. } NODE_DBG("subscribe, queue size: %d\n", msg_size(&(mud->mqtt_state.pending_msg_q))); NODE_DBG("leave mqtt_socket_subscribe.\n"); return 1; }