/** ****************************************************************************** * * @file pios_udp.c * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. * Parts by Thorsten Klose (tk@midibox.org) (tk@midibox.org) * @brief UDP commands. Inits UDPs, controls UDPs & Interupt handlers. * @see The GNU Public License (GPL) Version 3 * @defgroup PIOS_UDP UDP Functions * @{ * *****************************************************************************/ /* * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* Project Includes */ #include "pios.h" #if defined(PIOS_INCLUDE_UDP) #include /* Provide a COM driver */ const struct pios_com_driver pios_udp_com_driver = { .set_baud = PIOS_UDP_ChangeBaud, .tx_nb = PIOS_UDP_TxBufferPutMoreNonBlocking, .tx = PIOS_UDP_TxBufferPutMore, .rx = PIOS_UDP_RxBufferGet, .rx_avail = PIOS_UDP_RxBufferUsed, }; static struct pios_udp_dev * find_udp_dev_by_id (uint8_t udp) { if (udp >= pios_udp_num_devices) { /* Undefined UDP port for this board (see pios_board.c) */ return NULL; } /* Get a handle for the device configuration */ return &(pios_udp_devs[udp]); } /** * Open some UDP sockets */ void PIOS_UDP_Init(void) { struct pios_udp_dev * udp_dev; uint8_t i; for (i = 0; i < pios_udp_num_devices; i++) { /* Get a handle for the device configuration */ udp_dev = find_udp_dev_by_id(i); //PIOS_DEBUG_Assert(udp_dev); /* Clear buffer counters */ udp_dev->rx.head = udp_dev->rx.tail = udp_dev->rx.size = 0; /* assign socket */ udp_dev->socket = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); memset(&udp_dev->server,0,sizeof(udp_dev->server)); memset(&udp_dev->client,0,sizeof(udp_dev->client)); udp_dev->server.sin_family = AF_INET; udp_dev->server.sin_addr.s_addr = inet_addr(udp_dev->cfg->ip); udp_dev->server.sin_port = htons(udp_dev->cfg->port); int res= bind(udp_dev->socket, (struct sockaddr *)&udp_dev->server,sizeof(udp_dev->server)); /* use nonblocking IO */ int flags = fcntl(udp_dev->socket, F_GETFL, 0); fcntl(udp_dev->socket, F_SETFL, flags | O_NONBLOCK); printf("udp dev %i - socket %i opened - result %i\n",i,udp_dev->socket,res); /* TODO do some error handling - wait no, we can't - we are void anyway ;) */ } } /** * Changes the baud rate of the UDP peripheral without re-initialising. * \param[in] udp UDP name (GPS, TELEM, AUX) * \param[in] baud Requested baud rate */ void PIOS_UDP_ChangeBaud(uint8_t udp, uint32_t baud) { } /** * puts a byte onto the receive buffer * \param[in] UDP UDP name * \param[in] b byte which should be put into Rx buffer * \return 0 if no error * \return -1 if UDP not available * \return -2 if buffer full (retry) * \note Applications shouldn't call these functions directly, instead please use \ref PIOS_COM layer functions */ int32_t PIOS_UDP_RxBufferPut(uint8_t udp, uint8_t b) { struct pios_udp_dev * udp_dev; /* Get a handle for the device configuration */ udp_dev = find_udp_dev_by_id(udp); if (!udp_dev) { /* Undefined UDP port for this board (see pios_board.c) */ return -1; } if (udp_dev->rx.size >= sizeof(udp_dev->rx.buf)) { /* Buffer full (retry) */ return -2; } /* Copy received byte into receive buffer */ udp_dev->rx.buf[udp_dev->rx.head++] = b; if (udp_dev->rx.head >= sizeof(udp_dev->rx.buf)) { udp_dev->rx.head = 0; } udp_dev->rx.size++; /* No error */ return 0; } /** * attempt to receive */ void PIOS_UDP_RECV(uint8_t udp) { struct pios_udp_dev * udp_dev; unsigned char localbuffer[PIOS_UDP_RX_BUFFER_SIZE]; /* Get a handle for the device configuration */ udp_dev = find_udp_dev_by_id(udp); if (!udp_dev) { /* Undefined UDP port for this board (see pios_board.c) */ return; } /* use nonblocking IO */ int flags = fcntl(udp_dev->socket, F_GETFL, 0); fcntl(udp_dev->socket, F_SETFL, flags | O_NONBLOCK); /* receive data */ int received; udp_dev->clientLength=sizeof(udp_dev->client); if ((received = recvfrom(udp_dev->socket, localbuffer, (PIOS_UDP_RX_BUFFER_SIZE - udp_dev->rx.size), 0, (struct sockaddr *) &udp_dev->client, (socklen_t*)&udp_dev->clientLength)) < 0) { return; } /* copy received data to buffer */ int t; for (t=0;trx.buf) - udp_dev->rx.size); } /** * Returns number of used bytes in receive buffer * \param[in] UDP UDP name * \return > 0: number of used bytes * \return 0 if UDP not available * \note Applications shouldn't call these functions directly, instead please use \ref PIOS_COM layer functions */ int32_t PIOS_UDP_RxBufferUsed(uint8_t udp) { struct pios_udp_dev * udp_dev; /* Get a handle for the device configuration */ udp_dev = find_udp_dev_by_id(udp); if (!udp_dev) { /* Undefined UDP port for this board (see pios_board.c) */ return -2; } /* fill buffer */ PIOS_UDP_RECV(udp); return (udp_dev->rx.size); } /** * Gets a byte from the receive buffer * \param[in] UDP UDP name * \return -1 if UDP not available * \return -2 if no new byte available * \return >= 0: number of received bytes * \note Applications shouldn't call these functions directly, instead please use \ref PIOS_COM layer functions */ int32_t PIOS_UDP_RxBufferGet(uint8_t udp) { struct pios_udp_dev * udp_dev; /* Get a handle for the device configuration */ udp_dev = find_udp_dev_by_id(udp); if (!udp_dev) { /* Undefined UDP port for this board (see pios_board.c) */ return -2; } /* fill buffer */ PIOS_UDP_RECV(udp); if (!udp_dev->rx.size) { /* Nothing new in the buffer */ return -1; } /* get byte */ uint8_t b = udp_dev->rx.buf[udp_dev->rx.tail++]; if (udp_dev->rx.tail >= sizeof(udp_dev->rx.buf)) { udp_dev->rx.tail = 0; } udp_dev->rx.size--; /* Return received byte */ return b; } /** * Returns the next byte of the receive buffer without taking it * \param[in] UDP UDP name * \return -1 if UDP not available * \return -2 if no new byte available * \return >= 0: number of received bytes * \note Applications shouldn't call these functions directly, instead please use \ref PIOS_COM layer functions */ int32_t PIOS_UDP_RxBufferPeek(uint8_t udp) { struct pios_udp_dev * udp_dev; /* Get a handle for the device configuration */ udp_dev = find_udp_dev_by_id(udp); if (!udp_dev) { /* Undefined UDP port for this board (see pios_board.c) */ return -2; } /* fill buffer */ PIOS_UDP_RECV(udp); if (!udp_dev->rx.size) { /* Nothing new in the buffer */ return -1; } /* get byte */ uint8_t b = udp_dev->rx.buf[udp_dev->rx.tail]; /* Return received byte */ return b; } /** * returns number of free bytes in transmit buffer * \param[in] UDP UDP name * \return number of free bytes * \return 0 if UDP not available * \note Applications shouldn't call these functions directly, instead please use \ref PIOS_COM layer functions */ int32_t PIOS_UDP_TxBufferFree(uint8_t udp) { struct pios_udp_dev * udp_dev; /* Get a handle for the device configuration */ udp_dev = find_udp_dev_by_id(udp); if (!udp_dev) { /* Undefined UDP port for this board (see pios_board.c) */ return 0; } return PIOS_UDP_RX_BUFFER_SIZE; } /** * returns number of used bytes in transmit buffer * \param[in] UDP UDP name * \return number of used bytes * \return 0 if UDP not available * \note Applications shouldn't call these functions directly, instead please use \ref PIOS_COM layer functions */ int32_t PIOS_UDP_TxBufferUsed(uint8_t udp) { struct pios_udp_dev * udp_dev; /* Get a handle for the device configuration */ udp_dev = find_udp_dev_by_id(udp); if (!udp_dev) { /* Undefined UDP port for this board (see pios_board.c) */ return 0; } return 0; } /** * puts more than one byte onto the transmit buffer (used for atomic sends) * \param[in] UDP UDP name * \param[in] *buffer pointer to buffer to be sent * \param[in] len number of bytes to be sent * \return 0 if no error * \return -1 if UDP not available * \return -2 if buffer full or cannot get all requested bytes (retry) * \return -3 if UDP not supported by UDPTxBufferPut Routine * \note Applications shouldn't call these functions directly, instead please use \ref PIOS_COM layer functions */ int32_t PIOS_UDP_TxBufferPutMoreNonBlocking(uint8_t udp, uint8_t *buffer, uint16_t len) { struct pios_udp_dev * udp_dev; /* Get a handle for the device configuration */ udp_dev = find_udp_dev_by_id(udp); if (!udp_dev) { /* Undefined UDP port for this board (see pios_board.c) */ return -1; } if (len >= PIOS_UDP_RX_BUFFER_SIZE) { /* Buffer cannot accept all requested bytes (retry) */ return -2; } /* send data to client - non blocking*/ /* use nonblocking IO */ int flags = fcntl(udp_dev->socket, F_GETFL, 0); fcntl(udp_dev->socket, F_SETFL, flags | O_NONBLOCK); sendto(udp_dev->socket, buffer, len, 0, (struct sockaddr *) &udp_dev->client, (socklen_t)sizeof(udp_dev->client)); /* No error */ return 0; } /** * puts more than one byte onto the transmit buffer (used for atomic sends)
* (blocking function) * \param[in] UDP UDP name * \param[in] *buffer pointer to buffer to be sent * \param[in] len number of bytes to be sent * \return 0 if no error * \return -1 if UDP not available * \return -3 if UDP not supported by UDPTxBufferPut Routine * \note Applications shouldn't call these functions directly, instead please use \ref PIOS_COM layer functions */ int32_t PIOS_UDP_TxBufferPutMore(uint8_t udp, uint8_t *buffer, uint16_t len) { struct pios_udp_dev * udp_dev; /* Get a handle for the device configuration */ udp_dev = find_udp_dev_by_id(udp); if (!udp_dev) { /* Undefined UDP port for this board (see pios_board.c) */ return -1; } if (len >= PIOS_UDP_RX_BUFFER_SIZE) { /* Buffer cannot accept all requested bytes (retry) */ return -2; } /* send data to client - blocking*/ /* use blocking IO */ int flags = fcntl(udp_dev->socket, F_GETFL, 0); fcntl(udp_dev->socket, F_SETFL, flags & ~O_NONBLOCK); sendto(udp_dev->socket, buffer, len, 0, (struct sockaddr *) &udp_dev->client, sizeof(udp_dev->client)); /* No error */ return 0; } /** * puts a byte onto the transmit buffer * \param[in] UDP UDP name * \param[in] b byte which should be put into Tx buffer * \return 0 if no error * \return -1 if UDP not available * \return -2 if buffer full (retry) * \return -3 if UDP not supported by UDPTxBufferPut Routine * \note Applications shouldn't call these functions directly, instead please use \ref PIOS_COM layer functions */ int32_t PIOS_UDP_TxBufferPut_NonBlocking(uint8_t udp, uint8_t b) { return PIOS_UDP_TxBufferPutMoreNonBlocking(udp, &b, 1); } /** * puts a byte onto the transmit buffer
* (blocking function) * \param[in] UDP UDP name * \param[in] b byte which should be put into Tx buffer * \return 0 if no error * \return -1 if UDP not available * \return -3 if UDP not supported by UDPTxBufferPut Routine * \note Applications shouldn't call these functions directly, instead please use \ref PIOS_COM layer functions */ int32_t PIOS_UDP_TxBufferPut(uint8_t udp, uint8_t b) { return PIOS_UDP_TxBufferPutMore(udp, &b, 1); } #endif