-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathpelican.c
165 lines (142 loc) · 3.89 KB
/
pelican.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <libdill.h>
#include "bp.h"
#include "io_util.h"
#include "logging.h"
static const ev_t EV_CARS_YELLOW = 1UL << 0;
static const ev_t EV_PEDS_WALK = 1UL << 1;
static const ev_t EV_CARS_GREEN = 1UL << 2;
static const ev_t EV_LIGHT_TIMEOUT = 1UL << 4;
static const ev_t EV_PEDS_BUTTON = 1UL << 5;
static const ev_t EV_PEDS_OFF = 1UL << 6;
static int ext_ev_ch;
const char *ev_to_str(ev_t ev)
{
if (ev == EV_CARS_YELLOW)
{
return "EV_CARS_YELLOW";
}
else if (ev == EV_PEDS_WALK)
{
return "EV_PEDS_WALK";
}
else if (ev == EV_CARS_GREEN)
{
return "EV_CARS_GREEN";
}
else if (ev == EV_PEDS_WALK)
{
return "EV_PEDS_WALK";
}
else if (ev == EV_LIGHT_TIMEOUT)
{
return "EV_LIGHT_TIMEOUT";
}
else if (ev == EV_PEDS_BUTTON)
{
return "EV_PEDS_BUTTON";
}
else if (ev == EV_PEDS_OFF)
{
return "EV_PEDS_OFF";
}
else
{
return "Unknown";
}
}
// the main behavior of the pelican crossing
// is cycling the lights in order
static void bt_cycle(bt_ctx_t *ctx, void *user_ctx)
{
while (true)
{
bt_sync(ctx, EV_CARS_GREEN, EV_NONE, EV_NONE);
bt_sync(ctx, EV_CARS_YELLOW, EV_NONE, EV_NONE);
bt_sync(ctx, EV_PEDS_WALK, EV_NONE, EV_NONE);
for (size_t i = 0; i < 3; i++)
{
// Flash pedestrian light
bt_sync(ctx, EV_PEDS_OFF, EV_NONE, EV_NONE);
bt_sync(ctx, EV_PEDS_WALK, EV_NONE, EV_NONE);
}
bt_sync(ctx, EV_PEDS_OFF, EV_NONE, EV_NONE);
}
}
// the light changes are interspersed by time delays
static void bt_intersperse(bt_ctx_t *ctx, void *user_ctx)
{
int64_t tmout;
while (true)
{
// on EV_CARS_YELLOW, or EV_PEDS_WALK, or EV_PEDS_OFF
ev_t ev = bt_sync(ctx, EV_NONE, EV_CARS_YELLOW | EV_PEDS_WALK | EV_PEDS_OFF, EV_NONE);
if (ev == EV_CARS_YELLOW)
{
tmout = 3000;
}
else if (ev == EV_PEDS_OFF)
{
tmout = 500;
}
// start a timeout timer
start_timer(EV_LIGHT_TIMEOUT, tmout);
// wait for the timer event while blocking the successive events
bt_sync(ctx, EV_NONE, EV_LIGHT_TIMEOUT, EV_PEDS_WALK | EV_PEDS_OFF | EV_CARS_GREEN);
}
}
// light cycling sequence is started by pressing the
// "pedestrian waiting" button and the next cycle can
// only start afte 'cars green' light
static void bt_trigger(bt_ctx_t *ctx, void *user_ctx)
{
while (true)
{
bt_sync(ctx, EV_NONE, EV_PEDS_BUTTON, EV_CARS_YELLOW);
bt_sync(ctx, EV_NONE, EV_CARS_GREEN, EV_PEDS_BUTTON);
}
}
// makes sure cars have guaranteed minimal time
// of green light
static void bt_min_cars_green(bt_ctx_t *ctx, void *user_ctx)
{
while (true)
{
// after 'cars green' block 'cars yellow'
// for 5s
bt_sync(ctx, EV_NONE, EV_CARS_GREEN, EV_NONE);
start_timer(EV_LIGHT_TIMEOUT, 5000);
bt_sync(ctx, EV_NONE, EV_LIGHT_TIMEOUT, EV_CARS_YELLOW);
}
}
static ev_t external_ev_clbk(void)
{
int rc;
ev_t ev;
rc = chrecv(ext_ev_ch, &ev, sizeof(ev_t), -1);
log_assert(rc == 0);
return ev;
}
static ev_t key_decoder(char key)
{
return EV_PEDS_BUTTON;
}
int main(int argc, char *argv[])
{
const bt_init_t bthreads[] = {{bt_cycle, NULL},
{bt_intersperse, NULL},
{bt_trigger, NULL},
{bt_min_cars_green, NULL}};
const size_t n = sizeof(bthreads) / sizeof(bthreads[0]);
logging_init();
ext_ev_ch = prepare_ext_event_pipeline(key_decoder);
bp_ctx_t *bp_ctx = bp_new(bthreads, n, external_ev_clbk, NULL);
log_assert(bp_ctx);
LOG(INFO, "Starting");
bp_run(bp_ctx);
bp_destroy(&bp_ctx);
LOG(INFO, "Stopping");
exit(EXIT_SUCCESS);
}