Monday, March 11, 2013

The Virtual Wire Interface (VWI)

One of the main project goals for Cosa is to provide an efficient object-oriented programming platform for small Internet of Things/M2M devices. This will require a number of components and especially support for wireless communication.

The latest addition to Cosa is a set of classes to support low level wireless communication on RF315/433 devices.

Fig.1: RF433 Receiver/Transmitter

The starting point is the popular VirtualWire library, which has been ported from C to C++ and refactored to the object-oriented style of Cosa. It has also been extended to allow multiple codecs, i.e. methods of encoding/decoding messages.

Fig.2: Codec class hierarchy

Currently the following codecs are supported:
  1. The original 4-to-6 bit symbol codec from VirtualWire
  2. Manchester phase encoding
  3. 4B5B block coding
  4. Fixed bit stuffing(4)
The codecs can be dynamically selected at run-time. It is possible to even select them automatically depending on the message start symbols. Please note that there is no API for this feature yet.

The Virtual Wire Interface (VWI) is constructed with separate Receiver, Transmitter and Codec classes to allow fine-tuning of memory footprint for ultra small devices such as the ATtiny85. For instance, it is possible to use the Transmitter without including the Receiver.

Fig.3: VWI Static Member Functions

The Interrupt Service Routine (ISR) is controlled by static member functions in the VWI container class. The VWI::begin() member function is used to setup the Virtual Wire Interface for a given communication bit rate and idle mode. The ISR is also enabled by VWI::begin(). To allow power down sleep mode and ultra low power consumption there are two static member function to enable/disable the ISR (Timer Interrupt Handler).

Fig.4: VWI::Receiver Member Functions

The VWI::Receiver and VWI::Transmitter classes handle the issuing of message send and receive. The VWI::Receiver interface is simple; begin() for setup, await() for message and recv() for receiving a message. There is a possible timeout limit on the receiving of a message.

Fig.5: VWI::Transmitter Member Functions

The Virtual Wire Interface (VWI) also has a device driver for IOStream (VWIO). This allows printouts to be easily redirected and sent over the wireless interface without changes to source code other than the Trace or other IOStream driver binding. All the printing function in IOStream will print to the wireless connection.

Fig.6: VWIO-IOSTream::Device Classes

Below is a snippet from the CosaVWIOtrace example sketch:

VirtualWireCodec codec;
VWIO tx(Board::D12, &codec);


void setup()
{
  ...
  // Start virtual wire output stream and trace
  tx.begin(4000);
  trace.begin(&tx, PSTR("CosaVWIOtrace: started"));
  ...
}

void loop()
{
  // Monitor digital pin values
  trace << RTC::millis() << PSTR(": D0..10:");
  for (uint8_t i = 0; i < 11; i++)
    trace << ' ' << InputPin::read(i);
  trace << endl;
  SLEEP(2);

  // Monitor analog pin values
  trace << RTC::millis() << PSTR(": A0..7:");
  for (uint8_t i = 0; i < 8; i++)
    trace << ' ' << AnalogPin::sample(i);
  trace << endl;
  SLEEP(2);
}


The blue sections are the only parts changed compared to printing to the serial output. The internal buffer in VWIO will be sent as a VWI message when either it becomes full or when carriage return is received. This is a normal buffer flush policy for buffered devices.

In the Cosa examples directory there are the following VWI sketches.
  1. CosaVWIsender, sends a simple message with an identity, sequence number and two analog readings. Can be modified for the different Codecs available for VWI. Can run on an ATtiny85.
  2. CosaVWIreceiver, receiver for CosaVWIsender. Can also be modified for the different Codecs. Sender and receiver should use the same codec. 
  3. CosaVWIOtrace, sends trace output over the Virtual Wire Interface. Should be used together with CosaVWImonitor. 
  4. CosaVWImonitor, receive stream of text printout over VWI.
  5. CosaVWItempsensor, ATtiny85 sketch that reads temperature measurements from a 1-Wire DS18B20 Digital Thermometer and sends the value using VWI. Message contains ROM identity of the 1-Wire device, sequence number and temperature reading. See Fig.7-8 below.
  6. CosaVWItempmonitor, receives temperature readings from CosaVWItempsensor(s) and prints to serial output.
  7. CosaVWIkey, simple application to demonstrate power down sleep mode and wakeup/send of a message on pressing a button. 
  8. CosaVWIclient is an example of a simple implementation of reliable, in-order, message protocol with addressing and message sequence numbering. This sketch will retransmit messages if an acknowledgement is not received from CosaVWIserver. Collects and prints statistics on retransmissions and error rate. Allows the different Codecs to be compared with regard to throughput and package drops (noise, etc).
  9. CosaVWIserver receives and print messages from CosaVWIclient. Sends an acknowledgement back to the client. 
