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

Subversion Repositories s6soc

[/] [s6soc/] [trunk/] [sw/] [zipos/] [doorbell.c] - Rev 22

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
	//
	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_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;
 
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	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) {
		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;
			sys->io_uart = 'N';
			while(sptr < &sound_data[NSAMPLE_WORDS]) {
				int	len = &sound_data[NSAMPLE_WORDS]-sptr;
				if (len > 256)
					len = 256;
 
				// We stall here, if the audio FIFO is full
				write(FILENO_AUX, sptr, len);
				sptr += 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);
				}
			}
 
			sys->io_uart = '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);
				sys->io_uart = 'S';
			}
		}
	}
}
#endif
 
 

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

powered by: WebSVN 2.1.0

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