850d23a59f7e1d7331f2599362d17e514da4b343
[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 <string.h>
38 #include <pthread.h>
39 #include <sys/time.h>
40 #include <sys/types.h>
41 #include <sys/wait.h>
42
43 #ifdef CONFIG_MODULE_SCHEDULER
44 #include <scheduler.h>
45 #endif
46
47 pthread_mutex_t mut;
48 static volatile int cpt = 0;
49
50 #ifdef SA_SIGINFO
51 static void sigusr1(__attribute__((unused)) int sig,
52                     __attribute__((unused)) siginfo_t *info,
53                     __attribute__((unused)) void *uc)
54 #else
55 void sigusr1(__attribute__((unused)) int sig)
56 #endif
57 {
58         pthread_mutex_unlock(&mut);
59
60 #ifdef CONFIG_MODULE_SCHEDULER
61         scheduler_interrupt();
62 #endif
63 }
64
65 void host_wait_ms(int ms)
66 {
67         struct timeval tv, tv2, diff;
68
69         gettimeofday(&tv, NULL);
70         diff.tv_sec = (1000 * ms) / 1000000;
71         diff.tv_usec = (1000 * ms) % 1000000;
72         timeradd(&tv, &diff, &tv);
73         gettimeofday(&tv2, NULL);
74
75         while (timercmp(&tv2, &tv, <)) {
76                 usleep(1000);
77                 gettimeofday(&tv2, NULL);
78         }
79 }
80
81
82 /* sends signal to child */
83 void *parent(void *arg)
84 {
85         pthread_t *thread = arg;
86         struct timeval cur_tv, prev_tv, tv_millisec;
87         int n;
88
89         gettimeofday(&prev_tv, NULL);
90
91         while (1) {
92                 usleep(1000);
93                 gettimeofday(&cur_tv, NULL);
94
95                 n = 0;
96                 while (timercmp(&prev_tv, &cur_tv, <)) {
97                         if (n > 5) {
98                                 /* give some time between subsequent
99                                  * signals */
100                                 usleep(100);
101                                 n = 0;
102                         }
103                         pthread_mutex_lock(&mut);
104                         pthread_kill(*thread, SIGUSR1);
105
106                         /* signal was acked */
107                         tv_millisec.tv_sec = 0;
108                         tv_millisec.tv_usec = 1000;
109                         timeradd(&prev_tv, &tv_millisec, &prev_tv);
110                         n ++;
111                 }
112         }
113
114         pthread_exit(NULL);
115         return NULL;
116 }
117
118 int hostsim_init(void)
119 {
120         struct sigaction sigact;
121         pthread_t parent_id, child_id;
122         int ret;
123
124         pthread_mutex_init(&mut, NULL);
125
126         parent_id = pthread_self();
127
128         pthread_mutex_lock(&mut);
129         ret = pthread_create(&child_id, NULL, parent, (void *)&parent_id);
130         if (ret) {
131                 printf("pthread_create() returned %d\n", ret);
132                 pthread_mutex_unlock(&mut);
133                 return -1;
134         }
135
136         /* register a signal handler, which is interruptible */
137         memset(&sigact, 0, sizeof(sigact));
138         sigemptyset(&sigact.sa_mask);
139         sigact.sa_flags |= SA_NODEFER;
140         sigact.sa_sigaction = sigusr1;
141         sigaction(SIGUSR1, &sigact, NULL);
142
143         /* */
144         if (siginterrupt (SIGUSR1, 0) != 0)
145                 return -1;
146
147         pthread_mutex_unlock(&mut);
148
149         return 0;
150 }
151 #endif /* HOST_VERSION */