📄 demo1_opex.c
字号:
void task9A(OPEX_TCB *); // forward reference declarations
void task9B(OPEX_TCB *);
// state: initialize
void task9(OPEX_TCB *me)
{
// initialize port
cbi(DDRA, task9bitno); // make this bit an input
sbi(PORTA, task9bitno); // enable the pull-up resistor
me->state = (PINA & (1<<task9bitno)); // retain I/O bit state
me->funcp = &task9A; // change state
OPEX_sched_resched(me, 0, 0, 0, 0, 1); // run next state on next tick
}
///////////////////////
// state: periodic poll and look for change on I/O bit
void task9A(OPEX_TCB *me)
{
BYTE b;
b = (PINA & (1<<task9bitno)); // get I/O bit state
if (b != me->state) { // has bit changed yet?
me->funcp = &task9B; // yes, change state
OPEX_sched_resched(me, 0, 0, 0, 0, 1); // run next state on next tick
}
else // bit is unchanged
OPEX_sched_resched(me, 0, 0, 0, 0, TicksPerSecond/8); // run task9A again leisurely rate
}
///////////////////////
// state: if bit is same as prior to delay from state 9A, it's changed.
// if bit is different than prior to delay, it was a debounce glitch
void task9B(OPEX_TCB *me)
{
BYTE b;
b = (PINA & (1<<task9bitno)); // get the I/O
OPEX_puts(me->name); // display taskname
if (b != me->state) { // is bit still changed?
me->state = b; // retain I/O bit state
sprintf_P(StringBuf1, PSTR(" PORTA bit changed 0x%X"), b);
OPEX_putline(StringBuf1);
}
else {
OPEX_putline(" PORTA glitch ignored");
OPEX_sched_resched(me, 0, 0, 0, 0, 8); // run task9A again more leisurely rate
}
me->funcp = &task9A; // next state is
OPEX_sched_resched(me, 0, 0, 0, 0, TicksPerSecond/8); // run task9A again more leisurely rate
}
//////////////////////////////////////////////////
//////////////////////////////////////////////////
//// Scheduled /////
void show_named_task(OPEX_TCB *me)
{
char taskname[32];
if (me->pinfo == NULL) { // NULL if this was just launched
me->pinfo = (void *)1;
OPEX_sched_on_flag(&OPEX_sched_flags, (1<<OPEX_sched_FLAGBIT_SERIAL_RECEIVED_CR) ); // run this func again when another nl comes in
}
else {
OPEX_puts_P(PSTR("find named task: "));
OPEX_putline(taskname);
if (OPEX_gets(taskname, sizeof(taskname), 0) > 1) // if not an empty line
report(OPEX_sched_get_named(taskname));
OPEX_sched_quit();
}
}
// SCHEDULED ///////////////////////////////////////////////
// monitor the serial port incoming for a 1 char cmd
// this one looks ever second or so for a certain char
//
// This task runs each time a single character arrives on the serial port.
// when a particular character arrives, via the switch statement below,
// various actions are taken.
// when a 'd' is received, the task for the function host_cmd2() is launched, then this task quits.
// The host_cmd2() task sleeps until a carriage return comes in, signifying the end of the d command's
// data has arrived. Then the d command (set date/time) is processed. Then this command, host_cmd1() is
// relaunched by host_cmd2();
// This technique yields non-blocking I/O and assures fast executing, without polling.
//
void host_cmd1(OPEX_TCB *me)
{
void host_cmd2(OPEX_TCB *); // declare reference to this function
void echotest(OPEX_TCB *); // ditto
OPEX_TCB *f, *f1;
char c[1];
BYTE b;
//report(me);
while(OPEX_peek(c, 0) != 0) { // inspect all newly arrived chars
// input the char and take action
OPEX_getc(c); // get from FIFO (peekc above said there's >=1 chars waiting)
switch (c[0]) {
case '$': // jump to bootstrap code
//save_date();
OPEX_putline_P(PSTR(JMPBOOT));
while (serial_get_txIE()); // let serial output finish
;
cli();
asm(JMPBOOT);
break;
case 'd': // host set date command. Give the serial port to the command processor
// this will read the rest of the command line, up to a CR
OPEX_sched_new(&host_cmd2, "host_cmd2"); // do the command
OPEX_sched_quit(); // stop checking chars, host_cmd2 will restart me
break; // never gets here
case 'e': // echo serial test
OPEX_sched_new(&echotest, "echotest2"); // do the command
OPEX_sched_quit(); // stop checking chars, host_cmd2 will restart me
break; // never gets here
case 'K': // kill all tasks
while (flagwaitQ != NULL) //kill those in this queue
OPEX_sched_kill(flagwaitQ);
f = schedQ; // kill all but me in the sched time sorted queue
f = f->next; // skip this task (me)
while (f) {
f1 = f->next;
OPEX_sched_kill(f);
f = f1;
}
OPEX_sched_quit(); // now I quit
break;
case 'k': // kill all tasks except this one
while (flagwaitQ != NULL)
OPEX_sched_kill(flagwaitQ);
f = schedQ; // kill all but me in the sched time sorted queue
f = f->next; // // skip this task (me)
while (f) {
f1 = f->next;
OPEX_sched_kill(f);
f = f1;
}
break; // leave me running
case 'm':
sprintf_P(StringBuf1, PSTR("Startup MCUSR=0x%X"), mcusr);
OPEX_putline(StringBuf1);
OPEX_sched_show_mem(StringBuf1, RAMEND); // do the command
break;
case 'n':
OPEX_sched_new(&show_named_task, NULL);
break;
case 'q': // brief display
f = OPEX_sched_new(&task_showQ, NULL); // do the command as a separate task, NULL name
f->pinfo = (void *)1; // set brief mode flag
break;
case 'Q': // verbose display
f = OPEX_sched_new(&task_showQ, NULL); // do the command as a separate task, NULL name
f->pinfo = NULL; // set brief mode flag
//OPEX_sched_showQ(StringBuf1, 0); // do the command
break;
case 'r': // toggle reporting of task executions on/off
reporting ^= 1;
break;
case 't': // test daylight savings (US times, change if EU)
if (OPEX_is_daylight_saving()) {
cli();
OPEX_daylight_saving_changes_at(0, &time); // get ending DST date for DST this year
--time.hour; time.minute = 59; time.second = 30; // just before that time
sei();
}
else {
cli();
OPEX_daylight_saving_changes_at(1, &time); // get starting DST date for DST this year
--time.hour; time.minute = 59; time.second = 30; // just before that time
sei();
}
OPEX_daylight_saving_adjust();
OPEX_sched_time_changed(); // inform all tasks of change - also gets dst monitor task
break;
case 'x':
OPEX_sched_new(&OW_test_main, "OW_Test");
break;
case 'y':
OPEX_sched_new(&DS1820, "DS1820");
break;
case '0': // these toggle flag bits for test7
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
b = (BYTE) (c[0] & 7); // key typed is the binary bit #
// for digit b (0 to 7) received, toggle flag bit b
// task 7 runs when any odd bit # changes (task 7's mask is 0xAA)
// flag pointer, bit number, new value
OPEX_sched_change_flag( &task7_flags, b, ( (task7_flags & (1 << b)) ) ? 0 : 1 );
break;
default:
break;
} // switch
} // while
// run this func again later when a character arrives on serial port
OPEX_sched_on_flag(&OPEX_sched_flags, (1<<OPEX_sched_FLAGBIT_SERIAL_RECEIVED_ANY) );
}
// SCHEDULED ///////////////////////////////////////////////
// Parse the received string and set the date/time or just print same. Then quit.
//
void host_cmd2(OPEX_TCB *me)
{
int mo, d, y, h, m, s, gmt_offset;
if ( (OPEX_sched_flags & (1<<OPEX_sched_FLAGBIT_SERIAL_RECEIVED_CR)) == 0)
// wait for CR received flag to come on, or it may already be on
OPEX_sched_on_flag(&OPEX_sched_flags, (1<<OPEX_sched_FLAGBIT_SERIAL_RECEIVED_CR) );
// the above OPEX call does not return, it reschedules this function upon receipt of CR
// ??? this has a possible race condition with the ISR
OPEX_sched_flags &= ~(1<<OPEX_sched_FLAGBIT_SERIAL_RECEIVED_CR);
// read in a line of text which has arrived with a CR
d = OPEX_gets(StringBuf1, 63, 0); // get line of text from serial port, no wait, clears the flag bit
// process the received line of text
if (strlen(StringBuf1) >1) {
if (sscanf_P(StringBuf1, PSTR("%d %3s %d/%d/%d %d:%d:%d"), // valid format?
&gmt_offset, &StringBuf1, &d, &mo, &y, &h, &m, &s) == 8)
{
y %= 100; // oh well, assume century 20xx
GMT_offset_standard = (int8_t)gmt_offset; // <<< offset for STANDARD time, no matter DST
OPEX_date_stuff(&time, (BYTE)y, (BYTE)d, (BYTE)mo, (BYTE)h, (BYTE)m, (BYTE)s , 0);
save_date(); // save to EEPROM
OPEX_daylight_saving_adjust();
OPEX_sched_time_changed(); // inform all tasks of change - also gets dst monitor task
}
else { // invalid format
sprintf_P(StringBuf1, PSTR("Err, e.g.:-8 Sun mm/dd/yy hh:mm:ss"));
OPEX_putline(StringBuf1);
}
}
OPEX_sched_new(&host_cmd1, "host_cmd1"); // restart single char cmd processor
OPEX_sched_quit();
}
// Echo line of test to serial port - test/demo
// see 'e' command in host_cmd1
void echotest(OPEX_TCB *me)
{
switch (me->state) {
case 0:
OPEX_putline_P(PSTR("Enter text and CR - not echoed"));
me->state = 1;
OPEX_sched_on_flag(&OPEX_sched_flags, (1<<OPEX_sched_FLAGBIT_SERIAL_RECEIVED_CR) );
// the above line of code causes this func to run again when CR is received
break; // never gets here
case 1:
OPEX_gets(StringBuf1, 63, 0); // get string, no wait
OPEX_putline(StringBuf1);
OPEX_sched_new(&host_cmd1, "host_cmd1"); // restart single char cmd processor
OPEX_sched_quit();
}
}
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
/// MAIN ///
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
int main(void)
{
char *p;
mcusr = MCUSR; // retain cause of reset
MCUSR = 0; // reset causes
io_init(); // see AVR_dependent for these...
timer_init();
serial_init();
OPEX_com_init(); // init OPEX serial I/O
//Global interrupt enable
sei();
OPEX_putline_P(PSTR("\r\nRESET"));
OPEX_init_dateTime(); // set OPEX date and time defaults
reporting = 1;
// top level
for ( ;; ) {
_stack_watch = 0xffff;
// initialization -
while (OPEX_getc(StringBuf1) != 0) // purge left over serial data if any
;
OPEX_putline_P(PSTR("\r\n\nLaunching"));
OPEX_sched_setIdleFunc(&idle); // establish an idle user task
// launch recurring tasks (the if expressions are in case one fails to launch due to malloc()
// non of these execute until all are launched
if (
(OPEX_sched_new(&DST_monitor, (p = "DST")) == NULL)
|| (OPEX_sched_new(&host_cmd1, (p = "Host_Cmd1")) == NULL)
|| (OPEX_sched_new(&task0, (p = "TASK0")) == NULL)
|| (OPEX_sched_new(&task1, (p = "TASK1")) == NULL)
|| (OPEX_sched_new(&task2, (p = "TASK2")) == NULL)
|| (OPEX_sched_new(&task3, (p = "TASK3")) == NULL)
|| (OPEX_sched_new(&task4, (p = "TASK4")) == NULL)
|| (OPEX_sched_new(&task5, (p = "TASK5")) == NULL)
|| (OPEX_sched_new(&task6, (p = "TASK6")) == NULL)
|| (OPEX_sched_new(&task7, (p = "TASK7")) == NULL)
|| (OPEX_sched_new(&task8, (p = "TASK8")) == NULL)
|| (OPEX_sched_new(&task9, (p = "TASK9")) == NULL)
//|| (OPEX_sched_new(&DS1820, (p = "DS1820")) == NULL)
)
{
sprintf_P(StringBuf1, PSTR("OPEX_sched_new err on %s"), p);
OPEX_putline(StringBuf1);
}
else { // all launched successfully, so start scheduler
OPEX_putline_P(PSTR("Starting Scheduler") );
OPEX_sched_start(); // returns when all tasks quit, just start up again
OPEX_putline_P(PSTR("Scheduler returned!") );
}
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -