/* **************************************************************************** * Program RT - a real time multi process shell/demostrator * This version supports messaging using linked lists or an array * for linked list define LINKED_LIST * * * D H Rice, copyright 1991 * * Press A or B to generate an event. **************************************************************************** */ #include #include #include #include #include #include "boolean.h" /*Sec 0.0 compile options */ #define LINKED_LIST /* Sec 1.0 */ /*==========*/ /* Sec 1.1 Process Names */ #define PROC_A 1 #define PROC_B 2 #define PROC_C 3 #define PROC_D 4 /* the following are only sources */ #define CLOCK 5 #define KEYBOARD 6 /* Sec 1.1.1 Column position for Process Names */ #define SCR_PROC_A 41 #define SCR_PROC_B 48 #define SCR_PROC_C 55 #define SCR_PROC_D 64 /* the following are only sources */ #define SCR_CLOCK 26 #define SCR_KEYBOARD 34 /* printf("Reason CLK Keyboard [A] [B] [C] [D]"); */ /* Sec 1.2 Event Numbers */ #define FREE_MESSAGE 0 #define EVENT_A 1 #define EVENT_B 2 #define EVENT_C 3 #define EVENT_D 4 #define EVENT_NODE27 5 #define EVENT_NODE28 6 #define EVENT_NODE6 7 /* process D events */ #define EVENT_0TON 8 #define EVENT_NTO0 9 #define EVENT_RESET 10 /* Sec 1.3 Process states */ #define PA_IDLE 0 #define PB_IDLE 0 #define PB_POSSIBLE 1 #define PC_IDLE 0 #define PD_MWI_NOT_SET 0 #define PD_MWI_SET 1 /* Sec 1.4 Misc defines */ #define MAX_BUFFER 20 #ifdef LINKED_LIST #define NULL_PTR ( message_T * ) NULL #endif /* */ /* Sec 2.0 Type definitions */ /* ************************ */ #ifndef LINKED_LIST typedef struct { int origin, /* source process */ process, /* destination process */ event, /* event type of the message */ in_post, /* True while message is sent but not found */ data; /* data passed between the processes */ } message_T; #endif #ifdef LINKED_LIST struct message_ST { int origin, /* source process */ process, /* destination process */ event, /* event type of the message */ in_post, /* True while message is sent but not found */ data; /* data passed between the processes */ struct message_ST * link; } ; typedef struct message_ST message_T; #endif /* */ /* Sec 3. Variable definitions */ /* ************************ */ /* Sec 3.1 Message and system gobal variables */ message_T message_buffer[MAX_BUFFER+1]; /* an array of messsage buffers */ #ifdef LINKED_LIST message_T /* pointers to two queues * Queue: free - message not in use * Queue: in_post - message sent but not arrived. */ * next_free, * next_in_post, * last_free, * last_in_post; #endif time_t time_now, next_time; /* Sec 3.2 Process's internal variables */ /* Sec 3.2.1 Process [A] internal variables */ int PA_event_cnt = 0; /* Sec 3.2.2 Process [B] internal variables */ int PB_state = PB_IDLE; /* Sec 3.2.3 Process [C] internal variables */ int PC_state = PC_IDLE; /* Sec 3.2.4 Process [D] internal variables */ int PD_state = PD_MWI_NOT_SET, PD_mwi_cnt = 0; /* */ /* Sec 4.0 procedures*/ /*===================*/ /* Sec 4.1 message buffer procedures*/ /*==================================*/ #ifndef LINKED_LIST message_T * malloc_message( void ); message_T * malloc_message( void ) { int cnt = 0 ; message_T * message_P = & message_buffer[0]; /* look for a free message */ while ( cnt < MAX_BUFFER ) { if ( message_P[cnt].event == FREE_MESSAGE ) { return( & message_P[cnt] ); } cnt ++; } /* error - no free message buffers */ message_P = NULL; return( message_P ); } void free_message(message_T * message_P); void free_message(message_T * message_P) { message_P->event = FREE_MESSAGE; } void send_message(message_T * m_P ); void send_message(message_T * m_P ) { int start,finish; char buff[81]; m_P->in_post = TRUE; /* The message is 'sent' as soon as the event is filled in */ /* draw_message_sequence(m_P); */ switch (m_P->origin) { case PROC_A: start = SCR_PROC_A; break; case PROC_B: start = SCR_PROC_B; break; case PROC_C: start = SCR_PROC_C; break; case PROC_D: start = SCR_PROC_D; break; case CLOCK: start = SCR_CLOCK; break; case KEYBOARD: start = SCR_KEYBOARD; break; } switch (m_P->process) { case PROC_A: finish = SCR_PROC_A; break; case PROC_B: finish = SCR_PROC_B; break; case PROC_C: finish = SCR_PROC_C; break; case PROC_D: finish = SCR_PROC_D; break; case CLOCK: finish = SCR_CLOCK; break; case KEYBOARD: finish = SCR_KEYBOARD; break; } window(1,3,79,22); textbackground(CYAN); textcolor(YELLOW); delline(); if ( start < finish ) { gotoxy(start,17); memset(buff,'-',finish-start); buff[3] = (char)( 'A'+m_P->event - 1 ); buff[finish-start-1] = (char) '>'; buff[finish-start] = (char) 0 ; cputs(buff); } else { gotoxy(start,17); memset(buff,'-',start-finish); buff[0] = (char) '<'; buff[3] = (char)( 'A'+m_P->event - 1 ); buff[start-finish] = (char) 0 ; cputs(buff); } } void send_message1( int from, int to, int event, int data , char * comment ); void send_message1( int from, int to, int event, int data , char * comment) { int start,finish; char buff[81]; message_T * message_P; /* generate a time event */ message_P = malloc_message(); if ( message_P != NULL ) { message_P->origin = from; message_P->process = to; message_P->event = event; message_P->in_post = TRUE; message_P->data = data; /* The message is 'sent' as soon as the event is filled in */ /* draw_message_sequence(m_P); */ switch (message_P->origin) { case PROC_A: start = SCR_PROC_A; break; case PROC_B: start = SCR_PROC_B; break; case PROC_C: start = SCR_PROC_C; break; case PROC_D: start = SCR_PROC_D; break; case CLOCK: start = SCR_CLOCK; break; case KEYBOARD: start = SCR_KEYBOARD; break; } switch (message_P->process) { case PROC_A: finish = SCR_PROC_A; break; case PROC_B: finish = SCR_PROC_B; break; case PROC_C: finish = SCR_PROC_C; break; case PROC_D: finish = SCR_PROC_D; break; case CLOCK: finish = SCR_CLOCK; break; case KEYBOARD: finish = SCR_KEYBOARD; break; } window(1,3,79,22); textbackground(BLUE); textcolor(YELLOW); delline(); gotoxy(1,17); cprintf("%s\n",comment); textbackground(CYAN); if ( start < finish ) { gotoxy(start,17); memset(buff,'-',finish-start); buff[3] = (char)( 'A'+message_P->event - 1 ); buff[finish-start-1] = (char) '>'; buff[finish-start] = (char) 0 ; cputs(buff); } else { gotoxy(start,17); memset(buff,'-',start-finish); buff[0] = (char) '<'; buff[3] = (char)( 'A'+message_P->event - 1 ); buff[start-finish] = (char) 0 ; cputs(buff); } } } message_T * get_message( void ); message_T * get_message( void ) { int cnt = 0 ; message_T * message_P = & message_buffer[0]; /* look for the first message */ while ( cnt < MAX_BUFFER ) { if ( ( message_P[cnt].event != FREE_MESSAGE ) && ( message_P[cnt].in_post == TRUE )) { message_P -> in_post = FALSE; return( & message_P[cnt] ); } cnt ++; } /* error - no free message buffers */ message_P = NULL; return( message_P ); } void clear_out_message_buffer( void ); void clear_out_message_buffer( void ) { int cnt; for ( cnt=0 ; cnt < MAX_BUFFER ; cnt ++ ) { message_buffer[cnt].event = FREE_MESSAGE; } } #endif #ifdef LINKED_LIST message_T * malloc_message( void ); message_T * malloc_message( void ) { message_T * message_P ; /* seperate the message from the free queue */ message_P = next_free; if ( next_free != NULL_PTR ) { next_free = next_free->link; message_P->link = NULL_PTR; } return( message_P ); } void free_message(message_T * message_P); void free_message(message_T * message_P) { /* link the message into the free queue */ if ( last_free != NULL_PTR ) { last_free->link = message_P; } last_free = message_P; if ( next_free == NULL_PTR ) { /* * if the queqe is empty then now there is a message * the next_free ptr should point to it */ next_free = last_free; } message_P->link = NULL_PTR; } void send_message(message_T * m_P ); void send_message(message_T * m_P ) { int start,finish; char buff[81]; /* link message into in_post queue */ if ( next_in_post != NULL_PTR ) { next_in_post->link = m_P ; next_in_post = next_in_post ; } m_P->link = NULL_PTR; /* draw_message_sequence(m_P); */ switch (m_P->origin) { case PROC_A: start = SCR_PROC_A; break; case PROC_B: start = SCR_PROC_B; break; case PROC_C: start = SCR_PROC_C; break; case PROC_D: start = SCR_PROC_D; break; case CLOCK: start = SCR_CLOCK; break; case KEYBOARD: start = SCR_KEYBOARD; break; } switch (m_P->process) { case PROC_A: finish = SCR_PROC_A; break; case PROC_B: finish = SCR_PROC_B; break; case PROC_C: finish = SCR_PROC_C; break; case PROC_D: finish = SCR_PROC_D; break; case CLOCK: finish = SCR_CLOCK; break; case KEYBOARD: finish = SCR_KEYBOARD; break; } window(1,3,79,22); textbackground(CYAN); textcolor(YELLOW); delline(); if ( start < finish ) { gotoxy(start,17); memset(buff,'-',finish-start); buff[3] = (char)( 'A'+m_P->event - 1 ); buff[finish-start-1] = (char) '>'; buff[finish-start] = (char) 0 ; cputs(buff); } else { gotoxy(start,17); memset(buff,'-',start-finish); buff[0] = (char) '<'; buff[3] = (char)( 'A'+m_P->event - 1 ); buff[start-finish] = (char) 0 ; cputs(buff); } } void send_message1( int from, int to, int event, int data , char * comment ); void send_message1( int from, int to, int event, int data , char * comment) { int start,finish; char buff[81]; message_T * message_P; /* generate a time event */ message_P = malloc_message(); if ( message_P != NULL ) { message_P->origin = from; message_P->process = to; message_P->event = event; message_P->in_post = TRUE; message_P->data = data; /* link message into in_post queue */ if ( next_in_post == NULL ) { /* * if it's the first message * then the nextin_post needs to point to it */ next_in_post = message_P; } if ( last_in_post != NULL_PTR ) { last_in_post->link = message_P ; } last_in_post = message_P ; message_P->link = NULL_PTR; /* The message is 'sent' as soon as the event is filled in */ /* draw_message_sequence */ switch (message_P->origin) { case PROC_A: start = SCR_PROC_A; break; case PROC_B: start = SCR_PROC_B; break; case PROC_C: start = SCR_PROC_C; break; case PROC_D: start = SCR_PROC_D; break; case CLOCK: start = SCR_CLOCK; break; case KEYBOARD: start = SCR_KEYBOARD; break; } switch (message_P->process) { case PROC_A: finish = SCR_PROC_A; break; case PROC_B: finish = SCR_PROC_B; break; case PROC_C: finish = SCR_PROC_C; break; case PROC_D: finish = SCR_PROC_D; break; case CLOCK: finish = SCR_CLOCK; break; case KEYBOARD: finish = SCR_KEYBOARD; break; } window(1,3,79,22); textbackground(BLUE); textcolor(YELLOW); delline(); gotoxy(1,17); cprintf("%s\n",comment); textbackground(CYAN); if ( start < finish ) { gotoxy(start,17); memset(buff,'-',finish-start); buff[3] = (char)( 'A'+message_P->event - 1 ); buff[finish-start-1] = (char) '>'; buff[finish-start] = (char) 0 ; cputs(buff); } else { gotoxy(start,17); memset(buff,'-',start-finish); buff[0] = (char) '<'; buff[3] = (char)( 'A'+message_P->event - 1 ); buff[start-finish] = (char) 0 ; cputs(buff); } } } message_T * get_message( void ); message_T * get_message( void ) { message_T * message_P ; /* look for the first message */ message_P = next_in_post; if ( next_in_post != NULL_PTR ) { next_in_post = next_in_post->link; message_P->link = NULL_PTR ; } /* error - no free message buffers */ return( message_P ); } void clear_out_message_buffer( void ); void clear_out_message_buffer( void ) { /* this function sets up four linked lists, one full and three empty. * the four lists represent the four states a message can be in * */ message_T * message_P = & message_buffer[0]; int cnt; /* this would mnormally done by mallocing memory */ for ( cnt=0 ; cnt < MAX_BUFFER ; cnt ++ ) { message_buffer[cnt].link = & message_buffer[cnt+1]; message_P = &message_buffer[cnt]; } next_free = &message_buffer[0]; last_free = &message_buffer[MAX_BUFFER-1]; last_free->link = ( message_T * ) NULL; next_in_post = (message_T *) NULL; last_in_post = (message_T *) NULL; } #endif /* Sec 4.2 Input Polling Software */ /*================================*/ void alarm_test( void ); void alarm_test( void ) { /* check out the time */ if ( next_time < time( & time_now ) ) { /* generate a time event */ #if 0 send_message1(CLOCK,PROC_A,EVENT_C,0,"Timer event"); #endif next_time = time_now + 3l; } } void run_input_polling( void ); void run_input_polling( void ) { int ip_char; alarm_test(); /* scan keyboard */ if ( kbhit() != 0 ) { ip_char = getch(); switch ( ip_char ) { case 'A': case 'a': send_message1(KEYBOARD,PROC_B,EVENT_NODE27,0," node27"); break; case 'B': case 'b': send_message1(KEYBOARD,PROC_B,EVENT_NODE28,0," node28"); break; case 'C': case 'c': send_message1(KEYBOARD,PROC_C,EVENT_NODE6,0," node6"); break; case 'E': case 'e': exit(0); break; case 'R': case 'r': send_message1(KEYBOARD,PROC_D,EVENT_RESET,0," reset"); break; } } }; /* */ /* Sec 4.3 Process Status Display Functions */ /*==========================================*/ void display_status_proc_A( void ); void display_status_proc_A( void ) { window(1,24,20,24); textbackground(GREEN); textcolor(YELLOW); clrscr(); cprintf("[A]Cnt:%d",PA_event_cnt); } void display_status_proc_B( void ); void display_status_proc_B( void ) { window(21,24,40,24); textbackground(GREEN); textcolor(YELLOW); clrscr(); cprintf("[B] state: %d ",PB_state); } void display_status_proc_C( void ); void display_status_proc_C( void ) { window(41,24,60,24); textbackground(GREEN); textcolor(YELLOW); clrscr(); } void display_status_proc_D( void ); void display_status_proc_D( void ) { window(61,24,79,24); textbackground(GREEN); textcolor(YELLOW); clrscr(); cprintf("[D] mwi mml:%3d",PD_mwi_cnt); } /* */ /* Sec 5. Process code */ /* =================== */ /* Sec 5.1 Process A */ /* =================== */ void PAEA( void ); void PAEA( void ) { /* key A pressed */ PA_event_cnt = PA_event_cnt + 1; if ( PA_event_cnt == 11 ) { send_message1(PROC_A,PROC_C,EVENT_B,2,"Counter overloaded "); } } void PAEB( void ); void PAEB( void ) { /* key B pressed */ PA_event_cnt = 0; send_message1(PROC_A,PROC_C,EVENT_A,0," Counter reset "); } void PAEC( void ); void PAEC( void ) { /* timer event */ PA_event_cnt = PA_event_cnt - 1; if ( PA_event_cnt < 0 ) { PA_event_cnt = 0; } if ( PA_event_cnt == 10 ) { send_message1(PROC_A,PROC_C,EVENT_A,1," Overload cleared! "); } } void PAED( void ); void PAED( void ) { exit(0); } void Process_A(message_T * message_P); void Process_A(message_T * message_P) { switch(message_P->event) { case EVENT_A: PAEA(); break; case EVENT_B: PAEB(); break; case EVENT_C: PAEC(); break; case EVENT_D: PAED(); break; } display_status_proc_A(); free_message(message_P); }; /* */ /* Sec 5.2 Process_B */ /* =================== */ /************************************************************************ * This process has two input events * event > node27 | - node27,"Keep the Message?" * event > node28 | - node28,"delete message" * if every node27 if followed by a node28, then all messages are deleted * PB_msg_cnt contains the count of uncleared messages. *************************************************************************/ void Process_B(message_T * message_P); void Process_B(message_T * message_P) { { switch(PB_state) { case PB_IDLE: { switch(message_P->event) { case EVENT_NODE27: PB_state = PB_POSSIBLE; break; case EVENT_NODE28: break; } } break; case PB_POSSIBLE: { switch(message_P->event) { case EVENT_NODE27: PB_state = PB_POSSIBLE; break; case EVENT_NODE28: send_message1(PROC_B,PROC_D,EVENT_0TON,1," Messages cleared"); PB_state = PB_IDLE; break; } } break; } display_status_proc_B(); free_message(message_P); } } /* Sec 5.3 Process_C */ /* =================== */ /************************************************************************ * This process has one input events * event > NODE6 | message has just been left *************************************************************************/ void Process_C(message_T * message_P); void Process_C(message_T * message_P) { { PC_state = PC_IDLE; switch(PC_state) { case PC_IDLE: { switch(message_P->event) { case EVENT_NODE6: send_message1(PROC_C,PROC_D,EVENT_NTO0,1," Messages waiting"); break; case EVENT_NTO0: PD_state = PD_MWI_NOT_SET; break; } } break; } display_status_proc_C(); free_message(message_P); } } /* Sec 5.4 Process_D */ /* =================== */ /************************************************************************ * This process has two input events * > 0 to n | - event indicating messages are now waiting * > n to 0 | - event indicating no messages are now waiting * PD_mwi_cnt contains the count of set MWI settings sent. *************************************************************************/ void Process_D(message_T * message_P); void Process_D(message_T * message_P) { { switch(PD_state) { case PD_MWI_NOT_SET: { switch(message_P->event) { case EVENT_0TON: PD_mwi_cnt++; PD_state = PD_MWI_SET; break; case EVENT_NTO0: PD_state = PD_MWI_NOT_SET; break; case EVENT_RESET: PD_mwi_cnt = 0; break; } } break; case PD_MWI_SET: { switch(message_P->event) { case EVENT_0TON: break; case EVENT_NTO0: PD_mwi_cnt++; PD_state = PD_MWI_NOT_SET; break; case EVENT_RESET: PD_mwi_cnt = 0; break; } } break; } display_status_proc_D(); free_message(message_P); } } /* */ /* Sec 6. Main */ /* =========== */ main() { message_T * message_P; PA_event_cnt = 0 ; next_time = time( &time_now); /* clear all the messages in the message buffer to free */ clear_out_message_buffer(); textbackground(BLUE); textcolor(YELLOW); window(1,1,80,25); clrscr(); window(1,1,79,2); gotoxy(1,1); printf(" ***** Real Time Demonstrator - press A or B ****\n\r"); printf("Reason CLK Keyboard [A] [B] [C] [D]"); display_status_proc_A(); display_status_proc_B(); display_status_proc_C(); display_status_proc_D(); while ( TRUE ) { run_input_polling(); /* ie get keyboard input and send a message */ message_P = get_message(); if ( message_P != NULL ) { switch ( message_P->process ) { case PROC_A: Process_A(message_P); break; case PROC_B: Process_B(message_P); break; case PROC_C: Process_C(message_P); break; case PROC_D: Process_D(message_P); break; } } } }