• AVR Freaks

Hot!ATWINC1500 UDP server

Author
larrycook99
Starting Member
  • Total Posts : 46
  • Reward points : 0
  • Joined: 2012/04/01 11:37:34
  • Location: Lexington, KY
  • Status: offline
2020/06/07 11:01:03 (permalink)
0

ATWINC1500 UDP server

I am trying to implement a UDP Server using the ATWINC1500 and the v2018-11-26 MLA code and am having no luck. I used the TCP Server code from this MLA to get a TCP server working and it runs very well.
 
Is there anyone that has successfully gotten a UDP server to work using the MLA code with the WINC1500?
 
The problem that I see is that after creating the socket and binding it to my port, when I call recvfrom() with no timeout (it says it should then wait forever for data to appear before returning) it returns immediately with SOCK_ERR_NO_ERROR and no data. My understanding is that 0 data indicates the socket was closed (is that correct?) but I never closed it and socket() and bind() returned with no error previously, so why is it returning immediately and with no data.
 
Does anyone have any idea why I am seeing what I am seeing? I assume that I am missing something but, for the life of me, I am not seeing it.
 
I thought, having the TCP server working, this would be easy. It has been anything but easy.
#1

11 Replies Related Threads

    aschen0866
    Super Member
    • Total Posts : 4573
    • Reward points : 0
    • Joined: 2006/01/08 22:18:32
    • Location: San Diego
    • Status: offline
    Re: ATWINC1500 UDP server 2020/06/07 18:52:12 (permalink)
    4 (1)
    larrycook99
     
    The problem that I see is that after creating the socket and binding it to my port, when I call recvfrom() with no timeout (it says it should then wait forever for data to appear before returning) it returns immediately with SOCK_ERR_NO_ERROR and no data. My understanding is that 0 data indicates the socket was closed (is that correct?) but I never closed it and socket() and bind() returned with no error previously, so why is it returning immediately and with no data.
     

    The UDP recvfrom() should be called within the socket callback when the callback event is SOCKET_MSG_RECVFROM.
     
    Socket APIs have the non-blocking nature. Unless there is an incorrect parameter setting, they usually return SOCK_ERR_NO_ERROR right the way. 
     
    #2
    larrycook99
    Starting Member
    • Total Posts : 46
    • Reward points : 0
    • Joined: 2012/04/01 11:37:34
    • Location: Lexington, KY
    • Status: offline
    Re: ATWINC1500 UDP server 2020/06/07 20:32:28 (permalink)
    0
    I am calling it from the socket callback as shown below:
     
    static void socket_cb(SOCKET sock, uint8_t message, void *pvMsg)
    {
        t_socketEventData *eData = (t_socketEventData *)pvMsg;

        if (message == M2M_SOCKET_BIND_EVENT) {
            if (eData->bindStatus == 0) {
                /* Prepare next buffer reception. */
               PRINTF("socket_cb: bind socket %d success!\r\n", sock);
               PRINTF("addr=%lx, port=%x\r\n",(eData->recvMsg.ai_addr.sin_addr.s_addr),
                      eData->recvMsg.ai_addr.sin_port);
               PRINTF("%x %x %x %x %x %x\r\n", eData->acceptResponse.sock, eData->listenStatus,
                      eData->numSendBytes, eData->acceptResponse.sock, eData->connectResponse.sock,
                      eData->connectResponse.error)
                recvfrom(sock, udpReceiveBuffer, WIFI_BUFFER_SIZE, 0);
            } else {
                PRINTF("socket_cb: bind error!\r\n");
            }
        } else if (message == M2M_SOCKET_RECVFROM_EVENT) {
            PRINTF("socket_cb: M2M_SOCKET_RECVFROM_EVENT socket %d, p_rxBuf=%x, bufSize=%x\r\n", sock,
                   (unsigned int)(eData->recvMsg.p_rxBuf), eData->recvMsg.bufSize);
            PRINTF("addr=%lx, port=%x\r\n",(eData->recvMsg.ai_addr.sin_addr.s_addr),
                   eData->recvMsg.ai_addr.sin_port);
            if (eData->recvMsg.p_rxBuf && eData->recvMsg.bufSize) {
                PRINTF("socket_cb: received app message.\r\n");
                /* Prepare next buffer reception. */
                recvfrom(sock, udpReceiveBuffer, WIFI_BUFFER_SIZE, 0);
            } else {
                if (eData->recvMsg.bufSize == SOCK_ERR_TIMEOUT) {
                    PRINTF("socket_cb: SOCK_ERR_TIMEOUT\r\n");
                    /* Prepare next buffer reception. */
                    recvfrom(sock, udpReceiveBuffer, WIFI_BUFFER_SIZE, 0);
                }
            }
        }
    }
     
    The function above is taken from Atmel example code. When recvfrom() returns the p_rxBuf and bufSize size are both 0. So recvfrom() gets called once after bind() and then never again.
     
    I am guessing I am missing something but I am not seeing it.
     
    #3
    larrycook99
    Starting Member
    • Total Posts : 46
    • Reward points : 0
    • Joined: 2012/04/01 11:37:34
    • Location: Lexington, KY
    • Status: offline
    Re: ATWINC1500 UDP server 2020/06/08 08:23:53 (permalink)
    0
    With respect to your comment about the API being non-blocking, a comment in the header for recvfrom() states about the timeout parameter, "Time, in milliseconds, to wait for receive data. If the timeout parameter is set to 0 then the socket will wait forever for data to be received." That sounds like it blocks to me, but whenever I call recvfrom() it returns without my having ever sent any UDP to the bound port. Further, when recvfrom() issues its callback, the data structure t_socketRecv contains the information about what was received, including p_rxBuf (pointer to the data buffer) and buffSize (amount of data in the buffer). Every time I get the callback both of these values are zero. And according to the comments about buffSize, "The received data chunk size. Holds a negative value if there is a receive error or ZERO on success upon reception of close socket message." So, getting 0 back implies that the socket was closed. But I didn't close it and I don't understand why it would have been.
     
    So, I am left perplexed as to why I am seeing the behavior that I see. I am assuming that I am doing something incorrectly, but I cannot figure out what that something is. Add to that the fact that TCP works perfectly, so what I got from the Microchip documents and code worked for that.
     
    Is there anyone out there that has UDP server (or client) code working with the Microchip prescribed method on a ATWINC1500?
    #4
    aschen0866
    Super Member
    • Total Posts : 4573
    • Reward points : 0
    • Joined: 2006/01/08 22:18:32
    • Location: San Diego
    • Status: offline
    Re: ATWINC1500 UDP server 2020/06/08 11:35:55 (permalink)
    0
    I run HTTP web server and DNS server (for HTTP redirect) using WINC1500 connected to a PIC32MZ processor. So I have both TCP server and UDP server running concurrently. I haven't had any issues. Then I don't use the MLA either. My host driver is from the ASF 3.47 release.
     
    As for the timeout parameter, I don't think it is the timeout for the recvfrom() call itself. The API call is still non-blocking. The timeout value is meant for the WINC module to time out its TCP or UPD receive operation. In all the WINC1500 example code and my own code, this value is always set to 0, meaning there is no timeout and receive waits forever.
     
    Here is the socket callback function for the simple UDP server example from ASF:

    /**
    * \brief Callback to get the Data from socket.
    *
    * \param[in] sock socket handler.
    * \param[in] u8Msg socket event type. Possible values are:
    * - SOCKET_MSG_BIND
    * - SOCKET_MSG_LISTEN
    * - SOCKET_MSG_ACCEPT
    * - SOCKET_MSG_CONNECT
    * - SOCKET_MSG_RECV
    * - SOCKET_MSG_SEND
    * - SOCKET_MSG_SENDTO
    * - SOCKET_MSG_RECVFROM
    * \param[in] pvMsg is a pointer to message structure. Existing types are:
    * - tstrSocketBindMsg
    * - tstrSocketListenMsg
    * - tstrSocketAcceptMsg
    * - tstrSocketConnectMsg
    * - tstrSocketRecvMsg
    */
    static void socket_cb(SOCKET sock, uint8_t u8Msg, void *pvMsg)
    {
    if (u8Msg == SOCKET_MSG_BIND) {
    tstrSocketBindMsg *pstrBind = (tstrSocketBindMsg *)pvMsg;
    if (pstrBind && pstrBind->status == 0) {
    /* Prepare next buffer reception. */
    printf("socket_cb: bind success!\r\n");
    recvfrom(sock, gau8SocketTestBuffer, MAIN_WIFI_M2M_BUFFER_SIZE, 0);
    } else {
    printf("socket_cb: bind error!\r\n");
    }
    } else if (u8Msg == SOCKET_MSG_RECVFROM) {
    tstrSocketRecvMsg *pstrRx = (tstrSocketRecvMsg *)pvMsg;
    if (packetCnt >= MAIN_WIFI_M2M_PACKET_COUNT) {
    return;
    }
    if (pstrRx->pu8Buffer && pstrRx->s16BufferSize) {
    packetCnt++;
    printf("socket_cb: received app message.(%u)\r\n", packetCnt);
    /* Prepare next buffer reception. */
    recvfrom(sock, gau8SocketTestBuffer, MAIN_WIFI_M2M_BUFFER_SIZE, 0);
    } else {
    if (pstrRx->s16BufferSize == SOCK_ERR_TIMEOUT) {
    /* Prepare next buffer reception. */
    recvfrom(sock, gau8SocketTestBuffer, MAIN_WIFI_M2M_BUFFER_SIZE, 0);
    }
    }
    }
    }

    As you can see, it doesn't have the type t_socketEventData. It uses two different types tstrSocketBindMsg and tstrSocketRecvMsg. They look like this

    /*!
    @struct \
    tstrSocketBindMsg
    @brief Socket bind status.
    An asynchronous call to the @ref bind socket operation, returns information through this structure in response.
    This structure together with the event @ref SOCKET_MSG_BIND are passed in parameters to the callback function.
    @see
    bind
    */
    typedef struct{
    sint8 status;
    /*!<
    The result of the bind operation.
    Holding a value of ZERO for a successful bind or otherwise a negative
    error code corresponding to the type of error.
    */
    }tstrSocketBindMsg;
     
    /*!
    @struct \
    tstrSocketRecvMsg
    @brief Socket recv status.
    Socket receive information is returned through this structure in response to the asynchronous call to the recv or recvfrom socket functions.
    This structure together with the events @ref SOCKET_MSG_RECV or @ref SOCKET_MSG_RECVFROM are passed-in parameters to the callback function.
    @remark
    In case the received data from the remote peer is larger than the USER buffer size defined during the asynchronous call to the @ref recv function,
    delivered to the user in a number of consecutive chunks according to the USER Buffer size.
    A negative or zero buffer size indicates an error with the following code:
    @ref SOCK_ERR_NO_ERROR : Socket connection closed. The application should now call @ref close().
    @ref SOCK_ERR_CONN_ABORTED : Socket connection aborted. The application should now call @ref close().
    @ref SOCK_ERR_TIMEOUT : Socket receive timed out. The socket connection remains open.
    */
    typedef struct{
    uint8 *pu8Buffer;
    /*!<
    Pointer to the USER buffer (passed to @ref recv and @ref recvfrom function) containing the received data chunk.
    */
    sint16 s16BufferSize;
    /*!<
    The received data chunk size.
    Holds a negative value if there is a receive error or ZERO on success upon reception of close socket message.
    */
    uint16 u16RemainingSize;
    /*!<
    The number of bytes remaining in the current @ref recv operation.
    */
    struct sockaddr_in strRemoteAddr;
    /*!<
    Socket address structure for the remote peer. It is valid for @ref SOCKET_MSG_RECVFROM event.
    */
    }tstrSocketRecvMsg;

    I can't see how both SOCKET_MSG_BIND and SOCKET_MSG_RECVFROM events can share a common type without another piece of code somewhere to merge these two pieces of information into one common structure for the socket callback. Can you?
     
     
    #5
    larrycook99
    Starting Member
    • Total Posts : 46
    • Reward points : 0
    • Joined: 2012/04/01 11:37:34
    • Location: Lexington, KY
    • Status: offline
    Re: ATWINC1500 UDP server 2020/06/08 20:19:45 (permalink)
    0
    I actually have Atmel Studio 7 installed and looked at that code and actually tried to use the functions intact but quickly realized there were differences but not as different as it first appeared. It is essentially the same code as in the MLA. Why Microchip decided they needed to rewrite the Atmel code is one of those things that I never understand. If it works, leave it alone. Changing things just confuses things.
     
    In the MLA code the t_socketEventData structure is really just a union of the Atmel structs and looks like:
     
    typedef union t_socketEventData
    {
    int8_t bindStatus; // 0 if bind successful, else error code
    int8_t listenStatus; // 0 if listen successful, else error code
    int16_t numSendBytes;
    t_socketAccept acceptResponse;
    t_socketConnect connectResponse;
    t_dnsReply dnsReply;
    t_socketRecv recvMsg;
    t_pingReply pingReply;
    } t_socketEventData;
     
    I have attempted to use the logic from the Atmel and Microchip examples and get the exact same behavior, which I cannot explain.
     
    And as I said before, I have A TCP server that I fashioned from the examples from the same places running just fine.
     
    As for the comment about the recvfrom() timeout, that makes sense to me. The blocking inferred by the comment never did.
     
    Does the code that you said you have running come from the Atmel example logic? Do you have functions similar to the ApplicationTask() and the socketCallback()? Any chance you could share your code because I am stumped by this? I assume it is something simple and when I find it I will hate myself but at the moment I am stumped.
    #6
    larrycook99
    Starting Member
    • Total Posts : 46
    • Reward points : 0
    • Joined: 2012/04/01 11:37:34
    • Location: Lexington, KY
    • Status: offline
    Re: ATWINC1500 UDP server 2020/06/09 08:38:25 (permalink)
    0
    I have attached a zip file of the source for the code that performs the TCP server function and tries to do the UDP server. I would appreciate it if someone could point out the obvious error in my UDP ways. Like I have said before, the TCP server works fine.
     
    Note that the main purpose of the TCP server is as a simple HTTP server, most of which is not shown. Also some of the code is done because the WiFi code is being built into the same system that also uses MicroChip MLA for their ENC28J60 ethernet chip chip.So the code is done so I can build for either the WINC1500 with its embedded Network Stack or the ENC28J60 with the Microchip MLA Network Stack but not both.
    #7
    larrycook99
    Starting Member
    • Total Posts : 46
    • Reward points : 0
    • Joined: 2012/04/01 11:37:34
    • Location: Lexington, KY
    • Status: offline
    Re: ATWINC1500 UDP server 2020/06/09 16:39:22 (permalink)
    4 (1)
    I figured it out!!!!
     
    It had nothing to do with the ApplicationTask() or socket_cb() logic. 
     
    It had to do with when I created the original TCP Server code I changed a define in wf_socket.h for TCP_SOCK_MAX from 7 to 4. Why did I do that? No idea now, other than it matches the TCP socket count for the MLA Network Stack code that I used on the ENC28J60.
     
    After I changed TCP_SOCK_MAC back to the original value of 7, UDP worked fine. Go figure...
     
    How did I find that?
     
    I decided to go back to my Explorer 16 board and run the UDP server example code there. It worked fine.
     
    Then I ported the ApplicationTask() and socket_cb() function logic to the Explorer code and it worked fine, too.
     
    So, I started looking for what the heck was different and remembered seeing that when I bound the UDP socket on the Explorer board it was socket 7 and not socket 4, like in my TCP server code that I couldn't get UDP working with. When I first saw it I just thought it odd but as nothing else explained the issue I was seeing, I remembered reading somewhere about someone else changing those socket defines and having an issue of some sort, so I decided, what the heck, and changed it back and the UDP code started working as expected.
     
    Geez!!! What a freaking pain in the backside that was!!!
     
    Does anyone know where such behavior might be documented because it certainly should be.
    #8
    aschen0866
    Super Member
    • Total Posts : 4573
    • Reward points : 0
    • Joined: 2006/01/08 22:18:32
    • Location: San Diego
    • Status: offline
    Re: ATWINC1500 UDP server 2020/06/09 17:19:37 (permalink)
    0
    I am glad you figured out the problem. You are only using static IP, aren't you?
     

    Does anyone know where such behavior might be documented because it certainly should be.

    For the long run, I would still recommend you ditching the MLA altogether. All the documentations I have seen are based off the ASF host driver.
     
    Those numbers you were talking about are the socket limits. They are documented in the Software Design Guide Section 6.1.3.
    #9
    larrycook99
    Starting Member
    • Total Posts : 46
    • Reward points : 0
    • Joined: 2012/04/01 11:37:34
    • Location: Lexington, KY
    • Status: offline
    Re: ATWINC1500 UDP server 2020/06/09 19:28:38 (permalink)
    0
    Actually we are using DHCP.
     
    The product is 10 years old and they have no intention of putting effort into redoing the code to ditch the MLA.
     
    I would be fine with it myself. 
     
    As to the socket limits, I see that they are documented as being the max of each type that you can have, however nowhere does it say you cannot set those limits to less and that doing so is bad, which was my issue.
    #10
    aschen0866
    Super Member
    • Total Posts : 4573
    • Reward points : 0
    • Joined: 2006/01/08 22:18:32
    • Location: San Diego
    • Status: offline
    Re: ATWINC1500 UDP server 2020/06/10 10:32:51 (permalink)
    5 (1)
    larrycook99
    Actually we are using DHCP.

    The reason I was asking is that there should be an API call m2m_wifi_request_dhcp_client() if DHCP is used. I didn't see it in your code.
     
    larrycook99 
    As to the socket limits, I see that they are documented as being the max of each type that you can have, however nowhere does it say you cannot set those limits to less and that doing so is bad, which was my issue.

    That's correct. You can't limit how many TCP or UDP sockets you would only want to use for a specific application. It is all handled inside the WINC module. This makes, for example, the web server implementation more challenging as nearly all modern browsers will try to open multiple concurrent sockets to download multiple files, and the WINC module will automatically accept a request if there is a TCP socket available.
     
    #11
    larrycook99
    Starting Member
    • Total Posts : 46
    • Reward points : 0
    • Joined: 2012/04/01 11:37:34
    • Location: Lexington, KY
    • Status: offline
    Re: ATWINC1500 UDP server 2020/06/18 06:59:51 (permalink)
    0
    You are correct, I do not call m2m_wifi_request_dhcp_client(). In the driver code that I am using that call does not exist. My code calls m2m_wifi_enable_dhcp() instead, which I assume is essentially the same function.
     
    As for the TCP and UDP number of sockets, I finally found the reference I had seen about the issue of changing the TCP max: https://github.com/arduino-libraries/WiFi101/issues/242
    #12
    Jump to:
    © 2020 APG vNext Commercial Version 4.5