part: Made irq_names static
[simavr] / examples / parts / uart_udp.c
1 /*
2         uart_udp.c
3
4         Copyright 2008, 2009 Michel Pollet <buserror@gmail.com>
5
6         This file is part of simavr.
7
8         simavr is free software: you can redistribute it and/or modify
9         it under the terms of the GNU General Public License as published by
10         the Free Software Foundation, either version 3 of the License, or
11         (at your option) any later version.
12
13         simavr is distributed in the hope that it will be useful,
14         but WITHOUT ANY WARRANTY; without even the implied warranty of
15         MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16         GNU General Public License for more details.
17
18         You should have received a copy of the GNU General Public License
19         along with simavr.  If not, see <http://www.gnu.org/licenses/>.
20  */
21
22 #include <netinet/in.h>
23 #include <netinet/tcp.h>
24 #include <arpa/inet.h>
25 #include <sys/socket.h>
26 #include <sys/time.h>
27 #include <pthread.h>
28 #include <string.h>
29 #include <stdio.h>
30 #include <errno.h>
31 #include <unistd.h>
32
33 #include "uart_udp.h"
34 #include "avr_uart.h"
35 #include "sim_hex.h"
36
37 DEFINE_FIFO(uint8_t,uart_udp_fifo, 512);
38
39 /*
40  * called when a byte is send via the uart on the AVR
41  */
42 static void uart_udp_in_hook(struct avr_irq_t * irq, uint32_t value, void * param)
43 {
44         uart_udp_t * p = (uart_udp_t*)param;
45 //      printf("uart_udp_in_hook %02x\n", value);
46         uart_udp_fifo_write(&p->in, value);
47 }
48
49 /*
50  * Called when the uart has room in it's input buffer. This is called repeateadly
51  * if necessary, while the xoff is called only when the uart fifo is FULL
52  */
53 static void uart_udp_xon_hook(struct avr_irq_t * irq, uint32_t value, void * param)
54 {
55         uart_udp_t * p = (uart_udp_t*)param;
56 //      if (!p->xon)
57 //              printf("uart_udp_xon_hook\n");
58         p->xon = 1;
59         // try to empty our fifo, the uart_udp_xoff_hook() will be called when
60         // other side is full
61         while (p->xon && !uart_udp_fifo_isempty(&p->out)) {
62                 uint8_t byte = uart_udp_fifo_read(&p->out);
63         //      printf("uart_udp_xon_hook send %02x\n", byte);
64                 avr_raise_irq(p->irq + IRQ_UART_UDP_BYTE_OUT, byte);
65         }
66 }
67
68 /*
69  * Called when the uart ran out of room in it's input buffer
70  */
71 static void uart_udp_xoff_hook(struct avr_irq_t * irq, uint32_t value, void * param)
72 {
73         uart_udp_t * p = (uart_udp_t*)param;
74 //      if (p->xon)
75 //              printf("uart_udp_xoff_hook\n");
76         p->xon = 0;
77 }
78
79 static void * uart_udp_thread(void * param)
80 {
81         uart_udp_t * p = (uart_udp_t*)param;
82
83         while (1) {
84                 fd_set read_set, write_set;
85                 int max = p->s + 1;
86                 FD_ZERO(&read_set);
87                 FD_ZERO(&write_set);
88
89                 FD_SET(p->s, &read_set);
90                 if (!uart_udp_fifo_isempty(&p->in))
91                         FD_SET(p->s, &write_set);
92
93                 struct timeval timo = { 0, 500 };       // short, but not too short interval
94                 int ret = select(max, &read_set, &write_set, NULL, &timo);
95
96                 if (!ret)
97                         continue;
98
99                 if (FD_ISSET(p->s, &read_set)) {
100                         uint8_t buffer[512];
101
102                         socklen_t len = sizeof(p->peer);
103                         ssize_t r = recvfrom(p->s, buffer, sizeof(buffer)-1, 0, (struct sockaddr*)&p->peer, &len);
104
105                 //      hdump("udp recv", buffer, r);
106
107                         // write them in fifo
108                         uint8_t * src = buffer;
109                         while (r-- && !uart_udp_fifo_isfull(&p->out))
110                                 uart_udp_fifo_write(&p->out, *src++);
111                         if (r > 0)
112                                 printf("UDP dropped %zu bytes\n", r);
113                 }
114                 if (FD_ISSET(p->s, &write_set)) {
115                         uint8_t buffer[512];
116                         // write them in fifo
117                         uint8_t * dst = buffer;
118                         while (!uart_udp_fifo_isempty(&p->in) && dst < (buffer+sizeof(buffer)))
119                                 *dst++ = uart_udp_fifo_read(&p->in);
120                         socklen_t len = dst - buffer;
121                         size_t r = sendto(p->s, buffer, len, 0, (struct sockaddr*)&p->peer, sizeof(p->peer));
122                 //      hdump("udp send", buffer, r);
123                 }
124         }
125 }
126
127 static const char * irq_names[IRQ_UART_UDP_COUNT] = {
128         [IRQ_UART_UDP_BYTE_IN] = "8<uart_udp.in",
129         [IRQ_UART_UDP_BYTE_OUT] = "8>uart_udp.out",
130 };
131
132 void uart_udp_init(struct avr_t * avr, uart_udp_t * p)
133 {
134         p->avr = avr;
135         p->irq = avr_alloc_irq(&avr->irq_pool, 0, IRQ_UART_UDP_COUNT, irq_names);
136         avr_irq_register_notify(p->irq + IRQ_UART_UDP_BYTE_IN, uart_udp_in_hook, p);
137
138         if ((p->s = socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
139                 fprintf(stderr, "%s: Can't create socket: %s", __FUNCTION__, strerror(errno));
140                 return ;
141         }
142
143         struct sockaddr_in address = { 0 };
144         address.sin_family = AF_INET;
145         address.sin_port = htons (4321);
146
147         if (bind(p->s, (struct sockaddr *) &address, sizeof(address))) {
148                 fprintf(stderr, "%s: Can not bind socket: %s", __FUNCTION__, strerror(errno));
149                 return ;
150         }
151
152         printf("uart_udp_init bridge on port %d\n", 4321);
153
154         pthread_create(&p->thread, NULL, uart_udp_thread, p);
155
156 }
157
158 void uart_udp_connect(uart_udp_t * p, char uart)
159 {
160         // disable the stdio dump, as we are sending binary there
161         uint32_t f = 0;
162         avr_ioctl(p->avr, AVR_IOCTL_UART_GET_FLAGS(uart), &f);
163         f &= ~AVR_UART_FLAG_STDIO;
164         avr_ioctl(p->avr, AVR_IOCTL_UART_SET_FLAGS(uart), &f);
165
166         avr_irq_t * src = avr_io_getirq(p->avr, AVR_IOCTL_UART_GETIRQ(uart), UART_IRQ_OUTPUT);
167         avr_irq_t * dst = avr_io_getirq(p->avr, AVR_IOCTL_UART_GETIRQ(uart), UART_IRQ_INPUT);
168         avr_irq_t * xon = avr_io_getirq(p->avr, AVR_IOCTL_UART_GETIRQ(uart), UART_IRQ_OUT_XON);
169         avr_irq_t * xoff = avr_io_getirq(p->avr, AVR_IOCTL_UART_GETIRQ(uart), UART_IRQ_OUT_XOFF);
170         if (src && dst) {
171                 avr_connect_irq(src, p->irq + IRQ_UART_UDP_BYTE_IN);
172                 avr_connect_irq(p->irq + IRQ_UART_UDP_BYTE_OUT, dst);
173         }
174         if (xon)
175                 avr_irq_register_notify(xon, uart_udp_xon_hook, p);
176         if (xoff)
177                 avr_irq_register_notify(xoff, uart_udp_xoff_hook, p);
178 }
179