/**************************************************************************** DESCRIPTION Called after the configuration has been read and will trigger buttons events if a pio has been pressed or held whilst the configuration was still being loaded , i.e. the power on button press */ void ButtonsCheckForChangeAfterInit(void) { uint32 input_state; /* contains translated pio and capsense bits, format is inputs */ ButtonsTaskData * lButtonsTask = theSink.theButtonsTask ; lButtonsTask->gBTime = B_INVALID ; /* translate the pio and capsense bits into 'input' bits mask */ #ifdef ENABLE_CAPSENSE input_state = ButtonsTranslate(lButtonsTask->gOldCapState, (((PIOGET()^theSink.conf1->PIOIO.pio_invert) | CHARGER_VREG_VALUE | CHARGER_CONNECT_VALUE))); #else input_state = ButtonsTranslate(0, (((PIOGET()^theSink.conf1->PIOIO.pio_invert) | CHARGER_VREG_VALUE | CHARGER_CONNECT_VALUE))); #endif /* perform a level detect looking for transistion of recently added button definition, mask inputs against level configured inputs to prevent false button press indications */ ButtonsLevelDetect ( (input_state & lButtonsTask->gPerformInputLevelCheck) , lButtonsTask ) ; /* perform an edge detect looking for transistion of recently added button definition, mask inputs against edge configured inputs to prevent false button press indications */ ButtonsEdgeDetect ( (input_state & lButtonsTask->gPerformInputEdgeCheck) , lButtonsTask) ; /* store current input states in order to be able to detect the transition of an input (pio or capsense) in the button handler */ lButtonsTask->gBOldInputState = input_state; /* Debounce required PIO lines */ if(!PioCommonDebounce((lButtonsTask->gButtonPIOLevelMask & ~(VREG_PIN_MASK|CHG_PIN_MASK)), lButtonsTask->button_config->debounce_number, lButtonsTask->button_config->debounce_period_ms )) { B_DEBUG(("B: **** ERROR **** PIO NOT AVAILABLE = 0x%lx\n",input_state)) ; #ifdef DEBUG_BUTTONS Panic(); #endif } ChargerDebounce( (CHARGER_VREG_EVENT|CHARGER_CONNECT_EVENT), lButtonsTask->button_config->debounce_number, lButtonsTask->button_config->debounce_period_ms ); B_DEBUG(("B: initial buttoncheck\n")) ; }
/**************************************************************************** DESCRIPTION Called after the configuration has been read and will trigger buttons events if a pio has been pressed or held whilst the configuration was still being loaded , i.e. the power on button press */ void ButtonsCheckForChangeAfterInit(void) { uint32 pio_state; ButtonsTaskData * lButtonsTask = theHeadset.theButtonsTask ; lButtonsTask->gBTime = B_INVALID ; { /* get 32 bit pio state for BC5 onwards chips */ pio_state = (((PIOGET() & 0xffff) | CHARGER_VREG_VALUE | CHARGER_CONNECT_VALUE)) ; /* perform a level detect looking for transistion of recently added button definition, mask pio's against level configured pios to prevent false butotn press indications */ ButtonsLevelDetect ( (pio_state & lButtonsTask->gPerformLevelCheck) , lButtonsTask ) ; /* perform an edge detect looking for transistion of recently added button definition, mask pio's against edge configured pios to prevent false button press indications */ ButtonsEdgeDetect ( (pio_state & lButtonsTask->gPerformEdgeCheck) , lButtonsTask) ; } /* store current set pio state in order to be able to detect the transition of a PIO in the button handler */ lButtonsTask->gOldPioState = pio_state; /* Debounce required PIO lines */ pio_state = PioDebounce32((0xFFFF & lButtonsTask->gButtonLevelMask), /* mask off upper 16 bits */ lButtonsTask->button_config->debounce_number, lButtonsTask->button_config->debounce_period_ms ); /* check whether it has been possible to select the use of PIOs specified, if it was not possible to use all the PIOs specified due to a PIO being assigned a different function by PSKEY then none of the PIOs will now work so mask out the unavailable PIO and assign the PIOs that are available for receiving change notifications */ if(pio_state) { /* mask out the unavailable PIOs and register those PIOs that are available for receiving change events */ PioDebounce32((0xFFFF & lButtonsTask->gButtonLevelMask & ~pio_state), /* mask off upper 16 bits */ lButtonsTask->button_config->debounce_number, lButtonsTask->button_config->debounce_period_ms ); B_DEBUG(("B: **** ERROR **** PIO NOT AVAILABLE = 0x%lx\n",pio_state)) ; #ifdef DEBUG_BUTTONS Panic(); #endif } #ifdef BHC612_ ChargerDebounce( (CHARGER_VREG_EVENT|CHARGER_CONNECT_EVENT), 4, 250 ); #else ChargerDebounce( (CHARGER_VREG_EVENT|CHARGER_CONNECT_EVENT), lButtonsTask->button_config->debounce_number, lButtonsTask->button_config->debounce_period_ms ); #endif }
static void ButtonsMessageHandler ( Task pTask, MessageId pId, Message pMessage ) { ButtonsTaskData * lBTask = (ButtonsTaskData*)pTask ; B_DEBUG(("B:Message\n")) ; switch ( pId ) { case MESSAGE_PIO_CHANGED : { const MessagePioChanged * lMessage = ( const MessagePioChanged * ) (pMessage ) ; uint32 lNewPioState = (uint32)( lMessage->state | CHARGER_VREG_VALUE | CHARGER_CONNECT_VALUE) ; B_DEBUG(("B:BMH - PIO_CHANGE: %x %x\n",lMessage->state16to31, lMessage->state)) ; /* when a pio is configured for an edge detect only there is significant performance gain to be had by only doing an edge detect call and not a level detect. To do this use a previously set edge detect mask and check this against the current pio being reported. Also need to check if a previously set PIO has now been removed and check for the edge transition once again. */ if((lBTask->gPerformEdgeCheck & lNewPioState) || (lBTask->gPerformEdgeCheck & lBTask->gOldPioState)) { /* check for a valid edge transition against current pio states masked with edge configured pios and perform appropriate action */ ButtonsEdgeDetect ( (uint32)( lNewPioState & lBTask->gPerformEdgeCheck), lBTask ) ; } /* only do a level detect call which is vm/messaging intensive when a pio has been configured as short or long or very long or very very long, i.e. not rising or falling */ if((lBTask->gPerformLevelCheck & lNewPioState ) || (lBTask->gPerformLevelCheck & lBTask->gOldPioState)) { /* perform a level detection, this call uses a number of messages and is quite slow to process */ ButtonsLevelDetect ( ((uint32)lNewPioState & lBTask->gPerformLevelCheck) , lBTask) ; } /* store current set pio state in order to be able to detect the transition of a PIO configured as edge detect only */ lBTask->gOldPioState = lNewPioState ; } break ; case MESSAGE_CHARGER_CHANGED: { const MessageChargerChanged *m = (const MessageChargerChanged *) (pMessage ) ; /* when a charger or vreg change event is detectecd perform both an edge and level detection passing in only those approriately masked pios for edge or level configured buttons */ ButtonsLevelDetect ( (((uint32)m->vreg_en_high << VREG_PIN) | ((uint32)m->charger_connected << CHG_PIN) | PIOGET()) & lBTask->gPerformLevelCheck , lBTask) ; ButtonsEdgeDetect ( (((uint32)m->vreg_en_high << VREG_PIN) | ((uint32)m->charger_connected << CHG_PIN) | PIOGET()) & lBTask->gPerformEdgeCheck , lBTask ) ; } break; case B_DOUBLE_TIMER: { /*if we have reached here, then a double timer has been received*/ B_DEBUG(("B:Double[%lx][%x]\n", lBTask->gBDoubleState , B_SHORT_SINGLE)) ; lBTask->gBDoubleTap = FALSE ; /*indicate that a short button was pressed and it did not become a double press */ ButtonsButtonDetected ( lBTask, lBTask->gBDoubleState , B_SHORT_SINGLE ); } break ; case B_INTERNAL_TIMER: { /*if we have reached here, then the buttons have been held longer than one of the timed messages*/ B_DEBUG(("B:Timer\n")) ; /* an internal timer has triggered which was initiated from the level detect function call */ if ( lBTask->gBTime == B_VERY_LONG ) { /* update timer state flag */ lBTask->gBTime = B_VERY_VERY_LONG ; } /* a long press timer event has triggered */ else if ( lBTask->gBTime == B_LONG ) { /* don't send very very long timer message until needed, i.e. very_long timer expired */ MessageSendLater ( &lBTask->task , B_INTERNAL_TIMER , 0 , (lBTask->button_config->very_very_long_press_time - lBTask->button_config->very_long_press_time ) ) ; /* update tiemr state flag */ lBTask->gBTime = B_VERY_LONG ; /*notify the app that the timer has expired*/ MessageSend( &theHeadset.task , EventVLongTimer , 0 ) ; } /* the first timer event triggered from the level detect call */ else { /* only send very long message when long timer expired to save messaging. */ MessageSendLater ( &lBTask->task , B_INTERNAL_TIMER , 0 , (lBTask->button_config->very_long_press_time - lBTask->button_config->long_press_time)) ; /*notify the app that the timer has expired*/ MessageSend( &theHeadset.task , EventLongTimer , 0 ) ; lBTask->gBTime = B_LONG ; } /*indicate that we have received a message */ ButtonsButtonDetected ( lBTask, lBTask->gBOldState , lBTask->gBTime ); } break ; case B_REPEAT_TIMER: { /*if we have reached here, the repeat time has been reached so send a new message*/ B_DEBUG(("B:Repeat[%lx][%x]\n", lBTask->gBOldState , B_REPEAT )) ; /*send another repeat message*/ MessageSendLater ( &lBTask->task , B_REPEAT_TIMER , 0 , lBTask->button_config->repeat_time ) ; ButtonsButtonDetected ( lBTask, lBTask->gBOldState , B_REPEAT ); } break; default : B_DEBUG(("B:?[%x]\n",pId)) ; break ; } }
static void ButtonsMessageHandler ( Task pTask, MessageId pId, Message pMessage ) { ButtonsTaskData * lBTask = (ButtonsTaskData*)pTask ; B_DEBUG(("B:Message\n")) ; switch ( pId ) { #ifdef ENABLE_CAPSENSE /* delay handling of messages until capsense hardware has settled down */ case B_MESSAGE_CAPSENSE_ENABLE : { /* connect the cap sense task to this task */ MessageCapsenseTask(&lBTask->task); } break; /* indication of a change of one of the capacitive touch sensors */ case MESSAGE_CAPSENSE_CHANGED : { uint8 i; const MessageCapsenseChanged * lMessage = ( const MessageCapsenseChanged * ) (pMessage ) ; uint16 CurrentCapState = lBTask->gOldCapState; B_DEBUG(("B:Cap - Events = %x pad = %x dir = %x\n",lMessage->num_events,lMessage->event[0].pad,lMessage->event[0].direction)) ; /* the cap sense changed message may contain more than one button press, check for other presses or releases */ for(i=0;i<lMessage->num_events;i++) { /* update the state of any sensor changes, direction is inverted, 0 = down, 1 = up */ if(lMessage->event[i].direction == CAPSENSE_EVENT_POS) CurrentCapState |= (1<<(lMessage->event[i].pad)); /* due to the fact that the fw will not report multiple press need to maintain which touch sensors are up and which are down and set/reset appropriately */ else CurrentCapState &= ~(1<<(lMessage->event[i].pad)); /* as the touch sensors as less effective when releasing, increase sesitivity when button indicates pressed to accurately detect the release event */ if(lMessage->event[i].direction == CAPSENSE_EVENT_POS) { if(!CapsenseConfigurePad(lMessage->event[i].pad, CAPSENSE_SET_TRIGGER_LEVEL, BM_CAP_SENSOR_HIGH_SENSITIVITY)) B_DEBUG(("B:Cap - invalid threshold %d\n",BM_CAP_SENSOR_LOW_SENSITIVITY)); /* button gone down, it is possible to record the time in mS at which the button went down, this can be used to accurately determine how long the button was held down for */ B_DEBUG(("B:Cap - Down Time %x = %ld mS\n",i,(uint32)lMessage->event[i].time_ms)) ; } /* return to original sensitivity when releasing button */ else { if(!CapsenseConfigurePad(lMessage->event[i].pad, CAPSENSE_SET_TRIGGER_LEVEL, BM_CAP_SENSOR_LOW_SENSITIVITY)) B_DEBUG(("B:Cap - invalid threshold %d\n",BM_CAP_SENSOR_LOW_SENSITIVITY)); /* button gone up, the time in mS can be used to get accurate duration information */ B_DEBUG(("B:Cap - Up Time %x = %ld mS\n",i,(uint32)lMessage->event[i].time_ms)) ; } } B_DEBUG(("B:Cap - state = %x\n",CurrentCapState)) ; /* check whether the sensor status change requires an event to be generated */ ButtonsCheckDetection(CurrentCapState, lBTask->gOldPIOState); /* update the last state value */ lBTask->gOldCapState = CurrentCapState; } break; #endif case MESSAGE_PIO_CHANGED : { const MessagePioChanged * lMessage = ( const MessagePioChanged * ) (pMessage ) ; /* get current pio state, eor with pio invert mask */ uint32 lNewPioState = (uint32)(theSink.conf1->PIOIO.pio_invert ^ (( lMessage->state | CHARGER_VREG_VALUE | CHARGER_CONNECT_VALUE) | (((uint32)lMessage->state16to31)<<16))); B_DEBUG(("B:BMH - PIO_CHANGE: %x %x\n",lMessage->state16to31, lMessage->state)) ; #ifdef ENABLE_CAPSENSE /* check whether the pio status change requires an event to be generated */ ButtonsCheckDetection(lBTask->gOldCapState, lNewPioState); #else /* check whether the pio status change requires an event to be generated */ ButtonsCheckDetection(0, lNewPioState); #endif } break ; case MESSAGE_CHARGER_CHANGED: { const MessageChargerChanged *m = (const MessageChargerChanged *) (pMessage ) ; B_DEBUG(("B:BMH - CHG_CHANGE: %lx\n",(((uint32)m->vreg_en_high << VREG_PIN) | ((uint32)m->charger_connected << CHG_PIN) | (PIOGET()^theSink.conf1->PIOIO.pio_invert)))) ; /* when a charger or vreg change event is detectecd perform both an edge and level detection passing in only those approriately masked pios for edge or level configured buttons */ /* check whether the pio status change requires an event to be generated */ #ifdef ENABLE_CAPSENSE ButtonsCheckDetection(lBTask->gOldCapState, (((uint32)m->vreg_en_high << VREG_PIN) | ((uint32)m->charger_connected << CHG_PIN) | (PIOGET()^theSink.conf1->PIOIO.pio_invert))); #else ButtonsCheckDetection(0, (((uint32)m->vreg_en_high << VREG_PIN) | ((uint32)m->charger_connected << CHG_PIN) | (PIOGET()^theSink.conf1->PIOIO.pio_invert))); #endif } break; case B_MULTIPLE_TIMER: { /*if we have reached here, then a double timer has been received*/ B_DEBUG(("B:Double[%lx][%x]\n", lBTask->gBMultipleState , B_SHORT_SINGLE)) ; /* when the multiple press timer has expired, check to see if a double press was made and if so indicate it */ if(lBTask->gBTapCount == DOUBLE_PRESS) ButtonsButtonDetected ( lBTask , (lBTask->gBMultipleState & lBTask->gPerformInputLevelCheck) , B_DOUBLE ); /* no double press and no triple press, therefore indicate as a short single press */ else ButtonsButtonDetected ( lBTask, (lBTask->gBMultipleState & lBTask->gPerformInputLevelCheck), B_SHORT_SINGLE ); /* reset the multiple button press count */ lBTask->gBTapCount = 0 ; lBTask->gBMultipleState = 0x0000; } break ; case B_INTERNAL_TIMER: { /*if we have reached here, then the buttons have been held longer than one of the timed messages*/ B_DEBUG(("B:Timer\n")) ; /* since a long/vlong or vvlong has been triggered, cancel any pending double press checks */ lBTask->gBMultipleState = 0x0000 ; lBTask->gBTapCount = 0 ; MessageCancelAll ( &lBTask->task , B_MULTIPLE_TIMER ) ; /* an internal timer has triggered which was initiated from the level detect function call */ if ( lBTask->gBTime == B_VERY_LONG ) { /* update timer state flag */ lBTask->gBTime = B_VERY_VERY_LONG ; } /* a long press timer event has triggered */ else if ( lBTask->gBTime == B_LONG ) { /* don't send very very long timer message until needed, i.e. very_long timer expired */ MessageSendLater ( &lBTask->task , B_INTERNAL_TIMER , 0 , (lBTask->button_config->very_very_long_press_time - lBTask->button_config->very_long_press_time ) ) ; /* update tiemr state flag */ lBTask->gBTime = B_VERY_LONG ; /*notify the app that the timer has expired*/ MessageSend( &theSink.task , EventSysVLongTimer , 0 ) ; } /* the first timer event triggered from the level detect call */ else { /* only send very long message when long timer expired to save messaging. */ MessageSendLater ( &lBTask->task , B_INTERNAL_TIMER , 0 , (lBTask->button_config->very_long_press_time - lBTask->button_config->long_press_time)) ; /*notify the app that the timer has expired*/ MessageSend( &theSink.task , EventSysLongTimer , 0 ) ; lBTask->gBTime = B_LONG ; } /*indicate that we have received a message */ ButtonsButtonDetected ( lBTask, (lBTask->gBOldInputState & lBTask->gPerformInputLevelCheck) , lBTask->gBTime ); } break ; case B_REPEAT_TIMER: { /*if we have reached here, the repeat time has been reached so send a new message*/ B_DEBUG(("B:Repeat[%lx][%x]\n", lBTask->gBOldInputState , B_REPEAT )) ; /*send another repeat message*/ MessageSendLater ( &lBTask->task , B_REPEAT_TIMER , 0 , lBTask->button_config->repeat_time ) ; ButtonsButtonDetected ( lBTask, (lBTask->gBOldInputState & lBTask->gPerformInputLevelCheck) , B_REPEAT ); } break; default : B_DEBUG(("B:?[%x]\n",pId)) ; break ; } }