OpenCores
URL https://opencores.org/ocsvn/s6soc/s6soc/trunk

Subversion Repositories s6soc

[/] [s6soc/] [trunk/] [sw/] [zipos/] [doorbell.c] - Blame information for rev 22

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 22 dgisselq
////////////////////////////////////////////////////////////////////////////////
2
//
3
// Filename:    doorbell.c
4
//
5
// Project:     CMod S6 System on a Chip, ZipCPU demonstration project
6
//
7
// Purpose:     
8
//
9
// Creator:     Dan Gisselquist, Ph.D.
10
//              Gisselquist Technology, LLC
11
//
12
////////////////////////////////////////////////////////////////////////////////
13
//
14
// Copyright (C) 2015-2016, Gisselquist Technology, LLC
15
//
16
// This program is free software (firmware): you can redistribute it and/or
17
// modify it under the terms of  the GNU General Public License as published
18
// by the Free Software Foundation, either version 3 of the License, or (at
19
// your option) any later version.
20
//
21
// This program is distributed in the hope that it will be useful, but WITHOUT
22
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or
23
// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
24
// for more details.
25
//
26
// You should have received a copy of the GNU General Public License along
27
// with this program.  (It's in the $(ROOT)/doc directory, run make with no
28
// target there if the PDF file isn't present.)  If not, see
29
// <http://www.gnu.org/licenses/> for a copy.
30
//
31
// License:     GPL, v3, as defined and found on www.gnu.org,
32
//              http://www.gnu.org/licenses/gpl.html
33
//
34
//
35
////////////////////////////////////////////////////////////////////////////////
36
//
37
//
38
#include "zipsys.h"
39
#include "board.h"
40
#include "ksched.h"
41
#include "kfildes.h"
42
#include "taskp.h"
43
#include "syspipe.h"
44
#include "ktraps.h"
45
#include "errno.h"
46
#include "swint.h"
47
 
48
#include "../dev/display.h"
49
#include "../dev/rtcsim.h"
50
 
51
/* Our system will need some pipes to handle ... life.  How about these:
52
 *
53
 *      rxpipe  - read()s from this pipe read from the UART
54
 *                      Interrupt fed
55
 *      txpipe  - write()s to this pipe write to the UART
56
 *                      Interrupt consumed
57
 *      keypipe - read()s from this pipe return values read by the keypad
58
 *      lcdpipe - write()s to this pipe write to the LCD display SPI port
59
 *      pwmpipe - write()s to this pipe will send values to the audio port
60
 *                      Interrupt consumed
61
 *      cmdpipe - written to by the user command task, read by the display task
62
 *              used to communicate menu status
63
 *
64
 */
65
 
66
/* We'll need some tasks as well:
67
 *      User command task
68
 *              Handles user interaction
69
 *                      Reads from pipe--either the keypad or the UARTRX pipe
70
 *                      (Might be two such tasks in the system, one for each.)
71
 *              Sets clock upon request
72
 *              Reads from a pipe (rxpipe or keypipe), Writes to the txpipe pipe
73
 *      Doorbell task
74
 *              Maintains system time on the clock      : TIME: HH:MM:SS
75
 *              Maintains system status on display      : Light is (dis/en)abled
76
 *              Transitions when the doorbell is rung to: (fixed time line)
77
 *                                                      : DOORBELL!!
78
 *              When the doorbell is clear, returns to the original task.
79
 *              ---
80
 *              Waits on events, writes to the lcdpipe and pwmpipe.
81
 *              Reads from a command pipe, so that it can handle any user menu's
82
 *                      Command pipe.  This, though, is tricky.  It requires
83
 *                      a task that can be interrupted by either an event or a
84
 *                      pipe.  Blocking is going to be more tricky ...
85
 *      Keypad task
86
 *              Normally, you might think this should be an interrupt task.
87
 *              But, it needs state in order to have timeouts and to debounce
88
 *              the input pin.  So ... let's leave this as a task.
89
 *              ---
90
 *              Waits on events(keypad/timer), writes to the keypipe
91
 *      Display task
92
 *              The display does *not* need to be written to at an interrupt
93
 *              level.  It really needs to be written to at a task level, so
94
 *              let's make a display task.
95
 *              ---
96
 *              Reads from the lcdpipe
97
 *      Real-time Clock Task
98
 *              Gets called once per second to update the real-time clock
99
 *              and to post those updates as an event to other tasks that might
100
 *              be interested in it.
101
 *              ---
102
 *              Waits on system tasks, uses two semaphores
103
 */
104
 
105
 
106
/*
107
 * Read the keypad, write the results to an output pipe
108
 */
109
// #define      KEYPAD_TASK     keypad_task_id
110
/*
111
 * Maintain a realtime clock
112
 */
113
#define RTCCLOCK_TASK   rtccclock_task_id
114
/*
115
 * Read from an incoming pipe, write results to the SPI port controlling the
116
 * display.
117
 */
118
#define DISPLAY_TASK    display_task_id
119
 
120
/*
121
 * Wait for a button press, and then based upon the clock set a light
122
 */
