diff --git a/mqtt.c b/mqtt.c index eea585f..6e6ee0c 100644 --- a/mqtt.c +++ b/mqtt.c @@ -8,6 +8,7 @@ #include "os_type.h" #include "mqtt.h" +#define DEBUG 1 /* Functions we will need to implement: * Send -- will handle all sending of all packets * Connect -- set up TCP connection and parameters @@ -87,6 +88,33 @@ LOCAL uint8_t ICACHE_FLASH_ATTR mqtt_connect(mqtt_session_t *session, uint8_t *u } +/************************************************************************************************/ +/* Function: encodeLength */ +/* Parameters: the length in bytes */ +/* Returns: encoded multi-byte number per MQTT standards. The first byte this pointer */ +/* returns is the number of bytes to follow. */ +/* The MQTT standard uses a very strange method of encoding the lengths of the various sections */ +/* of the packets. This makes it simpler to implement in code. */ +/************************************************************************************************/ + + +LOCAL uint8_t ICACHE_FLASH_ATTR *encodeLength(uint32_t trueLength) { + uint8_t *encodedByte = os_zalloc(sizeof(uint8_t) * 5); // can't be more than 5 bytes + uint8_t numBytes = 1; + do { + encodedByte[numBytes] = trueLength % 128; + trueLength /= 128; + if(trueLength > 0) { + encodedByte[numBytes] |= 128; + } + numBytes++; + } while(trueLength > 0); + encodedByte[0] = numBytes - 1; + + return encodedByte; + +} + /*************************************************************************************/ /* Function: mqtt_send */ /* Parameters: active mqtt_session_t, pointer to data, data length, and message type */ @@ -98,92 +126,92 @@ LOCAL uint8_t ICACHE_FLASH_ATTR mqtt_send(mqtt_session_t *session, uint8_t *data /** First thing to do is check the packet type. * This will inform everything else we do */ +#ifdef DEBUG os_printf("Entering mqtt_send!\n"); +#endif LOCAL mqtt_packet_t packet; LOCAL mqtt_packet_t *pPacket = &packet; uint8_t *fullPacket; switch(msgType) { - case MQTT_MSG_TYPE_CONNECT: + case MQTT_MSG_TYPE_CONNECT: ; // prepare packet for connect type - pPacket->fixedHeader = (uint8_t *)os_zalloc(sizeof(uint8_t) * 2); // fixed header cannot be longer than 5 - pPacket->fixedHeader[0] = ((uint8_t)msgType << 4) & 0xF0; // make sure lower 4 are clear - // prepare variable header - pPacket->varHeader = os_zalloc(sizeof(uint8_t) * 10); // 10 bytes for connect - pPacket->varHeader[0] = 0; - pPacket->varHeader[1] = 4; // length of protocol name - pPacket->varHeader[2] = 0x4D; // M - pPacket->varHeader[3] = 0x51; // Q - pPacket->varHeader[4] = 0x54; // T - pPacket->varHeader[5] = 0x54; // T - pPacket->varHeader[6] = 4; // protocol level - pPacket->varHeader[7] = 0b11000010; // connect flags, no QOS or will, clean session, user/pass - pPacket->varHeader[8] = 0; - pPacket->varHeader[9] = 10; // keepalive time - pPacket->varHeader_len = 10; - // prepare payload - pPacket->payload = (uint8_t *)os_zalloc(sizeof(uint8_t) * 26); - // client identifier "FRZN0" - pPacket->payload[0] = 0; - pPacket->payload[1] = 5; - pPacket->payload[2] = 0x46; // F - pPacket->payload[3] = 0x52; // R - pPacket->payload[4] = 0x5A; // Z - pPacket->payload[5] = 0x4E; // N - pPacket->payload[6] = 0x30; // 0 - // Username - pPacket->payload[7] = 0; - pPacket->payload[8] = 11; - // os_memcpy(pPacket->payload + 9, data, username_len); - pPacket->payload[9] = 0x4D; // M - pPacket->payload[10] = 0x72; // r - pPacket->payload[11] = 0x41; // A - pPacket->payload[12] = 0x75; // u - pPacket->payload[13] = 0x72; // r - pPacket->payload[14] = 0x65; // e - pPacket->payload[15] = 0x6C; // l - pPacket->payload[16] = 0x69; // i - pPacket->payload[17] = 0x75; // u - pPacket->payload[18] = 0x73; // s - pPacket->payload[19] = 0x52; // R - // Password - pPacket->payload[20] = 0; - pPacket->payload[21] = 4; - // os_memcpy(pPacket->payload + 22, data + offset, password_len); - pPacket->payload[22] = 0x74; // t - pPacket->payload[23] = 0x65; // e - pPacket->payload[24] = 0x73; // s - pPacket->payload[25] = 0x74; // t - pPacket->payload_len = 26; - pPacket->fixedHeader[1] = 36; // length of varHeader + payload_len - pPacket->length = 38; - fullPacket = os_zalloc(sizeof(uint8_t) * pPacket->length); //full packet length is 38 - os_memcpy(fullPacket, pPacket->fixedHeader, 2); - os_memcpy(fullPacket + 2, pPacket->varHeader, 10); - os_memcpy(fullPacket + 12, pPacket->payload, 26); - break; - case MQTT_MSG_TYPE_PUBLISH: + const uint8_t varDefaults[10] = { 0x00, 0x04, 0x4D, 0x51, 0x54, 0x54, 0x04, 0xC2, 0x00, 0x32 }; + pPacket->fixedHeader = (uint8_t *)os_zalloc(sizeof(uint8_t) * 5); // fixed header cannot be longer than 5 + pPacket->fixedHeader[0] = ((uint8_t)msgType << 4) & 0xF0; // make sure lower 4 are clear + // prepare variable header + pPacket->varHeader = os_zalloc(sizeof(uint8_t) * 10); // 10 bytes for connect + os_memcpy(pPacket->varHeader, varDefaults, 10); // copy defaults + pPacket->varHeader_len = 10; + // prepare payload + uint32_t offset = 0; + uint32_t maxPayloadLength = session->client_id_len + session->username_len + session->password_len + 12; // length can only take a maximum of 12 bytes + pPacket->payload = (uint8_t *)os_zalloc(sizeof(uint8_t) * maxPayloadLength); + // copy client id to payload + // insert a 0 + os_memset(pPacket->payload + offset, 0, 1); + offset += 1; + os_memcpy(pPacket->payload + offset, &session->client_id_len, 1); + offset += 1; + os_memcpy(pPacket->payload + offset, session->client_id, session->client_id_len); + offset += session->client_id_len; + // copy username to payload + // insert a 0 + os_memset(pPacket->payload + offset, 0, 1); + offset += 1; + os_memcpy(pPacket->payload + offset, &session->username_len, 1); + offset += 1; + os_memcpy(pPacket->payload + offset, session->username, session->username_len); + offset += session->username_len; + // Password + // insert a 0 + os_memset(pPacket->payload + offset, 0, 1); + offset += 1; + os_memcpy(pPacket->payload + offset, &session->password_len, 1); + offset += 1; + os_memcpy(pPacket->payload + offset, session->password, session->password_len); + offset += session->password_len; + pPacket->payload_len = offset; + os_printf("Total offset: %d", offset); + uint8_t *remaining_len_encoded = encodeLength((uint32_t)(pPacket->varHeader_len + pPacket->payload_len)); + os_memcpy(pPacket->fixedHeader + 1, remaining_len_encoded + 1, remaining_len_encoded[0]); // remaining length = length of varHeader + length of payload + pPacket->fixedHeader_len = remaining_len_encoded[0] + 1; + // the full length is the length of the varHeader, payload, and fixedHeader + pPacket->length = (pPacket->varHeader_len + pPacket->payload_len + pPacket->fixedHeader_len); + os_printf("Packet length: %d\n", pPacket->length); + // construct packet data + fullPacket = os_zalloc(sizeof(uint8_t) * pPacket->length); + os_memcpy(fullPacket, pPacket->fixedHeader, pPacket->fixedHeader_len); + os_memcpy(fullPacket + pPacket->fixedHeader_len, pPacket->varHeader, pPacket->varHeader_len); + os_memcpy(fullPacket + pPacket->fixedHeader_len + pPacket->varHeader_len, pPacket->payload, pPacket->payload_len); + break; + case MQTT_MSG_TYPE_PUBLISH: // prepare for publish - break; - case MQTT_MSG_TYPE_SUBSCRIBE: - // prepare for subscribe - break; - case MQTT_MSG_TYPE_UNSUBSCRIBE: - // prepare for unsubscribe - break; - case MQTT_MSG_TYPE_PINGREQ: - // prepare for ping - break; - case MQTT_MSG_TYPE_DISCONNECT: - // disconnect from broker - break; - default: - // something has gone wrong - os_printf("Attempt to send incorrect packet type: %d", (uint8_t)msgType); - return -1; + break; + case MQTT_MSG_TYPE_SUBSCRIBE: + // prepare for subscribe + break; + case MQTT_MSG_TYPE_UNSUBSCRIBE: + // prepare for unsubscribe + break; + case MQTT_MSG_TYPE_PINGREQ: + // prepare for ping + break; + case MQTT_MSG_TYPE_DISCONNECT: + // disconnect from broker + break; + default: + // something has gone wrong + os_printf("Attempt to send incorrect packet type: %d", (uint8_t)msgType); + return -1; } +#ifdef DEBUG os_printf("About to send MQTT connect...\n"); +#endif espconn_send(session->activeConnection, fullPacket, pPacket->length); os_free(fullPacket); + os_free(pPacket->fixedHeader); + os_free(pPacket->varHeader); + os_free(pPacket->payload); } LOCAL void ICACHE_FLASH_ATTR test(void *arg) { @@ -209,17 +237,31 @@ void ICACHE_FLASH_ATTR user_init() { // prepare the TCP/MQTT connection stuff // test server is at 51.15.65.206 - char testUser[] = "MrAureliusR"; - char testPass[] = "test"; - char testTopic[] = "input"; - pGlobalSession->port = 1883; // port 80 just for testing + char testUser[11] = { 0x4d, 0x72, 0x41, 0x75, 0x72, 0x65, 0x6c, 0x69, 0x75, 0x73, 0x52 }; + char *pTestUser = testUser; + char testPass[4] = { 0x74, 0x65, 0x73, 0x74 }; + char *pTestPass = testPass; + char testTopic[5] = "input"; + char clientID[5] = {0x46, 0x52, 0x5a, 0x4e, 0x30 }; + char *pClientID = clientID; + pGlobalSession->port = 1883; // mqtt port const char esp_tcp_server_ip[4] = {51, 15, 65, 206}; // remote IP of TCP server os_memcpy(pGlobalSession->ip, esp_tcp_server_ip, 4); - pGlobalSession->username = &testUser[0]; - pGlobalSession->password = &testPass[0]; - pGlobalSession->topic_name = &testTopic[0]; + pGlobalSession->username_len = 11; + pGlobalSession->username = os_zalloc(sizeof(uint8_t) * pGlobalSession->username_len); + os_memcpy(pGlobalSession->username, testUser, pGlobalSession->username_len); + pGlobalSession->password_len = 4; + pGlobalSession->password = os_zalloc(sizeof(uint8_t) * pGlobalSession->password_len); + os_memcpy(pGlobalSession->password, testPass, pGlobalSession->password_len); + pGlobalSession->topic_name_len = 5; + pGlobalSession->topic_name = os_zalloc(sizeof(uint8_t) * pGlobalSession->topic_name_len); + os_memcpy(pGlobalSession->topic_name, testTopic, pGlobalSession->topic_name_len); + pGlobalSession->client_id_len = 5; + pGlobalSession->client_id = os_zalloc(sizeof(uint8_t) * pGlobalSession->client_id_len); + os_memcpy(pGlobalSession->client_id, clientID, pGlobalSession->client_id_len); + os_timer_setfn(&oneTimer, (os_timer_func_t *)tcpConnect, pGlobalSession); os_timer_arm(&oneTimer, 15000, 0); os_timer_setfn(&testTimer, (os_timer_func_t *)test, pGlobalSession); - os_timer_arm(&testTimer, 16000, 0); + os_timer_arm(&testTimer, 17000, 0); } diff --git a/mqtt.h b/mqtt.h index 8582d08..9899aa0 100644 --- a/mqtt.h +++ b/mqtt.h @@ -39,10 +39,14 @@ typedef struct { uint32_t port; uint32_t localPort; uint8_t *client_id; + uint32_t client_id_len; uint8_t *topic_name; + uint32_t topic_name_len; uint8_t qos_level; uint8_t *username; + uint32_t username_len; uint8_t *password; + uint32_t password_len; char valid_connection; struct espconn *activeConnection; } mqtt_session_t; @@ -54,4 +58,4 @@ LOCAL void ICACHE_FLASH_ATTR connected_callback(void *arg); LOCAL void ICACHE_FLASH_ATTR data_recv_callback(void *arg, char *pdata, unsigned short len); LOCAL void ICACHE_FLASH_ATTR data_sent_callback(void *arg); LOCAL uint8_t ICACHE_FLASH_ATTR mqtt_send(mqtt_session_t *session, uint8_t *data, uint32_t len, mqtt_message_type msgType); -LOCAL uint8_t ICACHE_FLASH_ATTR mqtt_connect(mqtt_session_t *session); +LOCAL uint8_t ICACHE_FLASH_ATTR mqtt_connect(mqtt_session_t *session, uint8_t *username, uint8_t *password);