The provided communication links are not secure, or reliable and messages may be dropped due to noise, collisions and other types of errors. The basic communication style is a bit like UDP but without addressing. Applications must add retransmission or other methods to achieve more reliable communication if required. A protocol stack with windowing is planned to be added later in the project.

 Fig.7: CosaVWItempsensor on ATtiny85 with 1-Wire Digital Thermometer

To allow small ultra low-power devices, the VWI classes are fully adapted for ATtiny85/85V. There are several examples and demonstration sketches in the examples directory. The example with 1-Wire CosaVWItempsensor is without any reduction less than 6 Kbyte leaving more than 2 Kbyte for further application code.

Fig.8: CosaVWItempmonitor printout of received temperature readings

As a bonus the new object-oriented/C++ version of VirtualWire is ported back to Arduino and is available.

The next step for this sub-set of Cosa will be to introduce additional message formats to allow addressing of nodes (MAC/IP style); broadcast/point-to-point and build the next step of the protocol stack for more reliable communication links and middleware.

Please note that Cosa also has a device driver for NRF24L01+. This device is a much more powerful chip for low power communication links.

[Update 2013-11-17]
Please note that since this blog post was written the Virtual Wire interface has been refactored to implement an abstract Wireless interface in Cosa. This allows applications to move more or less seamlessly between the different implementations of the Wireless interface. Currently there are three implementation; Virtual Wire (VWI), NRF24L01P and CC1101. The example sketches above work on all three.

There are some minor changes to the VWI interface but the overall functionality is the same (See the new VWI.hh). It is still possible to use the Cosa refactored Virtual Wire class directly.

[Update 2014-05-03]
Please note that the links above are broken and this post is not up to date. The examples directory is https://github.com/mikaelpatel/Cosa/tree/master/examples/Wireless.

