Wiznet makers

Aimee0

Published January 02, 2024 ©

17 UCC

10 WCC

8 VAR

0 Contests

0 Followers

0 Following

Original Link

COAP messages on W5500 built for Nucleo-L476RG

This project is a project to send and receive COAP messages using W5500 over Nucleo-L476RG.

COMPONENTS Hardware components

WIZnet - W5500

x 1


PROJECT DESCRIPTION

This project is to send and receive COAP messages using W5500 over Nucleo-L476RG.

What is COAP

COAP is a lightweight protocol designed primarily to support efficient communication between IoT devices and devices with limited resources, such as various sensors.

COAP vs MQTT

 

COAP

MQTT

PurposeIt is primarily designed for communication between constrained devices.It is primarily designed for communication between many devices.
Protocol formatDesigned based on the RESTful architecture, it has a request and response form similar to HTTP.It is a message-driven protocol that exchanges messages between brokers and clients.
CommunicationIt uses a request-response model, in which the client sends the request and the server responds.It is based on the Publish-Subscribe model, where devices can subscribe to specific topics to receive messages or publish messages to specific topics.
Reliability and Connection ManagementPrimarily uses UDP, offering optional extensions for reliability. It is an unconnected protocol because it is UDP based.Primarily uses TCP, providing reliable connections and message delivery. 

Project Description

OS : mbed-OS

mbed-coap library : https://github.com/ARMmbed/mbed-os/tree/master/connectivity/libraries/mbed-coap

W5500 interface : https://os.mbed.com/users/sgnezdov/code/W5500Interface/#41393623ead4

 

#main.cpp

......

int main() {
    printf("Easy connect...\n");
    NetworkInterface *network = easy_connect(true);
    if (!network) {
        printf("Cannot connect to the network, see serial output");
        return 1;
    }

    printf("Connected to the network. Opening a socket...\n");

    // Open a socket on the network interface
    socket.open(network);

    // Initialize the CoAP protocol handle, pointing to local implementations on malloc/free/tx/rx functions
    coapHandle = sn_coap_protocol_init(&coap_malloc, &coap_free, &coap_tx_cb, &coap_rx_cb);

    // UDPSocket::recvfrom is blocking, so run it in a separate RTOS thread
    recvfromThread.start(&recvfromMain);

    // Path to the resource we want to retrieve
    const char* coap_uri_path = "/test";

    // See ns_coap_header.h
    sn_coap_hdr_s *coap_res_ptr = (sn_coap_hdr_s*)calloc(sizeof(sn_coap_hdr_s), 1);
    coap_res_ptr->uri_path_ptr = (uint8_t*)coap_uri_path;       // Path
    coap_res_ptr->uri_path_len = strlen(coap_uri_path);
    coap_res_ptr->msg_code = COAP_MSG_CODE_REQUEST_GET;         // CoAP method
    coap_res_ptr->content_format = COAP_CT_TEXT_PLAIN;          // CoAP content type
    coap_res_ptr->payload_len = 0;                              // Body length
    coap_res_ptr->payload_ptr = 0;                              // Body pointer
    coap_res_ptr->options_list_ptr = 0;                         // Optional: options list
    // Message ID is used to track request->response patterns, because we're using UDP (so everything is unconfirmed).
    // See the receive code to verify that we get the same message ID back
    coap_res_ptr->msg_id = 7;

    // Calculate the CoAP message size, allocate the memory and build the message
    uint16_t message_len = sn_coap_builder_calc_needed_packet_data_size(coap_res_ptr);
    printf("Calculated message length: %d bytes\n", message_len);

    uint8_t* message_ptr = (uint8_t*)malloc(message_len);
    sn_coap_builder(message_ptr, coap_res_ptr);

    // Uncomment to see the raw buffer that will be sent...
    // printf("Message is: ");
    // for (size_t ix = 0; ix < message_len; ix++) {
    //     printf("%02x ", message_ptr[ix]);
    // }
    // printf("\n");

    int scount = socket.sendto("i-ce.itron.cloud", 5683, message_ptr, message_len);
    printf("Sent %d bytes to coap://i-ce.itron.cloud:5683\n", scount);

    free(coap_res_ptr);
    free(message_ptr);

    Thread::wait(osWaitForever);
}
  1. Network initialization 
  2. open socket 
  3. COAP protocol init 
  4. COAP message recv thread start 
  5. COAP message builder run 
  6. send COAP message to i-ce.itron.cloud  server's 5685 port

 

#easy_connect.h

......
#define ETHERNET        1
#define WIFI_ESP8266    0
#define MESH_LOWPAN_ND  0
#define MESH_THREAD     0
#define WIFI_ODIN       0
#define WIFI_REALTEK    0