123
#define DOORBELL_TASK   doorbell_task_id
124
 
125
/*
126
 * Interract with any user commands, such as setting the clock, setting
127
 * nighttime (when the lights turn on) or setting daytime when only the
128
 * doorbell rings.
129
 */
130
// #define      COMMAND_TASK    command_task_id
131
#define LAST_TASK       last_task_id
132
 
133
typedef enum    {
134
#ifdef  RTCCLOCK_TASK
135
        RTCCLOCK_TASK,
136
#endif
137
#ifdef  DOORBELL_TASK
138
#ifdef  DISPLAY_TASK
139
        DOORBELL_TASK, DISPLAY_TASK,
140
#endif
141
#endif
142
#ifdef  KEYPAD_TASK
143
        KEYPAD_TASK,
144
#endif
145
#ifdef  COMMAND_TASK
146
        COMMAND_TASK,
147
#endif
148
        LAST_TASK
149
} TASKNAME;
150
 
151
 
152
void    rtctask(void),
153
        doorbell_task(void),
154
        display_task(void),
155
        keypad_task(void),
156
        command_task(void);
157
        // idle_task ... is accomplished within the kernel
158
extern  void    restore_context(int *), save_context(int *);
159
extern  SYSPIPE *rxpipe, *txpipe, *pwmpipe, *lcdpipe;
160
SYSPIPE *midpipe;
161
extern  KDEVICE *pipedev;
162
 
163
int     kntasks(void) {
164
        return LAST_TASK;
165
} void  kinit(TASKP *tasklist) {
166
#ifdef  RTCCLOCK_TASK
167
        //
168
        tasklist[RTCCLOCK_TASK]    = new_task(16, rtctask);
169
#endif
170
 
171
#ifdef  DOORBELL_TASK
172
#ifdef  DISPLAY_TASK
173
        //
174
        tasklist[DOORBELL_TASK]    = new_task(64, doorbell_task);
175
        tasklist[DOORBELL_TASK]->fd[FILENO_STDOUT] = sys_malloc(sizeof(KFILDES));
176
                tasklist[DOORBELL_TASK]->fd[FILENO_STDOUT]->id = (int)lcdpipe;
177
                tasklist[DOORBELL_TASK]->fd[FILENO_STDOUT]->dev= pipedev;
178
        tasklist[DOORBELL_TASK]->fd[FILENO_AUX] = sys_malloc(sizeof(KFILDES));
179
                tasklist[DOORBELL_TASK]->fd[FILENO_AUX]->id = (int)pwmpipe;
180
                tasklist[DOORBELL_TASK]->fd[FILENO_AUX]->dev= pipedev;
181
 
182
        //
183
        tasklist[DISPLAY_TASK] = new_task(32, display_task);
184
        tasklist[DISPLAY_TASK]->fd[FILENO_STDIN] = sys_malloc(sizeof(KFILDES));
185
                tasklist[DISPLAY_TASK]->fd[FILENO_STDIN]->id = (int)lcdpipe;
186
                tasklist[DISPLAY_TASK]->fd[FILENO_STDIN]->dev= pipedev;
187
#endif
188
#endif
189
 
190
 
191
#ifdef  KEYPAD_TASK
192
        tasklist[KEYPAD_TASK]    = new_task(16, keypad_task);
193
        tasklist[KEYPAD_TASK]->fd[FILENO_STDOUT] = sys_malloc(sizeof(KFILDES));
194
                tasklist[NMEA_TASK]->fd[FILENO_STDOUT]->id = (int)keypipe;
195
                tasklist[NMEA_TASK]->fd[FILENO_STDOUT]->dev= pipedev;
196
#endif
197
}
198
 
199
#ifdef DOORBELL_TASK
200
// #define      HALF_HOUR_S     1800    // Seconds per half hour
201
// #define      HALF_HOUR_S     180     // Seconds per three minutes--for test
202
#define HALF_HOUR_S     30      // 3 Mins is to long, here's 3 seconds
203
 
204
#include "../dev/samples.c"
205
 
206
const unsigned  dawn = 0x060000, dusk = 0x180000;
207
 
208
void    shownow(unsigned now) { // Uses 10 stack slots + 8 for write()
209
        char    dmsg[9];
210
        dmsg[0] = PACK(0x1b,'[','j','T');
211
        dmsg[1] = PACK('i','m','e',':');
212
        dmsg[2] = PACK(' ',((now>>20)&0x3)+'0',
213
                        ((now>>16)&0xf)+'0',':');
214
        dmsg[3] = PACK( ((now>>12)&0xf)+'0',
215
                        ((now>> 8)&0xf)+'0',
216
                        ':',
217
                        ((now>> 4)&0xf)+'0');
218
        dmsg[4] = PACK( ((now    )&0xf)+'0',
219
                        0x1b, '[', '1');
220
        dmsg[5] = PACK(';','0','H',' ');
221
        if ((now < dawn)||(now > dusk)) {
222
                dmsg[6] = PACK('N','i','g','h');
223
                dmsg[7] = PACK('t',' ','t','i');
224
                dmsg[8] = PACK('m','e',0,0);
225
        } else {
226
                dmsg[6] = PACK('D','a','y','l');
227
                dmsg[7] = PACK('i','g','h','t');
228
                dmsg[8] = PACK('!',' ',0,0);
229
        } write(FILENO_STDOUT, dmsg, 9);
230
}
231
 