[Update 2015-03-03]
Hamming(8,4) and (7,4) Codec has been added. This maps 4 bit data to 8 resp 7 bit symbols. The great advantage is 1-bit error detection and correction, and possible multi-bit error detection. This reduces the frame errors with almost 90% compared to the other Codecs (at 4 Kbps, 7 byte payload, 5 second message intervals, https://github.com/mikaelpatel/Cosa/blob/master/examples/Wireless/CosaWirelessDS18B20/CosaWirelessDS18B20.ino). The Hamming Code encoders/decoders are table driven which gives excellent performance and low memory footprint (144 resp 80 byte program memory).

21 comments:

  1. Can I use the same speed if ATTINY is used as transmitter and Arduino nano as receiver?

    ReplyDelete
  2. I've set 4000 speed for both devices but receiver sample (Arduino) doesn't print anything.
    I tried to check if any data is received using interrupt on pin 2 and see there are impulses sent with interval of 2/4/6 ms so something is coming
    Are there any ways to troubleshoot receiving?

    ReplyDelete
  3. The speed setting must be the same on both transmitter and receiver. Using an ATtiny and Nano is fine. That is one of the configurations I use. It is also important that the Codec is the same.

    When trouble-shooting start with a low speed (e.g. 2000) and a short distance (e.g. 20-50 cm).

    There is a large quality difference between RF315/433 modules. At least the cheap ones.

    Last, if you are using a new ATtiny please do not forget to burn the fuses. You also need to check the baudrate/speed if not using 8MHz/Internal clock.

    Cheers!

    ReplyDelete
    Replies
    1. Unfortunately no success :(
      I already tried 2000 and 1000 speed, different codecs and result is the same

      By burning the fuses you mean "burn bootloader" menu item, right? It's done

      Also my troubleshooting using interrupts shows there is always similar data is sent

      E.g.
      2222222222222222222222222222222222266442424422244244222442442244224644424422466642222244224622422444222222224

      (where number is time in msec between CHANGE event)

      So it seems data is received but not processed correctly. Is there any way to understand which processing step fails?

      Delete
    2. Hum. This is not a support site ;-) but if you want me to help you debug your hardware you need to give more details. So far you have only told me that you are using an ATtiny?? and a Nano??. What are you trying to run? Have you tried other libraries? Are you sure your hardware works? What is the circuit wiring? Voltage on the ATtiny? Clock frequency? Antenna? Etc. A sequence of numbers without space is not very much to go on ;-) For fun and to verify the latest release I rigged an Arduino Mega running CosaVWIreceiver and an ATtiny85 running CosaVWIdht11 and it works fine out of the box with RF433 modules. What are you using?

      Please try to be more specific and give more details. Also you should use the github/Cosa issue handling or the Arduino Forum/Cosa post instead of this blog.

      Cheers!

      Delete
    3. Mikael,
      thanks for the help

      I've found the reason finally
      My receiver outputs inverted signal. I think that's why original VirtualWire has vw_set_ptt_inverted(true); in sources
      So I've adjusted ISR(TIMER1_COMPA_vect) method to
      if ((receiver != 0 && receiver->m_enabled)
      && (transmitter == 0 || !transmitter->m_enabled))
      receiver->m_sample = !receiver->read();
      (added ! before receiver->read()) and now it works

      Delete
    4. Great! Happy to learn that you found the problem. What type of RF module is that? The push-to-talk (ptt) handling in the original VirtualWire library is actually turining the transmitter on/off. I could not find handling of inverted data from the receiver. Anyway hope this allows you to proceed with your project. If the module you are using is common it might be of interest to add a configuration to VWI.

      Cheers!

      Delete
  4. Sorry, you're right
    My both modules are cheap chinese ones (http://i00.i.aliimg.com/ordersnapshot/2013Q2_photo/159/159/231749159/737403782_1.jpg)
    But I also have pretty good RRQ3-433 receiver and will check it as well later

    ReplyDelete
  5. Not able to find this directory

    https://github.com/mikaelpatel/Cosa/blob/master/examples/VWI/

    ReplyDelete
  6. Try this directory https://github.com/mikaelpatel/Cosa/tree/master/example/Wireless instead.

    Cheers!

    ReplyDelete
  7. Where to find these samples?

    CosaVWIsender, CosaVWIreceiver, CosaVWIOtrace, CosaVWImonitor.....

    ReplyDelete
  8. Those samples are not available directly any more. They have been replaced with the more generic examples. The new Wireless examples allow several device drivers with the same code base.

    If you are looking for the old examples you may find them in git repository. Clone the git repository and checkout the old versions. Please see the git manual how to do that.

    Cheers!

    ReplyDelete
    Replies
    1. Mikael,

      Thank you for your help. I am able to run samples on Uno. I also want to run it on Arduino Yun, but could not find the board. Is Yun going to be supported?

      I tried 2 board with ATmega32U4 (same as Yun). No success.

      Is there anything I can do now?

      Thanks.

      Delete
    2. The question of supporting Yun is complex as there is a serial protocol between the Wifi and AVR (aka the bridge). There is also too small interest. You are basically the first to ask for that. I dont want to invest in buying something I am not going to use myself and put a lot of time into something that nobody needs.

      What ATmega32U4 boards have you tried? The download behavior on these devices are "difficult". You have to learn when to push the reset at the right time.

      I should also remind you that this is not a support site.

      Cheers!

      Delete
  9. I tried Cosa Arduino Leonardo, Cosa Arduino Micro (with ATmega32U4) with simple sample like Blink. Compile seems ok but fails eventually (after 2-3 minutes, possibly during upload). Cosa has good support for RF device (addressing, port on different type of RF). If Yun hosts RF receiver, RF sender send data to the receiver. Yun can easily post RF sender's data on internet. I am little surprised that I am the first one to ask. Since I am new to arduino, I don't know if there is other approach (different board) to do this kind of work.

    I am also interested in pcDuino V2 (clone of Yun) board support. Do you have plan to support this board? What it takes to add this? Is it possible to do it by myself?

    ReplyDelete
    Replies
    1. A quick answer to this but then please use the issues handling on github instead. https://github.com/mikaelpatel/Cosa/issues?state=open

      We are far from the intension of commenting the blob post above.

      First I verify Cosa on Arduino Uno, Nano, Pro Mini, Pro Micro, Leonard, Lilypad and Mega. Also with ATmega84, 85 and 861.

      Problems with the ATmega32U4 based boards is often a combination of IDE version, board bootloader and USB handling on the operating system.

      I need to repeat that there is currently limited interest for Yun and clones of that board. There are currently no plans to support that board.

      To add the Yun there are several things to be done. 1) There is a need for a board adaptation (pins definition etc), 2) the bridge protocol must be implemented, 3) the Cosa socket interface must be implemented to use Ethernet/Wifi and more.

      If you know what you are doing and have the specs then my guess is that it takes at least a week. Given that everything works out fine.


      Cheers!

      Delete
    2. Yes it would be possible to use Arduino Yun as a bridge between the Cosa RF modules to Ethernet/Wifi. This is already possible with an Ethernet Shield and RF modules such as NRF24L01+, CC1101, RFM69 and RF433.

      Cheers!

      Delete
  10. This comment has been removed by the author.

    ReplyDelete
  11. I added Yun to the Arduino\sketchbook\hardware\Cosa\avr\boards.txt.


    yun.name=My Cosa Arduino Yun
    yun.upload.via_ssh=true

    yun.vid.0=0x2341
    yun.pid.0=0x0041
    yun.vid.1=0x2341
    yun.pid.1=0x8041
    yun.upload.tool=avrdude
    yun.upload.protocol=avr109
    yun.upload.maximum_size=28672
    yun.upload.maximum_data_size=2560
    yun.upload.speed=57600
    yun.upload.disable_flushing=true
    yun.upload.use_1200bps_touch=true
    yun.upload.wait_for_upload_port=true

    yun.bootloader.tool=avrdude
    yun.bootloader.low_fuses=0xff
    yun.bootloader.high_fuses=0xd8
    yun.bootloader.extended_fuses=0xfb
    yun.bootloader.file=caterina/Caterina-Yun.hex
    yun.bootloader.unlock_bits=0x3F
    yun.bootloader.lock_bits=0x2F

    yun.build.mcu=atmega32u4
    yun.build.f_cpu=16000000L
    yun.build.vid=0x2341
    yun.build.pid=0x8041
    yun.build.usb_product="Arduino Yun"
    #yun.build.board=AVR_YUN
    yun.build.core=cosa
    yun.build.variant=yun
    yun.build.extra_flags={build.usb_flags}


    I am able to load and run few Cosa samples, such as CosaBlink (saw blink correctly. This sketch has no trace statement) and CosaWirelessReceiver (has trance statement).

    But I am getting following error in serial monitor, Tools | Serial Monitor when running above 2 sketches.

    Unable to connect: retrying (1)...
    Unable to connect: retrying (2)...
    Unable to connect: retrying (3)...
    Unable to connect: retrying (4)...
    Unable to connect: is the sketch using the bridge?


    Without trace, debugging will be hard. Any recommendations? Appreciate your help.

    ReplyDelete
    Replies
    1. Please check the Yun implementation and the schematics for details on the usage of the USB/CDC and Serial port. I think this might explain the behavior.

      Trace in Cosa is an IOStream and can easily be redirected. The normal usage in the example sketches is to bind to the UART but there are examples that bind to other IOStream::Device's such as Socket.

      Cheers!

      Delete
    2. The trace statements are from the WiFi side. It can not establish contact with the ATmega32U4 over the serial interface as Cosa does not implement the bridge protocol.

      Cheers!

      Delete