//
// 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;
}
Пример #2
0
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...
}
Пример #3
0
//
// 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;
}
Пример #4
0
//
// 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();
            }
        }
    }
Пример #5
0
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));
}