/*! * Check tx message queue to see if any messages are pending. * * \retvalue ERR_OK Transmission started successfully. * ERR_NOTAVAIL No channel available. * ERR_VALUE Invalid tx type selected. * ERR_DISABLED Device was remotely disable (MaxDCycle setting). * ERR_RXEMPTY Message queue is empty. */ static uint8_t CheckTx( void ) { LoRaPhy_ChannelParams_t channel; uint8_t flags; uint8_t TxDataBuffer[LORAPHY_BUFFER_SIZE]; if ( GetTxMsg(TxDataBuffer, sizeof(TxDataBuffer)) == ERR_OK ) { #if 0 if ( SetNextChannel() != ERR_OK ) { return ERR_NOTAVAIL; } #endif flags = LORAPHY_BUF_FLAGS(TxDataBuffer); channel = Channels[pLoRaDevice->currChannelIndex]; if ( flags & LORAPHY_PACKET_FLAGS_JOIN_REQ ) { pLoRaDevice->rxWindow1Delay = JoinAcceptDelay1 - RADIO_WAKEUP_TIME; pLoRaDevice->rxWindow2Delay = JoinAcceptDelay2 - RADIO_WAKEUP_TIME; } else { pLoRaDevice->rxWindow1Delay = ReceiveDelay1 - RADIO_WAKEUP_TIME; pLoRaDevice->rxWindow2Delay = ReceiveDelay2 - RADIO_WAKEUP_TIME; } Radio.SetChannel(channel.Frequency); Radio.SetMaxPayloadLength(MODEM_LORA, LORAPHY_BUF_SIZE(TxDataBuffer)); if ( pLoRaDevice->currDataRateIndex == DR_7 ) { // High Speed FSK channel Radio.SetTxConfig(MODEM_FSK, TxPowers[pLoRaDevice->currTxPowerIndex], 25e3, 0, Datarates[pLoRaDevice->currDataRateIndex] * 1e3, 0, 5, false, true, 0, 0, false, TX_TIMEOUT); TxTimeOnAir = Radio.TimeOnAir(MODEM_FSK, LORAPHY_BUF_SIZE(TxDataBuffer)); } else if ( pLoRaDevice->currDataRateIndex == DR_6 ) { // High speed LoRa channel Radio.SetTxConfig(MODEM_LORA, TxPowers[pLoRaDevice->currTxPowerIndex], 0, 1, Datarates[pLoRaDevice->currDataRateIndex], 1, 8, false, true, 0, 0, false, TX_TIMEOUT); TxTimeOnAir = Radio.TimeOnAir(MODEM_LORA, LORAPHY_BUF_SIZE(TxDataBuffer)); } else { // Normal LoRa channel Radio.SetTxConfig(MODEM_LORA, TxPowers[pLoRaDevice->currTxPowerIndex], 0, 0, Datarates[pLoRaDevice->currDataRateIndex], 1, 8, false, true, 0, 0, false, TX_TIMEOUT); TxTimeOnAir = Radio.TimeOnAir(MODEM_LORA, LORAPHY_BUF_SIZE(TxDataBuffer)); } if ( MaxDCycle == 255 ) { return ERR_DISABLED; } if ( MaxDCycle == 0 ) { AggregatedTimeOff = 0; } if ( MAX(Bands[channel.Band].TimeOff, AggregatedTimeOff) > (TimerGetCurrentTime()) ) { // Schedule transmission LOG_TRACE("Send in %d ticks on channel %d (DR: %u).", MAX(Bands[channel.Band].TimeOff, AggregatedTimeOff), channel.Frequency, pLoRaDevice->currDataRateIndex); vTaskDelay( MAX(Bands[channel.Band].TimeOff, AggregatedTimeOff) / MAX(Bands[channel.Band].TimeOff, AggregatedTimeOff)); } else { // Send now LOG_TRACE("Sending at %u ms on channel %d (DR: %u).", (uint32_t)(TimerGetCurrentTime() * portTICK_PERIOD_MS), channel.Frequency, pLoRaDevice->currDataRateIndex); Radio.Send(LORAPHY_BUF_PAYLOAD_START(TxDataBuffer), LORAPHY_BUF_SIZE(TxDataBuffer)); // LOG_DEBUG("Send data on channel with frequency %u Hz", channel.Frequency); } if ( (flags & LORAPHY_PACKET_FLAGS_FRM_MASK) == LORAPHY_PACKET_FLAGS_FRM_ADVERTISING ) { phyFlags.Bits.TxType = LORAPHY_TXTYPE_ADVERTISING; } else if ( (flags & LORAPHY_PACKET_FLAGS_FRM_MASK) == LORAPHY_PACKET_FLAGS_FRM_REGULAR ) { phyFlags.Bits.TxType = LORAPHY_TXTYPE_REGULAR; } else if ( (flags & LORAPHY_PACKET_FLAGS_FRM_MASK) == LORAPHY_PACKET_FLAGS_FRM_MULTICAST ) { phyFlags.Bits.TxType = LORAPHY_TXTYPE_MULTICAST; } else { return ERR_VALUE; } return ERR_OK; } return ERR_NOTAVAIL; /* no data to send? */ }
void ReadCTMU( void ) { int current_ipl; int i; int j; volatile unsigned int tempADch; tempADch = AD1CHS0; //store the current A/D mux channel selected AD1CON1 = 0x0000; // Unsigned integer format AD1CSSL = 0x0000; AD1CON3 = 0x0002; AD1CON2 = 0x0000; AD1CON1bits.ADON = 1; // Start A/D in continuous mode for(i = 0; i < NUM_TOUCHPADS; i++) { // Get the raw sensor reading. AD1CHS0 = STARTING_ADC_CHANNEL + buttonIndex; //select A/D channel // Make sure touch circuit is completely discharged IFS0bits.AD1IF = 0; AD1CON1bits.DONE = 0; AD1CON1bits.SAMP = 1; // Manually start the conversion // Wait for the A/D converter to begin sampling Nop(); Nop(); Nop(); Nop(); Nop(); Nop(); Nop(); Nop(); CTMUCONbits.IDISSEN = 1; // Drain any charge on the circuit Nop(); Nop(); Nop(); Nop(); Nop(); CTMUCONbits.IDISSEN = 0; Nop(); Nop(); Nop(); Nop(); Nop(); IFS0bits.AD1IF = 0; AD1CON1bits.SAMP = 0; while(!IFS0bits.AD1IF); // Wait for the A/D conversion to finish // Note: This A/D conversion not used. // A/D mux must connect to the channel // for CTMU to drain charge // Charge touch circuit // Since the charge is time dependent, set the CPU priority such // that we will not be interrupted during the read. SET_AND_SAVE_CPU_IPL( current_ipl, 7 ); IFS0bits.AD1IF = 0; AD1CON1bits.SAMP = 1; // Manually start the conversion CTMUCONbits.EDG2STAT = 0; // Make sure edge2 is 0 CTMUCONbits.EDG1STAT = 1; // Set edge1 - Start Charge for (j = 0; j < CHARGE_TIME_COUNT; j++); // Delay for CTMU charge time CTMUCONbits.EDG1STAT = 0; // Clear edge1 - Stop Charge // Re-enable interrupts. RESTORE_CPU_IPL( current_ipl ); IFS0bits.AD1IF = 0; AD1CON1bits.SAMP = 0; while(!IFS0bits.AD1IF); // Wait for the A/D conversion to finish value = ADC1BUF0; // Read the value from the A/D conversion //Discharge the touch circuit IFS0bits.AD1IF = 0; AD1CON1bits.SAMP = 1; // Manually start the conversion // Wait for A/D conversion to begin Nop(); Nop(); Nop(); Nop(); Nop(); Nop(); Nop(); Nop(); CTMUCONbits.IDISSEN = 1; // Drain any charge on the circuit Nop(); Nop(); Nop(); Nop(); Nop(); CTMUCONbits.IDISSEN = 0; // End charge drain Nop(); Nop(); Nop(); Nop(); IFS0bits.AD1IF = 0; AD1CON1bits.SAMP = 0; // Perform conversion while(!IFS0bits.AD1IF); // Wait for the A/D conversion to finish IFS0bits.AD1IF = 0; AD1CON1bits.DONE = 0; // Note: The A/D conversion not used // A/D mux must connect to the channel // for CTMU to drain charge //End of CTMU read bigVal = value * 16; // bigVal is current measurement left shifted 4 bits smallAvg = average[buttonIndex] / 16; // smallAvg is the current average right shifted 4 bits rawCTMU[buttonIndex] = bigVal; // raw array holds the most recent bigVal values // On power-up, reach steady-state readings if (first > 0) { first--; average[buttonIndex] = bigVal; SetNextChannel(); break; } // Is a keypad button pressed or released? if (bigVal < (average[buttonIndex] - trip[buttonIndex])) { // Pressed switch(buttonIndex) { case TOUCHPAD1: buttons.BTN1 = 1; break; case TOUCHPAD2: buttons.BTN2 = 1; break; case TOUCHPAD3: buttons.BTN3 = 1; break; case TOUCHPAD4: buttons.BTN4 = 1; break; case TOUCHPAD5: buttons.BTN5 = 1; break; } } else if (bigVal > (average[buttonIndex] - trip[buttonIndex] + hyst[buttonIndex])) { // Released switch(buttonIndex) { case TOUCHPAD1: buttons.BTN1 = 0; break; case TOUCHPAD2: buttons.BTN2 = 0; break; case TOUCHPAD3: buttons.BTN3 = 0; break; case TOUCHPAD4: buttons.BTN4 = 0; break; case TOUCHPAD5: buttons.BTN5 = 0; break; } } // Implement quick-release for a released button if (bigVal > average[buttonIndex]) { average[buttonIndex] = bigVal; // If raw is above Average, reset to high average. } // Average in the new value. Always Average (all buttons) // Counting 0..8 has effect of every 9th count cycling the next button. // Counting 0..4 will average faster and also can use 0..4*m, m=0,1,2,3.. if(i == 0) { if (AvgIndex < AVG_DELAY) { AvgIndex++; } else { AvgIndex = 0; } } if (AvgIndex == AVG_DELAY) { // Average in raw value. average[buttonIndex] = average[buttonIndex] + (value - smallAvg); } // Determine next sensor to test. SetNextChannel(); } if((screenState == SCREEN_GRAPH) || (screenState == SCREEN_CAPTURE)) { // Read the potentiometer and store it for the demo. GraphReadPotentiometer(); } #ifdef USE_TOUCHPAD_STATE_MACHINE GestureStateMachine(); #endif AD1CHS0 = tempADch; //restore A/D channel select }