KEY EVENT & STATE 구현 2007. 1. 25 PLATFORM TEAM 정용학
차례 Key Event HS TASK UI TASK LONG KEY STATE 구현 소스코드및실행화면 질의응답및토의 2
KEY EVENT - HS TASK hs_task keypad_scan_keypad hs_init keypad_pass_key_code keypad_init keypad_event_cb clk_def ui_key_event_cb clk_reg clk_reg2 UI_KEY_SIG UI TASK
KEY EVENT - HS TASK clk_def clk_def( &keypad_clk_cb_keypad ); double linked list 구조 call_back_ptr->prev_ptr = NULL; /* Previous and Next pointers */ call_back_ptr->next_ptr = NULL; /* Previous and Next pointers */ call_back_ptr->cntdown = 0; /* Countdown expiration, milliseconds */ call_back_ptr->routine_ptr = NULL; /* Routine to call on expiration */ call_back_ptr->crnt_ms = 0; /* This interval */ call_back_ptr->next_ms = 0; /* Next interval */ call_back_ptr->repeat = FALSE; /* Whether to repeat */
KEY EVENT - HS TASK clk_reg2 clk_reg( &keypad_clk_cb_keypad, keypad_scan_keypad, KEYPAD_POLL_TIME, KEYPAD_POLL_TIME, TRUE ); clk_reg2( call_back_ptr, (void (*)(int4,void*)) routine_ptr, ms_first, ms_periodic, repeat, NULL ); void clk_reg2 ( ) clk_cb_type *call_back_ptr, void (*routine_ptr)( int4 ms_interval, void *user_data_ptr ), int4 ms_first, int4 ms_periodic, boolean repeat, void *usr_data_ptr clk_cb_delete( call_back_ptr ); call_back_ptr 구조체에각원소저장 ; clk_cb_insert( call_back_ptr );
KEY EVENT - HS TASK clk_cb_delete (clk_cb_type *call_back_ptr ) active list cnt=3 cnt=2 cnt=4 cnt=2 2 + 4 = 6 call_back_ptr clk_tick_last active list cnt=3 cnt=2 cnt=4 clk_tick_last call_back_ptr
KEY EVENT - HS TASK clk_cb_insert (clk_cb_type *call_back_ptr ) 원래 A는 3초, B는 3 + 2 = 5초, C는 3 + 2 + 2 = 7초 X ( 6초 ) 가삽입되는경우 A를지나면 6-3 = 3초, B와비교하니더크다 B를지나면 3-2 = 1초, C와비교하니더작다 B와 C사이에 1초로삽입 C는 2-1 = 1초로바뀜 active list A B C X cnt=3 cnt=2 cnt=1 cnt=2 2-1 = 1 call_back_ptr clk_tick_last
KEY EVENT - HS TASK keypad_scan_keypad call back timer 에정의되어있어서 20msec 마다실행됨 if (keypad_locked) return; for (row=0; row<keypad_rows; row++) for (column=0; column<keypad_columns; column++) switch ( keypad_key_state[row][column] ) case KS_KEY_UP: if ( keys_pressed[row][column] == TRUE) keypad_key_state[row][column] = KS_DEBOUNCE; sleep_allowed = FALSE; break; case KS_DEBOUNCE: if ( keys_pressed[row][column] == TRUE ) KEYPAD_PASS_KEY_CODE( keys[row][column], HS_NONE_K ); keypad_key_state[row][column] = KS_UP_WAIT; sleep_allowed = FALSE; else keypad_key_state[row][column] = KS_KEY_UP; break; case KS_UP_WAIT: if ( keys_pressed[row][column] == TRUE ) sleep_allowed = FALSE; else keypad_key_state[row][column] = KS_KEY_UP; KEYPAD_PASS_KEY_CODE( HS_RELEASE_K, keys[row][column] ); break; if (keypad_key_buffer.wr_idx!= keypad_key_buffer.rd_idx ) sleep_allowed = FALSE; if (sleep_allowed) KEYPAD_SLEEP_ALLOW();
Key Status KEY EVENT - HS TASK 각키마다각자 status를가짐 KS_KEY_UP KS_KEY_UP 키가눌러져있지않은상태 KS_DEBOUNCE 처음진입시 KEYPAD_PASS_KEY_CODE 호출 PRESSED KEY KS_UP_WAIT 키가떼어질경우 KEYPAD_PASS_KEY_CODE 호출 RELEASE_KEY KS_DEBOUNCE KS_DEBOUNCE 있는이유 hardware 상의 noise 때문 KS_UP_WAIT 9
KEY EVENT - HS TASK keypad_pass_key_code ( byte key_code, byte key_parm ) MULTI_KEY 정의시매개변수 2 개 if ( keypad_event_cb ) #ifdef FEATURE_KEYPAD_MULTI_KEY #else keypad_key_event_type key_event; key_event.key_code = key_code; key_event.key_parm = key_parm; kpd_key_event_type key_event; key_event.key_code = key_code; #endif keypad_event_cb ( key_event ); if(keypad_debug) keypad_key_buffer 에저장 ; else keypad_key_buffer 에저장 ; keypad_event_cb 는처음에 NULL 값을가지므로 callback fuction 이없을경우는해당키값을 keypad_key_buffer 에저장하고 callback fuction 이있을경우는해당함수를실행한다 LOCAL keypad_key_event_cb_f_type *keypad_event_cb = NULL;
KEY EVENT - HS TASK keypad_event_cb 처음에는 NULL 값을가짐 UI 내에서 keypad_register 함수로인해 ui_key_event_cb라는함수를가리킴 void ui_key_event_cb ( kpd_key_event_type key_event ) if (((ui_key_buffer.wr_idx + 1) & UI_KEY_BUF_MASK)!= ui_key_buffer.rd_idx) ui_key_buffer.data [ ui_key_buffer.wr_idx ] = key_event.key_code; ui_key_buffer.wr_idx = (ui_key_buffer.wr_idx+1) & UI_KEY_BUF_MASK; (void) rex_set_sigs( &ui_tcb, UI_KEY_SIG );
KEY EVENT - HS TASK rex_set_sigs rex_set_sigs( &ui_tcb, UI_KEY_SIG ); rex_sigs_type rex_set_sigs( rex_tcb_type *p_tcb, rex_sigs_type p_sigs ) p_tcb->sigs = p_tcb->sigs p_sigs; if((p_tcb->wait & p_sigs)!= 0) p_tcb->wait = 0; if (( p_tcb->pri > rex_best_task->pri) && REX_TASK_RUNNABLE ( p_tcb )) rex_best_task = p_tcb; rex_sched();
KEY EVENT - UI TASK ui_task for ( ; ; ) ui_init uikey_init kpd_suv_srvc rex_wait ui_signal handle_keys ui_add_event ui_do_event kpd_reg_key_event get_key keypad_register handle_hs_keys
KEY EVENT - UI TASK boolean kpd_suv_srvc ( kpd_cb_f_handle_type *kpd_cb_func) kpd_sub_srvc (ui_kpd_sub_cb); keypad service를 subscribe 하기위해서사용됨 kpd_handle_type kpd_handle; if( kpd_subscribed ) return FALSE; kpd_handle.id = HS_KPD_DEVICE; kpd_handle.status = HS_SUBSCRIBED; kpd_cb_func ( kpd_handle ); kpd_subscribed = TRUE; return TRUE; void ui_kpd_sub_cb( kpd_handle_type kpd_handle ) ui_kpd_handle = kpd_handle;
KEY EVENT - UI TASK kpd_reg_key_event kpd_reg_key_event ( ui_kpd_handle, ui_key_event_cb ); keypad_register 함수호출후에 simulation boolean kpd_reg_key_event ( kpd_handle_type kpd_handle, kpd_cb_f_key_event_type *kpd_cb_func ) keypad_register(kpd_cb_func); // simulate.. while (( key.key_code = keypad_get_key() )!= HS_NONE_K) kpd_cb_func ( key );
KEY EVENT - UI TASK keypad_register keypad_register (kpd_cb_func); kpd_cb_fubc 는 ui_key_event_cb #ifdef FEATURE_KEYPAD_MULTI_KEY extern boolean keypad_register( keypad_key_event_cb_f_type *cb) #else extern boolean keypad_register( kpd_cb_f_key_event_type *cb) #endif if ( keypad_event_cb ) return FALSE; keypad_event_cb = cb; return TRUE; keypad_event_cb 는처음에 NULL 값 LOCAL keypad_key_event_cb_f_type *keypad_event_cb = NULL;
KEY EVENT - UI TASK rex_wait 해당 signal이들어오면진행중인 signal을 wait상태로보내고 scheduling 해당 signal이안들어오면계속 suspend 상태 rex_sigs_type rex_wait( rex_sigs_type p_sigs ) rex_sigs_type sigs = 0; if( (rex_curr_task->sigs & p_sigs) == 0 ) rex_curr_task->wait = p_sigs; rex_set_best_task ( REX_TASK_LIST_FRONT() ); rex_sched(); sigs = rex_curr_task->sigs; return sigs;
KEY EVENT - UI TASK ui_signal 현재 signal 에맞는함수를수행 rex_clr_sigs 해당 bit 를 0 으로 set void ui_signal ( rex_sigs_type sigs, q_type *ui_cmd_q_ptr )... if( sigs & UI_KEY_SIG ) (void) rex_clr_sigs( rex_self(), UI_KEY_SIG ) ; handle_keys(); rex_sigs_type rex_clr_sigs( rex_tcb_type *p_tcb, rex_sigs_type p_sigs ) rex_sigs_type prev_sigs = 0; p_sigs = ~p_sigs; prev_sigs = p_tcb->sigs; p_tcb->sigs = p_tcb->sigs & p_sigs; return prev_sigs;
KEY EVENT - UI TASK handle_keys get_key 함수를이용해 key 값을받아와서 handle_hs_key 함수를호출 while ( ( key = (hs_key_type) get_key())!= HS_NONE_K )... handle_hs_key (key); byte get_key( void ) byte keycode; if ( ui_key_buffer.wr_idx == ui_key_buffer.rd_idx ) keycode = HS_NONE_K; else keycode = ui_key_buffer.data [ ui_key_buffer.rd_idx ]; ui_key_buffer.rd_idx = (ui_key_buffer.rd_idx+1) & UI_KEY_BUF_MASK; return( keycode );
KEY EVENT - UI TASK handle_hs_key 키값에따라서이벤트를설정하고 ui_add_event 실행 void handle_hs_key ( hs_key_type key )... if( key!= HS_RELEASE_K && key!= HS_PWR_K ) ui_add_event( (word)key ); void ui_add_event ( word event ) if( ( ui_event.head+1 ) % UI_EVENT_SIZE!= ui_event.tail ) ui_event.head = ( ui_event.head+1 ) % UI_EVENT_SIZE; ui_event.buf [ ui_event.head ] = event;
KEY EVENT - UI TASK ui_do_event event 있을경우실행 ui_task() for( ; ; )... while ( ui.getkeys && ( ui_event.head!= ui_event.tail )) ui_event.tail = ( ui_event.tail+1 ) % UI_EVENT_SIZE; ui_do_event ( ui_event.buf [ ui_event.tail ] );
KEY EVENT - LONG KEY Long key 처리 keypad_scan_keypad 함수가 20msec 마다호출이되는상태에서 keypad_pass_key_code 호출 if (keypad_locked) return; for (row=0; row<keypad_rows; row++) for (column=0; column<keypad_columns; column++) switch ( keypad_key_state[row][column] ) case KS_KEY_UP: if ( keys_pressed[row][column] == TRUE) keypad_key_state[row][column] = KS_DEBOUNCE; sleep_allowed = FALSE; break; case KS_DEBOUNCE: if ( keys_pressed[row][column] == TRUE ) KEYPAD_PASS_KEY_CODE( keys[row][column], HS_NONE_K ); keypad_key_state[row][column] = KS_UP_WAIT; sleep_allowed = FALSE;
KEY EVENT - LONG KEY handle_hs_key keypad_pass_key_code 함수를통해받은 key값을 handle_hs_key에서처리 ui_keycb_reg 에서 clk_reg호출해서 cbtimer 에등록 switch( key ) case HS_0_K:... case HS_9_K: if (!ui.onetouch && ((int)key >= (int)'1' && (int)key <= (int)'9')) ui_keycb_reg( (int4)no_onetouch_time, (int4 )0, FALSE ); key_down_key = (word)key; 2500 void ui_keycb_reg( int4 ms_first, int4 ms_periodic, boolean repeat ) clk_reg( &key_cb, ui_key_cb, ms_first, ms_periodic, repeat);
KEY EVENT - LONG KEY 2500msec 안에키를뗄경우 (KS_KEY_UP) keypad_scan_keypad 함수에서 KS_KEY_UP 상태로되면서 HS_RELEASE_K 를 KEYPAD_PASS_KEY_CODE 인자로넘겨준다 case KS_UP_WAIT: if ( keys_pressed[row][column] == TRUE ) sleep_allowed = FALSE; else keypad_key_state[row][column] = KS_KEY_UP; KEYPAD_PASS_KEY_CODE( HS_RELEASE_K, keys[row][column] ); break;
KEY EVENT - LONG KEY handle_hs_key keypad_pass_key_code 함수를통해받은 HS_RELEASE_K 처리 ui_key_cb_dereg 함수로 callback timer에서제거한다 switch( key )... case HS_RELEASE_K: key_down_key = (word)hs_none_k; ui_keycb_dereg(); break;... void ui_keycb_dereg( void ) clk_dereg( &key_cb ); void clk_dereg ( clk_cb_type *call_back_ptr ) clk_cb_delete( call_back_ptr );
KEY EVENT - LONG KEY 2500msec 안에키를안뗄경우 ( KS_UP_WAIT ) 2500msec가지나면등록해놓은 callback timer에의해 ui_key_cb 함수호출 timeflags 에 UI_KEY_TIMER set, UI_TIMER_SIG set void ui_keycb_reg( int4 ms_first, int4 ms_periodic, boolean repeat ) clk_reg( &key_cb, ui_key_cb, ms_first, ms_periodic, repeat); static void ui_key_cb ( int4 interval ) ui_set_sigs (&timeflags, UI_KEY_TIMER); (void) rex_set_sigs( &ui_tcb, UI_TIMERS_SIG ); static void ui_set_sigs (word* bit_mask, word or_mask) INTLOCK(); *bit_mask = or_mask; INTFREE();
KEY EVENT - LONG KEY ui_signal timerflags를검사해서해당 event 수행 rex_clr_sigs 로 UI_TIMER_SIG unset void ui_signal ( rex_sigs_type sigs, q_type *ui_cmd_q_ptr ) if( sigs & UI_TIMERS_SIG ) handle_timers(); (void) rex_clr_sigs( &ui_tcb, UI_TIMERS_SIG );...
KEY EVENT - LONG KEY handle_timers ui_do_event 실행 clk_dereg 실행 if( timeflags & UI_KEY_TIMER ) ui_clear_sigs (&timeflags, (word) ~UI_KEY_TIMER); switch( key_down_key ) case HS_1_K:... case HS_0_K: ui.wasonetouch = TRUE; ui_do_event( (word)ui_digdown_f ); key_down_key = (word)ui_digdown_f; clk_dereg( &key_cb ); UI_ENABLE_SLEEP(); break;...
STATE 구현 KEY TASK input key event hs_key_thread() SetEvent 제어 UI TASK state machine ui_task() ALARM TASK alarm check alarm_thread()
STATE 구현 - ALARM TASK alarm_thread while(1) current_date = get_current_date(); current_time = get_current_time(); temp = my_schedule->head; while( temp!= NULL ) schedule_date = atoi(temp->date); schedule_time = atoi(temp->time); if( current_date == schedule_date && current_time == schedule_time) puts("\n\n\nalarm\a"); puts("========================================="); printf("1.date = %s\n",temp->date); printf("2.time = %s\n",temp->time); printf("3.type = %s\n",temp->kind); printf("4.memo = %s\n",temp->memo); puts("=========================================\n\n"); temp = temp->link; sleep(60000);
STATE 구현 - KEY TASK wr_idx 0 1 2 3 4 5... 27 28 29 30 31 rd_idx typedef struct byte rd_idx; /* read index */ byte wr_idx; /* write index */ byte data [ UI_KEY_BUF_SIZE ]; /* data buffer */ ui_key_buffer 31
STATE 구현 - KEY TASK Write void hs_key_thread( void* arg ) while ( TRUE ) WaitForSingleObject( hkeyevent, INFINITE); key_buffer.data[key_buffer.wr_idx] = getch(); key_buffer.wr_idx = (key_buffer.wr_idx+1) & UI_KEY_BUF_MASK; rex_set_sigs(ui_key_sig); SetEvent while ui_do_event( ); SetEvent( hkeyevent ); rex_set_sigs sigs = sigs p_sigs;
STATE 구현 - UI TASK head 0 1 2 3 4 5... 27 28 29 30 31 tail typedef struct int head; int tail; word buf[ UI_EVENT_SIZE ]; ui_event_type; 33
STATE 구현 - UI TASK ui_task ui_init(); scheduler_init(); for( ;; ) ui_signal(sigs); if ( ui_event.head!= ui_event.tail ) ui_event.tail=( ui_event.tail+1 )%UI_EVENT_SIZE; ui_do_event( ui_event.buf[ ui_event.tail ] ); SetEvent(hKeyEvent); else ui_do_event( UI_NONE_F ); if(!ui.pwr ) break; view_del_total(del); ui_do_event ui_maj_type new_state; ui.event = (int)in_event; do switch( state ) case UI_STARTUP_S: new_state = uistate_startup(); break; case UI_IDLE_S: new_state = uistate_idle(); break; case...... default : push / pop 연산 while ( new_state!= UI_NOSTATE_S );
STATE 구현 - UI TASK ui_signal if( (p_sigs & UI_KEY_SIG)!= 0) rex_clr_sigs(ui_key_sig); handle_keys(); get_key() if (key_buffer.wr_idx == key_buffer.rd_idx) keycode = HS_NONE_K; else keycode = key_buffer.data[key_buffer.rd_idx]; key_buffer.rd_idx = (key_buffer.rd_idx+1) & UI_KEY_BUF_MASK; rex_clr_sigs p_sigs = ~p_sigs; sigs = sigs & p_sigs; handle_keys ui_add_event hs_key_type key; while ( ( key = (hs_key_type)get_key())!= HS_NONE_K ) handle_hs_key(key); if( ( ui_event.head+1 ) % UI_EVENT_SIZE!= ui_event.tail ) ui_event.head = ( ui_event.head+1 ) % UI_EVENT_SIZE; ui_event.buf[ ui_event.head ] = event; handle_hs_key ui_add_event( (word)key );
36 소스코드및실행화면
37 질의응답및토의