URL
https://opencores.org/ocsvn/s6soc/s6soc/trunk
Subversion Repositories s6soc
[/] [s6soc/] [trunk/] [sw/] [zipos/] [doorbell.c] - Rev 27
Go to most recent revision | Compare with Previous | Blame | View Log
//////////////////////////////////////////////////////////////////////////////// // // Filename: doorbell.c // // Project: CMod S6 System on a Chip, ZipCPU demonstration project // // Purpose: // // Creator: Dan Gisselquist, Ph.D. // Gisselquist Technology, LLC // //////////////////////////////////////////////////////////////////////////////// // // Copyright (C) 2015-2016, Gisselquist Technology, LLC // // This program is free software (firmware): you can redistribute it and/or // modify it under the terms of the GNU General Public License as published // by the Free Software Foundation, either version 3 of the License, or (at // your option) any later version. // // This program is distributed in the hope that it will be useful, but WITHOUT // ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License // for more details. // // You should have received a copy of the GNU General Public License along // with this program. (It's in the $(ROOT)/doc directory, run make with no // target there if the PDF file isn't present.) If not, see // <http://www.gnu.org/licenses/> for a copy. // // License: GPL, v3, as defined and found on www.gnu.org, // http://www.gnu.org/licenses/gpl.html // // //////////////////////////////////////////////////////////////////////////////// // // #include "zipsys.h" #include "board.h" #include "ksched.h" #include "kfildes.h" #include "taskp.h" #include "syspipe.h" #include "ktraps.h" #include "errno.h" #include "swint.h" #include "../dev/display.h" #include "../dev/rtcsim.h" /* Our system will need some pipes to handle ... life. How about these: * * rxpipe - read()s from this pipe read from the UART * Interrupt fed * txpipe - write()s to this pipe write to the UART * Interrupt consumed * keypipe - read()s from this pipe return values read by the keypad * lcdpipe - write()s to this pipe write to the LCD display SPI port * pwmpipe - write()s to this pipe will send values to the audio port * Interrupt consumed * cmdpipe - written to by the user command task, read by the display task * used to communicate menu status * */ /* We'll need some tasks as well: * User command task * Handles user interaction * Reads from pipe--either the keypad or the UARTRX pipe * (Might be two such tasks in the system, one for each.) * Sets clock upon request * Reads from a pipe (rxpipe or keypipe), Writes to the txpipe pipe * Doorbell task * Maintains system time on the clock : TIME: HH:MM:SS * Maintains system status on display : Light is (dis/en)abled * Transitions when the doorbell is rung to: (fixed time line) * : DOORBELL!! * When the doorbell is clear, returns to the original task. * --- * Waits on events, writes to the lcdpipe and pwmpipe. * Reads from a command pipe, so that it can handle any user menu's * Command pipe. This, though, is tricky. It requires * a task that can be interrupted by either an event or a * pipe. Blocking is going to be more tricky ... * Keypad task * Normally, you might think this should be an interrupt task. * But, it needs state in order to have timeouts and to debounce * the input pin. So ... let's leave this as a task. * --- * Waits on events(keypad/timer), writes to the keypipe * Display task * The display does *not* need to be written to at an interrupt * level. It really needs to be written to at a task level, so * let's make a display task. * --- * Reads from the lcdpipe * Real-time Clock Task * Gets called once per second to update the real-time clock * and to post those updates as an event to other tasks that might * be interested in it. * --- * Waits on system tasks, uses two semaphores */ /* * Read the keypad, write the results to an output pipe */ // #define KEYPAD_TASK keypad_task_id /* * Maintain a realtime clock */ #define RTCCLOCK_TASK rtccclock_task_id /* * Read from an incoming pipe, write results to the SPI port controlling the * display. */ #define DISPLAY_TASK display_task_id /* * Wait for a button press, and then based upon the clock set a light */ #define DOORBELL_TASK doorbell_task_id /* * Interract with any user commands, such as setting the clock, setting * nighttime (when the lights turn on) or setting daytime when only the * doorbell rings. */ // #define COMMAND_TASK command_task_id #define LAST_TASK last_task_id typedef enum { #ifdef RTCCLOCK_TASK RTCCLOCK_TASK, #endif #ifdef DOORBELL_TASK #ifdef DISPLAY_TASK DOORBELL_TASK, DISPLAY_TASK, #endif #endif #ifdef KEYPAD_TASK KEYPAD_TASK, #endif #ifdef COMMAND_TASK COMMAND_TASK, #endif LAST_TASK } TASKNAME; void rtctask(void), doorbell_task(void), display_task(void), keypad_task(void), command_task(void); // idle_task ... is accomplished within the kernel extern void restore_context(int *), save_context(int *); extern SYSPIPE *rxpipe, *txpipe, *pwmpipe, *lcdpipe; SYSPIPE *midpipe; extern KDEVICE *pipedev; int kntasks(void) { return LAST_TASK; } void kinit(TASKP *tasklist) { #ifdef RTCCLOCK_TASK // tasklist[RTCCLOCK_TASK] = new_task(16, rtctask); #endif #ifdef DOORBELL_TASK #ifdef DISPLAY_TASK // 13 + 10 +9(uwrite)+4(uarthex)+2(uartstr)+2(uartchr) tasklist[DOORBELL_TASK] = new_task(64, doorbell_task); tasklist[DOORBELL_TASK]->fd[FILENO_STDOUT] = sys_malloc(sizeof(KFILDES)); tasklist[DOORBELL_TASK]->fd[FILENO_STDOUT]->id = (int)lcdpipe; tasklist[DOORBELL_TASK]->fd[FILENO_STDOUT]->dev= pipedev; tasklist[DOORBELL_TASK]->fd[FILENO_STDERR] = sys_malloc(sizeof(KFILDES)); tasklist[DOORBELL_TASK]->fd[FILENO_STDERR]->id = (int)txpipe; tasklist[DOORBELL_TASK]->fd[FILENO_STDERR]->dev= pipedev; tasklist[DOORBELL_TASK]->fd[FILENO_AUX] = sys_malloc(sizeof(KFILDES)); tasklist[DOORBELL_TASK]->fd[FILENO_AUX]->id = (int)pwmpipe; tasklist[DOORBELL_TASK]->fd[FILENO_AUX]->dev= pipedev; // tasklist[DISPLAY_TASK] = new_task(32, display_task); tasklist[DISPLAY_TASK]->fd[FILENO_STDIN] = sys_malloc(sizeof(KFILDES)); tasklist[DISPLAY_TASK]->fd[FILENO_STDIN]->id = (int)lcdpipe; tasklist[DISPLAY_TASK]->fd[FILENO_STDIN]->dev= pipedev; #endif #endif #ifdef KEYPAD_TASK tasklist[KEYPAD_TASK] = new_task(16, keypad_task); tasklist[KEYPAD_TASK]->fd[FILENO_STDOUT] = sys_malloc(sizeof(KFILDES)); tasklist[NMEA_TASK]->fd[FILENO_STDOUT]->id = (int)keypipe; tasklist[NMEA_TASK]->fd[FILENO_STDOUT]->dev= pipedev; #endif } #ifdef DOORBELL_TASK // #define HALF_HOUR_S 1800 // Seconds per half hour // #define HALF_HOUR_S 180 // Seconds per three minutes--for test #define HALF_HOUR_S 30 // 3 Mins is to long, here's 3 seconds #include "../dev/samples.c" const unsigned dawn = 0x060000, dusk = 0x180000; int nwritten = 0, nread = 0, nstarts = 0; void shownow(unsigned now) { // Uses 10 stack slots + 8 for write() char dmsg[9]; dmsg[0] = PACK(0x1b,'[','j','T'); dmsg[1] = PACK('i','m','e',':'); dmsg[2] = PACK(' ',((now>>20)&0x3)+'0', ((now>>16)&0xf)+'0',':'); dmsg[3] = PACK( ((now>>12)&0xf)+'0', ((now>> 8)&0xf)+'0', ':', ((now>> 4)&0xf)+'0'); dmsg[4] = PACK( ((now )&0xf)+'0', 0x1b, '[', '1'); dmsg[5] = PACK(';','0','H',' '); if ((now < dawn)||(now > dusk)) { dmsg[6] = PACK('N','i','g','h'); dmsg[7] = PACK('t',' ','t','i'); dmsg[8] = PACK('m','e',0,0); } else { dmsg[6] = PACK('D','a','y','l'); dmsg[7] = PACK('i','g','h','t'); dmsg[8] = PACK('!',' ',0,0); } write(FILENO_STDOUT, dmsg, 9); } void showbell(unsigned now) { // Uses 10 stack slots + 8 for write() char dmsg[9]; dmsg[0] = PACK(0x1b,'[','j','T'); dmsg[1] = PACK('i','m','e',':'); dmsg[2] = PACK(' ',((now>>20)&0x3)+'0', ((now>>16)&0xf)+'0',':'); dmsg[3] = PACK( ((now>>12)&0xf)+'0', ((now>> 8)&0xf)+'0', ':', ((now>> 4)&0xf)+'0'); dmsg[4] = PACK( ((now )&0xf)+'0', 0x1b, '[', '1'); dmsg[5] = PACK(';','0','H',' '); dmsg[6] = PACK('D','o','o','r'); dmsg[7] = PACK('b','e','l','l'); dmsg[8] = PACK('!',' ',0,0); write(FILENO_STDOUT, dmsg, 9); } void belllight(unsigned now) { IOSPACE *sys = (IOSPACE *)IOADDR; if ((now < dawn)||(now > dusk)) sys->io_spio = 0x088; // Turn our light on else sys->io_spio = 0x80; // Turn light off } void uartchr(char v) { if (write(FILENO_STDERR, &v, 1) != 1) write(FILENO_STDERR, "APPLE-PANIC", 11); } void uartstr(const char *str) { int cnt=0; while(str[cnt]) cnt++; if (cnt != write(FILENO_STDERR, str, cnt)) write(FILENO_STDERR, "PIPE-PANIC", 10); } void uarthex(int num) { for(int ds=28; ds>=0; ds-=4) { int ch; ch = (num>>ds)&0x0f; if (ch >= 10) ch = 'A'+ch-10; else ch += '0'; uartchr(ch); } uartstr("\r\n\0"); } void doorbell_task(void) { // Controls LED 0x08 // Start by initializing the display to GT Gisselquist\nTechnology // write(KFD_STDOUT, disp_build_backslash,sizeof(disp_build_backslash)); // write(KFD_STDOUT, disp_build_gtlogo, sizeof(disp_build_gtlogo)); // write(KFD_STDOUT, disp_reset_data, sizeof(disp_reset_data)); // write(KFD_STDOUT, disp_gtech_data, sizeof(disp_gtech_data)); IOSPACE *sys = (IOSPACE *)IOADDR; while(1) { nread = nwritten = 0; int event; // Initial state: doorbell is not ringing. In this state, we // can wait forever for an event sys->io_spio = 0x080; // Turn our light off event = wait(INT_BUTTON|SWINT_PPS,-1); unsigned when = rtcclock; if (event & INT_BUTTON) showbell(when); else if (event & SWINT_PPS) shownow(when); while(event & INT_BUTTON) { // Next state, the button has been pressed, the // doorbell is ringing // Seconds records the number of seconds since the // button was last pressed. int seconds = 0; // Check time: should we turn our light on or not? belllight(rtcclock); const int *sptr = sound_data; // uartchr('N'); while(sptr < &sound_data[NSAMPLE_WORDS]) { int len = &sound_data[NSAMPLE_WORDS]-sptr; if (len > 256) len = 256; /* while(len > 64) { write(FILENO_AUX, sptr, 64); sptr += 64; len -= 64; }*/ // We will stall here, if the audio FIFO is full write(FILENO_AUX, sptr, len); sptr += len; nwritten += len; // If the user presses the button more than // once, we start the sound over as well as // our light counter. event = wait(INT_BUTTON|SWINT_PPS, 0); if (event&INT_BUTTON) { if (sptr > &sound_data[2048]) { sptr = sound_data; seconds = 0; when = (volatile unsigned)rtcclock; showbell(when); } } else if (event&SWINT_PPS) { seconds++; belllight(rtcclock); showbell(when); } } uartchr('D'); // Next state: the doorbell is no longer ringing, but // we have yet to return to normal--the light is still // on. while((seconds < HALF_HOUR_S)&& (((event=wait(INT_BUTTON|SWINT_PPS,-1))&INT_BUTTON)==0)) { seconds++; belllight(rtcclock); showbell(when); } if (event&INT_BUTTON) { when = (volatile unsigned)rtcclock; showbell(when); uartchr('B'); } } // uartstr("\r\n"); uartstr("\r\nNWritten: "); uarthex(nwritten); uartstr("NRead : "); uarthex(nread); uartstr("NStarts : "); uarthex(nstarts); nwritten = nread = nstarts = 0; } } #endif /* NWritten: 000018E7 NRead : 000018E7 NStarts : 00000001 */
Go to most recent revision | Compare with Previous | Blame | View Log