......

NetworkInterface* easy_connect(bool log_messages = false) {
    NetworkInterface* network_interface = 0;
    int connect_success = -1;
    /// This should be removed once mbedOS supports proper dual-stack
#if defined (MESH) || (MBED_CONF_LWIP_IPV6_ENABLED==true)
    printf("[EasyConnect] IPv6 mode\n");
#else
    printf("[EasyConnect] IPv4 mode\n");
#endif

 #if MBED_CONF_APP_NETWORK_INTERFACE == WIFI_ESP8266
		...
#elif MBED_CONF_APP_NETWORK_INTERFACE == WIFI_ODIN
		...
#elif MBED_CONF_APP_NETWORK_INTERFACE == WIFI_REALTEK
		...
#elif MBED_CONF_APP_NETWORK_INTERFACE == ETHERNET

    if (log_messages) {
        printf("[EasyConnect] Ethernet...\n");
    }

    spi.format(32, 0);
    spi.frequency(100000);

    printf("Wait for SPI...\r\n");
    wait(1);
    
    printf("Network Setting DHCP\r\n");
	uint8_t mac_addr[6] = {0x00, 0x08, 0xdc, 0x45, 0x56, 0x67};
	
    printf("Init with MAC address\n");
    eth.init(mac_addr);
    
    int timeout_ms = 15*1000;
    int err = dhcp.setup(&eth, mac_addr, timeout_ms);
    if (err == (-1)) {
        printf("Timeout.\n");
        return NULL;
    }
    printf("DHCP completed\n");
    printf("Connected, IP: %d.%d.%d.%d\r\n", dhcp.yiaddr[0], dhcp.yiaddr[1], dhcp.yiaddr[2], dhcp.yiaddr[3]);
    char ip[24], gateway[24], netmask[24], dnsaddr[24];
    sprintf(ip,      "%d.%d.%d.%d", dhcp.yiaddr[0],  dhcp.yiaddr[1],  dhcp.yiaddr[2],  dhcp.yiaddr[3]);
    sprintf(gateway, "%d.%d.%d.%d", dhcp.gateway[0], dhcp.gateway[1], dhcp.gateway[2], dhcp.gateway[3]);
    sprintf(netmask, "%d.%d.%d.%d", dhcp.netmask[0], dhcp.netmask[1], dhcp.netmask[2], dhcp.netmask[3]);
    sprintf(dnsaddr, "%d.%d.%d.%d", dhcp.dnsaddr[0], dhcp.dnsaddr[1], dhcp.dnsaddr[2], dhcp.dnsaddr[3]);
    eth.init(ip, netmask, gateway);

    dns.setup(&eth);
    dns.set_server(dnsaddr);
    bool isOK = dns.lookup("coap.me");
    if (isOK) {
        printf("is ok\n");
        uint32_t hIP = dns.get_ip();
        printf("coap.me IP: %u\n", hIP);
    } else {
        printf("coap.me IP is not ok\n");
    }

    
    const SocketAddress dns_sa = SocketAddress((const void *)&dhcp.dnsaddr[0], NSAPI_IPv4, 53);
    nsapi_error_t nsErr = nsapi_dns_add_server(dns_sa);
    if (nsErr) {
    	printf("[EasyConnect] error adding DNS entry: %d\n", nsErr);
    }
    printf("[EasyConnect] DNS IP: %s\n", dns_sa.get_ip_address());
    
    SocketAddress coap_sa;
    nsErr = nsapi_dns_query(&eth, "coap.me", &coap_sa, NSAPI_IPv4);
    if (nsErr) {
    	printf("[EasyConnect] error resolving coap.me: %d\n", nsErr);
    }

    if (log_messages) {
        printf("[EasyConnect] Using Ethernet\n");
    }
    network_interface = &eth;
    connect_success = eth.connect();
#endif

#ifdef MESH
		...
#endif
    if(connect_success == 0) {
        if (log_messages) {
            printf("[EasyConnect] Connected to Network successfully\n");
            print_MAC(network_interface, log_messages);
        }
    } else {
        if (log_messages) {
            print_MAC(network_interface, log_messages);
            printf("[EasyConnect] Connection to Network Failed %d!\n", connect_success);
        }
        return NULL;
    }
    const char *ip_addr  = network_interface->get_ip_address();
    if (ip_addr == NULL) {
        if (log_messages) {
            printf("[EasyConnect] ERROR - No IP address\n");
        }
        return NULL;
    }
    if (log_messages) {
        printf("[EasyConnect] IP address %s\n", ip_addr);
    }
    return network_interface;
}

Setting up SPI interface and network connectivity to use W5500.

 

 

Documents
  • coap-example

Comments Write