e8a02f342093578e3e29c70bb635a07ca7cca84a
[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 static pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER;
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 static int lock_count = 0;
66
67 void hostsim_lock(void)
68 {
69         if (lock_count++)
70                 return;
71         pthread_mutex_lock(&mut);
72 }
73
74 void hostsim_unlock(void)
75 {
76         if (lock_count-- == 1)
77                 pthread_mutex_unlock(&mut);
78 }
79
80 int hostsim_islocked(void)
81 {
82         return lock_count;
83 }
84
85 void host_wait_ms(int ms)
86 {
87         struct timeval tv, tv2, diff;
88
89         gettimeofday(&tv, NULL);
90         diff.tv_sec = (1000 * ms) / 1000000;
91         diff.tv_usec = (1000 * ms) % 1000000;
92         timeradd(&tv, &diff, &tv);
93         gettimeofday(&tv2, NULL);
94
95         while (timercmp(&tv2, &tv, <)) {
96                 usleep(1000);
97                 gettimeofday(&tv2, NULL);
98         }
99 }
100
101
102 /* sends signal to child */
103 void *parent(void *arg)
104 {
105         pthread_t *thread = arg;
106         struct timeval cur_tv, prev_tv, tv_millisec;
107         int n;
108
109         gettimeofday(&prev_tv, NULL);
110
111         while (1) {
112                 usleep(1000);
113                 gettimeofday(&cur_tv, NULL);
114
115                 n = 0;
116                 while (timercmp(&prev_tv, &cur_tv, <)) {
117                         if (n > 5) {
118                                 /* give some time between subsequent
119                                  * signals */
120                                 usleep(100);
121                                 n = 0;
122                         }
123                         pthread_mutex_lock(&mut);
124                         pthread_kill(*thread, SIGUSR1);
125
126                         /* signal was acked */
127                         tv_millisec.tv_sec = 0;
128                         tv_millisec.tv_usec = 1000;
129                         timeradd(&prev_tv, &tv_millisec, &prev_tv);
130                         n ++;
131                 }
132         }
133
134         pthread_exit(NULL);
135         return NULL;
136 }
137
138 int hostsim_init(void)
139 {
140         struct sigaction sigact;
141         pthread_t parent_id, child_id;
142         int ret;
143
144         parent_id = pthread_self();
145
146         pthread_mutex_lock(&mut);
147         ret = pthread_create(&child_id, NULL, parent, (void *)parent_id);
148         if (ret) {
149                 printf("pthread_create() returned %d\n", ret);
150                 pthread_mutex_unlock(&mut);
151                 return -1;
152         }
153
154         /* register a signal handler, which is interruptible */
155         memset(&sigact, 0, sizeof(sigact));
156         sigemptyset(&sigact.sa_mask);
157         sigact.sa_flags |= SA_NODEFER;
158         sigact.sa_sigaction = sigusr1;
159         sigaction(SIGUSR1, &sigact, NULL);
160
161         /* */
162         if (siginterrupt (SIGUSR1, 0) != 0)
163                 return -1;
164
165         printf("hostsim_init()\n", ret);
166         pthread_mutex_unlock(&mut);
167
168         return 0;
169 }
170 #endif /* HOST_VERSION */