diff --git a/.vscode/settings.json b/.vscode/settings.json index a06ac45..45b4a6e 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -17,6 +17,7 @@ "debug.h": "c", "systick.h": "c", "timer.h": "c", - "stdint.h": "c" + "stdint.h": "c", + "mqtt_interface.h": "c" } } \ No newline at end of file diff --git a/include/config.h b/include/config.h index 2d4625f..318cd51 100644 --- a/include/config.h +++ b/include/config.h @@ -12,7 +12,7 @@ // MQTT configuration #define CLIENT_ID "ch32_node" -#define MQTT_TARGET_IP {192, 168, 102, 147} +#define MQTT_TARGET_IP {192, 168, 102, 100} #define MQTT_TARGET_PORT 1883 #define MQTT_KEEP_ALIVE_INTERVAL 60 diff --git a/include/dhcp.h b/include/dhcp.h new file mode 100644 index 0000000..68d0f99 --- /dev/null +++ b/include/dhcp.h @@ -0,0 +1,19 @@ +#ifndef DHCP_H +#define DHCP_H + +#include + +typedef enum { + DHCP_STATE_INIT, + DHCP_STATE_DISCOVER, + DHCP_STATE_REQUEST, + DHCP_STATE_LEASED, + DHCP_STATE_RENEW, + DHCP_STATE_RELEASE +} dhcp_state_t; + +void dhcp_init(void); +void dhcp_process(void); +uint8_t dhcp_get_state(void); + +#endif diff --git a/include/systick.h b/include/systick.h index 0f4e55c..bfcfe82 100644 --- a/include/systick.h +++ b/include/systick.h @@ -8,9 +8,8 @@ (uint32_t)(FUNCONF_SYSTEM_CORE_CLOCK / TIMER_DELAY) #define millis() (systick_millis) +// ms counter incremented by SysTick +extern volatile uint32_t systick_millis; void init_systick(void); -// ms counter incremented by SysTick -// extern volatile uint32_t systick_millis; - #endif // SYSTICK_H diff --git a/include/w5500.h b/include/w5500.h index 02a01c3..9f6d344 100644 --- a/include/w5500.h +++ b/include/w5500.h @@ -24,13 +24,16 @@ void handle_ip_assigned(void); // Initializes the W5500 chip void configure_network(void); -void configure_dhcp(void); +// void configure_dhcp(void); +void dhcp_init(void); +void dhcp_process(void); // resolves a domain name void resolve_domain_name(const char* domain_name); // init and connect the MQTT client -MQTTClient setup_mqtt_client(Network* network, ch32_mqtt_options_t* opts); +int setup_mqtt_client(Network* network, ch32_mqtt_options_t* opts, + MQTTClient* client); int subscribe_to_topic(MQTTClient* client, const char* topic, enum QoS qos, messageHandler message_callback); diff --git a/lib/ioLibrary_Driver/DHCP/dhcp.c b/lib/ioLibrary_Driver/DHCP/dhcp.c index 741cc06..1a2d9cd 100644 --- a/lib/ioLibrary_Driver/DHCP/dhcp.c +++ b/lib/ioLibrary_Driver/DHCP/dhcp.c @@ -974,10 +974,7 @@ void DHCP_init(uint8_t s, uint8_t * buf) /* Reset the DHCP timeout count and retry count. */ void reset_DHCP_timeout(void) { -#ifdef _DHCP_DEBUG_ - printf("> reset_DHCP_timeout !!!\r\n"); -#endif - // dhcp_tick_1s = 0; + dhcp_tick_1s = 0; dhcp_tick_next = DHCP_WAIT_TIME; dhcp_retry_count = 0; } diff --git a/src/dhcp.c b/src/dhcp.c new file mode 100644 index 0000000..2a93fb5 --- /dev/null +++ b/src/dhcp.c @@ -0,0 +1,105 @@ +#include "dhcp.h" + +#include +#include + +#include "debug.h" +#include "systick.h" +#include "w5500.h" + +static volatile dhcp_state_t dhcp_state = DHCP_STATE_INIT; +static volatile uint32_t dhcp_lease_time = 0; +static volatile uint32_t dhcp_last_time = 0; +static volatile uint32_t dhcp_retry_count = 0; +static uint32_t last_check_time = 0; + +// Buffers +static uint8_t dhcp_buffer[512]; +static wiz_NetInfo current_net_info = { + .mac = {0xEA, 0x11, 0x22, 0x33, 0x44, 0xEA}, .dhcp = NETINFO_DHCP}; + +static void update_network_config(void) { + wizchip_setnetinfo(¤t_net_info); + DEBUG_PRINT("IP config: %d.%d.%d.%d\n", current_net_info.ip[0], + current_net_info.ip[1], current_net_info.ip[2], + current_net_info.ip[3]); +} + +void callback_ip_assigned(void) { + dhcp_lease_time = getDHCPLeasetime(); + DEBUG_PRINT("IP newly assigned! Lease time: %lu sec\n", dhcp_lease_time); + + getIPfromDHCP(current_net_info.ip); + getGWfromDHCP(current_net_info.gw); + getSNfromDHCP(current_net_info.sn); + getDNSfromDHCP(current_net_info.dns); + + dhcp_state = DHCP_STATE_LEASED; +} + +void callback_ip_updated(void) { + dhcp_lease_time = getDHCPLeasetime(); + DEBUG_PRINT("IP lease updated! New lease time: %lu sec\n", dhcp_lease_time); + + getIPfromDHCP(current_net_info.ip); + getGWfromDHCP(current_net_info.gw); + getSNfromDHCP(current_net_info.sn); + getDNSfromDHCP(current_net_info.dns); + + dhcp_state = DHCP_STATE_LEASED; +} + +void callback_ip_conflict(void) { + DEBUG_PRINT("IP conflict!\n"); + dhcp_state = DHCP_STATE_INIT; + dhcp_retry_count = 0; +} + +void dhcp_init(void) { + setSHAR(current_net_info.mac); + DHCP_init(DHCP_SOCKET, dhcp_buffer); + reg_dhcp_cbfunc(callback_ip_assigned, callback_ip_updated, + callback_ip_conflict); + dhcp_state = DHCP_STATE_INIT; + dhcp_retry_count = 0; +} + +void dhcp_process(void) { + uint32_t current_time = millis(); + + // 500ms processing + if ((current_time - last_check_time) >= 500) { + last_check_time = current_time; + + switch (dhcp_state) { + case DHCP_STATE_INIT: + DHCP_run(); + if (dhcp_state == DHCP_STATE_LEASED) { + update_network_config(); + } + break; + + case DHCP_STATE_LEASED: + // renew @ 50% of lease time + if (current_time - dhcp_last_time >= (dhcp_lease_time * 500)) { + dhcp_state = DHCP_STATE_RENEW; + DHCP_run(); + } + break; + + case DHCP_STATE_RENEW: + DHCP_run(); + if (dhcp_state == DHCP_STATE_LEASED) { + update_network_config(); + dhcp_last_time = current_time; + } + break; + + default: + DHCP_run(); + break; + } + } +} + +uint8_t dhcp_get_state(void) { return dhcp_state; } \ No newline at end of file diff --git a/src/main.c b/src/main.c index 1a15447..aed7c6c 100644 --- a/src/main.c +++ b/src/main.c @@ -2,6 +2,7 @@ #include "ch32v003fun.h" #include "debug.h" +#include "dhcp.h" #include "gpio.h" #include "socket.h" #include "spi_dma.h" @@ -10,20 +11,35 @@ #include "uart.h" #include "w5500.h" -void init_system(void) { - SystemInit(); +#define MQTT_RECONNECT_INTERVAL 5000 +#define MQTT_YIELD_INTERVAL 100 +#define W5500_INIT_DELAY_MS 55 +#define DHCP_TIMEOUT_MS 15000 - init_gpio(); - init_systick(); - tim2_init(); +typedef struct { + Network network; + MQTTClient client; + ch32_mqtt_options_t opts; + uint32_t last_reconnect; + uint32_t last_yield; + uint8_t is_connected; +} mqtt_state_t; - init_uart(UART_BRR_APB1); - init_spidma(); +// init MQTT state +void mqtt_init(mqtt_state_t* state, char* client_id) { + // TODO + state->opts.clientid = client_id; + state->opts.username = ""; + state->opts.password = ""; + state->opts.qos = QOS0; + state->last_reconnect = 0; + state->last_yield = 0; + state->is_connected = 0; } // cb fn for when a message is received void message_arrived(MessageData* md) { - if (md == NULL || md->message == NULL) { + if (!md || !md->message) { DEBUG_PRINT("Error: MessageData is NULL.\n"); return; } @@ -47,57 +63,90 @@ void message_arrived(MessageData* md) { } } -// void print_bin(uint32_t value) { -// for (int i = 31; i >= 0; i--) { -// DEBUG_PRINT("%d", (value >> i) & 1); -// if (i % 4 == 0) printf(" "); -// } -// DEBUG_PRINT("\n"); -// } +// mqtt reconnect +// TODO: setup will, publish discovery messages, setup subs +void mqtt_process(mqtt_state_t* state) { + uint32_t now = millis(); + int rc; + + if (!state->is_connected) { + if (now - state->last_reconnect >= MQTT_RECONNECT_INTERVAL) { + DEBUG_PRINT("Attempting MQTT connection...\n"); + + rc = setup_mqtt_client(&state->network, &state->opts, &state->client); + if (rc == 0) { + DEBUG_PRINT("MQTT connected\n"); + state->is_connected = 1; + + rc = subscribe_to_topic(&state->client, SUB_TOPIC, QOS0, + message_arrived); + if (rc != 0) { + DEBUG_PRINT("Subscribe failed: %d\n", rc); + state->is_connected = 0; + } else { + publish_message(&state->client, "Device connected", PUB_TOPIC); + } + } + state->last_reconnect = now; + } + } else if (now - state->last_yield >= MQTT_YIELD_INTERVAL) { + rc = MQTTYield(&state->client, 100); + if (rc != 0) { + DEBUG_PRINT("Yield failed: %d\n", rc); + state->is_connected = 0; + } + state->last_yield = now; + } +} + +void init_system(void) { + SystemInit(); + + init_gpio(); + init_systick(); + tim2_init(); + + init_uart(UART_BRR_APB1); + init_spidma(); +} + +// Wait for DHCP lease +static int wait_for_dhcp(void) { + uint32_t start = millis(); + while (dhcp_get_state() != DHCP_STATE_LEASED) { + if (millis() - start >= DHCP_TIMEOUT_MS) { + DEBUG_PRINT("DHCP timeout\n"); + return 0; + } + dhcp_process(); + } + return 1; +} int main(void) { init_system(); - Delay_Ms(55); + Delay_Ms(W5500_INIT_DELAY_MS); - // uint32_t intsyscr = __get_INTSYSCR(); - // DEBUG_PRINT("INTSYSCR:\n"); - // DEBUG_PRINT("hex: 0x%08X\n", intsyscr); - // DEBUG_PRINT("bin: "); - // print_binary(intsyscr); - - // DEBUG_PRINT("init_system() done\n"); + // Configure network and DHCP configure_network(); + dhcp_init(); - // TODO: enabling any kind of SysTick IRQ literally causes the socket to hang - // forever with 1ms interval the hang is on DHCP_ACK, on check_DHCP_leasedIP - // -> sendto() ARP req with 100ms it happens somewhere on DNS req - - // systick irq enable here would complete the DHCP configuration and hang on - // DNS.. init_systick(); - - configure_dhcp(); - resolve_domain_name("example.com"); - - Network network; - ch32_mqtt_options_t opts = {CLIENT_ID, "", "", QOS0}; - - // Set up MQTT client - MQTTClient client = setup_mqtt_client(&network, &opts); - subscribe_to_topic(&client, SUB_TOPIC, QOS0, message_arrived); - - // Publish a message - publish_message(&client, "hi", PUB_TOPIC); - - while (1) { - // if ((millis() - dhcp_last_invocation) >= DHCP_INTERVAL) { - // dhcp_last_invocation = millis(); - // DHCP_run(); - // } - MQTTYield(&client, 1000); // keepalive + if (!wait_for_dhcp()) { + while (1) { + // todo: handle err + } } - MQTTDisconnect(&client); - close(TCP_SOCKET); + resolve_domain_name("example.com"); + + // mqtt + mqtt_state_t mqtt; + mqtt_init(&mqtt, CLIENT_ID); + + while (1) { + dhcp_process(); + mqtt_process(&mqtt); + } return 0; -} +} \ No newline at end of file diff --git a/src/systick.c b/src/systick.c index ef5ca07..cd21ade 100644 --- a/src/systick.c +++ b/src/systick.c @@ -1,11 +1,11 @@ #include "systick.h" +#include "MQTT/mqtt_interface.h" #include "ch32v003fun.h" #include "debug.h" // ms counter volatile uint32_t systick_millis = 0; -// volatile int toggle_state = 0; void init_systick(void) { SysTick->CTLR = 0; @@ -42,4 +42,5 @@ void SysTick_Handler(void) { // clear irq SysTick->SR = 0; systick_millis++; -} \ No newline at end of file + MilliTimer_Handler(); +} diff --git a/src/w5500.c b/src/w5500.c index 4b0b727..ea7b501 100644 --- a/src/w5500.c +++ b/src/w5500.c @@ -11,46 +11,10 @@ #include "config.h" #include "debug.h" #include "spi_dma.h" +#include "systick.h" -volatile uint32_t count = 0; -volatile int ip_assigned = 0; - -// Global buffers for DHCP and DNS -static uint8_t dhcp_buffer[512]; static uint8_t dns_buffer[512]; -// Function to handle IP assignment details -void handle_ip_assigned(void) { - DEBUG_PRINT("IP Assigned!\n"); - - wiz_NetInfo net_info; - getIPfromDHCP(net_info.ip); - getGWfromDHCP(net_info.gw); - getSNfromDHCP(net_info.sn); - - uint8_t dns[4]; - getDNSfromDHCP(dns); - - DEBUG_PRINT( - "IP: %d.%d.%d.%d\nGW: %d.%d.%d.%d\nNet: %d.%d.%d.%d\nDNS: " - "%d.%d.%d.%d\n", - net_info.ip[0], net_info.ip[1], net_info.ip[2], net_info.ip[3], - net_info.gw[0], net_info.gw[1], net_info.gw[2], net_info.gw[3], - net_info.sn[0], net_info.sn[1], net_info.sn[2], net_info.sn[3], dns[0], - dns[1], dns[2], dns[3]); - - wizchip_setnetinfo(&net_info); -} - -// Callback functions -void callback_ip_assigned(void) { - DEBUG_PRINT("Callback: IP assigned! Leased time: %lu sec\n", - getDHCPLeasetime()); - ip_assigned = 1; -} - -void callback_ip_conflict(void) { DEBUG_PRINT("Callback: IP conflict!\n"); } - void configure_network(void) { DEBUG_PRINT("===\n"); DEBUG_PRINT("Starting network configuration...\n"); @@ -65,36 +29,7 @@ void configure_network(void) { wizchip_init(rx_tx_buff_sizes, rx_tx_buff_sizes); } -void configure_dhcp(void) { - wiz_NetInfo net_info = {.mac = {0xEA, 0x11, 0x22, 0x33, 0x44, 0xEA}, - .dhcp = NETINFO_DHCP}; - setSHAR(net_info.mac); - DHCP_init(DHCP_SOCKET, dhcp_buffer); - - // Register DHCP callbacks - reg_dhcp_cbfunc(callback_ip_assigned, callback_ip_assigned, - callback_ip_conflict); - - // Attempt to acquire an IP address using DHCP - // retry - uint8_t retries = 0; - - while (!ip_assigned && retries < 30) { - DHCP_run(); - // Delay_Ms(100); - DEBUG_PRINT("DHCP_run()...\n"); - retries++; - } - - if (!ip_assigned) { - DEBUG_PRINT("\r\nIP was not assigned\r\n"); - return; - } - - handle_ip_assigned(); -} - -// todo: rm +// todo: rm !!! void resolve_domain_name(const char* domain_name) { DEBUG_PRINT("Resolving domain name \"%s\"...\n", domain_name); @@ -119,21 +54,23 @@ void resolve_domain_name(const char* domain_name) { } } -MQTTClient setup_mqtt_client(Network* network, ch32_mqtt_options_t* opts) { +int setup_mqtt_client(Network* network, ch32_mqtt_options_t* opts, + MQTTClient* client) { static unsigned char tx_buffer[MQTT_TX_BUFFER_SIZE]; static unsigned char rx_buffer[MQTT_RX_BUFFER_SIZE]; - MQTTClient client; int rc; uint8_t target_ip[] = MQTT_TARGET_IP; + // Initialize network NewNetwork(network, TCP_SOCKET); - if (ConnectNetwork(network, target_ip, MQTT_TARGET_PORT) != SOCK_OK) { - DEBUG_PRINT("Network connection failed.\n"); - return (MQTTClient){0}; // Return an empty client on failure + rc = ConnectNetwork(network, target_ip, MQTT_TARGET_PORT); + if (rc != SOCK_OK) { + DEBUG_PRINT("Network connection failed: %d\n", rc); + return -1; } // Initialize the MQTT client - MQTTClientInit(&client, network, MQTT_COMMAND_TIMEOUT_MS, tx_buffer, + MQTTClientInit(client, network, MQTT_COMMAND_TIMEOUT_MS, tx_buffer, sizeof(tx_buffer), rx_buffer, sizeof(rx_buffer)); // Setup MQTT connection data @@ -147,13 +84,13 @@ MQTTClient setup_mqtt_client(Network* network, ch32_mqtt_options_t* opts) { connect_data.cleansession = 1; // Connect to MQTT broker - rc = MQTTConnect(&client, &connect_data); + rc = MQTTConnect(client, &connect_data); if (rc != 0) { DEBUG_PRINT("Failed to connect: %d\n", rc); - return (MQTTClient){0}; // Return an empty client on failure + return -2; } - return client; + return 0; } int subscribe_to_topic(MQTTClient* client, const char* topic, enum QoS qos, @@ -163,7 +100,7 @@ int subscribe_to_topic(MQTTClient* client, const char* topic, enum QoS qos, DEBUG_PRINT("Failed to subscribe to %s: %d\n", topic, rc); return rc; } - return 0; // Success + return 0; } void publish_message(MQTTClient* client, const char* payload,