From b0e45683d7f72f6e588d45bc232e42e3a907818a Mon Sep 17 00:00:00 2001 From: nielsonm236 Date: Wed, 9 Nov 2022 12:19:28 -0700 Subject: [PATCH 1/2] QOS 1 support Numerous changes for limited QOS 1 support primarily to allow the Home Assistant Toggle function to work properly. --- NetworkModule/.Idea_Groups/Vector_File.grp | 2 +- NetworkModule/.Idea_Temp/COBJ.TMP | 494 +++---- NetworkModule/.Idea_Temp/IDEA.ERR | 7 +- NetworkModule/.Idea_Temp/IDEABLD.BAT | 2 +- NetworkModule/DS18B20.c | 60 - NetworkModule/Enc28j60.c | 23 +- NetworkModule/Main.c | 1211 ++++++++--------- NetworkModule/UART.c | 10 +- NetworkModule/httpd.c | 1 + NetworkModule/main.h | 3 +- NetworkModule/mqtt.c | 637 ++++++++- NetworkModule/mqtt.h | 71 +- NetworkModule/mqtt_pal.c | 103 +- NetworkModule/timer.c | 4 +- NetworkModule/uip.c | 20 +- NetworkModule/uipopt.h | 25 +- ...odule Manual - Code Rev 20221009 2141.docx | Bin 0 -> 162 bytes 17 files changed, 1587 insertions(+), 1086 deletions(-) create mode 100644 ~$twork Module Manual - Code Rev 20221009 2141.docx diff --git a/NetworkModule/.Idea_Groups/Vector_File.grp b/NetworkModule/.Idea_Groups/Vector_File.grp index 9651d79..1d4efab 100644 --- a/NetworkModule/.Idea_Groups/Vector_File.grp +++ b/NetworkModule/.Idea_Groups/Vector_File.grp @@ -1,5 +1,5 @@ # Group File Created by IDEA # Project: -# Sat Oct 15 06:37:27 2022 +# Wed Nov 09 11:24:42 2022 # "networkmodule_vector.o" diff --git a/NetworkModule/.Idea_Temp/COBJ.TMP b/NetworkModule/.Idea_Temp/COBJ.TMP index 96a0b5d..10a415a 100644 --- a/NetworkModule/.Idea_Temp/COBJ.TMP +++ b/NetworkModule/.Idea_Temp/COBJ.TMP @@ -4,17 +4,17 @@ header: executable format processor number 6, type 3 15 sections -616 symbols -6116 debug symbols +620 symbols +6227 debug symbols sections: .vector: hilo code, at address 0x8000 128 data bytes (0x0080) .const: hilo code, at address 0x8080 - 2700 data bytes (0x0a8c) -.text: hilo code, at address 0x8b0c - 23836 data bytes (0x5d1c) + 2711 data bytes (0x0a97) +.text: hilo code, at address 0x8b17 + 24349 data bytes (0x5f1d) .eeprom: hilo, at address 0x4000 108 data bytes (0x006c) .bsct: no attribute, at address 0x0 @@ -23,201 +23,203 @@ sections: 10 reserved bytes (0x000a) .bit: no attribute, at address 0xa 0 data bytes (0x0000) -.data: hilo (init), at address 0xe835 +.data: hilo (init), at address 0xea41 8 data bytes (0x0008) -memcpy_update: hilo code (init), at address 0xe83d +memcpy_update: hilo code (init), at address 0xea49 40 data bytes (0x0028) .bss: bss hilo, at address 0x3a - 1440 reserved bytes (0x05a0) + 1461 reserved bytes (0x05b5) .flash_update: hilo code, at address 0xfc80 451 data bytes (0x01c3) .iconst: bss hilo, at address 0x5fe 2 reserved bytes (0x0002) .debug: hilo, at address 0x0 - 100375 data bytes (0x18817) + 101564 data bytes (0x18cbc) .info.: no attribute, at address 0x0 3779 data bytes (0x0ec3) -.init: hilo code, at address 0xe828 +.init: hilo code, at address 0xea34 13 data bytes (0x000d) symbols: -__memory: 000005da section .bss defined public -___mqtt_recv: 0000c4c3 section .text defined public -c_itoly: 0000e53d section .text defined public -_mqtt_sync: 0000bfcb section .text defined public -_mqtt_unpack_response: 0000cded section .text defined public -_mqtt_unpack_connack_response: 0000c906 section .text defined public -_mqtt_unpack_publish_response: 0000ca40 section .text defined public -_mqtt_unpack_suback_response: 0000cac9 section .text defined public -_memmove: 0000e402 section .text defined public -_uip_ipchksum: 0000d4b4 section .text defined public -_uip_tcpchksum: 0000d51a section .text defined public +__memory: 000005ef section .bss defined public +___mqtt_recv: 0000c5e0 section .text defined public +c_itoly: 0000e749 section .text defined public +_mqtt_sync: 0000c03c section .text defined public +_mqtt_unpack_response: 0000d005 section .text defined public +_mqtt_unpack_connack_response: 0000ca45 section .text defined public +_mqtt_unpack_publish_response: 0000cbb2 section .text defined public +_mqtt_unpack_suback_response: 0000ccdf section .text defined public c_y: 00000007 section .ubsct defined public zpage -c_lgsbc: 0000e702 section .text defined public +c_lgsbc: 0000e90e section .text defined public +_memmove: 0000e60e section .text defined public +_uip_ipchksum: 0000d6d5 section .text defined public +_uip_tcpchksum: 0000d73b section .text defined public _stored_EEPROM_revision1: 00004015 section .eeprom defined public -_check_mqtt_server_arp_entry: 0000e2f5 section .text defined public +_check_mqtt_server_arp_entry: 0000e501 section .text defined public _stack_limit1: 000005ff section .iconst defined public _stored_unused1: 00004014 section .eeprom defined public -_ON_OFF_word_new1: 000001e1 section .bss defined public +_ON_OFF_word_new1: 000001e3 section .bss defined public _stored_unused3: 0000404c section .eeprom defined public -_uip_listenports: 000002a3 section .bss defined public +_uip_listenports: 000002b8 section .bss defined public _stored_unused4: 0000404d section .eeprom defined public -c_divul: 0000e5cf section .text defined public -_write_one: 0000abb0 section .text defined public +c_divul: 0000e7db section .text defined public +_write_one: 0000abe7 section .text defined public _stored_unused5: 0000404e section .eeprom defined public -_init_IWDG: 0000bd87 section .text defined public +_init_IWDG: 0000bdf8 section .text defined public _stored_prior_config: 00004050 section .eeprom defined public _auto_discovery: 000000fd section .bss defined public -_mqtt_close_tcp: 0000018e section .bss defined public -_mqtt_start: 0000013b section .bss defined public -_restart: 0000bcf4 section .text defined public +_mqtt_close_tcp: 0000018f section .bss defined public +_mqtt_start: 0000013c section .bss defined public +_restart: 0000bd65 section .text defined public _mqtt_sanity_ctr: 00000138 section .bss defined public _check_I2C_EEPROM_ctr: 000000bf section .bss defined public _check_DS18B20_ctr: 000000cb section .bss defined public _check_DS18B20_sensor_ctr: 000000c7 section .bss defined public -___mqtt_pack_str: 0000ce98 section .text defined public -_uip_arp_arpin: 0000e0fb section .text defined public -_mqtt_mq_clean: 0000cc63 section .text defined public -_check_reset_button: 0000bed8 section .text defined public -_mqtt_subscribe: 0000c1ee section .text defined public -_send_IOT_msg: 0000b131 section .text defined public -_unlock_eeprom: 0000b6c5 section .text defined public -_lock_eeprom: 0000b6d5 section .text defined public +___mqtt_pack_str: 0000d0b0 section .text defined public +_uip_arp_arpin: 0000e307 section .text defined public +_mqtt_mq_clean: 0000ce7b section .text defined public +_check_reset_button: 0000bf49 section .text defined public +_mqtt_subscribe: 0000c2ee section .text defined public +_send_IOT_msg: 0000b170 section .text defined public +_unlock_eeprom: 0000b736 section .text defined public +_lock_eeprom: 0000b746 section .text defined public _I2C_stop: 0000fd76 section .flash_update defined public _SDA_high: 0000fd23 section .flash_update defined public _SCL_high: 0000fd11 section .flash_update defined public _I2C_byte_address: 0000fca6 section .flash_update defined public -_uip_process: 0000d62e section .text defined public +_uip_process: 0000d84f section .text defined public _eeprom_base: 000000b3 section .bss defined public _topic_base: 000000fe section .bss defined public -c_lumd: 0000e778 section .text defined public -_HttpDCall: 00009dde section .text defined public -_periodic_timer_expired: 0000d3ab section .text defined public -_t100ms_timer_expired: 0000d3cb section .text defined public -_mqtt_timer_expired: 0000d3bb section .text defined public -_arp_timer_expired: 0000d3db section .text defined public -_connack_received: 0000028c section .bss defined public -_suback_received: 0000028b section .bss defined public -_publish_pinstate_all: 0000b591 section .text defined public -_mqtt_pal_sendall: 0000cee9 section .text defined public -_uip_TcpAppHubCall: 0000e383 section .text defined public -_mac_string: 00000193 section .bss defined public -_show_temperature_string: 00009d59 section .text defined public -_update_mac_string: 0000b8f6 section .text defined public -___mqtt_ping: 0000c26d section .text defined public -__idesc__: 0000e828 section .init defined public -_uip_flags: 000002bf section .bss defined public -_connect_flags: 00000180 section .bss defined public -_htons: 0000df5c section .text defined public +c_lumd: 0000e984 section .text defined public +_HttpDCall: 00009de7 section .text defined public +_periodic_timer_expired: 0000d5cc section .text defined public +_t100ms_timer_expired: 0000d5ec section .text defined public +_mqtt_timer_expired: 0000d5dc section .text defined public +_arp_timer_expired: 0000d5fc section .text defined public +_connack_received: 000002a2 section .bss defined public +_suback_received: 000002a1 section .bss defined public +_publish_pinstate_all: 0000b602 section .text defined public +_mqtt_pal_sendall: 0000d101 section .text defined public +_uip_TcpAppHubCall: 0000e58f section .text defined public +_mac_string: 00000194 section .bss defined public +_show_temperature_string: 00009d64 section .text defined public +_update_mac_string: 0000b967 section .text defined public +___mqtt_ping: 0000c373 section .text defined public +__idesc__: 0000ea34 section .init defined public +_uip_flags: 000002d4 section .bss defined public +_connect_flags: 00000181 section .bss defined public +_htons: 0000e168 section .text defined public _Read_Slave_NACKACK: 0000fd5c section .flash_update defined public _parse_tail: 0000007d section .bss defined public -_hex2int: 000096e3 section .text defined public -_two_hex2int: 00009711 section .text defined public +_hex2int: 000096ee section .text defined public +_two_hex2int: 0000971c section .text defined public +_mqttclient: 00000159 section .bss defined public _verify_count: 00000139 section .bss defined public -_mqttclient: 00000158 section .bss defined public -_ON_OFF_word_sent: 000001dd section .bss defined public -_prep_read: 0000ab9f section .text defined public +_ON_OFF_word_sent: 000001df section .bss defined public +_prep_read: 0000abd6 section .text defined public _eeprom_num_read: 000000b5 section .bss defined public -_check_restart_reboot: 0000bbbb section .text defined public -_reboot: 0000bd3b section .text defined public -___mqtt_next_pid: 0000c001 section .text defined public +_check_restart_reboot: 0000bc2c section .text defined public +_reboot: 0000bdac section .text defined public +___mqtt_next_pid: 0000c08c section .text defined public _HtmlPageIOControl_size: 0000007a section .bss defined public _HtmlPageConfiguration_size: 00000078 section .bss defined public -_adjust_template_size: 00009573 section .text defined public +_adjust_template_size: 0000957e section .text defined public _stored_devicename: 00004000 section .eeprom defined public _stored_mqtt_username: 00004035 section .eeprom defined public -_Pending_devicename: 000001b7 section .bss defined public +_Pending_devicename: 000001b8 section .bss defined public _Pending_mqtt_username: 000000e7 section .bss defined public -_parse_local_buf: 0000a433 section .text defined public -_uip_buf: 0000037e section .bss defined public -_mqtt_sendbuf: 000001ff section .bss defined public -_strlen: 0000e47a section .text defined public -_uip_listen: 0000d5e7 section .text defined public -_uip_len: 0000037a section .bss defined public +_parse_local_buf: 0000a43c section .text defined public +_uip_buf: 00000393 section .bss defined public +_mqtt_sendbuf: 00000201 section .bss defined public +_mqtt_check_sendbuf: 0000c072 section .text defined public +_strlen: 0000e686 section .text defined public +_uip_listen: 0000d808 section .text defined public +_uip_len: 0000038f section .bss defined public _stored_unused6: 0000404f section .eeprom defined public -_uip_slen: 000002ab section .bss defined public -_uip_conn: 00000378 section .bss defined public +_uip_slen: 000002c0 section .bss defined public +_uip_conn: 0000038d section .bss defined public _mqtt_conn: 00000136 section .bss defined public _code_revision: 00008850 section .const defined public _z_diag: 0000007c section .bss defined public _off_board_eeprom_index: 000000a5 section .bss defined public -_int2hex: 0000972c section .text defined public +_int2hex: 00009737 section .text defined public _copy_ram_index: 000000b7 section .bss defined public _stored_mqtt_password: 00004040 section .eeprom defined public _Pending_mqtt_password: 000000dc section .bss defined public -_Invert_word: 000001db section .bss defined public -_ON_OFF_word: 000001e3 section .bss defined public -c_eewrd: 0000e512 section .text defined public -c_ludv: 0000e764 section .text defined public -c_lglsh: 0000e6ca section .text defined public -_uip_conns: 000002c4 section .bss defined public -_update_ON_OFF: 0000a7cf section .text defined public +_Invert_word: 000001dd section .bss defined public +_ON_OFF_word: 000001e5 section .bss defined public +c_eewrd: 0000e71e section .text defined public +c_ludv: 0000e970 section .text defined public +c_lglsh: 0000e8d6 section .text defined public +_uip_conns: 000002d9 section .bss defined public +_update_ON_OFF: 0000a7d8 section .text defined public _stored_magic1: 0000402b section .eeprom defined public _stored_magic3: 0000402d section .eeprom defined public -_write_output_pins: 0000be59 section .text defined public -_read_input_pins: 0000bd9c section .text defined public +_write_output_pins: 0000beca section .text defined public +_read_input_pins: 0000be0d section .text defined public _io_map: 000080a3 section .const defined public -_encode_16bit_registers: 0000a810 section .text defined public -_init_off_board_string_pointers: 000094f7 section .text defined public -_uip_netmask: 000002b7 section .bss defined public -_Pending_netmask: 000001cd section .bss defined public +_encode_16bit_registers: 0000a819 section .text defined public +_init_off_board_string_pointers: 00009502 section .text defined public +_uip_netmask: 000002cc section .bss defined public +_Pending_netmask: 000001ce section .bss defined public _stored_netmask: 0000401f section .eeprom defined public -_Enc28j60Send: 0000927e section .text defined public -_uip_send: 0000df5d section .text defined public -_publish_outbound: 0000b3d4 section .text defined public -___mqtt_send: 0000c333 section .text defined public -_mqtt_mq_find: 0000cdb1 section .text defined public -_Enc28j60ReadPhy: 00008fee section .text defined public -_Enc28j60WritePhy: 0000903b section .text defined public -_stpcpy: 0000ced3 section .text defined public -__fctcpy: 0000e486 section .text defined public -_select: 00008f6b section .text defined public -_deselect: 00008f71 section .text defined public -_init_tHttpD_struct: 00009dce section .text defined public -_parsepost: 0000a2c2 section .text defined public -_off_board_EEPROM_detect: 0000ab59 section .text defined public +_Enc28j60Send: 00009289 section .text defined public +_uip_send: 0000e169 section .text defined public +_publish_outbound: 0000b435 section .text defined public +___mqtt_send: 0000c439 section .text defined public +_mqtt_mq_find: 0000cfc9 section .text defined public +_Enc28j60ReadPhy: 00008ff9 section .text defined public +_Enc28j60WritePhy: 00009046 section .text defined public +_stpcpy: 0000d0eb section .text defined public +__fctcpy: 0000e692 section .text defined public +_select: 00008f76 section .text defined public +_deselect: 00008f7c section .text defined public +_init_tHttpD_struct: 00009dd9 section .text defined public +_parsepost: 0000a2cb section .text defined public +_off_board_EEPROM_detect: 0000ab90 section .text defined public _eeprom_detect: 000000be section .bss defined public -_uip_connect: 0000d54e section .text defined public -_mqtt_connect: 0000c0b3 section .text defined public -_mqtt_disconnect: 0000c2d0 section .text defined public -_mqtt_pack_disconnect: 0000c956 section .text defined public -_update_debug_storage1: 0000bfab section .text defined public +_uip_connect: 0000d76f section .text defined public +_mqtt_connect: 0000c13e section .text defined public +_mqtt_disconnect: 0000c3d6 section .text defined public +_mqtt_pack_disconnect: 0000ca95 section .text defined public +_update_debug_storage1: 0000c01c section .text defined public _RXERIF_counter: 000000d7 section .bss defined public _TXERIF_counter: 000000d6 section .bss defined public _TRANSMIT_counter: 000000d2 section .bss defined public -_second_counter: 0000028d section .bss defined public +_second_counter: 000002a3 section .bss defined public _MQTT_resp_tout_counter: 000000d1 section .bss defined public _MQTT_not_OK_counter: 000000d0 section .bss defined public _MQTT_broker_dis_counter: 000000cf section .bss defined public -_mqtt_mq_register: 0000cbfc section .text defined public -_mqtt_unpack_fixed_header: 0000c630 section .text defined public -_mqtt_pack_fixed_header: 0000c6ed section .text defined public -_Enc28j60SwitchBank: 00008fdc section .text defined public -_SpiReadChunk: 0000d28d section .text defined public -_SpiWriteChunk: 0000d224 section .text defined public +_mqtt_mq_register: 0000ce14 section .text defined public +_mqtt_unpack_fixed_header: 0000c76f section .text defined public +_mqtt_pack_fixed_header: 0000c82c section .text defined public +_Enc28j60SwitchBank: 00008fe7 section .text defined public +_SpiReadChunk: 0000d4b2 section .text defined public +_SpiWriteChunk: 0000d449 section .text defined public _mqtt_start_status: 000000f9 section .bss defined public _MQTT_error_status: 000000f8 section .bss defined public _stored_config_settings: 00004051 section .eeprom defined public -_Pending_config_settings: 000001b6 section .bss defined public -_check_eeprom_settings: 0000b729 section .text defined public -_debug: 000001f5 section .bss defined public +_Pending_config_settings: 000001b7 section .bss defined public +_check_eeprom_settings: 0000b79a section .text defined public +_debug: 000001f7 section .bss defined public _stored_debug: 00004062 section .eeprom defined public _stored_uip_ethaddr_oct: 00004017 section .eeprom defined public _eeprom_copy_to_flash_request: 000000a7 section .bss defined public -_user_reboot_request: 00000191 section .bss defined public -_Pending_uip_ethaddr_oct: 000001b0 section .bss defined public -_reboot_request: 00000192 section .bss defined public -_restart_request: 00000190 section .bss defined public -_state_request: 000001da section .bss defined public -_mqtt_pack_connection_request: 0000c79c section .text defined public -_mqtt_pack_publish_request: 0000c996 section .text defined public -_mqtt_pack_subscribe_request: 0000cb2b section .text defined public -_mqtt_pack_ping_request: 0000c976 section .text defined public +_user_reboot_request: 00000192 section .bss defined public +_Pending_uip_ethaddr_oct: 000001b1 section .bss defined public +_reboot_request: 00000193 section .bss defined public +_restart_request: 00000191 section .bss defined public +_state_request: 000001dc section .bss defined public +_mqtt_pack_connection_request: 0000c8db section .text defined public +_mqtt_pack_publish_request: 0000cad5 section .text defined public +_mqtt_pack_pubxxx_request: 0000cc6d section .text defined public +_mqtt_pack_subscribe_request: 0000cd41 section .text defined public +_mqtt_pack_ping_request: 0000cab5 section .text defined public _CLK_PCKENR1: 000050c7 section absolute defined public absolute _UART2_BRR1: 00005242 section absolute defined public absolute -_uip_appdata: 0000037c section .bss defined public -_uip_sappdata: 000002ad section .bss defined public +_uip_appdata: 00000391 section .bss defined public +_uip_sappdata: 000002c2 section .bss defined public _TIM1_ARRH: 00005262 section absolute defined public absolute _TIM1_CCR2H: 00005267 section absolute defined public absolute _TIM2_ARRH: 0000530d section absolute defined public absolute @@ -225,12 +227,12 @@ _TIM2_CCR2H: 00005311 section absolute defined public absolute _TIM3_ARRH: 0000532b section absolute defined public absolute _TIM3_CCR2H: 0000532f section absolute defined public absolute _DM_BK2RH: 00007f94 section absolute defined public absolute -c_lzmp: 0000e792 section .text defined public -_compare_flash_to_EEPROM0: 0000abca section .text defined public -_copy_flash_to_EEPROM0: 0000ac21 section .text defined public -c_smodx: 0000e7b7 section .text defined public -_FindDevices: 00008db6 section .text defined public -_check_runtime_changes: 0000b92d section .text defined public +c_lzmp: 0000e99e section .text defined public +_compare_flash_to_EEPROM0: 0000ac01 section .text defined public +_copy_flash_to_EEPROM0: 0000ac58 section .text defined public +c_smodx: 0000e9c3 section .text defined public +_FindDevices: 00008dc1 section .text defined public +_check_runtime_changes: 0000b99e section .text defined public c_x: 00000004 section .ubsct defined public zpage _PA_ODR: 00005000 section absolute defined public absolute _PB_ODR: 00005005 section absolute defined public absolute @@ -325,7 +327,7 @@ _FLASH_DUKR: 00005064 section absolute defined public absolute _SPI_RXCRCR: 00005206 section absolute defined public absolute _SPI_TXCRCR: 00005207 section absolute defined public absolute _TIM1_RCR: 00005264 section absolute defined public absolute -c_ltor: 0000e752 section .text defined public +c_ltor: 0000e95e section .text defined public _RST_SR: 000050b3 section absolute defined public absolute _CLK_CSSR: 000050c8 section absolute defined public absolute _BEEP_CSR: 000050f3 section absolute defined public absolute @@ -337,7 +339,7 @@ _TIM1_SMCR: 00005252 section absolute defined public absolute _TIM4_SR: 00005342 section absolute defined public absolute _ADC_CSR: 00005400 section absolute defined public absolute _SWIM_CSR: 00007f80 section absolute defined public absolute -c_lgor: 0000e6eb section .text defined public +c_lgor: 0000e8f7 section .text defined public _CLK_CMSR: 000050c3 section absolute defined public absolute _CLK_SWCR: 000050c5 section absolute defined public absolute _CLK_SWIMCCR: 000050cd section absolute defined public absolute @@ -349,32 +351,32 @@ _TIM2_PSCR: 0000530c section absolute defined public absolute _TIM3_PSCR: 0000532a section absolute defined public absolute _TIM4_PSCR: 00005345 section absolute defined public absolute _CFG_GCR: 00007f60 section absolute defined public absolute -_ON_OFF_word_new2: 000001df section .bss defined public +_ON_OFF_word_new2: 000001e1 section .bss defined public _CLK_SWR: 000050c4 section absolute defined public absolute _WWDG_WR: 000050d2 section absolute defined public absolute _TIM1_EGR: 00005257 section absolute defined public absolute _TIM2_EGR: 00005304 section absolute defined public absolute _TIM3_EGR: 00005324 section absolute defined public absolute _TIM4_EGR: 00005343 section absolute defined public absolute -c_lgsub: 0000e718 section .text defined public -_uip_add32: 0000d40f section .text defined public +c_lgsub: 0000e924 section .text defined public +_uip_add32: 0000d630 section .text defined public _CLK_CKDIVR: 000050c6 section absolute defined public absolute _CLK_PCKENR2: 000050ca section absolute defined public absolute _UART2_BRR2: 00005243 section absolute defined public absolute _CLK_CCOR: 000050c9 section absolute defined public absolute _stored_magic2: 0000402c section .eeprom defined public -_uip_acc32: 000002c0 section .bss defined public +_uip_acc32: 000002d5 section .bss defined public _CLK_HSITRIMR: 000050cc section absolute defined public absolute _IWDG_PR: 000050e1 section absolute defined public absolute _SPI_CRCPR: 00005205 section absolute defined public absolute -_uip_hostaddr: 000002bb section .bss defined public -_uip_draddr: 000002b3 section .bss defined public -_uip_mqttserveraddr: 000002af section .bss defined public -_Pending_hostaddr: 000001d5 section .bss defined public -_Pending_draddr: 000001d1 section .bss defined public +_uip_hostaddr: 000002d0 section .bss defined public +_uip_draddr: 000002c8 section .bss defined public +_uip_mqttserveraddr: 000002c4 section .bss defined public +_Pending_hostaddr: 000001d6 section .bss defined public +_Pending_draddr: 000001d2 section .bss defined public _Pending_mqttserveraddr: 000000f4 section .bss defined public _stored_hostaddr: 00004027 section .eeprom defined public -_IpAddr: 00000186 section .bss defined public +_IpAddr: 00000187 section .bss defined public _stored_draddr: 00004023 section .eeprom defined public _stored_mqttserveraddr: 00004031 section .eeprom defined public _uip_ethaddr: 0000000c section .data defined public @@ -393,8 +395,8 @@ _DM_BK1RL: 00007f92 section absolute defined public absolute _I2C_OARH: 00005214 section absolute defined public absolute _DM_BK1RH: 00007f91 section absolute defined public absolute _lastDiscrep: 0000000a section .data defined public -c_bmulx: 0000e4bb section .text defined public -_mqtt_startup: 0000acab section .text defined public +c_bmulx: 0000e6c7 section .text defined public +_mqtt_startup: 0000ace2 section .text defined public _I2C_SR3: 00005219 section absolute defined public absolute _UART2_CR3: 00005246 section absolute defined public absolute _ADC_CR3: 00005403 section absolute defined public absolute @@ -406,19 +408,19 @@ _I2C_CCRH: 0000521c section absolute defined public absolute _TIM1_PSCRH: 00005260 section absolute defined public absolute _ADC_AWSRH: 0000540c section absolute defined public absolute _ADC_AWCRH: 0000540e section absolute defined public absolute -c_itolx: 0000e52f section .text defined public -c_uitolx: 0000e821 section .text defined public -_memcmp: 0000e3d2 section .text defined public -_strcmp: 0000e467 section .text defined public -_restart_reboot_step: 0000018f section .bss defined public +c_itolx: 0000e73b section .text defined public +c_uitolx: 0000ea2d section .text defined public +_memcmp: 0000e5de section .text defined public +_strcmp: 0000e673 section .text defined public +_restart_reboot_step: 00000190 section .bss defined public _mqtt_restart_step: 00000135 section .bss defined public -c_lcmp: 0000e579 section .text defined public +c_lcmp: 0000e785 section .text defined public _auto_discovery_step: 000000fc section .bss defined public _I2C_TRISER: 0000521d section absolute defined public absolute _UART2_CR4: 00005247 section absolute defined public absolute -c_divsl: 0000e5b8 section .text defined public +c_divsl: 0000e7c4 section .text defined public _UART2_CR5: 00005248 section absolute defined public absolute -_second_toggle: 00000291 section .bss defined public +_second_toggle: 000002a7 section .bss defined public _UART2_CR6: 00005249 section absolute defined public absolute _TIM1_IER: 00005254 section absolute defined public absolute _TIM2_IER: 00005301 section absolute defined public absolute @@ -454,7 +456,7 @@ _ADC_DRL: 00005405 section absolute defined public absolute _ADC_TDRL: 00005407 section absolute defined public absolute _ADC_HTRL: 00005409 section absolute defined public absolute _ADC_LTRL: 0000540b section absolute defined public absolute -_uip_arp_out: 0000e1aa section .text defined public +_uip_arp_out: 0000e3b6 section .text defined public _TIM1_ARRL: 00005263 section absolute defined public absolute _TIM1_CCR2L: 00005268 section absolute defined public absolute _TIM2_ARRL: 0000530e section absolute defined public absolute @@ -462,147 +464,149 @@ _TIM2_CCR2L: 00005312 section absolute defined public absolute _TIM3_ARRL: 0000532c section absolute defined public absolute _TIM3_CCR2L: 00005330 section absolute defined public absolute _DM_BK2RL: 00007f95 section absolute defined public absolute -_I2C_reset: 0000a87f section .text defined public +_I2C_reset: 0000a888 section .text defined public _TIM1_CCR1H: 00005265 section absolute defined public absolute _TIM2_CCR1H: 0000530f section absolute defined public absolute _TIM3_CCR1H: 0000532d section absolute defined public absolute _TIM1_CCR1L: 00005266 section absolute defined public absolute _TIM2_CCR1L: 00005310 section absolute defined public absolute _TIM3_CCR1L: 0000532e section absolute defined public absolute -c_smul: 0000e7e2 section .text defined public +c_smul: 0000e9ee section .text defined public _TIM1_CCR3H: 00005269 section absolute defined public absolute _TIM2_CCR3H: 00005314 section absolute defined public absolute _TIM1_CCR3L: 0000526a section absolute defined public absolute _TIM2_CCR3L: 00005314 section absolute defined public absolute _stored_pin_control: 00004052 section .eeprom defined public -_LEDcontrol: 00009477 section .text defined public -_pin_control: 000001e5 section .bss defined public -_Pending_pin_control: 000001a0 section .bss defined public +_LEDcontrol: 00009482 section .text defined public +_pin_control: 000001e7 section .bss defined public +_Pending_pin_control: 000001a1 section .bss defined public _I2C_control: 0000fc80 section .flash_update defined public _TIM1_CCR4H: 0000526b section absolute defined public absolute -c_sdivx: 0000e7bd section .text defined public +c_sdivx: 0000e9c9 section .text defined public _TIM1_CCR4L: 0000526c section absolute defined public absolute -_client_id: 00000156 section .bss defined public +_client_id: 00000157 section .bss defined public _TIM1_DTR: 0000526e section absolute defined public absolute _TIM4_ARR: 00005346 section absolute defined public absolute _ITC_SPR1: 00007f70 section absolute defined public absolute -_t100ms_ctr1: 00000182 section .bss defined public -_mqtt_start_ctr1: 0000013a section .bss defined public +_t100ms_ctr1: 00000183 section .bss defined public +_mqtt_start_ctr1: 0000013b section .bss defined public _ITC_SPR2: 00007f71 section absolute defined public absolute _ITC_SPR4: 00007f73 section absolute defined public absolute -c_ladd: 0000e561 section .text defined public +c_ladd: 0000e76d section .text defined public _stored_port: 0000401d section .eeprom defined public _stored_mqttport: 0000402f section .eeprom defined public -_Pending_port: 000001cb section .bss defined public +_Pending_port: 000001cc section .bss defined public _Pending_mqttport: 000000f2 section .bss defined public _mqttport: 000000da section .bss defined public -c_lgadd: 0000e6b3 section .text defined public +c_lgadd: 0000e8bf section .text defined public _ITC_SPR5: 00007f74 section absolute defined public absolute +_Enc28j60Receive_throttle: 000001db section .bss defined public +_publish_outbound_throttle: 0000013a section .bss defined public _ITC_SPR6: 00007f75 section absolute defined public absolute _ITC_SPR7: 00007f76 section absolute defined public absolute -c_eewrw: 0000e4c9 section .text defined public +c_eewrw: 0000e6d5 section .text defined public _ITC_SPR8: 00007f77 section absolute defined public absolute _DM_BK1RE: 00007f90 section absolute defined public absolute _DM_BK2RE: 00007f93 section absolute defined public absolute -_Enc28j60Receive: 000091cf section .text defined public -_mqtt_keep_alive: 0000017e section .bss defined public -_emb_itoa: 00009617 section .text defined public -_wait_timer: 0000d3ec section .text defined public -_uip_arp_timer: 0000dfa4 section .text defined public -_periodic_timer: 00000298 section .bss defined public -_mqtt_timer: 00000297 section .bss defined public -_t100ms_timer: 00000293 section .bss defined public -_arp_timer: 00000295 section .bss defined public -_mqtt_outbound_timer: 00000294 section .bss defined public -c_ldiv: 0000e599 section .text defined public -___mqtt_pack_uint16: 0000ce57 section .text defined public -___mqtt_unpack_uint16: 0000ce7b section .text defined public -_one_wire_low: 00008d79 section .text defined public +_Enc28j60Receive: 000091da section .text defined public +_mqtt_keep_alive: 0000017f section .bss defined public +_emb_itoa: 00009622 section .text defined public +_wait_timer: 0000d60d section .text defined public +_uip_arp_timer: 0000e1b0 section .text defined public +_periodic_timer: 000002ad section .bss defined public +_mqtt_timer: 000002ac section .bss defined public +_t100ms_timer: 000002a9 section .bss defined public +_arp_timer: 000002aa section .bss defined public +c_ldiv: 0000e7a5 section .text defined public +___mqtt_pack_uint16: 0000d06f section .text defined public +___mqtt_unpack_uint16: 0000d093 section .text defined public +_one_wire_low: 00008d84 section .text defined public _SDA_low: 0000fd30 section .flash_update defined public _SCL_low: 0000fd1e section .flash_update defined public _numROMs: 000000c4 section .bss defined public -_restore_eeprom_debug_bytes: 0000bf9e section .text defined public -_First: 00008e40 section .text defined public +_restore_eeprom_debug_bytes: 0000c00f section .text defined public +_First: 00008e4b section .text defined public _stored_magic4: 0000402e section .eeprom defined public -_mqtt_enabled: 00000181 section .bss defined public -_reset_pulse: 00008ce3 section .text defined public +_mqtt_enabled: 00000182 section .bss defined public +_reset_pulse: 00008cee section .text defined public _SCL_pulse: 0000fd0b section .flash_update defined public c_lreg: 00000000 section .ubsct defined public zpage -_Enc28j60ReadReg: 00008f77 section .text defined public -_Enc28j60WriteReg: 00008f97 section .text defined public -_Enc28j60SetMaskReg: 00008fae section .text defined public -_Enc28j60ClearMaskReg: 00008fc5 section .text defined public +_Enc28j60ReadReg: 00008f82 section .text defined public +_Enc28j60WriteReg: 00008fa2 section .text defined public +_Enc28j60SetMaskReg: 00008fb9 section .text defined public +_Enc28j60ClearMaskReg: 00008fd0 section .text defined public _io_reg: 00005000 section absolute defined public absolute -c_lneg: 0000e73d section .text defined public -c_lgneg: 0000e6d8 section .text defined public +c_lneg: 0000e949 section .text defined public +c_lgneg: 0000e8e4 section .text defined public _doneFlag: 0000000b section .data defined public -_get_temperature: 00008b15 section .text defined public -_convert_temperature: 00008bce section .text defined public +_get_temperature: 00008b20 section .text defined public +_convert_temperature: 00008bd9 section .text defined public _send_mqtt_temperature: 000000c6 section .bss defined public -_publish_temperature: 0000b630 section .text defined public +_publish_temperature: 0000b6a1 section .text defined public _new_FoundROM_crc: 0000003b section .bss defined public _old_FoundROM_crc: 0000003a section .bss defined public _ps: 0000852f section .const defined public -c_eewrc: 0000e4df section .text defined public -_transmit_byte: 00008d0e section .text defined public +c_eewrc: 0000e6eb section .text defined public +_transmit_byte: 00008d19 section .text defined public _FoundROM: 0000003c section .bss defined public _ROM: 00000064 section .bss defined public _DS18B20_scratch_byte: 00000076 section .bss defined public -_SpiWriteByte: 0000d1fa section .text defined public -_SpiReadByte: 0000d263 section .text defined public +_SpiWriteByte: 0000d41f section .text defined public +_SpiReadByte: 0000d488 section .text defined public _I2C_read_byte: 0000fcc6 section .flash_update defined public -_int2nibble: 0000974b section .text defined public -_parse_complete: 0000018d section .bss defined public +_int2nibble: 00009756 section .text defined public +_parse_complete: 0000018e section .bss defined public _I2C_transmit_byte: 0000fd3d section .flash_update defined public _I2C_failcode: 000000bd section .bss defined public _eeprom_num_write: 000000b6 section .bss defined public -_I2C_write_byte: 0000a871 section .text defined public -_mqtt_parse_complete: 0000018c section .bss defined public -_upgrade_EEPROM: 0000b6e8 section .text defined public -_timer_update: 0000d371 section .text defined public -_publish_pinstate: 0000b4c1 section .text defined public -_read_bit: 00008d2e section .text defined public -_write_bit: 00008d5c section .text defined public -_Enc28j60Init: 0000906f section .text defined public -_gpio_init: 000093f4 section .text defined public -_HttpDStringInit: 00009490 section .text defined public -_HttpDInit: 00009d9d section .text defined public -_clock_init: 0000d2cd section .text defined public -_spi_init: 0000d1d5 section .text defined public -_uip_arp_init: 0000df81 section .text defined public -_uip_init: 0000d51f section .text defined public -_mqtt_init: 0000c05b section .text defined public -_strcat: 0000e453 section .text defined public -_mqtt_mq_init: 0000cbad section .text defined public +_I2C_write_byte: 0000a87a section .text defined public +_mqtt_parse_complete: 0000018d section .bss defined public +_upgrade_EEPROM: 0000b759 section .text defined public +_timer_update: 0000d596 section .text defined public +_publish_pinstate: 0000b532 section .text defined public +_read_bit: 00008d39 section .text defined public +_write_bit: 00008d67 section .text defined public +_Enc28j60Init: 0000907a section .text defined public +_gpio_init: 000093ff section .text defined public +_HttpDStringInit: 0000949b section .text defined public +_HttpDInit: 00009da8 section .text defined public +_clock_init: 0000d4f2 section .text defined public +_spi_init: 0000d3fa section .text defined public +_uip_arp_init: 0000e18d section .text defined public +_uip_init: 0000d740 section .text defined public +_mqtt_init: 0000c0e6 section .text defined public +_strcat: 0000e65f section .text defined public +_mqtt_mq_init: 0000cdc5 section .text defined public _DS18B20_scratch: 0000006c section .bss defined public -c_lgursh: 0000e72f section .text defined public -c_rtol: 0000e7a5 section .text defined public -_Port_Httpd: 0000018a section .bss defined public -_init_DS18B20: 00008d95 section .text defined public -_debugflash: 0000bf44 section .text defined public +c_lgursh: 0000e93b section .text defined public +c_rtol: 0000e9b1 section .text defined public +_Port_Httpd: 0000018b section .bss defined public +_init_DS18B20: 00008da0 section .text defined public +_debugflash: 0000bfb5 section .text defined public _eeprom_copy_to_flash: 0000fd7f section .flash_update defined public _copy_ram_to_flash: 00000012 section memcpy_update defined public -_unlock_flash: 0000b6da section .text defined public -_lock_flash: 0000b6e3 section .text defined public -_mqtt_publish: 0000c15d section .text defined public -_fastflash: 0000bf78 section .text defined public +_unlock_flash: 0000b74b section .text defined public +_lock_flash: 0000b754 section .text defined public +_mqtt_publish: 0000c1e8 section .text defined public +_fastflash: 0000bfe9 section .text defined public __endzp: 0000000a section .ubsct defined public -_dallas_crc8: 00008f28 section .text defined public -_main: 0000a8bc section .text defined public +_dallas_crc8: 00008f33 section .text defined public +_main: 0000a8c5 section .text defined public __stack: 000007ff section absolute defined public absolute _ITC_SPR3: 00007f72 section absolute defined public absolute _redefine_temp_sensors: 000000c3 section .bss defined public -c_lgadc: 0000e6a3 section .text defined public -_mqtt_sanity_check: 0000b255 section .text defined public -_mqtt_redefine_temp_sensors: 0000b0e5 section .text defined public -c_ladc: 0000e550 section .text defined public -_publish_callback: 0000b2f4 section .text defined public -_define_temp_sensors: 0000b107 section .text defined public -_exit: 00008b13 section .text defined public +c_lgadc: 0000e8af section .text defined public +_mqtt_sanity_check: 0000b294 section .text defined public +_mqtt_redefine_temp_sensors: 0000b124 section .text defined public +c_ladc: 0000e75c section .text defined public +_publish_callback: 0000b346 section .text defined public +_define_temp_sensors: 0000b146 section .text defined public +___mqtt_puback: 0000c279 section .text defined public +_exit: 00008b1e section .text defined public __vectab: 00008000 section .vector defined public _CLK_ICKR: 000050c0 section absolute defined public absolute _CLK_ECKR: 000050c1 section absolute defined public absolute _IWDG_KR: 000050e0 section absolute defined public absolute -_stack_error: 000001d9 section .bss defined public -__stext: 00008b0c section .text defined public -_Next: 00008e4b section .text defined public +_stack_error: 000001da section .bss defined public +__stext: 00008b17 section .text defined public +_Next: 00008e56 section .text defined public diff --git a/NetworkModule/.Idea_Temp/IDEA.ERR b/NetworkModule/.Idea_Temp/IDEA.ERR index 11f24e1..ac330bc 100644 --- a/NetworkModule/.Idea_Temp/IDEA.ERR +++ b/NetworkModule/.Idea_Temp/IDEA.ERR @@ -51,28 +51,25 @@ uip.o: uip_arp.o: uip_tcpapphub.o: (C:\Program Files (x86)\COSMIC\FSE_Compilers\CXSTM8\lib\libisl0.sm8)memcmp.o: -(C:\Program Files (x86)\COSMIC\FSE_Compilers\CXSTM8\lib\libisl0.sm8)memmov.o: (C:\Program Files (x86)\COSMIC\FSE_Compilers\CXSTM8\lib\libisl0.sm8)strcat0.o: (C:\Program Files (x86)\COSMIC\FSE_Compilers\CXSTM8\lib\libisl0.sm8)strcmp0.o: (C:\Program Files (x86)\COSMIC\FSE_Compilers\CXSTM8\lib\libisl0.sm8)strlen0.o: (C:\Program Files (x86)\COSMIC\FSE_Compilers\CXSTM8\lib\libm0.sm8)fctcpy.o: (C:\Program Files (x86)\COSMIC\FSE_Compilers\CXSTM8\lib\libm0.sm8)bmulx.o: +(C:\Program Files (x86)\COSMIC\FSE_Compilers\CXSTM8\lib\libm0.sm8)cmulx.o: (C:\Program Files (x86)\COSMIC\FSE_Compilers\CXSTM8\lib\libm0.sm8)eeprom.o: (C:\Program Files (x86)\COSMIC\FSE_Compilers\CXSTM8\lib\libm0.sm8)itolx.o: -(C:\Program Files (x86)\COSMIC\FSE_Compilers\CXSTM8\lib\libm0.sm8)itoly.o: (C:\Program Files (x86)\COSMIC\FSE_Compilers\CXSTM8\lib\libm0.sm8)ladc.o: (C:\Program Files (x86)\COSMIC\FSE_Compilers\CXSTM8\lib\libm0.sm8)ladd.o: (C:\Program Files (x86)\COSMIC\FSE_Compilers\CXSTM8\lib\libm0.sm8)lcmp.o: (C:\Program Files (x86)\COSMIC\FSE_Compilers\CXSTM8\lib\libm0.sm8)lsdiv.o: (C:\Program Files (x86)\COSMIC\FSE_Compilers\CXSTM8\lib\libm0.sm8)ldiv.o: (C:\Program Files (x86)\COSMIC\FSE_Compilers\CXSTM8\lib\libm0.sm8)lgadc.o: -(C:\Program Files (x86)\COSMIC\FSE_Compilers\CXSTM8\lib\libm0.sm8)lgadd.o: (C:\Program Files (x86)\COSMIC\FSE_Compilers\CXSTM8\lib\libm0.sm8)lglsh.o: (C:\Program Files (x86)\COSMIC\FSE_Compilers\CXSTM8\lib\libm0.sm8)lgneg.o: (C:\Program Files (x86)\COSMIC\FSE_Compilers\CXSTM8\lib\libm0.sm8)lgor.o: (C:\Program Files (x86)\COSMIC\FSE_Compilers\CXSTM8\lib\libm0.sm8)lgsbc.o: (C:\Program Files (x86)\COSMIC\FSE_Compilers\CXSTM8\lib\libm0.sm8)lgsub.o: -(C:\Program Files (x86)\COSMIC\FSE_Compilers\CXSTM8\lib\libm0.sm8)lgursh.o: (C:\Program Files (x86)\COSMIC\FSE_Compilers\CXSTM8\lib\libm0.sm8)lneg.o: (C:\Program Files (x86)\COSMIC\FSE_Compilers\CXSTM8\lib\libm0.sm8)lreg.o: (C:\Program Files (x86)\COSMIC\FSE_Compilers\CXSTM8\lib\libm0.sm8)ltor.o: @@ -82,6 +79,8 @@ uip_tcpapphub.o: (C:\Program Files (x86)\COSMIC\FSE_Compilers\CXSTM8\lib\libm0.sm8)rtol.o: (C:\Program Files (x86)\COSMIC\FSE_Compilers\CXSTM8\lib\libm0.sm8)sdivx.o: (C:\Program Files (x86)\COSMIC\FSE_Compilers\CXSTM8\lib\libm0.sm8)smul.o: +(C:\Program Files (x86)\COSMIC\FSE_Compilers\CXSTM8\lib\libm0.sm8)utol.o: (C:\Program Files (x86)\COSMIC\FSE_Compilers\CXSTM8\lib\libm0.sm8)utolx.o: +(C:\Program Files (x86)\COSMIC\FSE_Compilers\CXSTM8\lib\libm0.sm8)umul.o: (C:\Program Files (x86)\COSMIC\FSE_Compilers\CXSTM8\lib\libm0.sm8)xreg.o: (C:\Program Files (x86)\COSMIC\FSE_Compilers\CXSTM8\lib\libm0.sm8)yreg.o: diff --git a/NetworkModule/.Idea_Temp/IDEABLD.BAT b/NetworkModule/.Idea_Temp/IDEABLD.BAT index 3b67e2b..6bdb2ce 100644 --- a/NetworkModule/.Idea_Temp/IDEABLD.BAT +++ b/NetworkModule/.Idea_Temp/IDEABLD.BAT @@ -1,5 +1,5 @@ REM COMMAND FILE BUILT BY IDEA -REM Sat Oct 15 06:37:23 2022 +REM Wed Nov 09 11:24:39 2022 REM cxstm8 -v -l +strict +debug +modsl0 +split +warn "networkmodule_vector.c" cxstm8 -v -l +strict +debug +modsl0 +split +warn "ds18b20.c" "enc28j60.c" "gpio.c" "httpd.c" "i2c.c" "main.c" "mqtt.c" "mqtt_pal.c" "spi.c" "timer.c" "uart.c" "uip.c" "uip_arp.c" "uip_tcpapphub.c" diff --git a/NetworkModule/DS18B20.c b/NetworkModule/DS18B20.c index 2cae0c8..3c144d1 100644 --- a/NetworkModule/DS18B20.c +++ b/NetworkModule/DS18B20.c @@ -36,11 +36,8 @@ #include "uart.h" #include "uipopt.h" -// #if BUILD_SUPPORT == BROWSER_ONLY_BUILD || BUILD_SUPPORT == MQTT_BUILD -// extern uint8_t DS18B20_scratch_byte[2]; // Array to store scratchpad bytes uint8_t DS18B20_scratch_byte[2]; // Array to store scratchpad bytes // read from DS18B20 -// extern uint8_t DS18B20_scratch[5][2]; // Stores the temperature measurement uint8_t DS18B20_scratch[5][2]; // Stores the temperature measurement // for the DS18B20s @@ -82,7 +79,6 @@ uint8_t ROM[8]; // ROM bytes // [7] = CRC uint8_t lastDiscrep = 0; // last discrepancy uint8_t doneFlag = 0; // Done flag -// extern uint8_t FoundROM[5][8]; // Table of ROM codes uint8_t FoundROM[5][8]; // Table of ROM codes // [x][0] = Family Code // [x][1] = LSByte serial number @@ -94,15 +90,6 @@ uint8_t FoundROM[5][8]; // Table of ROM codes // [x][7] = CRC extern int numROMs; // Count of DS18B20 devices found -// extern uint8_t temp_FoundROM[5][8]; // Temporary table of old ROM codes -// // [x][0] = Family Code -// // [x][1] = LSByte serial number -// // [x][2] = byte 2 serial number -// // [x][3] = byte 3 serial number -// // [x][4] = byte 4 serial number -// // [x][5] = byte 5 serial number -// // [x][6] = MSByte serial number -// // [x][7] = CRC uint8_t new_FoundROM_crc; // Used in calculation of the CRC for // the FoundROM table. Used to determine // if a table change has occurred. @@ -174,7 +161,6 @@ void get_temperature() int i; uint8_t j; uint8_t device_num; -// extern uint8_t DS18B20_scratch[5][2]; // Read current temperature from up to 5 devices for (device_num = 0; device_num < 5; device_num++) { @@ -257,7 +243,6 @@ void convert_temperature(uint8_t device_num, uint8_t degCorF) // int16_t whole_temp; uint8_t decimal_temp; -// extern uint8_t DS18B20_scratch[5][2]; uint8_t sign_char; // Convert temperature reading to string. @@ -398,10 +383,6 @@ void convert_temperature(uint8_t device_num, uint8_t degCorF) whole_temp++; sign_char = '-'; } -// else { -// // Positive number -// sign_char = ' '; -// } // Extract whole temp and decimal temp parts of the DS18B20 // values @@ -452,7 +433,6 @@ void convert_temperature(uint8_t device_num, uint8_t degCorF) whole_temp = (int16_t)(F_temp2 / 16); // Now calculate the "decimal" part of the display in degrees F decimal_temp = (uint8_t)(F_temp2 & 0xf); -// sign_char = ' '; if (F_temp2 < 0) { // Must use twos complement if the degrees F result is negative whole_temp = whole_temp * -1; @@ -635,9 +615,6 @@ void FindDevices(void) numROMs = -1; // -1 indicates no devices if (!reset_pulse()) { //Begins when a presence is detected - -// UARTPrintf("\r\nPresence detected\r\n"); - if (First()) { //Begins when at least one part is found do { numROMs++; // On first pass this increments numROMs to index 0 @@ -660,30 +637,12 @@ void FindDevices(void) // table new_FoundROM_crc = (uint8_t)(FoundROM[0][7] + FoundROM[1][7] + FoundROM[2][7] + FoundROM[3][7] + FoundROM[4][7]); -// UARTPrintf("\r\nDS18B20 FindDevices numROMs = "); -// if (numROMs >= 0) { -// emb_itoa(numROMs, OctetArray, 10, 2); -// UARTPrintf(OctetArray); -// } -// else if (numROMs == -1) UARTPrintf("-1"); -// else UARTPrintf("unitialized"); -// UARTPrintf("\r\n"); - if (new_FoundROM_crc != old_FoundROM_crc) { // Signal the main loop that the temp sensors need to be updated in the // Browser display and over MQTT redefine_temp_sensors = 1; old_FoundROM_crc = new_FoundROM_crc; } - -// UARTPrintf("new_FoundROM_crc = "); -// emb_itoa(new_FoundROM_crc, OctetArray, 16, 2); -// UARTPrintf(OctetArray); -// UARTPrintf(" redefine_temp_sensors = "); -// emb_itoa(redefine_temp_sensors, OctetArray, 16, 2); -// UARTPrintf(OctetArray); -// UARTPrintf("\r\n"); - } @@ -761,25 +720,8 @@ uint8_t Next(void) } } while(n < 8); //loop until through all ROM bytes 0-7 -// { -// uint8_t i; -// UARTPrintf("\r\nROM bytes: "); -// for (i=0; i<8; i++) { -// emb_itoa(ROM[i], OctetArray, 16, 2); -// UARTPrintf(OctetArray); -// UARTPrintf(" "); -// } -// UARTPrintf("\r\n"); -// } - // Calculate CRC for first 7 ROM bytes crc = dallas_crc8(ROM, 7); - -// UARTPrintf("\r\nDS18B20 CRC:"); -// if (crc != ROM[7]) UARTPrintf("Fail"); -// else UARTPrintf("Pass"); -// UARTPrintf("\r\n"); - if (m < 65 || (crc != ROM[7])) lastDiscrep = 0; // if search was unsuccessful then reset the last discrepancy to 0 @@ -817,5 +759,3 @@ uint8_t dallas_crc8(uint8_t *data, uint8_t size) } return crc; } - -// #endif // BUILD_SUPPORT == BROWSER_ONLY_BUILD || BUILD_SUPPORT == MQTT_BUILD diff --git a/NetworkModule/Enc28j60.c b/NetworkModule/Enc28j60.c index 3dfbd00..0909f18 100644 --- a/NetworkModule/Enc28j60.c +++ b/NetworkModule/Enc28j60.c @@ -639,6 +639,11 @@ uint16_t Enc28j60Receive(uint8_t* pBuffer) // Check for buffer overflow - RXERIF (bit 0) of EIR register // If overflow increment the error counter if (Enc28j60ReadReg(BANKX_EIR) & 0x01) { + +#if DEBUG_SUPPORT != 11 +UARTPrintf("Enc28j60Receive OVERFLOW detected\r\n"); +#endif // DEBUG_SUPPORT != 11 + RXERIF_counter++; // Clear RXERIF Enc28j60ClearMaskReg(BANKX_EIR, (1< 0) { // This code is executed if incoming traffic is HTTP or MQTT (not ARP). // uip_len includes the headers, so it will be > 0 even if no TCP // payload. if (((struct uip_eth_hdr *) & uip_buf[0])->type == htons(UIP_ETHTYPE_IP)) { + +#if DEBUG_SUPPORT != 11 // UARTPrintf("Detected uip_len > 0 UIP_ETHTYPE_IP\r\n"); // UARTPrintf("uip_len = "); // emb_itoa(uip_len, OctetArray, 10, 5); // UARTPrintf(OctetArray); // UARTPrintf("\r\n"); +#endif // DEBUG_SUPPORT != 11 uip_input(); // Calls uip_process(UIP_DATA) to process a received // packet. @@ -754,7 +802,8 @@ int main(void) // the network the global variable uip_len will have been set to a // value > 0. if (uip_len > 0) { - uip_arp_out(); + uip_arp_out(); // Verifies arp entry in the ARP table and builds + // the LLH // The original uip code has a uip_split_output function. It is not // needed for this application due to small packet sizes, so the // Enc28j60 transmit functions are called directly. @@ -762,7 +811,9 @@ int main(void) } } else if (((struct uip_eth_hdr *) & uip_buf[0])->type == htons(UIP_ETHTYPE_ARP)) { +// #if DEBUG_SUPPORT != 11 // UARTPrintf("Detected uip_len > 0 UIP_ETHTYPE_ARP\r\n"); +// #endif // DEBUG_SUPPORT != 11 uip_arp_arpin(); // If the above process resulted in data that should be sent out on // the network the global variable uip_len will have been set to a @@ -796,7 +847,8 @@ int main(void) if (mqtt_enabled && mqtt_start == MQTT_START_COMPLETE && restart_reboot_step == RESTART_REBOOT_IDLE) { - mqtt_sanity_check(); +// mqtt_sanity_check(); + mqtt_sanity_check(&mqttclient); } // Check for Temperature Sensor changes and send redefine @@ -823,14 +875,21 @@ int main(void) for(i = 0; i < UIP_CONNS; i++) { uip_periodic(i); // uip_periodic() calls uip_process(UIP_TIMER) for each connection. + // Every connection is checked in this loop one time. // uip_process(UIP_TIMER) will check the HTTP and MQTT connections - // for any unserviced outbound traffic. HTTP can have pending - // transmissions because the web pages can be broken into several - // packets. MQTT will always use this function to transmit packets. + // for any unserviced outbound traffic one packet at a time. + // HTTP connections (the webbrowser) will generate and place its + // data in the uip_buf via a call to HttpDCall(). HTTP connections + // can have pending transmissions which are continuations of a + // series of packets because the web pages can be broken into + // several packets. + // MQTT will always use this function to transmit packets. MQTT + // will have placed its outbound packets in the mqtt_sendbuf. MQTT + // connections will consist of a complete message in one packet. // // If uip_periodic() resulted in data that should be sent out on // the network the global variable uip_len will have been set to a - // value > 0. + // value > 0 so that Enc28j60Send() will be called. // // Note that when the device first powers up and MQTT is enabled the // MQTT processes will attempt to send a SYN to create a TCP @@ -874,15 +933,49 @@ int main(void) // If the MQTT timer expires (50ms) // And MQTT is enabled // And MQTT startup is complete - // Then check for messages that need to be published including a - // check for pin state changes - // Note that publish_outbound only places the message in the queue, then - // uip_periodic() will cause the actual transmission at 20ms intervals. + // Then check for pin state change messages that need to be + // published + // Note that publish_outbound only places the message in the mqtt_sendbuf + // queue, then uip_periodic() will cause the actual transmission at 20ms + // intervals. // Also // Increment the MQTT timers every 50ms if (mqtt_timer_expired()) { if (mqtt_enabled) { - if (mqtt_start == MQTT_START_COMPLETE) publish_outbound(); + if (mqtt_start == MQTT_START_COMPLETE) { + if (publish_outbound_throttle == 0) { + // publish_outbound() is called to send pin_control state change + // PUBLISH messages. Due to the small size of the mqtt_sendbuf the + // rate at which theses messages are placed in the mqtt_sendbuf + // needs to be throttled so it can be assured that a message + // has time to be transmitted before another is placed in the + // mqtt_sendbuf, also leaving time for other transmit messages + // (for example "ping" messages and PUBACK messages). + // During implementation of QOS 1 the "publish_outbound_throttle" + // was implemented to allow even more time for these transmit + // processes if necessary. + // A setting of "0" allows 50ms between calls to publish_outbound(). + // 50ms is the mqtt_time_expired() interval). This seems to be + // adequate at this writing. Each incremental increase in the + // publish_outbound_throttle test adds another 50ms: + // "== 0" is 50ms interval + // "== 1" is 100ms + // "== 2" is 150ms + // and so on. + // For future reference this throttle was implemented during test + // of the Home Assistant "Toggle" function, wherein a large burst + // of incoming PUBLISH messages would occur. There is the need to + // assure enough processing gaps to accomodate messages that need + // to pass through the very small mqtt_sendbuf, which then gets + // emptied through the uip_buf. The process is problematic because + // the uip_buf is also used for all incoming PUBLISH messages. + // IF IT TURNS OUT THIS THROTTLE NEVER NEED TO BE INCREASED THE + // CODE COULD BE SIMPLIFIED A LITTLE BY ELIMINATING IT. + publish_outbound(); + publish_outbound_throttle = 0; + } + else publish_outbound_throttle++; + } mqtt_start_ctr1++; // Increment the MQTT start loop timer 1. This is // used to: // - Timeout the MQTT Server ARP request or the @@ -912,7 +1005,6 @@ int main(void) // Block the request if no EEPROM was detected or if an error occurred // during SREC download. if (eeprom_copy_to_flash_request == I2C_COPY_EEPROM0_REQUEST) { -// UARTPrintf("\r\neeprom0_copy_to_flash_request received\r\n"); eeprom_copy_to_flash_request = I2C_COPY_EEPROM0_WAIT; check_I2C_EEPROM_ctr = t100ms_ctr1; } @@ -932,10 +1024,10 @@ int main(void) // the eeprom_copy_to_flash() function will call the copy_ram_to_flash() // function in the memcpy_update segment from RAM. if (_fctcpy ('m') == 0) { - // UARTPrintf("eeprom0 fctcpy failed\r\n"); +// UARTPrintf("eeprom0 fctcpy failed\r\n"); } else { - // UARTPrintf("eeprom0 fctcpy success\r\n"); +// UARTPrintf("eeprom0 fctcpy success\r\n"); } if (eeprom_detect == 1 && upgrade_failcode == UPGRADE_OK) { @@ -956,12 +1048,10 @@ int main(void) if (eeprom_copy_to_flash_request == I2C_COPY_EEPROM1_REQUEST) { eeprom_copy_to_flash_request = I2C_COPY_EEPROM1_WAIT; check_I2C_EEPROM_ctr = t100ms_ctr1; -// UARTPrintf("\r\nCmd 72 waiting\r\n"); } // Give main loop 500ms for browser update if ((eeprom_copy_to_flash_request == I2C_COPY_EEPROM1_WAIT) && (t100ms_ctr1 > (check_I2C_EEPROM_ctr + 5))) { -// UARTPrintf("\r\nCmd 72 executing\r\n"); unlock_flash(); // eeprom_copy_to_flash will cause a reboot on completion of the // function. @@ -1003,7 +1093,6 @@ int main(void) // intervals if ((stored_config_settings & 0x08) && (second_counter > (check_DS18B20_sensor_ctr + 10))) { check_DS18B20_sensor_ctr = second_counter; -// check_temperature_sensor_changes(); // Call FindDevices to generate a new FoundROM table and determine if // any changes occured in the sensor population. FindDevices(); @@ -1060,42 +1149,31 @@ uint8_t off_board_EEPROM_detect(void) eeprom_detect = 0; -// UARTPrintf("\r\nVerifying prescence of EEPROM\r\n"); - // Make sure the I2C bus is in a sane condition. I2C_reset(); wait_timer(1000); // Wait 1 ms // Read 1 byte from Off-Board EEPROM. -// UARTPrintf("\r\nStep 1\r\n"); prep_read(I2C_EEPROM0_WRITE, I2C_EEPROM0_READ, I2C_EEPROM0_BASE); byte = I2C_read_byte(1); // Write inverted byte to Off-Board EEPROM. -// UARTPrintf("\r\nStep 2\r\n"); write_one((uint8_t)~byte); // Read and validate 1 byte from Off-Board EEPROM. -// UARTPrintf("\r\nStep 3\r\n"); prep_read(I2C_EEPROM0_WRITE, I2C_EEPROM0_READ, I2C_EEPROM0_BASE); if ((uint8_t)~byte == I2C_read_byte(1)) { eeprom_detect = 1; } else { - -// UARTPrintf("\r\nEEPROM not present XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\r\n"); - } // Restore the original 1 byte to Off-Board EEPROM. -// UARTPrintf("\r\nStep 4\r\n"); write_one(byte); -// UARTPrintf("\r\nExit EEPROM Verify\r\n"); - return eeprom_detect; } #endif // OB_EEPROM_SUPPORT == 1 @@ -1147,14 +1225,9 @@ uint8_t compare_flash_to_EEPROM1(void) uint8_t temp; flash_ptr = (char *)FLASH_START_PROGRAM_MEMORY; - -// UARTPrintf("\r\nComparing EEPROM1 to Flash\r\n"); prep_read(I2C_EEPROM1_WRITE, I2C_EEPROM1_READ, I2C_EEPROM1_BASE); - fail = 0; -// UARTPrintf("\r\n"); - // Compare Flash to Off-Board EEPROM1 up to but not including the // IO_TIMERS and IO_NAMES. // Terminate at the first mis-compare @@ -1175,17 +1248,7 @@ uint8_t compare_flash_to_EEPROM1(void) if (*flash_ptr != temp) { fail = 1; } - -// if (fail == 0) { -// UARTPrintf("\r\nEEPROM1 matches Flash\r\n"); -// } -// else { -// UARTPrintf("\r\nEEPROM1 doesn't match Flash\r\n"); -// UARTPrintf(" Miscompare at: "); -// emb_itoa(i, OctetArray, 16, 4); -// UARTPrintf(OctetArray); -// UARTPrintf("\r\n"); -// } + // if (fail == 0) EEPROM1 matches Flash return fail; } #endif // BUILD_SUPPORT == CODE_UPLOADER_BUILD @@ -1205,15 +1268,9 @@ uint8_t compare_flash_to_EEPROM0(void) uint8_t temp; flash_ptr = (char *)FLASH_START_PROGRAM_MEMORY; - -// UARTPrintf("\r\nComparing EEPROM0 to Flash\r\n"); - prep_read(I2C_EEPROM0_WRITE, I2C_EEPROM0_READ, I2C_EEPROM0_BASE); - fail = 0; -// UARTPrintf("\r\n"); - // Compare Flash to Off-Board EEPROM0 up to but not including the // IO_TIMERS and IO_NAMES. // Terminate at the first mis-compare @@ -1221,12 +1278,6 @@ uint8_t compare_flash_to_EEPROM0(void) temp = I2C_read_byte(0); if (*flash_ptr != temp) { fail = 1; - -// UARTPrintf("\r\nMiscompare at address: \r\n"); -// emb_itoa(i, OctetArray, 16, 4); -// UARTPrintf(" "); -// UARTPrintf(OctetArray); - break; } else { @@ -1241,12 +1292,7 @@ uint8_t compare_flash_to_EEPROM0(void) fail = 1; } -// if (fail == 0) { -// UARTPrintf("\r\nEEPROM0 matches Flash\r\n"); -// } -// else { -// UARTPrintf("\r\nEEPROM0 doesn't match Flash\r\n"); -// } + // if (fail == 0) EEPROM0 matches Flash return fail; } #endif // OB_EEPROM_SUPPORT == 1 @@ -1267,18 +1313,13 @@ void copy_code_uploader_to_EEPROM1(void) flash_ptr = (char *)FLASH_START_PROGRAM_MEMORY; address_index = I2C_EEPROM1_BASE; - -// UARTPrintf("\r\nCopying Code Uploader from Flash to off-board EEPROM1\r\n"); - + I2C_reset(); wait_timer(1000); // Wait 1 ms while (address_index < FLASH_START_USER_RESERVE) { // Note for "while" statement: address_index will be incremented by 128 // with each loop. - -// UARTPrintf("."); - I2C_control(I2C_EEPROM1_WRITE); // Send Write Control Byte for upper // Off-Board EEPROM area I2C_byte_address(address_index); @@ -1296,17 +1337,11 @@ void copy_code_uploader_to_EEPROM1(void) for (i=0; i<128; i++) { if (i == 127) I2C_last_flag = 1; temp_byte = I2C_read_byte(I2C_last_flag); - -// if (temp_byte != *flash) { -// UARTPrintf("\r\nCode Uploader copy mis-compare XXXXXXXXXXXXXXXXXXXXXXXXX\r\n"); -// } flash_ptr++; } address_index += 128; IWDG_KR = 0xaa; // Prevent the IWDG hardware watchdog from firing. } - -// UARTPrintf("\r\nCode Uploader copy complete\r\n"); } #endif // BUILD_SUPPORT == CODE_UPLOADER_BUILD @@ -1333,17 +1368,10 @@ void copy_flash_to_EEPROM0(void) flash_ptr = (char *)FLASH_START_PROGRAM_MEMORY; address_index = I2C_EEPROM0_BASE; - -// UARTPrintf("\r\nCopying Flash to off-board EEPROM0\r\n"); - I2C_reset(); wait_timer(1000); // Wait 1 ms -// while (address_index < (FLASH_START_USER_RESERVE - 0x8000)) { while (address_index < OFFSET_TO_FLASH_START_USER_RESERVE) { - -// UARTPrintf("."); - I2C_control(I2C_EEPROM0_WRITE); I2C_byte_address(address_index); for (i=0; i<128; i++) { @@ -1360,17 +1388,11 @@ void copy_flash_to_EEPROM0(void) for (i=0; i<128; i++) { if (i == 127) I2C_last_flag = 1; temp_byte = I2C_read_byte(I2C_last_flag); - -// if (temp_byte != *flash) { -// UARTPrintf("\r\nFlash copy mis-compare XXXXXXXXXXXXXXXXXXXXXXXXX\r\n"); -// } - flash_ptr++; + flash_ptr++; } address_index += 128; IWDG_KR = 0xaa; // Prevent the IWDG hardware watchdog from firing. } - -// UARTPrintf("\r\nFlash copy complete\r\n"); } #endif // OB_EEPROM_SUPPORT == 1 @@ -1578,7 +1600,7 @@ void mqtt_startup(void) // that the mqtt.c code can tell the main.c code that the CONNECT CONNACK // was received. // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX - // On reboot I frequently see that we get to this point, a Connack is + // On reboot I sometimes see that we get to this point, a Connack is // sent to us, but we don't get a connack_received from the mqtt code. // I suspect the problem is that I'm not shutting down the mqtt code // properly, and the process steps here are seen as an error of some @@ -1603,6 +1625,7 @@ void mqtt_startup(void) } break; +#if QOS_SUPPORT == 0 case MQTT_START_QUEUE_SUBSCRIBE1: if (mqtt_start_ctr1 > 4) { // Subscribe to the output control messages @@ -1611,27 +1634,54 @@ void mqtt_startup(void) // Wait 200ms before queueing first Subscribe msg. // // The mqtt_subscribe function will create the message and put it in the - // transmit queue. uip_periodic() will start the process that will call - // mqtt_sync to put the message in the uip_buf. - - // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX - // I find that I can't queue multiple subscribe messages without them - // taking 10's of seconds to complete. Had this same problem with - // publish messages. I think something is wrong with the LiamBindle - // transmit queueing, or my interface to it. The quickest solution for - // now is to queue a message, return to the main loop so it can - // transmit, then queue another message. - // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + // mqtt_sendbuf queue. uip_periodic() will start the process that will + // call mqtt_sync to put the message in the uip_buf. + // + // In the mqtt_subscribe call the maximum QOS level supported is specified + // as 0. + // + // Note: Timing is managed here to prevent placing multiple SUBSCRIBE + // messages in the mqtt_sendbuf as that buffer is very small. + + suback_received = 0; + strcpy(topic_base, devicetype); + strcat(topic_base, stored_devicename); + strcat(topic_base, "/output/+/set"); + mqtt_subscribe(&mqttclient, topic_base, 0); + mqtt_start_ctr1 = 0; // Clear 50ms counter + mqtt_start = MQTT_START_VERIFY_SUBSCRIBE1; + } + break; +#endif // QOS_SUPPORT == 0 + +#if QOS_SUPPORT == 1 + case MQTT_START_QUEUE_SUBSCRIBE1: + if (mqtt_start_ctr1 > 4) { + // Subscribe to the output control messages + // + // Queue the mqtt_subscribe messages for transmission to the MQTT Broker. + // Wait 200ms before queueing first Subscribe msg. + // + // The mqtt_subscribe function will create the message and put it in the + // mqtt_sendbuf queue. uip_periodic() will start the process that will + // call mqtt_sync to put the message in the uip_buf. + // + // In the mqtt_subscribe call the maximum QOS level supported is specified + // as 1 for HA compatibility. + // + // Note: Timing is managed here to prevent placing multiple SUBSCRIBE + // messages in the mqtt_sendbuf as that buffer is very small. suback_received = 0; strcpy(topic_base, devicetype); strcat(topic_base, stored_devicename); strcat(topic_base, "/output/+/set"); - mqtt_subscribe(&mqttclient, topic_base); + mqtt_subscribe(&mqttclient, topic_base, 1); mqtt_start_ctr1 = 0; // Clear 50ms counter mqtt_start = MQTT_START_VERIFY_SUBSCRIBE1; } break; +#endif // QOS_SUPPORT == 1 case MQTT_START_VERIFY_SUBSCRIBE1: // Verify that the SUBSCRIBE SUBACK was received. @@ -1656,20 +1706,41 @@ void mqtt_startup(void) } break; + +#if QOS_SUPPORT == 0 + case MQTT_START_QUEUE_SUBSCRIBE2: + if (mqtt_start_ctr1 > 4) { + // Subscribe to the state-req message + // + // Wait 200ms before queuing the Subscribe message + suback_received = 0; + strcpy(topic_base, devicetype); + strcat(topic_base, stored_devicename); + strcat(topic_base, "/state-req"); + mqtt_subscribe(&mqttclient, topic_base, 0); + mqtt_start_ctr1 = 0; // Clear 50ms counter + mqtt_start = MQTT_START_VERIFY_SUBSCRIBE2; + } + break; +#endif // QOS_SUPPORT == 0 + +#if QOS_SUPPORT == 1 case MQTT_START_QUEUE_SUBSCRIBE2: if (mqtt_start_ctr1 > 4) { // Subscribe to the state-req message + // This Subscribe is at QOS 0 // // Wait 200ms before queuing the Subscribe message suback_received = 0; strcpy(topic_base, devicetype); strcat(topic_base, stored_devicename); strcat(topic_base, "/state-req"); - mqtt_subscribe(&mqttclient, topic_base); + mqtt_subscribe(&mqttclient, topic_base, 0); mqtt_start_ctr1 = 0; // Clear 50ms counter mqtt_start = MQTT_START_VERIFY_SUBSCRIBE2; } break; +#endif // QOS_SUPPORT == 1 case MQTT_START_VERIFY_SUBSCRIBE2: // Verify that the SUBSCRIBE SUBACK was received. @@ -1705,10 +1776,11 @@ void mqtt_startup(void) } break; -/* case MQTT_START_QUEUE_PUBLISH_AUTO: if (mqtt_start_ctr1 > 2) { // Publish Home Assistant Auto Discovery messages + // This part of the state machine runs only if Home Assistant Auto + // Discovery is enabled. // This step of the state machine is entered multiple times until all // Home Assistant Auto Discovery Publish messages are sent. // @@ -1720,215 +1792,10 @@ void mqtt_startup(void) // placeholder Publish message during the "copy to uip_buf" process // and will replace the special markers at that time to create the // actual Publish message required by Home Assistant. This complication - // is necessary because the MQTT transmit buffer is not large enough to - // contain an entire Auto Discovery Publish message, so it is - // constructed on-the-fly as the app_message is written to the uip_buf - // transmit buffer by the mqtt_pal.c function. - // - // The following placeholder Publish message will create an Output Auto - // Discovery message. "xx" is the output IO number. - // mqtt_publish(&mqttclient, - // topic_base, - // "%Oxx", - // 4, - // MQTT_PUBLISH_QOS_0 | MQTT_PUBLISH_RETAIN); - // - // The following placeholder Publish message will create an Input Auto - // Discovery message. "xx" is the input IO number. - // mqtt_publish(&mqttclient, - // topic_base, - // "%Ixx", - // 4, - // MQTT_PUBLISH_QOS_0 | MQTT_PUBLISH_RETAIN); - // - // The following placeholder Publish message will create a Temperature - // Sensor Auto Discovery message. "xx" is the input IO number. - // mqtt_publish(&mqttclient, - // topic_base, - // "%Txx", - // 4, - // MQTT_PUBLISH_QOS_0 | MQTT_PUBLISH_RETAIN); - //---------------------------------------------------------------------// - - // This part of the state machine will walk through the pin_control - // bytes and send an Auto Discovery Publish message for every pin as - // follows: - // - // For every pin that is an Enabled Input: - // - An Output Config message is sent with an empty payload (to make - // sure any prior Output definition is deleted in Home Assistant). - // - An Input Config message is sent with a definition payload. - // - // For every pin that is an Enabled Output: - // - An Input Config message is sent with an empty payload (to make - // sure any prior Input definition is deleted in Home Assistant). - // - An Output Config message is sent with a defining payload. - // - // For every pin that is Disabled: - // - An Input Config message is sent with an empty payload (to make - // sure any prior Input definition is deleted in Home Assistant). - // - An Output Config message is sent with an empty payload (to make - // sure any prior Output definition is deleted in Home Assistant). - // - // If DS18B20 is enabled: - // - A Temperature Sensor Config message is sent with an empty - // payload for all 5 sensors (to make sure any prior Temperature - // Sensor definition is deleted in Home Assistant). - // - A Temperature Sensor Config message is sent for every sensor - // that was discovered. - - if (auto_discovery == DEFINE_INPUTS) { - // Pins 1 to 15 each require two Config messages. - // One to delete any prior Output definition. - // One to send the Input definition. - // Pin 16 requires seven Config messages. - // One to delete any prior Output definition. - // One to send the Input definition. - // Five to delete any prior Temperature Sensor definition. - if (((pin_control[pin_ptr - 1] & 0x01) == 0x01) - && ((pin_control[pin_ptr - 1] & 0x02) == 0x00)) { - // Pin is an Enabled Input pin - if (auto_discovery_step == SEND_OUTPUT_DELETE) { - // Create Output pin delete msg. - send_IOT_msg(pin_ptr, OUTPUTMSG, DELETE_IOT, 0); - auto_discovery_step = SEND_INPUT_DEFINE; - } - - else if (auto_discovery_step == SEND_INPUT_DEFINE) { - // Create Input pin define msg. - send_IOT_msg(pin_ptr, INPUTMSG, DEFINE_IOT, 0); - - if (pin_ptr == 16) { - pin_ptr = 1; - auto_discovery = DEFINE_OUTPUTS; - auto_discovery_step = SEND_INPUT_DELETE; - } - else { - pin_ptr++; - auto_discovery_step = SEND_OUTPUT_DELETE; - } - } - } - else { - if (pin_ptr == 16) { - pin_ptr = 1; - auto_discovery = DEFINE_OUTPUTS; - auto_discovery_step = SEND_INPUT_DELETE; - } - else pin_ptr++; - } - } - - else if (auto_discovery == DEFINE_OUTPUTS) { - // Pins 1 to 15 each require two Config messages. - // One to delete any prior Input definition. - // One to send the Output definition. - // Pin 16 requires seven Config messages. - // One to delete any prior Input definition. - // One to send the Output definition. - // Five to delete any prior Temperature Sensor definition. - if (((pin_control[pin_ptr - 1] & 0x01) == 0x01) - && ((pin_control[pin_ptr - 1] & 0x02) == 0x02)) { - // Pin is an Enabled Output pin - if (auto_discovery_step == SEND_INPUT_DELETE) { - // Create Input pin delete msg. - send_IOT_msg(pin_ptr, INPUTMSG, DELETE_IOT, 0); - auto_discovery_step = SEND_OUTPUT_DEFINE; - } - - else if (auto_discovery_step == SEND_OUTPUT_DEFINE) { - // Create Output pin define msg. - send_IOT_msg(pin_ptr, OUTPUTMSG, DEFINE_IOT, 0); - - if (pin_ptr == 16) { - pin_ptr = 1; - auto_discovery = DEFINE_DISABLED; - auto_discovery_step = SEND_INPUT_DELETE; - } - else pin_ptr++; - auto_discovery_step = SEND_INPUT_DELETE; - } - } - else { - if (pin_ptr == 16) { - pin_ptr = 1; - auto_discovery = DEFINE_DISABLED; - auto_discovery_step = SEND_INPUT_DELETE; - } - else pin_ptr++; - } - } - - else if (auto_discovery == DEFINE_DISABLED) { - // Pins 1 to 15 each require two Config messages. - // One to delete any prior Input definition. - // One to delete any prior Output definition. - // Pin 16 requires seven Config messages. - // One to delete any prior Input definition. - // One to delete any prior Output definition. - // Five to delete any prior Temperature Sensor definition. - if ((pin_control[pin_ptr - 1] & 0x01) == 0x00) { - // Pin is Disabled - if (auto_discovery_step == SEND_INPUT_DELETE) { - // Create Input pin delete msg. - send_IOT_msg(pin_ptr, INPUTMSG, DELETE_IOT, 0); - auto_discovery_step = SEND_OUTPUT_DELETE; - } - - else if (auto_discovery_step == SEND_OUTPUT_DELETE) { - // Create Output pin delete msg. - send_IOT_msg(pin_ptr, OUTPUTMSG, DELETE_IOT, 0); - - if (pin_ptr == 16) { - auto_discovery = DEFINE_TEMP_SENSORS; - auto_discovery_step = SEND_TEMP_SENSOR_DELETE; - } - else { - pin_ptr++; - auto_discovery_step = SEND_INPUT_DELETE; - } - } - } - else { - if (pin_ptr == 16) { - auto_discovery = DEFINE_TEMP_SENSORS; - auto_discovery_step = SEND_TEMP_SENSOR_DELETE; - } - else pin_ptr++; - } - } - - else if (auto_discovery == DEFINE_TEMP_SENSORS) { - define_temp_sensors(); - } - - mqtt_start_ctr1 = 0; // Clear the 50ms counter - if (auto_discovery == AUTO_COMPLETE) { - auto_discovery_step = STEP_NULL; - mqtt_start = MQTT_START_QUEUE_PUBLISH_ON; - } - } - break; -*/ - - case MQTT_START_QUEUE_PUBLISH_AUTO: - if (mqtt_start_ctr1 > 2) { - // Publish Home Assistant Auto Discovery messages - // This step of the state machine is entered multiple times until all - // Home Assistant Auto Discovery Publish messages are sent. - // - //---------------------------------------------------------------------// - // This function will create a "placeholder" Publish message. The - // placeholder message contains special markers that need to be - // replaced later with more extensive text fields required in the - // actual Publish message. The mqtt_pal.c function will detect the - // placeholder Publish message during the "copy to uip_buf" process - // and will replace the special markers at that time to create the - // actual Publish message required by Home Assistant. This complication - // is necessary because the MQTT transmit buffer is not large enough to - // contain an entire Auto Discovery Publish message, so it is - // constructed on-the-fly as the app_message is written to the uip_buf - // transmit buffer by the mqtt_pal.c function. + // is necessary because the MQTT transmit buffer (mqtt_sendbuf) is not + // large enough to contain an entire Auto Discovery Publish message, so + // it is constructed on-the-fly as the app_message is written to the + // uip_buf transmit buffer by the mqtt_pal.c function. // // The following placeholder Publish message will create an Output Auto // Discovery message. "xx" is the output IO number. @@ -2078,7 +1945,6 @@ void mqtt_startup(void) } else if (auto_discovery == DEFINE_TEMP_SENSORS) { -// UARTPrintf("auto_discovery == DEFINE_TEMP_SENSORS\r\n"); define_temp_sensors(); } @@ -2094,6 +1960,7 @@ void mqtt_startup(void) if (mqtt_start_ctr1 > 4) { // Wait 200ms before queuing Publish message // Publish the availability "online" message + // This message is always published with QOS 0 strcpy(topic_base, devicetype); strcat(topic_base, stored_devicename); strcat(topic_base, "/availability"); @@ -2124,24 +1991,6 @@ void mqtt_startup(void) } -/* -void mqtt_redefine_temp_sensors(void) -{ - if (mqtt_start_ctr1 > 2) { - auto_discovery = DEFINE_TEMP_SENSORS; - if (auto_discovery_step == STEP_NULL) { - auto_discovery_step = SEND_TEMP_SENSOR_DELETE; - } - define_temp_sensors(); - mqtt_start_ctr1 = 0; // Clear the 50ms counter - if (auto_discovery == AUTO_COMPLETE) { - auto_discovery_step = STEP_NULL; - redefine_temp_sensors = 0; - } - } -} -*/ - void mqtt_redefine_temp_sensors(void) { // This routine can be called during runtime (ie, AFTER initialization) to @@ -2164,89 +2013,6 @@ void mqtt_redefine_temp_sensors(void) } -/* -void define_temp_sensors(void) -{ - // This function is called from two places: - // The mqtt_startup function - // The main loop when redefine_temp_sensors == 1 - // - // This function is called from the mqtt_startup function when - // auto_discovery == DEFINE_TEMP_SENSORS - // This function is part of the state machine contained within the - // mqtt_startup and will manipulate the following state machine controls: - // auto_discovery_step == SEND_TEMP_SENSOR_DELETE - // auto_discovery_step = SEND_TEMP_SENSOR_DELETE2 - // auto_discovery_step = SEND_TEMP_SENSOR_DEFINE - // When complete this function will set - // auto_discovery = AUTO_COMPLETE - // - // This function also is called from the main loop when - // redefine_temp_sensors == 1 - // - // It should not be possible for the mqtt_startup function and the main - // loop to be calling this function at the same time. - - // Pin 16 will be disabled already if it is being used for temperature - // sensors. - // This part of the state machine will always send a delete temperature - // sensor message for every entry in the temp_FoundROM and FoundROM tables - // to make sure all sensors are deleted. - // Then, if temp sensors are enabled, it will send a define msg for every - // sensor appearing in the FoundROM table. Note that this may cause - // duplicate "delete" messages to be generated, and/or messages to delete - // sensor "000000000000" which is the "empty" value in the tables. - - if (auto_discovery_step == SEND_TEMP_SENSOR_DELETE) { - // Create temperature sensor delete msg for every entry in the - // FoundROM table - send_IOT_msg(sensor_number, TMPRMSG, DELETE_IOT, 0); - if (sensor_number == 4) { - sensor_number = 0; - auto_discovery_step = SEND_TEMP_SENSOR_DELETE2; - } - else sensor_number++; - } - - else if (auto_discovery_step == SEND_TEMP_SENSOR_DELETE2) { - // Create temperature sensor delete msg for every entry in the - // temp_FoundROM table - send_IOT_msg(sensor_number, TMPRMSG, DELETE_IOT, 1); - - if (sensor_number == 4) { - sensor_number = 0; - auto_discovery_step = SEND_TEMP_SENSOR_DEFINE; - } - else sensor_number++; - } - - else if (auto_discovery_step == SEND_TEMP_SENSOR_DEFINE) { - // Create temperature sensor define msg. - // If temp sensors are not enabled we will not create a Config - // message. - // If no sensors were detected numROMs will be -1 and we will not - // create a Config message). - // If there is at least one sensor detetected numROMs will be zero or - // greater. In that case send the sensor definition as a Config message. - - if ((stored_config_settings & 0x08) && (sensor_number <= (numROMs))) { - // If the test is true Temperature Sensors are enabled and a - // sensor is defined. - // Send Temp Sensor define messages. - send_IOT_msg(sensor_number, TMPRMSG, DEFINE_IOT, 0); - } - - if (sensor_number == 4) { - auto_discovery = AUTO_COMPLETE; - } - else sensor_number++; - } - else { - auto_discovery = AUTO_COMPLETE; - } -} -*/ - void define_temp_sensors(void) { // This function is called from two places: @@ -2272,142 +2038,36 @@ void define_temp_sensors(void) // send_IOT_msg() routine which is called from this routine will abort // sending a msg if the Temperature Sensor ID is 000000000000 (which // indicates no sensor is present at that numROMs pointer). - - // Create temperature sensor define msg. - // If temp sensors are not enabled we will not create a Config message. - // If no sensors were detected numROMs will be -1 and we will not create - // a Config message). - // If there is at least one sensor detetected numROMs will be zero or - // greater. In that case send the sensor definition as a Config message. - - -// UARTPrintf("Checking if sensor number "); -// emb_itoa(sensor_number, OctetArray, 10, 1); -// UARTPrintf(OctetArray); -// UARTPrintf(" needs IOT_msg"); -// UARTPrintf("\r\n"); - - - if ((stored_config_settings & 0x08) && (sensor_number <= (numROMs))) { - // If the test is true Temperature Sensors are enabled and a sensor is - // defined. - // Send Temp Sensor define messages. - -// UARTPrintf("Sending IOT_msg for sensor number "); -// emb_itoa(sensor_number, OctetArray, 10, 1); -// UARTPrintf(OctetArray); -// UARTPrintf("\r\n"); - - send_IOT_msg(sensor_number, TMPRMSG, DEFINE_IOT); - } - - if (sensor_number == 4) { - auto_discovery = AUTO_COMPLETE; - } - else sensor_number++; -} - - -/* -void send_IOT_msg(uint8_t IOT_ptr, uint8_t IOT, uint8_t DefOrDel, uint8_t delete_flag) -{ - // Format and send IO delete/define messages and sensor delete/define - // messages. - //---------------------------------------------------------------------// - // For IOT == INPUTMSG or OUTPUTMSG the IOT_ptr indicates the pin number - // (1 to 16) that is being messaged. - // For IOT == TMPRMSG the IOT_PTR indicates the sensor number (0 to 4) that - // is being messaged. - //---------------------------------------------------------------------// - unsigned char app_message[16]; // Stores the application message (the - // payload) that will be sent in an MQTT - // message. - // For Input or Output IO messages - // app_message[2] to [5] contains the pin - // number allowing app_message to be used - // in creating the topic part of the - // message - // For Temperature Sensor messages - // app_message[2] to [14] contains the - // sensor number allowing app_message to be - // used in creating the topic part of the - // message. - - // Create the % marker in the payload template - app_message[0] = '%'; - - // Create first part of topic and identification part of app_message - strcpy(topic_base, "homeassistant/"); - if (IOT == INPUTMSG) { - strcat(topic_base, "binary_sensor/"); - app_message[1] = 'I'; - } - if (IOT == OUTPUTMSG) { - strcat(topic_base, "switch/"); - app_message[1] = 'O'; - } - if (IOT == TMPRMSG) { - strcat(topic_base, "sensor/"); - app_message[1] = 'T'; - } - - if ((IOT == INPUTMSG) || (IOT == OUTPUTMSG)) { - // Create the pin number for the app_message and topic. - emb_itoa(IOT_ptr, OctetArray, 10, 2); - // Add pin number to payload template - app_message[2] = OctetArray[0]; - app_message[3] = OctetArray[1]; - app_message[4] = '\0'; - } - - if (IOT == TMPRMSG) { - // Create the sensor number for the app_message and topic. - // Add first part of sensor ID to payload template. - { - int i; - int j; - j = 2; - for (i=6; i>0; i--) { - if (flag == 0) int2hex(FoundROM[IOT_ptr][i]); - if (flag == 1) int2hex(temp_FoundROM[IOT_ptr][i]); - app_message[j++] = OctetArray[0]; - app_message[j++] = OctetArray[1]; - } - app_message[14] = '\0'; - } - } + + // Create temperature sensor define msg. + // If temp sensors are not enabled we will not create a Config message. + // If no sensors were detected numROMs will be -1 and we will not create + // a Config message). + // If there is at least one sensor detetected numROMs will be zero or + // greater. In that case send the sensor definition as a Config message. - // Create the rest of the topic - strcat(topic_base, mac_string); - strcat(topic_base, "/"); - strcat(topic_base, &app_message[2]); - strcat(topic_base, "/config"); + if ((stored_config_settings & 0x08) && (sensor_number <= (numROMs))) { + // If the test is true Temperature Sensors are enabled and a sensor is + // defined. + // Send Temp Sensor define messages. + send_IOT_msg(sensor_number, TMPRMSG, DEFINE_IOT); + } - // If deleting the pin or sensor replace the app_message with NULL - if (DefOrDel == DELETE_IOT) app_message[0] = '\0'; - - // Send the message - // Note: This message will be intercepted in the mqtt_pal.c - // mqtt_pal_sendall() routine and additional payload content will - // be added. - mqtt_publish(&mqttclient, - topic_base, - app_message, - strlen(app_message), - MQTT_PUBLISH_QOS_0 | MQTT_PUBLISH_RETAIN); + if (sensor_number == 4) { + auto_discovery = AUTO_COMPLETE; + } + else sensor_number++; } -*/ + void send_IOT_msg(uint8_t IOT_ptr, uint8_t IOT, uint8_t DefOrDel) { // Format and send IO delete/define messages and sensor delete/define // messages. - //---------------------------------------------------------------------// // For IOT == INPUTMSG or OUTPUTMSG the IOT_ptr indicates the pin number // (1 to 16) that is being messaged. // For IOT == TMPRMSG the IOT_PTR indicates the sensor number (0 to 4) that // is being messaged. - //---------------------------------------------------------------------// unsigned char app_message[16]; // Stores the application message (the // payload) that will be sent in an MQTT // message. @@ -2452,9 +2112,6 @@ void send_IOT_msg(uint8_t IOT_ptr, uint8_t IOT, uint8_t DefOrDel) if (IOT == TMPRMSG) { // Create the sensor number for the app_message and topic. // Add first part of sensor ID to payload template. - -// UARTPrintf("Called IOT == TMPRMSG\r\n"); - { int i; int j; @@ -2466,11 +2123,6 @@ void send_IOT_msg(uint8_t IOT_ptr, uint8_t IOT, uint8_t DefOrDel) } app_message[14] = '\0'; } - -// UARTPrintf("Created Temp Sensor Config msg for "); -// UARTPrintf(app_message); -// UARTPrintf("\r\n"); - } // Create the rest of the topic @@ -2487,6 +2139,7 @@ void send_IOT_msg(uint8_t IOT_ptr, uint8_t IOT, uint8_t DefOrDel) // Note: This message will be intercepted in the mqtt_pal.c // mqtt_pal_sendall() routine and additional payload content will // be added. + // This message is always published with QOS 0 mqtt_publish(&mqttclient, topic_base, app_message, @@ -2495,7 +2148,8 @@ void send_IOT_msg(uint8_t IOT_ptr, uint8_t IOT, uint8_t DefOrDel) } -void mqtt_sanity_check(void) +// void mqtt_sanity_check(void) +void mqtt_sanity_check(struct mqtt_client *client) { // This is similar to a firmware restart except it is focused on restarting // only the MQTT components. The process is triggered every XX seconds IF @@ -2517,10 +2171,15 @@ void mqtt_sanity_check(void) // Note that the Broker ping timeout may be shorter than this response // timeout. If the Broker times out first it will disconnect from this // device. That should not cause a problem. - if (mqttclient.number_of_timeouts > 1) { + if (client->number_of_timeouts > 1) { // Reset the timeout counter - mqttclient.number_of_timeouts = 0; + client->number_of_timeouts = 0; MQTT_resp_tout_counter++; + +#if DEBUG_SUPPORT != 11 +UARTPrintf("mqtt_sanity_check Response Timeout\r\n"); +#endif // DEBUG_SUPPORT != 11 + mqtt_restart_step = MQTT_RESTART_BEGIN; } @@ -2532,6 +2191,11 @@ void mqtt_sanity_check(void) if (mqtt_start == MQTT_START_COMPLETE && mqtt_conn->tcpstateflags == UIP_CLOSED) { MQTT_broker_dis_counter++; + +#if DEBUG_SUPPORT != 11 +UARTPrintf("mqtt_sanity_check Broker Disconnect\r\n"); +#endif // DEBUG_SUPPORT != 11 + mqtt_restart_step = MQTT_RESTART_BEGIN; } @@ -2539,8 +2203,16 @@ void mqtt_sanity_check(void) // != MQTT_OK needs to be qualified with MQTT_START_COMPLETE because a // not OK condition can be present prior to mqtt_connect() running. if (mqtt_start == MQTT_START_COMPLETE - && mqttclient.error != MQTT_OK) { + && client->error != MQTT_OK) { MQTT_not_OK_counter++; + +#if DEBUG_SUPPORT != 11 +UARTPrintf("mqtt_sanity_check MQTT_not_OK - Error code:"); +emb_itoa(client->error, OctetArray, 16, 4); +UARTPrintf(OctetArray); +UARTPrintf("\r\n"); +#endif // DEBUG_SUPPORT != 11 + mqtt_restart_step = MQTT_RESTART_BEGIN; } break; @@ -2708,6 +2380,7 @@ void mqtt_sanity_check(void) //---------------------------------------------------------------------------// +#if QOS_SUPPORT == 0 void publish_callback(void** unused, struct mqtt_response_publish *published) { char* pBuffer; @@ -2718,14 +2391,14 @@ void publish_callback(void** unused, struct mqtt_response_publish *published) pin_value = 0; ParseNum = 0; - // This function will be called if a "publish" is received from the Broker. - // The publish message will contain a payload that, in this application, + // This function will be called if a PUBLISH is received from the Broker. + // The PUBLISH message will contain a payload that, in this application, // will be the output control bits. // // This function is called from within the mqtt_recv() function. The data // left in the uip_buf will remain there until this function completes. // - // Dissecting the Publish message: + // Dissecting the PUBLISH message: // - We know that the MQTT Headers + Payload starts at pointer uip_appdata // - We know that the Fixed Header is 2 bytes // - Next comes the Variable Header @@ -2852,6 +2525,202 @@ void publish_callback(void** unused, struct mqtt_response_publish *published) // Note: if none of the above matched the parsing we just exit without // executing any functionality (the message is effectively ignored). } +#endif // QOS_SUPPORT == 0 + + +#if QOS_SUPPORT == 1 +void publish_callback(void** unused, struct mqtt_response_publish *published) +{ + char* pBuffer; + uint8_t pin_value; + uint8_t ParseNum; + int i; + uint16_t j; + uint8_t qos; + + pin_value = 0; + ParseNum = 0; + qos = 0; + + // This function will be called if a "Publish" is received from the Broker. + // The publish message will contain a payload that, in this application, + // will be the output control bits. + // + // Since the Subscribe messages were all QOS1 then all Publish messages from + // the Broker should be QOS1. + // + // This function is called from within the mqtt_recv() function. The data + // left in the uip_buf will remain there until this function completes. + // + // Dissecting the Publish message: + // - We know that the MQTT Headers + Payload starts at pointer uip_appdata + // - We know that the Fixed Header is 2 bytes + // - Next comes the Variable Header topic name. It is one of the following: + // - First bytes contain the Topic Name. So we should expect: + // - "NetworkModule/" + // - "Devicename/" + // - "output/" + // - "xx/" (output number or 'all') + // - "set" + // OR + // - "NetworkModule/" + // - "Devicename/" + // - "state-req" + // - Next comes the Variable Header Packet ID (since we are QOS1) + // - This is 2 bytes + // - Next comes the Payload + // - If "Output/xx/set" we expect a payload of "ON" or "OFF" + // - if "Output/all/set" we expect a payload of "ON" or "OFF" + // - If "state-req" we expect no payload + // + // Once we collect the above information: + // - Set or clear an individual pin + // OR + // - Loop to set or clear "all" pins + // OR + // - Set the state_request variable + + // Set the pBuffer pointer to the start of the MQTT packet + pBuffer = uip_appdata; + // Extract the QOS value from the Fixed Header Control Byte + qos = (uint8_t)(*pBuffer & 0x02); + // Skip the Fixed Header Control Byte (1 byte) + // Skip the Fixed Header Remaining Length Byte (1 byte) + // Skip the Topic name length bytes (2 bytes) + // Skip the NetworkModule/ text (14 bytes) + pBuffer += 18; + // Skip the Devicename/ text + pBuffer += strlen(stored_devicename) + 1; + + // Determine if the sub-topic is "output" or "state-req" + if (*pBuffer == 'o') { + // "output" detected + // Format can be any of these: + // output/01/setIDON + // output/01/setIDOFF + // output/all/setIDON + // output/all/setIDOFF + // In the above "ID" are the two bytes of the Packet ID which precedes the + // payload + // In the above "ON" or "OFF" are in the payload. + + // Skip past the "output/" characters + pBuffer+= 7; + + // Check if output field is "all". If so, update all output + // pin_control bytes to ON or OFF + if (*pBuffer == 'a') { + // Skip past the "all/setIDO" part of the message. + // Note that an "all" message is always sent with QOS == 0. + pBuffer+=8; + // Determine if payload is ON or OFF + if (*pBuffer == 'N') { + // Turn all outputs ON + for (i=0; i<16; i++) { + if (pin_control[i] & 0x02) { // Output pin? + Pending_pin_control[i] = (uint8_t)(pin_control[i] | 0x80); + } + } + } + else { + // Turn all outputs OFF + for (i=0; i<16; i++) { + if (pin_control[i] & 0x02) { // Output pin? + Pending_pin_control[i] = (uint8_t)(pin_control[i] & ~0x80); + } + } + } + } + + else if (*pBuffer == '0' || *pBuffer == '1') { + // Output field is a digit + // Note that Output messages can be received with QOS == 0 or QOS == 1. + // Collect the IO number + // Parse ten's digit + ParseNum = (uint8_t)((*pBuffer - '0') * 10); + pBuffer++; + // Parse one's digit + ParseNum += (uint8_t)(*pBuffer - '0'); + // Verify ParseNum is in the correct range + if (ParseNum > 0 && ParseNum < 17) { + // Adjust Parsenum to match 0 to 15 numbering (instead of 1 to 16) + ParseNum--; + // Skip past the "1/setIDO" part of the message. If QOS == 0 there is + // no Packet Identifier. Else there IS a 2 byte Packet Identifier that + // also needs to be skipped. + if (qos == 0) pBuffer+=6; + else { + pBuffer+=8; + } + // Determine if payload is ON or OFF + if (*pBuffer == 'N') { + // Turn output ON (and make sure it is an output) + if (pin_control[ParseNum] & 0x02 == 0x02) // Output pin? + Pending_pin_control[ParseNum] |= (uint8_t)0x80; + +#if DEBUG_SUPPORT != 11 +UARTPrintf("publish_callback - Output "); +i = ParseNum + 1; +emb_itoa(i, OctetArray, 10, 2); +UARTPrintf(OctetArray); +UARTPrintf(" ON\r\n"); +#endif // DEBUG_SUPPORT != 11 + + } + if (*pBuffer == 'F') { + // Turn output OFF (and make sure it is an output) + if (pin_control[ParseNum] & 0x02 == 0x02) // Output pin? + Pending_pin_control[ParseNum] &= (uint8_t)~0x80; + +#if DEBUG_SUPPORT != 11 +UARTPrintf("publish_callback - Output "); +i = ParseNum + 1; +emb_itoa(i, OctetArray, 10, 2); +UARTPrintf(OctetArray); +UARTPrintf(" OFF\r\n"); +#endif // DEBUG_SUPPORT != 11 + + } + // Set the appropriate bit in MQTT_transmit to force a + // publish_pinstate for this pin. + j = 1; + j = (j << ParseNum); + MQTT_transmit = (MQTT_transmit | j); + } + } + // The above code effectively did for MQTT what the POST parsing does for + // HTML (changed the pin_control byte). So we need to set the + // mqtt_parse_complete value so that the check_runtime_changes() function + // will perform the necessary IO actions. + mqtt_parse_complete = 1; + } + + // Determine if the sub-topic is "state-req". + // This Topic should always be received at QOS 0. + else if (*pBuffer == 's') { + // "state-req" detected + // Format is: + // state-req + pBuffer += 8; + if (*pBuffer == 'q') { + *pBuffer = '0'; // Destroy 'q' in buffer so subsequent "state" + // messages won't be misinterpreted + // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + // WARNING: To save flash space I don't check every + // sub-topic character. But I also don't clear the + // uip_buf. So, I could pick up on stuff left by a + // prevous message if not careful. In this limited + // application I can get away with it, but this can + // trip me up in the future if more messages are + // added. + // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + state_request = STATE_REQUEST_RCVD; + } + } + // Note: if none of the above matched the parsing we just exit without + // executing any functionality (the message is effectively ignored). +} +#endif // QOS_SUPPORT == 1 void publish_outbound(void) @@ -2882,13 +2751,31 @@ void publish_outbound(void) // Note that if the high order bits were to keep changing very quickly the // code might not get to the low order bits as often. This is a flaw but // may not matter much in this application. The code only checks and sends - // a message at the periodic_timer_expired(), thus it takes 16 expirations - // to get all bits sent, and frequent changes in higher order bits will - // supersede the processing of lower order bits. + // a message at the periodic_timer_expired(), thus it takes at least 16 + // expirations to get all bits sent, and frequent changes in higher order + // bits will supersede the processing of lower order bits. uint16_t xor_tmp; int i; uint16_t j; + int signal_break; + + signal_break = 0; + + // Check the mqtt_sendbuf to make sure it is emptied before PUBLISHing a + // pin_state message. This is to prevent overflow of the mqtt_sendbuf when + // Home Assistant pushes a large number of PUBLISH request messages, each + // of which requires a PUBACK to be processed through the mqtt_sendbuf. Due + // to timing that PUBACK Response might occupy the MQTT_sendbug along with + // another PUBACK as well as a Ping Response. + // This check effectively acts aa a throttle on the publish_outbound + // process. + { +// uint16_t mqtt_sendbuf_remaining; +// mqtt_sendbuf_remaining = mqtt_check_sendbuf(&mqttclient); +// if (!(mqtt_sendbuf_remaining > (MQTT_SENDBUF_SIZE - 15))) return; + if (!(mqtt_check_sendbuf(&mqttclient) > (MQTT_SENDBUF_SIZE - 15))) return; + } if (state_request == STATE_REQUEST_IDLE) { // XOR the current ON_OFF_word with the ON_OFF_word_sent (_sent being the @@ -2900,7 +2787,7 @@ void publish_outbound(void) j = 0x8000; while ( 1 ) { - // Check if DS18B20 is enabled, and if yes check if a temperature + // Check if DS18B20 is enabled, and if yes check if a Temperature // Publish needs to occur. if (stored_config_settings & 0x08) { // DS18B20 enabled? if (j == 0x8000) { // Servicing IO 16? @@ -2912,45 +2799,51 @@ void publish_outbound(void) } } -#if DEBUG_SUPPORT == 7 || DEBUG_SUPPORT == 15 - // If UART is enabled we need to skip IO 11 to prevent UART signal - // switching from generating MQTT ON/OFF messages. - if (j == 0x0400) { // Servicing IO 11? - j = j >> 1; - i--; - } -#endif // DEBUG_SUPPORT - - // Scan xor_temp for IOs that have changed. - if (xor_tmp & j) { - // Note that any pin reassigned to a DS18B20 can be scanned - // without harm - its pin_control ON/OFF will never change. - // - // If a pin is Enabled (either Input or Output) and its ON/OFF - // state changed a Publish needs to occur. + // Perform a publish_pinstate for each pin that has changed OR if an + // MQTT PUBLISH attempts to change a pin state. + // xor_temp is used to detect pin changes generated by the IOControl + // GUI. + // MQTT_transmit is used to detect pin changes requested via a received + // MQTT PUBLISH command. + // Further explanation: Originally I was simply using the xor_temp + // method for changes pushed by the IOControl GUI >and< for changes + // pushed by receipt of a MQTT PUBLISH State Change. However, it's been + // found that sometimes a Client (like Home Assistant) can get out of + // sync with the actual state of a pin, so it is safer to always + // generate a pin state PUBLISH Response even if the MQTT Client + // requests that a pin be changed to a state that it is already in, for + // instance if the Client PUBLISH State Change says to turn a pin OFF + // when it is already OFF. That is a case where the Client is out of + // sync, so the Network Module will generate a PUBLISH Response to get + // the Client back into sync. + if ((xor_tmp & j) || (MQTT_transmit & j)) { + // A publish_pinstate needs to occur if: + // A pin is Enabled (either Input or Output) and its ON/OFF state + // changed as indicated by xor_temp + // OR + // A MQTT PUBLISH was received for a pin as indicated by the + // MQTT_transmit word. if (pin_control[i] & 0x01) { // enabled + // Send a PUBLISH Response continaing the pin state if (pin_control[i] & 0x02) publish_pinstate('O', (uint8_t)(i+1), ON_OFF_word, j); else publish_pinstate('I', (uint8_t)(i+1), ON_OFF_word, j); - // Update the "sent" pin state information so that the bit - // in ON_OFF_word_sent matches the bit in ON_OFF_word for the - // pin just transmitted. This will indicate it was already sent. - if (ON_OFF_word & j) ON_OFF_word_sent |= j; - else ON_OFF_word_sent &= (uint16_t)~j; // Break out of the while loop, as we can only send one Publish // message per pass. - break; + signal_break = 1; } + // else Pin is not enabled so no Publish was required. - else { - // Pin is not enabled so no Publish was required. - // Update the "sent" pin state information so that the bit in - // ON_OFF_word_sent matches the bit in ON_OFF_word for the pin - // just examined. This will inidcate it was already processed - // and will prevent hitting on the pin again. - if (ON_OFF_word & j) ON_OFF_word_sent |= j; - else ON_OFF_word_sent &= (uint16_t)~j; - } + // Update the "sent" pin state information so that the bit in + // ON_OFF_word_sent matches the bit in ON_OFF_word for the pin + // just examined. This will inidcate it was processed. + if (ON_OFF_word & j) ON_OFF_word_sent |= j; + else ON_OFF_word_sent &= (uint16_t)~j; + // Clear the bit in the MQTT_transmit word to indicate that the + // transmit was satisfied. + MQTT_transmit &= ~j; + // Break out of the while() loop only if a PUBLISH Response was sent. + if (signal_break == 1) break; } // If no Publish was sent check the next one. Note: If any Publish @@ -3016,13 +2909,24 @@ void publish_pinstate(uint8_t direction, uint8_t pin, uint16_t value, uint16_t m strcpy(app_message, "OFF"); size = 3; } - + + +#if DEBUG_SUPPORT != 11 +UARTPrintf("publish pinstate "); +UARTPrintf(topic_base); +UARTPrintf(" "); +UARTPrintf(app_message); +UARTPrintf("\r\n"); +#endif // DEBUG_SUPPORT != 11 + + // Queue publish message + // This message is always published with QOS 0 mqtt_publish(&mqttclient, topic_base, app_message, size, - MQTT_PUBLISH_QOS_0 | MQTT_PUBLISH_RETAIN); + MQTT_PUBLISH_QOS_0 | MQTT_PUBLISH_RETAIN); } @@ -3084,6 +2988,7 @@ void publish_pinstate_all(void) strcat(topic_base, "/state"); // Queue publish message + // This message is always published with QOS 0 mqtt_publish(&mqttclient, topic_base, app_message, @@ -3129,8 +3034,9 @@ void publish_temperature(uint8_t sensor) // Build the application message convert_temperature(sensor, 0); // Convert to degress C in OctetArray - + // Queue publish message + // This message is always published with QOS 0 mqtt_publish(&mqttclient, topic_base, OctetArray, // app_message @@ -3722,7 +3628,6 @@ void check_eeprom_settings(void) lock_flash(); // Initialize the Pending IO_TIMER variables -// for (i=0; i<16; i++) Pending_IO_TIMER[i] = IO_TIMER[i]; memcpy(&Pending_IO_TIMER[0], &IO_TIMER[0], 32); #endif // BUILD_SUPPORT == BROWSER_ONLY_BUILD @@ -3733,7 +3638,6 @@ void check_eeprom_settings(void) // Read the pin_control bytes from EEEPROM for (i=0; i<16; i++) pin_control[i] = stored_pin_control[i]; -// memcpy(&pin_control[0], &stored_pin_control[0], 16); // Check the "Retain/On/Off at Boot" settings and force the ON/OFF state // accordingly. Do this on Outputs only. @@ -3798,7 +3702,6 @@ void check_eeprom_settings(void) // bit so that the MQTT feature is enabled. This is needed even if no pins // are enabled so that the temperature sensor reporting will work. if (stored_config_settings & 0x04) mqtt_enabled = 1; - #endif // BUILD_SUPPORT == MQTT_BUILD } @@ -3830,53 +3733,42 @@ void check_runtime_changes(void) // Read the input registers and update the pin_control values as needed. // // Step 2: - // Check if the UART is enabled via a DEBUG_SUPPORT setting. If yes, - // supersede any settings on IO 11 and force it to an Output for use by the - // UART. - // - // Step 3: - // Check if the DS18B20 feature is enabled. If enabled over-ride the + // Check if the DS18B20 feature is enabled. If yes over-ride the // pin_control byte settings for IO 16 to force them to all zero. This // forces the disabled state so the DS18B20 code can utilize the pin for // temperature sensor communication. // + // Step 3: + // Check if I2C functionality is enabled. If yes over-ride the pin_control + // byte settings for pins 14 and 15 to force them to all zero. This forces + // the disabled state so that the I2C code can utilize the pin for I2C + // communication. + // // Step 4: + // Check if the UART is enabled. If yes over-ride the pin_control byte + // settings for IO 11 to force them to all zero. This forces the disabled + // state so the UART code can utilize the pin for UART communication. + // + // Step 5: // Manage Output pin Timers. Change Output pin states and Timers as // appropriate. // - // Step 5: + // Step 6: // Check if the user requested changes to Device Name, Output States, IP // Address, Gateway Address, Netmask, Port, or MAC. If a change occurred // update the appropriate variables and output controls, and store the new // values in EEPROM. uint8_t update_EEPROM; -// uint32_t temp_pin_timer; unlock_eeprom(); read_input_pins(); - -#if DEBUG_SUPPORT == 7 || DEBUG_SUPPORT == 15 - // If UART debug support is enabled the following code forces IO 11 to an - // output state and keeps it that way. The UART code will operate the pin - // for IO 11 as needed for UART transmit to a terminal. - pin_control[10] = Pending_pin_control[10] = (uint8_t)0x03; // force to output/enabled - // Update the stored_pin_control[] variables - if (stored_pin_control[10] != pin_control[10]) stored_pin_control[10] = pin_control[10]; - // For UART mode Port D Bit 5 needs to be set to Output / Push-Pull / - // 10MHz slope - PD_DDR |= 0x20; // Set Output mode - PD_CR1 |= 0x20; // Set Push-Pull - PD_CR2 |= 0x20; // Set 10MHz -#endif // DEBUG_SUPPORT - - // Check the DS18B20 Enable bit. If enabled over-ride the pin_control byte // bits for IO 16 to force them to all zero. This forces the disabled // state for IO 16 and makes sure all other bits are in a neutral condition - // should the DS18B20 be Disabled at some future time. + // should the DS18B20 function be Disabled at some future time. if (Pending_config_settings & 0x08) { pin_control[15] = Pending_pin_control[15] = (uint8_t)0x00; // Update the stored_pin_control[] variables @@ -3884,17 +3776,28 @@ void check_runtime_changes(void) } - #if I2C_SUPPORT == 1 - // Disable pins 14 and 15 so that they can be used by the I2C function - pin_control[13] = Pending_pin_control[13] = (uint8_t)0x00; - pin_control[14] = Pending_pin_control[14] = (uint8_t)0x00; - // Update the stored_pin_control[] variables - if (stored_pin_control[13] != pin_control[13]) stored_pin_control[13] = pin_control[13]; - if (stored_pin_control[14] != pin_control[14]) stored_pin_control[14] = pin_control[14]; + // If I2C functionality is enabled disable pins 14 and 15 so that they can + // be used by the I2C function. + // This check is run here in case the user tried to change the pin state + // from Disabled in the GUI. This will force the state back to Disabled. + pin_control[13] = Pending_pin_control[13] = (uint8_t)0x00; + pin_control[14] = Pending_pin_control[14] = (uint8_t)0x00; + // Update the stored_pin_control[] variables + if (stored_pin_control[13] != pin_control[13]) stored_pin_control[13] = pin_control[13]; + if (stored_pin_control[14] != pin_control[14]) stored_pin_control[14] = pin_control[14]; #endif // I2C_SUPPORT == 1 +#if DEBUG_SUPPORT == 7 || DEBUG_SUPPORT == 15 + // If UART functionality is enabled disable pin 11 so that it can be used + // for the UART transmit pin. + // This check is run here in case the user tried to change the pin state + // from Disabled in the GUI. This will force the state back to Disabled. + pin_control[10] = Pending_pin_control[10] = (uint8_t)0x00; + // Update the stored_pin_control[] variables + if (stored_pin_control[10] != pin_control[10]) stored_pin_control[10] = pin_control[10]; +#endif // DEBUG_SUPPORT #if BUILD_SUPPORT == BROWSER_ONLY_BUILD @@ -3953,7 +3856,6 @@ void check_runtime_changes(void) { int i; for (i=0; i<16; i++) { -// if (((pin_control[i] & 0x03) == 0x03) && ((pin_control[i] & 0x08) == 0)) { if ((pin_control[i] & 0x0b) == 0x03) { // The above: If an Enabled Output AND Retain is not set if (IO_TIMER[i] != Pending_IO_TIMER[i]) { @@ -3982,20 +3884,17 @@ void check_runtime_changes(void) { int i; for (i=0; i<16; i++) { -// if (((pin_control[i] & 0x03) == 0x03) && ((pin_control[i] & 0x08) == 0x00)) { if ((pin_control[i] & 0x0b) == 0x03) { // The above: If an Enabled Output AND Retain is not set if (((IO_TIMER[i] & 0x3fff) != 0) && (pin_timer[i] == 0)) { // The above: If pin has a non-zero TIMER value AND the timer // countdown is zero -// if (((pin_control[i] & 0x80) == 0x80) && ((pin_control[i] & 0x10) == 0x00)) { if ((pin_control[i] & 0x90) == 0x80) { // The above: If the pin is ON and the idle state is OFF // Turn the pin OFF Pending_pin_control[i] &= 0x7f; pin_control[i] &= 0x7f; } -// if (((pin_control[i] & 0x80) == 0x00) && ((pin_control[i] & 0x10) == 0x10)) { if ((pin_control[i] & 0x90) == 0x10) { // The above: If the pin is OFF and the idle state is ON // Turn the pin ON @@ -4041,7 +3940,6 @@ void check_runtime_changes(void) { int i; for (i=0; i<16; i++) { -// if (((pin_control[i] & 0x03) == 0x03) && ((pin_control[i] & 0x08) == 0x00)) { if ((pin_control[i] & 0x0b) == 0x03) { // The above: If an Enabled Output AND Retain is not set if ((IO_TIMER[i] & 0x3fff) != 0) { @@ -4068,15 +3966,6 @@ void check_runtime_changes(void) #endif BUILD_SUPPORT == BROWSER_ONLY_BUILD if (parse_complete || mqtt_parse_complete) { - -// UARTPrintf("parse_complete = "); -// emb_itoa(parse_complete, OctetArray, 10, 1); -// UARTPrintf(OctetArray); -// UARTPrintf(" mqtt_parse_complete = "); -// emb_itoa(mqtt_parse_complete, OctetArray, 10, 1); -// UARTPrintf(OctetArray); -// UARTPrintf("\r\n"); - // Check for changes from the user via the GUI, MQTT, or REST commands. // If parse_complete == 1 all TCP Fragments have been received during // HTML POST processing, OR a REST command was processed. @@ -4117,18 +4006,6 @@ void check_runtime_changes(void) { int i; for (i=0; i<16; i++) { - -// UARTPrintf("pin_control"); -// emb_itoa(i, OctetArray, 10, 2); -// UARTPrintf(OctetArray); -// UARTPrintf(" "); -// emb_itoa(pin_control[i], OctetArray, 2, 8); -// UARTPrintf(OctetArray); -// UARTPrintf(" Pending_pin_control "); -// emb_itoa(Pending_pin_control[i], OctetArray, 2, 8); -// UARTPrintf(OctetArray); -// UARTPrintf("\r\n"); - if (pin_control[i] != Pending_pin_control[i]) { // Something changed - sort it out @@ -4196,12 +4073,7 @@ void check_runtime_changes(void) pin_control[i] &= 0x80; pin_control[i] |= (uint8_t)(Pending_pin_control[i] & 0x7f); } - -// UARTPrintf("Updated pin_control "); -// emb_itoa(pin_control[i], OctetArray, 2, 8); -// UARTPrintf(OctetArray); -// UARTPrintf("\r\n"); - + if (update_EEPROM) { // Update the stored_pin_control[] variables if (stored_pin_control[i] != pin_control[i]) stored_pin_control[i] = pin_control[i]; @@ -4365,17 +4237,6 @@ void check_runtime_changes(void) user_reboot_request = 0; reboot_request = 1; } - -// UARTPrintf("Restart Request "); -// emb_itoa(restart_request, OctetArray, 10, 1); -// UARTPrintf(OctetArray); -// UARTPrintf("\r\n"); - -// UARTPrintf("Reboot Request "); -// emb_itoa(reboot_request, OctetArray, 10, 1); -// UARTPrintf(OctetArray); -// UARTPrintf("\r\n"); - } @@ -4465,6 +4326,7 @@ void check_restart_reboot(void) if (t100ms_ctr1 > 1) { // We can only get here if mqtt_enabled == 1 // Wait at least 100 ms before publishing availability message + // This message is always published with QOS 0 if (mqtt_start == MQTT_START_COMPLETE) { // Publish the availability "offline" message strcpy(topic_base, devicetype); @@ -4906,10 +4768,7 @@ void oneflash(void) void restore_eeprom_debug_bytes(void) { // Restore debug bytes from EEPROM to RAM -// int i; - #if DEBUG_SUPPORT != 0 -// for (i = 0; i < 10; i++) debug[i] = stored_debug[i]; memcpy(&debug[0], &stored_debug[0], 10); #endif // DEBUG_SUPPORT } diff --git a/NetworkModule/UART.c b/NetworkModule/UART.c index f25a38e..f8d7bcb 100644 --- a/NetworkModule/UART.c +++ b/NetworkModule/UART.c @@ -130,11 +130,10 @@ extern uint8_t Pending_pin_control[16]; void InitializeUART(void) { unsigned char tmp; - - // If UART debug support is enabled the following code forces IO 11 to - // an output state and keeps it that way. The UART code will operate - // the pin for IO 11 as needed for UART transmit to a terminal. - pin_control[10] = Pending_pin_control[10] = (uint8_t)0x03; // Set pin 11 to output/enabled + + // The following code forces IO 11 to a Disabled state so that the UART + // code can operate the IO 11 pin for UART transmit to a terminal. + pin_control[10] = Pending_pin_control[10] = (uint8_t)0x00; // Disable // Update the stored_pin_control[] variables unlock_eeprom(); if (stored_pin_control[10] != pin_control[10]) stored_pin_control[10] = pin_control[10]; @@ -146,7 +145,6 @@ void InitializeUART(void) PD_CR1 |= 0x20; // Set Push-Pull PD_CR2 |= 0x20; // Set 10MHz - // Clear the Idle Line Detected bit in the status register by a read to the // UART2_SR register followed by a Read to the UART2_DR register. tmp = UART2_SR; diff --git a/NetworkModule/httpd.c b/NetworkModule/httpd.c index 2ca6e1e..ebcdb4f 100644 --- a/NetworkModule/httpd.c +++ b/NetworkModule/httpd.c @@ -3223,6 +3223,7 @@ static uint16_t CopyHttpData(uint8_t* pBuffer, #if DEBUG_SUPPORT == 11 || DEBUG_SUPPORT == 15 else if ((nParsedMode == 'e') && (nParsedNum >= 30) && (nParsedNum < 40)) { + // This displays the Link Error Statistics if (nParsedNum == 31) { emb_itoa(second_counter, OctetArray, 10, 10); pBuffer = stpcpy(pBuffer, OctetArray); diff --git a/NetworkModule/main.h b/NetworkModule/main.h index f55ee4b..9bb1617 100644 --- a/NetworkModule/main.h +++ b/NetworkModule/main.h @@ -190,7 +190,8 @@ void mqtt_redefine_temp_sensors(void); void define_temp_sensors(void); // void send_IOT_msg(uint8_t IOT_ptr, uint8_t IOT, uint8_t DefOrDel, uint8_t delete_flag); void send_IOT_msg(uint8_t IOT_ptr, uint8_t IOT, uint8_t DefOrDel); -void mqtt_sanity_check(void); +// void mqtt_sanity_check(void); +void mqtt_sanity_check(struct mqtt_client *client); void publish_callback(void** unused, struct mqtt_response_publish *published); void publish_outbound(void); void publish_pinstate(uint8_t direction, uint8_t pin, uint16_t value, uint16_t mask); diff --git a/NetworkModule/mqtt.c b/NetworkModule/mqtt.c index 7fa1838..46386a4 100644 --- a/NetworkModule/mqtt.c +++ b/NetworkModule/mqtt.c @@ -55,16 +55,16 @@ extern uint32_t second_counter; extern uint16_t uip_slen; extern uint8_t MQTT_error_status; // Global so GUI can show error status // indicator -uint8_t connack_received; // Used to communicate CONNECT CONNACK received - // from mqtt.c to main.c -uint8_t suback_received; // Used to communicate SUBSCRIBE SUBACK received - // from mqtt.c to main.c +uint8_t connack_received; // Used to communicate CONNECT CONNACK + // received from mqtt.c to main.c +uint8_t suback_received; // Used to communicate SUBSCRIBE SUBACK + // received from mqtt.c to main.c -uint8_t mqtt_sendbuf[140]; // Buffer to contain MQTT transmit queue - // and data. -extern uint8_t mqtt_start; // Tracks the MQTT startup steps +uint8_t mqtt_sendbuf[MQTT_SENDBUF_SIZE]; // Buffer to contain MQTT transmit + // queue and data. +extern uint8_t mqtt_start; // Tracks the MQTT startup steps -extern uint8_t OctetArray[11]; // Used in UART debug sessions +extern uint8_t OctetArray[11]; // Used in UART debug sessions @@ -102,6 +102,19 @@ int16_t mqtt_sync(struct mqtt_client *client) } +uint16_t mqtt_check_sendbuf(struct mqtt_client *client) +{ + // This function cleans the mqtt_sendbuf (if needed) then reports the + // remaining size of the mqtt_sendbuf (the free space remaining in the + // buffer). + uint16_t rv; + if (!(client->mq.curr_sz > (MQTT_SENDBUF_SIZE - 15))) mqtt_mq_clean(&client->mq); + rv = client->mq.curr_sz; + return rv; +} + + + uint16_t __mqtt_next_pid(struct mqtt_client *client) { // This function generates a psudo random packet id (pid) @@ -136,6 +149,14 @@ int16_t mqtt_init(struct mqtt_client *client, uint8_t *recvbuf, uint16_t recvbufsz, void (*publish_response_callback)(void** state,struct mqtt_response_publish *publish)) { + +#if DEBUG_SUPPORT != 11 +UARTPrintf("__mqtt_init sendbuf size = "); +emb_itoa(sendbufsz, OctetArray, 10, 3); +UARTPrintf(OctetArray); +UARTPrintf("\r\n"); +#endif // DEBUG_SUPPORT != 11 + if (client == NULL || sendbuf == NULL || recvbuf == NULL) { return MQTT_ERROR_NULLPTR; } @@ -207,6 +228,15 @@ int16_t mqtt_connect(struct mqtt_client *client, client->error = MQTT_OK; } +// UARTPrintf("__mqtt_connect sendbuf rem = "); +// emb_itoa(client->mq.curr_sz, OctetArray, 10, 3); +// UARTPrintf(OctetArray); +// mqtt_mq_clean(&client->mq); +// UARTPrintf(" after clean = "); +// emb_itoa(client->mq.curr_sz, OctetArray, 10, 3); +// UARTPrintf(OctetArray); +// UARTPrintf("\r\n"); + // try to pack the message MQTT_CLIENT_TRY_PACK(rv, msg, client, mqtt_pack_connection_request( @@ -247,6 +277,16 @@ int16_t mqtt_publish(struct mqtt_client *client, // UARTPrintf(OctetArray); // UARTPrintf("\r\n"); +// UARTPrintf("__mqtt_publish sendbuf rem = "); +// emb_itoa(client->mq.curr_sz, OctetArray, 10, 3); +// UARTPrintf(OctetArray); +// mqtt_mq_clean(&client->mq); +// UARTPrintf(" after clean = "); +// emb_itoa(client->mq.curr_sz, OctetArray, 10, 3); +// UARTPrintf(OctetArray); +// UARTPrintf("\r\n"); + + // try to pack the message MQTT_CLIENT_TRY_PACK( rv, msg, client, @@ -269,8 +309,35 @@ int16_t mqtt_publish(struct mqtt_client *client, } +#if QOS_SUPPORT == 1 +int16_t __mqtt_puback(struct mqtt_client *client, uint16_t packet_id) +{ + int16_t rv; + struct mqtt_queued_message *msg; + +// UARTPrintf("mqtt_puback Generating PUBACK\r\n"); + + // try to pack the message + MQTT_CLIENT_TRY_PACK( + rv, msg, client, + mqtt_pack_pubxxx_request( + client->mq.curr, client->mq.curr_sz, + MQTT_CONTROL_PUBACK, + packet_id + ), + 0 + ); + // save the control type and packet id of the message + msg->control_type = MQTT_CONTROL_PUBACK; + msg->packet_id = packet_id; + return MQTT_OK; +} +#endif // QOS_SUPPORT == 1 + + int16_t mqtt_subscribe(struct mqtt_client *client, - const char* topic_name) + const char* topic_name, + int max_qos_level) { int16_t rv; uint16_t packet_id; @@ -283,7 +350,8 @@ int16_t mqtt_subscribe(struct mqtt_client *client, mqtt_pack_subscribe_request( client->mq.curr, client->mq.curr_sz, packet_id, - topic_name + topic_name, + max_qos_level ), 1 ); @@ -345,6 +413,7 @@ int16_t mqtt_disconnect(struct mqtt_client *client) } +#if QOS_SUPPORT == 0 int16_t __mqtt_send(struct mqtt_client *client) { int16_t len; @@ -424,6 +493,8 @@ int16_t __mqtt_send(struct mqtt_client *client) // MQTT_CONTROL_PINGREQ -> awaiting // MQTT_CONTROL_PINGRESP -> n/a // MQTT_CONTROL_DISCONNECT -> complete + + switch (msg->control_type) { case MQTT_CONTROL_DISCONNECT: @@ -461,8 +532,177 @@ int16_t __mqtt_send(struct mqtt_client *client) return MQTT_OK; } +#endif // QOS_SUPPORT == 0 + + +#if QOS_SUPPORT == 1 +int16_t __mqtt_send(struct mqtt_client *client) +{ + uint8_t inspected; + int16_t len; + int16_t i = 0; + + if (client->error < 0 && client->error != MQTT_ERROR_SEND_BUFFER_IS_FULL) { + return client->error; + } + + // loop through all messages in the queue. mqtt_mq_length returns the + // number of messages in the message queue. + len = mqtt_mq_length(&client->mq); + +// if (len > 0) { +// UARTPrintf("__mqtt_send number of msgs in queue = "); +// emb_itoa(len, OctetArray, 10, 2); +// UARTPrintf(OctetArray); +// UARTPrintf("\r\n"); +// } + + +// Here's a problem ... I think. This next "for" loop will attempt to send all +// messages in the mqtt_sendbuf. The problem is that mqtt_pal_sendall is designed +// to place a single message in the uip_buf, then expects a return to the main.c +// main loop so that the message will be transferred from the uip_buf to the +// ENC28J60. So I think the loop below needs to break once a message is encountered +// and submitted to mqtt_pal_sendall. We should return later to send any additional +// messages. + + + + + for(; i < len; ++i) { + struct mqtt_queued_message *msg = mqtt_mq_get(&client->mq, i); + int16_t resend = 0; + if (msg->state == MQTT_QUEUED_UNSENT) { + // message has not been sent so lets send it + resend = 1; + } + else if (msg->state == MQTT_QUEUED_AWAITING_ACK) { + // check for timeout + if (second_counter > msg->time_sent + client->response_timeout) { + resend = 1; + client->number_of_timeouts += 1; + client->send_offset = 0; + } + } + + // goto next message if we don't need to send + if (!resend) continue; + + // we're sending the message + { + // Some notes about this part of the code. The original code was + // designed to send larger messages, thus mqtt_pal_sendall might + // return a tmp value that indicates there is more to send. In this + // application we use a technique in the mqtt_pal_sendall routine + // that can replace placeholders in the mqtt message that is to be + // sent, resulting in an mqtt message that is larger than the + // message template given to it to send. So the mqtt_pal_sendall + // routine was redesigned to cause it to send the entire message + // even if it required multiple packets. Thus the return value + // always equals the size of the original template ... indicating + // a complete send. + int16_t tmp = mqtt_pal_sendall(msg->start + client->send_offset, msg->size - client->send_offset); + // mqtt_pal_sendall returns a negative number if an error, or a positive + // number with the number of bytes sent + if (tmp < 0) { + client->error = tmp; + return tmp; + } + else { + client->send_offset += tmp; + if(client->send_offset < msg->size) { + // partial sent. Await additional calls + // A PARTIAL SHOULD NEVER OCCUR AS ALL MQTT MESSAGES ARE SHORT + // ENOUGH IN THIS APPLICATION THAT THEY WILL BE SENT IN ONE PASS. + // THIS CODE COULD BE SIMPLIFIED. + break; + } + else { + // Whole message has been sent - and by "sent" we mean copied + // to the uip_buf. + client->send_offset = 0; + } + } + } + + // update timeout watcher + client->time_of_last_send = second_counter; + msg->time_sent = client->time_of_last_send; + + // Determine the state to put the message in. + // Control Types: + // MQTT_CONTROL_CONNECT -> awaiting + // MQTT_CONTROL_CONNACK -> n/a + // MQTT_CONTROL_PUBLISH -> qos == 0 ? complete : awaiting + // MQTT_CONTROL_PUBACK -> complete + // MQTT_CONTROL_PUBREC -> awaiting (Only for qos 2) + // MQTT_CONTROL_PUBREL -> awaiting (Only for qos 2) + // MQTT_CONTROL_PUBCOMP -> complete (Only for qos 2) + // MQTT_CONTROL_SUBSCRIBE -> awaiting + // MQTT_CONTROL_SUBACK -> n/a + // MQTT_CONTROL_PINGREQ -> awaiting + // MQTT_CONTROL_PINGRESP -> n/a + // MQTT_CONTROL_DISCONNECT -> complete + + switch (msg->control_type) { + case MQTT_CONTROL_PUBACK: +#if DEBUG_SUPPORT != 11 +UARTPrintf("mqtt_puback Sent PUBACK\r\n"); +#endif // DEBUG_SUPPORT != 11 + msg->state = MQTT_QUEUED_COMPLETE; + break; + case MQTT_CONTROL_DISCONNECT: + msg->state = MQTT_QUEUED_COMPLETE; + break; + case MQTT_CONTROL_PUBLISH: + inspected = (uint8_t)((MQTT_PUBLISH_QOS_MASK & (msg->start[0])) >> 1); // determine qos + if (inspected == 0) { + msg->state = MQTT_QUEUED_COMPLETE; + } + else { + msg->state = MQTT_QUEUED_AWAITING_ACK; + // set DUP flag for subsequent sends [Spec MQTT-3.3.1-1] + msg->start[0] |= MQTT_PUBLISH_DUP; + } + // Above handles QOS 0 and 1. No handling for QOS 2. + // XXXXXXXXXXXXXXXXXXXX THE NM ONLY PUBLISHES WITH QOS0. THE ABOVE + // CAN BE SIMPLIFIED. XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + break; + case MQTT_CONTROL_CONNECT: + case MQTT_CONTROL_SUBSCRIBE: + case MQTT_CONTROL_PINGREQ: + msg->state = MQTT_QUEUED_AWAITING_ACK; + break; + default: + client->error = MQTT_ERROR_MALFORMED_REQUEST; + return MQTT_ERROR_MALFORMED_REQUEST; + } + // ADDING BREAK HERE. WE SENT ONE MESSAGE (ALL WE CAN SEND PER PASS) + break; + } + + // check for keep-alive + { + // At about 3/4 of the timeout period perform a ping. This calculation + // uses integer arithmetic so it is only an approximation. It is assumed + // that timeouts are not a small number (for instance, the timeout should + // be at least 15 seconds). + uint32_t keep_alive_timeout = client->time_of_last_send + (uint32_t)((client->keep_alive * 3) / 4); + if ((second_counter > keep_alive_timeout) && (mqtt_start == MQTT_START_COMPLETE)) { + int16_t rv = __mqtt_ping(client); + if (rv != MQTT_OK) { + client->error = rv; + return rv; + } + } + } + + return MQTT_OK; +} +#endif // QOS_SUPPORT == 1 +#if QOS_SUPPORT == 0 int16_t __mqtt_recv(struct mqtt_client *client) { struct mqtt_response response; @@ -546,12 +786,213 @@ int16_t __mqtt_recv(struct mqtt_client *client) break; } break; - + case MQTT_CONTROL_PUBLISH: // QOS0 only so Call Publish Callback client->publish_response_callback(&client->publish_response_callback_state, &response.decoded.publish); break; + + case MQTT_CONTROL_SUBACK: + // release associated SUBSCRIBE + msg = mqtt_mq_find(&client->mq, MQTT_CONTROL_SUBSCRIBE, &response.decoded.suback.packet_id); + suback_received = 1; // Communicate SUBACK received to main.c + if (msg == NULL) { + client->error = MQTT_ERROR_ACK_OF_UNKNOWN; + mqtt_recv_ret = MQTT_ERROR_ACK_OF_UNKNOWN; + break; + } + msg->state = MQTT_QUEUED_COMPLETE; + // check that subscription was successful (currently only one + // subscribe at a time) + if (response.decoded.suback.return_codes[0] == MQTT_SUBACK_FAILURE) { + client->error = MQTT_ERROR_SUBSCRIBE_FAILED; + mqtt_recv_ret = MQTT_ERROR_SUBSCRIBE_FAILED; + break; + } + break; + + case MQTT_CONTROL_PINGRESP: + // release associated PINGREQ + msg = mqtt_mq_find(&client->mq, MQTT_CONTROL_PINGREQ, NULL); + if (msg == NULL) { + client->error = MQTT_ERROR_ACK_OF_UNKNOWN; + mqtt_recv_ret = MQTT_ERROR_ACK_OF_UNKNOWN; + break; + } + msg->state = MQTT_QUEUED_COMPLETE; + break; + default: + client->error = MQTT_ERROR_MALFORMED_RESPONSE; + mqtt_recv_ret = MQTT_ERROR_MALFORMED_RESPONSE; + break; + } + + { + // Because we have the UIP code as the front end to MQTT there will + // never be more than one receive msg in the uip_buf, so the + // processing above will have "consumed" it. If a new receive message + // comes in on the ethernet while this code is operating it will be + // held in the enc28j60 hardware buffer until the application gets + // back around to receiving it. + // + // The original code was set up to let several messages get queued in + // the receive buffer, then those messages are read out. When a + // message is read the original code "cleans the buffer" by moving any + // remaining messages toward the beginning of the buffer, over-writing + // the messages consumed. Or at least that's what I think it's doing. + // + // Reset receive pointers to start of buffer. + client->recv_buffer.curr = client->recv_buffer.mem_start; + client->recv_buffer.curr_sz = client->recv_buffer.mem_size; + } + + // In case there was some error handling the (well formed) message, we end + // up here + return mqtt_recv_ret; +} +#endif // QOS_SUPPORT == 0 + + +#if QOS_SUPPORT == 1 +int16_t __mqtt_recv(struct mqtt_client *client) +{ + struct mqtt_response response; + int16_t mqtt_recv_ret = MQTT_OK; + int16_t rv, consumed; + struct mqtt_queued_message *msg = NULL; + + // Read the input buffer and check for errors + + // The original MQTT code used a mqtt_pal_recvall() function to move + // data from an OS host buffer into an MQTT dedicated receive buffer. + // In this application that process is not needed and we only need to + // check if there is any receive data in the uip_buf. To do this we + // only need to check if uip_len is > 0. If it is not we need to + // generate an error by setting rv = -1. + if (uip_len > 0) rv = uip_len; + else rv = -1; + + client->recv_buffer.curr += rv; + client->recv_buffer.curr_sz -= rv; + + // attempt to parse + consumed = mqtt_unpack_response(&response, client->recv_buffer.mem_start, client->recv_buffer.curr - client->recv_buffer.mem_start); + + if (consumed < 0) { + client->error = consumed; + return consumed; + } + + // response was unpacked successfully + + // The switch statement below manages how the client responds to messages + // from the broker. + + // Control Types (that we expect to receive from the broker): + // MQTT_CONTROL_CONNACK: + // -> release associated CONNECT + // -> handle response + // MQTT_CONTROL_PUBLISH: + // -> stage response, none if qos==0, PUBACK if qos==1, PUBREC if qos==2 + // -> call publish callback + // MQTT_CONTROL_PUBACK: (not implemented as we always PUBLISH with qos==0 thus + // never receive a PUBACK) + // -> release associated PUBLISH + // MQTT_CONTROL_PUBREC: (Only for qos 2) + // -> release PUBLISH + // -> stage PUBREL + // MQTT_CONTROL_PUBREL: (Only for qos 2) + // -> release associated PUBREC + // -> stage PUBCOMP + // MQTT_CONTROL_PUBCOMP: (Only for qos 2) + // -> release PUBREL + // MQTT_CONTROL_SUBACK: + // -> release SUBSCRIBE + // -> handle response + // MQTT_CONTROL_UNSUBACK: (Not implemented) + // -> release UNSUBSCRIBE + // MQTT_CONTROL_PINGRESP: + // -> release PINGREQ + +// UARTPrintf("__mqtt_recv control_type = "); +// emb_itoa(response.fixed_header.control_type, OctetArray, 16, 4); +// UARTPrintf(OctetArray); +// UARTPrintf("\r\n"); + + switch (response.fixed_header.control_type) { + + case MQTT_CONTROL_CONNACK: + // release associated CONNECT + msg = mqtt_mq_find(&client->mq, MQTT_CONTROL_CONNECT, NULL); + connack_received = 1; // Communicate CONNACK received to main.c + if (msg == NULL) { + client->error = MQTT_ERROR_ACK_OF_UNKNOWN; + mqtt_recv_ret = MQTT_ERROR_ACK_OF_UNKNOWN; + break; + } + msg->state = MQTT_QUEUED_COMPLETE; + // check that connection was successful + if (response.decoded.connack.return_code != MQTT_CONNACK_ACCEPTED) { + if (response.decoded.connack.return_code == MQTT_CONNACK_REFUSED_IDENTIFIER_REJECTED) { + client->error = MQTT_ERROR_CONNECT_CLIENT_ID_REFUSED; + mqtt_recv_ret = MQTT_ERROR_CONNECT_CLIENT_ID_REFUSED; + } + else { + client->error = MQTT_ERROR_CONNECTION_REFUSED; + mqtt_recv_ret = MQTT_ERROR_CONNECTION_REFUSED; + } + break; + } + break; + + case MQTT_CONTROL_PUBLISH: + // Stage response, none if qos==0, PUBACK if qos==1, PUBREC + // if qos==2 + // Note1: The staged response (a PUBACK) is put in the + // mqtt_sendbuf. The PUBACK will stay in the mqtt_sendbuf until + // the __mqtt_send routine is called to empty the mqtt_sendbuf. + // Note2: The received PUBLISH being processed here (and via the + // publish_callback routine) is in the uip_buf and will stay there + // until this processing completes. + +#if DEBUG_SUPPORT != 11 +UARTPrintf("mqtt_recv Received PUBLISH\r\n"); +#endif // DEBUG_SUPPORT != 11 + +// UARTPrintf("__mqtt_recv sendbuf rem = "); +// emb_itoa(client->mq.curr_sz, OctetArray, 10, 3); +// UARTPrintf(OctetArray); +// mqtt_mq_clean(&client->mq); +// UARTPrintf(" after clean = "); +// emb_itoa(client->mq.curr_sz, OctetArray, 10, 3); +// UARTPrintf(OctetArray); +// UARTPrintf("\r\n"); + + if (response.decoded.publish.qos_level == 1) { + rv = __mqtt_puback(client, response.decoded.publish.packet_id); + if (rv != MQTT_OK) { + +#if DEBUG_SUPPORT != 11 +UARTPrintf("__mqtt_puback failed\r\n"); +#endif // DEBUG_SUPPORT != 11 + + client->error = rv; + mqtt_recv_ret = rv; + break; + } + } + // QOS2 not supported - code eliminated + // For QOS0 and QOS1 call Publish Callback. + // Note that publish_callback doesn't actually put anything in the + // mqtt_sendbuf, it only queues a process that will later place + // PUBLISH messages in the mqtt_sendbuf. + +// UARTPrintf("mqtt_recv Calling callback\r\n"); + + client->publish_response_callback(&client->publish_response_callback_state, &response.decoded.publish); + break; + case MQTT_CONTROL_SUBACK: // release associated SUBSCRIBE msg = mqtt_mq_find(&client->mq, MQTT_CONTROL_SUBSCRIBE, &response.decoded.suback.packet_id); @@ -611,6 +1052,7 @@ int16_t __mqtt_recv(struct mqtt_client *client) // up here return mqtt_recv_ret; } +#endif // QOS_SUPPORT == 1 @@ -950,6 +1392,7 @@ int16_t mqtt_pack_ping_request(uint8_t *buf, uint16_t bufsz) /* PUBLISH */ +#if QOS_SUPPORT == 0 int16_t mqtt_pack_publish_request(uint8_t *buf, uint16_t bufsz, const char* topic_name, uint16_t packet_id, @@ -1004,8 +1447,83 @@ int16_t mqtt_pack_publish_request(uint8_t *buf, uint16_t bufsz, return buf - start; } +#endif // QOS_SUPPORT == 0 +#if QOS_SUPPORT == 1 +int16_t mqtt_pack_publish_request(uint8_t *buf, uint16_t bufsz, + const char* topic_name, + uint16_t packet_id, + const void* application_message, + uint16_t application_message_size, + uint8_t publish_flags) +{ + const uint8_t *const start = buf; + int16_t rv; + struct mqtt_fixed_header fixed_header; + uint32_t remaining_length; + uint8_t inspected_qos; + + // check for null pointers + if(buf == NULL || topic_name == NULL) { + return MQTT_ERROR_NULLPTR; + } + + // inspect qos level + inspected_qos = (uint8_t)((publish_flags & MQTT_PUBLISH_QOS_MASK) >> 1); + + // build the fixed header + fixed_header.control_type = MQTT_CONTROL_PUBLISH; + + // calculate remaining length + remaining_length = (uint32_t)__mqtt_packed_cstrlen(topic_name); + if (inspected_qos > 0) { + remaining_length += 2; + } + remaining_length += (uint32_t)application_message_size; + fixed_header.remaining_length = remaining_length; + + // force dup to 0 if qos is 0 [Spec MQTT-3.3.1-2] + publish_flags &= (uint8_t)(~MQTT_PUBLISH_DUP); + + // make sure that qos is not 3 [Spec MQTT-3.3.1-2] + if (inspected_qos == 3) { + return MQTT_ERROR_PUBLISH_FORBIDDEN_QOS; + } + + fixed_header.control_flags = publish_flags; + +// UARTPrintf("mqtt_pack_publish_request flags "); +// emb_itoa(publish_flags, OctetArray, 16, 2); +// UARTPrintf(OctetArray); +// UARTPrintf("\r\n"); + + // pack fixed header + rv = mqtt_pack_fixed_header(buf, bufsz, &fixed_header); + if (rv <= 0) return rv; // something went wrong + + buf += rv; + bufsz -= rv; + + // check that buffer is big enough + if (bufsz < remaining_length) return 0; + + // pack variable header + buf += __mqtt_pack_str(buf, topic_name); + if (inspected_qos > 0) { + buf += __mqtt_pack_uint16(buf, packet_id); + } + + // pack payload + memcpy(buf, application_message, application_message_size); + buf += application_message_size; + + return buf - start; +} +#endif // QOS_SUPPORT == 1 + + +#if QOS_SUPPORT == 0 int16_t mqtt_unpack_publish_response(struct mqtt_response *mqtt_response, const uint8_t *buf) { const uint8_t *const start = buf; @@ -1039,6 +1557,99 @@ int16_t mqtt_unpack_publish_response(struct mqtt_response *mqtt_response, const // return number of bytes consumed return buf - start; } +#endif // QOS_SUPPORT == 0 + + +#if QOS_SUPPORT == 1 +int16_t mqtt_unpack_publish_response(struct mqtt_response *mqtt_response, const uint8_t *buf) +{ + const uint8_t *const start = buf; + struct mqtt_fixed_header *fixed_header; + struct mqtt_response_publish *response; + + fixed_header = &(mqtt_response->fixed_header); + response = &(mqtt_response->decoded.publish); + + // get flags + response->dup_flag = (uint8_t)((fixed_header->control_flags & MQTT_PUBLISH_DUP) >> 3); + response->qos_level = (uint8_t)((fixed_header->control_flags & MQTT_PUBLISH_QOS_MASK) >> 1); + response->retain_flag = (uint8_t)(fixed_header->control_flags & MQTT_PUBLISH_RETAIN); + +#if DEBUG_SUPPORT != 11 +if (response->dup_flag == 1) { +UARTPrintf("mqtt_unpack_publish_response dup received\r\n"); +} +#endif // DEBUG_SUPPORT != 11 + + // make sure that remaining length is valid + if (mqtt_response->fixed_header.remaining_length < 4) { + return MQTT_ERROR_MALFORMED_RESPONSE; + } + + // parse variable header + response->topic_name_size = __mqtt_unpack_uint16(buf); + buf += 2; + response->topic_name = buf; + buf += response->topic_name_size; + + if (response->qos_level > 0) { + response->packet_id = __mqtt_unpack_uint16(buf); + buf += 2; + } + + // get payload + response->application_message = buf; + if (response->qos_level == 0) { + response->application_message_size = (uint16_t)(fixed_header->remaining_length - response->topic_name_size - 2); + } + else { + response->application_message_size = (uint16_t)(fixed_header->remaining_length - response->topic_name_size - 4); + } + buf += response->application_message_size; + + // return number of bytes consumed + return buf - start; +} +#endif // QOS_SUPPORT == 1 + + +#if QOS_SUPPORT == 1 +/* PUBXXX */ +int16_t mqtt_pack_pubxxx_request(uint8_t *buf, uint16_t bufsz, + enum MQTTControlPacketType control_type, + uint16_t packet_id) +{ + const uint8_t *const start = buf; + struct mqtt_fixed_header fixed_header; + int16_t rv; + if (buf == NULL) { + return MQTT_ERROR_NULLPTR; + } + + /* pack fixed header */ + fixed_header.control_type = control_type; + if (control_type == MQTT_CONTROL_PUBREL) { + fixed_header.control_flags = 0x02; + } else { + fixed_header.control_flags = 0; + } + fixed_header.remaining_length = 2; + rv = mqtt_pack_fixed_header(buf, bufsz, &fixed_header); + if (rv <= 0) { + return rv; + } + buf += rv; + bufsz -= rv; + + if (bufsz < fixed_header.remaining_length) { + return 0; + } + + buf += __mqtt_pack_uint16(buf, packet_id); + + return buf - start; +} +#endif // QOS_SUPPORT == 1 /* SUBACK */ @@ -1067,7 +1678,7 @@ int16_t mqtt_unpack_suback_response (struct mqtt_response *mqtt_response, const /* SUBSCRIBE */ -int16_t mqtt_pack_subscribe_request(uint8_t *buf, uint16_t bufsz, uint16_t packet_id, char *topic) +int16_t mqtt_pack_subscribe_request(uint8_t *buf, uint16_t bufsz, uint16_t packet_id, char *topic, int max_qos_level) { int16_t rv; const uint8_t *const start = buf; @@ -1094,7 +1705,7 @@ int16_t mqtt_pack_subscribe_request(uint8_t *buf, uint16_t bufsz, uint16_t packe // pack payload buf += __mqtt_pack_str(buf, topic); - *buf++ = 0; //max_qos + *buf++ = (uint8_t)max_qos_level; //max_qos return buf - start; } diff --git a/NetworkModule/mqtt.h b/NetworkModule/mqtt.h index 137fad1..5f83eb8 100644 --- a/NetworkModule/mqtt.h +++ b/NetworkModule/mqtt.h @@ -85,6 +85,15 @@ SOFTWARE. */ +// Size of the mqtt_sendbuf +#define MQTT_SENDBUF_SIZE 160 + + +// Function reports the remaining size of the mqtt_sendbuf (the free space +// remaining in the buffer). +uint16_t mqtt_check_sendbuf(struct mqtt_client *client); + + // An enumeration of the MQTT control packet types. // see // MQTT v3.1.1: MQTT Control Packet Types @@ -92,8 +101,14 @@ SOFTWARE. MQTT_CONTROL_CONNECT=1u, MQTT_CONTROL_CONNACK=2u, MQTT_CONTROL_PUBLISH=3u, + MQTT_CONTROL_PUBACK=4u, + MQTT_CONTROL_PUBREC=5u, + MQTT_CONTROL_PUBREL=6u, + MQTT_CONTROL_PUBCOMP=7u, MQTT_CONTROL_SUBSCRIBE=8u, MQTT_CONTROL_SUBACK=9u, +// MQTT_CONTROL_UNSUBSCRIBE=10u, +// MQTT_CONTROL_UNSUBACK=11u, MQTT_CONTROL_PINGREQ=12u, MQTT_CONTROL_PINGRESP=13u, MQTT_CONTROL_DISCONNECT=14u @@ -254,6 +269,16 @@ struct mqtt_response_publish { }; +/* +// The response to a PUBREC packet. +// See http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718053 +// MQTT v3.1.1: PUBREL - Publish Release. +struct mqtt_response_pubrel { + // The published messages packet ID. + uint16_t packet_id; +}; +*/ + // An enumeration of subscription acknowledgement return codes. // see // MQTT v3.1.1: SUBACK Return Codes. @@ -301,6 +326,7 @@ struct mqtt_response { union { struct mqtt_response_connack connack; struct mqtt_response_publish publish; +// struct mqtt_response_pubrel pubrel; struct mqtt_response_suback suback; struct mqtt_response_pingresp pingresp; } decoded; @@ -487,11 +513,38 @@ int16_t mqtt_pack_publish_request(uint8_t *buf, uint16_t bufsz, uint8_t publish_flags); +// Serialize a PUBACK, PUBREC, PUBREL, or PUBCOMP packet and put it in buf. +// buf - the buffer to put the PUBXXX packet in. +// bufsz - the maximum number of bytes that can be put into buf. +// control_type - the type of packet. Must be one of: +// MQTT_CONTROL_PUBACK +// MQTT_CONTROL_PUBREC +// MQTT_CONTROL_PUBREL +// MQTT_CONTROL_PUBCOMP +// packet_id - the packet ID of the packet being acknowledged. +// returns - the number of bytes put into buf, 0 if buf is too small to fit the +// PUBXXX packet, a negative value if there was a protocol violation. +// +// see +// MQTT v3.1.1: PUBACK - Publish Acknowledgement. +// see +// MQTT v3.1.1: PUBREC - Publish Received. +// see +// MQTT v3.1.1: PUBREL - Publish Released. +// see +// MQTT v3.1.1: PUBCOMP - Publish Complete. +int16_t mqtt_pack_pubxxx_request(uint8_t *buf, uint16_t bufsz, + enum MQTTControlPacketType control_type, + uint16_t packet_id); + + // Serialize a SUBSCRIBE packet and put it in buf. // buf - the buffer to put the SUBSCRIBE packet in. // bufsz - the maximum number of bytes that can be put into buf. // packet_id - the packet ID to be used. // topic_name - the topic name to subscribe to +// max_qos_level - The maximum QOS level with which the broker can send +// application messages for this topic. // returns - The number of bytes put into buf, 0 if buf is too small to fit // the SUBSCRIBE packet, a negative value if there was a protocol // violation. @@ -499,7 +552,8 @@ int16_t mqtt_pack_publish_request(uint8_t *buf, uint16_t bufsz, // see // MQTT v3.1.1: SUBSCRIBE - Subscribe to Topics. int16_t mqtt_pack_subscribe_request(uint8_t *buf, uint16_t bufsz, - uint16_t packet_id, char *topic); + uint16_t packet_id, char *topic, + int max_qos_level); // Serialize a PINGREQ and put it into buf. @@ -783,7 +837,7 @@ int16_t mqtt_sync(struct mqtt_client *client); // // If sendbuf fills up completely during runtime a // MQTT_ERROR_SEND_BUFFER_IS_FULL error will be set. Similarly if recvbuf is -// ever too small to receive a message from the broker an +// ever too small to receive a message from the broker a // MQTT_ERROR_RECV_BUFFER_TOO_SMALL error will be set. // // A pointer to mqtt_client.publish_response_callback_state is always passed @@ -852,6 +906,16 @@ int16_t mqtt_publish(struct mqtt_client *client, uint8_t publish_flags); +// Acknowledge an incoming publish with QOS==1. +// +// client - The MQTT client. +// packet_id - The packet ID of the ingress publish being acknowledged. +// returns - MQTT_OK upon success, an MQTTErrors otherwise. +int16_t __mqtt_puback(struct mqtt_client *client, uint16_t packet_id); + + + + // Subscribe to a topic. // // prerequisite: mqtt_connect must have been called. @@ -862,7 +926,8 @@ int16_t mqtt_publish(struct mqtt_client *client, // application messages for this topic. // returns - MQTT_OK upon success, an MQTTErrors otherwise. int16_t mqtt_subscribe(struct mqtt_client *client, - const char* topic_name); + const char* topic_name, + int max_qos_level); // Ping the broker. diff --git a/NetworkModule/mqtt_pal.c b/NetworkModule/mqtt_pal.c index 21732cd..7dddf8f 100644 --- a/NetworkModule/mqtt_pal.c +++ b/NetworkModule/mqtt_pal.c @@ -201,26 +201,29 @@ int16_t mqtt_pal_sendall(const void* buf, uint16_t len) { // //---------------------------------------------------------------------------// - // Two types of MQTT transmissions are handled here. One is the normal - // MQTT packet. The other is a Home Assistant Auto Discovery packet. Because - // the MQTT packet buffer is very small in this application it cannot hold - // an entire Auto Discovery packet. So this function checks if the + // Two types of MQTT transmissions are handled here. One is the normal MQTT + // packet. The other is a Home Assistant Auto Discovery packet. The variable + // "auto_found" determines which path is used (auto_found == 0 if a normal + // MQTT packet). + // Because the MQTT packet buffer is very small in this application it cannot + // hold an entire Auto Discovery packet. So this function checks if the // application is trying to send an Auto Discovery packet. If yes, the // function will generate the Auto Discovery packet here. If no, it is // assummed that the packet was generated external to this function and - // is already present in the MQTT transmit buffer. + // is already present in the MQTT transmit buffer (a normal MQTT packet). // // For Auto Discovery Publish messages main.c needs to create a publish // message like the following. It includes a message placeholder and the // length of that placeholder. // // This message triggers an Output discovery message. "xx" is the output - // number. + // number. MQTT_PUBLISH_QOS_x could be MQTT_PUBLISH_QOS_0 or + // MQTT_PUBLISH_QOS_1. // mqtt_publish(&mqttclient, // topic_base, // "%Oxx", // 4, - // MQTT_PUBLISH_QOS_0 | MQTT_PUBLISH_RETAIN); + // MQTT_PUBLISH_QOS_x | MQTT_PUBLISH_RETAIN); // // This message triggers an Input discovery message. "xx" is the input // number. @@ -260,8 +263,10 @@ int16_t mqtt_pal_sendall(const void* buf, uint16_t len) { // template_buf[3] = LSByte of variable header length mBuffer = buf; *((uint32_t*)&template_buf[0]) = *((uint32_t*)mBuffer); // copy 4 bytes - - // Check if Publish message with a payload + + // Check if Publish message with a payload. + // See https://bytesofgigabytes.com/mqtt/mqtt-protocol-packet-structure/ + // for description of the packet structure examined here. if ((template_buf[0] & 0xf0) == 0x30) { // This is a Publish message // Examine remaining length @@ -339,7 +344,8 @@ int16_t mqtt_pal_sendall(const void* buf, uint16_t len) { // of the application message is shown. if (payload_buf[1] == 'O') { // This is an Output auto discovery message - payload_size = 264; // Manually calculated payload size without +// payload_size = 287; // Manually calculated payload size without + payload_size = 274; // Manually calculated payload size without // devicename } if (payload_buf[1] == 'I') { @@ -348,28 +354,12 @@ int16_t mqtt_pal_sendall(const void* buf, uint16_t len) { // devicename } - - - // 20220924 TEMPERATURE SENSOR PAYLOAD EXPERIMENTS MADE NECESSARY - // BY CHANGES IN HA THAT NOW REQUIRE "device_class" AND "state_class" - // STATEMENTS IN THE CONFIG STATEMENT. NOT SURE IF "unit_of_meas" IS - // NEEDED ANYMORE. - if (payload_buf[1] == 'T') { // This is a Temperature Sensor auto discovery message -// payload_size = 283; // Manually calculated payload size without -// // devicename payload_size = 332; // Manually calculated payload size without // devicename -// payload_size = 311; // Manually calculated payload size without -// // devicename } - - - - - // Add device name size to payload size payload_size += (3 * (uint8_t)strlen(stored_devicename)); @@ -413,11 +403,6 @@ int16_t mqtt_pal_sendall(const void* buf, uint16_t len) { payload_size = payload_size + template_buf[1] - 4; if (payload_buf[1] == 'T') payload_size -= 10; -// // Calculate uip_slen (it will be used later). It is the new remaining -// // length plus 3 (for the control byte and the two remaining length -// // bytes). -// uip_slen = payload_size + 3; - // Note: The value "len" remains unchanged. It is the length of the // "app_message" provided to this function, even if we are creating a // new payload for trasnmission. @@ -481,6 +466,8 @@ int16_t mqtt_pal_sendall(const void* buf, uint16_t len) { // "avty_t":"~/availability", // 26 // "stat_t":"~/output/01", // 23 // "cmd_t":"~/output/01/set", // 26 + // "qos":"1", // 10 +// // "ret":"true", // 13 // "dev":{ // 7 // "ids":["NetworkModule_aabbccddeeff"], // 37 // "mdl":"HW-584", // 15 @@ -489,7 +476,8 @@ int16_t mqtt_pal_sendall(const void* buf, uint16_t len) { // "sw":"20201220 1322" // 20 // } // 1 // } // 1 - // // Total: 264 plus 3 x devicename +// // // Total: 287 plus 3 x devicename + // // Total: 274 plus 3 x devicename // // input payload // { // 1 @@ -511,30 +499,6 @@ int16_t mqtt_pal_sendall(const void* buf, uint16_t len) { // temperature sensor payload // { // 1 // "uniq_id":"aabbccddeeff_temp_xxxxxxxxxxxx", // 43 - // "name":"devicename123456789 temp xxxxxxxxxxxx", // 28 (without devicename) - // "~":"NetworkModule/devicename123456789", // 21 (without devicename) - // "avty_t":"~/availability", // 26 - // "stat_t":"~/temp/xxxxxxxxxxxx", // 31 - // "unit_of_meas":"\xc2\xb0\x43", // 21 - // "dev":{ // 7 - // "ids":["NetworkModule_aabbccddeeff"], // 37 - // "mdl":"HW-584", // 15 - // "mf":"NetworkModule", // 21 - // "name":"devicename123456789", // 10 (without devicename) - // "sw":"20210204 0311" // 20 - // } // 1 - // } // 1 - // // Total: 283 plus 3 x devicename - - - - - // 20220924 TEMPERATURE SENSOR PAYLOAD EXPERIMENTS MADE NECESSARY - // BY CHANGES IN HA THAT NOW REQUIRE "device_class" AND "state_class" - // STATEMENTS IN THE CONFIG STATEMENT. - // temperature sensor payload - // { // 1 - // "uniq_id":"aabbccddeeff_temp_xxxxxxxxxxxx", // 43 // 00000000011111111112222222222333333333344444444445 // 12345678901234567890123456789012345678901234567890 // "name":"devicename123456789 temp xxxxxxxxxxxx", // 28 (without devicename) @@ -556,11 +520,6 @@ int16_t mqtt_pal_sendall(const void* buf, uint16_t len) { - - - - - // "stpcpy()" is used to efficiently copy data to the uip_buf // utilizing the pBuffer pointer. pBuffer = stpcpy(pBuffer, "{\"uniq_id\":\""); @@ -615,13 +574,27 @@ int16_t mqtt_pal_sendall(const void* buf, uint16_t len) { pBuffer += 2; pBuffer = stpcpy(pBuffer, "/set\","); + +#if QOS_SUPPORT == 0 + // QOS level + pBuffer = stpcpy(pBuffer, "\"qos\":\"0\","); +#if DEBUG_SUPPORT != 11 +UARTPrintf("mqtt_pal_sendall Sent QOS = 0\r\n"); +#endif // DEBUG_SUPPORT != 11 +#endif // QOS_SUPPORT == 0 + +#if QOS_SUPPORT == 1 + // QOS level + pBuffer = stpcpy(pBuffer, "\"qos\":\"1\","); +#if DEBUG_SUPPORT != 11 +UARTPrintf("mqtt_pal_sendall Sent QOS = 1\r\n"); +#endif // DEBUG_SUPPORT != 11 + // Retain True +// pBuffer = stpcpy(pBuffer, "\"ret\":\"true\","); +#endif // QOS_SUPPORT == 1 } // Special case for temperature pin - // 20220924 TEMPERATURE SENSOR PAYLOAD EXPERIMENTS MADE NECESSARY - // BY CHANGES IN HA THAT NOW REQUIRE "device_class" AND "state_class" - // STATEMENTS IN THE CONFIG STATEMENT. NOT SURE IF "unit_of_meas" IS - // NEEDED ANYMORE. if (payload_buf[1] == 'T') { pBuffer = stpcpy(pBuffer, "\"unit_of_meas\":\"\xc2\xb0\x43\","); pBuffer = stpcpy(pBuffer, "\"dev_cla\":\"temperature\","); diff --git a/NetworkModule/timer.c b/NetworkModule/timer.c index 16ef174..b4543e1 100644 --- a/NetworkModule/timer.c +++ b/NetworkModule/timer.c @@ -37,7 +37,7 @@ uint8_t periodic_timer; // Peroidic_timer counter uint8_t mqtt_timer; // MQTT_timer counter uint16_t arp_timer; // arp_timer counter -uint8_t mqtt_outbound_timer; // mqtt_outbound_timer counter +// uint8_t mqtt_outbound_timer; // mqtt_outbound_timer counter uint8_t t100ms_timer; // MQTT_timer counter uint16_t second_toggle; // MQTT timing: Used in developing a 1 second counter @@ -247,7 +247,7 @@ void timer_update(void) // function calls will determine their timeout points. periodic_timer++; mqtt_timer++; - mqtt_outbound_timer++; +// mqtt_outbound_timer++; arp_timer++; t100ms_timer++; diff --git a/NetworkModule/uip.c b/NetworkModule/uip.c index 996f6c0..6c9c03c 100644 --- a/NetworkModule/uip.c +++ b/NetworkModule/uip.c @@ -474,12 +474,20 @@ void uip_process(uint8_t flag) // Note: When a UIP_APPCALL is made to receive data the uip_len value will // be set to the TCP data length. When a UIP_APPCALL is made to transmit // data the appcall will set the uip_len value. + // + // Note: In TcpAppHub.h this define appears: + // #define UIP_APPCALL uip_TcpAppHubCall + // So, a UIP_APPCALL actually calls uip_TcpAppHubCall which sorts out + // whether the UIP_APPCALL is for an HTTP or MQTT message based on the Port + // specified in the message. uip_sappdata = uip_appdata = &uip_buf[UIP_IPTCPH_LEN + UIP_LLH_LEN]; // Check if we were invoked because of a poll request for a particular // connection. A UIP_POLL_REQUEST will occur without any receive data // present, so uip_len should be zero when it occurs. + // UIP_POLL_REQUEST IS NOT USED IN THIS APPLICATION, SO THIS CODE COULD BE + // REMOVED. THAT WOULD ONLY SAVE 21 BYTES, BUT REMOVAL IS AN OPTION. if (flag == UIP_POLL_REQUEST) { if ((uip_connr->tcpstateflags & UIP_TS_MASK) == UIP_ESTABLISHED && !uip_outstanding(uip_connr)) { // UARTPrintf(" uip.c: APPCALL due to POLL REQUEST\r\n"); @@ -489,7 +497,7 @@ void uip_process(uint8_t flag) } goto drop; } - + // Check if we were invoked because of the perodic timer firing. A // UIP_TIMER will occur without any receive data present, so uip_len // should be zero when it occurs. @@ -511,12 +519,16 @@ void uip_process(uint8_t flag) // connection to time out. If so, we increase the connection's timer and // remove the connection if it times out. if (uip_connr->tcpstateflags == UIP_TIME_WAIT || uip_connr->tcpstateflags == UIP_FIN_WAIT_2) { +#if DEBUG_SUPPORT != 11 +UARTPrintf(" uip.c: periodic APPCALL waiting for timeout\r\n"); +#endif // DEBUG_SUPPORT != 11 ++(uip_connr->timer); if (uip_connr->timer == UIP_TIME_WAIT_TIMEOUT) { uip_connr->tcpstateflags = UIP_CLOSED; } } else if (uip_connr->tcpstateflags != UIP_CLOSED) { +// UARTPrintf(" uip.c: periodic APPCALL awaiting outstanding data\r\n"); // If the connection has outstanding data, we increase the connection's // timer and see if it has reached the RTO value in which case we // retransmit. @@ -530,7 +542,6 @@ void uip_process(uint8_t flag) // We call UIP_APPCALL() with uip_flags set to UIP_TIMEDOUT to // inform the application that the connection has timed out. uip_flags = UIP_TIMEDOUT; -// UARTPrintf(" uip.c: APPCALL due to Timeout\r\n"); UIP_APPCALL(); // Timeout call. uip_len was cleared above. // We also send a reset packet to the remote host. @@ -566,7 +577,6 @@ void uip_process(uint8_t flag) // the actual retransmit after which we jump into the code for // sending out the packet (the apprexmit label). uip_flags = UIP_REXMIT; -// UARTPrintf(" uip.c: APPCALL due to ESTABLISHED\r\n"); UIP_APPCALL(); // Call to get old data for retransmit. uip_len // was cleared above. goto apprexmit; @@ -581,6 +591,7 @@ void uip_process(uint8_t flag) } } else if ((uip_connr->tcpstateflags & UIP_TS_MASK) == UIP_ESTABLISHED) { +// UARTPrintf(" uip.c: periodic APPCALL poll for new data\r\n"); // If there was no need for a retransmission, we poll the application // for new data. uip_flags = UIP_POLL; @@ -600,6 +611,7 @@ void uip_process(uint8_t flag) //---------------------------------------------------------------------------// + // flag == UIP_DATA, ie uip_process(UIP_DATA), will start here. // This is where the input processing starts. We fall through to this point // if the call was uip_process(UIP_DATA) UIP_STAT(++uip_stat.ip.recv); @@ -609,7 +621,7 @@ void uip_process(uint8_t flag) if (BUF->vhl != 0x45) { // IP version and header length. UIP_STAT(++uip_stat.ip.drop); UIP_STAT(++uip_stat.ip.vhlerr); -// UARTPrintf(" uip.c: drop invlaid header\r\n"); +// UARTPrintf(" uip.c: drop invalid header\r\n"); goto drop; } diff --git a/NetworkModule/uipopt.h b/NetworkModule/uipopt.h index 7d9f96a..574dc18 100644 --- a/NetworkModule/uipopt.h +++ b/NetworkModule/uipopt.h @@ -286,7 +286,7 @@ // USAGE: Provides the most run time error data and UART display. // * Specific debug data: Reset Status Register counters, TXERIF counter, // RXERIF counter, Stack Overflow bit, and ENC28J60 revision level. -#define DEBUG_SUPPORT 15 +#define DEBUG_SUPPORT 11 // IWDG_ENABLE @@ -314,8 +314,8 @@ // Code Uploader requires additional hardware in the form of an off-board I2C // EEPROM, thus OB_EEPROM_SUPPORT and I2C_SUPPORT must be enabled. // Un-comment ONLY ONE of the following: -#define BUILD_SUPPORT MQTT_BUILD -// #define BUILD_SUPPORT BROWSER_ONLY_BUILD +// #define BUILD_SUPPORT MQTT_BUILD +#define BUILD_SUPPORT BROWSER_ONLY_BUILD // #define BUILD_SUPPORT CODE_UPLOADER_BUILD @@ -362,6 +362,25 @@ #define DEBUG_SENSOR_SERIAL 0 +// QOS_SUPPORT +// Determines the QOS level supported in MQTT when receiving PUBLISH messages +// from the Broker/Server. +// QOS 0 works for most applications because the PUBLISH messaging rate to the +// Network Module can be limited by the host based application and the usage +// model for the Network Module is to be on a local network only. However, +// Home Assistant has a "Toggle" function that can result in very rapid +// message delivery to the Network Module so QOS 1 was implemented to assist +// in assuring that all HA PUBLISH messages are properly received by the +// Network Module. +// Even when QOS 1 is enabled the setting should have no effect on host +// applications that deliver messages with QOS 0. +// THIS IS A TEMPORARY BUILD MODE TO ALLOW TRANSITION TO QOS 1 MODE. +// EVENTUALLY THE "QOS 0 ONLY" CODE WILL BE REMOVED. +// 0 = "Fire and Forget" Mode +// 1 = Acknowlege Receipt Mode +#define QOS_SUPPORT 1 + + //---------------------------------------------------------------------------// /** diff --git a/~$twork Module Manual - Code Rev 20221009 2141.docx b/~$twork Module Manual - Code Rev 20221009 2141.docx new file mode 100644 index 0000000000000000000000000000000000000000..5b230c63c295de4333be589c7a643bbe0650b05d GIT binary patch literal 162 zcmZSa&CE_^AQiAM_%dWNWHW$t<^eG`6mtM+F({jn!6Gk~fw4h^L82Q%n?UIRD4heP TOQ7@wFfGck0!&LV>;cmN2f7rb literal 0 HcmV?d00001 From bb23f629d7645ba4dcebef61a3d07e4b590e08c7 Mon Sep 17 00:00:00 2001 From: nielsonm236 Date: Tue, 29 Nov 2022 14:19:57 -0700 Subject: [PATCH 2/2] Pre-release to address HA Header Toggle Second pre-release to address HA Header Toggle. Deprecated the QOS1 changes. Added REST batch command. --- NetworkModule/.Idea_Groups/Vector_File.grp | 2 +- NetworkModule/.Idea_Temp/COBJ.TMP | 602 +++++----- NetworkModule/.Idea_Temp/IDEA.ERR | 9 +- NetworkModule/.Idea_Temp/IDEABLD.BAT | 2 +- NetworkModule/DS18B20.c | 22 +- NetworkModule/Enc28j60.c | 9 + NetworkModule/Enc28j60.h | 2 + NetworkModule/Gpio.c | 6 +- NetworkModule/Main.c | 849 ++++++-------- NetworkModule/httpd.c | 237 +++- NetworkModule/main.h | 3 +- NetworkModule/mqtt.c | 1227 +++++++++----------- NetworkModule/mqtt.h | 4 +- NetworkModule/mqtt_pal.c | 31 +- NetworkModule/uip.c | 242 +++- NetworkModule/uipopt.h | 68 +- 16 files changed, 1625 insertions(+), 1690 deletions(-) diff --git a/NetworkModule/.Idea_Groups/Vector_File.grp b/NetworkModule/.Idea_Groups/Vector_File.grp index 1d4efab..14b4468 100644 --- a/NetworkModule/.Idea_Groups/Vector_File.grp +++ b/NetworkModule/.Idea_Groups/Vector_File.grp @@ -1,5 +1,5 @@ # Group File Created by IDEA # Project: -# Wed Nov 09 11:24:42 2022 +# Mon Nov 28 19:28:29 2022 # "networkmodule_vector.o" diff --git a/NetworkModule/.Idea_Temp/COBJ.TMP b/NetworkModule/.Idea_Temp/COBJ.TMP index 10a415a..67e2419 100644 --- a/NetworkModule/.Idea_Temp/COBJ.TMP +++ b/NetworkModule/.Idea_Temp/COBJ.TMP @@ -3,18 +3,18 @@ header: executable format processor number 6, type 3 -15 sections -620 symbols -6227 debug symbols +14 sections +580 symbols +5535 debug symbols sections: .vector: hilo code, at address 0x8000 128 data bytes (0x0080) .const: hilo code, at address 0x8080 - 2711 data bytes (0x0a97) -.text: hilo code, at address 0x8b17 - 24349 data bytes (0x5f1d) + 7481 data bytes (0x1d39) +.text: hilo code, at address 0x9db9 + 22567 data bytes (0x5827) .eeprom: hilo, at address 0x4000 108 data bytes (0x006c) .bsct: no attribute, at address 0x0 @@ -23,203 +23,187 @@ sections: 10 reserved bytes (0x000a) .bit: no attribute, at address 0xa 0 data bytes (0x0000) -.data: hilo (init), at address 0xea41 +.data: hilo, at address 0xa 8 data bytes (0x0008) -memcpy_update: hilo code (init), at address 0xea49 - 40 data bytes (0x0028) -.bss: bss hilo, at address 0x3a - 1461 reserved bytes (0x05b5) -.flash_update: hilo code, at address 0xfc80 - 451 data bytes (0x01c3) +memcpy_update: no attribute, at address 0x12 + 0 data bytes (0x0000) +.bss: bss hilo, at address 0x12 + 1438 reserved bytes (0x059e) +.flash_update: no attribute, at address 0xfc80 + 0 data bytes (0x0000) .iconst: bss hilo, at address 0x5fe 2 reserved bytes (0x0002) .debug: hilo, at address 0x0 - 101564 data bytes (0x18cbc) + 98474 data bytes (0x180aa) .info.: no attribute, at address 0x0 - 3779 data bytes (0x0ec3) -.init: hilo code, at address 0xea34 - 13 data bytes (0x000d) + 3730 data bytes (0x0e92) symbols: -__memory: 000005ef section .bss defined public -___mqtt_recv: 0000c5e0 section .text defined public -c_itoly: 0000e749 section .text defined public -_mqtt_sync: 0000c03c section .text defined public -_mqtt_unpack_response: 0000d005 section .text defined public -_mqtt_unpack_connack_response: 0000ca45 section .text defined public -_mqtt_unpack_publish_response: 0000cbb2 section .text defined public -_mqtt_unpack_suback_response: 0000ccdf section .text defined public +__memory: 000005b0 section .bss defined public +_pbi: 000001bf section .bss defined public +___mqtt_recv: 0000d31a section .text defined public +c_itoly: 0000f2f5 section .text defined public +_mqtt_sync: 0000cd8f section .text defined public +_mqtt_unpack_response: 0000dc2e section .text defined public +_mqtt_unpack_connack_response: 0000d745 section .text defined public +_mqtt_unpack_publish_response: 0000d87f section .text defined public +_mqtt_unpack_suback_response: 0000d908 section .text defined public c_y: 00000007 section .ubsct defined public zpage -c_lgsbc: 0000e90e section .text defined public -_memmove: 0000e60e section .text defined public -_uip_ipchksum: 0000d6d5 section .text defined public -_uip_tcpchksum: 0000d73b section .text defined public +c_lgsbc: 0000f4ba section .text defined public +_memmove: 0000f1ef section .text defined public +_uip_ipchksum: 0000e2f1 section .text defined public +_uip_tcpchksum: 0000e357 section .text defined public _stored_EEPROM_revision1: 00004015 section .eeprom defined public -_check_mqtt_server_arp_entry: 0000e501 section .text defined public +_periodic_service: 0000ba62 section .text defined public +_check_mqtt_server_arp_entry: 0000f0e2 section .text defined public _stack_limit1: 000005ff section .iconst defined public _stored_unused1: 00004014 section .eeprom defined public -_ON_OFF_word_new1: 000001e3 section .bss defined public +_ON_OFF_word_new1: 000001a1 section .bss defined public _stored_unused3: 0000404c section .eeprom defined public -_uip_listenports: 000002b8 section .bss defined public +_uip_listenports: 00000279 section .bss defined public +_MQTT_transmit: 000000b8 section .bss defined public _stored_unused4: 0000404d section .eeprom defined public -c_divul: 0000e7db section .text defined public -_write_one: 0000abe7 section .text defined public +c_divul: 0000f387 section .text defined public _stored_unused5: 0000404e section .eeprom defined public -_init_IWDG: 0000bdf8 section .text defined public +_init_IWDG: 0000cb4f section .text defined public _stored_prior_config: 00004050 section .eeprom defined public -_auto_discovery: 000000fd section .bss defined public -_mqtt_close_tcp: 0000018f section .bss defined public -_mqtt_start: 0000013c section .bss defined public -_restart: 0000bd65 section .text defined public -_mqtt_sanity_ctr: 00000138 section .bss defined public -_check_I2C_EEPROM_ctr: 000000bf section .bss defined public -_check_DS18B20_ctr: 000000cb section .bss defined public -_check_DS18B20_sensor_ctr: 000000c7 section .bss defined public -___mqtt_pack_str: 0000d0b0 section .text defined public -_uip_arp_arpin: 0000e307 section .text defined public -_mqtt_mq_clean: 0000ce7b section .text defined public -_check_reset_button: 0000bf49 section .text defined public -_mqtt_subscribe: 0000c2ee section .text defined public -_send_IOT_msg: 0000b170 section .text defined public -_unlock_eeprom: 0000b736 section .text defined public -_lock_eeprom: 0000b746 section .text defined public -_I2C_stop: 0000fd76 section .flash_update defined public -_SDA_high: 0000fd23 section .flash_update defined public -_SCL_high: 0000fd11 section .flash_update defined public -_I2C_byte_address: 0000fca6 section .flash_update defined public -_uip_process: 0000d84f section .text defined public -_eeprom_base: 000000b3 section .bss defined public -_topic_base: 000000fe section .bss defined public -c_lumd: 0000e984 section .text defined public -_HttpDCall: 00009de7 section .text defined public -_periodic_timer_expired: 0000d5cc section .text defined public -_t100ms_timer_expired: 0000d5ec section .text defined public -_mqtt_timer_expired: 0000d5dc section .text defined public -_arp_timer_expired: 0000d5fc section .text defined public -_connack_received: 000002a2 section .bss defined public -_suback_received: 000002a1 section .bss defined public -_publish_pinstate_all: 0000b602 section .text defined public -_mqtt_pal_sendall: 0000d101 section .text defined public -_uip_TcpAppHubCall: 0000e58f section .text defined public -_mac_string: 00000194 section .bss defined public -_show_temperature_string: 00009d64 section .text defined public -_update_mac_string: 0000b967 section .text defined public -___mqtt_ping: 0000c373 section .text defined public -__idesc__: 0000ea34 section .init defined public -_uip_flags: 000002d4 section .bss defined public -_connect_flags: 00000181 section .bss defined public -_htons: 0000e168 section .text defined public -_Read_Slave_NACKACK: 0000fd5c section .flash_update defined public -_parse_tail: 0000007d section .bss defined public -_hex2int: 000096ee section .text defined public -_two_hex2int: 0000971c section .text defined public -_mqttclient: 00000159 section .bss defined public -_verify_count: 00000139 section .bss defined public -_ON_OFF_word_sent: 000001df section .bss defined public -_prep_read: 0000abd6 section .text defined public -_eeprom_num_read: 000000b5 section .bss defined public -_check_restart_reboot: 0000bc2c section .text defined public -_reboot: 0000bdac section .text defined public -___mqtt_next_pid: 0000c08c section .text defined public -_HtmlPageIOControl_size: 0000007a section .bss defined public -_HtmlPageConfiguration_size: 00000078 section .bss defined public -_adjust_template_size: 0000957e section .text defined public +_auto_discovery: 000000bd section .bss defined public +_mqtt_close_tcp: 0000014e section .bss defined public +_mqtt_start: 000000fb section .bss defined public +_restart: 0000cabc section .text defined public +_mqtt_sanity_ctr: 000000f8 section .bss defined public +_check_DS18B20_ctr: 00000089 section .bss defined public +___mqtt_pack_str: 0000dcd9 section .text defined public +_uip_process: 0000e46b section .text defined public +_uip_arp_arpin: 0000eee8 section .text defined public +_mqtt_mq_clean: 0000daa4 section .text defined public +_check_reset_button: 0000cc90 section .text defined public +_mqtt_subscribe: 0000d043 section .text defined public +_send_IOT_msg: 0000beff section .text defined public +_unlock_eeprom: 0000c4c8 section .text defined public +_lock_eeprom: 0000c4d8 section .text defined public +_check_restart_reboot: 0000c983 section .text defined public +_reboot: 0000cb03 section .text defined public +___mqtt_next_pid: 0000ce58 section .text defined public +_topic_base: 000000be section .bss defined public +c_lumd: 0000f530 section .text defined public +_HttpDCall: 0000adb2 section .text defined public +_mqtt_timer_expired: 0000e1f8 section .text defined public +_periodic_timer_expired: 0000e1e8 section .text defined public +_t100ms_timer_expired: 0000e208 section .text defined public +_arp_timer_expired: 0000e218 section .text defined public +_connack_received: 00000263 section .bss defined public +_suback_received: 00000262 section .bss defined public +_publish_pinstate_all: 0000c394 section .text defined public +_mqtt_pal_sendall: 0000dd2a section .text defined public +_uip_TcpAppHubCall: 0000f170 section .text defined public +_mac_string: 00000153 section .bss defined public +_show_temperature_string: 0000ad2f section .text defined public +_update_mac_string: 0000c6eb section .text defined public +___mqtt_ping: 0000d0c8 section .text defined public +_uip_flags: 00000295 section .bss defined public +_connect_flags: 00000140 section .bss defined public +_htons: 0000ed49 section .text defined public +_parse_tail: 00000053 section .bss defined public +_hex2int: 0000a87a section .text defined public +_two_hex2int: 0000a8a8 section .text defined public +_mqttclient: 00000118 section .bss defined public +_verify_count: 000000f9 section .bss defined public +_ON_OFF_word_sent: 0000019d section .bss defined public +_HtmlPageIOControl_size: 00000050 section .bss defined public +_HtmlPageConfiguration_size: 0000004e section .bss defined public +_adjust_template_size: 0000a71f section .text defined public _stored_devicename: 00004000 section .eeprom defined public _stored_mqtt_username: 00004035 section .eeprom defined public -_Pending_devicename: 000001b8 section .bss defined public -_Pending_mqtt_username: 000000e7 section .bss defined public -_parse_local_buf: 0000a43c section .text defined public -_uip_buf: 00000393 section .bss defined public -_mqtt_sendbuf: 00000201 section .bss defined public -_mqtt_check_sendbuf: 0000c072 section .text defined public -_strlen: 0000e686 section .text defined public -_uip_listen: 0000d808 section .text defined public -_uip_len: 0000038f section .bss defined public +_Pending_devicename: 00000177 section .bss defined public +_Pending_mqtt_username: 000000a5 section .bss defined public +_parse_local_buf: 0000b47c section .text defined public +_uip_buf: 00000354 section .bss defined public +_mqtt_sendbuf: 000001c2 section .bss defined public +_mqtt_check_sendbuf: 0000ce3e section .text defined public +_strlen: 0000f267 section .text defined public +_uip_listen: 0000e424 section .text defined public +_uip_len: 00000350 section .bss defined public _stored_unused6: 0000404f section .eeprom defined public -_uip_slen: 000002c0 section .bss defined public -_uip_conn: 0000038d section .bss defined public -_mqtt_conn: 00000136 section .bss defined public -_code_revision: 00008850 section .const defined public -_z_diag: 0000007c section .bss defined public -_off_board_eeprom_index: 000000a5 section .bss defined public -_int2hex: 00009737 section .text defined public -_copy_ram_index: 000000b7 section .bss defined public +_uip_slen: 00000281 section .bss defined public +_uip_conn: 0000034e section .bss defined public +_mqtt_conn: 000000f6 section .bss defined public +_code_revision: 00009afd section .const defined public +_z_diag: 00000052 section .bss defined public +_ps: 000097dc section .const defined public +c_eewrc: 0000f297 section .text defined public _stored_mqtt_password: 00004040 section .eeprom defined public -_Pending_mqtt_password: 000000dc section .bss defined public -_Invert_word: 000001dd section .bss defined public -_ON_OFF_word: 000001e5 section .bss defined public -c_eewrd: 0000e71e section .text defined public -c_ludv: 0000e970 section .text defined public -c_lglsh: 0000e8d6 section .text defined public -_uip_conns: 000002d9 section .bss defined public -_update_ON_OFF: 0000a7d8 section .text defined public +_Pending_mqtt_password: 0000009a section .bss defined public +_Invert_word: 0000019b section .bss defined public +_ON_OFF_word: 000001a3 section .bss defined public +c_eewrd: 0000f2ca section .text defined public +c_ludv: 0000f51c section .text defined public +_int2hex: 0000a8c3 section .text defined public +c_lglsh: 0000f482 section .text defined public +_uip_conns: 0000029a section .bss defined public +_update_ON_OFF: 0000b818 section .text defined public _stored_magic1: 0000402b section .eeprom defined public _stored_magic3: 0000402d section .eeprom defined public -_write_output_pins: 0000beca section .text defined public -_read_input_pins: 0000be0d section .text defined public +_write_output_pins: 0000cc21 section .text defined public +_read_input_pins: 0000cb64 section .text defined public _io_map: 000080a3 section .const defined public -_encode_16bit_registers: 0000a819 section .text defined public -_init_off_board_string_pointers: 00009502 section .text defined public -_uip_netmask: 000002cc section .bss defined public -_Pending_netmask: 000001ce section .bss defined public +_encode_16bit_registers: 0000b859 section .text defined public +_init_off_board_string_pointers: 0000a71e section .text defined public +_uip_netmask: 0000028d section .bss defined public +_Pending_netmask: 0000018d section .bss defined public _stored_netmask: 0000401f section .eeprom defined public -_Enc28j60Send: 00009289 section .text defined public -_uip_send: 0000e169 section .text defined public -_publish_outbound: 0000b435 section .text defined public -___mqtt_send: 0000c439 section .text defined public -_mqtt_mq_find: 0000cfc9 section .text defined public -_Enc28j60ReadPhy: 00008ff9 section .text defined public -_Enc28j60WritePhy: 00009046 section .text defined public -_stpcpy: 0000d0eb section .text defined public -__fctcpy: 0000e692 section .text defined public -_select: 00008f76 section .text defined public -_deselect: 00008f7c section .text defined public -_init_tHttpD_struct: 00009dd9 section .text defined public -_parsepost: 0000a2cb section .text defined public -_off_board_EEPROM_detect: 0000ab90 section .text defined public -_eeprom_detect: 000000be section .bss defined public -_uip_connect: 0000d76f section .text defined public -_mqtt_connect: 0000c13e section .text defined public -_mqtt_disconnect: 0000c3d6 section .text defined public -_mqtt_pack_disconnect: 0000ca95 section .text defined public -_update_debug_storage1: 0000c01c section .text defined public -_RXERIF_counter: 000000d7 section .bss defined public -_TXERIF_counter: 000000d6 section .bss defined public -_TRANSMIT_counter: 000000d2 section .bss defined public -_second_counter: 000002a3 section .bss defined public -_MQTT_resp_tout_counter: 000000d1 section .bss defined public -_MQTT_not_OK_counter: 000000d0 section .bss defined public -_MQTT_broker_dis_counter: 000000cf section .bss defined public -_mqtt_mq_register: 0000ce14 section .text defined public -_mqtt_unpack_fixed_header: 0000c76f section .text defined public -_mqtt_pack_fixed_header: 0000c82c section .text defined public -_Enc28j60SwitchBank: 00008fe7 section .text defined public -_SpiReadChunk: 0000d4b2 section .text defined public -_SpiWriteChunk: 0000d449 section .text defined public -_mqtt_start_status: 000000f9 section .bss defined public -_MQTT_error_status: 000000f8 section .bss defined public +_Enc28j60Send: 0000a4ff section .text defined public +_uip_send: 0000ed4a section .text defined public +_publish_outbound: 0000c1cd section .text defined public +___mqtt_send: 0000d18e section .text defined public +_mqtt_mq_find: 0000dbf2 section .text defined public +_Enc28j60ReadPhy: 0000a26f section .text defined public +_Enc28j60WritePhy: 0000a2bc section .text defined public +_stpcpy: 0000dd14 section .text defined public +_select: 0000a1ec section .text defined public +_deselect: 0000a1f2 section .text defined public +_init_tHttpD_struct: 0000ada4 section .text defined public +_parsepost: 0000b30b section .text defined public +_uip_connect: 0000e38b section .text defined public +_mqtt_connect: 0000cf08 section .text defined public +_mqtt_disconnect: 0000d12b section .text defined public +_mqtt_pack_disconnect: 0000d795 section .text defined public +_update_debug_storage1: 0000cd6f section .text defined public +_RXERIF_counter: 00000095 section .bss defined public +_TXERIF_counter: 00000094 section .bss defined public +_TRANSMIT_counter: 00000090 section .bss defined public +_second_counter: 00000264 section .bss defined public +_MQTT_resp_tout_counter: 0000008f section .bss defined public +_MQTT_not_OK_counter: 0000008e section .bss defined public +_MQTT_broker_dis_counter: 0000008d section .bss defined public +_mqtt_mq_register: 0000da3d section .text defined public +_mqtt_unpack_fixed_header: 0000d46f section .text defined public +_mqtt_pack_fixed_header: 0000d52c section .text defined public +_Enc28j60SwitchBank: 0000a25d section .text defined public +_SpiReadChunk: 0000e0ce section .text defined public +_SpiWriteChunk: 0000e065 section .text defined public +_mqtt_start_status: 000000b7 section .bss defined public +_MQTT_error_status: 000000b6 section .bss defined public _stored_config_settings: 00004051 section .eeprom defined public -_Pending_config_settings: 000001b7 section .bss defined public -_check_eeprom_settings: 0000b79a section .text defined public -_debug: 000001f7 section .bss defined public +_Pending_config_settings: 00000176 section .bss defined public +_check_eeprom_settings: 0000c51e section .text defined public +_debug: 000001b5 section .bss defined public _stored_debug: 00004062 section .eeprom defined public _stored_uip_ethaddr_oct: 00004017 section .eeprom defined public -_eeprom_copy_to_flash_request: 000000a7 section .bss defined public -_user_reboot_request: 00000192 section .bss defined public -_Pending_uip_ethaddr_oct: 000001b1 section .bss defined public -_reboot_request: 00000193 section .bss defined public -_restart_request: 00000191 section .bss defined public -_state_request: 000001dc section .bss defined public -_mqtt_pack_connection_request: 0000c8db section .text defined public -_mqtt_pack_publish_request: 0000cad5 section .text defined public -_mqtt_pack_pubxxx_request: 0000cc6d section .text defined public -_mqtt_pack_subscribe_request: 0000cd41 section .text defined public -_mqtt_pack_ping_request: 0000cab5 section .text defined public +_user_reboot_request: 00000151 section .bss defined public +_Pending_uip_ethaddr_oct: 00000170 section .bss defined public +_reboot_request: 00000152 section .bss defined public +_restart_request: 00000150 section .bss defined public +_state_request: 0000019a section .bss defined public +_mqtt_pack_connection_request: 0000d5db section .text defined public +_mqtt_pack_publish_request: 0000d7d5 section .text defined public +_mqtt_pack_subscribe_request: 0000d96a section .text defined public +_mqtt_pack_ping_request: 0000d7b5 section .text defined public _CLK_PCKENR1: 000050c7 section absolute defined public absolute _UART2_BRR1: 00005242 section absolute defined public absolute -_uip_appdata: 00000391 section .bss defined public -_uip_sappdata: 000002c2 section .bss defined public +_uip_appdata: 00000352 section .bss defined public +_uip_sappdata: 00000283 section .bss defined public _TIM1_ARRH: 00005262 section absolute defined public absolute _TIM1_CCR2H: 00005267 section absolute defined public absolute _TIM2_ARRH: 0000530d section absolute defined public absolute @@ -227,12 +211,10 @@ _TIM2_CCR2H: 00005311 section absolute defined public absolute _TIM3_ARRH: 0000532b section absolute defined public absolute _TIM3_CCR2H: 0000532f section absolute defined public absolute _DM_BK2RH: 00007f94 section absolute defined public absolute -c_lzmp: 0000e99e section .text defined public -_compare_flash_to_EEPROM0: 0000ac01 section .text defined public -_copy_flash_to_EEPROM0: 0000ac58 section .text defined public -c_smodx: 0000e9c3 section .text defined public -_FindDevices: 00008dc1 section .text defined public -_check_runtime_changes: 0000b99e section .text defined public +c_lzmp: 0000f54a section .text defined public +c_smodx: 0000f56f section .text defined public +_FindDevices: 0000a057 section .text defined public +_check_runtime_changes: 0000c722 section .text defined public c_x: 00000004 section .ubsct defined public zpage _PA_ODR: 00005000 section absolute defined public absolute _PB_ODR: 00005005 section absolute defined public absolute @@ -327,7 +309,7 @@ _FLASH_DUKR: 00005064 section absolute defined public absolute _SPI_RXCRCR: 00005206 section absolute defined public absolute _SPI_TXCRCR: 00005207 section absolute defined public absolute _TIM1_RCR: 00005264 section absolute defined public absolute -c_ltor: 0000e95e section .text defined public +c_ltor: 0000f50a section .text defined public _RST_SR: 000050b3 section absolute defined public absolute _CLK_CSSR: 000050c8 section absolute defined public absolute _BEEP_CSR: 000050f3 section absolute defined public absolute @@ -339,7 +321,7 @@ _TIM1_SMCR: 00005252 section absolute defined public absolute _TIM4_SR: 00005342 section absolute defined public absolute _ADC_CSR: 00005400 section absolute defined public absolute _SWIM_CSR: 00007f80 section absolute defined public absolute -c_lgor: 0000e8f7 section .text defined public +c_lgor: 0000f4a3 section .text defined public _CLK_CMSR: 000050c3 section absolute defined public absolute _CLK_SWCR: 000050c5 section absolute defined public absolute _CLK_SWIMCCR: 000050cd section absolute defined public absolute @@ -351,52 +333,50 @@ _TIM2_PSCR: 0000530c section absolute defined public absolute _TIM3_PSCR: 0000532a section absolute defined public absolute _TIM4_PSCR: 00005345 section absolute defined public absolute _CFG_GCR: 00007f60 section absolute defined public absolute -_ON_OFF_word_new2: 000001e1 section .bss defined public +_ON_OFF_word_new2: 0000019f section .bss defined public _CLK_SWR: 000050c4 section absolute defined public absolute _WWDG_WR: 000050d2 section absolute defined public absolute _TIM1_EGR: 00005257 section absolute defined public absolute _TIM2_EGR: 00005304 section absolute defined public absolute _TIM3_EGR: 00005324 section absolute defined public absolute _TIM4_EGR: 00005343 section absolute defined public absolute -c_lgsub: 0000e924 section .text defined public -_uip_add32: 0000d630 section .text defined public +c_lgsub: 0000f4d0 section .text defined public +_uip_add32: 0000e24c section .text defined public _CLK_CKDIVR: 000050c6 section absolute defined public absolute _CLK_PCKENR2: 000050ca section absolute defined public absolute _UART2_BRR2: 00005243 section absolute defined public absolute _CLK_CCOR: 000050c9 section absolute defined public absolute _stored_magic2: 0000402c section .eeprom defined public -_uip_acc32: 000002d5 section .bss defined public +_uip_acc32: 00000296 section .bss defined public _CLK_HSITRIMR: 000050cc section absolute defined public absolute _IWDG_PR: 000050e1 section absolute defined public absolute _SPI_CRCPR: 00005205 section absolute defined public absolute -_uip_hostaddr: 000002d0 section .bss defined public -_uip_draddr: 000002c8 section .bss defined public -_uip_mqttserveraddr: 000002c4 section .bss defined public -_Pending_hostaddr: 000001d6 section .bss defined public -_Pending_draddr: 000001d2 section .bss defined public -_Pending_mqttserveraddr: 000000f4 section .bss defined public +_uip_hostaddr: 00000291 section .bss defined public +_uip_draddr: 00000289 section .bss defined public +_uip_mqttserveraddr: 00000285 section .bss defined public +_Pending_hostaddr: 00000195 section .bss defined public +_Pending_draddr: 00000191 section .bss defined public +_Pending_mqttserveraddr: 000000b2 section .bss defined public _stored_hostaddr: 00004027 section .eeprom defined public -_IpAddr: 00000187 section .bss defined public +_IpAddr: 00000146 section .bss defined public _stored_draddr: 00004023 section .eeprom defined public _stored_mqttserveraddr: 00004031 section .eeprom defined public _uip_ethaddr: 0000000c section .data defined public _stored_unused2: 0000404b section .eeprom defined public _AWU_APR: 000050f1 section absolute defined public absolute -_ram_ptr: 000000b9 section .bss defined public -_flash_ptr: 000000bb section .bss defined public _stack_limit2: 000005fe section .iconst defined public -_pin_ptr: 000000fb section .bss defined public +_pin_ptr: 000000bb section .bss defined public _AWU_TBR: 000050f2 section absolute defined public absolute _stored_EEPROM_revision2: 00004016 section .eeprom defined public _I2C_FREQR: 00005212 section absolute defined public absolute -_sensor_number: 000000fa section .bss defined public +_sensor_number: 000000ba section .bss defined public _I2C_OARL: 00005213 section absolute defined public absolute _DM_BK1RL: 00007f92 section absolute defined public absolute _I2C_OARH: 00005214 section absolute defined public absolute _DM_BK1RH: 00007f91 section absolute defined public absolute _lastDiscrep: 0000000a section .data defined public -c_bmulx: 0000e6c7 section .text defined public -_mqtt_startup: 0000ace2 section .text defined public +c_bmulx: 0000f273 section .text defined public +_mqtt_startup: 0000ba95 section .text defined public _I2C_SR3: 00005219 section absolute defined public absolute _UART2_CR3: 00005246 section absolute defined public absolute _ADC_CR3: 00005403 section absolute defined public absolute @@ -408,19 +388,19 @@ _I2C_CCRH: 0000521c section absolute defined public absolute _TIM1_PSCRH: 00005260 section absolute defined public absolute _ADC_AWSRH: 0000540c section absolute defined public absolute _ADC_AWCRH: 0000540e section absolute defined public absolute -c_itolx: 0000e73b section .text defined public -c_uitolx: 0000ea2d section .text defined public -_memcmp: 0000e5de section .text defined public -_strcmp: 0000e673 section .text defined public -_restart_reboot_step: 00000190 section .bss defined public -_mqtt_restart_step: 00000135 section .bss defined public -c_lcmp: 0000e785 section .text defined public -_auto_discovery_step: 000000fc section .bss defined public +c_itolx: 0000f2e7 section .text defined public +c_uitolx: 0000f5d9 section .text defined public +_memcmp: 0000f1bf section .text defined public +_strcmp: 0000f254 section .text defined public +_restart_reboot_step: 0000014f section .bss defined public +_mqtt_restart_step: 000000f5 section .bss defined public +c_lcmp: 0000f331 section .text defined public +_auto_discovery_step: 000000bc section .bss defined public _I2C_TRISER: 0000521d section absolute defined public absolute _UART2_CR4: 00005247 section absolute defined public absolute -c_divsl: 0000e7c4 section .text defined public +c_divsl: 0000f370 section .text defined public _UART2_CR5: 00005248 section absolute defined public absolute -_second_toggle: 000002a7 section .bss defined public +_second_toggle: 00000268 section .bss defined public _UART2_CR6: 00005249 section absolute defined public absolute _TIM1_IER: 00005254 section absolute defined public absolute _TIM2_IER: 00005301 section absolute defined public absolute @@ -432,7 +412,7 @@ _TIM2_CCMR1: 00005305 section absolute defined public absolute _TIM2_CCER1: 00005308 section absolute defined public absolute _TIM3_CCMR1: 00005325 section absolute defined public absolute _TIM3_CCER1: 00005327 section absolute defined public absolute -_OctetArray: 000000a8 section .bss defined public +_OctetArray: 0000007b section .bss defined public _TIM1_CCMR2: 00005259 section absolute defined public absolute _TIM1_CCER2: 0000525d section absolute defined public absolute _TIM2_CCMR2: 00005306 section absolute defined public absolute @@ -441,7 +421,7 @@ _TIM3_CCMR2: 00005326 section absolute defined public absolute _TIM1_CCMR3: 0000525a section absolute defined public absolute _TIM2_CCMR3: 00005307 section absolute defined public absolute _TIM1_CCMR4: 0000525b section absolute defined public absolute -_Port_Mqttd: 000000d8 section .bss defined public +_Port_Mqttd: 00000096 section .bss defined public _TIM1_CNTRH: 0000525e section absolute defined public absolute _TIM2_CNTRH: 0000530a section absolute defined public absolute _TIM3_CNTRH: 00005328 section absolute defined public absolute @@ -456,7 +436,7 @@ _ADC_DRL: 00005405 section absolute defined public absolute _ADC_TDRL: 00005407 section absolute defined public absolute _ADC_HTRL: 00005409 section absolute defined public absolute _ADC_LTRL: 0000540b section absolute defined public absolute -_uip_arp_out: 0000e3b6 section .text defined public +_uip_arp_out: 0000ef97 section .text defined public _TIM1_ARRL: 00005263 section absolute defined public absolute _TIM1_CCR2L: 00005268 section absolute defined public absolute _TIM2_ARRL: 0000530e section absolute defined public absolute @@ -464,149 +444,129 @@ _TIM2_CCR2L: 00005312 section absolute defined public absolute _TIM3_ARRL: 0000532c section absolute defined public absolute _TIM3_CCR2L: 00005330 section absolute defined public absolute _DM_BK2RL: 00007f95 section absolute defined public absolute -_I2C_reset: 0000a888 section .text defined public _TIM1_CCR1H: 00005265 section absolute defined public absolute _TIM2_CCR1H: 0000530f section absolute defined public absolute _TIM3_CCR1H: 0000532d section absolute defined public absolute _TIM1_CCR1L: 00005266 section absolute defined public absolute _TIM2_CCR1L: 00005310 section absolute defined public absolute _TIM3_CCR1L: 0000532e section absolute defined public absolute -c_smul: 0000e9ee section .text defined public +c_smul: 0000f59a section .text defined public _TIM1_CCR3H: 00005269 section absolute defined public absolute _TIM2_CCR3H: 00005314 section absolute defined public absolute _TIM1_CCR3L: 0000526a section absolute defined public absolute _TIM2_CCR3L: 00005314 section absolute defined public absolute _stored_pin_control: 00004052 section .eeprom defined public -_LEDcontrol: 00009482 section .text defined public -_pin_control: 000001e7 section .bss defined public -_Pending_pin_control: 000001a1 section .bss defined public -_I2C_control: 0000fc80 section .flash_update defined public +_LEDcontrol: 0000a6f8 section .text defined public +_pin_control: 000001a5 section .bss defined public +_Pending_pin_control: 00000160 section .bss defined public _TIM1_CCR4H: 0000526b section absolute defined public absolute -c_sdivx: 0000e9c9 section .text defined public +c_sdivx: 0000f575 section .text defined public _TIM1_CCR4L: 0000526c section absolute defined public absolute -_client_id: 00000157 section .bss defined public +_client_id: 00000116 section .bss defined public _TIM1_DTR: 0000526e section absolute defined public absolute _TIM4_ARR: 00005346 section absolute defined public absolute _ITC_SPR1: 00007f70 section absolute defined public absolute -_t100ms_ctr1: 00000183 section .bss defined public -_mqtt_start_ctr1: 0000013b section .bss defined public +_t100ms_ctr1: 00000142 section .bss defined public +_mqtt_start_ctr1: 000000fa section .bss defined public _ITC_SPR2: 00007f71 section absolute defined public absolute _ITC_SPR4: 00007f73 section absolute defined public absolute -c_ladd: 0000e76d section .text defined public +c_ladd: 0000f319 section .text defined public _stored_port: 0000401d section .eeprom defined public _stored_mqttport: 0000402f section .eeprom defined public -_Pending_port: 000001cc section .bss defined public -_Pending_mqttport: 000000f2 section .bss defined public -_mqttport: 000000da section .bss defined public -c_lgadd: 0000e8bf section .text defined public +_Pending_port: 0000018b section .bss defined public +_Pending_mqttport: 000000b0 section .bss defined public +_mqttport: 00000098 section .bss defined public +c_lgadd: 0000f46b section .text defined public _ITC_SPR5: 00007f74 section absolute defined public absolute -_Enc28j60Receive_throttle: 000001db section .bss defined public -_publish_outbound_throttle: 0000013a section .bss defined public _ITC_SPR6: 00007f75 section absolute defined public absolute _ITC_SPR7: 00007f76 section absolute defined public absolute -c_eewrw: 0000e6d5 section .text defined public +c_eewrw: 0000f281 section .text defined public _ITC_SPR8: 00007f77 section absolute defined public absolute +_mqtt_partial_buffer_length: 000001c0 section .bss defined public +_current_msg_length: 000001c1 section .bss defined public _DM_BK1RE: 00007f90 section absolute defined public absolute _DM_BK2RE: 00007f93 section absolute defined public absolute -_Enc28j60Receive: 000091da section .text defined public -_mqtt_keep_alive: 0000017f section .bss defined public -_emb_itoa: 00009622 section .text defined public -_wait_timer: 0000d60d section .text defined public -_uip_arp_timer: 0000e1b0 section .text defined public -_periodic_timer: 000002ad section .bss defined public -_mqtt_timer: 000002ac section .bss defined public -_t100ms_timer: 000002a9 section .bss defined public -_arp_timer: 000002aa section .bss defined public -c_ldiv: 0000e7a5 section .text defined public -___mqtt_pack_uint16: 0000d06f section .text defined public -___mqtt_unpack_uint16: 0000d093 section .text defined public -_one_wire_low: 00008d84 section .text defined public -_SDA_low: 0000fd30 section .flash_update defined public -_SCL_low: 0000fd1e section .flash_update defined public -_numROMs: 000000c4 section .bss defined public -_restore_eeprom_debug_bytes: 0000c00f section .text defined public -_First: 00008e4b section .text defined public +_Enc28j60Receive: 0000a450 section .text defined public +_mqtt_keep_alive: 0000013e section .bss defined public +_emb_itoa: 0000a7ae section .text defined public +_wait_timer: 0000e229 section .text defined public +_uip_arp_timer: 0000ed91 section .text defined public +_periodic_timer: 0000026e section .bss defined public +_mqtt_timer: 0000026d section .bss defined public +_t100ms_timer: 0000026a section .bss defined public +_arp_timer: 0000026b section .bss defined public +c_ldiv: 0000f351 section .text defined public +___mqtt_pack_uint16: 0000dc98 section .text defined public +___mqtt_unpack_uint16: 0000dcbc section .text defined public +_one_wire_low: 0000a026 section .text defined public +_numROMs: 00000086 section .bss defined public +_restore_eeprom_debug_bytes: 0000cd62 section .text defined public +_First: 0000a0c1 section .text defined public _stored_magic4: 0000402e section .eeprom defined public -_mqtt_enabled: 00000182 section .bss defined public -_reset_pulse: 00008cee section .text defined public -_SCL_pulse: 0000fd0b section .flash_update defined public +_mqtt_enabled: 00000141 section .bss defined public +_reset_pulse: 00009f90 section .text defined public c_lreg: 00000000 section .ubsct defined public zpage -_Enc28j60ReadReg: 00008f82 section .text defined public -_Enc28j60WriteReg: 00008fa2 section .text defined public -_Enc28j60SetMaskReg: 00008fb9 section .text defined public -_Enc28j60ClearMaskReg: 00008fd0 section .text defined public +_Enc28j60ReadReg: 0000a1f8 section .text defined public +_Enc28j60WriteReg: 0000a218 section .text defined public +_Enc28j60SetMaskReg: 0000a22f section .text defined public +_Enc28j60ClearMaskReg: 0000a246 section .text defined public _io_reg: 00005000 section absolute defined public absolute -c_lneg: 0000e949 section .text defined public -c_lgneg: 0000e8e4 section .text defined public +c_lneg: 0000f4f5 section .text defined public +c_lgneg: 0000f490 section .text defined public _doneFlag: 0000000b section .data defined public -_get_temperature: 00008b20 section .text defined public -_convert_temperature: 00008bd9 section .text defined public -_send_mqtt_temperature: 000000c6 section .bss defined public -_publish_temperature: 0000b6a1 section .text defined public -_new_FoundROM_crc: 0000003b section .bss defined public -_old_FoundROM_crc: 0000003a section .bss defined public -_ps: 0000852f section .const defined public -c_eewrc: 0000e6eb section .text defined public -_transmit_byte: 00008d19 section .text defined public -_FoundROM: 0000003c section .bss defined public -_ROM: 00000064 section .bss defined public -_DS18B20_scratch_byte: 00000076 section .bss defined public -_SpiWriteByte: 0000d41f section .text defined public -_SpiReadByte: 0000d488 section .text defined public -_I2C_read_byte: 0000fcc6 section .flash_update defined public -_int2nibble: 00009756 section .text defined public -_parse_complete: 0000018e section .bss defined public -_I2C_transmit_byte: 0000fd3d section .flash_update defined public -_I2C_failcode: 000000bd section .bss defined public -_eeprom_num_write: 000000b6 section .bss defined public -_I2C_write_byte: 0000a87a section .text defined public -_mqtt_parse_complete: 0000018d section .bss defined public -_upgrade_EEPROM: 0000b759 section .text defined public -_timer_update: 0000d596 section .text defined public -_publish_pinstate: 0000b532 section .text defined public -_read_bit: 00008d39 section .text defined public -_write_bit: 00008d67 section .text defined public -_Enc28j60Init: 0000907a section .text defined public -_gpio_init: 000093ff section .text defined public -_HttpDStringInit: 0000949b section .text defined public -_HttpDInit: 00009da8 section .text defined public -_clock_init: 0000d4f2 section .text defined public -_spi_init: 0000d3fa section .text defined public -_uip_arp_init: 0000e18d section .text defined public -_uip_init: 0000d740 section .text defined public -_mqtt_init: 0000c0e6 section .text defined public -_strcat: 0000e65f section .text defined public -_mqtt_mq_init: 0000cdc5 section .text defined public -_DS18B20_scratch: 0000006c section .bss defined public -c_lgursh: 0000e93b section .text defined public -c_rtol: 0000e9b1 section .text defined public -_Port_Httpd: 0000018b section .bss defined public -_init_DS18B20: 00008da0 section .text defined public -_debugflash: 0000bfb5 section .text defined public -_eeprom_copy_to_flash: 0000fd7f section .flash_update defined public -_copy_ram_to_flash: 00000012 section memcpy_update defined public -_unlock_flash: 0000b74b section .text defined public -_lock_flash: 0000b754 section .text defined public -_mqtt_publish: 0000c1e8 section .text defined public -_fastflash: 0000bfe9 section .text defined public +_get_temperature: 00009dc2 section .text defined public +_convert_temperature: 00009e7b section .text defined public +_send_mqtt_temperature: 00000088 section .bss defined public +_publish_temperature: 0000c433 section .text defined public +_transmit_byte: 00009fbb section .text defined public +_FoundROM: 00000012 section .bss defined public +_ROM: 0000003a section .bss defined public +_DS18B20_scratch_byte: 0000004c section .bss defined public +_SpiWriteByte: 0000e03b section .text defined public +_SpiReadByte: 0000e0a4 section .text defined public +_int2nibble: 0000a8e2 section .text defined public +_parse_complete: 0000014d section .bss defined public +_mqtt_parse_complete: 0000014c section .bss defined public +_upgrade_EEPROM: 0000c4dd section .text defined public +_timer_update: 0000e1b2 section .text defined public +_publish_pinstate: 0000c2c4 section .text defined public +_read_bit: 00009fdb section .text defined public +_write_bit: 0000a009 section .text defined public +_Enc28j60Init: 0000a2f0 section .text defined public +_gpio_init: 0000a675 section .text defined public +_HttpDStringInit: 0000a711 section .text defined public +_HttpDInit: 0000ad73 section .text defined public +_clock_init: 0000e10e section .text defined public +_spi_init: 0000e016 section .text defined public +_uip_arp_init: 0000ed6e section .text defined public +_uip_init: 0000e35c section .text defined public +_mqtt_init: 0000ceb2 section .text defined public +_strcat: 0000f240 section .text defined public +_mqtt_mq_init: 0000d9ee section .text defined public +_DS18B20_scratch: 00000042 section .bss defined public +c_lgursh: 0000f4e7 section .text defined public +c_rtol: 0000f55d section .text defined public +_Port_Httpd: 0000014a section .bss defined public +_init_DS18B20: 0000a042 section .text defined public +_debugflash: 0000cd08 section .text defined public +_mqtt_publish: 0000cfb2 section .text defined public +_fastflash: 0000cd3c section .text defined public __endzp: 0000000a section .ubsct defined public -_dallas_crc8: 00008f33 section .text defined public -_main: 0000a8c5 section .text defined public +_dallas_crc8: 0000a1a9 section .text defined public +_main: 0000b8ba section .text defined public __stack: 000007ff section absolute defined public absolute _ITC_SPR3: 00007f72 section absolute defined public absolute -_redefine_temp_sensors: 000000c3 section .bss defined public -c_lgadc: 0000e8af section .text defined public -_mqtt_sanity_check: 0000b294 section .text defined public -_mqtt_redefine_temp_sensors: 0000b124 section .text defined public -c_ladc: 0000e75c section .text defined public -_publish_callback: 0000b346 section .text defined public -_define_temp_sensors: 0000b146 section .text defined public -___mqtt_puback: 0000c279 section .text defined public -_exit: 00008b1e section .text defined public +c_lgadc: 0000f45b section .text defined public +_mqtt_sanity_check: 0000c023 section .text defined public +c_ladc: 0000f308 section .text defined public +_publish_callback: 0000c0d5 section .text defined public +_define_temp_sensors: 0000bed5 section .text defined public +_exit: 00009dc0 section .text defined public __vectab: 00008000 section .vector defined public _CLK_ICKR: 000050c0 section absolute defined public absolute _CLK_ECKR: 000050c1 section absolute defined public absolute _IWDG_KR: 000050e0 section absolute defined public absolute -_stack_error: 000001da section .bss defined public -__stext: 00008b17 section .text defined public -_Next: 00008e56 section .text defined public +_stack_error: 00000199 section .bss defined public +__stext: 00009db9 section .text defined public +_Next: 0000a0cc section .text defined public +_client_id_text: 000000fc section .bss defined public diff --git a/NetworkModule/.Idea_Temp/IDEA.ERR b/NetworkModule/.Idea_Temp/IDEA.ERR index ac330bc..6a4d047 100644 --- a/NetworkModule/.Idea_Temp/IDEA.ERR +++ b/NetworkModule/.Idea_Temp/IDEA.ERR @@ -51,13 +51,12 @@ uip.o: uip_arp.o: uip_tcpapphub.o: (C:\Program Files (x86)\COSMIC\FSE_Compilers\CXSTM8\lib\libisl0.sm8)memcmp.o: -(C:\Program Files (x86)\COSMIC\FSE_Compilers\CXSTM8\lib\libisl0.sm8)strcat0.o: -(C:\Program Files (x86)\COSMIC\FSE_Compilers\CXSTM8\lib\libisl0.sm8)strcmp0.o: (C:\Program Files (x86)\COSMIC\FSE_Compilers\CXSTM8\lib\libisl0.sm8)strlen0.o: +(C:\Program Files (x86)\COSMIC\FSE_Compilers\CXSTM8\lib\libisl0.sm8)strncm.o: (C:\Program Files (x86)\COSMIC\FSE_Compilers\CXSTM8\lib\libm0.sm8)fctcpy.o: (C:\Program Files (x86)\COSMIC\FSE_Compilers\CXSTM8\lib\libm0.sm8)bmulx.o: -(C:\Program Files (x86)\COSMIC\FSE_Compilers\CXSTM8\lib\libm0.sm8)cmulx.o: (C:\Program Files (x86)\COSMIC\FSE_Compilers\CXSTM8\lib\libm0.sm8)eeprom.o: +(C:\Program Files (x86)\COSMIC\FSE_Compilers\CXSTM8\lib\libm0.sm8)imul.o: (C:\Program Files (x86)\COSMIC\FSE_Compilers\CXSTM8\lib\libm0.sm8)itolx.o: (C:\Program Files (x86)\COSMIC\FSE_Compilers\CXSTM8\lib\libm0.sm8)ladc.o: (C:\Program Files (x86)\COSMIC\FSE_Compilers\CXSTM8\lib\libm0.sm8)ladd.o: @@ -65,6 +64,7 @@ uip_tcpapphub.o: (C:\Program Files (x86)\COSMIC\FSE_Compilers\CXSTM8\lib\libm0.sm8)lsdiv.o: (C:\Program Files (x86)\COSMIC\FSE_Compilers\CXSTM8\lib\libm0.sm8)ldiv.o: (C:\Program Files (x86)\COSMIC\FSE_Compilers\CXSTM8\lib\libm0.sm8)lgadc.o: +(C:\Program Files (x86)\COSMIC\FSE_Compilers\CXSTM8\lib\libm0.sm8)lgadd.o: (C:\Program Files (x86)\COSMIC\FSE_Compilers\CXSTM8\lib\libm0.sm8)lglsh.o: (C:\Program Files (x86)\COSMIC\FSE_Compilers\CXSTM8\lib\libm0.sm8)lgneg.o: (C:\Program Files (x86)\COSMIC\FSE_Compilers\CXSTM8\lib\libm0.sm8)lgor.o: @@ -77,10 +77,7 @@ uip_tcpapphub.o: (C:\Program Files (x86)\COSMIC\FSE_Compilers\CXSTM8\lib\libm0.sm8)lumod.o: (C:\Program Files (x86)\COSMIC\FSE_Compilers\CXSTM8\lib\libm0.sm8)lzmp.o: (C:\Program Files (x86)\COSMIC\FSE_Compilers\CXSTM8\lib\libm0.sm8)rtol.o: -(C:\Program Files (x86)\COSMIC\FSE_Compilers\CXSTM8\lib\libm0.sm8)sdivx.o: (C:\Program Files (x86)\COSMIC\FSE_Compilers\CXSTM8\lib\libm0.sm8)smul.o: -(C:\Program Files (x86)\COSMIC\FSE_Compilers\CXSTM8\lib\libm0.sm8)utol.o: (C:\Program Files (x86)\COSMIC\FSE_Compilers\CXSTM8\lib\libm0.sm8)utolx.o: -(C:\Program Files (x86)\COSMIC\FSE_Compilers\CXSTM8\lib\libm0.sm8)umul.o: (C:\Program Files (x86)\COSMIC\FSE_Compilers\CXSTM8\lib\libm0.sm8)xreg.o: (C:\Program Files (x86)\COSMIC\FSE_Compilers\CXSTM8\lib\libm0.sm8)yreg.o: diff --git a/NetworkModule/.Idea_Temp/IDEABLD.BAT b/NetworkModule/.Idea_Temp/IDEABLD.BAT index 6bdb2ce..323ae2c 100644 --- a/NetworkModule/.Idea_Temp/IDEABLD.BAT +++ b/NetworkModule/.Idea_Temp/IDEABLD.BAT @@ -1,5 +1,5 @@ REM COMMAND FILE BUILT BY IDEA -REM Wed Nov 09 11:24:39 2022 +REM Mon Nov 28 19:28:25 2022 REM cxstm8 -v -l +strict +debug +modsl0 +split +warn "networkmodule_vector.c" cxstm8 -v -l +strict +debug +modsl0 +split +warn "ds18b20.c" "enc28j60.c" "gpio.c" "httpd.c" "i2c.c" "main.c" "mqtt.c" "mqtt_pal.c" "spi.c" "timer.c" "uart.c" "uip.c" "uip_arp.c" "uip_tcpapphub.c" diff --git a/NetworkModule/DS18B20.c b/NetworkModule/DS18B20.c index 3c144d1..5cc7ac4 100644 --- a/NetworkModule/DS18B20.c +++ b/NetworkModule/DS18B20.c @@ -90,11 +90,11 @@ uint8_t FoundROM[5][8]; // Table of ROM codes // [x][7] = CRC extern int numROMs; // Count of DS18B20 devices found -uint8_t new_FoundROM_crc; // Used in calculation of the CRC for +// uint8_t new_FoundROM_crc; // Used in calculation of the CRC for // the FoundROM table. Used to determine // if a table change has occurred. -uint8_t old_FoundROM_crc; // Stores the prior FoundROM table CRC. -extern uint8_t redefine_temp_sensors; // Flag used to signal the need +// uint8_t old_FoundROM_crc; // Stores the prior FoundROM table CRC. +// extern uint8_t redefine_temp_sensors; // Flag used to signal the need // to redefine the HA temp sensors // via Auto Discovery messages @@ -579,9 +579,9 @@ void one_wire_low(int wait) void init_DS18B20(void) { // Initialize variables used in DS18B20 operation - new_FoundROM_crc = 0; - old_FoundROM_crc = 0; - redefine_temp_sensors = 0; +// new_FoundROM_crc = 0; +// old_FoundROM_crc = 0; +// redefine_temp_sensors = 0; // Initialize temperature sensor arrays memset(&DS18B20_scratch[0][0], 0, 10); memset(&FoundROM[0][0], 0, 40); @@ -635,14 +635,14 @@ void FindDevices(void) } // Add up the crc values for each entry to act as a CRC for the FoundROM // table - new_FoundROM_crc = (uint8_t)(FoundROM[0][7] + FoundROM[1][7] + FoundROM[2][7] + FoundROM[3][7] + FoundROM[4][7]); +// new_FoundROM_crc = (uint8_t)(FoundROM[0][7] + FoundROM[1][7] + FoundROM[2][7] + FoundROM[3][7] + FoundROM[4][7]); - if (new_FoundROM_crc != old_FoundROM_crc) { +// if (new_FoundROM_crc != old_FoundROM_crc) { // Signal the main loop that the temp sensors need to be updated in the // Browser display and over MQTT - redefine_temp_sensors = 1; - old_FoundROM_crc = new_FoundROM_crc; - } +// redefine_temp_sensors = 1; +// old_FoundROM_crc = new_FoundROM_crc; +// } } diff --git a/NetworkModule/Enc28j60.c b/NetworkModule/Enc28j60.c index 0909f18..566e23b 100644 --- a/NetworkModule/Enc28j60.c +++ b/NetworkModule/Enc28j60.c @@ -712,6 +712,15 @@ UARTPrintf("Enc28j60Receive MAXFRAME exceeded\r\n"); // And decrement PacketCounter Enc28j60SetMaskReg(BANKX_ECON2 , (1< 500) { +UARTPrintf("Enc28j60Received nBytes = "); +emb_itoa(nBytes, OctetArray, 10, 3); +UARTPrintf(OctetArray); +UARTPrintf("\r\n"); +} +#endif // DEBUG_SUPPORT != 11 return nBytes; } diff --git a/NetworkModule/Enc28j60.h b/NetworkModule/Enc28j60.h index f2a16a1..af78375 100644 --- a/NetworkModule/Enc28j60.h +++ b/NetworkModule/Enc28j60.h @@ -77,6 +77,8 @@ #define ENC28J60_LEDB 12 // Maximum frame length in bytes to prevent possible buffer overflows +// The factor pushing the MAXFRAME is the size of the largest Home Assistant +// Config message plus headers. // #define ENC28J60_MAXFRAME 500 #define ENC28J60_MAXFRAME 550 diff --git a/NetworkModule/Gpio.c b/NetworkModule/Gpio.c index c39ec3d..ed77f07 100644 --- a/NetworkModule/Gpio.c +++ b/NetworkModule/Gpio.c @@ -47,9 +47,9 @@ extern uint8_t stored_pin_control[16]; // Per pin control settings stored in // clever implementation. // Ccreate a variable with the structure of the port registers and define -// it's position on the memory location of the port registers -// this way we can manipulate this data as an array of ports -volatile struct io_registers io_reg[ NUM_PORTS ] @0x5000; // make room for PA .. PG starting at 0x5000 +// its position on the memory location of the port registers. This way we +// can manipulate this data as an array of ports. +volatile struct io_registers io_reg[ NUM_PORTS ] @0x5000; // Make room for PA .. PG starting at 0x5000 // Define the pair PORT:BIT for each of the 16 I/Os const struct io_mapping io_map[16] = { diff --git a/NetworkModule/Main.c b/NetworkModule/Main.c index 19b0a0e..43d60ed 100644 --- a/NetworkModule/Main.c +++ b/NetworkModule/Main.c @@ -51,7 +51,8 @@ //---------------------------------------------------------------------------// //---------------------------------------------------------------------------// //---------------------------------------------------------------------------// -const char code_revision[] = "20221109 0109"; // Normal Release Revision +// IMPORTANT: The code_revision must be exactly 13 characters +const char code_revision[] = "20221127 0000"; // Normal Release Revision // const char code_revision[] = "20210529 1999"; // Browser Only test build // const char code_revision[] = "20210529 2999"; // MQTT test build // const char code_revision[] = "20210531 CU01"; // Code Uploader test build @@ -194,8 +195,6 @@ uint16_t Invert_word; // Invert state of pins in single 16 bit // word uint8_t state_request; // Indicates that a PUBLISH state // request was received -uint8_t Enc28j60Receive_throttle; // Used to throttle receipt of packets - // from the Enc28j60 device. uint8_t stack_error; // Stack error flag storage @@ -266,8 +265,6 @@ char client_id_text[26]; // Client ID comprised of text uint8_t mqtt_start; // Tracks the MQTT startup steps uint8_t mqtt_start_ctr1; // Tracks time for the MQTT startup // steps -uint8_t publish_outbound_throttle; // Used to throttle calls to the - // publish_outbound function. uint8_t verify_count; // Used to limit the number of ARP and // TCP verify attempts uint8_t mqtt_sanity_ctr; // Tracks time for the MQTT sanity steps @@ -343,7 +340,7 @@ uint8_t MQTT_broker_dis_counter; // Counts broker disconnect events in // DS18B20 variables uint32_t check_DS18B20_ctr; // Counter used to trigger temperature // measurements -uint32_t check_DS18B20_sensor_ctr; // Counter used to trigger temperature +// uint32_t check_DS18B20_sensor_ctr; // Counter used to trigger temperature // sensor add/delete checks // uint8_t DS18B20_scratch[5][2]; // Stores the temperature measurement for the // // DS18B20s @@ -373,7 +370,7 @@ extern uint8_t FoundROM[5][8]; // Table of found ROM codes // // [x][6] = MSByte serial number // // [x][7] = CRC -uint8_t redefine_temp_sensors; // Used to trigger the temperature sensor +// uint8_t redefine_temp_sensors; // Used to trigger the temperature sensor // update process in the Browser display and // in MQTT // #endif // BUILD_SUPPORT == BROWSER_ONLY_BUILD || BUILD_SUPPORT == MQTT_BUILD @@ -413,6 +410,7 @@ int main(void) { uip_ipaddr_t IpAddr; uint8_t flash_mismatch; + extern uint16_t uip_slen; parse_complete = 0; reboot_request = 0; @@ -421,7 +419,6 @@ int main(void) t100ms_ctr1 = 0; restart_reboot_step = RESTART_REBOOT_IDLE; stack_error = 0; - Enc28j60Receive_throttle = 0; #if IWDG_ENABLE == 1 init_IWDG(); // Initialize the hardware watchdog @@ -436,8 +433,6 @@ int main(void) mqtt_keep_alive = 60; // Ping interval in seconds mqtt_start_ctr1 = 0; // Tracks time for the MQTT startup // steps - publish_outbound_throttle = 0; // Used to throttle calls to the - // publish_outbound function. mqtt_sanity_ctr = 0; // Tracks time for the MQTT sanity // steps mqtt_restart_step = MQTT_RESTART_IDLE; // Step counter for MQTT restart @@ -559,7 +554,7 @@ int main(void) // Iniialize DS18B20 timer check_DS18B20_ctr = second_counter; // Initialize DS18B20 sensor add/delete check counter - check_DS18B20_sensor_ctr = second_counter; +// check_DS18B20_sensor_ctr = second_counter; // Collect initial temperature get_temperature(); // Iniialize DS18B20 transmit control variable @@ -743,59 +738,36 @@ int main(void) IWDG_KR = 0xaa; // Prevent the IWDG hardware watchdog from firing. If the // processor hangs the IWDG will perform a hardware reset. - if (Enc28j60Receive_throttle == 25) { - // The Enc28j60Receive_throttle was implemented when QOS 1 was - // introduced in the MQTT code. This was needed to prevent a burst of - // incoming PUBLISH messages from so fully occupying the uip_buf that - // no outgoing messages from MQTT could be sent during the burst. - // Timing note: The main loop runs in about 1ms, so the throttle value - // will delay extracting messages from the ENC28J60 by 100ms for a - // throttle value of 100. - // The ENC28J60 is set up for a receive buffer of 6KB (see ENC28J60.h). - // The ENC28J60 buffer size should be more than enough to hold all - // messages that are received in a burst (say from a Home Assistant - // "Toggle" operation) until they can be processed, assuming the burst - // isn't repeated at a rapid rate. A PUBLISH message in a "Toggle" burst - // will be about 88 bytes, consisting of 54 bytes LLH/TCPIP headers and - // about 34 bytes MQTT PUBLISH message. A burst of 16 PUBLISH messages - // from HA thus requires about 1400 bytes in the ENC28J60 receive - // buffer. - // IMPORTANT: Analysis of all messages being received by the Network - // Module shows that there is a lot of traffic on a typical Ethernet - // cable that makes it through the ENC28J60 filters and needs to be - // dispositioned by the uip.c code. For example: - // - ARP pings - // - ICMP traffic - // - Messages that match the MAC address, but not the IP address - // - Messages that match MAC and IP, but are not a valid Port - // - Other miscellaneous traffic that is discarded - // I have no idea where most of the above traffic originates, but it all - // occupies processing and buffer memory in addition to the genuine - // application traffic of interest. SO - throttles need to be large - // enough to allow enough message processing time, but small enough to - // prevent buffer over-runs. - // - // SOME EXPERIMENTATION COULD BE DONE HERE TO SEE HOW SMALL THE THROTTLE - // VALUE CAN BE MADE AND STILL HAVE RELIABLE LONG TERM OPERATION. - uip_len = Enc28j60Receive(uip_buf); // Check for incoming packets - Enc28j60Receive_throttle = 0; - } - else Enc28j60Receive_throttle++; + // The ENC28J60 is set up for a receive buffer of 6KB (see ENC28J60.h). + // The ENC28J60 buffer size should be more than enough to hold all + // messages that are received in a burst (say from a Home Assistant + // "Toggle" operation) until they can be processed, assuming the burst + // isn't repeated at a rapid rate. A PUBLISH message in a Home Assistant + // Header Toggle burst will be about 88 bytes, consisting of 54 bytes + // LLH/TCPIP headers and about 34 bytes MQTT PUBLISH message. A burst of + // 16 PUBLISH messages from HA thus requires about 1400 bytes in the + // ENC28J60 receive buffer. + // + // IMPORTANT: Analysis of all messages being received by the Network + // Module shows that there is a lot of traffic on a typical Ethernet + // cable that makes it through the ENC28J60 filters and needs to be + // dispositioned by the uip.c code. For example: + // - ARP pings + // - ICMP traffic + // - Messages that match the MAC address, but not the IP address + // - Messages that match MAC and IP, but are not a valid Port + // - Other miscellaneous traffic that is discarded + // I have no idea where most of the above traffic originates, but it all + // occupies processing and buffer memory in addition to the genuine + // application traffic of interest. + + uip_len = Enc28j60Receive(uip_buf); // Check for incoming packets if (uip_len > 0) { - // This code is executed if incoming traffic is HTTP or MQTT (not ARP). - // uip_len includes the headers, so it will be > 0 even if no TCP - // payload. if (((struct uip_eth_hdr *) & uip_buf[0])->type == htons(UIP_ETHTYPE_IP)) { - -#if DEBUG_SUPPORT != 11 -// UARTPrintf("Detected uip_len > 0 UIP_ETHTYPE_IP\r\n"); -// UARTPrintf("uip_len = "); -// emb_itoa(uip_len, OctetArray, 10, 5); -// UARTPrintf(OctetArray); -// UARTPrintf("\r\n"); -#endif // DEBUG_SUPPORT != 11 - + // This code is executed if incoming traffic is HTTP or MQTT (not ARP). + // uip_len includes the headers, so it will be > 0 even if no TCP + // payload. uip_input(); // Calls uip_process(UIP_DATA) to process a received // packet. // If the above process resulted in data that should be sent out on @@ -811,9 +783,7 @@ int main(void) } } else if (((struct uip_eth_hdr *) & uip_buf[0])->type == htons(UIP_ETHTYPE_ARP)) { -// #if DEBUG_SUPPORT != 11 -// UARTPrintf("Detected uip_len > 0 UIP_ETHTYPE_ARP\r\n"); -// #endif // DEBUG_SUPPORT != 11 + // This code is executed if incoming traffic is an ARP request. uip_arp_arpin(); // If the above process resulted in data that should be sent out on // the network the global variable uip_len will have been set to a @@ -847,7 +817,6 @@ int main(void) if (mqtt_enabled && mqtt_start == MQTT_START_COMPLETE && restart_reboot_step == RESTART_REBOOT_IDLE) { -// mqtt_sanity_check(); mqtt_sanity_check(&mqttclient); } @@ -857,77 +826,33 @@ int main(void) // b) Not currently performing MQTT startup // c) Not currently performing restart_reboot // d) Redefine temp sensors is requested - if (mqtt_enabled - && mqtt_start == MQTT_START_COMPLETE - && restart_reboot_step == RESTART_REBOOT_IDLE - && redefine_temp_sensors) { - mqtt_redefine_temp_sensors(); - } +// XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +// XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +// XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +// XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +// XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +// XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +// THIS PROBABLY NEEDS TO BE DISABLED. THE VERY LARGE UIP_BUF IS NOT +// AVAILABLE AFTER COMPLETION OF MQTT STARTUP, SO TEMPERATURE SENSOR +// DEFINES CAN ONLY BE SENT TO HA DURING BOOT. +// if (mqtt_enabled +// && mqtt_start == MQTT_START_COMPLETE +// && restart_reboot_step == RESTART_REBOOT_IDLE +// && redefine_temp_sensors) { +// mqtt_redefine_temp_sensors(); +// } +// XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +// XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +// XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +// XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +// XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +// XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +// XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX #endif // BUILD_SUPPORT == MQTT_BUILD // Update the time keeping function timer_update(); - if (periodic_timer_expired()) { - // The periodic timer expires every 20ms. - { - int i; - for(i = 0; i < UIP_CONNS; i++) { - uip_periodic(i); - // uip_periodic() calls uip_process(UIP_TIMER) for each connection. - // Every connection is checked in this loop one time. - // uip_process(UIP_TIMER) will check the HTTP and MQTT connections - // for any unserviced outbound traffic one packet at a time. - // HTTP connections (the webbrowser) will generate and place its - // data in the uip_buf via a call to HttpDCall(). HTTP connections - // can have pending transmissions which are continuations of a - // series of packets because the web pages can be broken into - // several packets. - // MQTT will always use this function to transmit packets. MQTT - // will have placed its outbound packets in the mqtt_sendbuf. MQTT - // connections will consist of a complete message in one packet. - // - // If uip_periodic() resulted in data that should be sent out on - // the network the global variable uip_len will have been set to a - // value > 0 so that Enc28j60Send() will be called. - // - // Note that when the device first powers up and MQTT is enabled the - // MQTT processes will attempt to send a SYN to create a TCP - // connection. The uip_periodic() function discovers the SYN is - // pending to be sent, causing uip_len to be > 0. Below you'll see - // that uip_arp_out() is called first, and on the first pass it will - // find that an ARP request is needed. The SYN will be replaced with - // an ARP request, and on a future cycle through this routine the - // SYN will be sent IF the ARP request was successful. - // - // Note: From time to time I see a lot of re-xmit attempts with the - // Browser interface. This doesn't seem to hurt anything so far, but - // it does slow down painting of a Browser page. I suspect the - // timeout for uip_periodic() may be too short. On the otherhand, - // shorter is better for servicing MQTT. So, it is a compromise but - // might need examination in the future it it become problematic. - if (uip_len > 0) { - uip_arp_out(); // Verifies arp entry in the ARP table and builds - // the LLH - Enc28j60Send(uip_buf, uip_len); - } - } - } - } - - - // 100ms timer - if (t100ms_timer_expired()) { - t100ms_ctr1++; // Increment the 100ms counter. ctr1 is used in the - // restart/reboot process. Normally the counter is - // not used and will just roll over every 2^32 - // counts. Any code that uses crt1 should reset it to - // zero then compare to a value needed for a timeout. -#if BUILD_SUPPORT == BROWSER_ONLY_BUILD - decrement_pin_timers(); // Decrement the pin_timers every 100ms -#endif // BUILD_SUPPORT == BROWSER_ONLY_BUILD - } - #if BUILD_SUPPORT == MQTT_BUILD // If the MQTT timer expires (50ms) @@ -943,38 +868,14 @@ int main(void) if (mqtt_timer_expired()) { if (mqtt_enabled) { if (mqtt_start == MQTT_START_COMPLETE) { - if (publish_outbound_throttle == 0) { - // publish_outbound() is called to send pin_control state change - // PUBLISH messages. Due to the small size of the mqtt_sendbuf the - // rate at which theses messages are placed in the mqtt_sendbuf - // needs to be throttled so it can be assured that a message - // has time to be transmitted before another is placed in the - // mqtt_sendbuf, also leaving time for other transmit messages - // (for example "ping" messages and PUBACK messages). - // During implementation of QOS 1 the "publish_outbound_throttle" - // was implemented to allow even more time for these transmit - // processes if necessary. - // A setting of "0" allows 50ms between calls to publish_outbound(). - // 50ms is the mqtt_time_expired() interval). This seems to be - // adequate at this writing. Each incremental increase in the - // publish_outbound_throttle test adds another 50ms: - // "== 0" is 50ms interval - // "== 1" is 100ms - // "== 2" is 150ms - // and so on. - // For future reference this throttle was implemented during test - // of the Home Assistant "Toggle" function, wherein a large burst - // of incoming PUBLISH messages would occur. There is the need to - // assure enough processing gaps to accomodate messages that need - // to pass through the very small mqtt_sendbuf, which then gets - // emptied through the uip_buf. The process is problematic because - // the uip_buf is also used for all incoming PUBLISH messages. - // IF IT TURNS OUT THIS THROTTLE NEVER NEED TO BE INCREASED THE - // CODE COULD BE SIMPLIFIED A LITTLE BY ELIMINATING IT. - publish_outbound(); - publish_outbound_throttle = 0; - } - else publish_outbound_throttle++; + // publish_outbound() is called to send pin_control state change + // PUBLISH messages. + publish_outbound(); + // Call the periodic_service() function to clear out the MQTT + // traffic just now placed in the uip_buf. Even though there is + // a period9ic_service() call in the main loop we don't want to + // wait for its timer to expire for MQTT service. + periodic_service(); } mqtt_start_ctr1++; // Increment the MQTT start loop timer 1. This is // used to: @@ -996,6 +897,26 @@ int main(void) #endif // BUILD_SUPPORT == MQTT_BUILD + if (periodic_timer_expired()) { + // The periodic timer expires every 20ms. + // Call the periodic_service() function + periodic_service(); + } + + + // 100ms timer + if (t100ms_timer_expired()) { + t100ms_ctr1++; // Increment the 100ms counter. ctr1 is used in the + // restart/reboot process. Normally the counter is + // not used and will just roll over every 2^32 + // counts. Any code that uses crt1 should reset it to + // zero then compare to a value needed for a timeout. +#if BUILD_SUPPORT == BROWSER_ONLY_BUILD + decrement_pin_timers(); // Decrement the pin_timers every 100ms +#endif // BUILD_SUPPORT == BROWSER_ONLY_BUILD + } + + #if BUILD_SUPPORT == CODE_UPLOADER_BUILD // Check for a request to copy the Off-Board EEPROM0 to Flash. // The request is automatically generated by the process that uploads the @@ -1091,12 +1012,12 @@ int main(void) // Check for DS18B20 temperature sensor additions/deletions at 10s // intervals - if ((stored_config_settings & 0x08) && (second_counter > (check_DS18B20_sensor_ctr + 10))) { - check_DS18B20_sensor_ctr = second_counter; +// if ((stored_config_settings & 0x08) && (second_counter > (check_DS18B20_sensor_ctr + 10))) { +// check_DS18B20_sensor_ctr = second_counter; // Call FindDevices to generate a new FoundROM table and determine if // any changes occured in the sensor population. - FindDevices(); - } +// FindDevices(); +// } // Update temperature data @@ -1130,6 +1051,57 @@ int main(void) } +void periodic_service(void) +{ + int i; + for(i = 0; i < UIP_CONNS; i++) { + uip_periodic(i); + // uip_periodic() calls uip_process(UIP_TIMER) for each connection. + // Every connection is checked in this loop one time. + // uip_process(UIP_TIMER) will check the HTTP and MQTT connections + // for any unserviced outbound traffic one packet at a time. + // HTTP connections (the webbrowser) will generate and place its + // data in the uip_buf via a call to HttpDCall(). HTTP connections + // can have pending transmissions which are continuations of a + // series of packets because the web pages can be broken into + // several packets. + // MQTT will always use this function to transmit packets. MQTT + // will have placed its outbound packets in the mqtt_sendbuf. MQTT + // connections will consist of a complete message in one packet. + // + // If uip_periodic() resulted in data that should be sent out on + // the network the global variable uip_len will have been set to a + // value > 0 so that Enc28j60Send() will be called. + // + // Note that when the device first powers up and MQTT is enabled the + // MQTT processes will attempt to send a SYN to create a TCP + // connection. The uip_periodic() function discovers the SYN is + // pending to be sent, causing uip_len to be > 0. Below you'll see + // that uip_arp_out() is called first, and on the first pass it will + // find that an ARP request is needed. The SYN will be replaced with + // an ARP request, and on a future cycle through this routine the + // SYN will be sent IF the ARP request was successful. + // + // Note: From time to time I see a lot of re-xmit attempts with the + // Browser interface. This doesn't seem to hurt anything so far, but + // it does slow down painting of a Browser page. I suspect the + // timeout for uip_periodic() may be too short. On the otherhand, + // shorter is better for servicing MQTT. So, it is a compromise but + // might need examination in the future it it become problematic. + if (uip_len > 0) { + +// #if DEBUG_SUPPORT != 11 +// UARTPrintf("periodic_service now transmitting uip_buf\r\n"); +// #endif // DEBUG_SUPPORT != 11 + + uip_arp_out(); // Verifies arp entry in the ARP table and builds + // the LLH + Enc28j60Send(uip_buf, uip_len); + } + } +} + + #if OB_EEPROM_SUPPORT == 1 uint8_t off_board_EEPROM_detect(void) { @@ -1533,8 +1505,14 @@ void mqtt_startup(void) mqtt_init(&mqttclient, mqtt_sendbuf, sizeof(mqtt_sendbuf), +#if NAGLE_SUPPORT == 0 &uip_buf[UIP_IPTCPH_LEN + UIP_LLH_LEN], UIP_APPDATA_SIZE, +#endif // NAGLE_SUPPORT == 0 +#if NAGLE_SUPPORT == 1 + &uip_buf[MQTT_PBUF], + MQTT_PBUF_SIZE, +#endif // NAGLE_SUPPORT == 1 publish_callback); mqtt_start_ctr1 = 0; // Clear 50ms counter mqtt_start = MQTT_START_QUEUE_CONNECT; @@ -1625,7 +1603,6 @@ void mqtt_startup(void) } break; -#if QOS_SUPPORT == 0 case MQTT_START_QUEUE_SUBSCRIBE1: if (mqtt_start_ctr1 > 4) { // Subscribe to the output control messages @@ -1637,9 +1614,6 @@ void mqtt_startup(void) // mqtt_sendbuf queue. uip_periodic() will start the process that will // call mqtt_sync to put the message in the uip_buf. // - // In the mqtt_subscribe call the maximum QOS level supported is specified - // as 0. - // // Note: Timing is managed here to prevent placing multiple SUBSCRIBE // messages in the mqtt_sendbuf as that buffer is very small. @@ -1647,41 +1621,15 @@ void mqtt_startup(void) strcpy(topic_base, devicetype); strcat(topic_base, stored_devicename); strcat(topic_base, "/output/+/set"); + // In the mqtt_subscribe call the maximum QOS level spedified (0 in this + // case) is the max QOS level supported for the topic messages being + // subcribed to. The SUBSCRIBE itself has no QOS level as a special + // SUBACK message must be returned to verify the SUBSCRIBE transaction. mqtt_subscribe(&mqttclient, topic_base, 0); mqtt_start_ctr1 = 0; // Clear 50ms counter mqtt_start = MQTT_START_VERIFY_SUBSCRIBE1; } break; -#endif // QOS_SUPPORT == 0 - -#if QOS_SUPPORT == 1 - case MQTT_START_QUEUE_SUBSCRIBE1: - if (mqtt_start_ctr1 > 4) { - // Subscribe to the output control messages - // - // Queue the mqtt_subscribe messages for transmission to the MQTT Broker. - // Wait 200ms before queueing first Subscribe msg. - // - // The mqtt_subscribe function will create the message and put it in the - // mqtt_sendbuf queue. uip_periodic() will start the process that will - // call mqtt_sync to put the message in the uip_buf. - // - // In the mqtt_subscribe call the maximum QOS level supported is specified - // as 1 for HA compatibility. - // - // Note: Timing is managed here to prevent placing multiple SUBSCRIBE - // messages in the mqtt_sendbuf as that buffer is very small. - - suback_received = 0; - strcpy(topic_base, devicetype); - strcat(topic_base, stored_devicename); - strcat(topic_base, "/output/+/set"); - mqtt_subscribe(&mqttclient, topic_base, 1); - mqtt_start_ctr1 = 0; // Clear 50ms counter - mqtt_start = MQTT_START_VERIFY_SUBSCRIBE1; - } - break; -#endif // QOS_SUPPORT == 1 case MQTT_START_VERIFY_SUBSCRIBE1: // Verify that the SUBSCRIBE SUBACK was received. @@ -1706,29 +1654,10 @@ void mqtt_startup(void) } break; - -#if QOS_SUPPORT == 0 - case MQTT_START_QUEUE_SUBSCRIBE2: - if (mqtt_start_ctr1 > 4) { - // Subscribe to the state-req message - // - // Wait 200ms before queuing the Subscribe message - suback_received = 0; - strcpy(topic_base, devicetype); - strcat(topic_base, stored_devicename); - strcat(topic_base, "/state-req"); - mqtt_subscribe(&mqttclient, topic_base, 0); - mqtt_start_ctr1 = 0; // Clear 50ms counter - mqtt_start = MQTT_START_VERIFY_SUBSCRIBE2; - } - break; -#endif // QOS_SUPPORT == 0 - -#if QOS_SUPPORT == 1 case MQTT_START_QUEUE_SUBSCRIBE2: if (mqtt_start_ctr1 > 4) { // Subscribe to the state-req message - // This Subscribe is at QOS 0 + // The QOS is 0 for this topic subscription // // Wait 200ms before queuing the Subscribe message suback_received = 0; @@ -1740,7 +1669,6 @@ void mqtt_startup(void) mqtt_start = MQTT_START_VERIFY_SUBSCRIBE2; } break; -#endif // QOS_SUPPORT == 1 case MQTT_START_VERIFY_SUBSCRIBE2: // Verify that the SUBSCRIBE SUBACK was received. @@ -1781,21 +1709,22 @@ void mqtt_startup(void) // Publish Home Assistant Auto Discovery messages // This part of the state machine runs only if Home Assistant Auto // Discovery is enabled. - // This step of the state machine is entered multiple times until all - // Home Assistant Auto Discovery Publish messages are sent. + // This step of the state machine is executed every 150 ms and is + // entered multiple times until all Home Assistant Auto Discovery + // Config PUBLISH messages are sent. // //---------------------------------------------------------------------// - // This function will create a "placeholder" Publish message. The - // placeholder message contains special markers that need to be - // replaced later with more extensive text fields required in the - // actual Publish message. The mqtt_pal.c function will detect the - // placeholder Publish message during the "copy to uip_buf" process - // and will replace the special markers at that time to create the - // actual Publish message required by Home Assistant. This complication - // is necessary because the MQTT transmit buffer (mqtt_sendbuf) is not - // large enough to contain an entire Auto Discovery Publish message, so - // it is constructed on-the-fly as the app_message is written to the - // uip_buf transmit buffer by the mqtt_pal.c function. + // This function will create a "placeholder" PUBLISH message. The + // required PUBLISH messages are too large to fit in the mqtt_sendbuf + // so a placeholder message is created instead. The placeholder message + // contains special markers that need to be replaced later with more + // extensive text fields that are required in the actual Publish + // message. The mqtt_pal.c function will detect the placeholder Publish + // message during the "copy to uip_buf" process and will replace the + // special markers "on the fly" to create the actual PUBLISH message + // required by Home Assistant. + // + // These messages are always PUBLISHed with QOS 0 // // The following placeholder Publish message will create an Output Auto // Discovery message. "xx" is the output IO number. @@ -1958,9 +1887,8 @@ void mqtt_startup(void) case MQTT_START_QUEUE_PUBLISH_ON: if (mqtt_start_ctr1 > 4) { - // Wait 200ms before queuing Publish message - // Publish the availability "online" message - // This message is always published with QOS 0 + // Wait 200ms before queuing the "availability online" PUBLISH message. + // This message is always published with QOS 0. strcpy(topic_base, devicetype); strcat(topic_base, stored_devicename); strcat(topic_base, "/availability"); @@ -1990,7 +1918,7 @@ void mqtt_startup(void) } // end switch } - +/* void mqtt_redefine_temp_sensors(void) { // This routine can be called during runtime (ie, AFTER initialization) to @@ -2011,7 +1939,7 @@ void mqtt_redefine_temp_sensors(void) } } } - +*/ void define_temp_sensors(void) { @@ -2176,9 +2104,9 @@ void mqtt_sanity_check(struct mqtt_client *client) client->number_of_timeouts = 0; MQTT_resp_tout_counter++; -#if DEBUG_SUPPORT != 11 -UARTPrintf("mqtt_sanity_check Response Timeout\r\n"); -#endif // DEBUG_SUPPORT != 11 +// #if DEBUG_SUPPORT != 11 +// UARTPrintf("mqtt_sanity_check Response Timeout\r\n"); +// #endif // DEBUG_SUPPORT != 11 mqtt_restart_step = MQTT_RESTART_BEGIN; } @@ -2192,9 +2120,9 @@ UARTPrintf("mqtt_sanity_check Response Timeout\r\n"); && mqtt_conn->tcpstateflags == UIP_CLOSED) { MQTT_broker_dis_counter++; -#if DEBUG_SUPPORT != 11 -UARTPrintf("mqtt_sanity_check Broker Disconnect\r\n"); -#endif // DEBUG_SUPPORT != 11 +// #if DEBUG_SUPPORT != 11 +// UARTPrintf("mqtt_sanity_check Broker Disconnect\r\n"); +// #endif // DEBUG_SUPPORT != 11 mqtt_restart_step = MQTT_RESTART_BEGIN; } @@ -2206,11 +2134,21 @@ UARTPrintf("mqtt_sanity_check Broker Disconnect\r\n"); && client->error != MQTT_OK) { MQTT_not_OK_counter++; + #if DEBUG_SUPPORT != 11 -UARTPrintf("mqtt_sanity_check MQTT_not_OK - Error code:"); -emb_itoa(client->error, OctetArray, 16, 4); +// MQTT not OK values are all negative numbers from 0x8000 to 0x801c. +// For debug display strip the first 4 bits, convert the remaining bits +// using emb_itoa (as it can only handle positive numbers), then rebuild +// the code for display. +{ +int16_t temp1; +UARTPrintf("mqtt_sanity_check MQTT_not_OK - Error code: 0x"); +temp1 = client->error & 0x00ff; +emb_itoa(temp1, OctetArray, 16, 4); +OctetArray[0] = '8'; UARTPrintf(OctetArray); UARTPrintf("\r\n"); +} #endif // DEBUG_SUPPORT != 11 mqtt_restart_step = MQTT_RESTART_BEGIN; @@ -2327,14 +2265,22 @@ UARTPrintf("\r\n"); // the transmission as part of the uip_periodic function. // // The only messages that must be retained in the mqtt_sendbuf are the - // CONNECT, SUBSCRIBE, and PINGREQ messages. Since the CONNECT and SUBSCRIBE - // messages are only sent by the mqtt_startup state machine we can carefully - // manage that state machine to make sure the ACK for each of those messages - // is received before continuing the state machine. This means that the only - // message that will be retained in the mqtt_sendbuf during normal operation - // is the PINGREQ message. That message is two bytes long. So, we can - // minimize the size of the mqtt_sendbuf to the point that only that 2 byte - // message and the longest of any other MQTT transmit message will fit. + // CONNECT, SUBSCRIBE, and PINGREQ messages. + // Since the CONNECT and SUBSCRIBE messages are only sent by the mqtt_startup + // state machine we can carefully manage that state machine to make sure the + // ACK for each of those messages is received before continuing the state + // machine. This means that the only messages that will be retained in the + // mqtt_sendbuf during normal operation are the PINGREQ messages. PINGREQ + // messages are only two bytes long. So, we can minimize the size of the + // mqtt_sendbuf to the point that only a 2 byte message and the longest of + // any other MQTT transmit message will fit. + // + // The mqtt_sendbuf always starts with a 12 byte Message Queue structure. + // + // PINGREQ Msg (in the mqtt_sendbuf) + // Fixed Header 2 bytes + // Queued Message Header 11 bytes + // Total: 13 bytes // // Output PUBLISH Msg (in the mqtt_sendbuf) // Fixed Header 2 bytes @@ -2342,7 +2288,8 @@ UARTPrintf("\r\n"); // Topic NetworkModule/DeviceName012345678/output/xx 43 bytes // Topic Length 2 bytes // Packet ID 2 bytes - // Total: 49 bytes + // Queued Message Header 11 bytes + // Total: 60 bytes // // Temperature PUBLISH Msg (in the mqtt_sendbuf) // Fixed Header 2 bytes @@ -2350,7 +2297,8 @@ UARTPrintf("\r\n"); // Topic NetworkModule/DeviceName012345678/temp/xx-000.0 47 bytes // Topic Length 2 bytes // Packet ID 2 bytes - // Total: 53 bytes + // Queued Message Header 11 bytes + // Total: 64 bytes // // Status PUBLISH Msg (in the mqtt_sendbuf) // Fixed Header 2 bytes @@ -2358,177 +2306,43 @@ UARTPrintf("\r\n"); // Topic NetworkModule/DeviceName123456789/availabilityoffline 53 bytes // Topic Length 2 bytes // Packet ID 2 bytes - // Total: 59 bytes + // Queued Message Header 11 bytes + // Total: 70 bytes // - // The implication of the above is that the mqtt_sendbuf needs to be as - // large as one PINGREQ message (2 bytes) plus the longest Publish message - // (59 bytes), or 61 bytes. I think the structure added to the mqtt_sendbuf - // for each message in the queue is 11 bytes (search on - // struct mqtt_queued_message - // This would make the requirement for the mqtt_sendbuf = 61 + 22 = 83. + // The implication of the above is that in normal operation the mqtt_sendbuf + // needs to be as large as the Message Queue (12 bytes) plus one PINGREQ + // message (13 bytes) plus the longest Publish message (70 bytes), or 108 + // bytes. // - // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX - // IMPORTANT IMPORTANT IMPORTANT - // An analysis of the MQTT Startup process shows the CONNECT message to be - // up to 120 bytes in length. Add the queue management structure of 11 - // bytes and the mqtt_sendbuf needs to be a minimum of 131 bytes. Note that - // no PINGREQ can occur during the MQTT Startup process, so the CONNECT - // message will occupy the mqtt_sendbuf alone. This sets the required size - // of the mqtt_sendbuf at 131 bytes ... will make it 140 to provide a - // little flexibility in code for message changes. - // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + // However, during MQTT startup the CONNECT message + // CONNECT Msg (in the mqtt_sendbuf) + // Fixed Header 2 bytes + // Variable Header 10 bytes + // Length of protocol name 2 bytes + // Protocol name 4 bytes + // Protocol level 1 byte + // Connect flags 1 byte + // Keep Alive 2 bytes + // Payload + // Client ID Length 2 bytes + // Client ID 25 bytes + // Will Topic Length 2 bytes + // Will Topic 14+19+13 46 bytes + // Will Message Length 2 bytes + // Will Message 7 bytes + // Username Length 2 bytes + // Username 10 bytes + // Passwoard Length 2 bytes + // Password 10 bytes + // Total 130 bytes + // Thus the CONNECT message can be up to up to 130 bytes in length. Add the + // Message Queue (12 bytes) plus the Queued Message Header (11 bytes) and the + // mqtt_sendbuf needs to be a minimum of 153 bytes. Note that no PINGREQ can + // occur during the MQTT Startup process, so the CONNECT message will occupy + // the mqtt_sendbuf alone. This sets the required size of the mqtt_sendbuf at + // 153 bytes ... will make it 160 to provide a little buffer. //---------------------------------------------------------------------------// - -#if QOS_SUPPORT == 0 -void publish_callback(void** unused, struct mqtt_response_publish *published) -{ - char* pBuffer; - uint8_t pin_value; - uint8_t ParseNum; - int i; - - pin_value = 0; - ParseNum = 0; - - // This function will be called if a PUBLISH is received from the Broker. - // The PUBLISH message will contain a payload that, in this application, - // will be the output control bits. - // - // This function is called from within the mqtt_recv() function. The data - // left in the uip_buf will remain there until this function completes. - // - // Dissecting the PUBLISH message: - // - We know that the MQTT Headers + Payload starts at pointer uip_appdata - // - We know that the Fixed Header is 2 bytes - // - Next comes the Variable Header - // - First bytes contain the Topic Name. So we should expect: - // - "NetworkModule/" - // - "Devicename/" - // - "output/" - // - "xx/" (output number or 'all') - // - "set" - // OR - // - "NetworkModule/" - // - "Devicename/" - // - "state-req" - // - Next comes the Payload - // - If "Output/xx/set" we expect a payload of "ON" or "OFF" - // - if "Output/all/set" we expect a payload of "ON" or "OFF" - // - If "state-req" we expect no payload - // - We are QOS 0 so no Packet ID - // - // Once we collect the above information: - // - Set or clear an individual pin - // OR - // - Loop to set or clear "all" pins - // OR - // - Set the state_request variable - pBuffer = uip_appdata; - // Skip the Fixed Header Control Byte (1 byte) - // Skip the Fixed Header Remaining Length Byte (1 byte) - // Skip the Topic name length bytes (2 bytes) - // Skip the NetworkModule/ text (14 bytes) - pBuffer += 18; - // Skip the Devicename/ text - pBuffer += strlen(stored_devicename) + 1; - - // Determine if the sub-topic is "output" or "state-req" - if (*pBuffer == 'o') { - // "output" detected - // Format can be any of these: - // output/01/setON - // output/01/setOFF - // output/all/setON - // output/all/setOFF - // - // Skip past the "output/" characters - pBuffer+= 7; - - // Check if output field is "all". If so, update all output - // pin_control bytes to ON or OFF - if (*pBuffer == 'a') { - // Determine if payload is ON or OFF - pBuffer+=8; - if (*pBuffer == 'N') { - // Turn all outputs ON - for (i=0; i<16; i++) { - if (pin_control[i] & 0x02) { // Output pin? - Pending_pin_control[i] = (uint8_t)(pin_control[i] | 0x80); - } - } - } - else { - // Turn all outputs OFF - for (i=0; i<16; i++) { - if (pin_control[i] & 0x02) { // Output pin? - Pending_pin_control[i] = (uint8_t)(pin_control[i] & ~0x80); - } - } - } - } - - else if (*pBuffer == '0' || *pBuffer == '1') { - // Output field is a digit - // Collect the IO number - // Parse ten's digit - ParseNum = (uint8_t)((*pBuffer - '0') * 10); - pBuffer++; - // Parse one's digit - ParseNum += (uint8_t)(*pBuffer - '0'); - // Verify ParseNum is in the correct range - if (ParseNum > 0 && ParseNum < 17) { - // Adjust Parsenum to match 0 to 15 numbering (instead of 1 to 16) - ParseNum--; - // Determine if payload is ON or OFF - pBuffer+=6; - if (*pBuffer == 'N') { - // Turn output ON (and make sure it is an output) - if (pin_control[ParseNum] & 0x02 == 0x02) // Output pin? - Pending_pin_control[ParseNum] |= (uint8_t)0x80; - } - if (*pBuffer == 'F') { - // Turn output OFF (and make sure it is an output) - if (pin_control[ParseNum] & 0x02 == 0x02) // Output pin? - Pending_pin_control[ParseNum] &= (uint8_t)~0x80; - } - } - } - // The above code effectively did for MQTT what the POST parsing does for - // HTML (changed the pin_control byte). So we need to set the - // mqtt_parse_complete value so that the check_runtime_changes() function - // will perform the necessary IO actions. - mqtt_parse_complete = 1; - } - - // Determine if the sub-topic is "state-req". - else if (*pBuffer == 's') { - // "state-req" detected - // Format is: - // state-req - pBuffer += 8; - if (*pBuffer == 'q') { - *pBuffer = '0'; // Destroy 'q' in buffer so subsequent "state" - // messages won't be misinterpreted - // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX - // WARNING: To save flash space I don't check every - // sub-topic character. But I also don't clear the - // uip_buf. So, I could pick up on stuff left by a - // prevous message if not careful. In this limited - // application I can get away with it, but this can - // trip me up in the future if more messages are - // added. - // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX - state_request = STATE_REQUEST_RCVD; - } - } - // Note: if none of the above matched the parsing we just exit without - // executing any functionality (the message is effectively ignored). -} -#endif // QOS_SUPPORT == 0 - - -#if QOS_SUPPORT == 1 void publish_callback(void** unused, struct mqtt_response_publish *published) { char* pBuffer; @@ -2536,19 +2350,14 @@ void publish_callback(void** unused, struct mqtt_response_publish *published) uint8_t ParseNum; int i; uint16_t j; - uint8_t qos; - + pin_value = 0; ParseNum = 0; - qos = 0; // This function will be called if a "Publish" is received from the Broker. // The publish message will contain a payload that, in this application, // will be the output control bits. // - // Since the Subscribe messages were all QOS1 then all Publish messages from - // the Broker should be QOS1. - // // This function is called from within the mqtt_recv() function. The data // left in the uip_buf will remain there until this function completes. // @@ -2566,8 +2375,7 @@ void publish_callback(void** unused, struct mqtt_response_publish *published) // - "NetworkModule/" // - "Devicename/" // - "state-req" - // - Next comes the Variable Header Packet ID (since we are QOS1) - // - This is 2 bytes + // - We are QOS 0 so no Packet ID // - Next comes the Payload // - If "Output/xx/set" we expect a payload of "ON" or "OFF" // - if "Output/all/set" we expect a payload of "ON" or "OFF" @@ -2581,9 +2389,15 @@ void publish_callback(void** unused, struct mqtt_response_publish *published) // - Set the state_request variable // Set the pBuffer pointer to the start of the MQTT packet + +#if NAGLE_SUPPORT == 0 pBuffer = uip_appdata; - // Extract the QOS value from the Fixed Header Control Byte - qos = (uint8_t)(*pBuffer & 0x02); +#endif // NAGLE_SUPPORT == 0 + +#if NAGLE_SUPPORT == 1 + pBuffer = &uip_buf[MQTT_PBUF]; +#endif // NAGLE_SUPPORT == 1 + // Skip the Fixed Header Control Byte (1 byte) // Skip the Fixed Header Remaining Length Byte (1 byte) // Skip the Topic name length bytes (2 bytes) @@ -2596,21 +2410,20 @@ void publish_callback(void** unused, struct mqtt_response_publish *published) if (*pBuffer == 'o') { // "output" detected // Format can be any of these: - // output/01/setIDON - // output/01/setIDOFF - // output/all/setIDON - // output/all/setIDOFF - // In the above "ID" are the two bytes of the Packet ID which precedes the - // payload + // If QOS 0: + // output/01/setON + // output/01/setOFF + // output/all/setON + // output/all/setOFF // In the above "ON" or "OFF" are in the payload. // Skip past the "output/" characters pBuffer+= 7; - + // Check if output field is "all". If so, update all output // pin_control bytes to ON or OFF if (*pBuffer == 'a') { - // Skip past the "all/setIDO" part of the message. + // Skip past the "all/setO" part of the message. // Note that an "all" message is always sent with QOS == 0. pBuffer+=8; // Determine if payload is ON or OFF @@ -2634,37 +2447,34 @@ void publish_callback(void** unused, struct mqtt_response_publish *published) else if (*pBuffer == '0' || *pBuffer == '1') { // Output field is a digit - // Note that Output messages can be received with QOS == 0 or QOS == 1. + // Note that Output messages can are received with QOS == 0. // Collect the IO number // Parse ten's digit ParseNum = (uint8_t)((*pBuffer - '0') * 10); pBuffer++; // Parse one's digit ParseNum += (uint8_t)(*pBuffer - '0'); + // Verify ParseNum is in the correct range if (ParseNum > 0 && ParseNum < 17) { // Adjust Parsenum to match 0 to 15 numbering (instead of 1 to 16) ParseNum--; - // Skip past the "1/setIDO" part of the message. If QOS == 0 there is - // no Packet Identifier. Else there IS a 2 byte Packet Identifier that - // also needs to be skipped. - if (qos == 0) pBuffer+=6; - else { - pBuffer+=8; - } + // Skip past the "1/setO" part of the message. If QOS == 0 there is + // no Packet Identifier. + pBuffer+=6; // Determine if payload is ON or OFF if (*pBuffer == 'N') { // Turn output ON (and make sure it is an output) if (pin_control[ParseNum] & 0x02 == 0x02) // Output pin? Pending_pin_control[ParseNum] |= (uint8_t)0x80; -#if DEBUG_SUPPORT != 11 -UARTPrintf("publish_callback - Output "); -i = ParseNum + 1; -emb_itoa(i, OctetArray, 10, 2); -UARTPrintf(OctetArray); -UARTPrintf(" ON\r\n"); -#endif // DEBUG_SUPPORT != 11 +// #if DEBUG_SUPPORT != 11 +// UARTPrintf("publish_callback - Output "); +// i = ParseNum + 1; +// emb_itoa(i, OctetArray, 10, 2); +// UARTPrintf(OctetArray); +// UARTPrintf(" ON\r\n"); +// #endif // DEBUG_SUPPORT != 11 } if (*pBuffer == 'F') { @@ -2672,13 +2482,13 @@ UARTPrintf(" ON\r\n"); if (pin_control[ParseNum] & 0x02 == 0x02) // Output pin? Pending_pin_control[ParseNum] &= (uint8_t)~0x80; -#if DEBUG_SUPPORT != 11 -UARTPrintf("publish_callback - Output "); -i = ParseNum + 1; -emb_itoa(i, OctetArray, 10, 2); -UARTPrintf(OctetArray); -UARTPrintf(" OFF\r\n"); -#endif // DEBUG_SUPPORT != 11 +// #if DEBUG_SUPPORT != 11 +// UARTPrintf("publish_callback - Output "); +// i = ParseNum + 1; +// emb_itoa(i, OctetArray, 10, 2); +// UARTPrintf(OctetArray); +// UARTPrintf(" OFF\r\n"); +// #endif // DEBUG_SUPPORT != 11 } // Set the appropriate bit in MQTT_transmit to force a @@ -2720,7 +2530,6 @@ UARTPrintf(" OFF\r\n"); // Note: if none of the above matched the parsing we just exit without // executing any functionality (the message is effectively ignored). } -#endif // QOS_SUPPORT == 1 void publish_outbound(void) @@ -2764,20 +2573,23 @@ void publish_outbound(void) // Check the mqtt_sendbuf to make sure it is emptied before PUBLISHing a // pin_state message. This is to prevent overflow of the mqtt_sendbuf when - // Home Assistant pushes a large number of PUBLISH request messages, each - // of which requires a PUBACK to be processed through the mqtt_sendbuf. Due - // to timing that PUBACK Response might occupy the MQTT_sendbug along with - // another PUBACK as well as a Ping Response. + // Home Assistant pushes a large number of PUBLISH request messages. // This check effectively acts aa a throttle on the publish_outbound // process. - { -// uint16_t mqtt_sendbuf_remaining; -// mqtt_sendbuf_remaining = mqtt_check_sendbuf(&mqttclient); -// if (!(mqtt_sendbuf_remaining > (MQTT_SENDBUF_SIZE - 15))) return; - if (!(mqtt_check_sendbuf(&mqttclient) > (MQTT_SENDBUF_SIZE - 15))) return; + if (!(mqtt_check_sendbuf(&mqttclient) > (MQTT_SENDBUF_SIZE - 15))) { + // mqtt_check_sendbuf() returns the amount of space left in the + // mqtt_sendbuf. We want to make sure it is empty except for the + // 12 byte Message Queue, so we check that only 15 bytes are used. + // If mqtt_sendbuf is not empty we exit but wlll come back later and + // check again. It should empty quickly as the main loop will be + // calling the MQTT routines to transmit whatever is there. + return; } if (state_request == STATE_REQUEST_IDLE) { + // STATE_REQUEST_IDLE is the normal state indicating that a state-req + // message has not been received thus pin states can be transmitted if + // needed. // XOR the current ON_OFF_word with the ON_OFF_word_sent (_sent being the // pin states we already transmitted via MQTT). This gives a result that // has a 1 for any pin state that still needs to be transmitted. @@ -2911,13 +2723,13 @@ void publish_pinstate(uint8_t direction, uint8_t pin, uint16_t value, uint16_t m } -#if DEBUG_SUPPORT != 11 -UARTPrintf("publish pinstate "); -UARTPrintf(topic_base); -UARTPrintf(" "); -UARTPrintf(app_message); -UARTPrintf("\r\n"); -#endif // DEBUG_SUPPORT != 11 +// #if DEBUG_SUPPORT != 11 +// UARTPrintf("publish pinstate "); +// UARTPrintf(topic_base); +// UARTPrintf(" "); +// UARTPrintf(app_message); +// UARTPrintf("\r\n"); +// #endif // DEBUG_SUPPORT != 11 // Queue publish message @@ -4220,10 +4032,10 @@ void check_runtime_changes(void) // request will take precedence in the check_restart_reboot() function. // // Explanation of "user_reboot_request": This variable is used to commun- - // icate that the user pressed a button in the GUI that signals the need - // to reboot. We can't just set "reboot_request" when the button click is - // detected because we need to make sure a restart or reboot isn't already - // occurring. + // icate that the user pressed a button in the GUI, or briefly pressed the + // hardware Reset Button, that signals the need to reboot. We can't just set + // "reboot_request" when a button click is detected because we need to make + // sure a restart or reboot isn't already occurring. // Note: To simplify code user_reboot_request is also set when user changes // are detected in the check_runtime_changes() function. This eliminates an // additional check below. @@ -4606,7 +4418,6 @@ void write_output_pins(void) uint16_t xor_tmp; // it's cheaper in terms of code space using int, instead of uint8_t ! int i; - int j; // Update the output pins to match the bits in the ON_OFF_word. // To simplify code this function writes all pins. Note that if the pin is @@ -4616,26 +4427,21 @@ void write_output_pins(void) // Invert the output if the Invert_word has the corresponding bit set. xor_tmp = (uint16_t)(Invert_word ^ ON_OFF_word); - // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX - // When DS18B20 mode is enabled do not write Output 16 - // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX -// if (stored_config_settings & 0x08) j = 15; -// else j = 16; - j = 16; - -//#if I2C_SUPPORT == 1 -// THIS IS A TEMPORARY WORKAROUND TO TEST I2C SUPPORT -//j = 13; -//#endif // I2C_SUPPORT - // Loop across all IO and set or clear them according to the mask - // Skip IO pins that are being used for I2C or DS18B20 - for (i=0; i 20) user_reboot_request = 1; + return; } } - // If we got here the button remained pressed for 5 seconds - // Turn off the LED, clear the magic number, and reset the device + + // If we got here the button remained pressed for 5 seconds causing the + // for() loop above to time out. + // Turn off the LED, clear the magic number, and reset the device. + // Clearing the magic number will cause the module to return to default + // settings. LEDcontrol(0); // turn LED off unlock_eeprom(); stored_magic4 = 0x00; diff --git a/NetworkModule/httpd.c b/NetworkModule/httpd.c index ebcdb4f..cb8a08e 100644 --- a/NetworkModule/httpd.c +++ b/NetworkModule/httpd.c @@ -4291,22 +4291,22 @@ void HttpDCall(uint8_t* pBuffer, uint16_t nBytes, struct tHttpD* pSocket) } else { // Didn't find '/' - send default page -#if BUILD_SUPPORT == BROWSER_ONLY_BUILD || BUILD_SUPPORT == MQTT_BUILD - -// UARTPrintf("Get slash search1\r\n"); - - pSocket->current_webpage = WEBPAGE_IOCONTROL; - pSocket->pData = g_HtmlPageIOControl; - pSocket->nDataLeft = HtmlPageIOControl_size; - init_off_board_string_pointers(pSocket); -#endif // BUILD_SUPPORT == BROWSER_ONLY_BUILD || BUILD_SUPPORT == MQTT_BUILD -#if BUILD_SUPPORT == CODE_UPLOADER_BUILD - pSocket->current_webpage = WEBPAGE_UPLOADER; - pSocket->pData = g_HtmlPageUploader; - pSocket->nDataLeft = (uint16_t)(sizeof(g_HtmlPageUploader) - 1); -#endif // BUILD_SUPPORT == CODE_UPLOADER_BUILD - pSocket->nParseLeft = 0; // Set to 0 so we will go on to STATE_ - // SENDHEADER + // While this is not a PARSE_FAIL, going through the PARSE_FAIL + // logic will accomplish what we want (paint the default page). + pSocket->ParseState = PARSE_FAIL; +// #if BUILD_SUPPORT == BROWSER_ONLY_BUILD || BUILD_SUPPORT == MQTT_BUILD +// pSocket->current_webpage = WEBPAGE_IOCONTROL; +// pSocket->pData = g_HtmlPageIOControl; +// pSocket->nDataLeft = HtmlPageIOControl_size; +// init_off_board_string_pointers(pSocket); +// #endif // BUILD_SUPPORT == BROWSER_ONLY_BUILD || BUILD_SUPPORT == MQTT_BUILD +// #if BUILD_SUPPORT == CODE_UPLOADER_BUILD +// pSocket->current_webpage = WEBPAGE_UPLOADER; +// pSocket->pData = g_HtmlPageUploader; +// pSocket->nDataLeft = (uint16_t)(sizeof(g_HtmlPageUploader) - 1); +// #endif // BUILD_SUPPORT == CODE_UPLOADER_BUILD +// pSocket->nParseLeft = 0; // Set to 0 so we will go on to STATE_ +// // SENDHEADER } } @@ -4316,22 +4316,22 @@ void HttpDCall(uint8_t* pBuffer, uint16_t nBytes, struct tHttpD* pSocket) // there will be a space here instead of a digit, and we should just // exit the while() loop and send the default page. if (*pBuffer == ' ') { -#if BUILD_SUPPORT == BROWSER_ONLY_BUILD || BUILD_SUPPORT == MQTT_BUILD - -// UARTPrintf("Get slash search2\r\n"); - - pSocket->current_webpage = WEBPAGE_IOCONTROL; - pSocket->pData = g_HtmlPageIOControl; - pSocket->nDataLeft = HtmlPageIOControl_size; - init_off_board_string_pointers(pSocket); -#endif // BUILD_SUPPORT == BROWSER_ONLY_BUILD || BUILD_SUPPORT == MQTT_BUILD -#if BUILD_SUPPORT == CODE_UPLOADER_BUILD - pSocket->current_webpage = WEBPAGE_UPLOADER; - pSocket->pData = g_HtmlPageUploader; - pSocket->nDataLeft = (uint16_t)(sizeof(g_HtmlPageUploader) - 1); -#endif // BUILD_SUPPORT == CODE_UPLOADER_BUILD - pSocket->nParseLeft = 0; // Set to 0 so we will go on to STATE_ - // SENDHEADER + // While this is not a PARSE_FAIL, going through the PARSE_FAIL + // logic will accomplish what we want (paint the default page). + pSocket->ParseState = PARSE_FAIL; +// #if BUILD_SUPPORT == BROWSER_ONLY_BUILD || BUILD_SUPPORT == MQTT_BUILD +// pSocket->current_webpage = WEBPAGE_IOCONTROL; +// pSocket->pData = g_HtmlPageIOControl; +// pSocket->nDataLeft = HtmlPageIOControl_size; +// init_off_board_string_pointers(pSocket); +// #endif // BUILD_SUPPORT == BROWSER_ONLY_BUILD || BUILD_SUPPORT == MQTT_BUILD +// #if BUILD_SUPPORT == CODE_UPLOADER_BUILD +// pSocket->current_webpage = WEBPAGE_UPLOADER; +// pSocket->pData = g_HtmlPageUploader; +// pSocket->nDataLeft = (uint16_t)(sizeof(g_HtmlPageUploader) - 1); +// #endif // BUILD_SUPPORT == CODE_UPLOADER_BUILD +// pSocket->nParseLeft = 0; // Set to 0 so we will go on to STATE_ +// // SENDHEADER } // Parse first ParseNum digit. Looks like the user did input a // filename digit, so collect it here. @@ -4339,7 +4339,9 @@ void HttpDCall(uint8_t* pBuffer, uint16_t nBytes, struct tHttpD* pSocket) // Still good - parse number pSocket->ParseNum = (uint8_t)((*pBuffer - '0') * 10); pSocket->ParseState = PARSE_NUM1; - pSocket->nParseLeft = 1; // Set to 1 so PARSE_NUM1 will be called + pSocket->nParseLeft = 1; // Set to 1 so we don't exit the parsing + // while() loop yet. PARSE_NUM1 will be + // called. pBuffer++; } else { @@ -4357,14 +4359,17 @@ void HttpDCall(uint8_t* pBuffer, uint16_t nBytes, struct tHttpD* pSocket) // Still good - parse number pSocket->ParseNum += (uint8_t)(*pBuffer - '0'); pSocket->ParseState = PARSE_VAL; - pSocket->nParseLeft = 1; // Set to 1 so PARSE_VAL will be called + pSocket->nParseLeft = 1; // Set to 1 so we don't exit the parsing + // while() loop yet. PARSE_VA: will be + // called. pBuffer++; } else { - // Something out of sync or invalid filename - exit while() loop - // but do not change the current_webpage - pSocket->nParseLeft = 0; // Set to 0 so we will go on to STATE_ - // SENDHEADER + // Something out of sync or invalid filename - exit while() via + // the PARSE_FAIL logic. +// pSocket->nParseLeft = 0; // Set to 0 so we will exit the parsing +// // while() loop and will go on to STATE_ +// // SENDHEADER pSocket->ParseState = PARSE_FAIL; } } @@ -4437,6 +4442,7 @@ void HttpDCall(uint8_t* pBuffer, uint16_t nBytes, struct tHttpD* pSocket) // build) // http://IP/75 Show Code Uploader Timer (works only in the Code // Uploader build) + // http://IP/80 Mask and Output Pin settings // http://IP/91 Reboot // http://IP/98 Show Very Short Form IO States page // http://IP/99 Show Short Form IO States page @@ -4620,6 +4626,111 @@ void HttpDCall(uint8_t* pBuffer, uint16_t nBytes, struct tHttpD* pSocket) #endif // BUILD_SUPPORT == CODE_UPLOADER_BUILD #endif // OB_EEPROM_SUPPORT == 1 + +#if BUILD_SUPPORT == BROWSER_ONLY_BUILD || BUILD_SUPPORT == MQTT_BUILD + case 80: // Mask and Output Pin settings + // This is similar to case 55 and case 56, except a 4 hex char + // Mask and a 4 hex char Pin State value hould also be in the + // buffer. Capture the characters, check validity, parse into + // binary values, and set the pending control bytes. + // + // Example URL command + // 192.168.1.182/80ff00c300 + // The above example will affect only the upper 8 output pins + // and will set output pins as follows: + // Output 16 >> 11000011 << Output 9 + // Output 8 to 1 are not affected + // + { + uint16_t word; + uint16_t mmmm; + uint16_t pppp; + uint16_t nibble; + uint16_t bit_ptr; + int i; + int k; + + word = 0; + mmmm = 0; + pppp = 0; + k = 0; + + while (k < 2) { + i = 4; + while (i > 0) { + if (hex2int(*pBuffer) != -1) { + nibble = (uint16_t)hex2int(*pBuffer); + word |= (nibble << ((i-1)*4)); + pBuffer++; + i--; + } + else { + // Something out of sync or invalid filename. Indicate + // parse failure and break out of inner while(i) loop. + pSocket->ParseState = PARSE_FAIL; + break; + } + } // end of inner while(i) loop + if (k == 0) mmmm = word; + else pppp = word; + k++; + word = 0; + if (pSocket->ParseState == PARSE_FAIL) { + // If fail detected break out of outer while(k) loop. + break; + } + } // end of outer while(k) loop + if (pSocket->ParseState == PARSE_FAIL) { + // break out of switch + break; + } + + // Now check that the URL termination is valid + if (*pBuffer != ' ') { + pSocket->ParseState = PARSE_FAIL; + } + pBuffer++; + if (*pBuffer != 'H') { + pSocket->ParseState = PARSE_FAIL; + } + + if (pSocket->ParseState == PARSE_FAIL) { + // If fail detected break out of the switch, but do not + // change the current_webpage. This will cause the URL + // command to be ignored and the current webpage to be + // refreshed. + break; + } + + + // If we didn't break out of the switch yet we should have + // valid Mask (mmmm) and Pin State (pppp) values. Now we + // modify the Pending_pin_control bytes accordingly. + + bit_ptr = 1; + for (i=0; i<16; i++) { + if ((mmmm & bit_ptr) != 0) { + // If the Mask for this pin is non-zero check if the pin + // is an enabled output. If yes, uptate the pin state. + Pending_pin_control[i] = pin_control[i]; + if ((pin_control[i] & 0x03) == 0x03) { // Enabled output + if ((pppp & bit_ptr) == 0) { + Pending_pin_control[i] &= 0x7f; // Output OFF + } + else { + Pending_pin_control[i] |= 0x80; // Output ON + } + } + } + // Shift the bit pointer and check the next pin + bit_ptr = bit_ptr << 1; + } + } + parse_complete = 1; + GET_response_type = 204; // No return webpage + break; +#endif // BUILD_SUPPORT == BROWSER_ONLY_BUILD || BUILD_SUPPORT == MQTT_BUILD + case 91: // Reboot user_reboot_request = 1; break; @@ -4650,17 +4761,20 @@ void HttpDCall(uint8_t* pBuffer, uint16_t nBytes, struct tHttpD* pSocket) } else { // Show default page -#if BUILD_SUPPORT == BROWSER_ONLY_BUILD || BUILD_SUPPORT == MQTT_BUILD - pSocket->current_webpage = WEBPAGE_IOCONTROL; - pSocket->pData = g_HtmlPageIOControl; - pSocket->nDataLeft = HtmlPageIOControl_size; - init_off_board_string_pointers(pSocket); -#endif // BUILD_SUPPORT == BROWSER_ONLY_BUILD || BUILD_SUPPORT == MQTT_BUILD -#if BUILD_SUPPORT == CODE_UPLOADER_BUILD - pSocket->current_webpage = WEBPAGE_UPLOADER; - pSocket->pData = g_HtmlPageUploader; - pSocket->nDataLeft = (uint16_t)(sizeof(g_HtmlPageUploader) - 1); -#endif // BUILD_SUPPORT == CODE_UPLOADER_BUILD + // While NOT a PARSE_FAIL, going through the PARSE_FAIL logic + // will accomplish what we want. + pSocket->ParseState = PARSE_FAIL; +// #if BUILD_SUPPORT == BROWSER_ONLY_BUILD || BUILD_SUPPORT == MQTT_BUILD +// pSocket->current_webpage = WEBPAGE_IOCONTROL; +// pSocket->pData = g_HtmlPageIOControl; +// pSocket->nDataLeft = HtmlPageIOControl_size; +// init_off_board_string_pointers(pSocket); +// #endif // BUILD_SUPPORT == BROWSER_ONLY_BUILD || BUILD_SUPPORT == MQTT_BUILD +// #if BUILD_SUPPORT == CODE_UPLOADER_BUILD +// pSocket->current_webpage = WEBPAGE_UPLOADER; +// pSocket->pData = g_HtmlPageUploader; +// pSocket->nDataLeft = (uint16_t)(sizeof(g_HtmlPageUploader) - 1); +// #endif // BUILD_SUPPORT == CODE_UPLOADER_BUILD } break; @@ -4669,14 +4783,21 @@ void HttpDCall(uint8_t* pBuffer, uint16_t nBytes, struct tHttpD* pSocket) } if (pSocket->ParseState == PARSE_FAIL) { - // Parsing failed above. By going to STATE_SENDHEADER200 - // javascript should repaint the page already sent. While - // inefficient this will satisfy the browser's need for a - // reply when it requests favicon.ico or whatever else it - // requests that we don't have. - pSocket->nPrevBytes = 0xFFFF; - pSocket->nState = STATE_SENDHEADER200; - break; + // Parsing failed above OR there was a decision to display the + // default webpage. +#if BUILD_SUPPORT == BROWSER_ONLY_BUILD || BUILD_SUPPORT == MQTT_BUILD + pSocket->current_webpage = WEBPAGE_IOCONTROL; + pSocket->pData = g_HtmlPageIOControl; + pSocket->nDataLeft = HtmlPageIOControl_size; + init_off_board_string_pointers(pSocket); +#endif // BUILD_SUPPORT == BROWSER_ONLY_BUILD || BUILD_SUPPORT == MQTT_BUILD +#if BUILD_SUPPORT == CODE_UPLOADER_BUILD + pSocket->current_webpage = WEBPAGE_UPLOADER; + pSocket->pData = g_HtmlPageUploader; + pSocket->nDataLeft = (uint16_t)(sizeof(g_HtmlPageUploader) - 1); +#endif // BUILD_SUPPORT == CODE_UPLOADER_BUILD + pSocket->nParseLeft = 0; // Set to 0 so we will go on to STATE_ + // SENDHEADER } if (pSocket->nParseLeft == 0) { @@ -4691,7 +4812,7 @@ void HttpDCall(uint8_t* pBuffer, uint16_t nBytes, struct tHttpD* pSocket) // No return webpage - send header with Content-Length: 0 pSocket->nState = STATE_SENDHEADER204; } - break; + break; // Break out of while loop } } // end of while loop } diff --git a/NetworkModule/main.h b/NetworkModule/main.h index 9bb1617..96b1714 100644 --- a/NetworkModule/main.h +++ b/NetworkModule/main.h @@ -152,6 +152,7 @@ int main(void); +void periodic_service(void); void init_IWDG(void); void unlock_eeprom(void); void lock_eeprom(void); @@ -186,7 +187,7 @@ uint32_t calculate_timer(uint16_t timer_value); void decrement_pin_timers(void); void mqtt_startup(void); -void mqtt_redefine_temp_sensors(void); +// void mqtt_redefine_temp_sensors(void); void define_temp_sensors(void); // void send_IOT_msg(uint8_t IOT_ptr, uint8_t IOT, uint8_t DefOrDel, uint8_t delete_flag); void send_IOT_msg(uint8_t IOT_ptr, uint8_t IOT, uint8_t DefOrDel); diff --git a/NetworkModule/mqtt.c b/NetworkModule/mqtt.c index 46386a4..a9d2db0 100644 --- a/NetworkModule/mqtt.c +++ b/NetworkModule/mqtt.c @@ -66,6 +66,21 @@ extern uint8_t mqtt_start; // Tracks the MQTT startup steps extern uint8_t OctetArray[11]; // Used in UART debug sessions +#if NAGLE_SUPPORT == 1 +uint8_t current_msg_length; // Contains the length of the MQTT + // message currently being extracted + // from the uip_buf. +uint8_t mqtt_partial_buffer_length; // Trackes the length of data in the + // MQTT Partial Buffer so that we know + // how much of a partially received + // MQTT message was received. +uint8_t pbi; // Partial Buffer Index - provides an + // index for writing and reading the + // MQTT partial buffer +#endif // NAGLE_SUPPORT == 1 + + + // Implements the functionality of MQTT-C. @@ -73,19 +88,368 @@ extern uint8_t OctetArray[11]; // Used in UART debug sessions int16_t mqtt_sync(struct mqtt_client *client) { + // Check for incoming data (note there may not be any) and check + // if there is something that needs to be transmitted. int16_t err; +#if NAGLE_SUPPORT == 1 + uint16_t total_msg_length; // Contains the total length of the + // MQTT message(s) in the uip_buf + char *msgBuffer; // A pointer used to read MQTT + // messages from the uip_buf + uint8_t outer_break; // Used in breaking a double while() + // loop. +#endif // NAGLE_SUPPORT == 1 + +#if NAGLE_SUPPORT == 0 // Call receive - // We got here because an incoming message was detected by the UIP - // code for the MQTT Port. The way to be sure that receive processing - // should occur is if uip_newdata() is true OR uip_acked() is true - // AND uip_len > 0. if ((uip_newdata() || uip_acked()) && uip_len > 0) { + // We got here because an incoming message was detected by the UIP + // code for the MQTT Port. The way to be sure that receive processing + // should occur is if uip_newdata() is true OR uip_acked() is true + // AND uip_len > 0. err = __mqtt_recv(client); if (err != MQTT_OK) { return err; } } +#endif // NAGLE_SUPPORT == 0 + + +#if NAGLE_SUPPORT == 1 + // Call receive + if ((uip_newdata() || uip_acked()) && uip_len > 0) { + // We got here because an incoming message was detected by the UIP + // code for the MQTT Port. The way to be sure that receive processing + // should occur is if uip_newdata() is true OR uip_acked() is true + // AND uip_len > 0. + // + // When a TCP Packet is received with MQTT messages (the datagram) in + // it the packet will be placed in the uip_buf startng at the location + // indicated by pointer uip_appdata. The datagram might have one MQTT + // messages, or it may have multiple MQTT messages, and any given MQTT + // message might be divided between two sequential packets. And, if a + // message is divided between sequential packets a new MQTT message + // might follow the remnant that starts the new packet. + // + // The code here will pull MQTT messages one at a time from the TCP + // packets and will call __mqtt_recv and __mqtt_send to interpret those + // messages and send a response to the originator (if needed). A concern + // is that there can be no actual transmission of of responses to + // messages until the uip_buf is emptied. There is very limited space in + // the mqtt_sendbuf, so responses need to accumulate there. Fortunately + // the following analysis shows that there should be very little + // response traffic filling the mqtt_sendbuf. + // + // The only MQTT messages that will be received AFTER boot initialization + // completes are: + // PUBLISH: + // msg->state is not updated until __mqtt_send() is called. + // PINGRESP: + // No transmit activity occurs. The message queue is updated with + // msg->state = MQTT_QUEUED_COMPLETE. This allows the queue slot to be + // reused if needed. + // + // Next __mqtt_send() is called to clean up message states after + // __mqtt_recv(). + // DISCONNECT: + // A transmit message can be placed in the mqtt_sendbuf by the + // mqtt_disconnect() function. When __mqtt_send is run the transmit + // queue is updated with msg->state = MQTT_QUEUED_COMPLETE. This + // allows the queue slot to be reused is needed (although that won't + // happen as Disconnect will be followed by a reboot). + // PUBLISH: + // At QOS 0 no transmit activity occurs. Only publish_callback() is + // called, which updates tracking variables which will later result in + // generation of PUBLISH messages for transmit from the Network Module. + // Those transmits will occur, at earliest, after the processing of the + // current TCP packet is complete. The transmit queue is updated with + // msg->state = MQTT_QUEUED_COMPLETE. allows the queue slot to be + // reused is needed. + // PINGREQ: + // At the end of __mqtt_send() at about a 30 second interval a PINGREQ + // message gets placed in the transmit queue and the queue is updated + // with msg->state = MQTT_QUEUED_AWAITING_ACK. Any subsequent call to + // __mqtt_send() will transmit the message, resulting in a PINGRESP from + // the host. A PINGREQ is a 2 byte message so it occupies very little + // space in the mqtt_sendbuf. + + // Initialize the pointer for the uip_buf data and determine the + // total length of the data. + msgBuffer = uip_appdata; + total_msg_length = uip_len; + outer_break = 0; + + + +/* +KEEP THIS CODE FOR A SHORT TIME JUST IN CASE. THIS WAS THE FIRST WORKING +CODE FOR THE HA-HEADER-TOGGLE-BATCHED-MQTT-MESSAGES FIX. WORKED FINE. +COMPRESSED INTO A MORE EFFICIENT VERSION BELOW THIS SAVE. + while (total_msg_length > 0) { + // If total_msg_length is greater than zero then there is data in + // the uip_buf that needs to be read. + // This loop will move MQTT messages to the MQTT Partial Buffer one + // message at a time. When a complete message is constructed in the + // MQTT Partial Buffer the __mqtt_recv() function will be called to + // interpret the message. + // We start by collecting the Control byte and Remaining Lenght byte + // that always start an MQTT message. We might be continuing the + // capture of a message that started in a previous TCP packet so here + // we sort that out. + if (mqtt_partial_buffer_length == 0) { + // If mqtt_partial_buffer_length is zero we should be starting the + // capture of a new MQTT message. + // Try to capture the Control Byte and Remaining Length. The data + // might end while doing this. + + pbi = 0; + uip_buf[MQTT_PBUF + pbi++] = *msgBuffer; // Control Byte + mqtt_partial_buffer_length++; + msgBuffer++; + total_msg_length--; + if (total_msg_length == 0) { + // Check if we just read the last byte of data in the uip_buf. + // If yes we just hit the end of a TCP packet and we need to exit + // __mqtt_sync to wait for the next packet. + // pbi and mqtt_partial_buffer_length are retained globally so + // they can be used to continue the extraction of MQTT messages + // on the next call to mqtt_sync(). + return MQTT_OK; + } + + uip_buf[MQTT_PBUF + pbi++] = *msgBuffer; // Remaining Length Byte + current_msg_length = uip_buf[MQTT_PBUF + 1]; + mqtt_partial_buffer_length++; + msgBuffer++; + total_msg_length--; + } + + else if (mqtt_partial_buffer_length == 1) { + // If mqtt_partial_buffer_length is one then the MQTT Partial Buffer + // contains the Control byte of a MQTT message that started at the + // very end of a previous TCP packet. We assume new packets have + // at least 2 bytes of data in them, so we read the next byte which + // will be the Remaining Length. + uip_buf[MQTT_PBUF + pbi++] = *msgBuffer; + mqtt_partial_buffer_length++; + current_msg_length = uip_buf[MQTT_PBUF + 1]; + msgBuffer++; + total_msg_length--; + } + + else if (mqtt_partial_buffer_length > 1) { + // If mqtt_partial_buffer_length is greater than one then the MQTT + // Partial Buffer contains the Control byte AND the Remaining Length + // of a MQTT message that started at the very end of a previous TCP + // packet. + // Nothing needs to happen here as the current_msg_length was + // captured when readng the previous packet. + } + + if (current_msg_length == 0) { + // The above code captured the Control byte and Remaining Length. If + // the Remaining Length is zero this must be a PINGRESP. Call + // __mqtt_recv() then clear the MQTT Partial Buffer handling + // variables in case there are more MQTT messages in the uip_buf + // after this message. + err = __mqtt_recv(client); + mqtt_partial_buffer_length = 0; + pbi = 0; + if (err != MQTT_OK) { + return err; + } + // Call send + // If we run __mqtt_recv() we need to follow that with a call to + // __mqtt_send() so that each processed MQTT message finishes its + // recv/send process (mostly making sure the message state is + // updated correctly). + // mqtt_send() shouldn't actually transmit anything via the uip_buf + // at this point. It should only update the msg->state of messages + // as needed. + err = __mqtt_send(client); + // Set global MQTT error flag so GUI can show status + if (err == MQTT_OK) MQTT_error_status = 1; + else MQTT_error_status = 0; + if (err != MQTT_OK) { + return err; + } + + if (total_msg_length == 0) { + // If total_msg_length is zero then the MQTT message just + // processed was the end of the TCP packet. We need to break + // out of the while() loop so that another TCP packet can be + // collected. + break; + } + else { + // If total_msg_length is greater than zero then there is another + // MQTT message in the uip_buf. Start the while() loop over again + // to read the data. + continue; + } + } + + // Getting this far means we collected the Control byte and the + // Remaining Length and there is more to the MQTT message in the + // uip_buf. Continue reading the MQTT message from the uip_buf. We + // could hit an end of packet at any byte. + while(1) { + uip_buf[MQTT_PBUF + pbi++] = *msgBuffer; + mqtt_partial_buffer_length++; + msgBuffer++; + total_msg_length--; + current_msg_length--; + if (current_msg_length == 0) { + // If current_msg_length is zero we just copied the entire MQTT + // message into the MQTT Partial Buffer. Call __mqtt_recv() then + // clear the MQTT Partial Buffer handling variables in case there + // are more MQTT messages in the uip_buf after this message. + err = __mqtt_recv(client); + mqtt_partial_buffer_length = 0; + pbi = 0; + if (err != MQTT_OK) { + return err; + } + + // Call send + // If we run __mqtt_recv() we need to follow that with a call to + // __mqtt_send() so that each processed MQTT message finishes its + // recv/send process (mostly making sure the message state is + // updated correctly). + // mqtt_send() shouldn't actually transmit anything via the uip_buf + // at this point. It should only update the msg->state of messages + // as needed. + err = __mqtt_send(client); + // Set global MQTT error flag so GUI can show status + if (err == MQTT_OK) MQTT_error_status = 1; + else MQTT_error_status = 0; + if (err != MQTT_OK) { + return err; + } + + if (total_msg_length == 0) { + // If total_msg_length is zero then the MQTT message just + // extracted (or part thereof) was the end of the TCP packet. + // We need to break out of the inner and outer while() loops so + // that another TCP packet can be collected. + // Note: the current_msg_length, mqtt_partial_buffer_length, and + // pbi are all retained in global memory so that the next packet + // starts where this one left off. + outer_break = 1; + break; + } + else { + // If total_msg_length is greater than zero then there is + // another MQTT message in the uip_buf that needs to be read. + // Break out of the inner while() loop to read the next MQTT + // message. + break; + } + } + if (total_msg_length == 0) { + // If total_msg_length is zero then the MQTT message just + // extracted (or part thereof) was the end of the TCP packet. + // We need to break out of the inner and outer while() loops so + // that another TCP packet can be collected. + // Note: the current_msg_length, mqtt_partial_buffer_length, and + // pbi are all retained in global memory so that the next packet + // starts where this one left off. + outer_break = 1; + break; + } + } + if (outer_break == 1) break; + } // end of outer while() loop +*/ + + + + + + while (total_msg_length > 0) { + // If total_msg_length is greater than zero then there is data in + // the uip_buf that needs to be read. + // This loop will move MQTT messages to the MQTT Partial Buffer one + // message at a time. When a complete message is constructed in the + // MQTT Partial Buffer the __mqtt_recv() function will be called to + // interpret the message. + + // Capture a byte from the uip_buf + uip_buf[MQTT_PBUF + pbi++] = *msgBuffer; + mqtt_partial_buffer_length++; + msgBuffer++; + total_msg_length--; + + if (mqtt_partial_buffer_length == 2) { + // If mqtt_partial_buffer_length == 2 a new current_msg_length + // (Remaining Lenght) is in the second byte. + current_msg_length = uip_buf[MQTT_PBUF + 1]; + } + + if (mqtt_partial_buffer_length > 2) { + // If mqtt_partial_buffer_length > 2 then the Control Byte and + // Remaining Lenght Byte have both been captured and we must + // decrement the current_msg_length with each additional byte read. + current_msg_length--; + } + + if (mqtt_partial_buffer_length == 1) { + if (total_msg_length == 0) { + // Hit end of packet at first byte of new message. Leave _mqtt_sync + // to collect another packet. + return MQTT_OK; + } + // If not at the end of the packet continue to loop to collect one + // byte (the Remaining Length) before further decisions. + continue; + } + + if (current_msg_length == 0) { + // Captured a complete message. Call __mqtt_recv() then clear the + // MQTT Partial Buffer handling variables in case there are more + // MQTT messages in the uip_buf after this message. + err = __mqtt_recv(client); + mqtt_partial_buffer_length = 0; + pbi = 0; + if (err != MQTT_OK) { + return err; + } + // Call send + // If we run __mqtt_recv() we need to follow that with a call to + // __mqtt_send() so that each processed MQTT message finishes its + // recv/send process (mostly making sure the message state is updated + // correctly). + // mqtt_send() shouldn't actually transmit anything via the uip_buf + // at this point. It should only update the msg->state of messages + // as needed. + err = __mqtt_send(client); + // Set global MQTT error flag so GUI can show status + if (err == MQTT_OK) MQTT_error_status = 1; + else MQTT_error_status = 0; + if (err != MQTT_OK) { + return err; + } + } + + // At this point if total_msg_length == 0 then the MQTT message just + // extracted (or part thereof) was the end of the TCP packet. The + // while() loop will terminate so that another TCP packet can be + // collected. + // Note: the current_msg_length, mqtt_partial_buffer_length, and pbi + // are all retained in global memory so that the next packet starts + // where this one left off. + } + + + + + + + + } +#endif // NAGLE_SUPPORT == 1 + // Call send // mqtt_send() will check the send_buf to see if there are any queued @@ -150,12 +514,16 @@ int16_t mqtt_init(struct mqtt_client *client, void (*publish_response_callback)(void** state,struct mqtt_response_publish *publish)) { -#if DEBUG_SUPPORT != 11 -UARTPrintf("__mqtt_init sendbuf size = "); -emb_itoa(sendbufsz, OctetArray, 10, 3); -UARTPrintf(OctetArray); -UARTPrintf("\r\n"); -#endif // DEBUG_SUPPORT != 11 + +#if NAGLE_SUPPORT == 1 + // Initialize variables used in extracting MQTT messages from batched / + // fragmented TCP packets + current_msg_length = 0; + mqtt_partial_buffer_length = 0; + pbi = 0; +#endif // NAGLE_SUPPORT == 1 + + if (client == NULL || sendbuf == NULL || recvbuf == NULL) { return MQTT_ERROR_NULLPTR; @@ -165,8 +533,10 @@ UARTPrintf("\r\n"); client->recv_buffer.mem_start = recvbuf; client->recv_buffer.mem_size = recvbufsz; - client->recv_buffer.curr = client->recv_buffer.mem_start; - client->recv_buffer.curr_sz = client->recv_buffer.mem_size; + // The .curr variables are not needed since the receive buffer is fed + // one message at a time. + // client->recv_buffer.curr = client->recv_buffer.mem_start; + // client->recv_buffer.curr_sz = client->recv_buffer.mem_size; client->error = MQTT_ERROR_CONNECT_NOT_CALLED; client->response_timeout = 30; @@ -180,10 +550,11 @@ UARTPrintf("\r\n"); // A macro function that: -// 1) Checks that the client isn't in an error state. +// 1) Checks that the client isn't already in an error state. // 2) Attempts to pack to client's message queue. // a) handles errors -// b) if mq buffer is too small, cleans it and tries again +// b) if mq buffer is too small (as indicated by tmp == 0), +// cleans it and tries again // 3) Upon successful pack, registers the new message. #define MQTT_CLIENT_TRY_PACK(tmp, msg, client, pack_call, release) \ if (client->error < 0) { \ @@ -228,15 +599,6 @@ int16_t mqtt_connect(struct mqtt_client *client, client->error = MQTT_OK; } -// UARTPrintf("__mqtt_connect sendbuf rem = "); -// emb_itoa(client->mq.curr_sz, OctetArray, 10, 3); -// UARTPrintf(OctetArray); -// mqtt_mq_clean(&client->mq); -// UARTPrintf(" after clean = "); -// emb_itoa(client->mq.curr_sz, OctetArray, 10, 3); -// UARTPrintf(OctetArray); -// UARTPrintf("\r\n"); - // try to pack the message MQTT_CLIENT_TRY_PACK(rv, msg, client, mqtt_pack_connection_request( @@ -272,21 +634,6 @@ int16_t mqtt_publish(struct mqtt_client *client, uint16_t packet_id; packet_id = __mqtt_next_pid(client); -// UARTPrintf("mqtt_publish flags "); -// emb_itoa(publish_flags, OctetArray, 16, 2); -// UARTPrintf(OctetArray); -// UARTPrintf("\r\n"); - -// UARTPrintf("__mqtt_publish sendbuf rem = "); -// emb_itoa(client->mq.curr_sz, OctetArray, 10, 3); -// UARTPrintf(OctetArray); -// mqtt_mq_clean(&client->mq); -// UARTPrintf(" after clean = "); -// emb_itoa(client->mq.curr_sz, OctetArray, 10, 3); -// UARTPrintf(OctetArray); -// UARTPrintf("\r\n"); - - // try to pack the message MQTT_CLIENT_TRY_PACK( rv, msg, client, @@ -309,32 +656,6 @@ int16_t mqtt_publish(struct mqtt_client *client, } -#if QOS_SUPPORT == 1 -int16_t __mqtt_puback(struct mqtt_client *client, uint16_t packet_id) -{ - int16_t rv; - struct mqtt_queued_message *msg; - -// UARTPrintf("mqtt_puback Generating PUBACK\r\n"); - - // try to pack the message - MQTT_CLIENT_TRY_PACK( - rv, msg, client, - mqtt_pack_pubxxx_request( - client->mq.curr, client->mq.curr_sz, - MQTT_CONTROL_PUBACK, - packet_id - ), - 0 - ); - // save the control type and packet id of the message - msg->control_type = MQTT_CONTROL_PUBACK; - msg->packet_id = packet_id; - return MQTT_OK; -} -#endif // QOS_SUPPORT == 1 - - int16_t mqtt_subscribe(struct mqtt_client *client, const char* topic_name, int max_qos_level) @@ -413,132 +734,17 @@ int16_t mqtt_disconnect(struct mqtt_client *client) } -#if QOS_SUPPORT == 0 int16_t __mqtt_send(struct mqtt_client *client) { - int16_t len; - int16_t i = 0; + // Function to manage transfer of messages from the mqtt_sendbuf to the + // uip_buf so that they will be transmitted on the ethernet. + // This application must use the uip_buf for all outbound traffic, and the + // uip_buf is only serviced via calls in the main loop. Thus only one + // message at a time can be serviced by calls to mqtt_pall_sendall(). + // As a result the loop below will terminate with a break if a message is + // transferred from the mqtt_sendbuf to the uip_buf. The code will be + // called again later to pick up the next message in the queue. - if (client->error < 0 && client->error != MQTT_ERROR_SEND_BUFFER_IS_FULL) { - return client->error; - } - - // loop through all messages in the queue - len = mqtt_mq_length(&client->mq); - - for(; i < len; ++i) { - struct mqtt_queued_message *msg = mqtt_mq_get(&client->mq, i); - int16_t resend = 0; - if (msg->state == MQTT_QUEUED_UNSENT) { - // message has not been sent so lets send it - resend = 1; - } - else if (msg->state == MQTT_QUEUED_AWAITING_ACK) { - // check for timeout - if (second_counter > msg->time_sent + client->response_timeout) { - resend = 1; - client->number_of_timeouts += 1; - client->send_offset = 0; - } - } - - // goto next message if we don't need to send - if (!resend) continue; - - // we're sending the message - { - // Some notes about this part of the code. The original code was - // designed to send larger messages, thus mqtt_pal_sendall might - // return a tmp value that indicates there is more to send. In this - // application we use a technique in the mqtt_pal_sendall routine - // that can replace placeholders in the mqtt message that is to be - // sent, resulting in an mqtt message that is larger than the - // message template given to it to send. So the mqtt_pal_sendall - // routine was redesigned to cause it to send the entire message - // even if it required multiple packets. Thus the return value - // always equals the size of the original template ... indicating - // a complete send. - int16_t tmp = mqtt_pal_sendall(msg->start + client->send_offset, msg->size - client->send_offset); - // mqtt_pal_sendall returns a negative number if an error, or a positive - // number with the number of bytes sent - if (tmp < 0) { - client->error = tmp; - return tmp; - } - else { - client->send_offset += tmp; - if(client->send_offset < msg->size) { - // partial sent. Await additional calls - break; - } - else { - // Whole message has been sent - and by "sent" we mean copied - // to the uip_buf. - client->send_offset = 0; - } - } - } - - // update timeout watcher - client->time_of_last_send = second_counter; - msg->time_sent = client->time_of_last_send; - - // Determine the state to put the message in. - // Control Types: - // MQTT_CONTROL_CONNECT -> awaiting - // MQTT_CONTROL_CONNACK -> n/a - // MQTT_CONTROL_PUBLISH -> complete - // MQTT_CONTROL_SUBSCRIBE -> awaiting - // MQTT_CONTROL_SUBACK -> n/a - // MQTT_CONTROL_PINGREQ -> awaiting - // MQTT_CONTROL_PINGRESP -> n/a - // MQTT_CONTROL_DISCONNECT -> complete - - - - switch (msg->control_type) { - case MQTT_CONTROL_DISCONNECT: - msg->state = MQTT_QUEUED_COMPLETE; - break; - case MQTT_CONTROL_PUBLISH: - msg->state = MQTT_QUEUED_COMPLETE; - break; - case MQTT_CONTROL_CONNECT: - case MQTT_CONTROL_SUBSCRIBE: - case MQTT_CONTROL_PINGREQ: - msg->state = MQTT_QUEUED_AWAITING_ACK; - break; - default: - client->error = MQTT_ERROR_MALFORMED_REQUEST; - return MQTT_ERROR_MALFORMED_REQUEST; - } - } - - // check for keep-alive - { - // At about 3/4 of the timeout period perform a ping. This calculation - // uses integer arithmetic so it is only an approximation. It is assumed - // that timeouts are not a small number (for instance, the timeout should - // be at least 15 seconds). - uint32_t keep_alive_timeout = client->time_of_last_send + (uint32_t)((client->keep_alive * 3) / 4); - if ((second_counter > keep_alive_timeout) && (mqtt_start == MQTT_START_COMPLETE)) { - int16_t rv = __mqtt_ping(client); - if (rv != MQTT_OK) { - client->error = rv; - return rv; - } - } - } - - return MQTT_OK; -} -#endif // QOS_SUPPORT == 0 - - -#if QOS_SUPPORT == 1 -int16_t __mqtt_send(struct mqtt_client *client) -{ - uint8_t inspected; int16_t len; int16_t i = 0; @@ -546,163 +752,137 @@ int16_t __mqtt_send(struct mqtt_client *client) return client->error; } - // loop through all messages in the queue. mqtt_mq_length returns the + // Find the next unsent message in the queue. mqtt_mq_length returns the // number of messages in the message queue. len = mqtt_mq_length(&client->mq); -// if (len > 0) { -// UARTPrintf("__mqtt_send number of msgs in queue = "); -// emb_itoa(len, OctetArray, 10, 2); -// UARTPrintf(OctetArray); -// UARTPrintf("\r\n"); -// } - - -// Here's a problem ... I think. This next "for" loop will attempt to send all -// messages in the mqtt_sendbuf. The problem is that mqtt_pal_sendall is designed -// to place a single message in the uip_buf, then expects a return to the main.c -// main loop so that the message will be transferred from the uip_buf to the -// ENC28J60. So I think the loop below needs to break once a message is encountered -// and submitted to mqtt_pal_sendall. We should return later to send any additional -// messages. - - - - for(; i < len; ++i) { - struct mqtt_queued_message *msg = mqtt_mq_get(&client->mq, i); - int16_t resend = 0; - if (msg->state == MQTT_QUEUED_UNSENT) { - // message has not been sent so lets send it - resend = 1; - } - else if (msg->state == MQTT_QUEUED_AWAITING_ACK) { - // check for timeout - if (second_counter > msg->time_sent + client->response_timeout) { - resend = 1; - client->number_of_timeouts += 1; - client->send_offset = 0; - } + // Even though only one message can be sent each time this function + // is entered a for() loop is required in case a previously sent + // message is in state MQTT_QUEUED_AWAITING_ACK. This allows other + // messages in the queue to be sent even if one is still awaiting + // an ACK. Due to application timing this should never happen. Also + // note that a message could be resent if it times out in the queue. + // This should also never happen. + struct mqtt_queued_message *msg = mqtt_mq_get(&client->mq, i); + int16_t resend = 0; + if (msg->state == MQTT_QUEUED_UNSENT) { + // message has not been sent so lets send it + resend = 1; + } + else if (msg->state == MQTT_QUEUED_AWAITING_ACK) { + // check for timeout + if (second_counter > msg->time_sent + client->response_timeout) { + resend = 1; + client->number_of_timeouts += 1; + client->send_offset = 0; } + } - // goto next message if we don't need to send - if (!resend) continue; - - // we're sending the message - { - // Some notes about this part of the code. The original code was - // designed to send larger messages, thus mqtt_pal_sendall might - // return a tmp value that indicates there is more to send. In this - // application we use a technique in the mqtt_pal_sendall routine - // that can replace placeholders in the mqtt message that is to be - // sent, resulting in an mqtt message that is larger than the - // message template given to it to send. So the mqtt_pal_sendall - // routine was redesigned to cause it to send the entire message - // even if it required multiple packets. Thus the return value - // always equals the size of the original template ... indicating - // a complete send. - int16_t tmp = mqtt_pal_sendall(msg->start + client->send_offset, msg->size - client->send_offset); - // mqtt_pal_sendall returns a negative number if an error, or a positive - // number with the number of bytes sent - if (tmp < 0) { - client->error = tmp; - return tmp; + // goto next message if we don't need to send + if (!resend) continue; + + // we're sending the message + { + // Some notes about this part of the code. The original code was + // designed to send larger messages, thus mqtt_pal_sendall might + // return a tmp value that indicates there is more to send. In this + // application we use a technique in the mqtt_pal_sendall routine + // that can replace placeholders in the mqtt message that is to be + // sent, resulting in an mqtt message that is larger than the + // message template given to it to send. So the mqtt_pal_sendall + // routine was redesigned to cause it to send the entire message + // even if it required multiple packets. Thus the return value + // always equals the size of the original template ... indicating + // a complete send. + int16_t tmp = mqtt_pal_sendall(msg->start + client->send_offset, msg->size - client->send_offset); + // mqtt_pal_sendall returns a negative number if an error, or a positive + // number with the number of bytes sent + if (tmp < 0) { + client->error = tmp; + return tmp; + } + else { + client->send_offset += tmp; + if(client->send_offset < msg->size) { + // partial sent. Await additional calls + // A PARTIAL SHOULD NEVER OCCUR AS ALL MQTT MESSAGES ARE SHORT + // ENOUGH IN THIS APPLICATION THAT THEY WILL BE SENT IN ONE PASS. + // THIS CODE COULD BE SIMPLIFIED. + break; } else { - client->send_offset += tmp; - if(client->send_offset < msg->size) { - // partial sent. Await additional calls - // A PARTIAL SHOULD NEVER OCCUR AS ALL MQTT MESSAGES ARE SHORT - // ENOUGH IN THIS APPLICATION THAT THEY WILL BE SENT IN ONE PASS. - // THIS CODE COULD BE SIMPLIFIED. - break; - } - else { - // Whole message has been sent - and by "sent" we mean copied - // to the uip_buf. - client->send_offset = 0; - } + // Whole message has been sent - and by "sent" we mean copied + // to the uip_buf. + client->send_offset = 0; } } + } - // update timeout watcher - client->time_of_last_send = second_counter; - msg->time_sent = client->time_of_last_send; - - // Determine the state to put the message in. - // Control Types: - // MQTT_CONTROL_CONNECT -> awaiting - // MQTT_CONTROL_CONNACK -> n/a - // MQTT_CONTROL_PUBLISH -> qos == 0 ? complete : awaiting - // MQTT_CONTROL_PUBACK -> complete - // MQTT_CONTROL_PUBREC -> awaiting (Only for qos 2) - // MQTT_CONTROL_PUBREL -> awaiting (Only for qos 2) - // MQTT_CONTROL_PUBCOMP -> complete (Only for qos 2) - // MQTT_CONTROL_SUBSCRIBE -> awaiting - // MQTT_CONTROL_SUBACK -> n/a - // MQTT_CONTROL_PINGREQ -> awaiting - // MQTT_CONTROL_PINGRESP -> n/a - // MQTT_CONTROL_DISCONNECT -> complete + // update timeout watcher + client->time_of_last_send = second_counter; + msg->time_sent = client->time_of_last_send; + + // Determine the state to put the message in. + // Control Types: + // MQTT_CONTROL_CONNECT -> awaiting + // MQTT_CONTROL_CONNACK -> n/a + // MQTT_CONTROL_PUBLISH -> qos == 0 ? complete : awaiting + // MQTT_CONTROL_PUBACK -> complete + // MQTT_CONTROL_PUBREC -> awaiting (Only for qos 2) + // MQTT_CONTROL_PUBREL -> awaiting (Only for qos 2) + // MQTT_CONTROL_PUBCOMP -> complete (Only for qos 2) + // MQTT_CONTROL_SUBSCRIBE -> awaiting + // MQTT_CONTROL_SUBACK -> n/a + // MQTT_CONTROL_PINGREQ -> awaiting + // MQTT_CONTROL_PINGRESP -> n/a + // MQTT_CONTROL_DISCONNECT -> complete - switch (msg->control_type) { - case MQTT_CONTROL_PUBACK: -#if DEBUG_SUPPORT != 11 -UARTPrintf("mqtt_puback Sent PUBACK\r\n"); -#endif // DEBUG_SUPPORT != 11 - msg->state = MQTT_QUEUED_COMPLETE; - break; - case MQTT_CONTROL_DISCONNECT: - msg->state = MQTT_QUEUED_COMPLETE; - break; - case MQTT_CONTROL_PUBLISH: - inspected = (uint8_t)((MQTT_PUBLISH_QOS_MASK & (msg->start[0])) >> 1); // determine qos - if (inspected == 0) { - msg->state = MQTT_QUEUED_COMPLETE; - } - else { - msg->state = MQTT_QUEUED_AWAITING_ACK; - // set DUP flag for subsequent sends [Spec MQTT-3.3.1-1] - msg->start[0] |= MQTT_PUBLISH_DUP; - } - // Above handles QOS 0 and 1. No handling for QOS 2. - // XXXXXXXXXXXXXXXXXXXX THE NM ONLY PUBLISHES WITH QOS0. THE ABOVE - // CAN BE SIMPLIFIED. XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX - break; - case MQTT_CONTROL_CONNECT: - case MQTT_CONTROL_SUBSCRIBE: - case MQTT_CONTROL_PINGREQ: - msg->state = MQTT_QUEUED_AWAITING_ACK; - break; - default: - client->error = MQTT_ERROR_MALFORMED_REQUEST; - return MQTT_ERROR_MALFORMED_REQUEST; - } - // ADDING BREAK HERE. WE SENT ONE MESSAGE (ALL WE CAN SEND PER PASS) - break; + switch (msg->control_type) { + case MQTT_CONTROL_DISCONNECT: + msg->state = MQTT_QUEUED_COMPLETE; + break; + case MQTT_CONTROL_PUBLISH: + // This application only sends messages at QOS 0 + msg->state = MQTT_QUEUED_COMPLETE; + break; + case MQTT_CONTROL_CONNECT: + case MQTT_CONTROL_SUBSCRIBE: + case MQTT_CONTROL_PINGREQ: + msg->state = MQTT_QUEUED_AWAITING_ACK; + break; + default: + client->error = MQTT_ERROR_MALFORMED_REQUEST; + return MQTT_ERROR_MALFORMED_REQUEST; + } + // Need to break here - we sent one message (we can only send one + // message each time this function is called). + break; } // check for keep-alive { - // At about 3/4 of the timeout period perform a ping. This calculation - // uses integer arithmetic so it is only an approximation. It is assumed - // that timeouts are not a small number (for instance, the timeout should - // be at least 15 seconds). - uint32_t keep_alive_timeout = client->time_of_last_send + (uint32_t)((client->keep_alive * 3) / 4); - if ((second_counter > keep_alive_timeout) && (mqtt_start == MQTT_START_COMPLETE)) { - int16_t rv = __mqtt_ping(client); - if (rv != MQTT_OK) { - client->error = rv; - return rv; - } + // At about 3/4 of the timeout period perform a ping. This calculation + // uses integer arithmetic so it is only an approximation. It is + // assumed that timeouts are not a small number (for instance, the + // timeout should be at least 15 seconds). + // Note that a ping is required only when the module is idle, as + // indicated by checking against the time that the last command was + // sent (time_of_last_send). + uint32_t keep_alive_timeout = client->time_of_last_send + (uint32_t)((client->keep_alive * 3) / 4); + if ((second_counter > keep_alive_timeout) && (mqtt_start == MQTT_START_COMPLETE)) { + int16_t rv = __mqtt_ping(client); + if (rv != MQTT_OK) { + client->error = rv; + return rv; } + } } return MQTT_OK; } -#endif // QOS_SUPPORT == 1 -#if QOS_SUPPORT == 0 int16_t __mqtt_recv(struct mqtt_client *client) { struct mqtt_response response; @@ -718,166 +898,15 @@ int16_t __mqtt_recv(struct mqtt_client *client) // check if there is any receive data in the uip_buf. To do this we // only need to check if uip_len is > 0. If it is not we need to // generate an error by setting rv = -1. - if (uip_len > 0) rv = uip_len; + if (mqtt_partial_buffer_length > 0) rv = mqtt_partial_buffer_length; else rv = -1; client->recv_buffer.curr += rv; client->recv_buffer.curr_sz -= rv; // attempt to parse - consumed = mqtt_unpack_response(&response, client->recv_buffer.mem_start, client->recv_buffer.curr - client->recv_buffer.mem_start); - - if (consumed < 0) { - client->error = consumed; - return consumed; - } - - // response was unpacked successfully - - // The switch statement below manages how the client responds to messages - // from the broker. - - // Control Types (that we expect to receive from the broker): - // MQTT_CONTROL_CONNACK: - // -> release associated CONNECT - // -> handle response - // MQTT_CONTROL_PUBLISH: - // -> stage response, none if qos==0, PUBACK if qos==1, PUBREC if qos==2 - // -> call publish callback - // MQTT_CONTROL_PUBACK: - // -> release associated PUBLISH - // MQTT_CONTROL_PUBREC: - // -> release PUBLISH - // -> stage PUBREL - // MQTT_CONTROL_PUBREL: - // -> release associated PUBREC - // -> stage PUBCOMP - // MQTT_CONTROL_PUBCOMP: - // -> release PUBREL - // MQTT_CONTROL_SUBACK: - // -> release SUBSCRIBE - // -> handle response - // MQTT_CONTROL_UNSUBACK: - // -> release UNSUBSCRIBE - // MQTT_CONTROL_PINGRESP: - // -> release PINGREQ - switch (response.fixed_header.control_type) { - - case MQTT_CONTROL_CONNACK: - // release associated CONNECT - msg = mqtt_mq_find(&client->mq, MQTT_CONTROL_CONNECT, NULL); - connack_received = 1; // Communicate CONNACK received to main.c - if (msg == NULL) { - client->error = MQTT_ERROR_ACK_OF_UNKNOWN; - mqtt_recv_ret = MQTT_ERROR_ACK_OF_UNKNOWN; - break; - } - msg->state = MQTT_QUEUED_COMPLETE; - // check that connection was successful - if (response.decoded.connack.return_code != MQTT_CONNACK_ACCEPTED) { - if (response.decoded.connack.return_code == MQTT_CONNACK_REFUSED_IDENTIFIER_REJECTED) { - client->error = MQTT_ERROR_CONNECT_CLIENT_ID_REFUSED; - mqtt_recv_ret = MQTT_ERROR_CONNECT_CLIENT_ID_REFUSED; - } - else { - client->error = MQTT_ERROR_CONNECTION_REFUSED; - mqtt_recv_ret = MQTT_ERROR_CONNECTION_REFUSED; - } - break; - } - break; - - case MQTT_CONTROL_PUBLISH: - // QOS0 only so Call Publish Callback - client->publish_response_callback(&client->publish_response_callback_state, &response.decoded.publish); - break; - - case MQTT_CONTROL_SUBACK: - // release associated SUBSCRIBE - msg = mqtt_mq_find(&client->mq, MQTT_CONTROL_SUBSCRIBE, &response.decoded.suback.packet_id); - suback_received = 1; // Communicate SUBACK received to main.c - if (msg == NULL) { - client->error = MQTT_ERROR_ACK_OF_UNKNOWN; - mqtt_recv_ret = MQTT_ERROR_ACK_OF_UNKNOWN; - break; - } - msg->state = MQTT_QUEUED_COMPLETE; - // check that subscription was successful (currently only one - // subscribe at a time) - if (response.decoded.suback.return_codes[0] == MQTT_SUBACK_FAILURE) { - client->error = MQTT_ERROR_SUBSCRIBE_FAILED; - mqtt_recv_ret = MQTT_ERROR_SUBSCRIBE_FAILED; - break; - } - break; - - case MQTT_CONTROL_PINGRESP: - // release associated PINGREQ - msg = mqtt_mq_find(&client->mq, MQTT_CONTROL_PINGREQ, NULL); - if (msg == NULL) { - client->error = MQTT_ERROR_ACK_OF_UNKNOWN; - mqtt_recv_ret = MQTT_ERROR_ACK_OF_UNKNOWN; - break; - } - msg->state = MQTT_QUEUED_COMPLETE; - break; - - default: - client->error = MQTT_ERROR_MALFORMED_RESPONSE; - mqtt_recv_ret = MQTT_ERROR_MALFORMED_RESPONSE; - break; - } - - { - // Because we have the UIP code as the front end to MQTT there will - // never be more than one receive msg in the uip_buf, so the - // processing above will have "consumed" it. If a new receive message - // comes in on the ethernet while this code is operating it will be - // held in the enc28j60 hardware buffer until the application gets - // back around to receiving it. - // - // The original code was set up to let several messages get queued in - // the receive buffer, then those messages are read out. When a - // message is read the original code "cleans the buffer" by moving any - // remaining messages toward the beginning of the buffer, over-writing - // the messages consumed. Or at least that's what I think it's doing. - // - // Reset receive pointers to start of buffer. - client->recv_buffer.curr = client->recv_buffer.mem_start; - client->recv_buffer.curr_sz = client->recv_buffer.mem_size; - } - - // In case there was some error handling the (well formed) message, we end - // up here - return mqtt_recv_ret; -} -#endif // QOS_SUPPORT == 0 - - -#if QOS_SUPPORT == 1 -int16_t __mqtt_recv(struct mqtt_client *client) -{ - struct mqtt_response response; - int16_t mqtt_recv_ret = MQTT_OK; - int16_t rv, consumed; - struct mqtt_queued_message *msg = NULL; - - // Read the input buffer and check for errors - - // The original MQTT code used a mqtt_pal_recvall() function to move - // data from an OS host buffer into an MQTT dedicated receive buffer. - // In this application that process is not needed and we only need to - // check if there is any receive data in the uip_buf. To do this we - // only need to check if uip_len is > 0. If it is not we need to - // generate an error by setting rv = -1. - if (uip_len > 0) rv = uip_len; - else rv = -1; - - client->recv_buffer.curr += rv; - client->recv_buffer.curr_sz -= rv; - - // attempt to parse - consumed = mqtt_unpack_response(&response, client->recv_buffer.mem_start, client->recv_buffer.curr - client->recv_buffer.mem_start); +// consumed = mqtt_unpack_response(&response, client->recv_buffer.mem_start, client->recv_buffer.curr - client->recv_buffer.mem_start); + consumed = mqtt_unpack_response(&response, &uip_buf[MQTT_PBUF], mqtt_partial_buffer_length); if (consumed < 0) { client->error = consumed; @@ -899,13 +928,13 @@ int16_t __mqtt_recv(struct mqtt_client *client) // MQTT_CONTROL_PUBACK: (not implemented as we always PUBLISH with qos==0 thus // never receive a PUBACK) // -> release associated PUBLISH - // MQTT_CONTROL_PUBREC: (Only for qos 2) + // MQTT_CONTROL_PUBREC: (Not implemented - Only for qos 2) // -> release PUBLISH // -> stage PUBREL - // MQTT_CONTROL_PUBREL: (Only for qos 2) + // MQTT_CONTROL_PUBREL: (Not implemented - Only for qos 2) // -> release associated PUBREC // -> stage PUBCOMP - // MQTT_CONTROL_PUBCOMP: (Only for qos 2) + // MQTT_CONTROL_PUBCOMP: (Not implemented - Only for qos 2) // -> release PUBREL // MQTT_CONTROL_SUBACK: // -> release SUBSCRIBE @@ -915,11 +944,6 @@ int16_t __mqtt_recv(struct mqtt_client *client) // MQTT_CONTROL_PINGRESP: // -> release PINGREQ -// UARTPrintf("__mqtt_recv control_type = "); -// emb_itoa(response.fixed_header.control_type, OctetArray, 16, 4); -// UARTPrintf(OctetArray); -// UARTPrintf("\r\n"); - switch (response.fixed_header.control_type) { case MQTT_CONTROL_CONNACK: @@ -949,47 +973,15 @@ int16_t __mqtt_recv(struct mqtt_client *client) case MQTT_CONTROL_PUBLISH: // Stage response, none if qos==0, PUBACK if qos==1, PUBREC // if qos==2 - // Note1: The staged response (a PUBACK) is put in the - // mqtt_sendbuf. The PUBACK will stay in the mqtt_sendbuf until - // the __mqtt_send routine is called to empty the mqtt_sendbuf. - // Note2: The received PUBLISH being processed here (and via the - // publish_callback routine) is in the uip_buf and will stay there - // until this processing completes. - -#if DEBUG_SUPPORT != 11 -UARTPrintf("mqtt_recv Received PUBLISH\r\n"); -#endif // DEBUG_SUPPORT != 11 - -// UARTPrintf("__mqtt_recv sendbuf rem = "); -// emb_itoa(client->mq.curr_sz, OctetArray, 10, 3); -// UARTPrintf(OctetArray); -// mqtt_mq_clean(&client->mq); -// UARTPrintf(" after clean = "); -// emb_itoa(client->mq.curr_sz, OctetArray, 10, 3); -// UARTPrintf(OctetArray); -// UARTPrintf("\r\n"); - - if (response.decoded.publish.qos_level == 1) { - rv = __mqtt_puback(client, response.decoded.publish.packet_id); - if (rv != MQTT_OK) { - -#if DEBUG_SUPPORT != 11 -UARTPrintf("__mqtt_puback failed\r\n"); -#endif // DEBUG_SUPPORT != 11 - - client->error = rv; - mqtt_recv_ret = rv; - break; - } - } - // QOS2 not supported - code eliminated - // For QOS0 and QOS1 call Publish Callback. + // The received PUBLISH being processed here (and via the + // publish_callback routine) is in the MQTT Partial Buffer + // uip_buf and will stay there until this processing completes. + + // QOS1 and QOS2 not supported - code eliminated + // For QOS0 call Publish Callback. // Note that publish_callback doesn't actually put anything in the // mqtt_sendbuf, it only queues a process that will later place // PUBLISH messages in the mqtt_sendbuf. - -// UARTPrintf("mqtt_recv Calling callback\r\n"); - client->publish_response_callback(&client->publish_response_callback_state, &response.decoded.publish); break; @@ -1041,18 +1033,19 @@ UARTPrintf("__mqtt_puback failed\r\n"); // the receive buffer, then those messages are read out. When a // message is read the original code "cleans the buffer" by moving any // remaining messages toward the beginning of the buffer, over-writing - // the messages consumed. Or at least that's what I think it's doing. + // the messages consumed. Or at least that's what I think it was doing. // - // Reset receive pointers to start of buffer. - client->recv_buffer.curr = client->recv_buffer.mem_start; - client->recv_buffer.curr_sz = client->recv_buffer.mem_size; + // Reset receive pointers to start of buffer. NO LONGER NEEDED: Due to + // lack of memory in this application the receive buffer is very small + // and is fed one message at a time. +// client->recv_buffer.curr = client->recv_buffer.mem_start; +// client->recv_buffer.curr_sz = client->recv_buffer.mem_size; } // In case there was some error handling the (well formed) message, we end // up here return mqtt_recv_ret; } -#endif // QOS_SUPPORT == 1 @@ -1392,65 +1385,6 @@ int16_t mqtt_pack_ping_request(uint8_t *buf, uint16_t bufsz) /* PUBLISH */ -#if QOS_SUPPORT == 0 -int16_t mqtt_pack_publish_request(uint8_t *buf, uint16_t bufsz, - const char* topic_name, - uint16_t packet_id, - const void* application_message, - uint16_t application_message_size, - uint8_t publish_flags) -{ - const uint8_t *const start = buf; - int16_t rv; - struct mqtt_fixed_header fixed_header; - uint32_t remaining_length; - - // check for null pointers - if(buf == NULL || topic_name == NULL) { - return MQTT_ERROR_NULLPTR; - } - - // build the fixed header - fixed_header.control_type = MQTT_CONTROL_PUBLISH; - - // calculate remaining length - remaining_length = (uint32_t)__mqtt_packed_cstrlen(topic_name); - remaining_length += (uint32_t)application_message_size; - fixed_header.remaining_length = remaining_length; - - // force dup to 0 if qos is 0 [Spec MQTT-3.3.1-2] - publish_flags &= (uint8_t)(~MQTT_PUBLISH_DUP); - - fixed_header.control_flags = publish_flags; - -// UARTPrintf("mqtt_pack_publish_request flags "); -// emb_itoa(publish_flags, OctetArray, 16, 2); -// UARTPrintf(OctetArray); -// UARTPrintf("\r\n"); - - // pack fixed header - rv = mqtt_pack_fixed_header(buf, bufsz, &fixed_header); - if (rv <= 0) return rv; // something went wrong - - buf += rv; - bufsz -= rv; - - // check that buffer is big enough - if (bufsz < remaining_length) return 0; - - // pack variable header - buf += __mqtt_pack_str(buf, topic_name); - - // pack payload - memcpy(buf, application_message, application_message_size); - buf += application_message_size; - - return buf - start; -} -#endif // QOS_SUPPORT == 0 - - -#if QOS_SUPPORT == 1 int16_t mqtt_pack_publish_request(uint8_t *buf, uint16_t bufsz, const char* topic_name, uint16_t packet_id, @@ -1462,42 +1396,26 @@ int16_t mqtt_pack_publish_request(uint8_t *buf, uint16_t bufsz, int16_t rv; struct mqtt_fixed_header fixed_header; uint32_t remaining_length; - uint8_t inspected_qos; - + // check for null pointers if(buf == NULL || topic_name == NULL) { return MQTT_ERROR_NULLPTR; } - // inspect qos level - inspected_qos = (uint8_t)((publish_flags & MQTT_PUBLISH_QOS_MASK) >> 1); - // build the fixed header fixed_header.control_type = MQTT_CONTROL_PUBLISH; // calculate remaining length remaining_length = (uint32_t)__mqtt_packed_cstrlen(topic_name); - if (inspected_qos > 0) { - remaining_length += 2; - } + remaining_length += (uint32_t)application_message_size; fixed_header.remaining_length = remaining_length; // force dup to 0 if qos is 0 [Spec MQTT-3.3.1-2] publish_flags &= (uint8_t)(~MQTT_PUBLISH_DUP); - // make sure that qos is not 3 [Spec MQTT-3.3.1-2] - if (inspected_qos == 3) { - return MQTT_ERROR_PUBLISH_FORBIDDEN_QOS; - } - fixed_header.control_flags = publish_flags; -// UARTPrintf("mqtt_pack_publish_request flags "); -// emb_itoa(publish_flags, OctetArray, 16, 2); -// UARTPrintf(OctetArray); -// UARTPrintf("\r\n"); - // pack fixed header rv = mqtt_pack_fixed_header(buf, bufsz, &fixed_header); if (rv <= 0) return rv; // something went wrong @@ -1510,20 +1428,15 @@ int16_t mqtt_pack_publish_request(uint8_t *buf, uint16_t bufsz, // pack variable header buf += __mqtt_pack_str(buf, topic_name); - if (inspected_qos > 0) { - buf += __mqtt_pack_uint16(buf, packet_id); - } - + // pack payload memcpy(buf, application_message, application_message_size); buf += application_message_size; return buf - start; } -#endif // QOS_SUPPORT == 1 -#if QOS_SUPPORT == 0 int16_t mqtt_unpack_publish_response(struct mqtt_response *mqtt_response, const uint8_t *buf) { const uint8_t *const start = buf; @@ -1548,108 +1461,16 @@ int16_t mqtt_unpack_publish_response(struct mqtt_response *mqtt_response, const buf += 2; response->topic_name = buf; buf += response->topic_name_size; - - // get payload - response->application_message = buf; - response->application_message_size = (uint16_t)(fixed_header->remaining_length - response->topic_name_size - 2); - buf += response->application_message_size; - - // return number of bytes consumed - return buf - start; -} -#endif // QOS_SUPPORT == 0 - - -#if QOS_SUPPORT == 1 -int16_t mqtt_unpack_publish_response(struct mqtt_response *mqtt_response, const uint8_t *buf) -{ - const uint8_t *const start = buf; - struct mqtt_fixed_header *fixed_header; - struct mqtt_response_publish *response; - fixed_header = &(mqtt_response->fixed_header); - response = &(mqtt_response->decoded.publish); - - // get flags - response->dup_flag = (uint8_t)((fixed_header->control_flags & MQTT_PUBLISH_DUP) >> 3); - response->qos_level = (uint8_t)((fixed_header->control_flags & MQTT_PUBLISH_QOS_MASK) >> 1); - response->retain_flag = (uint8_t)(fixed_header->control_flags & MQTT_PUBLISH_RETAIN); - -#if DEBUG_SUPPORT != 11 -if (response->dup_flag == 1) { -UARTPrintf("mqtt_unpack_publish_response dup received\r\n"); -} -#endif // DEBUG_SUPPORT != 11 - - // make sure that remaining length is valid - if (mqtt_response->fixed_header.remaining_length < 4) { - return MQTT_ERROR_MALFORMED_RESPONSE; - } - - // parse variable header - response->topic_name_size = __mqtt_unpack_uint16(buf); - buf += 2; - response->topic_name = buf; - buf += response->topic_name_size; - - if (response->qos_level > 0) { - response->packet_id = __mqtt_unpack_uint16(buf); - buf += 2; - } - // get payload response->application_message = buf; - if (response->qos_level == 0) { - response->application_message_size = (uint16_t)(fixed_header->remaining_length - response->topic_name_size - 2); - } - else { - response->application_message_size = (uint16_t)(fixed_header->remaining_length - response->topic_name_size - 4); - } + + response->application_message_size = (uint16_t)(fixed_header->remaining_length - response->topic_name_size - 2); buf += response->application_message_size; // return number of bytes consumed return buf - start; } -#endif // QOS_SUPPORT == 1 - - -#if QOS_SUPPORT == 1 -/* PUBXXX */ -int16_t mqtt_pack_pubxxx_request(uint8_t *buf, uint16_t bufsz, - enum MQTTControlPacketType control_type, - uint16_t packet_id) -{ - const uint8_t *const start = buf; - struct mqtt_fixed_header fixed_header; - int16_t rv; - if (buf == NULL) { - return MQTT_ERROR_NULLPTR; - } - - /* pack fixed header */ - fixed_header.control_type = control_type; - if (control_type == MQTT_CONTROL_PUBREL) { - fixed_header.control_flags = 0x02; - } else { - fixed_header.control_flags = 0; - } - fixed_header.remaining_length = 2; - rv = mqtt_pack_fixed_header(buf, bufsz, &fixed_header); - if (rv <= 0) { - return rv; - } - buf += rv; - bufsz -= rv; - - if (bufsz < fixed_header.remaining_length) { - return 0; - } - - buf += __mqtt_pack_uint16(buf, packet_id); - - return buf - start; -} -#endif // QOS_SUPPORT == 1 /* SUBACK */ diff --git a/NetworkModule/mqtt.h b/NetworkModule/mqtt.h index 5f83eb8..e1833fd 100644 --- a/NetworkModule/mqtt.h +++ b/NetworkModule/mqtt.h @@ -691,7 +691,9 @@ struct mqtt_queued_message* mqtt_mq_find(struct mqtt_message_queue *mq, enum MQT #define mqtt_mq_get(mq_ptr, index) (((struct mqtt_queued_message*) ((mq_ptr)->mem_end)) - 1 - index) -// Returns the number of messages in the message queue, mq_ptr. +// Returns the number of messages in the message queue, mq_ptr. This will +// include messages that have already been sent if this call is not +// immediately preceded by a mqtt_mq_clean(). #define mqtt_mq_length(mq_ptr) (((struct mqtt_queued_message*) ((mq_ptr)->mem_end)) - (mq_ptr)->queue_tail) diff --git a/NetworkModule/mqtt_pal.c b/NetworkModule/mqtt_pal.c index 7dddf8f..e76e31b 100644 --- a/NetworkModule/mqtt_pal.c +++ b/NetworkModule/mqtt_pal.c @@ -217,13 +217,12 @@ int16_t mqtt_pal_sendall(const void* buf, uint16_t len) { // length of that placeholder. // // This message triggers an Output discovery message. "xx" is the output - // number. MQTT_PUBLISH_QOS_x could be MQTT_PUBLISH_QOS_0 or - // MQTT_PUBLISH_QOS_1. + // number. // mqtt_publish(&mqttclient, // topic_base, // "%Oxx", // 4, - // MQTT_PUBLISH_QOS_x | MQTT_PUBLISH_RETAIN); + // MQTT_PUBLISH_QOS_0 | MQTT_PUBLISH_RETAIN); // // This message triggers an Input discovery message. "xx" is the input // number. @@ -344,8 +343,7 @@ int16_t mqtt_pal_sendall(const void* buf, uint16_t len) { // of the application message is shown. if (payload_buf[1] == 'O') { // This is an Output auto discovery message -// payload_size = 287; // Manually calculated payload size without - payload_size = 274; // Manually calculated payload size without + payload_size = 264; // Manually calculated payload size without // devicename } if (payload_buf[1] == 'I') { @@ -466,8 +464,6 @@ int16_t mqtt_pal_sendall(const void* buf, uint16_t len) { // "avty_t":"~/availability", // 26 // "stat_t":"~/output/01", // 23 // "cmd_t":"~/output/01/set", // 26 - // "qos":"1", // 10 -// // "ret":"true", // 13 // "dev":{ // 7 // "ids":["NetworkModule_aabbccddeeff"], // 37 // "mdl":"HW-584", // 15 @@ -476,8 +472,7 @@ int16_t mqtt_pal_sendall(const void* buf, uint16_t len) { // "sw":"20201220 1322" // 20 // } // 1 // } // 1 -// // // Total: 287 plus 3 x devicename - // // Total: 274 plus 3 x devicename + // // Total: 264 plus 3 x devicename // // input payload // { // 1 @@ -574,24 +569,6 @@ int16_t mqtt_pal_sendall(const void* buf, uint16_t len) { pBuffer += 2; pBuffer = stpcpy(pBuffer, "/set\","); - -#if QOS_SUPPORT == 0 - // QOS level - pBuffer = stpcpy(pBuffer, "\"qos\":\"0\","); -#if DEBUG_SUPPORT != 11 -UARTPrintf("mqtt_pal_sendall Sent QOS = 0\r\n"); -#endif // DEBUG_SUPPORT != 11 -#endif // QOS_SUPPORT == 0 - -#if QOS_SUPPORT == 1 - // QOS level - pBuffer = stpcpy(pBuffer, "\"qos\":\"1\","); -#if DEBUG_SUPPORT != 11 -UARTPrintf("mqtt_pal_sendall Sent QOS = 1\r\n"); -#endif // DEBUG_SUPPORT != 11 - // Retain True -// pBuffer = stpcpy(pBuffer, "\"ret\":\"true\","); -#endif // QOS_SUPPORT == 1 } // Special case for temperature pin diff --git a/NetworkModule/uip.c b/NetworkModule/uip.c index 6c9c03c..e846b7b 100644 --- a/NetworkModule/uip.c +++ b/NetworkModule/uip.c @@ -486,8 +486,6 @@ void uip_process(uint8_t flag) // Check if we were invoked because of a poll request for a particular // connection. A UIP_POLL_REQUEST will occur without any receive data // present, so uip_len should be zero when it occurs. - // UIP_POLL_REQUEST IS NOT USED IN THIS APPLICATION, SO THIS CODE COULD BE - // REMOVED. THAT WOULD ONLY SAVE 21 BYTES, BUT REMOVAL IS AN OPTION. if (flag == UIP_POLL_REQUEST) { if ((uip_connr->tcpstateflags & UIP_TS_MASK) == UIP_ESTABLISHED && !uip_outstanding(uip_connr)) { // UARTPrintf(" uip.c: APPCALL due to POLL REQUEST\r\n"); @@ -519,9 +517,9 @@ void uip_process(uint8_t flag) // connection to time out. If so, we increase the connection's timer and // remove the connection if it times out. if (uip_connr->tcpstateflags == UIP_TIME_WAIT || uip_connr->tcpstateflags == UIP_FIN_WAIT_2) { -#if DEBUG_SUPPORT != 11 -UARTPrintf(" uip.c: periodic APPCALL waiting for timeout\r\n"); -#endif // DEBUG_SUPPORT != 11 +// #if DEBUG_SUPPORT != 11 +// UARTPrintf(" uip.c: periodic APPCALL waiting for timeout\r\n"); +// #endif // DEBUG_SUPPORT != 11 ++(uip_connr->timer); if (uip_connr->timer == UIP_TIME_WAIT_TIMEOUT) { uip_connr->tcpstateflags = UIP_CLOSED; @@ -710,7 +708,8 @@ UARTPrintf(" uip.c: periodic APPCALL waiting for timeout\r\n"); // ----------------------------------------------------------------------- // - // TCP input processing. + // TCP input processing. At this point we've determined that incoming data + // is for us. tcp_input: UIP_STAT(++uip_stat.tcp.recv); @@ -860,7 +859,8 @@ UARTPrintf(" uip.c: periodic APPCALL waiting for timeout\r\n"); uip_connr->rcv_nxt[0] = BUF->seqno[0]; uip_add_rcv_nxt(1); - // Parse the TCP MSS option, if present. + // Parse the TCP MSS option, if present. This is a received SYN, so we are + // capturing the MSS of the host. if ((BUF->tcpoffset & 0xf0) > 0x50) { for (c = 0; c < ((BUF->tcpoffset >> 4) - 5) << 2;) { opt = uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + c]; @@ -877,7 +877,28 @@ UARTPrintf(" uip.c: periodic APPCALL waiting for timeout\r\n"); // An MSS option with the right option length. tmp16 = ((uint16_t)uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 2 + c] << 8) | (uint16_t)uip_buf[UIP_IPTCPH_LEN + UIP_LLH_LEN + 3 + c]; - uip_connr->initialmss = uip_connr->mss = tmp16 > UIP_TCP_MSS ? UIP_TCP_MSS : tmp16; + +// The host should never send a SYN by itself ... as the host doesn't set up +// connections with the application. Still, if it does send one display the +// value. +// #if DEBUG_SUPPORT != 11 +// UARTPrintf("found_listen: Incoming MSS = "); +// emb_itoa(tmp16, OctetArray, 10, 5); +// UARTPrintf(OctetArray); +// UARTPrintf("\r\n"); +// #endif // DEBUG_SUPPORT != 11 + + // MODIFICATION FOR THIS APPLICATION: The original uip.c code would + // set the receive MSS and transmit MSS to be the same. So the smaller + // of the advertised MSS from the host or the UIP_TCP_MSS would get + // used for BOTH transmit and receive. This does not have to be the + // case. The host MSS can (and, for this application, always will) be + // larger than the application MSS because this application uses such + // a small transmit buffer, and hosts always have large buffers. Here + // the original code is commented out and replaced with code that + // maintains the UIP_TCP_MSS as the receive MSS. +// uip_connr->initialmss = uip_connr->mss = tmp16 > UIP_TCP_MSS ? UIP_TCP_MSS : tmp16; + uip_connr->initialmss = uip_connr->mss = UIP_TCP_MSS; // And we are done processing options. break; @@ -939,7 +960,147 @@ UARTPrintf(" uip.c: periodic APPCALL waiting for timeout\r\n"); UIP_APPCALL(); // ???? goto drop; } + + +/* +#if DEBUG_SUPPORT != 11 +{ + // Display the first 20 bytes of the app_data + int q; + char *qBuffer; + char temp; + uint16_t port; + uint8_t IP; + + // Extract the source IP address from the headers + qBuffer = &uip_buf[0]; + qBuffer += 26; + UARTPrintf("uip_process - Source IP = "); + IP = *qBuffer; + emb_itoa(IP, OctetArray, 10, 3); + UARTPrintf(OctetArray); + qBuffer++; + UARTPrintf(" "); + IP = *qBuffer; + emb_itoa(IP, OctetArray, 10, 3); + UARTPrintf(OctetArray); + qBuffer++; + UARTPrintf(" "); + IP = *qBuffer; + emb_itoa(IP, OctetArray, 10, 3); + UARTPrintf(OctetArray); + qBuffer++; + UARTPrintf(" "); + IP = *qBuffer; + emb_itoa(IP, OctetArray, 10, 3); + UARTPrintf(OctetArray); + qBuffer++; + + // Extract the destination port from the headers + qBuffer = &uip_buf[0]; + qBuffer += 36; + UARTPrintf(" Port = "); + port = (*qBuffer << 8); + qBuffer++; + port += *qBuffer; + emb_itoa(port, OctetArray, 10, 5); + UARTPrintf(OctetArray); + // Extract the total length from the headers + qBuffer = &uip_buf[0]; + qBuffer += 16; + UARTPrintf(" Total Length = "); + port = (*qBuffer << 8); + qBuffer++; + port += *qBuffer; + emb_itoa(port, OctetArray, 10, 4); + UARTPrintf(OctetArray); + UARTPrintf("\r\n"); + +/* + // Display the content of the uip_buf + qBuffer = uip_appdata; + UARTPrintf("uip_process - uip_appdata hex row1 = "); + for (q = 0; q<20; q++) { + emb_itoa(*qBuffer, OctetArray, 16, 2); + UARTPrintf(OctetArray); + UARTPrintf(" "); + qBuffer++; + } + UARTPrintf("\r\n"); + UARTPrintf("uip_process - uip_appdata hex row2 = "); + for (q = 0; q<20; q++) { + emb_itoa(*qBuffer, OctetArray, 16, 2); + UARTPrintf(OctetArray); + UARTPrintf(" "); + qBuffer++; + } + UARTPrintf("\r\n"); + UARTPrintf("uip_process - uip_appdata hex row3 = "); + for (q = 0; q<20; q++) { + emb_itoa(*qBuffer, OctetArray, 16, 2); + UARTPrintf(OctetArray); + UARTPrintf(" "); + qBuffer++; + } + UARTPrintf("\r\n"); + + // Display the content of the uip_buf in text format + qBuffer = uip_appdata; + UARTPrintf("uip_process - uip_appdata txt row1 = "); + for (q = 0; q<20; q++) { + if (*qBuffer > 31 && *qBuffer < 127) { + UARTPrintf(" "); + OctetArray[0] = *qBuffer; + OctetArray[1] = 0; + UARTPrintf(OctetArray); + } + else { + emb_itoa(*qBuffer, OctetArray, 16, 2); + UARTPrintf(OctetArray); + } + UARTPrintf(" "); + qBuffer++; + } + UARTPrintf("\r\n"); + UARTPrintf("uip_process - uip_appdata txt row2 = "); + for (q = 0; q<20; q++) { + if (*qBuffer > 31 && *qBuffer < 127) { + UARTPrintf(" "); + OctetArray[0] = *qBuffer; + OctetArray[1] = 0; + UARTPrintf(OctetArray); + } + else { + emb_itoa(*qBuffer, OctetArray, 16, 2); + UARTPrintf(OctetArray); + } + UARTPrintf(" "); + qBuffer++; + } + UARTPrintf("\r\n"); + UARTPrintf("uip_process - uip_appdata txt row3 = "); + for (q = 0; q<20; q++) { + if (*qBuffer > 31 && *qBuffer < 127) { + UARTPrintf(" "); + OctetArray[0] = *qBuffer; + OctetArray[1] = 0; + UARTPrintf(OctetArray); + } + else { + emb_itoa(*qBuffer, OctetArray, 16, 2); + UARTPrintf(OctetArray); + } + UARTPrintf(" "); + qBuffer++; + } + UARTPrintf("\r\n"); +} +#endif // DEBUG_SUPPORT != 11 +*/ + + + // Calculate the length of the data, if the application has sent any data // to us. // @@ -967,6 +1128,9 @@ UARTPrintf(" uip.c: periodic APPCALL waiting for timeout\r\n"); || BUF->seqno[1] != uip_connr->rcv_nxt[1] || BUF->seqno[2] != uip_connr->rcv_nxt[2] || BUF->seqno[3] != uip_connr->rcv_nxt[3])) { +// #if DEBUG_SUPPORT != 11 +// UARTPrintf("uip_process - Unexpected sequence number - sending ACK\r\n"); +// #endif // DEBUG_SUPPORT != 11 goto tcp_send_ack; } } @@ -1040,7 +1204,8 @@ UARTPrintf(" uip.c: periodic APPCALL waiting for timeout\r\n"); // and we send an ACK. We move into the ESTABLISHED state. if((uip_flags & UIP_ACKDATA) && (BUF->flags & TCP_CTL) == (TCP_SYN | TCP_ACK)) { - // Parse the TCP MSS option, if present + // Parse the TCP MSS option, if present. This is a received SYN, so we + // are capturing the MSS of the host. if((BUF->tcpoffset & 0xf0) > 0x50) { for(c = 0; c < ((BUF->tcpoffset >> 4) - 5) << 2 ;) { opt = uip_buf[UIP_IPTCPH_LEN + UIP_LLH_LEN + c]; @@ -1057,8 +1222,27 @@ UARTPrintf(" uip.c: periodic APPCALL waiting for timeout\r\n"); // An MSS option with the right option length tmp16 = (uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 2 + c] << 8) | uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 3 + c]; - uip_connr->initialmss = - uip_connr->mss = tmp16 > UIP_TCP_MSS? UIP_TCP_MSS: tmp16; + +// This is the host response to our SYN. Display the value. +// #if DEBUG_SUPPORT != 11 +// UARTPrintf("case UIP_SYN_SENT - Incoming SYNACK: Incoming MSS = "); +// emb_itoa(tmp16, OctetArray, 10, 5); +// UARTPrintf(OctetArray); +// UARTPrintf("\r\n"); +// #endif // DEBUG_SUPPORT != 11 + + // MODIFICATION FOR THIS APPLICATION: The original uip.c code + // would set the receive MSS and transmit MSS to be the same. So + // the smaller of the advertised MSS from the host or the + // UIP_TCP_MSS would get used for BOTH transmit and receive. This + // does not have to be the case. The host MSS can (and, for this + // application, always will) be larger than the application MSS + // because this application uses such a small transmit buffer, + // and hosts always have large buffers. Here the original code is + // commented out and replaced with code that maintains the + // UIP_TCP_MSS as the receive MSS. + // uip_connr->initialmss = uip_connr->mss = tmp16 > UIP_TCP_MSS? UIP_TCP_MSS: tmp16; + uip_connr->initialmss = uip_connr->mss = UIP_TCP_MSS; // And we are done processing options break; @@ -1166,11 +1350,17 @@ UARTPrintf(" uip.c: periodic APPCALL waiting for timeout\r\n"); // This data will not be acknowledged by the receiver, and the // application will retransmit it. This is called the "persistent timer" // and uses the retransmission mechanim. - tmp16 = ((uint16_t)BUF->wnd[0] << 8) + (uint16_t)BUF->wnd[1]; - if (tmp16 > uip_connr->initialmss || tmp16 == 0) { - tmp16 = uip_connr->initialmss; - } - uip_connr->mss = tmp16; + // + // MODIFICATION FOR THIS APPLICATION: We don't want to change the + // uip_connr->mss value based on anything the host sends us. If for + // some reason the host sends a window size that is small it implies + // an error somewhere. I believe this code should be disabled and + // looked at again later. +// tmp16 = ((uint16_t)BUF->wnd[0] << 8) + (uint16_t)BUF->wnd[1]; +// if (tmp16 > uip_connr->initialmss || tmp16 == 0) { +// tmp16 = uip_connr->initialmss; +// } +// uip_connr->mss = tmp16; // If this packet constitutes an ACK for outstanding data (flagged by // the UIP_ACKDATA flag), we should call the application since it might @@ -1218,6 +1408,9 @@ UARTPrintf(" uip.c: periodic APPCALL waiting for timeout\r\n"); // If uip_slen > 0, the application has data to be sent. if (uip_slen > 0) { +// #if DEBUG_SUPPORT != 11 +// UARTPrintf("uip.c uip_slen > 0\r\n"); +// #endif // DEBUG_SUPPORT != 11 // If the connection has acknowledged data, the contents of the // ->len variable should be discarded. if ((uip_flags & UIP_ACKDATA) != 0) { @@ -1229,9 +1422,20 @@ UARTPrintf(" uip.c: periodic APPCALL waiting for timeout\r\n"); if (uip_connr->len == 0) { // The application cannot send more than what is allowed by the // mss (the minumum of the MSS and the available window). - if (uip_slen > uip_connr->mss) { - uip_slen = uip_connr->mss; - } + // + // MODIFICATION FOR THIS APPLICATION: The original uip.c code + // would set the receive MSS and transmit MSS to be the same. So + // the smaller of the advertised MSS from the host or the + // UIP_TCP_MSS would get used for BOTH transmit and receive. This + // does not have to be the case. The host MSS can (and, for this + // application, always will) be larger than the application MSS + // because this application uses such a small transmit buffer, + // and hosts always have large buffers. Here the original code is + // commented out and an assumption made that the host can receive + // the small transmit we are making. +// if (uip_slen > uip_connr->mss) { +// uip_slen = uip_connr->mss; +// } // Remember how much data we send out now so that we know when // everything has been acknowledged. diff --git a/NetworkModule/uipopt.h b/NetworkModule/uipopt.h index 574dc18..4a58f08 100644 --- a/NetworkModule/uipopt.h +++ b/NetworkModule/uipopt.h @@ -144,12 +144,42 @@ // The TCP Maximum Segment size. This should be set to no more than // UIP_BUFSIZE - UIP_LLH_LEN - UIP_TCPIP_HLEN. This ends up being the maximum // size of the part of the datagram that can be transmitted to the Browser or -// to the MQTT server in each packet. NOTE: Experimentation has shown that the -// UIP_TCP_MSS should actually be slightly smaller to avoid errors (not sure -// why and could use more investigation). So an additional 6 bytes are -// subtracted. +// to the MQTT server in each packet. +// +// NOTE1: Experimentation has shown that the UIP_TCP_MSS should actually be +// slightly smaller than the original code defined. "Slightly" appears to be +// at least 4 bytes. This is to avoid errors (not sure why and could use more +// investigation). To be safe an additional 6 bytes are subtracted. +// if NAGLE_SUPPORT == 1 +// +// NOTE2: When MQTT support was added two problems occurred: +// 1) It was found that during MQTT startup, if Home Assistant Auto Discovery +// was used, a larger uip_buf was needed to trasnmit some of the Auto +// Discovery messages in a single packet. This consumed nearly all the +// available RAM. +// 2) Later it was found that Home Assistant used Nagle's Algorithm to pack +// multiple MQTT messages into single datagrams, AND that those datagrams +// could span multiple packets when transmitted to the Network Module. So, +// memory was needed to deconstruct the datagram into individual MQTT +// messages and to reconstruct the MQTT messages that spanned a packet +// boundary. +// To handle the above the upper part of the uip_buf is made available for use +// as an "MQTT partial buffer" (a receive reconstruction buffer) after MQTT +// startup has completed. This is done by making the UIP_TCP_MSS value smaller +// by another 60 bytes, then using pointers based on a "MQTT_PBUF" define to +// access the memory area. +// endif NAGLE_SUPPORT == 1 +// // In this application the headers occupy a total of 54 bytes as defined in uip.h. -#define UIP_TCP_MSS (UIP_BUFSIZE - UIP_LLH_LEN - UIP_TCPIP_HLEN - 6) +#define UIP_TCP_MSS (UIP_BUFSIZE - UIP_LLH_LEN - UIP_TCPIP_HLEN - 6 - 60) + + +// if NAGLE_SUPPORT == 1 +// The starting point of the MQTT Partial Buffer within the uip_buf +// See explantion in #define UIP_TCP_MSS +#define MQTT_PBUF_SIZE 60 +#define MQTT_PBUF (UIP_BUFSIZE - MQTT_PBUF_SIZE) +// endif NAGLE_SUPPORT == 1 // The size of the advertised receiver's window. Should be set low (i.e., to @@ -314,8 +344,8 @@ // Code Uploader requires additional hardware in the form of an off-board I2C // EEPROM, thus OB_EEPROM_SUPPORT and I2C_SUPPORT must be enabled. // Un-comment ONLY ONE of the following: -// #define BUILD_SUPPORT MQTT_BUILD -#define BUILD_SUPPORT BROWSER_ONLY_BUILD +#define BUILD_SUPPORT MQTT_BUILD +// #define BUILD_SUPPORT BROWSER_ONLY_BUILD // #define BUILD_SUPPORT CODE_UPLOADER_BUILD @@ -362,23 +392,13 @@ #define DEBUG_SENSOR_SERIAL 0 -// QOS_SUPPORT -// Determines the QOS level supported in MQTT when receiving PUBLISH messages -// from the Broker/Server. -// QOS 0 works for most applications because the PUBLISH messaging rate to the -// Network Module can be limited by the host based application and the usage -// model for the Network Module is to be on a local network only. However, -// Home Assistant has a "Toggle" function that can result in very rapid -// message delivery to the Network Module so QOS 1 was implemented to assist -// in assuring that all HA PUBLISH messages are properly received by the -// Network Module. -// Even when QOS 1 is enabled the setting should have no effect on host -// applications that deliver messages with QOS 0. -// THIS IS A TEMPORARY BUILD MODE TO ALLOW TRANSITION TO QOS 1 MODE. -// EVENTUALLY THE "QOS 0 ONLY" CODE WILL BE REMOVED. -// 0 = "Fire and Forget" Mode -// 1 = Acknowlege Receipt Mode -#define QOS_SUPPORT 1 +// NAGLE_SUPPORT +// Temporary build setting to enable support of Nagle's Algorithm in the MQTT +// code. +// THIS IS A TEMPORARY BUILD MODE. DELETE WHEN TESTING IS COMPLETE. +// 0 = No Nagle's Algorithm support +// 1 = Supported +#define NAGLE_SUPPORT 1