export FIFOs
[aversive.git] / modules / base / hostsim / hostsim.c
1 /*
2  *  Copyright Droids Corporation
3  *  Olivier Matz <zer0@droids-corp.org>
4  *
5  *  This program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2 of the License, or
8  *  (at your option) any later version.
9  *
10  *  This program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with this program; if not, write to the Free Software
17  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  *
19  *  Revision : $Id: main.c,v 1.10 2009-11-08 17:24:33 zer0 Exp $
20  *
21  */
22
23 #ifdef HOST_VERSION
24 /*
25  * AVR simulator. This code is used on host (PC for instance) to
26  * generate a signal that will call other aversive modules like
27  * scheduler or uart. The goal is to simulate the behaviour of
28  * hardware interrupts in a unix application.
29  */
30
31 #include <aversive.h>
32
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <signal.h>
36 #include <unistd.h>
37 #include <fcntl.h>
38 #include <string.h>
39 #include <pthread.h>
40 #include <sys/time.h>
41 #include <sys/types.h>
42 #include <sys/wait.h>
43 #include <termios.h>
44
45 #ifdef CONFIG_MODULE_SCHEDULER
46 #include <scheduler.h>
47 #endif
48 #ifdef CONFIG_MODULE_UART
49 #include <uart_host.h>
50 #endif
51
52 static pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER;
53 static volatile int cpt = 0;
54
55 static struct termios oldterm;
56 /* static */ int old_stdin, old_stdout;
57 static int stdin_pipe[2];
58 static int stdout_pipe[2];
59
60 enum msg_type {
61         SCHED,
62         UART_RCV,
63         UART_SND,
64 };
65
66 struct message {
67         enum msg_type type;
68         char c;
69 };
70 static struct message g_msg;
71
72 #ifdef SA_SIGINFO
73 static void sigusr1(__attribute__((unused)) int sig,
74                     __attribute__((unused)) siginfo_t *info,
75                     __attribute__((unused)) void *uc)
76 #else
77 void sigusr1(__attribute__((unused)) int sig)
78 #endif
79 {
80         struct message m;
81         m = g_msg;
82
83 #ifdef CONFIG_MODULE_SCHEDULER
84         if (m.type == SCHED) {
85                 pthread_mutex_unlock(&mut);
86                 scheduler_interrupt();
87         }
88 #endif
89
90 #ifdef CONFIG_MODULE_UART
91         if (m.type == UART_RCV) {
92                 uart_host_rx_event(m.c);
93                 pthread_mutex_unlock(&mut);
94         }
95         if (m.type == UART_SND) {
96                 uart_host_tx_event(m.c);
97                 pthread_mutex_unlock(&mut);
98         }
99 #endif
100 }
101
102 static int lock_count = 0;
103
104 void hostsim_lock(void)
105 {
106         if (lock_count++)
107                 return;
108         pthread_mutex_lock(&mut);
109 }
110
111 void hostsim_unlock(void)
112 {
113         if (lock_count-- == 1)
114                 pthread_mutex_unlock(&mut);
115 }
116
117 int hostsim_islocked(void)
118 {
119         return lock_count;
120 }
121
122 void host_wait_ms(int ms)
123 {
124         struct timeval tv, tv2, diff;
125
126         gettimeofday(&tv, NULL);
127         diff.tv_sec = (1000 * ms) / 1000000;
128         diff.tv_usec = (1000 * ms) % 1000000;
129         timeradd(&tv, &diff, &tv);
130         gettimeofday(&tv2, NULL);
131
132         while (timercmp(&tv2, &tv, <)) {
133                 usleep(1000);
134                 gettimeofday(&tv2, NULL);
135         }
136 }
137
138
139 /* sends signal to child */
140 void *parent(void *arg)
141 {
142         pthread_t thread = (pthread_t)arg;
143         struct timeval cur_tv, prev_tv, tv_millisec;
144         int n;
145
146         gettimeofday(&prev_tv, NULL);
147
148         while (1) {
149                 usleep(1000);
150                 gettimeofday(&cur_tv, NULL);
151
152                 n = 0;
153                 while (timercmp(&prev_tv, &cur_tv, <)) {
154                         if (n > 5) {
155                                 /* give some time between subsequent
156                                  * signals */
157                                 usleep(100);
158                                 n = 0;
159                         }
160                         pthread_mutex_lock(&mut);
161                         g_msg.type = SCHED;
162                         pthread_kill(thread, SIGUSR1);
163
164                         /* signal was acked */
165                         tv_millisec.tv_sec = 0;
166                         tv_millisec.tv_usec = 1000;
167                         timeradd(&prev_tv, &tv_millisec, &prev_tv);
168                         n ++;
169                 }
170         }
171
172         pthread_exit(NULL);
173         return NULL;
174 }
175
176 void *hostsim_uart_stdin(void *arg)
177 {
178         pthread_t thread = (pthread_t)arg;
179         int n;
180         char c;
181
182         /* read on old stdin and put it in pipe */
183         while (1) {
184                 n = read(old_stdin, &c, 1);
185                 if (n <= 0)
186                         break;
187
188                 pthread_mutex_lock(&mut);
189                 g_msg.type = UART_RCV;
190                 g_msg.c = c;
191                 pthread_kill(thread, SIGUSR1);
192
193                 write(stdin_pipe[1], &c, 1);
194         }
195         pthread_exit(NULL);
196         return NULL;
197 }
198
199 void *hostsim_uart_stdout(void *arg)
200 {
201         pthread_t thread = (pthread_t)arg;
202         int n;
203         char c;
204
205         /* read on our pipe, and forward it to the old stdout */
206         while (1) {
207                 n = read(stdout_pipe[0], &c, 1);
208                 if (n <= 0)
209                         break;
210
211                 pthread_mutex_lock(&mut);
212                 g_msg.type = UART_SND;
213                 g_msg.c = c;
214                 pthread_kill(thread, SIGUSR1);
215
216                 write(old_stdout, &c, 1);
217         }
218         pthread_exit(NULL);
219         return NULL;
220 }
221
222 int hostsim_uart_init(void)
223 {
224         struct termios term;
225
226         tcgetattr(0, &oldterm);
227         memcpy(&term, &oldterm, sizeof(term));
228         term.c_lflag &= ~(ICANON | ECHO | ISIG);
229         tcsetattr(0, TCSANOW, &term);
230
231         /* duplicate stdin */
232         old_stdin = dup(0);
233         if (old_stdin < 0)
234                 return 1;
235
236         /* duplicate stdout */
237         old_stdout = dup(1);
238         if (old_stdout < 0)
239                 return -1;
240
241         /* create 2 pipes */
242         if (pipe(stdin_pipe) < 0)
243                 return -1;
244         if (pipe(stdout_pipe) < 0)
245                 return -1;
246
247         /* replace file desc 0 (stdin) by our pipe */
248         if (dup2(stdin_pipe[0], 0) < 0)
249                 return -1;
250         close(stdin_pipe[0]);
251
252         /* replace file desc 1 (stdout) by our pipe */
253         if (dup2(stdout_pipe[1], 1) < 0)
254                 return -1;
255         close(stdout_pipe[1]);
256         setbuf(stdin, NULL);
257         setbuf(stdout, NULL);
258
259         return 0;
260 }
261
262 int hostsim_init(void)
263 {
264         struct sigaction sigact;
265         pthread_t parent_id, child_id, child2_id, child3_id;
266         int ret;
267
268         parent_id = pthread_self();
269
270         pthread_mutex_lock(&mut);
271         ret = pthread_create(&child_id, NULL, parent, (void *)parent_id);
272         if (ret) {
273                 printf("pthread_create() returned %d\n", ret);
274                 pthread_mutex_unlock(&mut);
275                 return -1;
276         }
277
278 #ifdef CONFIG_MODULE_UART
279         if (hostsim_uart_init())
280                 return -1;
281
282         ret = pthread_create(&child2_id, NULL, hostsim_uart_stdin, (void *)parent_id);
283         if (ret) {
284                 printf("pthread_create() returned %d\n", ret);
285                 pthread_mutex_unlock(&mut);
286                 return -1;
287         }
288         ret = pthread_create(&child3_id, NULL, hostsim_uart_stdout, (void *)parent_id);
289         if (ret) {
290                 printf("pthread_create() returned %d\n", ret);
291                 pthread_mutex_unlock(&mut);
292                 return -1;
293         }
294 #endif
295
296         /* register a signal handler, which is interruptible */
297         memset(&sigact, 0, sizeof(sigact));
298         sigemptyset(&sigact.sa_mask);
299         sigact.sa_flags |= SA_NODEFER;
300         sigact.sa_sigaction = sigusr1;
301         sigaction(SIGUSR1, &sigact, NULL);
302
303         /* */
304         if (siginterrupt (SIGUSR1, 0) != 0)
305                 return -1;
306
307         pthread_mutex_unlock(&mut);
308
309         return 0;
310 }
311
312 int hostsim_exit(void)
313 {
314 #ifdef CONFIG_MODULE_UART
315         tcsetattr(0, TCSANOW, &oldterm);
316 #endif
317         return 0;
318 }
319 #endif /* HOST_VERSION */