232
void    showbell(unsigned now) {        // Uses 10 stack slots + 8 for write()
233
        char    dmsg[9];
234
        dmsg[0] = PACK(0x1b,'[','j','T');
235
        dmsg[1] = PACK('i','m','e',':');
236
        dmsg[2] = PACK(' ',((now>>20)&0x3)+'0',
237
                        ((now>>16)&0xf)+'0',':');
238
        dmsg[3] = PACK( ((now>>12)&0xf)+'0',
239
                        ((now>> 8)&0xf)+'0',
240
                        ':',
241
                        ((now>> 4)&0xf)+'0');
242
        dmsg[4] = PACK( ((now    )&0xf)+'0',
243
                        0x1b, '[', '1');
244
        dmsg[5] = PACK(';','0','H',' ');
245
        dmsg[6] = PACK('D','o','o','r');
246
        dmsg[7] = PACK('b','e','l','l');
247
        dmsg[8] = PACK('!',' ',0,0);
248
        write(FILENO_STDOUT, dmsg, 9);
249
}
250
 
251
void    belllight(unsigned now) {
252
        IOSPACE *sys = (IOSPACE *)IOADDR;
253
        if ((now < dawn)||(now > dusk))
254
                sys->io_spio = 0x088; // Turn our light on
255
        else
256
                sys->io_spio = 0x80; // Turn light off
257
}
258
 
259
void    doorbell_task(void) {
260
        // Controls LED 0x08
261
 
262
        // Start by initializing the display to GT Gisselquist\nTechnology
263
        // write(KFD_STDOUT, disp_build_backslash,sizeof(disp_build_backslash));
264
        // write(KFD_STDOUT, disp_build_gtlogo, sizeof(disp_build_gtlogo));
265
        // write(KFD_STDOUT, disp_reset_data, sizeof(disp_reset_data));
266
        // write(KFD_STDOUT, disp_gtech_data, sizeof(disp_gtech_data));
267
 
268
        IOSPACE *sys = (IOSPACE *)IOADDR;
269
 
270
        while(1) {
271
                int     event;
272
                // Initial state: doorbell is not ringing.  In this state, we
273
                // can wait forever for an event
274
                sys->io_spio = 0x080; // Turn our light off
275
                event = wait(INT_BUTTON|SWINT_PPS,-1);
276
                unsigned when = rtcclock;
277
                if (event & INT_BUTTON)
278
                        showbell(when);
279
                else if (event & SWINT_PPS)
280
                        shownow(when);
281
 
282
                while(event & INT_BUTTON) {
283
                        // Next state, the button has been pressed, the
284
                        // doorbell is ringing
285
 
286
                        // Seconds records the number of seconds since the
287
                        // button was last pressed.
288
                        int     seconds = 0;
289
 
290
                        // Check time: should we turn our light on or not?
291
                        belllight(rtcclock);
292
                        const int *sptr = sound_data;
293
                        sys->io_uart = 'N';
294
                        while(sptr < &sound_data[NSAMPLE_WORDS]) {
295
                                int     len = &sound_data[NSAMPLE_WORDS]-sptr;
296
                                if (len > 256)
297
                                        len = 256;
298
 
299
                                // We stall here, if the audio FIFO is full
300
                                write(FILENO_AUX, sptr, len);
301
                                sptr += len;
302
                                // If the user presses the button more than
303
                                // once, we start the sound over as well as
304
                                // our light counter.
305
                                event = wait(INT_BUTTON|SWINT_PPS, 0);
306
                                if (event&INT_BUTTON) {
307
                                        if (sptr > &sound_data[2048]) {
308
                                                sptr = sound_data;
309
                                                seconds = 0;
310
                                                when = (volatile unsigned)rtcclock;
311
                                                showbell(when);
312
                                        }
313
                                } else if (event&SWINT_PPS) {
314
                                        seconds++;
315
                                        belllight(rtcclock);
316
                                        showbell(when);
317
                                }
318
                        }
319
 
320
                        sys->io_uart = 'D';
321
 
322
                        // Next state: the doorbell is no longer ringing, but
323
                        // we have yet to return to normal--the light is still
324
                        // on.
325
                        while((seconds < HALF_HOUR_S)&&
326
                                (((event=wait(INT_BUTTON|SWINT_PPS,-1))&INT_BUTTON)==0)) {
327
                                seconds++;
328
                                belllight(rtcclock);
329
                                showbell(when);
330
                        }
331
                        if (event&INT_BUTTON) {
332
                                when = (volatile unsigned)rtcclock;
333
                                showbell(when);
334
                                sys->io_uart = 'S';
335
                        }
336
                }
337
        }
338
}
339
#endif
340
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.