// // Extract a NMEA 0183 word from a sentence at the given // position. // // Positions are numbered from 1 to n, based on position in the // NMEA sentence. // // The position separator is ",", except for the last entry // in which its "*". // // $WIMWV,270,T,3.5,M,A*00 // | | | | | // 1 2 3 4 5 // // The first position (1) does not start with "," as its pointed // to after the prefix ($WIMWV,) // // The sentence is expected to end with '*' // // "270,T,3.5,M,A*" // // Returns the count placed into the buffer not including the '\0' // int ExtractNMEAWord(char* str, int position, char* outputBuf, int outputBufSize) { int length; char* start; char* end; int tokenCount = 0; if (str == NULL) { return 0; } if (*str == '\0') { return 0; } if (position == 0) { DBG_PRINT("E1"); return 0; } // Find start token start = NMEAMoveToToken(str, position - 1); if (start == NULL) { DBG_PRINT("E2"); return 0; } // Move past ',' if not start if (position != 1) { start++; } // Find next token end = NMEAMoveToToken(str, position); if (end == NULL) { DBG_PRINT("E3"); return 0; } // // *start points to first char // *end points at ',' or '*' // length = end - start; if ((length + 1) > outputBufSize) { DBG_PRINT("E4"); return 0; } memcpy(outputBuf, start, length); outputBuf[length] = '\0'; DBG_PRINT_NNL("length "); DBG_PRINT_INT(length); return length; }
void SampleSensors(void) { // Turn on sensors SENSORS_ENABLE = 1; // Settle time DelayMs(10); { sensorVals.temp = AdcSampleTemp(); sensorVals.tempCx10 = ConvertTempToCelcius(sensorVals.temp); DBG_INFO("\r\nTemp:"); DBG_PRINT_INT(sensorVals.tempCx10); } { // Using lookup and linear interpolate and temperature from above, see excel sheet unsigned char temp8 = (sensorVals.tempCx10 + 5)/10; // Truncate to 1C resolution sensorVals.humid = SampleHumidity(); // Sample sensorVals.humidSat = ConvertHumidityToSat(sensorVals.humid,temp8); DBG_INFO("\r\nHumidity:"); DBG_PRINT_INT((sensorVals.humidSat>>8)); DBG_INFO("."); DBG_PRINT_INT((40*(sensorVals.humidSat&0xff))>>10); } { sensorVals.light = SampleLight(); sensorVals.lightLux = ConvertLightToLux(sensorVals.light); DBG_INFO("\r\nLight:"); DBG_PRINT_INT(sensorVals.lightLux); } { sensorVals.fvr = SampleFvrForVdd(); sensorVals.vddmv = ConvertFvrToVddMv(sensorVals.fvr); DBG_INFO("\r\nBatt:"); DBG_PRINT_INT(sensorVals.vddmv); } { // We dont want to do this or the state change could be missed //sensorVals.switchState = SWITCH; } // Turn off sensors SENSORS_ENABLE = 0; // Done... }
// // This dispatches the given Set/Get state handler commands at // the specified index. // // It passes the boolean argument. // // This dispatch is typed to the current class by using the "this" pointer. // int MenloDweet::DispatchFunctionFromTable( PGM_P functionTable, // table of PGM function pointers MenloObject* object, // object "this" to invoke on int index, char* buf, int size_arg, bool bool_arg ) { int retVal; // Allows common use for SETSTATE/SETCONFIG if (functionTable == NULL) { xDBG_PRINT("DispatchFunction from table is null"); return DWEET_NO_FUNCTION; } // // Compiler (GCC) does not allow this, so resort to the union trick. // // method = (StateMethod)m; // union { unsigned long p; StateMethod m; } method; // Can't do this on an AtMega due to separate I + D space // method = functionTable[index]; // // MenloPlatform.h // method.p = MenloPlatform::GetMethodPointerFromMethodArray( (char**)functionTable, index); DBG_PRINT_NNL("function address "); DBG_PRINT_INT((uint16_t)method.p); // If the entry is null, return not implemented code if (method.p == NULL) { xDBG_PRINT("DispatchFunction from table entry is null"); return DWEET_NO_FUNCTION; } retVal = ((object)->*(method.m))(buf, size_arg, bool_arg); return retVal; }
// // Set a timer to power off the radio after a // period of inactivity. // // The inactivityTimer is the amount of time the radio // should remain powered on when there is no more // activity. // // A value of 0 means the radio is always powered // on. Otherwise its the time in milliseconds before // the radio will power down due to inactivity. // // When the radio is powered off ReceiveDataReady() // will return a no data indication since the receiver // if off. // void MenloRadio::SetPowerTimer(unsigned long inactivityTimer) { // // m_powerInterval is not zero if a timer has been set. // xDBG_PRINT_NNL("SetPowerTimer inactivityTimer low "); xDBG_PRINT_INT((uint16_t)inactivityTimer); xDBG_PRINT_NNL("SetPowerTimer inactivityTimer high "); xDBG_PRINT_INT((uint16_t)(inactivityTimer >> 16)); // See if there has been a change in the activity timer if (inactivityTimer != m_powerInterval) { #if NEW_TIMER if ((m_powerInterval != 0) && m_radioPowerState) { #else if (m_powerInterval != 0) { #endif xDBG_PRINT("SetPowerTimer unregistered previous timer"); m_timer.UnregisterIntervalTimer(&m_timerEvent); } m_powerInterval = inactivityTimer; // Update interval m_timerEvent.m_interval = m_powerInterval; // // m_powerInterval == 0 means radio always powered on // so we don't start the inactivityTimer. // if (m_powerInterval != 0) { #if NEW_TIMER if ((m_powerInterval != 0) && m_radioPowerState) { xDBG_PRINT("SetPowerTimer registering powerTimer"); m_timer.RegisterIntervalTimer(&m_timerEvent); } #else xDBG_PRINT("Old code SetPowerTimer registering powerTimer"); m_timer.RegisterIntervalTimer(&m_timerEvent); #endif } else { xDBG_PRINT("Radio inactivityTimer disabled"); } } } // // TimerEvent runs every m_powerInterval when enabled // and the radio is powered on. // unsigned long MenloRadio::TimerEvent(MenloDispatchObject* sender, MenloEventArgs* eventArgs) { xDBG_PRINT("RadioPower TimerEvent"); // // Indications of radioActivity // // ReceiveDataReady() - power on and receive data available // // WaitForSendComplete() - If packet is transmitting power // needs to remain on. // // Write - packet transmit - Need to see when its done // // channel and settings management: Let the radio itself manage // power internally if required for settings. // // // Application pattern is sleep 30 seconds, wake up and send an // update packet, then shutdown the radio and sleep when transmit // is done. Though in many cases we also want to listen for a little // while in case the gateway/edge unit has a message for us. // // Check to see if we should power down the radio if (m_radioPowerState) { if (m_radioActivity) { // // There has been radio activity in the last period // so reset it and return and check again in the next // period. // m_radioActivity = false; xDBG_PRINT("RadioPower cleared activity bit power still on"); } else { // // No radioActivity for at least one radio power interval // // See if attention is active // if (m_radioAttentionActive) { xDBG_PRINT("Radio Attention is active keeping power on"); DBG_PRINT_NNL("m_attentionInterval low "); DBG_PRINT_INT((uint16_t)m_attentionInterval); DBG_PRINT_NNL("m_attentionInterval high "); DBG_PRINT_INT((uint16_t)(m_attentionInterval >> 16)); DBG_PRINT_NNL("m_powerInterval low "); DBG_PRINT_INT((uint16_t)m_powerInterval); DBG_PRINT_NNL("m_powerInterval high "); DBG_PRINT_INT((uint16_t)(m_powerInterval >> 16)); if (m_powerInterval > m_attentionInterval) { // Don't under wrap m_attentionInterval = 0; } else { m_attentionInterval -= m_powerInterval; } if (m_attentionInterval == 0) { // Attention interval has gone to zero, clear attention m_radioAttentionActive = false; xDBG_PRINT("Radio Attention interval ended"); // // Radio will be powered down on the next power interval // if there is no activity. // } DBG_PRINT_NNL("new m_attentionInterval low "); DBG_PRINT_INT((uint16_t)m_attentionInterval); DBG_PRINT_NNL("new m_attentionInterval high "); DBG_PRINT_INT((uint16_t)(m_attentionInterval >> 16)); } else { // // Attention is not active and the radio has had // no activity for the power interval, so power down the radio. // DBG_PRINT("RadioPower no activity powering off radio"); m_radioPowerState = false; #if NEW_TIMER xDBG_PRINT("RadioTimerEvent powering off radio and uregistering timer"); m_timer.UnregisterIntervalTimer(&m_timerEvent); #endif OnPowerOff(); } } }
unsigned char PirTasks(void) { // PIR tasks state static unsigned short lastVal = 0; static unsigned short IIRsum = 0; static unsigned char counter = 0, suspect = 0, detected = 1, disarmed = 1; signed short delta; unsigned char absDelta; // Update the ADC value SampleChannel(PIR_CHANNEL); // Differentiate delta = adcResults.pir - lastVal; // Rectify and clamp to 6 bits (for 8bit IIR) if(delta > 63 || delta < -63) absDelta = 63; else if (delta < 0) absDelta = -delta; else absDelta = delta; // Update energy accumulator sensorVals.pirEnergy += absDelta; // IIR low pass results (+2 bit precision) IIRsum = (IIRsum*3) + (absDelta<<2); IIRsum = (IIRsum + 4) >> 2; // Save current sample lastVal = adcResults.pir; // Time and threshold based detection if((absDelta >= settings.pir_suspect_val) && (suspect < settings.pir_suspect_count)){counter = settings.pir_suspect_release; suspect++;} else if (counter) {counter--;} else if (suspect) {suspect--;counter = settings.pir_suspect_release;} else ; // Disarm detector until settled or for timeout if(detected == 1) { if(disarmed == 0) // True after initial detection { disarmed = settings.pir_disarm_time; // Disarm detector for a time } if( IIRsum < settings.pir_threshold // If we are not triggered || (--disarmed==0) ) // or the disarm timer is up { disarmed = 0; // Re-arm suspect = 0; // Clear time based detection IIRsum = 0; // Clear filter detected = 0; // Clear flag, will be armed on next sample } } // Suspicion raised above threshold, for distant movement else if (suspect >= settings.pir_suspect_count) { detected = 1; sensorVals.pirSuspCounts++; } // Threshold only based trigger, for close proximity else if(IIRsum >= settings.pir_threshold) { // Return detected detected = 1; sensorVals.pirCounts++; } // Debugging DBG_INFO("\r\nPIR,"); DBG_PRINT_INT(adcResults.pir); DBG_INFO(","); DBG_PRINT_INT(absDelta); DBG_INFO(","); DBG_PRINT_INT(IIRsum); DBG_INFO(","); DBG_PRINT_INT(suspect); DBG_INFO(","); DBG_PRINT_INT(detected); // Return return (detected & (disarmed==0)); }