2 ******************************************************************************
5 * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
6 * Parts by Thorsten Klose (tk@midibox.org) (tk@midibox.org)
7 * @brief UDP commands. Inits UDPs, controls UDPs & Interupt handlers.
8 * @see The GNU Public License (GPL) Version 3
9 * @defgroup PIOS_UDP UDP Functions
12 *****************************************************************************/
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 3 of the License, or
17 * (at your option) any later version.
19 * This program is distributed in the hope that it will be useful, but
20 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
21 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
24 * You should have received a copy of the GNU General Public License along
25 * with this program; if not, write to the Free Software Foundation, Inc.,
26 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
30 /* Project Includes */
33 #if defined(PIOS_INCLUDE_UDP)
36 #include <pios_udp_priv.h>
38 /* We need a list of UDP devices */
40 #define PIOS_UDP_MAX_DEV 256
41 static int8_t pios_udp_num_devices
= 0;
43 static pios_udp_dev pios_udp_devices
[PIOS_UDP_MAX_DEV
];
46 /* Provide a COM driver */
47 static void PIOS_UDP_ChangeBaud(uint32_t udp_id
, uint32_t baud
);
48 static void PIOS_UDP_RegisterRxCallback(uint32_t udp_id
, pios_com_callback rx_in_cb
, uint32_t context
);
49 static void PIOS_UDP_RegisterTxCallback(uint32_t udp_id
, pios_com_callback tx_out_cb
, uint32_t context
);
50 static void PIOS_UDP_TxStart(uint32_t udp_id
, uint16_t tx_bytes_avail
);
51 static void PIOS_UDP_RxStart(uint32_t udp_id
, uint16_t rx_bytes_avail
);
53 const struct pios_com_driver pios_udp_com_driver
= {
54 .set_baud
= PIOS_UDP_ChangeBaud
,
55 .tx_start
= PIOS_UDP_TxStart
,
56 .rx_start
= PIOS_UDP_RxStart
,
57 .bind_tx_cb
= PIOS_UDP_RegisterTxCallback
,
58 .bind_rx_cb
= PIOS_UDP_RegisterRxCallback
,
62 static pios_udp_dev
*find_udp_dev_by_id(uint8_t udp
)
64 if (udp
>= pios_udp_num_devices
) {
65 /* Undefined UDP port for this board (see pios_board.c) */
70 /* Get a handle for the device configuration */
71 return &(pios_udp_devices
[udp
]);
77 void *PIOS_UDP_RxThread(void *udp_dev_n
)
79 pios_udp_dev
*udp_dev
= (pios_udp_dev
*)udp_dev_n
;
82 * com devices never get closed except by application "reboot"
83 * we also never give up our mutex except for waiting
90 udp_dev
->clientLength
= sizeof(udp_dev
->client
);
91 if ((received
= recvfrom(udp_dev
->socket
,
93 PIOS_UDP_RX_BUFFER_SIZE
,
95 (struct sockaddr
*)&udp_dev
->client
,
96 (socklen_t
*)&udp_dev
->clientLength
)) >= 0) {
97 /* copy received data to buffer if possible */
98 /* we do NOT buffer data locally. If the com buffer can't receive, data is discarded! */
99 /* (thats what the USART driver does too!) */
100 bool rx_need_yield
= false;
101 if (udp_dev
->rx_in_cb
) {
102 (void)(udp_dev
->rx_in_cb
)(udp_dev
->rx_in_context
, udp_dev
->rx_buffer
, received
, NULL
, &rx_need_yield
);
105 #if defined(PIOS_INCLUDE_FREERTOS)
109 #endif /* PIOS_INCLUDE_FREERTOS */
118 int32_t PIOS_UDP_Init(uint32_t *udp_id
, const struct pios_udp_cfg
*cfg
)
120 pios_udp_dev
*udp_dev
= &pios_udp_devices
[pios_udp_num_devices
];
122 pios_udp_num_devices
++;
126 udp_dev
->rx_in_cb
= NULL
;
127 udp_dev
->tx_out_cb
= NULL
;
131 udp_dev
->socket
= socket(PF_INET
, SOCK_DGRAM
, IPPROTO_UDP
);
132 memset(&udp_dev
->server
, 0, sizeof(udp_dev
->server
));
133 memset(&udp_dev
->client
, 0, sizeof(udp_dev
->client
));
134 udp_dev
->server
.sin_family
= AF_INET
;
135 udp_dev
->server
.sin_addr
.s_addr
= inet_addr(udp_dev
->cfg
->ip
);
136 udp_dev
->server
.sin_port
= htons(udp_dev
->cfg
->port
);
137 int res
= bind(udp_dev
->socket
, (struct sockaddr
*)&udp_dev
->server
, sizeof(udp_dev
->server
));
139 /* Create transmit thread for this connection */
140 #if defined(PIOS_INCLUDE_FREERTOS)
141 // ( pdTASK_CODE pvTaskCode, const portCHAR * const pcName, unsigned portSHORT usStackDepth, void *pvParameters, unsigned portBASE_TYPE uxPriority, xTaskHandle *pvCreatedTask );
142 xTaskCreate((pdTASK_CODE
)PIOS_UDP_RxThread
, "UDP_Rx_Thread", 1024, (void *)udp_dev
, (tskIDLE_PRIORITY
+ 1), &udp_dev
->rxThread
);
144 pthread_create(&udp_dev
->rxThread
, NULL
, PIOS_UDP_RxThread
, (void *)udp_dev
);
148 printf("udp dev %i - socket %i opened - result %i\n", pios_udp_num_devices
- 1, udp_dev
->socket
, res
);
150 *udp_id
= pios_udp_num_devices
- 1;
156 void PIOS_UDP_ChangeBaud(uint32_t udp_id
, uint32_t baud
)
164 static void PIOS_UDP_RxStart(uint32_t udp_id
, uint16_t rx_bytes_avail
)
172 static void PIOS_UDP_TxStart(uint32_t udp_id
, uint16_t tx_bytes_avail
)
174 pios_udp_dev
*udp_dev
= find_udp_dev_by_id(udp_id
);
176 PIOS_Assert(udp_dev
);
178 int32_t length
, len
, rem
;
181 * we send everything directly whenever notified of data to send (lazy!)
183 if (udp_dev
->tx_out_cb
) {
184 while (tx_bytes_avail
> 0) {
185 bool tx_need_yield
= false;
186 length
= (udp_dev
->tx_out_cb
)(udp_dev
->tx_out_context
, udp_dev
->tx_buffer
, PIOS_UDP_RX_BUFFER_SIZE
, NULL
, &tx_need_yield
);
189 len
= sendto(udp_dev
->socket
, udp_dev
->tx_buffer
+ length
- rem
, rem
, 0,
190 (struct sockaddr
*)&udp_dev
->client
,
191 sizeof(udp_dev
->client
));
198 tx_bytes_avail
-= length
;
203 static void PIOS_UDP_RegisterRxCallback(uint32_t udp_id
, pios_com_callback rx_in_cb
, uint32_t context
)
205 pios_udp_dev
*udp_dev
= find_udp_dev_by_id(udp_id
);
207 PIOS_Assert(udp_dev
);
210 * Order is important in these assignments since ISR uses _cb
211 * field to determine if it's ok to dereference _cb and _context
213 udp_dev
->rx_in_context
= context
;
214 udp_dev
->rx_in_cb
= rx_in_cb
;
217 static void PIOS_UDP_RegisterTxCallback(uint32_t udp_id
, pios_com_callback tx_out_cb
, uint32_t context
)
219 pios_udp_dev
*udp_dev
= find_udp_dev_by_id(udp_id
);
221 PIOS_Assert(udp_dev
);
224 * Order is important in these assignments since ISR uses _cb
225 * field to determine if it's ok to dereference _cb and _context
227 udp_dev
->tx_out_context
= context
;
228 udp_dev
->tx_out_cb
= tx_out_cb
;
232 #endif /* if defined(PIOS_INCLUDE_UDP) */