If you worked for a real application with IQRF modules with DPA, you’ve probably reached to the conclusion that for communication with PC is very convenient to use UART. Me too. I like UART for his simple handling and easy accessibility, unlike SPI (just PC has no native SPI port 🙂 ). This post describes simple classes for DPA ↔ HDLC conversion written in C#.
What you need:
- Microsoft Visual C# Express 2010 or newer, SharpDevelop, etc…
- .NET 3.0
- USB-UART converter + IQRF-UART adapter.
- IQRF_DPA_Handler.cs attached at the end of this post.
IQRF_DPA_Handler.cs consist three main parts:
- class DPA_RX (this class handles RX events and decodes HDLC protocol to DPA params).
- class DPA_TX (this class builds HDLC protocol from DPA params).
- class DPA_UTILS (crc, etc…)
Class DPA_RX
Members:
public UInt16 NADR; // Node address public byte PNUM; // Peripheral number public byte PCMD; // Peripheral command public UInt16 HWPID; // Hardware profile ID public byte[] Data; // DPA Data public byte DLEN; // DPA Data length public byte ErrN; // Error number public byte DpaValue; private bool HDLC_CE; // control escape flag private byte CRC; // HDLC CRC public ArrayList Buffer; // Input buffer public const byte HDLC_FLAG_SEQUENCE = 0x7E; // Flag sequence constant public const byte HDLC_CONTROL_ESCAPE = 0x7D; // Control escape constant public const byte HDLC_ESCAPE_BIT = 0x20; // Escape bit constant public const byte HDLC_MIN_LEN = 0x0B; // Minimum length of response public const byte HDLC_MAX_LEN = 0x80; // Maximum length of buffer |
Methods:
public DPA_RX() // Constructor public DPA_RX_STATE DPA_RX_Parse(byte character) // Received data parser |
How to use it:
Create instance of DPA_RX object as global object:
DPA_RX DPA_RX_inst1 = new DPA_RX(); |
Inside SerialPort DataReceived event call DPA_RX_inst1.DPA_RX_Parse(character), where character is data byte received by SerialPort. Test result for DPA_RX_STATE.DPA_RX_OK. Example:
private void sp1_DataReceived(object sender, SerialDataReceivedEventArgs e) { try { byte[] bytes; SerialPort serialPort = (SerialPort)sender; // try to read all available bytes from serial port lock (serialPort) { bytes = new byte[serialPort.BytesToRead]; serialPort.Read(bytes, 0, bytes.Length); } // try to parse message for (int index = 0; index < bytes.Length; index++) { byte oneByte = bytes[index]; if (DPA_RX_inst1.DPA_RX_Parse(oneByte) == DPA_RX.DPA_RX_STATE.DPA_RX_OK) this.BeginInvoke(new EventHandler(ShowState)); } } // Some problem with serial port or parsing catch (Exception ex) { MessageBox.Show("Ups, some problems with message parsing: \n"+ex.Message); } } |
Then you can have inside ShowState something like:
private void ShowState(object s, EventArgs e) { // Fill labels against received parameters lblNADR.Text = "NADR: " + DPA_RX_inst1.NADR.ToString("X4"); lblPNUM.Text = "PNUM: " + DPA_RX_inst1.PNUM.ToString("X2"); lblPCMD.Text = "PCMD: " + DPA_RX_inst1.PCMD.ToString("X2"); lblHWPID.Text = "HWPID: " + DPA_RX_inst1.HWPID.ToString("X4"); lblERRN.Text = "ErrN: " + DPA_RX_inst1.ErrN.ToString("X2"); lblDPAVAL.Text = "DpaValue: " + DPA_RX_inst1.DpaValue.ToString("X2"); } |
which show you DPA Response data on relevant labels.
Class DPA_TX
Members:
public UInt16 NADR; // Node address public byte PNUM; // Peripheral number public byte PCMD; // Peripheral command public UInt16 HWPID; // Hardware profile ID public byte[] Data; // DPA Data public byte DLEN; // DPA Data length private byte CRC; // HDLC CRC public byte[] Buffer; // Output buffer |
Methods:
public DPA_TX() // Constructor public void BuildHDLC() // Build HDLC byte array form DPA Params |
How to use it:
Create instance of DPA_TX object where you need to send HDLC data:
DPA_TX DPA_TX_inst1 = new DPA_TX(); |
Then, set DPA Params, call BuilHDLC method, and send byte array Buffer via UART. Full example for Button click event:
private void button1_Click(object sender, EventArgs e) { // Create new instance of DPA_TX DPA_TX DPA_TX_inst1 = new DPA_TX(); DPA_TX_inst1.NADR = 0x0000; // Node address 2 DPA_TX_inst1.PNUM = 0x06; // LEDR DPA_TX_inst1.PCMD = 0x03; // Pulse LED DPA_TX_inst1.HWPID = 0xFFFF; // All HWPIDs DPA_TX_inst1.DLEN = 0; // No data DPA_TX_inst1.BuildHDLC(); // Fill output buffer // Try to send buffer content to IQRF try { // send buffer content to IQRF sp1.Write(DPA_TX_inst1.Buffer, 0, DPA_TX_inst1.Buffer.Length); } catch { } } |
Of course, you must have opened serial port.
class DPA_UTILS now consist only CalcCRC(ArrayList buffer) method. This method is internally used for CRC calculation and checking.
See full source code of .NET DPA class for details.
Enjoy.