예제 #1
0
boolean RF22ReliableDatagram::sendtoWait(uint8_t* buf, uint8_t len, uint8_t address)
{
    // Assemble the message
    uint8_t thisSequenceNumber = ++_lastSequenceNumber;

    Timer t;

    uint8_t retries = 0;
    while (retries++ <= _retries)
    {
        setHeaderId(thisSequenceNumber);
        setHeaderFlags(0);
        sendto(buf, len, address);
        waitPacketSent(3000);

        // Never wait for ACKS to broadcasts:
        if (address == RF22_BROADCAST_ADDRESS)
            return true;

        if (retries > 1)
            _retransmissions++;
        t.start();
        unsigned long thisSendTime = t.read_ms(); // Timeout does not include original transmit time


        // Compute a new timeout, random between _timeout and _timeout*2
    // This is to prevent collisions on every retransmit
        // if 2 nodes try to transmit at the same time
        uint16_t timeout = _timeout + (_timeout * (rand() % 100) / 100);
        while (t.read_ms() < (thisSendTime + timeout)) 
        {
            if (available()) {
                clearRxBuf(); // Not using recv, so clear it ourselves
                uint8_t from = headerFrom();
                uint8_t to = headerTo();
                uint8_t id = headerId();
                uint8_t flags = headerFlags();
                // Now have a message: is it our ACK?
                if (   from == address
                        && to == _thisAddress
                        && (flags & RF22_FLAGS_ACK)
            && (id == thisSequenceNumber))
        {
                    // Its the ACK we are waiting for
                    return true;
        }
        else if (   !(flags & RF22_FLAGS_ACK)
             && (id == _seenIds[from]))
        {
                    // This is a request we have already received. ACK it again
                    acknowledge(id, from);
                }
                // Else discard it
            }
            // Not the one we are waiting for, maybe keep waiting until timeout exhausted
        }
        // Timeout exhausted, maybe retry
    }
    return false;
}
예제 #2
0
bool RHReliableDatagram::sendtoWait(uint8_t* buf, uint8_t len, uint8_t address)
{
    // Assemble the message
    uint8_t thisSequenceNumber = ++_lastSequenceNumber;
    uint8_t retries = 0;
    while (retries++ <= _retries)
    {
	setHeaderId(thisSequenceNumber);
	setHeaderFlags(0);
	sendto(buf, len, address);
	waitPacketSent();

	// Never wait for ACKS to broadcasts:
	if (address == RH_BROADCAST_ADDRESS)
	    return true;

	if (retries > 1)
	    _retransmissions++;
	unsigned long thisSendTime = millis(); // Timeout does not include original transmit time

	// Compute a new timeout, random between _timeout and _timeout*2
	// This is to prevent collisions on every retransmit
	// if 2 nodes try to transmit at the same time
	uint16_t timeout = _timeout + (_timeout * random(0, 256) / 256);
        while ((millis() - thisSendTime) < timeout)
	{
	    if (available())
	    {
		uint8_t from, to, id, flags;
		if (recvfrom(0, 0, &from, &to, &id, &flags)) // Discards the message
		{
		    // Now have a message: is it our ACK?
		    if (   from == address 
			   && to == _thisAddress 
			   && (flags & RH_FLAGS_ACK) 
			   && (id == thisSequenceNumber))
		    {
			// Its the ACK we are waiting for
			return true;
		    }
		    else if (   !(flags & RH_FLAGS_ACK)
				&& (id == _seenIds[from]))
		    {
			// This is a request we have already received. ACK it again
			acknowledge(id, from);
		    }
		    // Else discard it
		}
	    }
	    // Not the one we are waiting for, maybe keep waiting until timeout exhausted
	    YIELD;
	}
	// Timeout exhausted, maybe retry
	YIELD;
    }
    return false;
}
예제 #3
0
void RHReliableDatagram::acknowledge(uint8_t id, uint8_t from)
{
    setHeaderId(id);
    setHeaderFlags(RH_FLAGS_ACK);
    // We would prefer to send a zero length ACK,
    // but if an RH_RF22 receives a 0 length message with a CRC error, it will never receive
    // a 0 length message again, until its reset, which makes everything hang :-(
    // So we send an ACK of 1 octet
    // REVISIT: should we send the RSSI for the information of the sender?
    uint8_t ack = '!';
    sendto(&ack, sizeof(ack), from); 
    waitPacketSent();
}
예제 #4
0
파일: RF22.cpp 프로젝트: Ygorf/RF22
boolean RF22::init()
{
    // Wait for RF22 POR (up to 16msec)
    delay(16);

    // Initialise the slave select pin
    pinMode(_slaveSelectPin, OUTPUT);
    digitalWrite(_slaveSelectPin, HIGH);

    // start the SPI library:
    // Note the RF22 wants mode 0, MSB first and default to 1 Mbps
    _spi->begin();
    _spi->setDataMode(SPI_MODE0);
    _spi->setBitOrder(MSBFIRST);
    _spi->setClockDivider(SPI_CLOCK_DIV16);  // (16 Mhz / 16) = 1 MHz
    delay(100);

    // Software reset the device
    reset();

    // Get the device type and check it
    // This also tests whether we are really connected to a device
    _deviceType = spiRead(RF22_REG_00_DEVICE_TYPE);
    if (   _deviceType != RF22_DEVICE_TYPE_RX_TRX
        && _deviceType != RF22_DEVICE_TYPE_TX)
	return false;

	// Set up interrupt handler
    if (_interrupt == 0)
    {
	_RF22ForInterrupt[0] = this;
	attachInterrupt(0, RF22::isr0, LOW);  
    }
    else if (_interrupt == 1)
    {
	_RF22ForInterrupt[1] = this;
	attachInterrupt(1, RF22::isr1, LOW);  
    }
    else
	return false;
 
    clearTxBuf();
    clearRxBuf();
  
    // Most of these are the POR default
    spiWrite(RF22_REG_7D_TX_FIFO_CONTROL2, RF22_TXFFAEM_THRESHOLD);
    spiWrite(RF22_REG_7E_RX_FIFO_CONTROL,  RF22_RXFFAFULL_THRESHOLD);
    spiWrite(RF22_REG_30_DATA_ACCESS_CONTROL, RF22_ENPACRX | RF22_ENPACTX | RF22_ENCRC | RF22_CRC_CRC_16_IBM);
    // Configure the message headers
    // Here we set up the standard packet format for use by the RF22 library
    // 8 nibbles preamble
    // 2 SYNC words 2d, d4
    // Header length 4 (to, from, id, flags)
    // 1 octet of data length (0 to 255)
    // 0 to 255 octets data
    // 2 CRC octets as CRC16(IBM), computed on the header, length and data
    // On reception the to address is check for validity against RF22_REG_3F_CHECK_HEADER3
    // or the broadcast address of 0xff
    // If no changes are made after this, the transmitted
    // to address will be 0xff, the from address will be 0xff
    // and all such messages will be accepted. This permits the out-of the box
    // RF22 config to act as an unaddresed, unreliable datagram service
    spiWrite(RF22_REG_32_HEADER_CONTROL1, RF22_BCEN_HEADER3 | RF22_HDCH_HEADER3);
    spiWrite(RF22_REG_33_HEADER_CONTROL2, RF22_HDLEN_4 | RF22_SYNCLEN_2);
    setPreambleLength(8);
    uint8_t syncwords[] = { 0x2d, 0xd4 };
    setSyncWords(syncwords, sizeof(syncwords));
    setPromiscuous(false); 
    // Check the TO header against RF22_DEFAULT_NODE_ADDRESS
    spiWrite(RF22_REG_3F_CHECK_HEADER3, RF22_DEFAULT_NODE_ADDRESS);
    // Set the default transmit header values
    setHeaderTo(RF22_DEFAULT_NODE_ADDRESS);
    setHeaderFrom(RF22_DEFAULT_NODE_ADDRESS);
    setHeaderId(0);
    setHeaderFlags(0);

    // Ensure the antenna can be switched automatically according to transmit and receive
    // This assumes GPIO0(out) is connected to TX_ANT(in) to enable tx antenna during transmit
    // This assumes GPIO1(out) is connected to RX_ANT(in) to enable rx antenna during receive
    spiWrite (RF22_REG_0B_GPIO_CONFIGURATION0, 0x12) ; // TX state
    spiWrite (RF22_REG_0C_GPIO_CONFIGURATION1, 0x15) ; // RX state

    // Enable interrupts
    spiWrite(RF22_REG_05_INTERRUPT_ENABLE1, RF22_ENTXFFAEM | RF22_ENRXFFAFULL | RF22_ENPKSENT | RF22_ENPKVALID | RF22_ENCRCERROR | RF22_ENFFERR);
    spiWrite(RF22_REG_06_INTERRUPT_ENABLE2, RF22_ENPREAVAL);

    // Set some defaults. An innocuous ISM frequency, and reasonable pull-in
    setFrequency(434.0, 0.05);
//    setFrequency(900.0);
    // Some slow, reliable default speed and modulation
    setModemConfig(FSK_Rb2_4Fd36);
//    setModemConfig(FSK_Rb125Fd125);
    // Minimum power
    setTxPower(RF22_TXPOW_8DBM);
//    setTxPower(RF22_TXPOW_17DBM);

    return true;
}
예제 #5
0
bool RHReliableDatagram::sendtoWait(uint8_t* buf, uint8_t len, uint8_t address)
{
    // Assemble the message
    uint8_t thisSequenceNumber = ++_lastSequenceNumber;
    uint8_t retries = 0;
    while (retries++ <= _retries)
    {
	setHeaderId(thisSequenceNumber);

        // Set and clear header flags depending on if this is an
        // initial send or a retry.
        uint8_t headerFlagsToSet = RH_FLAGS_NONE;
        // Always clear the ACK flag
        uint8_t headerFlagsToClear = RH_FLAGS_ACK;
        if (retries == 1) {
            // On an initial send, clear the RETRY flag in case
            // it was previously set
            headerFlagsToClear |= RH_FLAGS_RETRY;
        } else {
            // Not an initial send, set the RETRY flag
            headerFlagsToSet = RH_FLAGS_RETRY;
        }
        setHeaderFlags(headerFlagsToSet, headerFlagsToClear);

	sendto(buf, len, address);
	waitPacketSent();

	// Never wait for ACKS to broadcasts:
	if (address == RH_BROADCAST_ADDRESS)
	    return true;

	if (retries > 1)
	    _retransmissions++;
	unsigned long thisSendTime = millis(); // Timeout does not include original transmit time

	// Compute a new timeout, random between _timeout and _timeout*2
	// This is to prevent collisions on every retransmit
	// if 2 nodes try to transmit at the same time
#if (RH_PLATFORM == RH_PLATFORM_RASPI) // use standard library random(), bugs in random(min, max)
	uint16_t timeout = _timeout + (_timeout * (random() & 0xFF) / 256);
#else
	uint16_t timeout = _timeout + (_timeout * random(0, 256) / 256);
#endif
	int32_t timeLeft;
        while ((timeLeft = timeout - (millis() - thisSendTime)) > 0)
	{
	    if (waitAvailableTimeout(timeLeft))
	    {
		uint8_t from, to, id, flags;
		if (recvfrom(0, 0, &from, &to, &id, &flags)) // Discards the message
		{
		    // Now have a message: is it our ACK?
		    if (   from == address 
			   && to == _thisAddress 
			   && (flags & RH_FLAGS_ACK) 
			   && (id == thisSequenceNumber))
		    {
			// Its the ACK we are waiting for
			return true;
		    }
		    else if (   !(flags & RH_FLAGS_ACK)
				&& (id == _seenIds[from]))
		    {
			// This is a request we have already received. ACK it again
			acknowledge(id, from);
		    }
		    // Else discard it
		}
	    }
	    // Not the one we are waiting for, maybe keep waiting until timeout exhausted
	    YIELD;
	}
	// Timeout exhausted, maybe retry
	YIELD;
    }
    // Retries exhausted
    return false;
}
예제 #6
0
bool RH_RF22::init()
{
    if (!RHSPIDriver::init())
	return false;

    // Software reset the device
    reset();

    // Get the device type and check it
    // This also tests whether we are really connected to a device
    _deviceType = spiRead(RH_RF22_REG_00_DEVICE_TYPE);
    if (   _deviceType != RH_RF22_DEVICE_TYPE_RX_TRX
        && _deviceType != RH_RF22_DEVICE_TYPE_TX)
    {
	return false;
    }

    // Add by Adrien van den Bossche <*****@*****.**> for Teensy
#if defined (__MK20DX128__) || defined (__MK20DX256__)
    // ARM M4 requires the below. else pin interrupt doesn't work properly.
    pinMode(_interruptPin, INPUT); 
#endif

    // Enable interrupt output on the radio. Interrupt line will now go high until
    // an interrupt occurs
    spiWrite(RH_RF22_REG_05_INTERRUPT_ENABLE1, RH_RF22_ENTXFFAEM | RH_RF22_ENRXFFAFULL | RH_RF22_ENPKSENT | RH_RF22_ENPKVALID | RH_RF22_ENCRCERROR | RH_RF22_ENFFERR);
    spiWrite(RH_RF22_REG_06_INTERRUPT_ENABLE2, RH_RF22_ENPREAVAL);

    // Set up interrupt handler
    // Since there are a limited number of interrupt glue functions isr*() available,
    // we can only support a limited number of devices simultaneously
    // On some devices, notably most Arduinos, the interrupt pin passed in is actually the 
    // interrupt number. You have to figure out the interruptnumber-to-interruptpin mapping
    // yourself based on knowledge of what Arduino board you are running on.
    _deviceForInterrupt[_interruptCount] = this;
    if (_interruptCount == 0)
	attachInterrupt(_interruptPin, isr0, FALLING);
    else if (_interruptCount == 1)
	attachInterrupt(_interruptPin, isr1, FALLING);
    else if (_interruptCount == 2)
	attachInterrupt(_interruptPin, isr2, FALLING);
    else
	return false; // Too many devices, not enough interrupt vectors
    _interruptCount++;

    setModeIdle();

    clearTxBuf();
    clearRxBuf();
  
    // Most of these are the POR default
    spiWrite(RH_RF22_REG_7D_TX_FIFO_CONTROL2, RH_RF22_TXFFAEM_THRESHOLD);
    spiWrite(RH_RF22_REG_7E_RX_FIFO_CONTROL,  RH_RF22_RXFFAFULL_THRESHOLD);
    spiWrite(RH_RF22_REG_30_DATA_ACCESS_CONTROL, RH_RF22_ENPACRX | RH_RF22_ENPACTX | RH_RF22_ENCRC | (_polynomial & RH_RF22_CRC));

    // Configure the message headers
    // Here we set up the standard packet format for use by the RH_RF22 library
    // 8 nibbles preamble
    // 2 SYNC words 2d, d4
    // Header length 4 (to, from, id, flags)
    // 1 octet of data length (0 to 255)
    // 0 to 255 octets data
    // 2 CRC octets as CRC16(IBM), computed on the header, length and data
    // On reception the to address is check for validity against RH_RF22_REG_3F_CHECK_HEADER3
    // or the broadcast address of 0xff
    // If no changes are made after this, the transmitted
    // to address will be 0xff, the from address will be 0xff
    // and all such messages will be accepted. This permits the out-of the box
    // RH_RF22 config to act as an unaddresed, unreliable datagram service
    spiWrite(RH_RF22_REG_32_HEADER_CONTROL1, RH_RF22_BCEN_HEADER3 | RH_RF22_HDCH_HEADER3);
    spiWrite(RH_RF22_REG_33_HEADER_CONTROL2, RH_RF22_HDLEN_4 | RH_RF22_SYNCLEN_2);

    setPreambleLength(8);
    uint8_t syncwords[] = { 0x2d, 0xd4 };
    setSyncWords(syncwords, sizeof(syncwords));
    setPromiscuous(false); 
    // Check the TO header against RH_RF22_DEFAULT_NODE_ADDRESS
    spiWrite(RH_RF22_REG_3F_CHECK_HEADER3, RH_RF22_DEFAULT_NODE_ADDRESS);
    // Set the default transmit header values
    setHeaderTo(RH_RF22_DEFAULT_NODE_ADDRESS);
    setHeaderFrom(RH_RF22_DEFAULT_NODE_ADDRESS);
    setHeaderId(0);
    setHeaderFlags(0);


    // Set some defaults. An innocuous ISM frequency, and reasonable pull-in
    setFrequency(434.0, 0.05);
//    setFrequency(900.0);
    // Some slow, reliable default speed and modulation
    setModemConfig(FSK_Rb2_4Fd36);
//    setModemConfig(FSK_Rb125Fd125);

    // Lowish power
    setTxPower(RH_RF22_TXPOW_8DBM);

    return true;
}
예제 #7
0
bool RF22::init() {
	//TODO check.
	wiringPiSetup();

//	// Wait for RF22 POR (up to 16msec)
//	delay(16);

	if (wiringPiSPISetup(_slaveSelectPin, 1000000) == -1) {
		printf("Could not initialize SPI\n");
		return false;
	}

	delay(20);

	// Software reset the device
	reset();
	delay(1);

	// Get the device type and check it
	// This also tests whether we are really connected to a device
	_deviceType = spiRead(RF22_REG_00_DEVICE_TYPE);
	if (_deviceType != RF22_DEVICE_TYPE_RX_TRX && _deviceType != RF22_DEVICE_TYPE_TX)
		return false;

	// Set up interrupt handler
	if (_interrupt == 0) {
		_RF22ForInterrupt[0] = this;
		//attaching interrupt to gpio pins. see wiringPi.com -> gpio chart
		wiringPiISR(6, INT_EDGE_FALLING, RF22::isr0);
	} else if (_interrupt == 1) {
		_RF22ForInterrupt[1] = this;
		wiringPiISR(4, INT_EDGE_FALLING, RF22::isr1);
	} else
		return false;

	clearTxBuf();
	clearRxBuf();

	// Most of these are the POR default
	spiWrite(RF22_REG_7D_TX_FIFO_CONTROL2, RF22_TXFFAEM_THRESHOLD);
	spiWrite(RF22_REG_7E_RX_FIFO_CONTROL, RF22_RXFFAFULL_THRESHOLD);
	spiWrite(RF22_REG_30_DATA_ACCESS_CONTROL, RF22_ENPACRX | RF22_ENPACTX | RF22_ENCRC | RF22_CRC_CRC_16_IBM);
	// Configure the message headers
	// Here we set up the standard packet format for use by the RF22 library
	// 8 nibbles preamble
	// 2 SYNC words 2d, d4
	// Header length 4 (to, from, id, flags)
	// 1 octet of data length (0 to 255)
	// 0 to 255 octets data
	// 2 CRC octets as CRC16(IBM), computed on the header, length and data
	// On reception the to address is check for validity against RF22_REG_3F_CHECK_HEADER3
	// or the broadcast address of 0xff
	// If no changes are made after this, the transmitted
	// to address will be 0xff, the from address will be 0xff
	// and all such messages will be accepted. This permits the out-of the box
	// RF22 config to act as an unaddresed, unreliable datagram service
	spiWrite(RF22_REG_32_HEADER_CONTROL1, RF22_BCEN_HEADER3 | RF22_HDCH_HEADER3);
	spiWrite(RF22_REG_33_HEADER_CONTROL2, RF22_HDLEN_4 | RF22_SYNCLEN_2 | 0x1);
	setPreambleLength(8);
	uint8_t syncwords[] = { 0x2d, 0xd4 };
	setSyncWords(syncwords, sizeof(syncwords));
	setPromiscuous(false);
	// Check the TO header against RF22_DEFAULT_NODE_ADDRESS
	spiWrite(RF22_REG_3F_CHECK_HEADER3, RF22_DEFAULT_NODE_ADDRESS);
	// Set the default transmit header values
	setHeaderTo(RF22_DEFAULT_NODE_ADDRESS);
	setHeaderFrom(RF22_DEFAULT_NODE_ADDRESS);
	setHeaderId(0);
	setHeaderFlags(0);

	// Ensure the antenna can be switched automatically according to transmit and receive
	// This assumes GPIO0(out) is connected to TX_ANT(in) to enable tx antenna during transmit
	// This assumes GPIO1(out) is connected to RX_ANT(in) to enable rx antenna during receive
	spiWrite(RF22_REG_0B_GPIO_CONFIGURATION0, 0x12); // TX state
	spiWrite(RF22_REG_0C_GPIO_CONFIGURATION1, 0x15); // RX state
	//spiWrite(RF22_REG_0D_GPIO_CONFIGURATION2, 0x14); //raw data to port 4 have to activate it later?
	//put into a mode where the interrupt frequency is not as high as the clock of the rfm22.
	//the raspberry is connected to that pin and would freeze if an isr is registered.
	spiWrite(RF22_REG_0D_GPIO_CONFIGURATION2, 0x13);
	// Enable interrupts
	spiWrite(RF22_REG_05_INTERRUPT_ENABLE1,
			RF22_ENTXFFAEM | RF22_ENRXFFAFULL | RF22_ENPKSENT | RF22_ENPKVALID | RF22_ENCRCERROR | RF22_ENFFERR);
	spiWrite(RF22_REG_06_INTERRUPT_ENABLE2, RF22_ENPREAVAL);

	// Set some defaults. An innocuous ISM frequency, and reasonable pull-in
	setFrequency(434.0, 0.05);
//    setFrequency(900.0);
	// Some slow, reliable default speed and modulation
	setModemConfig(FSK_Rb2_4Fd36);
//    setModemConfig(FSK_Rb125Fd125);
	// Minimum power
	setTxPower(RF22_TXPOW_8DBM);
//    setTxPower(RF22_TXPOW_17DBM);

	return true;
}