diff --git a/Network Module Manual - Code Rev 20210221 1826.odt b/Network Module Manual - Code Rev 20210412 1333.docx
similarity index 62%
rename from Network Module Manual - Code Rev 20210221 1826.odt
rename to Network Module Manual - Code Rev 20210412 1333.docx
index ccde996..a97b7dc 100644
Binary files a/Network Module Manual - Code Rev 20210221 1826.odt and b/Network Module Manual - Code Rev 20210412 1333.docx differ
diff --git a/Network Module Manual - Code Rev 20210221 1826.docx b/Network Module Manual - Code Rev 20210412 1333.odt
similarity index 63%
rename from Network Module Manual - Code Rev 20210221 1826.docx
rename to Network Module Manual - Code Rev 20210412 1333.odt
index 6f01c3d..c1d4834 100644
Binary files a/Network Module Manual - Code Rev 20210221 1826.docx and b/Network Module Manual - Code Rev 20210412 1333.odt differ
diff --git a/Network Module Manual - Code Rev 20210221 1826.pdf b/Network Module Manual - Code Rev 20210412 1333.pdf
similarity index 68%
rename from Network Module Manual - Code Rev 20210221 1826.pdf
rename to Network Module Manual - Code Rev 20210412 1333.pdf
index 348a4d9..73c6d96 100644
Binary files a/Network Module Manual - Code Rev 20210221 1826.pdf and b/Network Module Manual - Code Rev 20210412 1333.pdf differ
diff --git a/NetworkModule/.Idea_Groups/Vector_File.grp b/NetworkModule/.Idea_Groups/Vector_File.grp
index 5e9643c..e98043b 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:
-# Sun Feb 21 11:31:10 2021
+# Mon Apr 12 07:55:28 2021
#
"networkmodule_vector.o"
diff --git a/NetworkModule/.Idea_Temp/COBJ.TMP b/NetworkModule/.Idea_Temp/COBJ.TMP
index 52e20fd..cccef5b 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
12 sections
-580 symbols
-5823 debug symbols
+568 symbols
+5478 debug symbols
sections:
.vector: hilo code, at address 0x8000
128 data bytes (0x0080)
.const: hilo code, at address 0x8080
- 7217 data bytes (0x1c31)
-.text: hilo code, at address 0x9cb1
- 23774 data bytes (0x5cde)
+ 7215 data bytes (0x1c2f)
+.text: hilo code, at address 0x9caf
+ 23458 data bytes (0x5ba2)
.eeprom: hilo, at address 0x4000
128 data bytes (0x0080)
.bsct: no attribute, at address 0x0
@@ -26,191 +26,177 @@ sections:
.data: hilo, at address 0xa
8 data bytes (0x0008)
.bss: bss hilo, at address 0x12
- 1456 reserved bytes (0x05b0)
+ 1365 reserved bytes (0x0555)
.iconst: bss hilo, at address 0x5fe
2 reserved bytes (0x0002)
.debug: hilo, at address 0x0
- 83054 data bytes (0x1446e)
+ 88978 data bytes (0x15b92)
.info.: no attribute, at address 0x0
- 3537 data bytes (0x0dd1)
+ 3609 data bytes (0x0e19)
symbols:
-__memory: 000005c2 section .bss defined public
-c_ftoi: 0000f664 section .text defined public
-___mqtt_pack_uint16: 0000df09 section .text defined public
-___mqtt_unpack_uint16: 0000df2d section .text defined public
-___mqtt_recv: 0000d56d section .text defined public
-c_uitof: 0000f964 section .text defined public
-c_itoly: 0000f6f5 section .text defined public
-_mqtt_sync: 0000d073 section .text defined public
-_mqtt_unpack_response: 0000de9f section .text defined public
-_mqtt_unpack_connack_response: 0000d9b8 section .text defined public
-_mqtt_unpack_publish_response: 0000daf2 section .text defined public
-_mqtt_unpack_suback_response: 0000db7b section .text defined public
-_memmove: 0000f4aa section .text defined public
-_uip_ipchksum: 0000e570 section .text defined public
-_uip_tcpchksum: 0000e5d6 section .text defined public
+__memory: 00000567 section .bss defined public
+___mqtt_recv: 0000d528 section .text defined public
+c_itoly: 0000f566 section .text defined public
+_mqtt_sync: 0000d030 section .text defined public
+_mqtt_unpack_response: 0000de52 section .text defined public
+_mqtt_unpack_connack_response: 0000d96b section .text defined public
+_mqtt_unpack_publish_response: 0000daa5 section .text defined public
+_mqtt_unpack_suback_response: 0000db2e section .text defined public
+_memmove: 0000f460 section .text defined public
+_uip_ipchksum: 0000e511 section .text defined public
+_uip_tcpchksum: 0000e577 section .text defined public
c_y: 00000007 section .ubsct defined public zpage
-c_lgursh: 0000f7b3 section .text defined public
-c_lgsbc: 0000f79d section .text defined public
+c_lgsbc: 0000f72b section .text defined public
_stored_EEPROM_revision1: 00004015 section .eeprom defined public
-_check_mqtt_server_arp_entry: 0000f3b2 section .text defined public
+_check_mqtt_server_arp_entry: 0000f352 section .text defined public
_stack_limit1: 000005ff section .iconst defined public
_stored_unused1: 00004014 section .eeprom defined public
-_ON_OFF_word_new1: 000001f4 section .bss defined public
+_ON_OFF_word_new1: 0000019a section .bss defined public
_stored_unused3: 0000404c section .eeprom defined public
-_uip_listenports: 000002cd section .bss defined public
+_uip_listenports: 00000272 section .bss defined public
_stored_unused4: 0000404d section .eeprom defined public
-c_divul: 0000f7fe section .text defined public
-_check_restart_reboot: 0000cc49 section .text defined public
-_reboot: 0000cdca section .text defined public
-___mqtt_next_pid: 0000d0a9 section .text defined public
+c_divul: 0000f5f8 section .text defined public
+_check_restart_reboot: 0000cc06 section .text defined public
+_reboot: 0000cd87 section .text defined public
+___mqtt_next_pid: 0000d066 section .text defined public
_stored_unused5: 0000404e section .eeprom defined public
-_uip_buf: 00000398 section .bss defined public
-_mqtt_sendbuf: 00000228 section .bss defined public
-_init_IWDG: 0000ce10 section .text defined public
+_init_IWDG: 0000cdcd section .text defined public
_stored_prior_config: 00004050 section .eeprom defined public
-_mqtt_close_tcp: 000001a1 section .bss defined public
-_mqtt_start: 00000128 section .bss defined public
-_restart: 0000cd83 section .text defined public
-_mqtt_sanity_ctr: 00000124 section .bss defined public
-_check_DS18B20_ctr: 000000e5 section .bss defined public
-___mqtt_pack_str: 0000df4a section .text defined public
-_uip_arp_arpin: 0000f1b8 section .text defined public
-_mqtt_mq_clean: 0000dd15 section .text defined public
-_uip_conns: 000002ee section .bss defined public
-_check_reset_button: 0000cf55 section .text defined public
-_topic_base: 000000ee section .bss defined public
-_mqtt_subscribe: 0000d296 section .text defined public
-_unlock_eeprom: 0000c5b1 section .text defined public
-_lock_eeprom: 0000c5c1 section .text defined public
-_uip_init_stats: 0000e6a3 section .text defined public
-_preload_alphas: 0000b522 section .text defined public
-_check_alphas: 0000b52f section .text defined public
-c_lumd: 0000f8fa section .text defined public
-_clear_saved_postpartial_all: 0000b508 section .text defined public
-_HttpDCall: 0000ab6e section .text defined public
-_periodic_timer_expired: 0000e457 section .text defined public
-_t100ms_timer_expired: 0000e487 section .text defined public
-_mqtt_outbound_timer_expired: 0000e467 section .text defined public
-_mqtt_timer_expired: 0000e477 section .text defined public
-_arp_timer_expired: 0000e497 section .text defined public
-_connack_received: 000002b5 section .bss defined public
-_suback_received: 000002b4 section .bss defined public
-_publish_pinstate_all: 0000c471 section .text defined public
-_mqtt_pal_sendall: 0000df9b section .text defined public
-_mqtt_pal_recvall: 0000e26b section .text defined public
-_uip_TcpAppHubCall: 0000f440 section .text defined public
-_code_revision: 00009a27 section .const defined public
-_ps: 00009689 section .const defined public
-c_eewrc: 0000f53f section .text defined public
-_uip_flags: 000002e9 section .bss defined public
-_connect_flags: 00000171 section .bss defined public
-_saved_postpartial_previous: 0000006b section .bss defined public
-_adjust_template_size: 0000a54f section .text defined public
+_mqtt_close_tcp: 00000147 section .bss defined public
+_mqtt_start: 000000f4 section .bss defined public
+_restart: 0000cd40 section .text defined public
+_mqtt_sanity_ctr: 000000f1 section .bss defined public
+_check_DS18B20_ctr: 0000008a section .bss defined public
+___mqtt_pack_str: 0000defd section .text defined public
+_uip_process: 0000e68b section .text defined public
+_uip_arp_arpin: 0000f158 section .text defined public
+_mqtt_mq_clean: 0000dcc8 section .text defined public
+_uip_conns: 00000293 section .bss defined public
+_check_reset_button: 0000cf12 section .text defined public
+_topic_base: 000000bb section .bss defined public
+_mqtt_subscribe: 0000d253 section .text defined public
+_unlock_eeprom: 0000c56e section .text defined public
+_lock_eeprom: 0000c57e section .text defined public
+c_lumd: 0000f7a1 section .text defined public
+_HttpDCall: 0000ac88 section .text defined public
+_periodic_timer_expired: 0000e3f8 section .text defined public
+_t100ms_timer_expired: 0000e428 section .text defined public
+_mqtt_outbound_timer_expired: 0000e408 section .text defined public
+_mqtt_timer_expired: 0000e418 section .text defined public
+_arp_timer_expired: 0000e438 section .text defined public
+_connack_received: 0000025b section .bss defined public
+_suback_received: 0000025a section .bss defined public
+_publish_pinstate_all: 0000c43d section .text defined public
+_mqtt_pal_sendall: 0000df4e section .text defined public
+_uip_TcpAppHubCall: 0000f3e0 section .text defined public
+_mac_string: 0000014c section .bss defined public
+_show_temperature_string: 0000ac22 section .text defined public
+_update_mac_string: 0000c95a section .text defined public
+___mqtt_ping: 0000d2d2 section .text defined public
+_uip_flags: 0000028e section .bss defined public
+_connect_flags: 00000139 section .bss defined public
_current_webpage: 00000047 section .bss defined public
+_update_debug_storage1: 0000d003 section .text defined public
+_htons: 0000efb9 section .text defined public
+_parse_tail: 0000004a section .bss defined public
+_hex2int: 0000a761 section .text defined public
+_two_hex2int: 0000a781 section .text defined public
+_auto_pub_count: 000000ba section .bss defined public
+_mqttclient: 00000111 section .bss defined public
+_ON_OFF_word_sent: 00000196 section .bss defined public
+_adjust_template_size: 0000a605 section .text defined public
+_break_while: 00000048 section .bss defined public
_stored_devicename: 00004000 section .eeprom defined public
_stored_mqtt_username: 00004035 section .eeprom defined public
-_Pending_devicename: 000001ca section .bss defined public
-_Pending_mqtt_username: 0000017d section .bss defined public
-_strlen: 0000f50f section .text defined public
-_uip_listen: 0000e6a4 section .text defined public
-_uip_len: 00000394 section .bss defined public
+_Pending_devicename: 00000170 section .bss defined public
+_Pending_mqtt_username: 000000a6 section .bss defined public
+_parse_local_buf: 0000b5a1 section .text defined public
+_uip_buf: 0000033d section .bss defined public
+_mqtt_sendbuf: 000001ce section .bss defined public
+_strlen: 0000f4d8 section .text defined public
+_uip_listen: 0000e644 section .text defined public
+_uip_len: 00000339 section .bss defined public
_stored_unused6: 0000404f section .eeprom defined public
-_uip_slen: 000002d5 section .bss defined public
-_stored_mqtt_password: 00004040 section .eeprom defined public
-_saved_postpartial: 0000008f section .bss defined public
-_Pending_mqtt_password: 00000172 section .bss defined public
-_Invert_word: 000001ee section .bss defined public
-_ON_OFF_word: 000001f6 section .bss defined public
-c_eewrd: 0000f572 section .text defined public
-c_rtol: 0000f927 section .text defined public
-_Port_Httpd: 0000019d section .bss defined public
-_saved_nparseleft: 000000b3 section .bss defined public
-c_ftol: 0000f66a section .text defined public
-c_ludv: 0000f7d3 section .text defined public
-_alpha: 00000048 section .bss defined public
-_hex2int: 0000a692 section .text defined public
-_auto_pub_count: 000000ea section .bss defined public
-_mqttclient: 00000145 section .bss defined public
-_ON_OFF_word_sent: 000001f0 section .bss defined public
-_int2hex: 0000a6b2 section .text defined public
-_isxdigit: 0000f490 section .text defined public
-c_lglsh: 0000f778 section .text defined public
-_break_while: 00000068 section .bss defined public
+_uip_slen: 0000027a section .bss defined public
+_uip_conn: 00000337 section .bss defined public
+_mqtt_conn: 000000ef section .bss defined public
+_code_revision: 00009a30 section .const defined public
_stored_debug: 00004062 section .eeprom defined public
-_debug: 00000208 section .bss defined public
-_uip_conn: 00000392 section .bss defined public
-_mqtt_conn: 00000122 section .bss defined public
-_htons: 0000f019 section .text defined public
-_z_diag: 00000069 section .bss defined public
-_parse_POST_address: 0000b6be section .text defined public
-_uip_process: 0000e6eb section .text defined public
-_update_debug_storage1: 0000d046 section .text defined public
-_update_ON_OFF: 0000b4c7 section .text defined public
-_debugflash: 0000cfc1 section .text defined public
-_mqtt_publish: 0000d205 section .text defined public
-_fastflash: 0000cff5 section .text defined public
+_debug: 000001ae section .bss defined public
+_z_diag: 00000049 section .bss defined public
+_ps: 000096db section .const defined public
+c_eewrc: 0000f508 section .text defined public
+_stored_mqtt_password: 00004040 section .eeprom defined public
+_Pending_mqtt_password: 0000009b section .bss defined public
+_Invert_word: 00000194 section .bss defined public
+_ON_OFF_word: 0000019c section .bss defined public
+c_eewrd: 0000f53b section .text defined public
+c_ludv: 0000f78d section .text defined public
+_int2hex: 0000a79c section .text defined public
+c_lglsh: 0000f6f3 section .text defined public
+_update_ON_OFF: 0000b954 section .text defined public
+_debugflash: 0000cf7e section .text defined public
+_mqtt_publish: 0000d1c2 section .text defined public
+_fastflash: 0000cfb2 section .text defined public
__endzp: 0000000a section .ubsct defined public
_magic1: 0000402b section .eeprom defined public
_magic3: 0000402d section .eeprom defined public
-_parse_POST_MAC: 0000b8d3 section .text defined public
-_write_output_pins: 0000cee2 section .text defined public
-_read_input_pins: 0000ce25 section .text defined public
-_io_map: 00008090 section .const defined public
-_encode_16bit_registers: 0000b9bd section .text defined public
-_uip_netmask: 000002e1 section .bss defined public
-_Pending_netmask: 000001e0 section .bss defined public
+_write_output_pins: 0000ce9f section .text defined public
+_read_input_pins: 0000cde2 section .text defined public
+_io_map: 000080a3 section .const defined public
+_encode_16bit_registers: 0000b995 section .text defined public
+_uip_netmask: 00000286 section .bss defined public
+_Pending_netmask: 00000186 section .bss defined public
_stored_netmask: 0000401f section .eeprom defined public
-_Enc28j60Send: 0000a33d section .text defined public
-_uip_send: 0000f01a section .text defined public
-_publish_outbound: 0000c2b4 section .text defined public
-___mqtt_send: 0000d3db section .text defined public
-_mqtt_mq_find: 0000de63 section .text defined public
-_Enc28j60ReadPhy: 0000a0c5 section .text defined public
-_Enc28j60WritePhy: 0000a112 section .text defined public
-_stpcpy: 0000df85 section .text defined public
-_select: 0000a042 section .text defined public
-_deselect: 0000a048 section .text defined public
-_uip_connect: 0000e60a section .text defined public
-_mqtt_connect: 0000d15b section .text defined public
-_mqtt_disconnect: 0000d378 section .text defined public
-_mqtt_pack_disconnect: 0000da08 section .text defined public
-_RXERIF_counter: 00000194 section .bss defined public
-_TXERIF_counter: 00000193 section .bss defined public
-_TRANSMIT_counter: 0000018f section .bss defined public
-_second_counter: 000002b7 section .bss defined public
-_MQTT_resp_tout_counter: 000000ed section .bss defined public
-_MQTT_not_OK_counter: 000000ec section .bss defined public
-_MQTT_broker_dis_counter: 000000eb section .bss defined public
-_mqtt_mq_register: 0000dcae section .text defined public
-_mqtt_unpack_fixed_header: 0000d6e2 section .text defined public
-_mqtt_pack_fixed_header: 0000d79f section .text defined public
-_Enc28j60SwitchBank: 0000a0b3 section .text defined public
-_SpiReadChunk: 0000e335 section .text defined public
-_SpiWriteChunk: 0000e2cc section .text defined public
-_mqtt_start_status: 00000127 section .bss defined public
-_MQTT_error_status: 000002b6 section .bss defined public
-_saved_newlines: 0000006a section .bss defined public
+_Enc28j60Send: 0000a3f3 section .text defined public
+_uip_send: 0000efba section .text defined public
+_publish_outbound: 0000c280 section .text defined public
+___mqtt_send: 0000d398 section .text defined public
+_mqtt_mq_find: 0000de16 section .text defined public
+_Enc28j60ReadPhy: 0000a17b section .text defined public
+_Enc28j60WritePhy: 0000a1c8 section .text defined public
+_stpcpy: 0000df38 section .text defined public
+_select: 0000a0f8 section .text defined public
+_deselect: 0000a0fe section .text defined public
+_uip_connect: 0000e5ab section .text defined public
+_mqtt_connect: 0000d118 section .text defined public
+_mqtt_disconnect: 0000d335 section .text defined public
+_mqtt_pack_disconnect: 0000d9bb section .text defined public
+_RXERIF_counter: 00000096 section .bss defined public
+_TXERIF_counter: 00000095 section .bss defined public
+_TRANSMIT_counter: 00000091 section .bss defined public
+_second_counter: 0000025c section .bss defined public
+_MQTT_resp_tout_counter: 00000090 section .bss defined public
+_MQTT_not_OK_counter: 0000008f section .bss defined public
+_MQTT_broker_dis_counter: 0000008e section .bss defined public
+_mqtt_mq_register: 0000dc61 section .text defined public
+_mqtt_unpack_fixed_header: 0000d695 section .text defined public
+_mqtt_pack_fixed_header: 0000d752 section .text defined public
+_Enc28j60SwitchBank: 0000a169 section .text defined public
+_SpiReadChunk: 0000e2d6 section .text defined public
+_SpiWriteChunk: 0000e26d section .text defined public
+_mqtt_start_status: 000000b8 section .bss defined public
+_MQTT_error_status: 000000b7 section .bss defined public
+_saved_newlines: 00000070 section .bss defined public
_stored_config_settings: 00004051 section .eeprom defined public
-_Pending_config_settings: 000001c9 section .bss defined public
-_check_eeprom_settings: 0000c607 section .text defined public
+_Pending_config_settings: 0000016f section .bss defined public
+_check_eeprom_settings: 0000c5c4 section .text defined public
_stored_uip_ethaddr_oct: 00004017 section .eeprom defined public
-_user_reboot_request: 000001a4 section .bss defined public
-_Pending_uip_ethaddr_oct: 000001c3 section .bss defined public
-_reboot_request: 000001a5 section .bss defined public
-_restart_request: 000001a3 section .bss defined public
-_state_request: 000001ed section .bss defined public
-_mqtt_pack_connection_request: 0000d84e section .text defined public
-_mqtt_pack_publish_request: 0000da48 section .text defined public
-_mqtt_pack_subscribe_request: 0000dbdd section .text defined public
-_mqtt_pack_ping_request: 0000da28 section .text defined public
+_user_reboot_request: 0000014a section .bss defined public
+_Pending_uip_ethaddr_oct: 00000169 section .bss defined public
+_reboot_request: 0000014b section .bss defined public
+_restart_request: 00000149 section .bss defined public
+_state_request: 00000193 section .bss defined public
+_mqtt_pack_connection_request: 0000d801 section .text defined public
+_mqtt_pack_publish_request: 0000d9fb section .text defined public
+_mqtt_pack_subscribe_request: 0000db90 section .text defined public
+_mqtt_pack_ping_request: 0000d9db section .text defined public
_CLK_PCKENR1: 000050c7 section absolute defined public absolute
_UART2_BRR1: 00005242 section absolute defined public absolute
-_clear_saved_postpartial_data: 0000b514 section .text defined public
-_uip_appdata: 00000396 section .bss defined public
-_uip_sappdata: 000002d7 section .bss defined public
+_uip_appdata: 0000033b section .bss defined public
+_uip_sappdata: 0000027c 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
@@ -218,16 +204,11 @@ _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: 0000f914 section .text defined public
-c_smodx: 0000f939 section .text defined public
-_FindDevices: 00009ed1 section .text defined public
-_check_runtime_changes: 0000c9d4 section .text defined public
+c_lzmp: 0000f7bb section .text defined public
+c_smodx: 0000f7e0 section .text defined public
+_FindDevices: 00009f87 section .text defined public
+_check_runtime_changes: 0000c991 section .text defined public
c_x: 00000004 section .ubsct defined public zpage
-_DS18B20_string: 000000c2 section .bss defined public
-_mac_string: 000001a6 section .bss defined public
-_parse_POST_string: 0000b53f section .text defined public
-_update_mac_string: 0000c99d section .text defined public
-___mqtt_ping: 0000d315 section .text defined public
_PA_ODR: 00005000 section absolute defined public absolute
_PB_ODR: 00005005 section absolute defined public absolute
_PC_ODR: 0000500a section absolute defined public absolute
@@ -321,7 +302,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: 0000f7c1 section .text defined public
+c_ltor: 0000f77b 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
@@ -333,7 +314,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: 0000f786 section .text defined public
+c_lgor: 0000f714 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
@@ -345,31 +326,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: 000001f2 section .bss defined public
+_ON_OFF_word_new2: 00000198 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
-_uip_add32: 0000e4cb section .text defined public
+c_lgsub: 0000f741 section .text defined public
+_uip_add32: 0000e46c 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
_magic2: 0000402c section .eeprom defined public
-_uip_acc32: 000002ea section .bss defined public
+_uip_acc32: 0000028f 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: 000002e5 section .bss defined public
-_uip_draddr: 000002dd section .bss defined public
-_uip_mqttserveraddr: 000002d9 section .bss defined public
-_Pending_hostaddr: 000001e8 section .bss defined public
-_Pending_draddr: 000001e4 section .bss defined public
-_Pending_mqttserveraddr: 0000018a section .bss defined public
+_uip_hostaddr: 0000028a section .bss defined public
+_uip_draddr: 00000282 section .bss defined public
+_uip_mqttserveraddr: 0000027e section .bss defined public
+_Pending_hostaddr: 0000018e section .bss defined public
+_Pending_draddr: 0000018a section .bss defined public
+_Pending_mqttserveraddr: 000000b3 section .bss defined public
_stored_hostaddr: 00004027 section .eeprom defined public
-_IpAddr: 00000199 section .bss defined public
+_IpAddr: 0000013f 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
@@ -384,8 +366,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: 0000f51b section .text defined public
-_mqtt_startup: 0000bc23 section .text defined public
+_mqtt_startup: 0000bbef section .text defined public
+c_bmulx: 0000f4e4 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
@@ -397,17 +379,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_uitolx: 0000f988 section .text defined public
-_restart_reboot_step: 000001a2 section .bss defined public
-_mqtt_restart_step: 00000121 section .bss defined public
-c_lcmp: 0000f731 section .text defined public
-c_itolx: 0000f6e7 section .text defined public
+c_itolx: 0000f558 section .text defined public
+c_uitolx: 0000f84a section .text defined public
+_memcmp: 0000f430 section .text defined public
+_strcmp: 0000f4c5 section .text defined public
+_restart_reboot_step: 00000148 section .bss defined public
+_mqtt_restart_step: 000000ee section .bss defined public
+c_lcmp: 0000f5a2 section .text defined public
_I2C_TRISER: 0000521d section absolute defined public absolute
_UART2_CR4: 00005247 section absolute defined public absolute
-c_divsl: 0000f7e7 section .text defined public
+c_divsl: 0000f5e1 section .text defined public
_UART2_CR5: 00005248 section absolute defined public absolute
-_auto_pub_toggle: 000000e9 section .bss defined public
-_second_toggle: 000002bb section .bss defined public
+_auto_pub_toggle: 000000b9 section .bss defined public
+_second_toggle: 00000260 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
@@ -419,17 +403,17 @@ _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: 000000b6 section .bss defined public
+_OctetArray: 00000074 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
_TIM2_CCER2: 00005309 section absolute defined public absolute
_TIM3_CCMR2: 00005326 section absolute defined public absolute
-_pBuffer2: 00000226 section .bss defined public
+_pBuffer2: 000001cc section .bss defined public
_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: 0000016d section .bss defined public
+_Port_Mqttd: 00000097 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
@@ -444,7 +428,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: 0000f267 section .text defined public
+_uip_arp_out: 0000f207 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
@@ -458,112 +442,116 @@ _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_imul: 0000f6c6 section .text defined public
-c_fmul: 0000f58f section .text defined public
-c_okmul: 0000f59d section .text defined public
+c_smul: 0000f80b 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: 0000a536 section .text defined public
-_pin_control: 000001f8 section .bss defined public
-_Pending_pin_control: 000001b3 section .bss defined public
+_LEDcontrol: 0000a5ec section .text defined public
+_pin_control: 0000019e section .bss defined public
+_Pending_pin_control: 00000159 section .bss defined public
_TIM1_CCR4H: 0000526b section absolute defined public absolute
-c_sdivx: 0000f93f section .text defined public
+c_sdivx: 0000f7e6 section .text defined public
_TIM1_CCR4L: 0000526c section absolute defined public absolute
-_client_id: 00000143 section .bss defined public
+_client_id: 0000010f 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: 00000195 section .bss defined public
-_mqtt_start_ctr1: 00000126 section .bss defined public
+_t100ms_ctr1: 0000013b section .bss defined public
+_mqtt_start_ctr1: 000000f3 section .bss defined public
_ITC_SPR2: 00007f71 section absolute defined public absolute
-_mqtt_start_ctr2: 00000125 section .bss defined public
+_mqtt_start_ctr2: 000000f2 section .bss defined public
_ITC_SPR4: 00007f73 section absolute defined public absolute
+c_ladd: 0000f58a section .text defined public
_stored_port: 0000401d section .eeprom defined public
_stored_mqttport: 0000402f section .eeprom defined public
-_parse_POST_port: 0000b7e0 section .text defined public
-_Pending_port: 000001de section .bss defined public
-_Pending_mqttport: 00000188 section .bss defined public
-_mqttport: 0000016f section .bss defined public
-c_ladd: 0000f719 section .text defined public
-c_lgadd: 0000f761 section .text defined public
+_Pending_port: 00000184 section .bss defined public
+_Pending_mqttport: 000000b1 section .bss defined public
+_mqttport: 00000099 section .bss defined public
+c_lgadd: 0000f6dc section .text defined public
_ITC_SPR5: 00007f74 section absolute defined public absolute
_ITC_SPR6: 00007f75 section absolute defined public absolute
_ITC_SPR7: 00007f76 section absolute defined public absolute
-c_eewrw: 0000f529 section .text defined public
+c_eewrw: 0000f4f2 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: 0000a28e section .text defined public
-_mqtt_keep_alive: 0000016b section .bss defined public
-_emb_itoa: 0000a5c6 section .text defined public
-_wait_timer: 0000e4a8 section .text defined public
-_uip_arp_timer: 0000f061 section .text defined public
-_periodic_timer: 000002c2 section .bss defined public
-_mqtt_timer: 000002c1 section .bss defined public
-_t100ms_timer: 000002bd section .bss defined public
-_arp_timer: 000002bf section .bss defined public
-_mqtt_outbound_timer: 000002be section .bss defined public
+_Enc28j60Receive: 0000a344 section .text defined public
+_mqtt_keep_alive: 00000137 section .bss defined public
+_emb_itoa: 0000a695 section .text defined public
+_wait_timer: 0000e449 section .text defined public
+_uip_arp_timer: 0000f001 section .text defined public
+_periodic_timer: 00000267 section .bss defined public
+_mqtt_timer: 00000266 section .bss defined public
+_t100ms_timer: 00000262 section .bss defined public
+_arp_timer: 00000264 section .bss defined public
+_mqtt_outbound_timer: 00000263 section .bss defined public
+c_ldiv: 0000f5c2 section .text defined public
+___mqtt_pack_uint16: 0000debc section .text defined public
+___mqtt_unpack_uint16: 0000dee0 section .text defined public
_numROMs: 00000012 section .bss defined public
-_clear_eeprom_debug_bytes: 0000d01b section .text defined public
-_First: 00009f17 section .text defined public
+_clear_eeprom_debug_bytes: 0000cfd8 section .text defined public
+_First: 00009fcd section .text defined public
_magic4: 0000402e section .eeprom defined public
-_mqtt_enabled: 0000018e section .bss defined public
-_reset_pulse: 00009e14 section .text defined public
+_mqtt_enabled: 0000013a section .bss defined public
+_reset_pulse: 00009eca section .text defined public
c_lreg: 00000000 section .ubsct defined public zpage
-_Enc28j60ReadReg: 0000a04e section .text defined public
-_Enc28j60WriteReg: 0000a06e section .text defined public
-_Enc28j60SetMaskReg: 0000a085 section .text defined public
-_Enc28j60ClearMaskReg: 0000a09c section .text defined public
+_Enc28j60ReadReg: 0000a104 section .text defined public
+_Enc28j60WriteReg: 0000a124 section .text defined public
+_Enc28j60SetMaskReg: 0000a13b section .text defined public
+_Enc28j60ClearMaskReg: 0000a152 section .text defined public
_io_reg: 00005000 section absolute defined public absolute
-c_lneg: 0000f8e5 section .text defined public
-c_lgneg: 0000f8d2 section .text defined public
+c_lneg: 0000f766 section .text defined public
+c_lgneg: 0000f701 section .text defined public
_doneFlag: 0000000b section .data defined public
_insertion_flag: 00000044 section .bss defined public
-_get_temperature: 00009cba section .text defined public
-_send_mqtt_temperature: 000000c1 section .bss defined public
-_publish_temperature: 0000c510 section .text defined public
-_transmit_byte: 00009e45 section .text defined public
+_DS18B20_scratch: 00000080 section .bss defined public
+c_lgursh: 0000f758 section .text defined public
+_get_temperature: 00009cb8 section .text defined public
+_convert_temperature: 00009d71 section .text defined public
+_send_mqtt_temperature: 0000007f section .bss defined public
+_publish_temperature: 0000c4dc section .text defined public
+_transmit_byte: 00009efb section .text defined public
_FoundROM: 00000014 section .bss defined public
_ROM: 0000003c section .bss defined public
-_SpiWriteByte: 0000e2a2 section .text defined public
-_SpiReadByte: 0000e30b section .text defined public
-_saved_nstate: 000000b5 section .bss defined public
-_saved_parsestate: 000000b4 section .bss defined public
-_parse_table: 000096a1 section .const defined public
-_parse_complete: 000001a0 section .bss defined public
-_mqtt_parse_complete: 0000019f section .bss defined public
-_upgrade_EEPROM: 0000c5c6 section .text defined public
-_timer_update: 0000e41d section .text defined public
-_publish_pinstate: 0000c3a1 section .text defined public
-_read_bit: 00009e65 section .text defined public
-_write_bit: 00009ea2 section .text defined public
-_Enc28j60Init: 0000a146 section .text defined public
-_gpio_init: 0000a4b3 section .text defined public
-_HttpDInit: 0000ab46 section .text defined public
-_clock_init: 0000e375 section .text defined public
-_spi_init: 0000e27d section .text defined public
-_uip_arp_init: 0000f03e section .text defined public
-_uip_init: 0000e5db section .text defined public
-_mqtt_init: 0000d103 section .text defined public
-_strcat: 0000f4fb section .text defined public
-_mqtt_mq_init: 0000dc5f section .text defined public
-_dallas_crc8: 00009fff section .text defined public
-_main: 0000ba1e section .text defined public
+_SpiWriteByte: 0000e243 section .text defined public
+_SpiReadByte: 0000e2ac section .text defined public
+_saved_nstate: 00000073 section .bss defined public
+_parse_complete: 00000146 section .bss defined public
+_mqtt_parse_complete: 00000145 section .bss defined public
+_upgrade_EEPROM: 0000c583 section .text defined public
+_timer_update: 0000e3be section .text defined public
+_publish_pinstate: 0000c36d section .text defined public
+_read_bit: 00009f1b section .text defined public
+_write_bit: 00009f58 section .text defined public
+_Enc28j60Init: 0000a1fc section .text defined public
+_gpio_init: 0000a569 section .text defined public
+_HttpDInit: 0000ac66 section .text defined public
+_clock_init: 0000e316 section .text defined public
+_spi_init: 0000e21e section .text defined public
+_uip_arp_init: 0000efde section .text defined public
+_uip_init: 0000e57c section .text defined public
+_mqtt_init: 0000d0c0 section .text defined public
+_strcat: 0000f4b1 section .text defined public
+_mqtt_mq_init: 0000dc12 section .text defined public
+c_rtol: 0000f7ce section .text defined public
+_Port_Httpd: 00000143 section .bss defined public
+_saved_nparseleft: 00000071 section .bss defined public
+_dallas_crc8: 0000a0b5 section .text defined public
+_main: 0000b9f6 section .text defined public
__stack: 000007ff section absolute defined public absolute
_ITC_SPR3: 00007f72 section absolute defined public absolute
-c_lgadc: 0000f751 section .text defined public
-_mqtt_sanity_check: 0000c135 section .text defined public
-c_ladc: 0000f708 section .text defined public
-_publish_callback: 0000c1d4 section .text defined public
-_exit: 00009cb8 section .text defined public
+c_lgadc: 0000f6cc section .text defined public
+_mqtt_sanity_check: 0000c101 section .text defined public
+c_ladc: 0000f579 section .text defined public
+_publish_callback: 0000c1a0 section .text defined public
+_exit: 00009cb6 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: 000001ec section .bss defined public
-__stext: 00009cb1 section .text defined public
-_Next: 00009f22 section .text defined public
-_client_id_text: 00000129 section .bss defined public
+_stack_error: 00000192 section .bss defined public
+__stext: 00009caf section .text defined public
+_Next: 00009fd8 section .text defined public
+_client_id_text: 000000f5 section .bss defined public
diff --git a/NetworkModule/.Idea_Temp/IDEA.ERR b/NetworkModule/.Idea_Temp/IDEA.ERR
index 2660c11..160c05d 100644
--- a/NetworkModule/.Idea_Temp/IDEA.ERR
+++ b/NetworkModule/.Idea_Temp/IDEA.ERR
@@ -47,37 +47,37 @@ uart.o:
uip.o:
uip_arp.o:
uip_tcpapphub.o:
-(C:\Program Files (x86)\COSMIC\FSE_Compilers\CXSTM8\lib\libisl0.sm8)isxdig0.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)bmulx.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)fmul.o:
-(C:\Program Files (x86)\COSMIC\FSE_Compilers\CXSTM8\lib\libm0.sm8)ftol.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)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:
(C:\Program Files (x86)\COSMIC\FSE_Compilers\CXSTM8\lib\libm0.sm8)ludiv.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)lgneg.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)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)uitof.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)utolx.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 e700607..b210284 100644
--- a/NetworkModule/.Idea_Temp/IDEABLD.BAT
+++ b/NetworkModule/.Idea_Temp/IDEABLD.BAT
@@ -1,5 +1,5 @@
REM COMMAND FILE BUILT BY IDEA
-REM Sun Feb 21 11:31:06 2021
+REM Mon Apr 12 07:55:24 2021
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" "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 407e24d..231c814 100644
--- a/NetworkModule/DS18B20.c
+++ b/NetworkModule/DS18B20.c
@@ -32,14 +32,17 @@
#include "DS18B20.h"
#include "main.h"
#include "timer.h"
+#include "uart.h"
#include "uipopt.h"
extern uint8_t DS18B20_scratch_byte[2]; // Array to store scratchpad bytes
// read from DS18B20
extern uint8_t OctetArray[11]; // Used in conversion of integer
- // values to character values
+ // values to character values and
+ // used to store generic strings
+// Table used for rounding the decimal part of temperatures
static const uint8_t dec_temp[] = {
'0', // 0x0000 0.0000 rounded off = 0.0
'1', // 0x0001 0.0625 rounded off = 0.1
@@ -58,7 +61,6 @@ static const uint8_t dec_temp[] = {
'9', // 0x1110 0.8750 rounded off = 0.9
'9'}; // 0x1111 0.9375 rounded off = 0.9
-
// GLOBAL VARIABLES FOR MAXIM DS18B20 CODE CONTRIBUTION
// Derived from Maxim code
// https://www.maximintegrated.com/en/design/technical-documents/app-notes/1/162.html
@@ -91,14 +93,14 @@ int numROMs; // Count of DS18B20 devices found
// voltage on the pull up resistor.
//---------------------------------------------------------------------------//
-// void get_temperature(uint8_t IO)
+
void get_temperature()
{
// This function will be called by main every 30 seconds. The function
// reads the current temperature from all devices, then signals the
// DS18B20s to start a new conversion so that a new temperature reading
// will be ready the next time this function is called. Then the function
- // returns leaving the temperature values in the DS18B20_string array.
+ // returns leaving the temperature values in the DS18B20_scratch array.
//
// Note that the first time the temperature is read from the DS18B20s the
// value will be indeterminate, but on the next read the value will be
@@ -130,15 +132,11 @@ void get_temperature()
// "nop_cnt<20" yields a 10us delay
// The delay is actually about 95% of the calculated value, but this is
// close enough for this application.
-
int i;
uint8_t j;
uint8_t device_num;
- uint8_t DS18B20_scratch_byte[9];
- uint16_t whole_temp;
- uint8_t decimal_temp;
- extern uint8_t DS18B20_string[5][7];
+ extern uint8_t DS18B20_scratch[5][2];
// Read current temperature from up to 5 devices
for (device_num = 0; device_num < 5; device_num++) {
@@ -184,7 +182,7 @@ void get_temperature()
// Send 8 bit read scratchpad command - about 75us per bit
// Read 72 bit scratchpad - about 75us per bit
// 80 x 75us = 6000us = 6ms
- // Approximate time spend in this routine when only the first 2 bytes
+ // Approximate time spent in this routine when only the first 2 bytes
// are read:
// Send 8 bit read scratchpad command - about 75us per bit
// Read 16 bit scratchpad - about 75us per bit
@@ -193,8 +191,8 @@ void get_temperature()
for (i=0; i<2; i++) {
j = 0x01;
while(1) {
- if (read_bit() == 1) DS18B20_scratch_byte[i] |= j;
- else DS18B20_scratch_byte[i] &= (uint8_t)~j;
+ if (read_bit() == 1) DS18B20_scratch[device_num][i] |= j;
+ else DS18B20_scratch[device_num][i] &= (uint8_t)~j;
if (j == 0x80) break;
j = (uint8_t)(j << 1);
}
@@ -207,78 +205,237 @@ void get_temperature()
// search_ROM process, starting with bit 0 of byte 0.
for (i = 0; i < 8; i++) transmit_byte(FoundROM[device_num][i]);
transmit_byte(0x44); // convert_temp command
-
- // Convert temperature reading to string.
- // DS18B20_temp_xx is a 16 bit signed value. Bits are organized as
- // follows:
- // Bits 15,14,13,12,11 are all the sign bit
- // Bits 10,9,8,7,6,5,4 are the digits of the temperature whole number
- // If positive value these bits can be converted to the decimal
- // whole number
- // If negative value these bits should be inverted, then converted
- // to the decimal whole number and an "-" should be added
- // Bits 3,2,1,0 are the decimal part of the temperature
- // If positive value and a single decimal is wanted the following
- // round off table applies:
- // 0x0000 0.0000 rounded off = 0.0
- // 0x0001 0.0625 rounded off = 0.1
- // 0x0010 0.1250 rounded off = 0.1
- // 0x0011 0.1875 rounded off = 0.2
- // 0x0100 0.2500 rounded off = 0.3
- // 0x0101 0.3125 rounded off = 0.3
- // 0x0110 0.3750 rounded off = 0.4
- // 0x0111 0.4375 rounded off = 0.4
- // 0x1000 0.5000 rounded off = 0.5
- // 0x1001 0.5625 rounded off = 0.6
- // 0x1010 0.6250 rounded off = 0.6
- // 0x1011 0.6875 rounded off = 0.7
- // 0x1100 0.7500 rounded off = 0.8
- // 0x1101 0.8125 rounded off = 0.8
- // 0x1110 0.8750 rounded off = 0.9
- // 0x1111 0.9375 rounded off = 0.9
- // If negative the four bits need to be inverted, then 1 added. The
- // above table will then apply.
- // The decimal part of the conversion is generated with a lookup
- // table static const uint8_t dec_temp[]
-
- whole_temp = DS18B20_scratch_byte[1];
+ }
+ }
+}
+
+
+void convert_temperature(uint8_t device_num, uint8_t degCorF)
+{
+//---------------------------------------------------------------------------//
+ // This function will convert a temperature value stored in the
+ // DS18B20_scratch array into a string in degrees C or degrees F. The
+ // function leaves the converted result in the global OctetArray string.
+ //
+ int16_t whole_temp;
+ uint8_t decimal_temp;
+ extern uint8_t DS18B20_scratch[5][2];
+ uint8_t temp_string[7];
+
+ // Convert temperature reading to string.
+ // DS18B20_temp_xx is a 16 bit signed value. Bits are organized as
+ // follows:
+ // Bits 15,14,13,12,11 are all the sign bit
+ // Bits 10,9,8,7,6,5,4 are the digits of the temperature whole number
+ // If positive value these bits can be converted to the decimal
+ // whole number
+ // If negative value these bits should be inverted, then converted
+ // to the decimal whole number and an "-" should be added
+ // Bits 3,2,1,0 are the decimal part of the temperature
+ // If positive value and a single decimal is wanted the round-off
+ // table declared in this file applies (static const uint8_t dec_temp[]).
+ // If negative the four "decimal" bits need to be inverted, then 1
+ // added (twos complement). The round-off table then applies.
+
+ // Test tables
+ // These can be enabled one set at a time to test any code changes made
+ // to the C and F conversion code. If enabled these test values will
+ // over-ride any values read from the temperature sensors.
+/*
+ DS18B20_scratch[0][1] = 0x07; // +125.0000C +257.0F
+ DS18B20_scratch[0][0] = 0xd0;
+ DS18B20_scratch[1][1] = 0x05; // +85.0000C +185.0F
+ DS18B20_scratch[1][0] = 0x50;
+ DS18B20_scratch[2][1] = 0x01; // +25.0625C +77.1F
+ DS18B20_scratch[2][0] = 0x91;
+ DS18B20_scratch[3][1] = 0x00; // +10.1250C +50.2F
+ DS18B20_scratch[3][0] = 0xa2;
+ DS18B20_scratch[4][1] = 0x00; // +0.5000C +32.9F
+ DS18B20_scratch[4][0] = 0x08;
+
+ DS18B20_scratch[0][1] = 0x00; // +0.0000C +32.0F
+ DS18B20_scratch[0][0] = 0x00;
+ DS18B20_scratch[1][1] = 0xff; // -0.5000C +31.1F
+ DS18B20_scratch[1][0] = 0xf8;
+ DS18B20_scratch[2][1] = 0xff; // -10.1250C +13.8F
+ DS18B20_scratch[2][0] = 0x5e;
+ DS18B20_scratch[3][1] = 0xfe; // -25.0625C -13.1F
+ DS18B20_scratch[3][0] = 0x6f;
+ DS18B20_scratch[4][1] = 0xfc; // -55.0000C -67.0F
+ DS18B20_scratch[4][0] = 0x90;
+
+ DS18B20_scratch[0][1] = 0x00; // +1.0000C +33.8F
+ DS18B20_scratch[0][0] = 0x10;
+ DS18B20_scratch[1][1] = 0x00; // +1.0625C +33.9F
+ DS18B20_scratch[1][0] = 0x11;
+ DS18B20_scratch[2][1] = 0x00; // +1.1250C +34.0F
+ DS18B20_scratch[2][0] = 0x12;
+ DS18B20_scratch[3][1] = 0x00; // +1.1875C +34.1F
+ DS18B20_scratch[3][0] = 0x13;
+ DS18B20_scratch[4][1] = 0x00; // +1.2500C +34.3F
+ DS18B20_scratch[4][0] = 0x14;
+
+ DS18B20_scratch[0][1] = 0x00; // +1.6875C +35.0F
+ DS18B20_scratch[0][0] = 0x1b;
+ DS18B20_scratch[1][1] = 0x00; // +1.7500C +35.2F
+ DS18B20_scratch[1][0] = 0x1c;
+ DS18B20_scratch[2][1] = 0x00; // +1.8125C +35.3F
+ DS18B20_scratch[2][0] = 0x1d;
+ DS18B20_scratch[3][1] = 0x00; // +1.8750C +35.4F
+ DS18B20_scratch[3][0] = 0x1e;
+ DS18B20_scratch[4][1] = 0x00; // +1.9375C +35.5F
+ DS18B20_scratch[4][0] = 0x1f;
+
+ DS18B20_scratch[0][1] = 0xff; // -1.0000C +30.2F
+ DS18B20_scratch[0][0] = 0xf0;
+ DS18B20_scratch[1][1] = 0xff; // -1.0625C +30.1F
+ DS18B20_scratch[1][0] = 0xef;
+ DS18B20_scratch[2][1] = 0xff; // -1.1250C +30.0F
+ DS18B20_scratch[2][0] = 0xee;
+ DS18B20_scratch[3][1] = 0xff; // -1.1875C +29.9F
+ DS18B20_scratch[3][0] = 0xed;
+ DS18B20_scratch[4][1] = 0xff; // -1.2500C +29.8F
+ DS18B20_scratch[4][0] = 0xec;
+
+ DS18B20_scratch[0][1] = 0xff; // -1.6875C +29.0F
+ DS18B20_scratch[0][0] = 0xe5;
+ DS18B20_scratch[1][1] = 0xff; // -1.7500C +28.9F
+ DS18B20_scratch[1][0] = 0xe4;
+ DS18B20_scratch[2][1] = 0xff; // -1.8125C +28.7F
+ DS18B20_scratch[2][0] = 0xe3;
+ DS18B20_scratch[3][1] = 0xff; // -1.8750C +28.6F
+ DS18B20_scratch[3][0] = 0xe2;
+ DS18B20_scratch[4][1] = 0xff; // -1.9375C +28.5F
+ DS18B20_scratch[4][0] = 0xe1;
+
+ DS18B20_scratch[0][1] = 0xfe; // -17.6875C +00.2F
+ DS18B20_scratch[0][0] = 0xe5;
+ DS18B20_scratch[1][1] = 0xfe; // -17.7500C +00.1F
+ DS18B20_scratch[1][0] = 0xe4;
+ DS18B20_scratch[2][1] = 0xfe; // -17.8125C -00.1F
+ DS18B20_scratch[2][0] = 0xe3;
+ DS18B20_scratch[3][1] = 0xfe; // -17.8750C -00.2F
+ DS18B20_scratch[3][0] = 0xe2;
+ DS18B20_scratch[4][1] = 0xfe; // -17.9375C -00.3F
+ DS18B20_scratch[4][0] = 0xe1;
+
+ DS18B20_scratch[0][1] = 0xfe; // -18.1875C -00.7F
+ DS18B20_scratch[0][0] = 0xdd;
+ DS18B20_scratch[1][1] = 0xfe; // -18.2500C -00.9F
+ DS18B20_scratch[1][0] = 0xdc;
+ DS18B20_scratch[2][1] = 0xfe; // -18.3125C -01.0F
+ DS18B20_scratch[2][0] = 0xdb;
+ DS18B20_scratch[3][1] = 0xfe; // -18.3750C -01.0F
+ DS18B20_scratch[3][0] = 0xda;
+ DS18B20_scratch[4][1] = 0xfe; // -18.4375C -01.2F
+ DS18B20_scratch[4][0] = 0xd9;
+*/
+
+
+ if (DS18B20_scratch[device_num][1] != 0x55) { // Check that sensor exists
+
+ if (degCorF == 0) {
+ // Convert to degrees C
+ // Extract whole temp and decimal temp parts of the DS18B20
+ // values
+ whole_temp = DS18B20_scratch[device_num][1];
whole_temp = whole_temp << 8;
- whole_temp |= DS18B20_scratch_byte[0];
+ whole_temp |= DS18B20_scratch[device_num][0];
whole_temp &= 0x07f0;
whole_temp = whole_temp >> 4;
-
- decimal_temp = (uint8_t)DS18B20_scratch_byte[0];
+ decimal_temp = (uint8_t)DS18B20_scratch[device_num][0];
decimal_temp &= 0x0f;
-
- if (DS18B20_scratch_byte[1] & 0xF8) {
- // Negative number conversion
+
+ if ((DS18B20_scratch[device_num][1] & 0x80) == 0x80) {
+ // Negative number conversion. Convert to positive
+ // number.
whole_temp = whole_temp ^ 0x007f;
decimal_temp = (uint8_t)(decimal_temp ^ 0x0f);
decimal_temp++;
decimal_temp = (uint8_t)(decimal_temp & 0x0f);
- DS18B20_string[device_num][0] = '-';
+ temp_string[0] = '-';
}
else {
- DS18B20_string[device_num][0] = ' ';
+ // Positive number
+ temp_string[0] = ' ';
}
-
- // Build string
- emb_itoa(whole_temp, OctetArray, 10, 3);
- DS18B20_string[device_num][1] = OctetArray[0];
- DS18B20_string[device_num][2] = OctetArray[1];
- DS18B20_string[device_num][3] = OctetArray[2];
- DS18B20_string[device_num][4] = '.';
- DS18B20_string[device_num][5] = dec_temp[decimal_temp];
- DS18B20_string[device_num][6] = '\0';
}
+
+
+ else {
+ // Convert to degrees F
+ // This routine avoids the use of float variables to perform
+ // C to F conversion in order to reduce code size. The result
+ // is that some conversions are off by 0.1 degree - but this
+ // is adequate for this application.
+ {
+ uint16_t raw_temp;
+ int16_t F_temp0;
+ int32_t F_temp1;
+ int32_t F_temp2;
+
+ // Use the raw number from the DS18B20 including the decimal
+ raw_temp = DS18B20_scratch[device_num][1];
+ raw_temp = raw_temp << 8;
+ raw_temp |= DS18B20_scratch[device_num][0];
+ // Recast raw_temp for subsequent calculations. Why two steps
+ // here? Recast of a uint16 to a int32 did not work properly,
+ // but recast of the uint16 to int16, then recast of the int16
+ // to the int32 DID work.
+ F_temp0 = (int16_t)raw_temp;
+ F_temp1 = (int32_t)F_temp0;
+ // Add 55 C to the value so math is always positive
+ // We actually add 55 * 16, or 880, since we are working
+ // with the raw number which includes 4 bits of decimal
+ // This next equation also includes the "9" part of the
+ // "9 / 5" calculation. We use 180 / 100 to avoid loss
+ // of precision in the integer arithmatic.
+ F_temp1 = (int32_t)((F_temp1 + 880) * 180);
+ // It is necessary to separate the "100" part of the
+ // "180 / 100" arithmatic so the compiler doesn't optimize
+ // and cause loss of precision.
+ F_temp2 = F_temp1 / 100;
+ // Now subtract 1072. This is the combination of the "+32"
+ // part of the C = (F * 9 / 5) + 32 equation, plus the removal
+ // of the 55 C offset. Again we are using values mulitplied
+ // by 16 since we are working with the raw number.
+ // +32 = 32 * 16 = +512
+ // The 55 C offset must be removed in terms of degrees F
+ // F = (-55 * 9 / 5) * 16 = -1584
+ // + 512 - 1584 = -1072
+ F_temp2 = F_temp2 - 1072;
+ // Now divide by 16 to get the "whole number" part of the
+ // display in degrees F
+ 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);
+ temp_string[0] = ' ';
+ if (F_temp2 < 0) {
+ // Must use twos complement if the result is negative
+ whole_temp = whole_temp * -1;
+ decimal_temp = (uint8_t)(((decimal_temp ^ 0xf) + 1) & 0x0f);
+ temp_string[0] = '-';
+ }
+ }
+ }
+
+ // Build string
+ emb_itoa(whole_temp, OctetArray, 10, 3);
+ temp_string[1] = OctetArray[0];
+ temp_string[2] = OctetArray[1];
+ temp_string[3] = OctetArray[2];
+ temp_string[4] = '.';
+ temp_string[5] = dec_temp[decimal_temp];
+ temp_string[6] = '\0';
+ strcpy(OctetArray, temp_string);
+ }
+ else {
+ // Sensor does not exist - return ------ string
+ strcpy(OctetArray, "------");
}
}
-// IO 15 is Port G bit 0 (of 0-7)
-// PG_DDR 1 is output, 0 is input
-// PG_ODR
-// PG_IDR
// IO 16 is Port C bit 6 (of 0-7)
// PC_DDR 1 is output, 0 is input
// PC_ODR
@@ -294,15 +451,15 @@ int reset_pulse()
PC_ODR |= 0x40; // write IO ODR to 1
PC_DDR |= 0x40; // write IO DDR to output
PC_ODR &= (uint8_t)~0x40; // write IO ODR to 0
- wait_timer(500);
+ wait_timer(500); // wait 500us
PC_DDR &= (uint8_t)~0x40; // write IO DDR to input
- wait_timer(100);
+ wait_timer(100); // wait 100us
// Check for "presence" state on the 1-wire. 0 = device(s) present.
rtn = 0;
if (PC_IDR & 0x40) rtn = 1;
- wait_timer(200);
+ wait_timer(200); // wait 200us
return rtn;
}
@@ -391,8 +548,6 @@ void write_bit(uint8_t transmit_bit)
}
-
-
void FindDevices(void)
{
// FIND DEVICES
diff --git a/NetworkModule/DS18B20.h b/NetworkModule/DS18B20.h
index 3f821a3..acc99a4 100644
--- a/NetworkModule/DS18B20.h
+++ b/NetworkModule/DS18B20.h
@@ -23,6 +23,7 @@
#define __DS18B20_H__
void get_temperature(void);
+void convert_temperature(uint8_t device_num, uint8_t degCorF);
int reset_pulse(void);
uint8_t check_CRC(void);
void transmit_byte(uint8_t transmit_value);
diff --git a/NetworkModule/Enc28j60.c b/NetworkModule/Enc28j60.c
index 68b1023..ff6172b 100644
--- a/NetworkModule/Enc28j60.c
+++ b/NetworkModule/Enc28j60.c
@@ -54,7 +54,7 @@
#if DEBUG_SUPPORT != 0
// Variables used to store debug information
extern uint8_t debug[NUM_DEBUG_BYTES];
-#endif // DEBUG_SUPPORT != 0
+#endif // DEBUG_SUPPORT
extern uint8_t RXERIF_counter; // Counts RXERIF errors
extern uint8_t TXERIF_counter; // Counts TXERIF errors
diff --git a/NetworkModule/Main.c b/NetworkModule/Main.c
index a57ab05..7d8ea39 100644
--- a/NetworkModule/Main.c
+++ b/NetworkModule/Main.c
@@ -49,7 +49,7 @@
//---------------------------------------------------------------------------//
//---------------------------------------------------------------------------//
//---------------------------------------------------------------------------//
-const char code_revision[] = "20210221 1826";
+const char code_revision[] = "20210412 1333";
//---------------------------------------------------------------------------//
//---------------------------------------------------------------------------//
//---------------------------------------------------------------------------//
@@ -57,11 +57,12 @@ const char code_revision[] = "20210221 1826";
//---------------------------------------------------------------------------//
// Stack overflow detection
// The following is used to declare two constants at the top of the RAM area.
-// Regular variable assignments start at memory address 0x0000 and grow upwards
-// to 0x5ff. Stack starts at 0x7ff and grows downward to 0x0600. Two constants
-// are placed at 0x5fe and 0x5ff and are monitored to make sure they never
-// change. If they do change it implies that the Stack has grown into the
-// variable storage RAM.
+// Regular variable assignments start at memory address 0x0000 and grow
+// upwards to 0x5ff. Stack starts at 0x7ff and grows downward to 0x0600. Two
+// constants are placed at 0x5fe and 0x5ff and are monitored to make sure
+// they never change. If they do change it implies that the Stack has grown
+// into the variable storage RAM, or that a "wild pointer" may have caused
+// writes to RAM to exceed the space allocated to RAM.
//
#pragma section @near [iconst]
uint8_t stack_limit1;
@@ -137,7 +138,7 @@ uint8_t stack_limit2;
// 30 debug bytes
// Byte 128 stored_debug[29]
// Byte 99 stored_debug[0]
-#endif // DEBUG_SUPPORT != 0
+#endif // DEBUG_SUPPORT
// 98 bytes used below
// >>> Add new variables HERE <<<
@@ -192,7 +193,19 @@ uint8_t stack_limit2;
uint8_t *pBuffer2;
uint8_t debug[NUM_DEBUG_BYTES];
//---------------------------------------------------------------------------//
-#endif // DEBUG_SUPPORT != 0
+#endif // DEBUG_SUPPORT
+
+#if MQTT_SUPPORT == 0
+// Define Flash addresses for IO Names and IO Timers
+char IO_NAME[16][16] @0xff00;
+uint16_t IO_TIMER[16] @0xfec0;
+uint16_t Pending_IO_TIMER[16];
+
+// Define pin_timers
+uint32_t pin_timer[16];
+
+#endif // MQTT_SUPPORT
+
uint8_t pin_control[16]; // Per pin configuration byte
@@ -251,29 +264,17 @@ extern uint32_t second_counter; // Time in seconds
extern uint8_t OctetArray[11]; // Used in emb_itoa conversions
-uint8_t RXERIF_counter; // Counts RXERIF errors detected by the
- // ENC28J60
-uint8_t TXERIF_counter; // Counts TXERIF errors detected by the
- // ENC28J60
-uint32_t TRANSMIT_counter; // Counts any transmit by the ENC28J60
-
-
+#if MQTT_SUPPORT == 1
// MQTT variables
+// Note: To maintain the same user interface for MQTT compiles and Browser Only
+// versions the MQTT user interface variables are always compiled.
uint8_t mqtt_enabled; // Used to signal use of MQTT functions
- // Initialized to 'disabled', but any
- // non-zero MQTT Server IP Adddress will
- // cause it to be 'enabled'
-uint8_t Pending_mqttserveraddr[4]; // Holds a new user entered MQTT Server
- // IP address
-uint16_t Pending_mqttport; // Holds a new user entered MQTT Port
- // number
-char Pending_mqtt_username[11]; // Holds a new user entered MQTT username
-char Pending_mqtt_password[11]; // Holds a new user entered MQTT password
-
+ // Initialized to 'disabled'. This can
+ // only get set to 1 if the MQTT Enable
+ // bit is set in the Config settings AND
+ // at least one IO pin is enabled.
uint8_t connect_flags; // Used in MQTT setup
-uint16_t mqttport; // MQTT port number
-uint16_t Port_Mqttd; // In use MQTT port number
uint16_t mqtt_keep_alive; // Ping interval
struct mqtt_client mqttclient; // Declare pointer to the MQTT client
// structure
@@ -283,8 +284,6 @@ char client_id_text[26]; // Client ID comprised of text
// (12 bytes) and terminator (1 byte)
// for a total of 26 bytes.
uint8_t mqtt_start; // Tracks the MQTT startup steps
-uint8_t mqtt_start_status; // Error (or success) status for startup
- // steps
uint8_t mqtt_start_ctr1; // Tracks time for the MQTT startup
// steps
uint8_t mqtt_start_ctr2; // Tracks time for the MQTT startup
@@ -304,7 +303,6 @@ struct uip_conn *mqtt_conn; // mqtt_conn points to the connection
// have to keep looking it up in the
// structure table while setting up MQTT
// operations.
-extern uint8_t MQTT_error_status; // For MQTT error status display in GUI
uint8_t mqtt_restart_step; // Step tracker for restarting MQTT
static const unsigned char devicetype[] = "NetworkModule/"; // Used in
@@ -316,29 +314,55 @@ unsigned char topic_base[51]; // Used for building connect, subscribe,
// NetworkModule/DeviceName123456789/output/+/set
// NetworkModule/DeviceName123456789/temp/15
// homeassistant/binary_sensor/macaddressxx/01/config
-uint8_t MQTT_resp_tout_counter; // Counts response timeout events in the
- // mqtt_sanity_check() function
-uint8_t MQTT_not_OK_counter; // Counts MQTT != OK events in the
- // mqtt_sanity_check() function
-uint8_t MQTT_broker_dis_counter; // Counts broker disconnect events in
- // the mqtt_sanity_check() function
uint8_t auto_pub_count; // Tracks the Home Assistant Auto Discovery
// publish msgs
uint8_t auto_pub_toggle; // Tracks the dual message count required for
// the Home Assistant Auto Discovery publish msgs
+#endif // MQTT_SUPPORT
+
+// These MQTT variables must always be compiled to maintain a common user
+// interface between the MQTT and Browser Only versions.
+uint8_t mqtt_start_status; // Error (or success) status for startup
+ // steps
+uint8_t MQTT_error_status; // For MQTT error status display in GUI
+uint8_t Pending_mqttserveraddr[4]; // Holds a new user entered MQTT Server
+ // IP address
+uint16_t Pending_mqttport; // Holds a new user entered MQTT Port
+ // number
+char Pending_mqtt_username[11]; // Holds a new user entered MQTT username
+char Pending_mqtt_password[11]; // Holds a new user entered MQTT password
+uint16_t mqttport; // MQTT port number
+uint16_t Port_Mqttd; // In use MQTT port number
+
+
+// The following are diagnostic counters mostly useful for checking for the
+// need for Full Duplex in an MQTT setting, they may still be useful in
+// other scenarios, so they remain functional even if MQTT is not enabled.
+uint8_t RXERIF_counter; // Counts RXERIF errors detected by the
+ // ENC28J60
+uint8_t TXERIF_counter; // Counts TXERIF errors detected by the
+ // ENC28J60
+uint32_t TRANSMIT_counter; // Counts any transmit by the ENC28J60
+uint8_t MQTT_resp_tout_counter; // Counts response timeout events in the
+ // mqtt_sanity_check() function
+uint8_t MQTT_not_OK_counter; // Counts MQTT != OK events in the
+ // mqtt_sanity_check() function
+uint8_t MQTT_broker_dis_counter; // Counts broker disconnect events in
+ // the mqtt_sanity_check() function
+
// DS18B20 variables
-uint32_t check_DS18B20_ctr; // Counter used to trigger temperature
- // measurements
-uint8_t DS18B20_string[5][7]; // Stores the temperature measurement for the
- // DS18B20s
-int8_t send_mqtt_temperature; // Indicates if a new temperature measurement
- // is pending transmit on MQTT. In this
- // application there are 5 sensors, so setting
- // to 4 will cause all 5 to transmit (4,3,2,1,0).
- // -1 indicates nothing to transmit.
-extern int numROMs; // Count of DS18B20 devices found
+uint32_t check_DS18B20_ctr; // Counter used to trigger temperature
+ // measurements
+uint8_t DS18B20_scratch[5][2]; // Stores the temperature measurement for the
+ // DS18B20s
+int8_t send_mqtt_temperature; // Indicates if a new temperature measurement
+ // is pending transmit on MQTT. In this
+ // application there are 5 sensors, so setting
+ // to 4 will cause all 5 to transmit (4,3,2,1,0).
+ // -1 indicates nothing to transmit.
+extern int numROMs; // Count of DS18B20 devices found
@@ -350,24 +374,23 @@ int main(void)
uip_ipaddr_t IpAddr;
parse_complete = 0;
- mqtt_parse_complete = 0;
reboot_request = 0;
user_reboot_request = 0;
restart_request = 0;
t100ms_ctr1 = 0;
restart_reboot_step = RESTART_REBOOT_IDLE;
- mqtt_close_tcp = 0;
stack_error = 0;
#if IWDG_ENABLE == 1
init_IWDG(); // Initialize the hardware watchdog
-#endif // IWDG_ENABLE == 1
+#endif // IWDG_ENABLE
+#if MQTT_SUPPORT == 1
// Initialize MQTT variables
+ mqtt_parse_complete = 0;
+ mqtt_close_tcp = 0;
mqtt_enabled = 0; // Initialized to 'disabled'
mqtt_start = MQTT_START_TCP_CONNECT; // Tracks the MQTT startup steps
- mqtt_start_status = MQTT_START_NOT_STARTED; // Tracks error states during
- // startup
mqtt_keep_alive = 60; // Ping interval in seconds
mqtt_start_ctr1 = 0; // Tracks time for the MQTT startup
// steps
@@ -375,11 +398,27 @@ int main(void)
// steps
mqtt_sanity_ctr = 0; // Tracks time for the MQTT sanity
// steps
- MQTT_error_status = 0; // For MQTT error status display in
- // GUI
mqtt_restart_step = MQTT_RESTART_IDLE; // Step counter for MQTT restart
state_request = STATE_REQUEST_IDLE; // Set the state request received to
// idle
+ auto_pub_count = 0; // Initialize Home Assistant Auto
+ // Discovery message counter
+ auto_pub_toggle = 0; // Initialize dual msg tracker for
+ // Home Assistant Auto Discovery
+ // message counter
+#endif // MQTT_SUPPORT
+
+ // The following are only used for tracking MQTT startup status, but they
+ // must always be compiled in order to maintaing a common user interface
+ // between the MQTT and Browser only compiles.
+ mqtt_start_status = MQTT_START_NOT_STARTED; // Tracks error states during
+ // startup
+ MQTT_error_status = 0; // For MQTT error status display in
+ // GUI
+
+ // While the following diagnostic counters are mostly useful for checking for
+ // the need for Full Duplex in an MQTT setting, they may still be useful in
+ // other scenarios, so they remain functional even if MQTT is not enabled.
TXERIF_counter = 0; // Initialize the TXERIF error counter
RXERIF_counter = 0; // Initialize the RXERIF error counter
TRANSMIT_counter = 0; // Initialize the TRANSMIT counter
@@ -389,11 +428,6 @@ int main(void)
// counter
MQTT_broker_dis_counter = 0; // Initialize the MQTT broker
// disconnect event counter
- auto_pub_count = 0; // Initialize Home Assistant Auto
- // Discovery message counter
- auto_pub_toggle = 0; // Initialize dual msg tracker for
- // Home Assistant Auto Discovery
- // message counter
clock_init(); // Initialize and enable clocks and timers
@@ -432,15 +466,9 @@ int main(void)
#if DEBUG_SUPPORT == 7 || DEBUG_SUPPORT == 15
- // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
- // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
- // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
- // If UART_DEBUG_SUPPORT is enabled the following code forces IO 11 to
+ // 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.
- // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
- // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
- // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
pin_control[10] = Pending_pin_control[10] = (uint8_t)0x03; // Set pin 11 to output/enabled
// Update the stored_pin_control[] variables
unlock_eeprom();
@@ -455,14 +483,15 @@ int main(void)
#endif // DEBUG_SUPPORT
#if DEBUG_SUPPORT == 7 || DEBUG_SUPPORT == 15
- // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
// Initialize the UART for debug output
InitializeUART();
-#endif // UART_DEBUG_SUPPORT
+#endif // DEBUG_SUPPORT
- // Initialize DS18B20 temperature storage strings
- for (i=0; i<5; i++) strcpy(DS18B20_string[i], "------");
+ // Initialize DS18B20 temperature storage values. Scratch byte 1 = 0x55
+ // cannot be produced by the DS18B20, so code will recognize this as a
+ // marker that the temperature has not been read from the DS18B20.
+ for (i=0; i<5; i++) DS18B20_scratch[i][1] = 0x55;
// Initialize DS18B20 devices (if enabled)
if (stored_config_settings & 0x08) {
// Find all devices
@@ -482,17 +511,6 @@ int main(void)
stack_limit1 = 0xaa;
stack_limit2 = 0x55;
-/*
- // Initialize mqtt client
-UARTPrintf("mqtt_init 1\r\n");
- mqtt_init(&mqttclient,
- mqtt_sendbuf,
- sizeof(mqtt_sendbuf),
- &uip_buf[UIP_IPTCPH_LEN + UIP_LLH_LEN],
- UIP_APPDATA_SIZE,
- publish_callback);
-*/
-
#if DEBUG_SUPPORT == 7 || DEBUG_SUPPORT == 15
// XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
// Check RST_SR (Reset Status Register)
@@ -526,7 +544,6 @@ UARTPrintf("mqtt_init 1\r\n");
UARTPrintf(OctetArray);
UARTPrintf("\r\n");
-// UARTPrintf("Reset Status Register Counters:\r\n");
UARTPrintf("EMCF: ");
emb_itoa(debug[25], OctetArray, 10, 3);
UARTPrintf(OctetArray);
@@ -658,6 +675,7 @@ UARTPrintf("mqtt_init 1\r\n");
}
}
+#if MQTT_SUPPORT == 1
// Perform MQTT startup if
// a) MQTT is enabled
// b) Not already at start complete
@@ -679,6 +697,7 @@ UARTPrintf("mqtt_init 1\r\n");
&& restart_reboot_step == RESTART_REBOOT_IDLE) {
mqtt_sanity_check();
}
+#endif // MQTT_SUPPORT
// Update the time keeping function
timer_update();
@@ -715,17 +734,21 @@ UARTPrintf("mqtt_init 1\r\n");
}
- // Increment 100ms counters every 100ms
+ // 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 256
// counts. Any code that uses crt1 must reset it to
// zero then compare to a value needed for a
- // timeout.
+ // timeout.
+#if MQTT_SUPPORT == 0
+ decrement_pin_timers(); // Decrement the pin_timers every 100ms
+#endif // MQTT_SUPPORT
}
+#if MQTT_SUPPORT == 1
// If MQTT is enabled and connected check for pin state changes and
// publish a message at 50ms intervals. publish_outbound only places the
// message in the queue. uip_periodic() will cause the actual
@@ -749,6 +772,7 @@ UARTPrintf("mqtt_init 1\r\n");
// used to provide timing for the MQTT Sanity
// Check function.
}
+#endif // MQTT_SUPPORT
// Call the ARP timer function every 10 seconds.
@@ -763,8 +787,10 @@ UARTPrintf("mqtt_init 1\r\n");
if ((stored_config_settings & 0x08) && (second_counter > (check_DS18B20_ctr + 30))) {
check_DS18B20_ctr = second_counter;
get_temperature();
+#if MQTT_SUPPORT == 1
send_mqtt_temperature = 4; // Indicates that all 5 temperature sensors
- // need to be transmitted.
+ // need to be transmitted via MQTT.
+#endif // MQTT_SUPPORT
}
@@ -805,7 +831,7 @@ UARTPrintf("mqtt_init 1\r\n");
// The user can press the Reset Button for 10 seconds to restore "factory
// defaults".
-
+#if MQTT_SUPPORT == 1
void mqtt_startup(void)
{
// This function walks through the steps needed to get MQTT initialized and
@@ -914,7 +940,6 @@ void mqtt_startup(void)
case MQTT_START_MQTT_INIT:
if (mqtt_start_ctr2 > 2) {
// Initialize mqtt client
-// UARTPrintf("mqtt_init 1\r\n");
mqtt_init(&mqttclient,
mqtt_sendbuf,
sizeof(mqtt_sendbuf),
@@ -998,14 +1023,12 @@ void mqtt_startup(void)
if (mqtt_start_ctr1 < 100) {
// Allow up to 10 seconds for CONNACK
if (connack_received == 1) {
-// UARTPrintf("connack received\r\n");
mqtt_start_ctr2 = 0; // Clear 100ms counter
mqtt_start_status |= MQTT_START_MQTT_CONNECT_GOOD;
mqtt_start = MQTT_START_QUEUE_SUBSCRIBE1;
}
}
else {
-// UARTPrintf("restart MQTT_START 1\r\n");
mqtt_start = MQTT_START_TCP_CONNECT;
// Clear the error indicator flags
mqtt_start_status = MQTT_START_NOT_STARTED;
@@ -1054,13 +1077,11 @@ void mqtt_startup(void)
if (mqtt_start_ctr1 < 100) {
// Allow up to 10 seconds for SUBACK
if (suback_received == 1) {
-// UARTPrintf("verified SUBSCRIBE1\r\n");
mqtt_start_ctr2 = 0; // Clear 100ms counter
mqtt_start = MQTT_START_QUEUE_SUBSCRIBE2;
}
}
else {
-// UARTPrintf("restart MQTT_START 2\r\n");
mqtt_start = MQTT_START_TCP_CONNECT;
// Clear the error indicator flags
mqtt_start_status = MQTT_START_NOT_STARTED;
@@ -1093,13 +1114,11 @@ void mqtt_startup(void)
if (mqtt_start_ctr1 < 100) {
// Allow up to 10 seconds for SUBACK
if (suback_received == 1) {
-// UARTPrintf("verified SUBSCRIBE2\r\n");
mqtt_start_ctr2 = 0; // Clear 100ms counter
if (stored_config_settings & 0x02) {
// Home Assistant Auto Discovery enabled
mqtt_start = MQTT_START_QUEUE_PUBLISH_AUTO;
auto_pub_count = 0;
-// UARTPrintf("start HA config\r\n");
}
else {
mqtt_start = MQTT_START_QUEUE_PUBLISH_ON;
@@ -1440,7 +1459,6 @@ void mqtt_startup(void)
mqtt_start_ctr2 = 0;
if (auto_pub_count == 16) {
mqtt_start = MQTT_START_QUEUE_PUBLISH_ON;
-// UARTPrintf("end HA config\r\n");
}
}
}
@@ -1593,16 +1611,6 @@ void mqtt_sanity_check(void)
break;
case MQTT_RESTART_SIGNAL_STARTUP:
-/*
- // Reinitialize the mqtt client
-UARTPrintf("mqtt_init in sanity check\r\n");
- mqtt_init(&mqttclient,
- mqtt_sendbuf,
- sizeof(mqtt_sendbuf),
- &uip_buf[UIP_IPTCPH_LEN + UIP_LLH_LEN],
- UIP_APPDATA_SIZE,
- publish_callback);
-*/
// Set mqtt_restart_step and mqtt_start to re-run the MQTT connection
// steps in the main loop
mqtt_restart_step = MQTT_RESTART_IDLE;
@@ -1694,7 +1702,7 @@ UARTPrintf("mqtt_init in sanity check\r\n");
// 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_sendbug needs to be a minimum of 131 bytes. Note that
+ // 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
@@ -2127,7 +2135,7 @@ void publish_temperature(uint8_t sensor)
topic_base[i] = '\0';
// Build the application message
- strcpy(app_message, DS18B20_string[sensor]);
+ convert_temperature(sensor, 0); // Convert to degress C in OctetArray
// Queue publish message
mqtt_publish(&mqttclient,
@@ -2137,6 +2145,7 @@ void publish_temperature(uint8_t sensor)
MQTT_PUBLISH_QOS_0 | MQTT_PUBLISH_RETAIN);
}
}
+#endif // MQTT_SUPPORT
void unlock_eeprom(void)
@@ -2164,13 +2173,31 @@ void lock_eeprom(void)
}
+void unlock_flash(void)
+{
+ // Unlock the Flash
+ // The Flash must be unlocked to allow any writes to it.
+ // Note that when Flash is written the hardware will stall code execution
+ // until the write completes. This typically takes 6ms per write.
+ FLASH_PUKR = 0x56; // MASS key 1
+ FLASH_PUKR = 0xAE; // MASS key 2
+}
+
+
+void lock_flash(void)
+{
+ // Lock the Flash so that it cannot be written. This clears the PUL bit.
+ FLASH_IAPSR &= (uint8_t)(~0x02);
+}
+
+
void upgrade_EEPROM(void)
{
// This functions upgrades prior revisions of the EEPROM to the current
// revision.
int i;
- // ----------------------------------------------------------------------//
+ //-------------------------------------------------------------------------//
// Starting with the January 2021 releases the EEPROM will contain a
// stored_EEPROM_revision value.
//
@@ -2191,6 +2218,7 @@ void upgrade_EEPROM(void)
// Address, etc) are retained even from the very early releases. Once an
// upgrade to a January 2021 (or later) release occurs the EEPROM will
// have a revision code that it uses to manage all subsequent upgrades.
+ //-------------------------------------------------------------------------//
//
unlock_eeprom();
while ( 1 ) {
@@ -2236,14 +2264,18 @@ void upgrade_EEPROM(void)
void check_eeprom_settings(void)
{
int i;
+ char temp[10];
// Check magic number in EEPROM.
- // If no magic number is found it is assumed that the EEPROM has never been
- // written, in which case the default Output States, IP Address, Gateway
- // Address, Netmask, MAC and Port number will be used.
+ //
// If the magic number IS found then it is assumed that the EEPROM contains
// valid copies of the Output States, IP Address, Gateway Address, Netmask,
// MAC and Port number.
+ //
+ // If no magic number is found it is assumed that the EEPROM has never been
+ // written, in which case the default Output States, IP Address, Gateway
+ // Address, Netmask, MAC and Port number will be used.
+ //
// The magic number sequence is MSB 0x55 0xee 0x0f 0xf0 LSB
if ((magic4 == 0x55) &&
@@ -2398,7 +2430,7 @@ void check_eeprom_settings(void)
// XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
// All pins need to default to "input" and "disable" to prevent
- // conflicting with external drivers.
+ // conflicting with external hardware drivers.
// pin_control_bytes should be set to defaults
// Each pin should be set to 00001010
// 0 ON/OFF
@@ -2423,8 +2455,78 @@ void check_eeprom_settings(void)
magic1 = 0xf0; // LSB
lock_eeprom();
+
+
+#if MQTT_SUPPORT == 0
+ // Initialize Flash memory that is used to store IO Timers
+ // Since the magic number didn't match all timers are set
+ // to zero.
+ unlock_flash();
+ // IO_TIMER bytes are written 4 bytes at a time to reduce
+ // Flash wear
+ i = 0;
+ while(i<16) {
+ FLASH_CR2 = 0x40;
+ FLASH_NCR2 = 0xBF;
+ memcpy(&IO_TIMER[i], 0, 4);
+ i += 4;
+ }
+
+ // Initialize Flash memory that is used to store IO Names
+ // Since the magic number didn't match all names are set
+ // to defaults. 4 byte writes are used to reduce Flash wear.
+ // Even though 16 bytes are allocated in Flash, only 8 bytes
+ // are written here (a 4 byte IO Name and a 4 byte set of
+ // NULL characters to provide a string terminator).
+ for (i=0; i<16; i++) {
+ strcpy(temp, "IO");
+ emb_itoa(i+1, OctetArray, 10, 2);
+ strcat(temp, OctetArray);
+ FLASH_CR2 = 0x40;
+ FLASH_NCR2 = 0xBF;
+ memcpy(&IO_NAME[i][0], &temp, 4);
+ FLASH_CR2 = 0x40;
+ FLASH_NCR2 = 0xBF;
+ memcpy(&IO_NAME[i][4], 0, 4);
+ }
+ lock_flash();
+#endif // MQTT_SUPPORT
+ }
+
+
+
+
+#if MQTT_SUPPORT == 0
+ // Check the IO Names in Flash to make sure they are not NULL and
+ // initialize the pin_timers.
+ // IO Names might be NULL if the device is programmed using
+ // "Program/Current Tab" instead of "Program/Address Range".
+ // "Program/Current Tab" will zero out the Flash area where these
+ // variables are stored but will leave a valid magic number in
+ // the EEPROM. If there is already an IO Name stored this code will
+ // not change it.
+ unlock_flash();
+ for (i=0; i<16; i++) {
+ strcpy(temp, "IO");
+ emb_itoa(i+1, OctetArray, 10, 2);
+ strcat(temp, OctetArray);
+ if (IO_NAME[i][0] == 0) {
+ FLASH_CR2 = 0x40;
+ FLASH_NCR2 = 0xBF;
+ memcpy(&IO_NAME[i][0], &temp, 4);
+ FLASH_CR2 = 0x40;
+ FLASH_NCR2 = 0xBF;
+ memcpy(&IO_NAME[i][4], 0, 4);
+ }
}
+
+
+ lock_flash();
+#endif // MQTT_SUPPORT
+
+
+
// Since this code is run one time at boot, initialize the variables that
// are dependent on EEPROM content.
@@ -2493,6 +2595,7 @@ void check_eeprom_settings(void)
// Update the MAC string
update_mac_string();
+#if MQTT_SUPPORT == 1
// If the MQTT Enable bit is set in the Config settings AND at least
// one IO pin is enabled set the mqtt_enabled byte.
if (stored_config_settings & 0x04) {
@@ -2500,6 +2603,7 @@ void check_eeprom_settings(void)
if (pin_control[i] & 0x01) mqtt_enabled = 1;
}
}
+#endif // MQTT_SUPPORT
}
@@ -2512,6 +2616,7 @@ void update_mac_string(void)
i = 5;
j = 0;
+
while (j<12) {
int2hex(stored_uip_ethaddr_oct[i]);
mac_string[j++] = OctetArray[0];
@@ -2524,18 +2629,34 @@ void update_mac_string(void)
void check_runtime_changes(void)
{
- // Step 1: Read the input registers and update the pin_control values as
- // needed.
+ //-------------------------------------------------------------------------//
+ // Step 1:
+ // Read the input registers and update the pin_control values as needed.
//
- // Step 2: 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. Note that the value parse_complete is used to
- // make sure that a complete POST entry has been received before attempting
- // to process the changes made by the user.
+ // 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
+ // 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 4:
+ // Manage Output pin Timers. Change Output pin states and Timers as
+ // appropriate.
+ //
+ // Step 5:
+ // 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.
int i;
uint8_t update_EEPROM;
+ uint32_t temp_pin_timer;
unlock_eeprom();
@@ -2543,15 +2664,9 @@ void check_runtime_changes(void)
#if DEBUG_SUPPORT == 7 || DEBUG_SUPPORT == 15
- // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
- // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
- // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
- // 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.
- // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
- // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
- // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+ // 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];
@@ -2573,6 +2688,147 @@ void check_runtime_changes(void)
if (stored_pin_control[15] != pin_control[15]) stored_pin_control[15] = pin_control[15];
}
+#if MQTT_SUPPORT == 0
+ // Manage Output pin Timers. Change Output pin states and Timers as
+ // appropriate.
+ //
+ // Note that Timers are ignored for any pin that is not defined as an
+ // Output pin.
+ //
+ // Check if the user changed the IO_TIMER value while the Timer was
+ // running:
+ // If an Output pin IO_TIMER value is changed by the user
+ // and the pin_timer for that pin is non-zero (the timer is running)
+ // then set the pin_timer for that pin to the IO_TIMER value
+ // THEN
+ // Collect the Pending IO_TIMER values and write them to Flash
+ //
+ // Check for Output pin Timer activate:
+ // If an Output pin and Retain is NOT set
+ // and pin has a non-zero IO_TIMER
+ // and the Output pin changed from its idle state to its active state
+ // then set the pin_timer for that pin to the IO_TIMER
+ //
+ // Check for Timer expiration:
+ // If an Output pin and Retain is NOT set
+ // and pin has a non-zero IO_TIMER
+ // and the Output pin is in its active state
+ // and the pin_timer for that pin is zero
+ // then set the Output pin to its idle state
+ //
+ // Some comments:
+ // 1) If the user changes the Output pin from active to idle while a
+ // pin_timer is running nothing needs to be done. One of two things
+ // happens:
+ // a) The pin_timer will eventually expire and no pin state change will
+ // occur.
+ // b) The user changes the Output pin from idle to active which reloads
+ // the pin_timer
+ //-------------------------------------------------------------------------//
+
+
+ // Check if the user changed the IO_TIMER value while the pin_timer
+ // was running. Typically the user is just changing the IO_TIMER value
+ // to zero, but they may also be correcting a user entry mistake - for
+ // example the user may have entered 100 minutes when they meant 10
+ // minutes, so they fix it in Configuration. The code here is intended
+ // to allow the user to change the value to any new value, and the
+ // timer should then continue with that new value.
+
+ // If an Output pin IO_TIMER value is changed by the user
+ // and the pin_timer for that pin is non-zero (the timer is running)
+ // then set the pin_timer for that pin to the IO_TIMER value
+ // THEN
+ // Collect the Pending IO_TIMER values and write them to Flash
+ if (parse_complete == 1) {
+
+ for (i=0; i<16; i++) {
+ if (((pin_control[i] & 0x03) == 0x03) && ((pin_control[i] & 0x04) == 0)) {
+ if (IO_TIMER[i] != Pending_IO_TIMER[i]) {
+ pin_timer[i] = calculate_timer(Pending_IO_TIMER[i]);
+ if (pin_timer[i] == 0x0000) {
+ if (pin_control[i] & 0x10) {
+ Pending_pin_control[i] |= 0x80;
+ pin_control[i] |= 0x80;
+ }
+ else {
+ Pending_pin_control[i] &= 0x7f;
+ pin_control[i] &= 0x7f;
+ }
+ // Update the 16 bit registers with the changed pin states
+ encode_16bit_registers();
+ // Update the Output pins
+ write_output_pins();
+ }
+ }
+ }
+ }
+
+ // Update the IO_TIMER array in Flash from the Pending_IO_TIMER
+ // array.
+ unlock_flash();
+
+ for (i=0; i<8; i+=2) {
+ // Check for compare 4 bytes at a time. If any miscompare write to
+ // Flash 4 bytes at a time.
+ if (IO_TIMER[i] != Pending_IO_TIMER[i] || IO_TIMER[i+1] != Pending_IO_TIMER[i+1]) {
+ FLASH_CR2 = 0x40;
+ FLASH_NCR2 = 0xBF;
+ memcpy(&IO_TIMER[i], &Pending_IO_TIMER[i], 4);
+ }
+ }
+ lock_flash();
+ }
+
+ // Check for Output pin Timer activate:
+ // If an Output pin and Retain is NOT set
+ // and pin has a non-zero IO_TIMER
+ // and the Output pin changed from its idle state to its active state
+ // then set the pin_timer for that pin to the IO_TIMER value
+ //
+ for (i=0; i<16; i++) {
+ if (((pin_control[i] & 0x03) == 0x03) && ((pin_control[i] & 0x04) == 0x00)) {
+ if ((IO_TIMER[i] & 0x3fff) != 0) {
+ if ((Pending_pin_control[i] & 0x80) != (pin_control[i] & 0x80)) {
+ if (((Pending_pin_control[i] & 0x80) == 0x80) && ((pin_control[i] & 0x10) == 0x00)) {
+ pin_timer[i] = calculate_timer(IO_TIMER[i]);
+ }
+ if (((Pending_pin_control[i] & 0x80) == 0x00) && ((pin_control[i] & 0x10) == 0x10)) {
+ pin_timer[i] = calculate_timer(IO_TIMER[i]);
+ }
+ }
+ }
+ }
+ }
+
+ // Check for Timer expiration:
+ // If an Output pin and Retain is NOT set
+ /// and pin has a non-zero IO_TIMER
+ // and the pin_timer for that pin is zero
+ // and the Output pin is in its active state
+ // then set the Output pin to its idle state
+ for (i=0; i<16; i++) {
+ if (((pin_control[i] & 0x03) == 0x03) && ((pin_control[i] & 0x04) == 0x00)) {
+ if (((IO_TIMER[i] & 0x3fff) != 0) && (pin_timer[i] == 0)) {
+ if (((pin_control[i] & 0x80) == 0x80) && ((pin_control[i] & 0x10) == 0x00)) {
+ Pending_pin_control[i] &= 0x7f;
+ pin_control[i] &= 0x7f;
+ }
+ if (((pin_control[i] & 0x80) == 0x00) && ((pin_control[i] & 0x10) == 0x10)) {
+ Pending_pin_control[i] |= 0x80;
+ pin_control[i] |= 0x80;
+ }
+ // Update the 16 bit registers with the changed pin states
+ encode_16bit_registers();
+ // Update the Output pins
+ write_output_pins();
+ }
+ }
+ }
+#endif MQTT_SUPPORT
+
+
+
if (parse_complete == 1 || mqtt_parse_complete == 1) {
// Check for changes from the user via the GUI, MQTT, or REST commands.
// If parse_complete == 1 all TCP Fragments have been received during
@@ -2581,7 +2837,7 @@ void check_runtime_changes(void)
// received.
// Check all pin_control bytes for changes.
- // ON/OFF state: If an Output pinÂ’s ON/OFF state changes the EEPROM is
+ // ON/OFF state: If an Output pin’s ON/OFF state changes the EEPROM is
// updated only if Retain is set, but a restart must not occur.
// IMPORTANT: This routine must only change Output pin ON/OFF states.
// The read_input_pins() function is the only place where Input pin
@@ -2647,7 +2903,7 @@ void check_runtime_changes(void)
// needed if MQTT is enabled, but it will be done even if MQTT is
// not enabled to simplify code.
update_EEPROM = 1;
- user_reboot_request = 1;
+ user_reboot_request = 1;
}
// Check for change in Invert
@@ -2658,7 +2914,7 @@ void check_runtime_changes(void)
// needed if MQTT is enabled, but it will be done even if MQTT is
// not enabled to simplify code.
update_EEPROM = 1;
- restart_request = 1;
+ restart_request = 1;
}
// Check for change in Retain/On/Off bits
@@ -2722,6 +2978,19 @@ void check_runtime_changes(void)
// Check for changes in the IP Address, Gateway Address,
// Netmask, and MQTT Server IP Address. Combined into one
// loop for code size reduction.
+// XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+// XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+// XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+// This performa a lot more EEPROM writes than needed. Since 4 bytes are
+// always written it would be better to reorganize the EEPROM so that all
+// of these values are stored on 4 byte boundaries and, if a write is
+// needed, to write a 4 byte word only once instead of writing a byte at
+// a time. Changing the method may also be overkill, as these bytes change
+// very infrequently, and the EEPROM can be written hundreds of thousands
+// of times.
+// XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+// XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+// XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
for (i=0; i<4; i++) {
if (stored_hostaddr[i] != Pending_hostaddr[i]) {
// Write the new octet to the EEPROM and singla a restart
@@ -2759,11 +3028,13 @@ void check_runtime_changes(void)
stored_devicename[i] = Pending_devicename[i];
// No restart is required in non-MQTT applications as this does not
// affect Ethernet operation.
+#if MQTT_SUPPORT == 1
if (mqtt_enabled == 1) {
// If MQTT is enabled a restart is required as this affects the
// MQTT topic name.
restart_request = 1;
}
+#endif // MQTT_SUPPORT
}
}
@@ -2896,6 +3167,16 @@ void check_restart_reboot(void)
restart_reboot_step = RESTART_REBOOT_ARM2;
break;
+#if MQTT_SUPPORT == 0
+ case RESTART_REBOOT_ARM2:
+ // Wait 1 second for anything in the process of being transmitted
+ // to fully buffer. Refresh of a page after POST can take a few
+ // seconds.
+ if (t100ms_ctr1 > 9) restart_reboot_step = RESTART_REBOOT_FINISH;
+ break;
+#endif // MQTT_SUPPORT
+
+#if MQTT_SUPPORT == 1
case RESTART_REBOOT_ARM2:
// Wait 1 second for anything in the process of being transmitted
// to fully buffer. Refresh of a page after POST can take a few
@@ -2910,7 +3191,7 @@ void check_restart_reboot(void)
case RESTART_REBOOT_SENDOFFLINE:
if (t100ms_ctr1 > 1) {
- // We can only get here is mqtt_enabled == 1
+ // We can only get here if mqtt_enabled == 1
// Wait at least 100 ms before publishing availability message
if (mqtt_start == MQTT_START_COMPLETE) {
// Publish the availability "offline" message
@@ -2997,6 +3278,7 @@ void check_restart_reboot(void)
restart_reboot_step = RESTART_REBOOT_FINISH;
}
break;
+#endif // MQTT_SUPPORT
case RESTART_REBOOT_FINISH:
if (reboot_request == 1) {
@@ -3030,7 +3312,7 @@ void restart(void)
// oneflash();
// #else
// oneflash(); // Quick flash for normal operation
-// #endif DEBUG_SUPPORT != 0
+// #endif DEBUG_SUPPORT
LEDcontrol(0); // Turn LED off
@@ -3039,12 +3321,15 @@ void restart(void)
restart_request = 0;
mqtt_close_tcp = 0;
+#if MQTT_SUPPORT == 1
mqtt_start = MQTT_START_TCP_CONNECT;
mqtt_start_status = MQTT_START_NOT_STARTED;
mqtt_start_ctr1 = 0;
mqtt_sanity_ctr = 0;
MQTT_error_status = 0;
mqtt_restart_step = MQTT_RESTART_IDLE;
+#endif // MQTT_SUPPORT
+
state_request = STATE_REQUEST_IDLE;
spi_init(); // Initialize the SPI bit bang interface to the
@@ -3055,16 +3340,6 @@ void restart(void)
uip_init(); // Initialize uIP
HttpDInit(); // Initialize httpd; sets up listening ports
-/*
- // Initialize mqtt client
-UARTPrintf("mqtt_init 2\r\n");
- mqtt_init(&mqttclient,
- mqtt_sendbuf,
- sizeof(mqtt_sendbuf),
- &uip_buf[UIP_IPTCPH_LEN + UIP_LLH_LEN],
- UIP_APPDATA_SIZE,
- publish_callback);
-*/
LEDcontrol(1); // Turn LED on
// From here we return to the main loop and should start running with new
// settings.
@@ -3211,6 +3486,37 @@ void write_output_pins(void)
}
+#if MQTT_SUPPORT == 0
+uint32_t calculate_timer(uint16_t timer_value)
+{
+ // Calculate the pin_timer value from the IO_TIMER value
+ // as follows:
+ // If units = 0.1s pin_timer = IO_TIMER Value + 1
+ // If units = 1s pin_timer = IO_TIMER Value * 10 + 1
+ // If units = 1m pin_timer = IO_TIMER Value * 10 * 60
+ // If units = 1h pin_timer = IO_TIMER Value * 10 * 60 * 60
+ // (note for manual: Any setting selected may be up to 100ms
+ // longer that the selected value)
+ if ((timer_value & 0xc000) == 0x0000) return (uint32_t)((timer_value & 0x3fff));
+ if ((timer_value & 0xc000) == 0x4000) return (uint32_t)(((timer_value & 0x3fff) * 10));
+ if ((timer_value & 0xc000) == 0x8000) return (uint32_t)(((timer_value & 0x3fff) * 600));
+ if ((timer_value & 0xc000) == 0xc000) return (uint32_t)(((timer_value & 0x3fff) * 36000));
+ return 0;
+}
+
+
+void decrement_pin_timers(void)
+{
+ int i;
+ // This function decrements the pin_timers as needed
+ // This function is called once per 100ms
+ for(i=0; i<16; i++) if (pin_timer[i] > 0) pin_timer[i]--;
+
+// if (pin_timer[0] != 0) UARTPrintf("pin_timer0 is non-zero\r\n");
+
+}
+#endif MQTT_SUPPORT
+
void check_reset_button(void)
{
@@ -3385,7 +3691,7 @@ void update_debug_storage() {
// // This loop can be enabled if you want the program to
// // hang after capturing data.
}
-#endif // DEBUG_SUPPORT != 0
+#endif // DEBUG_SUPPORT
#if DEBUG_SUPPORT != 0
@@ -3412,7 +3718,7 @@ void update_debug_storage1() {
lock_eeprom();
}
-#endif // DEBUG_SUPPORT != 0
+#endif // DEBUG_SUPPORT
#if DEBUG_SUPPORT != 0
@@ -3455,12 +3761,12 @@ void capture_uip_buf_transmit()
update_debug_storage();
}
}
-#endif // DEBUG_SUPPORT != 0
+#endif // DEBUG_SUPPORT
-#if DEBUG_SUPPORT != 0
+#if DEBUG_SUPPORT != 0 && MQTT_SUPPORT == 1
void capture_mqtt_sendbuf()
{
uint8_t i;
@@ -3477,7 +3783,7 @@ void capture_mqtt_sendbuf()
update_debug_storage(); // Write to EEPROM
}
}
-#endif // DEBUG_SUPPORT != 0
+#endif // DEBUG_SUPPORT && MQTT_SUPPORT
@@ -3513,4 +3819,4 @@ void capture_uip_buf_receive()
update_debug_storage();
}
}
-#endif // DEBUG_SUPPORT != 0
+#endif // DEBUG_SUPPORT
diff --git a/NetworkModule/httpd.c b/NetworkModule/httpd.c
index b69cd4b..5e71f65 100644
--- a/NetworkModule/httpd.c
+++ b/NetworkModule/httpd.c
@@ -53,21 +53,16 @@
#include "mqtt_pal.h"
#include "uipopt.h"
#include "uart.h"
+#include "ds18b20.h"
+#include "iostm8s005.h"
// #include "stdlib.h"
#include "string.h"
#include
#define STATE_CONNECTED 0 // Client has just connected
-#define STATE_GET_G 1 // G
-#define STATE_GET_GE 2 // GE
-#define STATE_GET_GET 3 // GET
-#define STATE_POST_P 4 // P
-#define STATE_POST_PO 5 // PO
-#define STATE_POST_POS 6 // POS
-#define STATE_POST_POST 7 // POST
-#define STATE_GOTGET 8 // Client just sent a GET request
-#define STATE_GOTPOST 9 // Client just sent a POST request
+#define STATE_GOTGET 1 // Client just sent a GET request
+#define STATE_GOTPOST 2 // Client just sent a POST request
#define STATE_PARSEPOST 10 // We are currently parsing the
// client's POST-data
#define STATE_SENDHEADER200 11 // Next we send the HTTP 200 header
@@ -98,7 +93,7 @@
extern uint8_t *pBuffer2;
extern uint8_t debug[NUM_DEBUG_BYTES];
extern uint8_t stored_debug[NUM_DEBUG_BYTES];
-#endif // DEBUG_SUPPORT != 0
+#endif // DEBUG_SUPPORT
extern uint16_t Port_Httpd; // Port number in use
@@ -158,80 +153,72 @@ uint8_t saved_nstate; // Saved nState used during TCP Fragment
// when a TCP fragmentation boundary occurred:
// STATE_NULL - indicates not
// processing fragment
- // STATE_GET_G
- // STATE_GET_GE
- // STATE_GET_GET
- // STATE_POST_P
- // STATE_POST_PO
- // STATE_POST_POS
- // STATE_POST_POST
// STATE_GOTGET
// STATE_GOTPOST
// STATE_PARSEPOST - parsing POST data
-uint8_t saved_parsestate; // Saved ParseState used during TCP Fragment
- // recovery. If not STATE_NULL saved_parsestate
- // will contain one of the following to
- // indicate the ParseState we were in when a
- // TCP fragmentation boundary occurred:
- // PARSE_CMD - STATE_PARSEPOST, seeking command character (a, b, c etc)
- // PARSE_NUM10 - STATE_PARSEPOST, seeking tens digit of command
- // PARSE_NUM1 - STATE_PARSEPOST, seeking ones digit of command
- // PARSE_EQUAL - STATE_PARSEPOST, seeking equal sign delimiter
- // PARSE_VAL - STATE_PARSEPOST, seeking data value following equal sign
- // PARSE_DELIM - STATE_PARSEPOST, seeking '&' delimiter
-uint8_t saved_nparseleft; // Saved nParseLeft during TCP Fragment recovery
-uint8_t saved_postpartial[36]; // If POST packet TCP fragmentation occurs saved_postpartial will
- // contain the that part of a POST value that was parsed in
- // the previous TCP Fragment as follows:
- // saved_postpartial[0] - the parsed ParseCmd
- // saved_postpartial[1] - the tens digit of the ParseNum
- // saved_postpartial[2] - the ones digit of the ParseNum
- // saved_postpartial[3] - the equal sign
- // saved_postpartial[4] - the first character of data
- // saved_postpartial[5] - the second character of data
- // saved_postpartial[x] - more characters of data
-uint8_t saved_postpartial_previous[36]; // When TCP Fragments are processed after the first
- // packet the saved_postpartial values are copied into the
- // saved_postpartial_previous values so that the new parsing
- // can use the saved_postpartial space for new data that might
- // get interrupted. The saved_postpartial_previous values are
- // used to restore the state of parsing from the previous
- // TCP Fragment.
-uint8_t saved_newlines; // Saved nNewlines value in case TCP fragmentation occurs during
- // the /r/n/r/n search.
-uint8_t z_diag; // The last value in a POST (hidden), used for diagnostics
-
-uint8_t break_while; // Used to indicate that a parsing "while loop" break is required
-uint8_t alpha[32]; // Used in parsing of multi-character values
-
-uint8_t current_webpage; // Tracks the web page that is currently displayed
+uint16_t saved_nparseleft; // Saved nParseLeft during TCP Fragment
+ // recovery
+uint8_t saved_newlines; // Saved nNewlines value in case TCP
+ // fragmentation occurs during the /r/n/r/n
+ // search.
+uint8_t parse_tail[38]; // If POST packet TCP fragmentation occurs
+ // parse_tail will contain partial POST value
+ // that was at the end of the packet. The
+ // size of this array is determined by the
+ // longest POST component. At this time that
+ // longest component is the &h00 POST reply.
+uint8_t z_diag; // The last value in a POST (hidden), used for
+ // diagnostics
+uint8_t break_while; // Used to indicate that a parsing "while loop"
+ // break is required
+uint8_t current_webpage; // Tracks the web page that is currently
+ // displayed
// MQTT variables
extern uint8_t mqtt_enabled; // Signals if MQTT has been enabled
extern uint8_t stored_mqttserveraddr[4]; // mqttserveraddr stored in EEPROM
-extern uint16_t stored_mqttport; // MQTT Port number stored in EEPROM
+extern uint16_t stored_mqttport; // MQTT Port number stored in
+ // EEPROM
extern char stored_mqtt_username[11]; // MQTT Username stored in EEPROM
extern char stored_mqtt_password[11]; // MQTT Password stored in EEPROM
-extern uint8_t Pending_mqttserveraddr[4]; // Temp storage for new MQTT IP Address
+extern uint8_t Pending_mqttserveraddr[4]; // Temp storage for new MQTT IP
+ // Address
extern uint16_t Pending_mqttport; // Temp storage for new MQTT Port
-extern char Pending_mqtt_username[11]; // Temp storage for new MQTT Username
-extern char Pending_mqtt_password[11]; // Temp storage for new MQTT Password
-
-extern uint8_t mqtt_start_status; // Contains error status from the MQTT start process
-extern uint8_t MQTT_error_status; // For MQTT error status display in GUI
-
-extern uint8_t RXERIF_counter; // Counts RXERIF errors
-extern uint8_t TXERIF_counter; // Counts TXERIF errors
+extern char Pending_mqtt_username[11]; // Temp storage for new MQTT
+ // Username
+extern char Pending_mqtt_password[11]; // Temp storage for new MQTT
+ // Password
+
+extern uint8_t mqtt_start_status; // Contains error status from the
+ // MQTT start process
+extern uint8_t MQTT_error_status; // For MQTT error status display in
+ // GUI
+
+extern uint8_t RXERIF_counter; // Counts RXERIF errors
+extern uint8_t TXERIF_counter; // Counts TXERIF errors
extern uint32_t TRANSMIT_counter; // Counts any transmit
-extern uint8_t MQTT_resp_tout_counter; // Counts response timeout events
-extern uint8_t MQTT_not_OK_counter; // Counts MQTT != OK events
-extern uint8_t MQTT_broker_dis_counter; // Counts broker disconnect events
+extern uint8_t MQTT_resp_tout_counter; // Counts response timeout events
+extern uint8_t MQTT_not_OK_counter; // Counts MQTT != OK events
+extern uint8_t MQTT_broker_dis_counter; // Counts broker disconnect events
extern uint32_t second_counter; // Counts seconds since boot
// DS18B20 variables
-extern uint8_t DS18B20_string[5][7]; // Stores the temperature measurement for the
- // DS18B20s
+extern uint8_t DS18B20_scratch[5][2]; // Stores the temperature measurement
+ // for the DS18B20s
+
+// Variables stored in Flash
+
+#if MQTT_SUPPORT == 0
+// Define Flash addresses for IO Names and IO Timers
+extern char IO_NAME[16][16] @0xff00;
+extern uint16_t IO_TIMER[16] @0xfec0;
+extern uint16_t Pending_IO_TIMER[16];
+#endif // MQTT_SUPPORT
+
+
+
+
//---------------------------------------------------------------------------//
@@ -245,18 +232,18 @@ extern uint8_t DS18B20_string[5][7]; // Stores the temperature measurement for
// code should insert data as the web page constant is copied from flash
// memory into the output data buffer.
//
-// - An example marker is %i01, wherein the CopyHttpData() function in the
-// application code will replace the "%i01" characters with a single "0" or
+// - An example marker is %n01, wherein the CopyHttpData() function in the
+// application code will replace the "%n01" characters with a single "0" or
// "1" character to signal the browser to paint a red or green box
-// indicating pin status.
+// indicating mqtt status.
//
// - Additional markers are inserted to help with compression of the web page
// templates to reduce the amount of flash memory required. In these cases
// the markers tell the application code to insert strings that are repeated
// many times in the web page HTML text, rather than have them repeatedly
-// appear in flash memory. For instance %y00 is used to signal the
+// appear in flash memory. For instance %y00 could be used to signal the
// application code to insert the string
-// "pattern='[0-9]{3}' title='Enter 000 to 255' maxlength='3'>"
+// "this is a test string"
// While this makes the code harder to read, it makes the web page templates
// much smaller.
//
@@ -280,7 +267,8 @@ extern uint8_t DS18B20_string[5][7]; // Stores the temperature measurement for
//
// - IMPORTANT: Be sure to carefully update the adjust_template_size function
// if any changes are made to the %xxx text replacement markers and strings
-// in the templates.
+// in the templates. Use CURL to verify that pages sizes are reported
+// correctly.
//
// - The templates include the line
// "".
@@ -304,7 +292,7 @@ extern uint8_t DS18B20_string[5][7]; // Stores the temperature measurement for
//---------------------------------------------------------------------------//
-
+#if MQTT_SUPPORT == 1
// IO Control Template
//
// PARSE_BYTES calculation:
@@ -335,10 +323,9 @@ extern uint8_t DS18B20_string[5][7]; // Stores the temperature measurement for
// + 6 - 1 = 42
#define WEBPAGE_IOCONTROL 0
#define PARSEBYTES_IOCONTROL 42
-#define PARSEBYTES_IOCONTROL_ADDL 0
static const char g_HtmlPageIOControl[] =
"%y04%y05"
- "IO Control"
+ "%a00: IO Control"
""
""
"
"
""
" lines.
// 4) Add double quotes at the start and end of the minfied script to make it part of the
// constant string.
@@ -504,10 +491,9 @@ const m = (data => {
// the sum of the two must not exceed 482.
#define WEBPAGE_CONFIGURATION 1
#define PARSEBYTES_CONFIGURATION 194
-#define PARSEBYTES_CONFIGURATION_ADDL 0
static const char g_HtmlPageConfiguration[] =
"%y04%y05"
- "Configuration"
+ "%a00: Configuration"
""
""
"
"
- ""
- ""
- ""
- ""
- "";
-#endif // UIP_STATISTICS
+#if MQTT_SUPPORT == 0
+// IO Control Template
+//
+// PARSE_BYTES calculation:
+// The form contained in this webpage will generate several data update
+// replies. These replies need to be parsed to extract the data from them. We
+// need to stop parsing the reply POST data after all update bytes are parsed.
+// The formula for determining the stop value is as follows:
+// Each POST has a "wrapper" consisting of
+// 1 byte ParseCmd
+// 2 byte ParseNum
+// 1 byte egual sign
+// 1 byte Delimiter
+// So, add 5 bytes to each POST as defined here:
+//
+// For 1 of the replies (Pin Control):
+// POST consists of 32 bytes data plus 5 byte wrapper (37 bytes)
+// PLUS
+// For 1 of the replies (hidden):
+// example: z00=x where x is 1 byte (note no &)
+// POST consists of a 1 byte data plus 4 byte wrapper (5 bytes)
+// THUS
+// The formula in this case is
+// PARSEBYTES = (1 x 37)
+// + (1 x 5)
+// PARSEBYTES = 37
+// + 5 = 42
+#define WEBPAGE_IOCONTROL 0
+#define PARSEBYTES_IOCONTROL 42
+static const char g_HtmlPageIOControl[] =
+"%y04%y05"
+ "%a00: IO Control"
+ ""
+ ""
+ "
IO Control
"
+ "";
-static const uint8_t page_string01_len = sizeof(page_string01) - 1;
-static const uint8_t page_string01_len_less4 = sizeof(page_string01) - 5;
-// STRING LENGTH MUST BE LESS THAN 256
-#if (page_string01_len > 255)
- #error "page_string01 is too big"
-#endif
-
+// Credit to Jevdeni Kiski for the javascript work and html improvements.
+// Below is the raw script used above before minify.
+// 1) Copy raw script to minify website, for example https://javascript-minifier.com/
+// 2) Copy the resulting minified script to an editor and replace all double quotes with
+// single quotes. THIS STEP IS VERY IMPORTANT.
+// 3) Copy the result to the above between the lines.
+// 4) Add double quotes at the start and end of the minfied script to make it part of the
+// constant string.
+// 5) It is OK to break up the minified script into lines enclosed by double quotes (just
+// to make it all visible in the code editors). But make sure no spaces are inadvertantly
+// removed from the minified script.
-// String for %y02 replacement in web page templates
-static const char page_string02[] =
- " "
- "
"
+ pBuffer=stpcpy(pBuffer, TEMPTEXT);
+ #undef TEMPTEXT
}
-
}
+
else if (nParsedMode == 'w') {
// This displays Code Revision information (13 characters)
pBuffer=stpcpy(pBuffer, code_revision);
}
-
+
+
else if (nParsedMode == 'y') {
// Indicates the need to insert one of several commonly occuring HTML
// strings. These strings were created to aid in compressing the web
@@ -2128,64 +2530,17 @@ static uint16_t CopyHttpData(uint8_t* pBuffer, const char** ppData, uint16_t* pD
// length for each string in the "array of strngs" is stored in an
// "array of string lengths" with nParsedNum again used as an index
// to select the correct value.
-
-
-
-// page_string
+ // Access the strings and string lengths as follows:
+ // ps[i].str
+ // ps[i].size
*pBuffer = (uint8_t)ps[nParsedNum].str[i];
insertion_flag[0]++;
if (insertion_flag[0] == ps[nParsedNum].size) insertion_flag[0] = 0;
-
-// Access the above strings, string length, and (string length - 4) as
-// follows:
-// ps[i].str
-// ps[i].size
-// ps[i].size_less4
-
-
-
-/*
- switch (nParsedNum)
- {
- case 1:
- // %y01 replaced with string
- *pBuffer = (uint8_t)page_string01[i];
- insertion_flag[0]++;
- if (insertion_flag[0] == page_string01_len) insertion_flag[0] = 0;
- break;
-
- case 2:
- // %y02 replaced with string
- *pBuffer = (uint8_t)page_string02[i];
- insertion_flag[0]++;
- if (insertion_flag[0] == page_string02_len) insertion_flag[0] = 0;
- break;
-
- case 4:
- // %y04 replaced with first header string
- *pBuffer = (uint8_t)page_string04[i];
- insertion_flag[0]++;
- if (insertion_flag[0] == page_string04_len) insertion_flag[0] = 0;
- break;
-
- case 5:
- // %y05 replaced with second header string
- *pBuffer = (uint8_t)page_string05[i];
- insertion_flag[0]++;
- if (insertion_flag[0] == page_string05_len) insertion_flag[0] = 0;
- break;
-
- default: break;
- }
-*/
-
-
-
-
pBuffer++;
}
}
+
else {
// If the above code did not process a "%" nParsedMode code and we were
// not continuing a string insertion then whatever character we read from
@@ -2202,6 +2557,27 @@ static uint16_t CopyHttpData(uint8_t* pBuffer, const char** ppData, uint16_t* pD
}
+char *show_temperature_string(char *pBuffer, uint8_t nParsedNum)
+{
+ // Display temperature strings in degrees C and degrees F
+ // Note: ℃ inserts a degree symbol followed by C.
+ // Note: ℉ inserts a degree symbol followed by F.
+ convert_temperature(nParsedNum, 0); // Convert to degrees C in OctetArray
+ pBuffer=stpcpy(pBuffer, OctetArray); // Display sensor value
+ #define TEMPTEXT "℃ " // Display degress C symbol
+ pBuffer=stpcpy(pBuffer, TEMPTEXT);
+ #undef TEMPTEXT
+
+ convert_temperature(nParsedNum, 1); // Convert to degrees F in OctetArray
+ pBuffer=stpcpy(pBuffer, OctetArray); // Display sensor value
+ #define TEMPTEXT "℉ " // Display degress F symbol
+ pBuffer=stpcpy(pBuffer, TEMPTEXT);
+ #undef TEMPTEXT
+
+ return pBuffer;
+}
+
+
void HttpDInit()
{
//Start listening on our port
@@ -2216,47 +2592,21 @@ void HttpDInit()
// Initialize fragment reassembly values
saved_nstate = STATE_NULL;
- saved_parsestate = PARSE_CMD;
saved_nparseleft = 0;
- clear_saved_postpartial_all();
}
-// define a structure that will help in terms of code reduction
-// when we process the GET and the POST
-struct STATES_TABLE {
- uint8_t current_state;
- char ch;
- uint8_t next_state;
-};
-
-// define number of states represented inside the table below
-#define AUTO_PARSE_ELEMENTS 9
-
-// allocate this in .const segment
-const struct STATES_TABLE parse_table[AUTO_PARSE_ELEMENTS] = {
-// current state char next state
- { STATE_CONNECTED, 'G', STATE_GET_G },
- { STATE_GET_G, 'E', STATE_GET_GE },
- { STATE_GET_GE, 'T', STATE_GET_GET },
- { STATE_GET_GET, ' ', STATE_GOTGET },
-
- { STATE_CONNECTED, 'P', STATE_POST_P },
- { STATE_POST_P, 'O', STATE_POST_PO },
- { STATE_POST_PO, 'S', STATE_POST_POS },
- { STATE_POST_POS, 'T', STATE_POST_POST },
- { STATE_POST_POST, ' ', STATE_GOTPOST }
-};
-
void HttpDCall(uint8_t* pBuffer, uint16_t nBytes, struct tHttpD* pSocket)
{
uint16_t nBufSize;
-// uint8_t i;
int i;
uint8_t j;
+ char local_buf[300];
+ uint16_t local_buf_index_max;
i = 0;
j = 0;
+ local_buf_index_max = 290; // local_buf index maximum
if (uip_connected()) {
//Initialize this connection
@@ -2267,18 +2617,25 @@ void HttpDCall(uint8_t* pBuffer, uint16_t nBytes, struct tHttpD* pSocket)
// nDataLeft above is used when we get around to calling CopyHttpData
// in state STATE_SENDDATA
}
+
else if (current_webpage == WEBPAGE_CONFIGURATION) {
pSocket->pData = g_HtmlPageConfiguration;
pSocket->nDataLeft = (uint16_t)(sizeof(g_HtmlPageConfiguration) - 1);
}
-#if DEBUG_SUPPORT == 11 || DEBUG_SUPPORT == 15 || UIP_STATISTICS == 1
- else if (current_webpage == WEBPAGE_STATS) {
- pSocket->pData = g_HtmlPageStats;
- pSocket->nDataLeft = (uint16_t)(sizeof(g_HtmlPageStats) - 1);
+#if UIP_STATISTICS == 1 && MQTT_SUPPORT == 0
+ else if (current_webpage == WEBPAGE_STATS1) {
+ pSocket->pData = g_HtmlPageStats1;
+ pSocket->nDataLeft = (uint16_t)(sizeof(g_HtmlPageStats1) - 1);
}
-#endif // DEBUG_SUPPORT == 11 || DEBUG_SUPPORT == 15 || UIP_STATISTICS == 1
+#endif // UIP_STATISTICS
+#if DEBUG_SUPPORT == 11 || DEBUG_SUPPORT == 15
+ else if (current_webpage == WEBPAGE_STATS2) {
+ pSocket->pData = g_HtmlPageStats2;
+ pSocket->nDataLeft = (uint16_t)(sizeof(g_HtmlPageStats2) - 1);
+ }
+#endif // DEBUG_SUPPORT
else if (current_webpage == WEBPAGE_SSTATE) {
pSocket->pData = g_HtmlPageSstate;
@@ -2374,69 +2731,33 @@ void HttpDCall(uint8_t* pBuffer, uint16_t nBytes, struct tHttpD* pSocket)
//
if (saved_nstate != STATE_NULL) {
// This point in the code will only be entered if we are parsing a TCP
- // Fragment after the first packet in a POST. While processing a prior
- // packet the parse was interrupted by the end of the packet. This code
- // will restore where we were in the parsing loop. This process relies
- // on no "out of order" packets.
+ // Fragment (a "continuation" packet that comes after the first packet
+ // in a POST). While processing a prior packet the parse was interrupted
+ // by the end of the packet. This code will restore where we were in the
+ // parsing loop. This process relies on no "out of order" packets.
+ //
+ // Note: This restoration is only needed if we hit a packet boundary
+ // while searching for the \r\n\r\n sequence in a POST. All other packet
+ // boundaries do not require any restoration as the boundary will be
+ // handled in the STATE_PARSEPOST code.
pSocket->nState = saved_nstate;
- // saved_nstate can be one of these: STATE_GOTPOST, STATE_PARSEPOST,
- // STATE_NULL. A TCP Fragment break can occur in any of these states.
- // A TCP Fragment cannot occur in pSocket->nState states
- // STATE_CONNECTED, STATE_GET_G, STATE_GET_GE, STATE_GET_GET,
- // STATE_POST_P, STATE_POST_PO, STATE_POST_POS, STATE_POST_POST,
- // STATE_GOTGET, STATE_SENDHEADER200, STATE_SENDHEADER204,
- // STATE_SENDDATA, STATE_PARSEGET.
- pSocket->ParseState = saved_parsestate;
- // saved_parsestate can be one of these: PARSE_CMD, PARSE_NUM10,
- // PARSE_NUM1, PARSE_EQUAL, PARSE_VAL, PARSE_DELIM, PARSE_SLASH1,
- // PARSE_FAIL
+ // saved_nstate can be one of these:
+ // STATE_GOTPOST
+ // STATE_PARSEPOST
+ // STATE_NULL
+ // A TCP Fragment break can occur in any of these states.
+ // A TCP Fragment cannot occur in these states:
+ // STATE_CONNECTED
+ // STATE_SENDHEADER204,
+ // STATE_SENDDATA
+ // STATE_PARSEGET
pSocket->nParseLeft = saved_nparseleft;
- // The number of bytes left to parse in the POST
+ // nParseLeft is the number of bytes left to parse in the POST data
pSocket->nNewlines = saved_newlines;
- // Next we'll capture the previous fragment's ParseCmd state data for
- // use in fragment reassembly. We need to do this because the
- // saved_postpartial[0] value will be reused below to capture any new
- // fragmentation state data.
- // In the following values:
- // [0] = ParseCmd
- // [1] = ParseNum ten's
- // [2] = ParseNum one's
- // [3] = Equal sign
- // [4] = 1st byte of value
- // [5] and up = More bytes of value
- for (i=0; i<36; i++) saved_postpartial_previous[i] = saved_postpartial[i];
-
- // If we had previously saved any partial input data we need to restore
- // it so the routines below can finish filling it in. What we saved will
- // vary depending on which command we were parsing.
- if (saved_nstate == STATE_PARSEPOST) {
- if (saved_parsestate == PARSE_CMD) {
- // No further restore needed
- }
- else if (saved_parsestate == PARSE_NUM10) {
- // Restore the ParseCmd
- pSocket->ParseCmd = saved_postpartial_previous[0];
- }
- else if (saved_parsestate == PARSE_NUM1) {
- // Restore the ParseCmd and tens digit of the ParseNum
- pSocket->ParseCmd = saved_postpartial_previous[0];
- pSocket->ParseNum = (uint8_t)((saved_postpartial_previous[1] - '0') * 10);
- }
- else if (saved_parsestate == PARSE_EQUAL || saved_parsestate == PARSE_VAL) {
- // Restore the ParseCmd and the entire ParseNum
- pSocket->ParseCmd = saved_postpartial_previous[0];
- pSocket->ParseNum = (uint8_t)((saved_postpartial_previous[1] - '0') * 10);
- pSocket->ParseNum += (uint8_t)(saved_postpartial_previous[2] - '0');
- }
- else if (saved_parsestate == PARSE_DELIM) {
- // No further restore needed
- }
- }
- // Note for TCP Fragmentation: No restore like that shown above is
- // required for saved_nstate == STATE_PARSEGET because the data searched
- // in the PARSE_GET parsing cannot be fragmented (it is all contained
- // within the first 100 bytes of the first packet).
+ // nNewlines tracks where we are in detecting the \r\n\r\n sequence
+ // that indicates start of POST data
}
+
// In the code below we are parsing for the "POST" or "GET " phrase. We do
// not need to worry about TCP fragmentation because the phrase will appear
@@ -2448,93 +2769,21 @@ void HttpDCall(uint8_t* pBuffer, uint16_t nBytes, struct tHttpD* pSocket)
// If we are parsing a TCP fragment then pSocket->nState may have been
// restored to STATE_PARSEPOST or STATE_PARSEGET. If so the parse code will
// run but won't do anything.
-
- {
- // use the structure defined on the top of this function to process
- // the GET and the POST
- // loop trough the table and identify the current state (pSocket->nState)
- for (i=0; i<=AUTO_PARSE_ELEMENTS ; i++) {
- // current table element is our current state?
- if (pSocket->nState == parse_table[i].current_state) {
- // if no more bytes left, return
- if (nBytes == 0) return;
- // if we get the expected character in the buffer, move to next state
- if (*pBuffer == parse_table[i].ch) {
- pSocket->nState = parse_table[i].next_state;
- // adjust counters
- nBytes--;
- pBuffer++;
- // signals a match found
- }
- }
- }
- }
-
-/*
-// This is the old, less efficient parse code that was used to find the POST
-// or GET phrases. The "parse_table" code above replaced this.
-
+
+ // If we are in STATE_CONNECTED (meaning we are reading the
+ // first and perhaps only packet in a series) check the first
+ // five characters of the uip_buf to see if this is a POST or
+ // GET request.
if (pSocket->nState == STATE_CONNECTED) {
- if (nBytes == 0) return;
- if (*pBuffer == 'G') {
- pSocket->nState = STATE_GET_G;
- }
- else if (*pBuffer == 'P') {
- pSocket->nState = STATE_POST_P;
- }
- nBytes--;
- pBuffer++;
- }
-
- if (pSocket->nState == STATE_GET_G) {
- if (nBytes == 0) return;
- if (*pBuffer == 'E') pSocket->nState = STATE_GET_GE;
- nBytes--;
- pBuffer++;
- }
-
- if (pSocket->nState == STATE_GET_GE) {
- if (nBytes == 0) return;
- if (*pBuffer == 'T') pSocket->nState = STATE_GET_GET;
- nBytes--;
- pBuffer++;
- }
-
- if (pSocket->nState == STATE_GET_GET) {
- if (nBytes == 0) return;
- if (*pBuffer == ' ') pSocket->nState = STATE_GOTGET;
- nBytes--;
- pBuffer++;
- }
-
- if (pSocket->nState == STATE_POST_P) {
- if (nBytes == 0) return;
- if (*pBuffer == 'O') pSocket->nState = STATE_POST_PO;
- nBytes--;
- pBuffer++;
- }
-
- if (pSocket->nState == STATE_POST_PO) {
- if (nBytes == 0) return;
- if (*pBuffer == 'S') pSocket->nState = STATE_POST_POS;
- nBytes--;
- pBuffer++;
- }
-
- if (pSocket->nState == STATE_POST_POS) {
- if (nBytes == 0) return;
- if (*pBuffer == 'T') pSocket->nState = STATE_POST_POST;
- nBytes--;
- pBuffer++;
- }
-
- if (pSocket->nState == STATE_POST_POST) {
- if (nBytes == 0) return;
- if (*pBuffer == ' ') pSocket->nState = STATE_GOTPOST;
- nBytes--;
- pBuffer++;
+ if (memcmp("POST", &pBuffer[0], 4) == 0) pSocket->nState = STATE_GOTPOST;
+ if (memcmp("GET", &pBuffer[0], 3) == 0) pSocket->nState = STATE_GOTGET;
+ pBuffer += 4;
+ nBytes -= 4;
+ // We are in STATE_NULL, which means we are collecting the first packet.
+ // Clear parse_tail so it will be ready if there is a TCP Fragment.
+ parse_tail[0] = '\0';
}
-*/
+
if (pSocket->nState == STATE_GOTPOST) {
//Search for \r\n\r\n
@@ -2579,27 +2828,25 @@ void HttpDCall(uint8_t* pBuffer, uint16_t nBytes, struct tHttpD* pSocket)
// Initialize Parsing variables
if (current_webpage == WEBPAGE_IOCONTROL) {
pSocket->nParseLeft = PARSEBYTES_IOCONTROL;
- pSocket->nParseLeftAddl = PARSEBYTES_IOCONTROL_ADDL;
}
if (current_webpage == WEBPAGE_CONFIGURATION) {
pSocket->nParseLeft = PARSEBYTES_CONFIGURATION;
- pSocket->nParseLeftAddl = PARSEBYTES_CONFIGURATION_ADDL;
}
- pSocket->ParseState = saved_parsestate = PARSE_CMD;
saved_nparseleft = pSocket->nParseLeft;
// Start parsing
pSocket->nState = STATE_PARSEPOST;
saved_nstate = STATE_PARSEPOST;
if (nBytes == 0) {
// If we are at end of fragment here we exit and will return in
- // STATE_PARSEPOST / PARSE_CMD
+ // STATE_PARSEPOST
return;
}
break;
}
}
}
-
+
+
if (pSocket->nState == STATE_GOTGET) {
// Don't search for \r\n\r\n ... instead parse what we've got
// Initialize Parsing variables
@@ -2609,601 +2856,110 @@ void HttpDCall(uint8_t* pBuffer, uint16_t nBytes, struct tHttpD* pSocket)
// Start parsing
pSocket->nState = STATE_PARSEGET;
}
-
+
+
if (pSocket->nState == STATE_PARSEPOST) {
- // This section will parse a POST sent by the user (usually when they
- // click on the "submit" button on a webpage). POST data will consist
- // of:
- // One digit with a ParseCmd
- // Two digits with a ParseNum indicating the item to be changed
- // One digit with an equal sign
- // A variable number of characters with a ParseState indicating the
- // new value of the item
- // One digit with a Parse Delimiter (an '&')
+ // Parse pre-process
+ // Copy the POST from the uip_buf to the local_buf until one of two
+ // things happens:
+ // a) The local_buf is full
+ // b) The end of the uip_buf is reached (end of the packet)
//
+ // Copy each POST component to the parse_tail as they are found.
+ // As each POST component is found it will replace the prior POST
+ // component. The objective is to let the parse_tail contain any
+ // partial POST that appears at the tail of the current packet.
+
+ uint16_t i = 0;
+ uint16_t j = 0;
+
+ // If we are continuing data collection due to a TCP Fragment
+ // parse_tail will have any fragment of the previous POST in
+ // it. Otherwise parse_tail is NULL.
+ strcpy(local_buf, parse_tail);
+ i = strlen(parse_tail);
+
while (1) {
- // When appropriate conditions are met a break will occur to leave
- // the while loop.
- if (pSocket->ParseState == PARSE_CMD) {
- pSocket->ParseCmd = *pBuffer;
- saved_postpartial[0] = *pBuffer;
- pSocket->ParseState = saved_parsestate = PARSE_NUM10;
- if (pSocket->nParseLeft > 0) { // Prevent underflow
- pSocket->nParseLeft--;
- }
- else {
- // Something out of sync - escape
- pSocket->ParseState = PARSE_DELIM;
- }
- saved_nparseleft = pSocket->nParseLeft;
- pBuffer++;
- nBytes --;
- if (nBytes == 0) { // Hit end of fragment. Break out of while()
- // loop.
- break;
- }
- }
+ local_buf[i] = *pBuffer;
+ local_buf[i+1] = '\0';
+ parse_tail[j] = *pBuffer;
+ parse_tail[j+1] = '\0';
+ pBuffer++;
+ nBytes--;
+ i++;
+ j++;
- else if (pSocket->ParseState == PARSE_NUM10) {
- pSocket->ParseNum = (uint8_t)((*pBuffer - '0') * 10);
- saved_postpartial[1] = *pBuffer;
- pSocket->ParseState = saved_parsestate = PARSE_NUM1;
- if (pSocket->nParseLeft > 0) { // Prevent underflow
- pSocket->nParseLeft--;
- }
- else {
- // Something out of sync - escape
- pSocket->ParseState = PARSE_DELIM;
- }
- saved_nparseleft = pSocket->nParseLeft;
- pBuffer++;
- nBytes--;
- if (nBytes == 0) {
- // Hit end of TCP Fragment. Break out of while() loop.
+ if (nBytes == 0) {
+ // Hit end of packet
+ if (strcmp(parse_tail, "&z00=0") == 0) {
+ // If this is also the end of the POST (as indicated by parse_tail
+ // equal to "&z00=0") then send the entire local_buf to parsing.
+ // Parse the local_buf
+ parse_local_buf(pSocket, local_buf, strlen(local_buf));
break;
}
- }
-
- else if (pSocket->ParseState == PARSE_NUM1) {
- pSocket->ParseNum += (uint8_t)(*pBuffer - '0');
- saved_postpartial[2] = *pBuffer;
- pSocket->ParseState = saved_parsestate = PARSE_EQUAL;
- if (pSocket->nParseLeft > 0) { // Prevent underflow
- pSocket->nParseLeft--;
- }
+
else {
- // Something out of sync - escape
- pSocket->ParseState = PARSE_DELIM;
- }
- saved_nparseleft = pSocket->nParseLeft;
- pBuffer++;
- nBytes--;
- if (nBytes == 0) {
- // Hit end of TCP Fragment. Break out of while() loop.
+ // We don't have all the POST data - it will be arriving in
+ // subsequent packets
+ // Back up the NULL terminator in the local_buf to the point where
+ // the last POST component ended. Note that this will eliminate
+ // one delimiter search in POST parsing so we need to decrement
+ // the nParseLeft value by one for this case.
+ i = i - strlen(parse_tail);
+ local_buf[i] = '\0';
+ pSocket->nParseLeft--;
+
+ // Parse the local_buf
+ parse_local_buf(pSocket, local_buf, strlen(local_buf));
+ // Save the nParseLeft value for the next pass
+ saved_nparseleft = pSocket->nParseLeft;
+
+ // Shift the content of parse_tail to eliminate the '&'
+ strcpy(parse_tail, &parse_tail[1]);
break;
}
- }
+ }
- else if (pSocket->ParseState == PARSE_EQUAL) {
- pSocket->ParseState = saved_parsestate = PARSE_VAL;
- saved_postpartial[3] = *pBuffer;
- if (pSocket->nParseLeft > 0) { // Prevent underflow
+ if (i == local_buf_index_max) {
+ // Hit end of local_buf
+ // We don't yet have all the data from this packet but need to
+ // parse what we have so far.
+ // Back up the NULL terminator in the local_buf to the point where
+ // the last POST component ended. Note that this will eliminate
+ // one delimiter search in POST parsing so we need to decrement
+ // the nParseLeft value by one for this case.
+ i = i - strlen(parse_tail);
+ local_buf[i] = '\0';
pSocket->nParseLeft--;
- }
- else {
- // Something out of sync - escape
- pSocket->ParseState = PARSE_DELIM;
- }
- saved_nparseleft = pSocket->nParseLeft;
- pBuffer++;
- nBytes--;
- if (nBytes == 0) {
- // Hit end of TCP Fragment. Break out of while() loop.
- break;
- }
- }
-
- else if (pSocket->ParseState == PARSE_VAL) {
- // 'a' is submit data for the Device Name
- // 'b' is submit data for the IP/Gateway/Netmask
- // 'c' is submit data for the Port number
- // 'd' is submit data for the MAC
- // 'g' is submit data for the Config settings string
- // 'h' is submit data for the Pin Control String
- // 'l' is submit data for the MQTT Username
- // 'm' is submit data for the MQTT Password
- // 'z' is submit data for a hidden input used for a diagnostic
- // indicator that all POST processing completed
-
-
- // Parse 'a' 'l' 'm' ----------------------------------------------//
- if (pSocket->ParseCmd == 'a'
- || pSocket->ParseCmd == 'l'
- || pSocket->ParseCmd == 'm' ) {
- // a = Update the Device Name field
- // l = Update the MQTT Username field
- // m = Update the MQTT Password field
-
- // If parsing 'a' 'l' or 'm' we know we are parsing a Configuration
- // page. Set current_webpage to WEBPAGE_CONFIGURATION so that the
- // browser will display this page after Save is clicked. This is a
- // workaround for the "multiple browser page interference" issue
- // where another browser might have changed the current_webpage
- // value.
- current_webpage = WEBPAGE_CONFIGURATION;
-
- break_while = 0; // Clear the break switch in case a TCP Fragment
- // occurs.
- switch (pSocket->ParseCmd) {
- case 'a': j = 19; break;
- case 'l':
- case 'm': j = 10; break;
- }
- parse_POST_string(&pBuffer, &nBytes, pSocket, j);
- if (break_while == 1) {
- // Hit end of TCP Fragment. Break out of while() loop.
- // The parse_POST_string() routine will have loaded the
- // saved_parsestate value with the next pSocket->ParseState.
- pSocket->ParseState = saved_parsestate;
- break;
- }
- // Else we didn't hit the end of a TCP Fragment so we fall through
- // to the PARSE_DELIM state
- }
-
- // Parse 'b' ------------------------------------------------------//
- else if (pSocket->ParseCmd == 'b') {
- // This code updates the "pending" IP address, Gateway address,
- // Netmask, and MQTT Host IP address which will then cause the
- // main.c functions to restart the software.
- // The value following the 'bxx=' ParseCmd and ParseNum consists
- // of eight alpha digits representing the value in hex. The
- // function call collects the alpha digits, validates them, and
- // converts them to the numeric value used by the other firmware
- // functions.
- break_while = 0; // Clear the break switch in case a TCP Fragment
- // occurs.
- parse_POST_address(&pBuffer, &nBytes, pSocket);
- if (break_while == 1) {
- // Hit end of TCP Fragment but still have characters to collect.
- // Break out of while() loop.
- // The next line shouldn't be needed because the values shouldn't have changed
- pSocket->ParseState = saved_parsestate = PARSE_VAL;
- break;
- }
- if (break_while == 2) {
- // Hit end of TCP Fragment just before &. Break out of while()
- // loop.
- pSocket->ParseState = saved_parsestate = PARSE_DELIM;
- break;
- }
- // Else we didn't hit the end of a TCP Fragment so we fall through
- // to the PARSE_DELIM state
- }
-
- // Parse 'c' ------------------------------------------------------//
- else if (pSocket->ParseCmd == 'c') {
- // This code updates the "pending" HTTP Port number or MQTT Port
- // number which will then cause the main.c functions to restart
- // the software.
- // ParseNum == 0 indicates the HTTP Port number.
- // ParseNum == 1 indicates the MQTT Port number.
- // The value following the 'cxx=' ParseCmd & ParseNum consists
- // of four alpha digits with the port number in hex form. The
- // function call collects the digits, validates them, and updates
- // the pending port number.
- break_while = 0; // Clear the break switch in case a TCP Fragment
- // occurs.
- parse_POST_port(&pBuffer, &nBytes, pSocket);
- if (break_while == 1) {
- // Hit end of TCP Fragment but still have characters to collect.
- // Break out of while() loop.
- pSocket->ParseState = saved_parsestate = PARSE_VAL;
- break;
- }
- if (break_while == 2) {
- // Hit end of TCP Fragment just before &. Break out of while()
- // loop.
- pSocket->ParseState = saved_parsestate = PARSE_DELIM;
- break;
- }
- // Else we didn't hit the end of a TCP Fragment so we fall through
- // to the PARSE_DELIM state
- }
-
- // Parse 'd' ------------------------------------------------------//
- else if (pSocket->ParseCmd == 'd') {
- // This code updates the "pending" MAC address which will then
- // cause the main.c functions to restart the software.
- // The value following the 'dxx=' ParseCmd and ParseNum consists
- // of twelve alpha digits in hex form ('0' to '9' and 'a' to 'f').
- // The function call collects the digits, validates them, and
- // updates the pending MAC number.
-
- break_while = 0; // Clear the break switch in case a TCP Fragment
- // occurs.
- parse_POST_MAC(&pBuffer, &nBytes, pSocket);
- if (break_while == 1) {
- // Hit end of TCP Fragment but still have characters to collect.
- // Break out of while() loop.
- pSocket->ParseState = saved_parsestate = PARSE_VAL;
- break;
- }
- if (break_while == 2) {
- // Hit end of TCP Fragment just before &. Break out of while()
- // loop.
- pSocket->ParseState = saved_parsestate = PARSE_DELIM;
- break;
- }
- // Else we didn't hit the end of a TCP Fragment so we fall through
- // to the PARSE_DELIM state
- }
- // Parse 'g' ------------------------------------------------------//
- else if (pSocket->ParseCmd == 'g') {
- // This code sets the Config Settings bytes which define the
- // DS18B20, MQTT, Full/Half Duplex, and Home Assistant Auto
- // Discovery functionality.
- //
- // There are always 2 characters in the string which represent a
- // hex encoded byte. Each is collected and saved for later
- // processing.
-
- preload_alphas();
-
- break_while = 0; // Clear the break switch in case a TCP Fragment
- // occurs.
-
- if (saved_postpartial_previous[0] == 'g') {
- // Clear the saved_postpartial_prevous[0] byte (the ParseCmd
- // byte) as it should only get used once on processing a given
- // TCP Fragment.
- saved_postpartial_previous[0] = '\0';
- // We are re-assembling a fragment that occurred during this
- // command. The ParseCmd and ParseNum values are already
- // restored. We need to determine where in this command the
- // fragmentation break occurred and continue from there.
- // Check alphas
- check_alphas();
- }
-
- else {
- // We are not doing a reassembly. Clear the data part of the
- // saved_postpartial values in case a fragment break occurs
- // during this parse
- clear_saved_postpartial_data(); // Clear [4] and higher
- }
-
- for (i=0; i<2; i++) {
- // Examine each 'alpha' character to see if it was already found
- // in a prior TCP Fragment. If not collect it now.
- // If collecting characters from the POST break the while() loop
- // if a TCP Fragment boundary is found unless the character
- // collected is the last 'alpha'.
- if (alpha[i] == '-') {
- alpha[i] = (uint8_t)(*pBuffer);
- saved_postpartial[i+4] = *pBuffer;
- pSocket->nParseLeft--;
- saved_nparseleft = pSocket->nParseLeft;
- pBuffer++;
- nBytes--;
- if (i != 1 && nBytes == 0) {
- break_while = 1; // Hit end of fragment. Break out of
- // while() loop.
- break; // Break out of for() loop
- }
- }
- }
- if (break_while == 1) {
- // Hit end of TCP Fragment. Break out of while() loop.
- break;
- }
-
- // If we get this far we no longer need the saved_postpartial
- // values and must clear them to prevent interference with
- // subsequent restores.
- clear_saved_postpartial_all();
-
- // Validate entries?
- // Check if they are hex characters?
-
- // Convert hex nibbles to a byte and store in Config settings
- Pending_config_settings = (uint8_t)(hex2int(alpha[0]));
- Pending_config_settings = (uint8_t)(Pending_config_settings<<4);
- Pending_config_settings |= (uint8_t)(hex2int((uint8_t)alpha[1]));;
-
- if (nBytes == 0) {
- // Hit end of fragment. Break out of while() loop. The next
- // character will be '&' so we need to set PARSE_DELIM.
- pSocket->ParseState = saved_parsestate = PARSE_DELIM;
- break;
- }
- // Else we didn't hit the end of a TCP Fragment so we fall through
- // to the PARSE_DELIM state
- }
-
- // Parse 'h' ------------------------------------------------------//
- else if (pSocket->ParseCmd == 'h') {
- // This code sets the Pending_pin_control bytes based on the information
- // in the 32 character string sent in the h00 field.
- //
- // There are always 32 characters in the string in 16 pairs of
- // hex encoded nibbles, each pair representing a hex encoded pin
- // control byte. The character pairs are extracted one set at a
- // time, converted to a numeric byte, and stored in their
- // corresponding Pending_pin_control byte.
-
- preload_alphas();
-
- break_while = 0; // Clear the break switch in case a TCP Fragment
- // occurs.
-
- if (saved_postpartial_previous[0] == 'h') {
- // Clear the saved_postpartial_prevous[0] byte (the ParseCmd
- // byte) as it should only get used once on processing a given
- // TCP Fragment.
- saved_postpartial_previous[0] = '\0';
- // We are re-assembling a fragment that occurred during this
- // command. The ParseCmd and ParseNum values are already
- // restored. We need to determine where in this command the
- // fragmentation break occurred and continue from there.
- // Check alphas
- check_alphas();
- }
-
- else {
- // We are not doing a reassembly. Clear the data part of the
- // saved_postpartial values in case a fragment break occurs
- // during this parse
- clear_saved_postpartial_data(); // Clear [4] and higher
- }
-
- for (i=0; i<32; i++) {
- // Examine each 'alpha' character to see if it was already found
- // in a prior TCP Fragment. If not collect it now.
- // If collecting characters from the POST break the while() loop
- // if a TCP Fragment boundary is found unless the character
- // collected is the last 'alpha'.
- if (alpha[i] == '-') {
- alpha[i] = (uint8_t)(*pBuffer);
- saved_postpartial[i+4] = *pBuffer;
- pSocket->nParseLeft--;
- saved_nparseleft = pSocket->nParseLeft;
- pBuffer++;
- nBytes--;
- if (i != 31 && nBytes == 0) {
- break_while = 1; // Hit end of fragment. Break out of
- // while() loop.
- break; // Break out of for() loop
- }
- }
- }
- if (break_while == 1) {
- // Hit end of TCP Fragment. Break out of while() loop.
- break;
- }
-
- // If we get this far we no longer need the saved_postpartial
- // values and must clear them to prevent interference with
- // subsequent restores.
- clear_saved_postpartial_all();
-
- // Sort the alpha characters into the pin control bytes
- {
- int i;
- int j;
- uint8_t k;
- i = 0;
- j = 0;
- while( i<32 ) {
- // The Configuration page updates all bits except the
- // ON/OFF bit
- // The IOControl page only updates the ON/OFF bit
- Pending_pin_control[j] = pin_control[j];
- // Convert the pin control string into numeric bytes
- // two characters at a time. "k" will contain the byte
- // after conversion.
- k = (uint8_t)hex2int(alpha[i]);
- k = (uint8_t)(k << 4);
- i++;
- k = (uint8_t)(k | hex2int(alpha[i]));
- i++;
- if (current_webpage == WEBPAGE_CONFIGURATION) {
- // Keep the ON/OFF bit as-is
- Pending_pin_control[j] = (uint8_t)(Pending_pin_control[j] & 0x80);
- // Mask out the ON/OFF bit in the temp variable
- k = (uint8_t)(k & 0x7f);
- }
- else {
- // current_webpage is WEBPAGE_IOCONTROL
- // Keep the configuration bits as-is
- Pending_pin_control[j] = (uint8_t)(Pending_pin_control[j] & 0x7f);
- // Mask out the configuration bits in the temp variable
- k = (uint8_t)(k & 0x80);
- }
- // "OR" in the changed bits
- Pending_pin_control[j] = (uint8_t)(Pending_pin_control[j] | k);
- j++;
- }
- }
-
- if (nBytes == 0) {
- // Hit end of fragment. Break out of while() loop. The next
- // character will be '&' so we need to set PARSE_DELIM.
- pSocket->ParseState = saved_parsestate = PARSE_DELIM;
- break;
- }
- // Else we didn't hit the end of a TCP Fragment so we fall through
- // to the PARSE_DELIM state
- }
-
- // Parse 'z' ------------------------------------------------------//
- else if (pSocket->ParseCmd == 'z') {
- // This code signals that a "hidden" post was received. This is a
- // diagnostic POST reply only, indicating that all data was
- // posted.
- //
- // Note on TCP Fragment reassembly: Once this value is collected
- // we no longer need to track anything for fragment reassembly as
- // we've already collected all useful information. nBytes may
- // still be > 0, but it won't be checked. nParseLeft will be zero,
- // causing us to enter STATE_SENDHEADER204.
- //
- // There is no '&' delimiter after this POST value.
- //
- // The next two lines aren't needed because we are going to zero
- // out the values.
- // if (pSocket->nParseLeft > 0) pSocket->nParseLeft--;
- // pBuffer++;
- // nBytes--;
- // Even if there was some error prior to this point we know we
- // just read the last allowable byte in a parsing. So:
- // Zero out the byte counters
- nBytes = 0;
- pSocket->nParseLeft = 0;
- break; // Break out of the while loop. We're done with POST.
- }
+ // Parse the local_buf
+ parse_local_buf(pSocket, local_buf, strlen(local_buf));
- // If we got to this point one of the "if/else if" above should have
- // executed leaving the pointers pointing at the "&" delimiter in
- // the POST data as the next character to be processed. So we set
- // the ParseState to PARSE_DELM and let the while() do its next pass.
- //
- // Note on TCP Fragment reassembly: We could check for
- // saved_parsestate == PARSE_DELIM, but that is its only remaining
- // possible value if we got here.
- pSocket->ParseState = saved_parsestate = PARSE_DELIM;
+ // Shift the content of parse_tail to eliminate the '&'
+ strcpy(parse_tail, &parse_tail[1]);
- if (pSocket->nParseLeft < 30) {
- // This snippet of code was necessary to enable a POST greater than
- // 255 bytes yet keep all math to 8 bits. As the nParseLeft value
- // counts down during POST processing it is checked when it goes
- // below a count of 30, and at that point the nParseLeftAddl value
- // is added ONCE to enable a longer down count. Using this scheme
- // the total POST can be up to 512 - 30 = 482 bytes. Makes the code
- // harder to follow, but eliminates the need for 16 bit values (and
- // math) which requires much more code space in flash. FYI, the
- // check point at "30" was arbitrary. With some thought about how
- // the content of the POST values it could probably be smaller.
- //
- // We've got got to make sure we don't add the 'additional' amount
- // on while we're procerssing a TCP Fragment. The way to be sure is
- // to only add to nParseLeft while processing a PARSE_DELIM.
- if (pSocket->nParseLeftAddl > 0) {
- pSocket->nParseLeft += pSocket->nParseLeftAddl;
- pSocket->nParseLeftAddl = 0;
- saved_nparseleft = pSocket->nParseLeft;
- }
- }
- }
-
- else if (pSocket->ParseState == PARSE_DELIM) {
- if (pSocket->nParseLeft > 0) {
- // Parse the next character, which must be a '&' delimiter. From
- // here we go parse the next command byte.
- pSocket->ParseState = saved_parsestate = PARSE_CMD;
- pSocket->nParseLeft--;
- saved_nparseleft = pSocket->nParseLeft;
- pBuffer++;
- nBytes--;
- // Since we just parsed a '&' clear the saved_postpartial bytes
- clear_saved_postpartial_all();
- // If the '&' delimiter was the last POST byte in this packet we
- // will exit the while loop and fall through to an exit without
- // going to STATE_SENDHEADER204
- if (nBytes == 0) {
- break; // Hit end of fragment but still have more to parse in
- // the next TCP Fragment. The next TCP Fragment will
- // start with a command byte.
- }
- }
- else {
- // If we came to PARSE_DELIM and there was nothing left to parse
- // in this or any subsequent packet (the normal exit state for
- // POST data) then we just make sure nParseLeft is zero (not
- // negative), nBytes is zero, and go on to exit.
- pSocket->nParseLeft = 0; // End the parsing
- nBytes = 0;
- break; // Exit parsing
- }
- }
- } // end of "while(1)" loop
-
- // If nParseLeft == 0 we should enter STATE_SENDHEADER204, but we
- // clean up the fragment tracking pointers first.
- //
- // If nParseLeft is > 0 we haven't received the whole POST yet. In that
- // case we should not enter STATE_SENDHEADER204 until we finish
- // receiving and parsing the whole POST.
- //
- // We also do not want the main.c loop to do any processing of the
- // Pending values collected so far until we've completed collecting ALL
- // POST data. We can tell we still have processing to do because:
- // saved_nstate != STATE_NULL
- // saved_nparseleft != 0.
- // I will use a global "parse_complete" variable to pass the state to
- // the main.c functions.
- //
- // What if we still have a fragment outstanding, some dangling part of
- // the TCP datagram that follows the POST data? That shouldn't happen
- // as the POST data is the last thing in the datagram. But even if it
- // did it should get dropped by the UIP processes and won't cause any
- // action to be taken.
- //
-
- if (pSocket->nParseLeft == 0) {
- // Finished parsing ... even if nBytes is not zero
- // Clear the saved states
- saved_nstate = STATE_NULL;
- saved_parsestate = PARSE_CMD;
- saved_nparseleft = 0;
- saved_newlines = 0;
- for (i=0; i<36; i++) saved_postpartial_previous[i] = saved_postpartial[i] = '\0';
-
- // Signal the main.c processes that parsing is complete
- parse_complete = 1;
- pSocket->nState = STATE_SENDHEADER204;
-
- // Patch: ON CHROME ONLY: When 'Save' is clicked after changing from
- // the IOControl page to the Configuration page for some reason no
- // Configuration page refresh occurs. At one time the wrong page
- // would display, but that does not seem to happen anymore. The next
- // steps are a workaround to get Chrome to behave better. I am not
- // sure why this happens as the 'if (uip_connected()' steps at the
- // start of this function call should have already done this. Note
- // that if the page change is done, then the 'Refresh' button is
- // clicked, then the 'Save' button is clicked this problem does not
- // appear. This problem was not seen with FireFox, Edge, or IE.
-
- if (current_webpage == WEBPAGE_IOCONTROL) {
- pSocket->pData = g_HtmlPageIOControl;
- pSocket->nDataLeft = (uint16_t)(sizeof(g_HtmlPageIOControl) - 1);
- }
- if (current_webpage == WEBPAGE_CONFIGURATION) {
- pSocket->pData = g_HtmlPageConfiguration;
- pSocket->nDataLeft = (uint16_t)(sizeof(g_HtmlPageConfiguration) - 1);
- }
- }
-
- else {
- // Else nParseLeft > 0 so we are still waiting on the remote host to
- // send more POST data. This should arrive in subsequent packets. The
- // remote host is not expecting a CLOSE connection until we are done
- // receiving all POST data. The CLOSE will happen as part of the
- // STATE_SENDHEADER204 process.
- //
- // Note on TCP Fragment reassembly: When the MSS is smaller than the
- // size of the packets that the remote host wants to send it will
- // simply send multiple packets of size MSS or smaller. We are
- // entirely dependent on nParseLeft to determine when to go to
- // STATE_SEND_HEADER, and we must assume that any additional fragments
- // that are sent after we get all the POST data are disposed of by the
- // UIP code. FYI, there shouldn't be any TCP Fragments after
- // nParseLeft = 0.
- //
- uip_len = 0;
+ // There is still more POST data in the uip_buf. Restore the
+ // partial POST component to the local_buf and reset the index
+ // values so the while() loop can continue data collection.
+ strcpy(local_buf, parse_tail);
+ i = strlen(parse_tail); // Note: parse_tail might be empty
+ // Note: the "j" index into parse_tail is not reset in this
+ // case as the packet might end before the parse_tail is
+ // completely collected.
+ continue;
+ }
+
+ if (*pBuffer == '&') {
+ // Starting a new POST component collection.
+ // Reset j so the parse_tail will fill with the new POST component.
+ j = 0;
+ parse_tail[0] = '\0';
+ continue;
+ }
}
}
+
if (pSocket->nState == STATE_PARSEGET) {
// This section will parse a GET request sent by the user. Normally in a
@@ -3362,8 +3118,11 @@ void HttpDCall(uint8_t* pBuffer, uint16_t nBytes, struct tHttpD* pSocket)
// http://IP/63 Show Help page
// http://IP/64 Show Help2 page
// http://IP/65 Flash LED 3 times
- // http://IP/66 Show Statistics page
- // http://IP/67 Clear Statistics
+ // http://IP/66 Show Link Error Statistics page
+ // http://IP/67 Clear Link Error Statistics and refresh page
+ // http://IP/68 Show Network Statistics page
+ // http://IP/69 Clear Network Statistics and refresh page
+ // http://IP/70 Clear the "Reset Status Register" counters
// http://IP/91 Reboot
// http://IP/98 Show Very Short Form IO States page
// http://IP/99 Show Short Form IO States page
@@ -3422,38 +3181,66 @@ void HttpDCall(uint8_t* pBuffer, uint16_t nBytes, struct tHttpD* pSocket)
// XXXXXXXXXXXXXXXXXXXXXX
break;
-#if DEBUG_SUPPORT == 11 || DEBUG_SUPPORT == 15 || UIP_STATISTICS == 1
- case 66: // Show statistics page
- current_webpage = WEBPAGE_STATS;
- pSocket->pData = g_HtmlPageStats;
- pSocket->nDataLeft = (uint16_t)(sizeof(g_HtmlPageStats) - 1);
+#if DEBUG_SUPPORT == 11 || DEBUG_SUPPORT == 15
+ case 66: // Show Link Error Statistics page
+ current_webpage = WEBPAGE_STATS2;
+ pSocket->pData = g_HtmlPageStats2;
+ pSocket->nDataLeft = (uint16_t)(sizeof(g_HtmlPageStats2) - 1);
pSocket->nState = STATE_CONNECTED;
pSocket->nPrevBytes = 0xFFFF;
break;
- case 67: // Clear statistics
- uip_init_stats();
- // Clear the "Reset Status Register" counters and the
- // Link Error Stats bytes.
+ case 67: // Clear Link Error Statistics
+ // Clear the the Link Error Statistics bytes.
// Important:
// The debug[] byte indexes used may change if the
// number of debug bytes changes.
- for (i = 20; i < 30; i++) debug[i] = 0;
+ debug[23] = 0; // Clear TXERIF counter
+ debug[24] = 0; // Clear RXERIF counter
update_debug_storage1();
- // Clear the statistics that are part of Link Error
- // Stats
TRANSMIT_counter = 0;
MQTT_resp_tout_counter = 0;
MQTT_not_OK_counter = 0;
MQTT_broker_dis_counter = 0;
- current_webpage = WEBPAGE_STATS;
- pSocket->pData = g_HtmlPageStats;
- pSocket->nDataLeft = (uint16_t)(sizeof(g_HtmlPageStats) - 1);
+ current_webpage = WEBPAGE_STATS2;
+ pSocket->pData = g_HtmlPageStats2;
+ pSocket->nDataLeft = (uint16_t)(sizeof(g_HtmlPageStats2) - 1);
+ pSocket->nState = STATE_CONNECTED;
+ pSocket->nPrevBytes = 0xFFFF;
+ break;
+#endif // DEBUG_SUPPORT
+
+#if UIP_STATISTICS == 1 && MQTT_SUPPORT == 0
+ case 68: // Show Network Statistics page
+ current_webpage = WEBPAGE_STATS1;
+ pSocket->pData = g_HtmlPageStats1;
+ pSocket->nDataLeft = (uint16_t)(sizeof(g_HtmlPageStats1) - 1);
+ pSocket->nState = STATE_CONNECTED;
+ pSocket->nPrevBytes = 0xFFFF;
+ break;
+
+ case 69: // Clear Network Statistics and refresh page
+ uip_init_stats();
+ current_webpage = WEBPAGE_STATS1;
+ pSocket->pData = g_HtmlPageStats1;
+ pSocket->nDataLeft = (uint16_t)(sizeof(g_HtmlPageStats1) - 1);
pSocket->nState = STATE_CONNECTED;
pSocket->nPrevBytes = 0xFFFF;
break;
-#endif // DEBUG_SUPPORT == 11 || DEBUG_SUPPORT == 15 || UIP_STATISTICS == 1
+#endif // UIP_STATISTICS
+
+#if DEBUG_SUPPORT == 11 || DEBUG_SUPPORT == 15
+ case 70: // Clear the "Reset Status Register" counters
+ // Clear the counts for EMCF, SWIMF, ILLOPF, IWDGF, WWDGF
+ // These only display via the UART
+ // Important:
+ // The debug[] byte indexes used may change if the
+ // number of debug bytes changes.
+ for (i = 25; i < 30; i++) debug[i] = 0;
+ update_debug_storage1();
+ break;
+#endif // DEBUG_SUPPORT
case 91: // Reboot
user_reboot_request = 1;
@@ -3468,7 +3255,7 @@ void HttpDCall(uint8_t* pBuffer, uint16_t nBytes, struct tHttpD* pSocket)
// pointer prevents "page interference" between normal browser
// activity and the automated functions that normally use this
// page.
- // current_webpage = WEBPAGE_SSTATE;
+ current_webpage = WEBPAGE_SSTATE;
pSocket->pData = g_HtmlPageSstate;
pSocket->nDataLeft = (uint16_t)(sizeof(g_HtmlPageSstate) - 1);
pSocket->nState = STATE_CONNECTED;
@@ -3595,581 +3382,533 @@ void HttpDCall(uint8_t* pBuffer, uint16_t nBytes, struct tHttpD* pSocket)
}
-void update_ON_OFF(uint8_t i, uint8_t j)
-{
- // Verify that pin is an output and it is enabled. If so
- // update the ON/OFF state. Otherwise the command is ignored.
- if ((pin_control[i] & 0x01) && (pin_control[i] & 0x02)) {
- Pending_pin_control[i] = pin_control[i];
- if (j==0) Pending_pin_control[i] &= (uint8_t)(~0x80);
- else Pending_pin_control[i] |= (uint8_t)0x80;
- parse_complete = 1;
- }
-}
-
-
-void clear_saved_postpartial_all(void)
-{
- int i;
- for (i=0; i<36; i++) saved_postpartial[i] = '\0';
-}
-
-
-void clear_saved_postpartial_data(void)
-{
- int i;
- for (i=4; i<36; i++) saved_postpartial[i] = '\0';
-}
-
-
-void clear_saved_postpartial_previous(void)
-{
- int i;
- for (i=0; i<36; i++) saved_postpartial_previous[i] = '\0';
-}
-
-
-void preload_alphas(void)
-{
- int i;
- for (i=0; i<32; i++) alpha[i] = '-';
-}
-
-
-void check_alphas(void)
-{
- int i;
- for (i=0; i<32; i++) {
- if (saved_postpartial_previous[i+4] != '\0') alpha[i] = saved_postpartial_previous[i+4];
- else break;
- }
-}
-
-
-void parse_POST_string(uint8_t** pBuffer, uint16_t * nBytes, struct tHttpD* pSocket, uint8_t num_chars)
+void parse_local_buf(struct tHttpD* pSocket, char* local_buf, uint16_t lbi_max)
{
- int i;
- uint8_t amp_found;
- uint8_t frag_flag;
- uint8_t resume;
- char tmp_Pending[20];
- // This function processes POST data for one of several string fields:
- // Device Name field
- // MQTT Username field
- // MQTT Password field
- //
- // The POST data for the string field is saved in Pending_tmp, and the
- // calling function must copy tmp_Pending to Pending_devicename,
- // Pending_mqtt_username, or Pending_mqtt_password as appropriate.
- //
- // ParseNum isn't used in the processing of this ParseCmd as a string field
- // is the only item assigned to the ParseCmd (for example there will be an
- // 'a00' but no 'a01').
- //
- // POST data for strings are a special case case in that the resulting
- // string can consist of anything from 0 to X number of characters. So, we
- // have to parse until the POST delimiter '&' is found.
- //
- amp_found = 0;
- //for (i=0; i<20; i++) tmp_Pending[i] = '\0';
- memset(tmp_Pending, '\0', 20);
+ uint16_t lbi; // Local buffer index
- if (saved_postpartial_previous[0] == pSocket->ParseCmd) {
- // Clear the saved_postpartial_prevous[0] byte (the ParseCmd byte) as it
- // should only get used once on processing a given TCP Fragment.
- saved_postpartial_previous[0] = '\0';
- // Since the ParseCmd matched the saved_postpartial_previous value we are
- // re-assembling a TCP Fragment that occurred during this command. The
- // ParseCmd and ParseNum values are already restored. We need to
- // determine where in this command the TCP Fragmentation break occurred
- // and continue from there.
- frag_flag = 1; // frag_flag is used to manage the TCP Fragment restore
- // process within this specific ParseCmd process.
- }
- else {
- frag_flag = 0;
- // We are not doing a TCP Fragment reassembly. Clear the data part of the
- // saved_postpartial values in case a TCP Fragment break occurs in this
- // parse.
- clear_saved_postpartial_data(); // Clear [4] and higher
- }
-
- // Notes on TCP Fragmentation
- // If we are recovering from fragmentation then the frag_flag will be 1.
- // If the string has zero length then we will enter this code with
- // saved_postpartial_previous[4] equal to '\0' and the next character
- // in the POST will be an &.
- // If the string has non-zero length but we didn't collect any characters
- // in the prior TCP Fragment then saved_postpartial_previous[4] will be
- // equal to '\0' but the next character in the POST will not be an &.
- // If the fragmentation occurred before the last character in the string
- // there will be at least one character in the saved_postpartial_previous[]
- // array and the next character in the POST will not be an &. We should
- // collect that/those character(s) then go to reading the POST. Note that
- // it is not possible to hit another fragment while finishing the
- // collection of a previously fragmented field.
- // If the last character in the string was collected in the previous TCP
- // Fragment but the & was not yet encountered then the & will be the first
- // character in the current packet.
-
- resume = 0;
- if (frag_flag == 1) {
- // Handle restoration of previously collected data, if any
- for (i = 0; i < num_chars; i++) {
- // First restore any data that was saved from the previous TCP
- // Fragment.
- // If the TCP Fragmentation occurred between the = and start of the
- // string data there won't be any stored data and we'll break out
- // of the for() loop with resume still equal zero.
- // If the TCP Fragmentation occurred between the = and & of a zero
- // length string there won't be any stored data and we'll break out
- // of the for() loop with resume still equal zero.
- if (saved_postpartial_previous[4+i] != '\0') {
- tmp_Pending[i] = saved_postpartial_previous[4+i];
- }
- else {
- resume = (uint8_t)i;
- break;
- }
+ // This function will parse a POST sent by the user (usually when they
+ // click on the "submit" button on a webpage). POST data will consist
+ // of:
+ // One digit with a ParseCmd
+ // Two digits with a ParseNum indicating the item to be changed
+ // One digit with an equal sign
+ // A variable number of characters with a ParseState indicating the
+ // new value of the item
+ // One digit with a Parse Delimiter (an '&')
+ //
+ // The parse pre-process has placed as much of the POST as possible
+ // in the local_buf. This routine will parse that data and will seek
+ // the end of the data as indicated by finding the &z00=0 POST
+ // component.
+
+ // When we parse the local_buf we always start in state PARSE_CMD
+ pSocket->ParseState = PARSE_CMD;
+
+ lbi = 0; // local buf index
+ while (1) {
+ // When appropriate conditions are met a break will occur to leave
+ // the while loop.
+ if (pSocket->ParseState == PARSE_CMD) {
+ pSocket->ParseCmd = (uint8_t)(local_buf[lbi]);
+ pSocket->ParseState = PARSE_NUM10;
+ pSocket->nParseLeft--;
+ lbi++;
+ }
+
+ else if (pSocket->ParseState == PARSE_NUM10) {
+ pSocket->ParseNum = (uint8_t)((local_buf[lbi] - '0') * 10);
+ pSocket->ParseState = PARSE_NUM1;
+ pSocket->nParseLeft--;
+ lbi++;
}
- if (**pBuffer == '&') {
- // Handle the case where all characters were collected in the last TCP
- // Fragment but the & was not seen. In this case the & is the first
- // character of this packet.
- amp_found = 1;
+
+ else if (pSocket->ParseState == PARSE_NUM1) {
+ pSocket->ParseNum += (uint8_t)(local_buf[lbi] - '0');
+ pSocket->ParseState = PARSE_EQUAL;
+ pSocket->nParseLeft--;
+ lbi++;
}
- }
+
+ else if (pSocket->ParseState == PARSE_EQUAL) {
+ pSocket->ParseState = PARSE_VAL;
+ pSocket->nParseLeft--;
+ lbi++;
+ }
+
+ else if (pSocket->ParseState == PARSE_VAL) {
+ // 'a' is POST data for the Device Name
+ // 'b' is POST data for the IP/Gateway/Netmask
+ // 'c' is POST data for the Port number
+ // 'd' is POST data for the MAC
+ // 'g' is POST data for the Config settings string
+ // 'h' is POST data for the Pin Control String
+ // 'i' is POST data for the IO Timers
+ // 'j' is POST data for the IO Names
+ // 'l' is POST data for the MQTT Username
+ // 'm' is POST data for the MQTT Password
+ // 'z' is POST data for a hidden input used as an end-of-POST
+ // indicator
+
+ // Parse 'a' 'l' 'm' 'j' ----------------------------------------------//
+ if (pSocket->ParseCmd == 'a'
+ || pSocket->ParseCmd == 'l'
+ || pSocket->ParseCmd == 'm'
+ || pSocket->ParseCmd == 'j' ) {
+ // a = Update the Device Name field
+ // l = Update the MQTT Username field
+ // m = Update the MQTT Password field
+ // j = Update the IO Name field
+
+ // If parsing 'a' 'l' 'm' 'j' we know we are parsing a Configuration
+ // page. Set current_webpage to WEBPAGE_CONFIGURATION so that the
+ // browser will display this page after Save is clicked. This is a
+ // workaround for the "multiple browser page interference" issue
+ // where another browser might have changed the current_webpage
+ // value.
+ current_webpage = WEBPAGE_CONFIGURATION;
- // If amp_found == 0 then there are characters to be collected from the
- // packet. The 'resume' variable will indicate where to resume inserting
- // these characters in tmp_Pending.
- // If no TCP Fragment occurred 'amp_found' and 'resume' will both equal zero
- // at this point.
- // If a TCP Fragment occurred between the = sign and the string data
- // 'amp_found' and 'resume' will both equal zero at this point.
-
- if (amp_found == 0) {
- for (i = resume; i < num_chars; i++) {
- // Collect characters until num_chars are collected or '&' is found in
- // uip_buf.
- if (amp_found == 0) {
- // Collect a byte of the devicename from the uip_buf until the '&' is
- // found.
- if (**pBuffer == '&') {
- // Set the amp_found flag and do not store this character in
- // devicename.
- amp_found = 1;
- }
- else {
- tmp_Pending[i] = **pBuffer;
- saved_postpartial[4+i] = **pBuffer;
- pSocket->nParseLeft--;
- saved_nparseleft = pSocket->nParseLeft;
- (*pBuffer)++;
- (*nBytes)--;
- if (*nBytes == 0) {
- // If nBytes == 0 we just read the last byte of POST data in the
- // uip_buf. The POST data will continue in the next TCP Fragment,
- // but we need to exit the for() and while() loops now.
- if (i == (num_chars - 1)) {
- // If i == (num_chars - 1) then we collected the maximum number of
- // characters without hitting '&' ... but we know '&' is next when
- // we return to process the next TCP Fragment, so we need to set
- // the saved parsestate accordingly.
- saved_parsestate = PARSE_DELIM;
+ {
+ int i;
+ uint8_t amp_found;
+ char tmp_Pending[20];
+ int num_chars;
+
+ num_chars = 0;
+
+ switch (pSocket->ParseCmd) {
+ case 'a': num_chars = 19; break;
+ case 'l':
+ case 'm': num_chars = 10; break;
+ case 'j': num_chars = 15; break;
+ }
+
+ // This function processes POST data for one of several string fields:
+ // Device Name field
+ // MQTT Username field
+ // MQTT Password field
+ // IO Name field
+ //
+ // POST data for strings are a special case case in that the resulting
+ // string can consist of anything from 0 to X number of characters. So, we
+ // have to parse until the POST delimiter '&' is found.
+ //
+ amp_found = 0;
+ memset(tmp_Pending, '\0', 20);
+
+ for (i = 0; i < num_chars; i++) {
+ // Collect characters until num_chars are collected or '&' is found.
+ if (amp_found == 0) {
+ // Collect a byte of the devicename from the local_buf until the '&' is
+ // found.
+ if (local_buf[lbi] == '&') amp_found = 1;
+ else {
+ tmp_Pending[i] = local_buf[lbi];
+ pSocket->nParseLeft--;
+ lbi++;
+ }
+ }
+ if (amp_found == 1) {
+ // We must reduce nParseLeft here because it is based on the PARESEBYTES_
+ // value which assumes num_chars bytes for the string field. If the
+ // POSTed string field is less than num_chars bytes then nParseLeft is
+ // too big by the number of characters omitted and must be corrected
+ // here. When we exit the loop the buffer index is left pointing at the
+ // '&' which starts the next field.
+ pSocket->nParseLeft--;
}
- break_while = 1;
- break; // This will break the for() loop. But we need to break the
- // while() loop on return from this function. So break_while
- // is set to 1.
}
+
+ switch (pSocket->ParseCmd)
+ {
+ case 'a':
+ memcpy(Pending_devicename, tmp_Pending, num_chars);
+ break;
+ case 'l':
+ memcpy(Pending_mqtt_username, tmp_Pending, num_chars);
+ break;
+ case 'm':
+ memcpy(Pending_mqtt_password, tmp_Pending, num_chars);
+ break;
+ case 'j':
+#if MQTT_SUPPORT == 0
+ unlock_flash();
+ if (strcmp(IO_NAME[pSocket->ParseNum], tmp_Pending) != 0) {
+ // The write to Flash will occur 4 bytes at a time to
+ // reduce Flash wear. All 16 bytes reserved in the Flash
+ // for a given IO Name will be written at one time in a
+ // sequence of 4 byte "word" writes.
+ i = 0;
+ while(i<16) {
+ FLASH_CR2 = 0x40;
+ FLASH_NCR2 = 0xBF;
+ memcpy(&IO_NAME[pSocket->ParseNum][i], &tmp_Pending[i], 4);
+ i += 4;
+ }
+ }
+ lock_flash();
+#endif // MQTT_SUPPORT
+ break;
+ }
}
}
- if (amp_found == 1) {
- // We need to null any remaining characters in the tmp_Pending string
- // up to num_chars in case we are shortening the string.
- tmp_Pending[i] = '\0';
- // We must reduce nParseLeft here because it is based on the PARESEBYTES_
- // value which assumes num_chars bytes for the string field. If the
- // POSTed string field is less than num_chars bytes then nParseLeft is
- // too big by the number of characters omitted and must be corrected
- // here. Note that nBytes is not decremented and the pBuffer pointer is
- // not advanced because nothing is read from the buffer. When we exit the
- // loop the buffer pointer is left pointing at the '&' which starts the
- // next field.
- pSocket->nParseLeft--;
- }
- }
- }
-
- // Always execute the following code before returning from the function.
- //
- // When the function was called the tmp_Pending value was filled with '\0'
- // so we know the new string is terminated with '\0'.
- //
- // If we read the entire string field we departed the for() loop with the
- // pointers still pointing at the '&', which is what all the other steps
- // in the POST read do.
- //
- // If we didn't find the '&' due to TCP fragmentation our saved pointers
- // will bring us back to this function to finish collecting the string
- // with the next TCP Fragment.
-
- // If break_while is not set we did not hit a TCP Fragement point and we
- // no longer need the saved_postpartial values. Clear them to prevent
- // interference with subsequent restores.
- if (break_while == 0) clear_saved_postpartial_all();
-
- // Update the Device Name field
- if (pSocket->ParseCmd == 'a') {
- for (i=0; iParseCmd == 'l') {
- for (i=0; iParseCmd == 'm') {
- for (i=0; iParseCmd == 'b') {
+ // This code updates the "pending" IP address, Gateway address,
+ // Netmask, and MQTT Host IP address which will then cause the
+ // main.c functions to restart the software.
+ // The value following the 'bxx=' ParseCmd and ParseNum consists
+ // of eight alpha nibbles representing the value in hex. The
+ // function call collects the alpha nibbles and converts them to
+ // the numeric value used by the other firmware functions.
+ {
+ int i;
+ int j;
+ uint8_t temp;
+
+ // The following updates the IP address, Gateway address, NetMask, and MQTT
+ // IP Address based on GUI input.
+ // The code converts eight alpha fields with hex alphas ('0' to 'f') into
+ // 4 octets representing the new setting.
+
+ // Convert characters of the hex string to numbers two characters
+ // at a time and store the result.
+ temp = 0;
+ i = 0;
+ j = 0;
+ while (i < 8) {
+ // Create a number from two hex characters
+ temp = two_hex2int(local_buf[lbi], local_buf[lbi+1]);
+ lbi +=2;
+ pSocket->nParseLeft -= 2;
+ i += 2;
+
+ j = (8 - i) / 2;
+
+ switch(pSocket->ParseNum)
+ {
+ case 0: Pending_hostaddr[j] = (uint8_t)temp; break;
+ case 4: Pending_draddr[j] = (uint8_t)temp; break;
+ case 8: Pending_netmask[j] = (uint8_t)temp; break;
+ case 12: Pending_mqttserveraddr[j] = (uint8_t)temp; break;
+ default: break;
+ }
+ }
+ }
+ }
-void parse_POST_address(uint8_t** pBuffer, uint16_t * nBytes, struct tHttpD* pSocket)
-{
- int i;
-
- preload_alphas();
-
- if (saved_postpartial_previous[0] == pSocket->ParseCmd) {
- // Clear the saved_postpartial_prevous[0] byte (the ParseCmd byte) as it
- // should only get used once on processing a given TCP Fragment.
- saved_postpartial_previous[0] = '\0';
- // We are re-assembling a fragment that occurred during this command. The
- // ParseCmd and ParseNum values are already restored. We need to determine
- // where in this command the fragmentation break occurred and continue
- // from there.
- //
- // Check for alphas found in prior TCP Fragment
- check_alphas();
- }
- else {
- // We are not doing a reassembly. Clear the data part of the
- // saved_postpartial values in case a fragment break occurs during this
- // parse.
- clear_saved_postpartial_data(); // Clear [4] and higher
- }
+ // Parse 'c' ------------------------------------------------------//
+ else if (pSocket->ParseCmd == 'c') {
+ // This code updates the "pending" HTTP Port number or MQTT Port
+ // number which will then cause the main.c functions to restart
+ // the software.
+ // ParseNum == 0 indicates the HTTP Port number.
+ // ParseNum == 1 indicates the MQTT Port number.
+ // The value following the 'cxx=' ParseCmd & ParseNum consists
+ // of four alpha nibbles with the port number in hex form. The
+ // function call collects the nibbles, validates them, and updates
+ // the pending port number.
+ {
+ int i;
+ uint16_t temp;
+
+ // Code to update the Port number based on GUI input.
+ // The code converts four alpha fields with hex alphas ('0' to 'f')
+ // into a 16 bit number, and validates that the number is within the
+ // valid range.
+
+ // Convert string to 16 bit integer
+ temp = 0;
+ for (i=0; i<4; i++) {
+ temp |= hex2int((uint8_t)local_buf[lbi]) << (12 - i*4);
+ lbi++;
+ pSocket->nParseLeft--;
+ }
- for (i=0; i<8; i++) {
- // Examine each 'alpha' character to see if it was already found
- // in a prior TCP Fragment. If not collect it now.
- // If collecting characters from the POST break the while() loop
- // if a TCP Fragment boundary is found unless the character
- // collected is the last 'alpha'.
- if (alpha[i] == '-') {
- alpha[i] = (uint8_t)(**pBuffer);
- saved_postpartial[i+4] = (uint8_t)(**pBuffer);
- pSocket->nParseLeft--;
- saved_nparseleft = pSocket->nParseLeft;
- (*pBuffer)++;
- (*nBytes)--;
- if (i != 7 && *nBytes == 0) {
- break_while = 1; // Hit end of fragment but still have characters to
- // collect in the next packet. Set break_while to 1
- // so that we'll break out of the while() loop on
- // return from this function.
- break; // Break out of for() loop.
+ if (temp > 9) { // Make change only if valid entry
+ if (pSocket->ParseNum == 0) Pending_port = (uint16_t)temp;
+ else Pending_mqttport = (uint16_t)temp;
+ }
+ }
}
- }
- }
- if (break_while == 1) { // Hit end of fragment. Break out of while() loop.
- return;
- }
- // If we get this far we no longer need the saved_postpartial values and
- // must clear them to prevent interference with subsequent restores.
- clear_saved_postpartial_all();
- {
- // The following updates the IP address, Gateway address, NetMask, and MQTT
- // IP Address based on GUI input.
- // The code converts eight alpha fields with hex alphas ('0' to 'f') into
- // 4 octets representing the new setting.
- uint16_t temp;
- int invalid;
- int j;
-
- invalid = 0;
- j = 0;
-
- // Validate each character in the string as a hex character
- for (i=0; i<8; i++) {
- if (!(isxdigit(alpha[i]))) invalid = 1;
- }
-
- if (invalid == 0) { // Make change only if valid entry
- // Convert characters of the hex string to numbers two characters
- // at a time and store the result.
- temp = 0;
- i = 0;
- while (i < 8) {
- // Create a number from two hex characters
- temp = hex2int(alpha[i]);
- temp = temp<<4;
- i++;
- temp = temp | hex2int(alpha[i]);
- i++;
-
- // if (i == 2) j = 3;
- // if (i == 4) j = 2;
- // if (i == 6) j = 1;
- // if (i == 8) j = 0;
- j = (8 - i) / 2;
-
- switch(pSocket->ParseNum)
+ // Parse 'd' ------------------------------------------------------//
+ else if (pSocket->ParseCmd == 'd') {
+ // This code updates the "pending" MAC address which will then
+ // cause the main.c functions to restart the software.
+ // The value following the 'dxx=' ParseCmd and ParseNum consists
+ // of twelve alpha nibbles in hex form ('0' to '9' and 'a' to 'f').
+ // The function call collects the nibbles, validates them, and
+ // updates the pending MAC number.
{
- case 0: Pending_hostaddr[j] = (uint8_t)temp; break;
- case 4: Pending_draddr[j] = (uint8_t)temp; break;
- case 8: Pending_netmask[j] = (uint8_t)temp; break;
- case 12: Pending_mqttserveraddr[j] = (uint8_t)temp; break;
- default: break;
+ int i;
+ uint16_t temp;
+
+ // Code to update the MAC number based on GUI input.
+ // The code converts twelve alpha fields with hex alphas ('0' to 'f')
+ // into 6 octets representing the new setting.
+
+ // Convert characters of the hex string to numbers two
+ // at a time and store the result.
+ i = 0;
+ while (i < 12) {
+ temp = 0;
+ // Create a number from two hex characters
+ temp = two_hex2int(local_buf[lbi], local_buf[lbi+1]);
+ lbi +=2;
+ pSocket->nParseLeft -= 2;
+ i += 2;
+ // Store result in Pending_uip_ethaddr_oct. Note that order is
+ // reversed in this variable.
+ Pending_uip_ethaddr_oct[ (12-i)/2 ] = (uint8_t)temp;
+ }
}
}
- }
- }
- if (*nBytes == 0) {
- // Hit end of fragment. Break out of while() loop. The first character
- // of the next packet will be '&' so we need to set PARSE_DELIM.
- break_while = 2; // Hit end of fragment. Set break_while to 2 so that
- // we'll break out of the while() loop on return from
- // this function AND go to the PARSE_DELIM state.
- }
- return;
-}
+ // Parse 'g' ------------------------------------------------------//
+ else if (pSocket->ParseCmd == 'g') {
+ {
+ // This code sets the Config Settings bytes which define the
+ // DS18B20, MQTT, Full/Half Duplex, and Home Assistant Auto
+ // Discovery functionality.
+ //
+ // There are always 2 characters in the string which represent a
+ // hex encoded byte. Each is collected and saved for later
+ // processing.
+ //
+ // Convert hex nibbles to a byte and store in Config settings
+ Pending_config_settings = two_hex2int(local_buf[lbi], local_buf[lbi+1]);
+ lbi +=2;
+ pSocket->nParseLeft -= 2;
+ }
+ }
-void parse_POST_port(uint8_t** pBuffer, uint16_t * nBytes, struct tHttpD* pSocket)
-{
- int i;
- preload_alphas();
+ // Parse 'h' ------------------------------------------------------//
+ else if (pSocket->ParseCmd == 'h') {
+ // This code sets the Pending_pin_control bytes based on the
+ // information in the 32 character string sent in the h00 field.
+ //
+ // There are always 32 characters in the string in 16 pairs of
+ // hex encoded nibbles, each pair representing a hex encoded pin
+ // control byte. The character pairs are extracted one set at a
+ // time, converted to a numeric byte, and stored in their
+ // corresponding Pending_pin_control byte.
+ {
+ int i;
+ int j;
+ uint8_t k;
+
+ // Sort the alpha characters into the pin control bytes
+ i = 0;
+ j = 0;
+ while( i<32 ) {
+ // The Configuration page updates all bits except the
+ // ON/OFF bit
+ // The IOControl page only updates the ON/OFF bit
+ Pending_pin_control[j] = pin_control[j];
+ // Convert the pin control string into numeric bytes
+ // two characters at a time. "k" will contain the byte
+ // after conversion.
+ k = two_hex2int(local_buf[lbi], local_buf[lbi+1]);
+ lbi +=2;
+ pSocket->nParseLeft -= 2;
+ i += 2;
+
+ if (current_webpage == WEBPAGE_CONFIGURATION) {
+ // Keep the ON/OFF bit as-is
+ Pending_pin_control[j] = (uint8_t)(Pending_pin_control[j] & 0x80);
+ // Mask out the ON/OFF bit in the temp variable
+ k = (uint8_t)(k & 0x7f);
+ }
+ else {
+ // current_webpage is WEBPAGE_IOCONTROL
+ // Keep the configuration bits as-is
+ Pending_pin_control[j] = (uint8_t)(Pending_pin_control[j] & 0x7f);
+ // Mask out the configuration bits in the temp variable
+ k = (uint8_t)(k & 0x80);
+ }
+ // "OR" in the changed bits
+ Pending_pin_control[j] = (uint8_t)(Pending_pin_control[j] | k);
+ j++;
+ }
+ }
+ }
- if (saved_postpartial_previous[0] == pSocket->ParseCmd) {
- // Clear the saved_postpartial_prevous[0] byte (the ParseCmd byte) as it
- // should only get used once on processing a given TCP Fragment.
- saved_postpartial_previous[0] = '\0';
- // We are re-assembling a fragment that occurred during this command. The
- // ParseCmd and ParseNum values are already restored. We need to determine
- // where in this command the fragmentation break occurred and continue
- // from there.
- //
- // Check for alphas found in prior TCP Fragment
- check_alphas();
- }
- else {
- // We are not doing a reassembly. Clear the data part of the
- // saved_postpartial values in case a fragment break occurs during this
- // parse.
- clear_saved_postpartial_data(); // Clear [4] and higher
- }
- {
- int i;
- for (i=0; i<4; i++) {
- // Examine each 'alpha' character to see if it was already found
- // in a prior TCP Fragment. If not collect it now.
- // If collecting characters from the POST break the while() loop
- // if a TCP Fragment boundary is found unless the character
- // collected is the last 'alpha'.
- if (alpha[i] == '-') {
- alpha[i] = (uint8_t)(**pBuffer);
- saved_postpartial[i+4] = **pBuffer;
- pSocket->nParseLeft--;
- saved_nparseleft = pSocket->nParseLeft;
- (*pBuffer)++;
- (*nBytes)--;
- if (i != 3 && *nBytes == 0) {
- break_while = 1; // Hit end of fragment but still have characters to
- // collect in the next packet. Set break_while to 1
- // so that we'll break out of the while() loop on
- // return from this function.
- break; // Break out of for() loop.
+#if MQTT_SUPPORT == 0
+ // Parse 'i' ------------------------------------------------------//
+ else if (pSocket->ParseCmd == 'i') {
+ // This code updates the IO Timer units and values in Flash.
+ // The value following the 'ixx=' ParseCmd & ParseNum consists of
+ // 2 bytes represented as hex encoded strings (4 nibbles).
+ // Upper 2 bits are units
+ // Lower 14 bits are value
+ // The bytes are converted from the hex encoded string to a 16
+ // bit integer for storage in Flash.
+ {
+ uint16_t temp;
+
+ // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+ // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+ // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+ // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+ // Need to replace this with a Word write to reduce wear
+ // on the Flash.
+ // This may require storing all received IO Timer values in
+ // RAM (requires 32 bytes) then checking them for changes
+ // before writing to Flash in the main.c "parse complete"
+ // code.
+ // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+ // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+ // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+ // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+
+ // Sort the alpha characters into the IO Timer bytes
+ // Collect upper byte
+ // Convert two bytes of the string buffer into numeric bytes
+ // two characters at a time.
+ temp = (uint8_t)(two_hex2int(local_buf[lbi], local_buf[lbi+1]));
+ temp = (temp << 8);
+ lbi += 2;
+ pSocket->nParseLeft -= 2;
+ // Collect lower byte
+ temp |= (uint8_t)(two_hex2int(local_buf[lbi], local_buf[lbi+1]));
+ lbi += 2;
+ pSocket->nParseLeft -= 2;
+ // Store in Pending_IO_TIMER array
+ Pending_IO_TIMER[pSocket->ParseNum] = temp;
}
}
+#endif // MQTT_SUPPORT
+
+
+ // Parse 'z' ------------------------------------------------------//
+ else if (pSocket->ParseCmd == 'z') {
+ // This code signals that the "hidden" post was received. This
+ // is an indicaor that the entire POST was received.
+ //
+ // There is no '&' delimiter after this POST value.
+ //
+ pSocket->nParseLeft = 0;
+ break; // Break out of the while loop. We're done with POST.
+ }
+
+ // If we got to this point one of the "if/else if" above should have
+ // executed leaving the pointers pointing at the "&" delimiter in
+ // the POST data as the next character to be processed. So we set
+ // the ParseState to PARSE_DELM and let the while() do its next pass.
+ //
+ pSocket->ParseState = PARSE_DELIM;
}
- if (break_while == 1) { // Hit end of fragment. Break out of while() loop.
- return;
- }
- }
-
- // If we get this far we no longer need the saved_postpartial values and
- // must clear them to prevent interference with subsequent restores.
- clear_saved_postpartial_all();
-
- {
- // Code to update the Port number based on GUI input.
- // The code converts four alpha fields with hex alphas ('0' to 'f')
- // into a 16 bit number, and validates that the number is within the
- // valid range.
- uint16_t temp;
- uint16_t nibble;
- int invalid;
- invalid = 0;
-
- // Validate each character in the string as a hex character
- for (i=0; i<4; i++) {
- if (!(isxdigit(alpha[i]))) invalid = 1;
+
+ else if (pSocket->ParseState == PARSE_DELIM) {
+ if ((pSocket->nParseLeft > 0) && (lbi < lbi_max)) {
+ // Parse the next character, which must be a '&' delimiter. From
+ // here we go parse the next command byte.
+ pSocket->ParseState = PARSE_CMD;
+ pSocket->nParseLeft--;
+ lbi++;
+ }
+ else if ((pSocket->nParseLeft > 0) && (lbi >= lbi_max)) {
+ // We hit the end of the data in the local_buf but there is still
+ // more POST data. Break out of the while(1) loop so we'll return
+ // to collect more data from the uip_buf.
+ break; // Exit parsing
+ }
+ else {
+ // If we came to PARSE_DELIM and there was nothing left to parse
+ // in this or any subsequent packet (the normal exit state for
+ // POST data) then we just make sure nParseLeft is zero (not
+ // negative) and go on to exit.
+ pSocket->nParseLeft = 0; // End the parsing
+ break; // Exit parsing
+ }
}
+ } // end of "while(1)" loop
+
+ // If nParseLeft == 0 we should enter STATE_SENDHEADER204, but we
+ // clean up the fragment tracking pointers first.
+ //
+ // If nParseLeft is > 0 we haven't received the whole POST yet. In that
+ // case we should not enter STATE_SENDHEADER204 until we finish
+ // receiving and parsing the whole POST.
+ //
+ // We also do not want the main.c loop to do any processing of the
+ // Pending values collected so far until we've completed collecting ALL
+ // POST data. We can tell we still have processing to do because:
+ // saved_nparseleft != 0.
+ // I will use a global "parse_complete" variable to pass the state to
+ // the main.c functions.
+ //
- // Convert string to integer
- temp = 0;
- nibble = 0;
- for (i=0; i<4; i++) {
- // nibble = hex2int(alpha[i]);
- // if (i == 0) nibble = nibble<<12;
- // if (i == 1) nibble = nibble<<8;
- // if (i == 2) nibble = nibble<<4;
- // temp = temp | nibble;
- temp |= hex2int(alpha[i]) << (12 - i*4);
- }
+ if (pSocket->nParseLeft == 0) {
+ // Finished parsing
+ // Clear the saved states
+ saved_nstate = STATE_NULL;
+ saved_nparseleft = 0;
+ saved_newlines = 0;
+
+ // Signal the main.c processes that parsing is complete
+ parse_complete = 1;
+ pSocket->nState = STATE_SENDHEADER204;
+
+ // Patch: ON CHROME ONLY: When 'Save' is clicked after changing from
+ // the IOControl page to the Configuration page for some reason no
+ // Configuration page refresh occurs. At one time the wrong page
+ // would display, but that does not seem to happen anymore. The next
+ // steps are a workaround to get Chrome to behave better. I am not
+ // sure why this happens as the 'if (uip_connected()' steps at the
+ // start of this function call should have already done this. Note
+ // that if the page change is done, then the 'Refresh' button is
+ // clicked, then the 'Save' button is clicked this problem does not
+ // appear. This problem was not seen with FireFox, Edge, or IE.
- if (invalid == 0) { // Next step of validation
- // Validate that the value is in the range 10 to 65535. Since we
- // already verified that the incoming characters were valid hex
- // characters we only need to verify that the number is not less
- // than 10.
- if (temp < 10) invalid = 1;
+ if (current_webpage == WEBPAGE_IOCONTROL) {
+ pSocket->pData = g_HtmlPageIOControl;
+ pSocket->nDataLeft = (uint16_t)(sizeof(g_HtmlPageIOControl) - 1);
}
-
- if (invalid == 0) { // Make change only if valid entry
- if (pSocket->ParseNum == 0) Pending_port = (uint16_t)temp;
- else Pending_mqttport = (uint16_t)temp;
+ if (current_webpage == WEBPAGE_CONFIGURATION) {
+ pSocket->pData = g_HtmlPageConfiguration;
+ pSocket->nDataLeft = (uint16_t)(sizeof(g_HtmlPageConfiguration) - 1);
}
}
- if (*nBytes == 0) {
- // Hit end of fragment. Break out of while() loop. The first character
- // of the next packet will be '&' so we need to set PARSE_DELIM.
- break_while = 2; // Hit end of fragment. Set break_while to 2 so that
- // we'll break out of the while() loop on return from
- // this function AND go to the PARSE_DELIM state.
+ else {
+ // Else nParseLeft > 0 so we are still waiting on the remote host to
+ // send more POST data. This should arrive in subsequent packets. The
+ // remote host is not expecting a CLOSE connection until we are done
+ // receiving all POST data. The CLOSE will happen as part of the
+ // STATE_SENDHEADER204 process.
+ //
+ // Note on TCP Fragment reassembly: When the MSS is smaller than the
+ // size of the packets that the remote host wants to send it will
+ // simply send multiple packets of size MSS or smaller. We are
+ // entirely dependent on nParseLeft to determine when to go to
+ // STATE_SEND_HEADER, and we must assume that any additional fragments
+ // that are sent after we get all the POST data are disposed of by the
+ // UIP code. FYI, there shouldn't be any TCP Fragments after
+ // nParseLeft = 0.
+ //
+ uip_len = 0;
}
- return;
}
-void parse_POST_MAC(uint8_t** pBuffer, uint16_t * nBytes, struct tHttpD* pSocket)
+void update_ON_OFF(uint8_t i, uint8_t j)
{
- int i;
-
- preload_alphas();
-
- if (saved_postpartial_previous[0] == pSocket->ParseCmd) {
- // Clear the saved_postpartial_prevous[0] byte (the ParseCmd byte) as it
- // should only get used once on processing a given TCP Fragment.
- saved_postpartial_previous[0] = '\0';
- // We are re-assembling a fragment that occurred during this command. The
- // ParseCmd and ParseNum values are already restored. We need to determine
- // where in this command the fragmentation break occurred and continue
- // from there.
- //
- // Check for alphas found in prior TCP Fragment
- check_alphas();
- }
- else {
- // We are not doing a reassembly. Clear the data part of the
- // saved_postpartial values in case a fragment break occurs during this
- // parse.
- clear_saved_postpartial_data(); // Clear [4] and higher
- }
-
- {
- int i;
- for (i=0; i<12; i++) {
- // Examine each 'alpha' character to see if it was already found
- // in a prior TCP Fragment. If not collect it now.
- // If collecting characters from the POST break the while() loop
- // if a TCP Fragment boundary is found unless the character
- // collected is the last 'alpha'.
- if (alpha[i] == '-') {
- alpha[i] = (uint8_t)(**pBuffer);
- saved_postpartial[i+4] = **pBuffer;
- pSocket->nParseLeft--;
- saved_nparseleft = pSocket->nParseLeft;
- (*pBuffer)++;
- (*nBytes)--;
- if (i != 11 && *nBytes == 0) {
- break_while = 1; // Hit end of fragment but still have characters to
- // collect in the next packet. Set break_while to 1
- // so that we'll break out of the while() loop on
- // return from this function.
- break; // Break out of for() loop.
- }
- }
- }
- if (break_while == 1) { // Hit end of fragment. Break out of while() loop.
- return;
- }
- }
-
- // If we get this far we no longer need the saved_postpartial values and
- // must clear them to prevent interference with subsequent restores.
- clear_saved_postpartial_all();
-
- {
- // Code to update the MAC number based on GUI input.
- // The code converts twelve alpha fields with hex alphas ('0' to 'f')
- // into 6 octets representing the new setting.
- uint16_t temp;
- int invalid;
- invalid = 0;
-
- // Validate each character in the string as a hex character
- for (i=0; i<12; i++) {
- if (!(isxdigit(alpha[i]))) invalid = 1;
- }
-
- if (invalid == 0) { // Make change only if valid entry
- // Convert characters of the hex string to numbers two
- // at a time and store the result.
- i = 0;
- while (i < 12) {
- temp = 0;
- // Create a number from two hex characters
- temp = hex2int(alpha[i]);
- temp = temp<<4;
- i++;
- temp = temp | hex2int(alpha[i]);
- i++;
-
- // switch(i) {
- // case 2: Pending_uip_ethaddr_oct[5] = (uint8_t)temp; break;
- // case 4: Pending_uip_ethaddr_oct[4] = (uint8_t)temp; break;
- // case 6: Pending_uip_ethaddr_oct[3] = (uint8_t)temp; break;
- // case 8: Pending_uip_ethaddr_oct[2] = (uint8_t)temp; break;
- // case 10: Pending_uip_ethaddr_oct[1] = (uint8_t)temp; break;
- // case 12: Pending_uip_ethaddr_oct[0] = (uint8_t)temp; break;
- // default: break;
- // }
- // Store result in Pending_uip_ethaddr_oct. Note that order is
- // reversed in this variable.
- Pending_uip_ethaddr_oct[ (12-i)/2 ] = (uint8_t)temp;
- }
- }
- }
-
- if (*nBytes == 0) {
- // Hit end of fragment. Break out of while() loop. The first character
- // of the next packet will be '&' so we need to set PARSE_DELIM.
- break_while = 2; // Hit end of fragment. Set break_while to 2 so that
- // we'll break out of the while() loop on return from
- // this function AND go to the PARSE_DELIM state.
+ // Verify that pin is an output and it is enabled. If so
+ // update the ON/OFF state. Otherwise the command is ignored.
+ if ((pin_control[i] & 0x01) && (pin_control[i] & 0x02)) {
+ Pending_pin_control[i] = pin_control[i];
+ if (j==0) Pending_pin_control[i] &= (uint8_t)(~0x80);
+ else Pending_pin_control[i] |= (uint8_t)0x80;
+ parse_complete = 1;
}
- return;
}
diff --git a/NetworkModule/httpd.h b/NetworkModule/httpd.h
index 4938e5a..ca1aecb 100644
--- a/NetworkModule/httpd.h
+++ b/NetworkModule/httpd.h
@@ -55,8 +55,7 @@ struct tHttpD
const uint8_t* pData;
uint16_t nDataLeft;
uint8_t nNewlines;
- uint8_t nParseLeft;
- uint8_t nParseLeftAddl;
+ uint16_t nParseLeft;
uint8_t ParseCmd;
uint8_t ParseNum;
uint8_t ParseState;
@@ -67,36 +66,20 @@ struct tHttpD
uint16_t adjust_template_size(void);
static uint16_t CopyStringP(uint8_t** ppBuffer, const char* pString);
-// static uint16_t CopyHttpHeader(uint8_t* pBuffer, uint16_t nDataLen, uint8_t type);
static uint16_t CopyHttpHeader(uint8_t* pBuffer, uint16_t nDataLen);
static uint16_t CopyHttpData(uint8_t* pBuffer, const char** ppData, uint16_t* pDataLeft, uint16_t nMaxBytes);
+char *show_temperature_string(char * pBuffer, uint8_t nParsedNum);
void emb_itoa(uint32_t num, char* str, uint8_t base, uint8_t pad);
int hex2int(char ch);
+uint8_t two_hex2int(char chmsb, char chlsb);
void int2hex(uint8_t i);
void HttpDInit(void);
void HttpDCall(uint8_t* pBuffer, uint16_t nBytes, struct tHttpD* pSocket);
-// void parse_POST_string(uint8_t curr_ParseCmd, int num_chars);
-void parse_POST_string(uint8_t** pBuffer, uint16_t * nBytes, struct tHttpD* pSocket, uint8_t num_chars);
-// void parse_POST_address(uint8_t curr_ParseCmd, uint8_t curr_ParseNum);
-void parse_POST_address(uint8_t** pBuffer, uint16_t * nBytes, struct tHttpD* pSocket);
-// void parse_POST_port(uint8_t curr_ParseCmd, uint8_t curr_ParseNum);
-void parse_POST_port(uint8_t** pBuffer, uint16_t * nBytes, struct tHttpD* pSocket);
-// void parse_POST_MAC(uint8_t curr_ParseCmd);
-void parse_POST_MAC(uint8_t** pBuffer, uint16_t * nBytes, struct tHttpD* pSocket);
-
+void parse_local_buf(struct tHttpD* pSocket, char* local_buf, uint16_t lbi_max);
void encode_16bit_registers(void);
void update_pin_control_bytes(void);
-
-uint8_t GpioGetPin(uint8_t nGpio);
-void GpioSetPin(uint8_t nGpio, uint8_t nState);
void update_ON_OFF(uint8_t i, uint8_t j);
-void clear_saved_postpartial_all(void);
-void clear_saved_postpartial_data(void);
-void clear_saved_postpartial_previous(void);
-void preload_alphas(void);
-void check_alphas(void);
-
#endif /*HTTPD_H_*/
diff --git a/NetworkModule/main.h b/NetworkModule/main.h
index 9383c13..7776f4a 100644
--- a/NetworkModule/main.h
+++ b/NetworkModule/main.h
@@ -34,6 +34,8 @@ int main(void);
void init_IWDG(void);
void unlock_eeprom(void);
void lock_eeprom(void);
+void unlock_flash(void);
+void lock_flash(void);
void upgrade_EEPROM(void);
void check_eeprom_settings(void);
void check_eeprom_IOpin_settings(void);
@@ -55,6 +57,9 @@ void capture_uip_buf_transmit(void);
void capture_uip_buf_receive(void);
void capture_mqtt_sendbuf(void);
+// void load_timer(uint8_t timer_num);
+uint32_t calculate_timer(uint16_t timer_value);
+void decrement_pin_timers(void);
void mqtt_startup(void);
void mqtt_sanity_check(void);
@@ -105,7 +110,6 @@ int8_t reverse_bit_order(uint8_t k);
#define RESTART_REBOOT_IDLE 0
#define RESTART_REBOOT_ARM 1
#define RESTART_REBOOT_ARM2 2
-// #define RESTART_REBOOT_DELETE_PIN_LOOP 3
#define RESTART_REBOOT_SENDOFFLINE 4
#define RESTART_REBOOT_DISCONNECT 5
#define RESTART_REBOOT_TCPCLOSE 6
diff --git a/NetworkModule/mqtt.c b/NetworkModule/mqtt.c
index 97c7f61..c515464 100644
--- a/NetworkModule/mqtt.c
+++ b/NetworkModule/mqtt.c
@@ -49,18 +49,21 @@ SOFTWARE.
#include "uart.h"
#include "uipopt.h"
+#if MQTT_SUPPORT == 1
+
extern uint32_t second_counter;
extern uint16_t uip_slen;
-uint8_t MQTT_error_status; // Global so GUI can show error status indicator
+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 mqtt_sendbuf[140]; // Buffer to contain MQTT transmit queue
- // and data. Restrict to 200 bytes if
- // debug is enabled.
-extern uint8_t mqtt_start; // Tracks the MQTT startup steps
+uint8_t mqtt_sendbuf[140]; // Buffer to contain MQTT transmit queue
+ // and data. Restrict to 200 bytes if
+ // debug is enabled.
+extern uint8_t mqtt_start; // Tracks the MQTT startup steps
#if DEBUG_SUPPORT != 0
@@ -353,19 +356,6 @@ int16_t __mqtt_send(struct mqtt_client *client)
// loop through all messages in the queue
len = mqtt_mq_length(&client->mq);
-
- // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
- // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
- // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
- // The following is a debug statement designed to show how many messages
- // are held in the mqtt transmit queue. Initial experiments showed that
- // the queue regularly held up to 3 messages, but never 4 or more.
-// if (len > 3) oneflash();
- // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
- // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
- // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
-
-
for(; i < len; ++i) {
struct mqtt_queued_message *msg = mqtt_mq_get(&client->mq, i);
int16_t resend = 0;
@@ -443,10 +433,13 @@ int16_t __mqtt_send(struct mqtt_client *client)
// check for keep-alive
{
- uint32_t keep_alive_timeout = client->time_of_last_send + (uint32_t)((float)(client->keep_alive) * 0.75);
+ // At about 3/4 of the timeout period perform a ping. This calculation
+ // uses integer arithmatic 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);
-// UARTPrintf("queued ping request\r\n");
if (rv != MQTT_OK) {
client->error = rv;
return rv;
@@ -467,12 +460,15 @@ int16_t __mqtt_recv(struct mqtt_client *client)
// Read the input buffer and check for errors
- // The original MQTT code used the mqtt_pal_recvall() function to move
+ // 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 has already been performed, so the
- // mqtt_pal_recvall() function only returns the length of the data.
- rv = mqtt_pal_recvall(client->recv_buffer.curr, client->recv_buffer.curr_sz);
-
+ // 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;
@@ -484,25 +480,6 @@ int16_t __mqtt_recv(struct mqtt_client *client)
return consumed;
}
-/*
- else if (consumed == 0) {
- // if curr_sz is 0 then the buffer is too small to ever fit the message
- // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
- // I DON'T THINK THIS CODE IS APPLICABLE TO THIS APPLICATION AS ALL
- // MESSAGES ARE VERY SHORT AND EASILY FIT IN THE UIP_BUF WHICH IS
- // BEING USED AS THE RECEIVE BUFFER. WE DON'T QUEUE RECEIVE
- // MESSAGES, AGAIN MAKING AN EASY FIT.
- // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
- if (client->recv_buffer.curr_sz == 0) {
- client->error = MQTT_ERROR_RECV_BUFFER_TOO_SMALL;
- return MQTT_ERROR_RECV_BUFFER_TOO_SMALL;
- }
-
- // just need to wait for the rest of the data
- return MQTT_OK;
- }
-*/
-
// response was unpacked successfully
// The switch statement below manages how the client responds to messages
@@ -600,57 +577,26 @@ int16_t __mqtt_recv(struct mqtt_client *client)
}
{
- // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
- // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
- // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
- // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
// 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.
+ // 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 this code "cleans the buffer" by moving any
+ // 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.
//
- // I need to understand this better and perhaps eliminate or simplify
- // the "cleanup".
- //
- // I'm trying to maintain a notion that only one receive message makes
- // it into this process and is completely consumed and (perhaps) a
- // transmit message queued before any new message can be received. 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 - likely AFTER
- // transmit processing is completed.
-
- // we've handled the response, now clean the buffer
- // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
- // SINCE WE ONLY RECEIVE ON MQTT MESSAGE AT A TIME IN THIS APPLICATION
- // THERE SHOULD BE NO NEED TO "CLEAN" THE RECEIVE BUFFER. SHOULD BE
- // ABLE TO JUST RESET THE POINTERS TO THE START OF THE BUFFER AS IN
- // THE INITIALIZATION CODE.
- // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
-// void* dest = (unsigned char*)client->recv_buffer.mem_start;
-// void* src = (unsigned char*)client->recv_buffer.mem_start + consumed;
-// uint16_t n = client->recv_buffer.curr - client->recv_buffer.mem_start - consumed;
-// memmove(dest, src, n);
-// client->recv_buffer.curr -= consumed;
-// client->recv_buffer.curr_sz += consumed;
-
- // Reset receive pointers to start of buffer. Note: We only receive
- // one message at a time in this application. There is no receive
- // queue as in the original mqtt.c code.
- // Note, since recvbuf and recvbufsz are not global variables we need
- // to use the structure member copy here
- // client->recv_buffer.curr = recvbuf;
- // client->recv_buffer.curr_sz = recvbufsz;
+ // 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
+ // In case there was some error handling the (well formed) message, we end
+ // up here
return mqtt_recv_ret;
}
@@ -1301,3 +1247,4 @@ int16_t __mqtt_pack_str(uint8_t *buf, const char* str)
return length + 2;
}
+#endif // MQTT_SUPPORT
diff --git a/NetworkModule/mqtt_pal.c b/NetworkModule/mqtt_pal.c
index b4b197c..dc8126e 100644
--- a/NetworkModule/mqtt_pal.c
+++ b/NetworkModule/mqtt_pal.c
@@ -78,8 +78,7 @@ char *stpcpy(char * dest, const char * src)
return --dest;
}
-// Implements mqtt_pal_sendall and mqtt_pal_recvall and any platform-specific
-// helpers you'd like.
+// Implements mqtt_pal_sendall
// The original LiamBindle code included socket based ethernet interfaces to
// a Linux-or-Apple like OS, OR to a Microsoft like OS. In this application
@@ -520,25 +519,3 @@ int16_t mqtt_pal_sendall(const void* buf, uint16_t len) {
// UIP code uses the uip_slen value.
}
-
-int16_t mqtt_pal_recvall(void* buf, uint16_t bufsz) {
- // This function will check if there is any data in the receive buffer and
- // report the size of that data to the MQTT calling process.
- // The return value is the number of bytes received
- // There is only one call to this process. It is in the mqtt.c file.
- //
- // Receive data should already be in the uip_buf or we wouldn't have been
- // called. But probably a good idea to verify that something is there. We
- // only need to reply with the size of the data received. Start of the
- // application data is at the uip_appdata pointer, and the MQTT client
- // already knows this because it was given the "uip_appdata" pointer in the
- // init process. The size of the application data is the value uip_len.
-
- int16_t rv;
- rv = -1; // Default to return an error if no data present
- if (uip_len > 0) { // Indicates data is present
- rv = uip_len; // Return the size of the data. Data begins at pointer
- // uip_appdata.
- }
- return rv;
-}
diff --git a/NetworkModule/mqtt_pal.h b/NetworkModule/mqtt_pal.h
index 7a9736a..5b77ec6 100644
--- a/NetworkModule/mqtt_pal.h
+++ b/NetworkModule/mqtt_pal.h
@@ -47,34 +47,6 @@ SOFTWARE.
*/
-/**
- * Includes/supports the types/calls required by the MQTT-C client.
- *
- * This is the only file included in mqtt.h, and mqtt.c. It is therefore
- * responsible for including/supporting all the required types and calls.
- *
- * Platform abstraction layer
- * Documentation of the types and calls required to port MQTT-C to a new platform.
- *
- * mqtt_pal.h is the only header file included in mqtt.c. Therefore, to port MQTT-C to a
- * new platform the following types, functions, constants, and macros must be defined in
- * mqtt_pal.h:
- * - Types:
- * - int8_t, int16_t, int32_t
- * - uint8_t, uint16_t, uint32_t
- * - Functions:
- * - memcpy, strlen
- * - Constants:
- * - INT_MIN
- *
- * Additionally, these macro's are required:
- * - HTONS(s) : host-to-network endian conversion for uint16_t.
- *
- * Lastly, mqtt_pal_sendall and mqtt_pal_recvall, must be implemented in mqtt_pal.c
- * for sending and receiving data.
- */
-
-
#include
#include
#include
@@ -86,12 +58,6 @@ SOFTWARE.
int16_t mqtt_pal_sendall(const void* buf, uint16_t len);
-// Non-blocking receive all the byte available.
-// buf - A pointer to the receive buffer.
-// bufsz - The max number of bytes that can be put into buf.
-// returns - The number of bytes received if successful, an MQTTErrors otherwise.
-int16_t mqtt_pal_recvall(void* buf, uint16_t bufsz);
-
char *stpcpy(char * dest, const char * src);
diff --git a/NetworkModule/uip.c b/NetworkModule/uip.c
index 3d5432b..21b19fe 100644
--- a/NetworkModule/uip.c
+++ b/NetworkModule/uip.c
@@ -116,7 +116,7 @@
// Variables used to store debug information
extern uint8_t *pBuffer2;
extern uint8_t debug[NUM_DEBUG_BYTES];
-#endif // DEBUG_SUPPORT != 0
+#endif // DEBUG_SUPPORT
/* The IP address of this host */
@@ -216,12 +216,12 @@ static uint16_t tmp16;
#define FBUF ((struct uip_tcpip_hdr *)&uip_reassbuf[0])
#define ICMPBUF ((struct uip_icmpip_hdr *)&uip_buf[UIP_LLH_LEN])
-#if UIP_STATISTICS == 1
+#if UIP_STATISTICS == 1 && MQTT_SUPPORT == 0
struct uip_stats uip_stat;
#define UIP_STAT(s) s
#else
#define UIP_STAT(s)
-#endif // UIP_STATISTICS == 1
+#endif // UIP_STATISTICS
#if ! UIP_ARCH_ADD32
void uip_add32(uint8_t *op32, uint16_t op16)
@@ -337,10 +337,10 @@ void uip_init(void)
for (c = 0; c < UIP_CONNS; ++c) uip_conns[c].tcpstateflags = UIP_CLOSED;
/* IPv4 initialization. */
-#if UIP_STATISTICS == 1
+#if UIP_STATISTICS == 1 && MQTT_SUPPORT == 0
// Initialize statistics
uip_init_stats();
-#endif // UIP_STATISTICS == 1
+#endif // UIP_STATISTICS
}
@@ -398,7 +398,7 @@ uip_connect(uip_ipaddr_t *ripaddr, uint16_t rport, uint16_t lport)
//---------------------------------------------------------------------------//
void uip_init_stats(void)
{
-#if UIP_STATISTICS == 1
+#if UIP_STATISTICS == 1 && MQTT_SUPPORT == 0
// Initialize statistics
uip_stat.ip.drop = 0;
uip_stat.ip.recv = 0;
@@ -422,7 +422,7 @@ void uip_init_stats(void)
uip_stat.tcp.rexmit = 0;
uip_stat.tcp.syndrop = 0;
uip_stat.tcp.synrst = 0;
-#endif // UIP_STATISTICS == 1
+#endif // UIP_STATISTICS
}
diff --git a/NetworkModule/uip_TcpAppHub.c b/NetworkModule/uip_TcpAppHub.c
index f33d98e..0107c6f 100644
--- a/NetworkModule/uip_TcpAppHub.c
+++ b/NetworkModule/uip_TcpAppHub.c
@@ -53,12 +53,16 @@
#include "uip.h"
#include "main.h"
#include "mqtt.h"
+#include "uipopt.h"
extern uint16_t Port_Httpd;
extern uint16_t Port_Mqttd;
+
+#if MQTT_SUPPORT == 1
extern struct mqtt_client mqttclient; // Pointer to MQTT client declared in main.c
extern uint8_t mqtt_start;
extern uint8_t mqtt_close_tcp;
+#endif // MQTT_SUPPORT
void uip_TcpAppHubCall(void)
// We get here via UIP_APPCALL in the uip.c code
@@ -74,6 +78,7 @@ void uip_TcpAppHubCall(void)
HttpDCall(uip_appdata, uip_datalen(), &uip_conn->appstate.HttpDSocket);
}
+#if MQTT_SUPPORT == 1
else if(uip_conn->lport == htons(Port_Mqttd)) {
// This code is called if incoming traffic is MQTT. mqtt_sync will read
// the incoming data (if any) from the uip_buf, then create any needed
@@ -91,4 +96,5 @@ void uip_TcpAppHubCall(void)
if (mqtt_close_tcp == 1) uip_close();
}
}
+#endif // MQTT_SUPPORT
}
diff --git a/NetworkModule/uipopt.h b/NetworkModule/uipopt.h
index 3363948..797b468 100644
--- a/NetworkModule/uipopt.h
+++ b/NetworkModule/uipopt.h
@@ -196,10 +196,12 @@
//---------------------------------------------------------------------------//
// Application specific compile controls
//
-// Controls whether the options for code compile. For instance:
+// Controls the options for code compile. For instance:
// - Controls inclusion of the Network Statistics web page
// - Controls inclusion of Debug support
// - Controls inclusion of the Independent Watchdog
+// - Controls inclusion of MQTT functionality
+// - Controls "Browser Only" build type
// UIP_STATISTICS
@@ -207,9 +209,12 @@
// Statistics are useful for debugging Network related problems. If you are
// modifying the project and need more program space eliminating the Network
// Statistics pages and processes will free up considerable space.
+// Note that Network Statistics will not fit in the memory when an MQTT build
+// is created. It will only fit if a Browser Only build is created. So,
+// MQTT_SUPPORT = 1 will override this setting and force it to disabled.
// 0 = disabled
// 1 = included
-#define UIP_STATISTICS 0
+#define UIP_STATISTICS 1
// DEBUG_SUPPORT
@@ -265,7 +270,6 @@
#define DEBUG_SUPPORT 11
-
// IWDG_ENABLE
// Determines if the Independent Watchdog is to be enabled
// For production code this should me enabled. It turns on the IWDG to cause a
@@ -279,6 +283,14 @@
#define IWDG_ENABLE 1
+// MQTT_SUPPORT
+// Determines if MQTT Support and Home Assistant Support is to be compiled
+// into the build.
+// 0 = Browser Only Support
+// 1 = MQTT Support
+#define MQTT_SUPPORT 1
+
+
//---------------------------------------------------------------------------//
/**
* Appication specific configurations
diff --git a/README.md b/README.md
index 0d8789c..0cf25f1 100644
--- a/README.md
+++ b/README.md
@@ -5,29 +5,41 @@ Did you buy one (or more) of these Network Modules and then find disappointment
- In the original from-the-factory firmware all of the modules have the same MAC address. That's a problem if you want more than one module on your network. And the supplier does not give you a way to change the MAC.
- If you change the IP Address the device returns to its default IP Address when it power cycles. That makes it pretty much useless even if you only put one on your network - unless you're OK with it always having IP Address 192.168.1.4.
-I was disappointed enough that I decided to reprogram the device to provide a web server interface that let's you change the IP Address, Gateway (Default Router) Address, Netmask, Port number (a REAL port number), and MAC Address. I also added the ability for the device to remember all these settings through a power cycle. Any Relay settings you make are also saved through a power cycle. In addition the Network Module can be operated as a generic MQTT device or as a Home Assistant device with Auto Discovery.
+I was disappointed enough that I decided to reprogram the device to provide a web server interface that let's you change the IP Address, Gateway (Default Router) Address, Netmask, Port number (a REAL port number), and MAC Address. I also added the ability for the device to remember all these settings through a power cycle. Any Relay settings you make are also optionally saved through a power cycle. In addition the Network Module can be operated as a generic MQTT device or as a Home Assistant device with Auto Discovery.
Short summary of release history:
-June 13, 2020 - A simple Browser Only interface was developed with the primary focus being retention of all user settings through reboot and power cycles. The release only supported 16 output pins This release was last updated in August 6, 2020 and was retired at that time but is still available in a zip file named "20200806_retired_release.zip".
+June 13, 2020 - A simple Browser Only GUI supporting 16 output pins with retention of all user settings through reboot and power cycles.
-August 13, 2020 - Added the ability to support 16 outputs, OR 8 outputs / 8 inputs, OR 16 inputs in three separate builds. Over time MQTT was added to the code, resulting in a 4th separate build of 8 outputs / 8 inputs supporting MQTT, and by December the code also supported Home Assistant with a crude form of Home Assistant Auto Discovery. The last update to this build occurred on December 30, 2020. It has now been retired, but it is still available in a zip file named "20201230_0411_retired".
+August 13, 2020 - Added support for 16 outputs, OR 8 outputs / 8 inputs, OR 16 inputs in three separate builds, plus an MQTT build with 8 outputs / 8 inputs, plus support for Home Assistant.
-January 23, 2021 - Latest release series. Provides a much improved Browser interface with the ability to define each pin as an Input or Output, each pin has its own Invert checkbox, and each pin can be individually set to power up as ON, OFF, or with its state prior to a power loss. As a result there is now only 1 pre-built firmware to handle all pinout configurations and MQTT (no longer need 4 separate builds!). In addition the Home Assistant interface is greatly improved with automatic reconfiguration of pin controls in Home Assistant when a user changes the Network Module configuration in its Browser.
+January 23, 2021 - A much improved Browser interface with the ability to define input/output pins individually. As a result there was no longer a need to have separate builds for the various configurations. Auto Discovery was added to the Home Assistant interface.
February 8, 2021 - Added an interface for up to 5 DS18B20 temperature sensors.
February 20, 2021 - Added a UART debug interface for use by developers. Beginning with this release you should obtain Source Code and Executables from the "Release" area of the GitHub page (along the right margin of the page).
-Help is avaialble via a link in the Configuration page that will take you to the GitHub Wiki page. The Network Statistics page was removed from the firmware due to lack of memory. A smaller Link Error Statustics page is available for use in diagnosing Half / Full Duplex issues (see the manual).
+April 7, 2021 - Released a parallel build for "Browser Only" users that does not include MQTT, but adds some requested features for users that do not want MQTT. The "Browser Only" version includes individual IO Names, IO Timers, and restores the Network Statistics page.
-Current users that upgrade to the new release will find that their Device Name, IP Address, Port Numbers, and MAC address entries are retained. However, since pins are now individually assigned, the pinout settings will have to be re-entered in the Configuration page. Note that firmware downgrade is not supported in an automated way. Check the Network Module Manual for downgrade instructions.
+Feature Comparison of the MQTT and Browser builds:
+Feature MQTT Build Browser Only Build
+MQTT Support x
+Home Assistant Support x
+Full/Half Duplex x x
+Link Error Statistics x x
+DS18B20 Temp Sensor x x
+IO Naming x
+IO Timers x
+Network Statistics x
-All functionality is described in detail in the "Network Module Manual". I suggest you take a look.
+
+Help is avaialble via a link in the Configuration page that will take you to the GitHub Wiki page. All functionality is described in detail in the "Network Module Manual". I suggest you take a look.
+
+If you upgrade from a pre-January 2021 version you will find that your Device Name, IP Address, Port Numbers, and MAC address entries are retained. However, since pins are now individually assigned your pinout settings will have to be re-entered in the Configuration page. Note that firmware downgrade is not supported in an automated way. Check the Network Module Manual for downgrade instructions.
Videos: I have not updated the YouTube videos yet. The "Network Module Manual" illustrates all the differences and the programming steps are the same, so the videos will be updated over the next few weeks. See the video links in the Wiki.
-Many thanks to Carlos Ladeira and Jevgeni Kiski for their many hours of work in the January 2021 release. Their collaboration with me greatly improved the code for everyone.
+Many thanks to Carlos Ladeira and Jevgeni Kiski for their many hours of work in the 2021 releases. Their collaboration with me greatly improved the code for everyone.
Tested with:
- Windows 10 Firefox 84.0.2 (64-bit)