How to use Raspberry Pi as NRF24L01+ receiver, using dotnet? - c#

The transmitter I am using is an Arduino nano every, and I have it working just fine with an Arduino Uno as the receiver, however using the same nrf module with a raspberry pi does not work.
I am using a Pi Model 3B V1.2, with the nrf24l01+ and the 5v power adapter. The nrf also has a 100uf capacitor attached to the vcc/grnd.
I am using the GettingStarted example for the arduino nrf, with different pin configs for either the nano every or the uno, and the addresses changed to hardcoded hex:
/*
* See documentation at https://nRF24.github.io/RF24
* See License information at root directory of this library
* Author: Brendan Doherty (2bndy5)
*/
/**
* A simple example of sending data from 1 nRF24L01 transceiver to another.
*
* This example was written to be used on 2 devices acting as "nodes".
* Use the Serial Monitor to change each node's behavior.
*/
#include <SPI.h>
#include "printf.h"
#include "RF24.h"
// instantiate an object for the nRF24L01 transceiver
RF24 radio(7, 8); // using pin 7 for the CE pin, and pin 8 for the CSN pin, for the uno
//RF24 radio(10, A0); // this pin setup for the nano every
// Let these addresses be used for the pair
//uint8_t address[][6] = {"1Node", "2Node"};
uint8_t address[][5] = {{0xE0, 0xE0, 0xE0, 0xE0, 0xE0}, {0xF0, 0xF0, 0xF0, 0xF0, 0xF0}};
// It is very helpful to think of an address as a path instead of as
// an identifying device destination
// to use different addresses on a pair of radios, we need a variable to
// uniquely identify which address this radio will use to transmit
bool radioNumber = 0; // 0 uses address[0] to transmit, 1 uses address[1] to transmit
// Used to control whether this node is sending or receiving
bool role = false; // true = TX role, false = RX role
// For this example, we'll be using a payload containing
// a single float number that will be incremented
// on every successful transmission
float payload = 0.0;
void setup() {
Serial.begin(115200);
while (!Serial) {
// some boards need to wait to ensure access to serial over USB
}
// initialize the transceiver on the SPI bus
if (!radio.begin()) {
Serial.println(F("radio hardware is not responding!!"));
while (1) {} // hold in infinite loop
}
// print example's introductory prompt
Serial.println(F("RF24/examples/GettingStarted"));
// To set the radioNumber via the Serial monitor on startup
Serial.println(F("Which radio is this? Enter '0' or '1'. Defaults to '0'"));
while (!Serial.available()) {
// wait for user input
}
char input = Serial.parseInt();
radioNumber = input == 1;
Serial.print(F("radioNumber = "));
Serial.println((int)radioNumber);
// role variable is hardcoded to RX behavior, inform the user of this
Serial.println(F("*** PRESS 'T' to begin transmitting to the other node"));
// Set the PA Level low to try preventing power supply related problems
// because these examples are likely run with nodes in close proximity to
// each other.
radio.setPALevel(RF24_PA_LOW); // RF24_PA_MAX is default.
// save on transmission time by setting the radio to only transmit the
// number of bytes we need to transmit a float
radio.setPayloadSize(sizeof(payload)); // float datatype occupies 4 bytes
//radio.setAutoAck(false);
// set the TX address of the RX node into the TX pipe
radio.openWritingPipe(address[radioNumber]); // always uses pipe 0
// set the RX address of the TX node into a RX pipe
radio.openReadingPipe(1, address[!radioNumber]); // using pipe 1
//radio.setAutoAck(false);
// additional setup specific to the node's role
if (role) {
radio.stopListening(); // put radio in TX mode
} else {
radio.startListening(); // put radio in RX mode
}
// For debugging info
//These dont work for the nano every:
//printf_begin(); // needed only once for printing details
//radio.printDetails(); // (smaller) function that prints raw register values
//radio.printPrettyDetails(); // (larger) function that prints human readable data
} // setup
void loop() {
if (role) {
// This device is a TX node
unsigned long start_timer = micros(); // start the timer
bool report = radio.write(&payload, sizeof(float)); // transmit & save the report
unsigned long end_timer = micros(); // end the timer
if (report) {
Serial.print(F("Transmission successful! ")); // payload was delivered
Serial.print(F("Time to transmit = "));
Serial.print(end_timer - start_timer); // print the timer result
Serial.print(F(" us. Sent: "));
Serial.println(payload); // print payload sent
payload += 0.01; // increment float payload
} else {
Serial.println(F("Transmission failed or timed out")); // payload was not delivered
}
// to make this example readable in the serial monitor
delay(1000); // slow transmissions down by 1 second
} else {
// This device is a RX node
uint8_t pipe;
if (radio.available(&pipe)) { // is there a payload? get the pipe number that recieved it
uint8_t bytes = radio.getPayloadSize(); // get the size of the payload
radio.read(&payload, bytes); // fetch payload from FIFO
Serial.print(F("Received "));
Serial.print(bytes); // print the size of the payload
Serial.print(F(" bytes on pipe "));
Serial.print(pipe); // print the pipe number
Serial.print(F(": "));
Serial.println(payload); // print the payload's value
}
} // role
if (Serial.available()) {
// change the role via the serial monitor
char c = toupper(Serial.read());
if (c == 'T' && !role) {
// Become the TX node
role = true;
Serial.println(F("*** CHANGING TO TRANSMIT ROLE -- PRESS 'R' TO SWITCH BACK"));
radio.stopListening();
} else if (c == 'R' && role) {
// Become the RX node
role = false;
Serial.println(F("*** CHANGING TO RECEIVE ROLE -- PRESS 'T' TO SWITCH BACK"));
radio.startListening();
}
}
} // loop
For the Raspberry pi I am using dotnet 6 with the Iot.Device.Bindings package, building on my windows machine, scp'ing the dotnet publish output to the pi and running through the dotnet cli with 'dotnet MyProgram.dll':
using System.Text;
using System.Linq.Expressions;
using System.Device.Spi;
using System.Device.Gpio;
using System.Device.Gpio.Drivers;
using Iot.Device.Nrf24l01;
byte[] address1 = new byte[] { 0xE0, 0xE0, 0xE0, 0xE0, 0xE0 };
byte[] address2 = new byte[] { 0xF0, 0xF0, 0xF0, 0xF0, 0xF0 };
int spiBusId = 1;
int spiChipSelect = 2;
int nrfCE = 5;
int nrfIRQ = 6;
byte nrfPacketSize = 4;
byte nrfChannel = 76;
OutputPower nrfPower = OutputPower.N12dBm;
DataRate nrfRate = DataRate.Rate1Mbps;
using RaspberryPi3Driver rpiDriver = new();
using GpioController gpio = new(PinNumberingScheme.Logical, rpiDriver);
SpiConnectionSettings spiSettings = new(spiBusId, spiChipSelect)
{
Mode = Nrf24l01.SpiMode,
ClockFrequency = Nrf24l01.SpiClockFrequency
};
using SpiDevice spi = SpiDevice.Create(spiSettings);
using Nrf24l01 nrf = new(spi, nrfCE, nrfIRQ, nrfPacketSize, gpioController: gpio, channel: nrfChannel, dataRate: nrfRate, outputPower: nrfPower);
// nrf.Address = address2;
nrf.Pipe0.Address = address1;
nrf.Pipe0.AutoAck = true;
nrf.DataReceived += DataReceived;
Console.WriteLine(nrf.NRFDetails());
while (true)
{
Thread.Sleep(200);
}
static void DataReceived(object sender, DataReceivedEventArgs e)
{
var data = e.Data.ToHexString();
Console.WriteLine($"Data received: {data}");
}
static class DataExtensions
{
public static string ToHexString(this byte[] data)
{
return string.Join(", ", data?.Select(x => $"{x:X}") ?? Array.Empty<string>());
}
public static string ToDecString(this byte[] data)
{
return string.Join(", ", data?.Select(x => $"{x}") ?? Array.Empty<string>());
}
public static string NRFDetails(this Nrf24l01 nrf, Expression<Func<Nrf24l01, Nrf24l01Pipe>>? pipeSel = null)
{
StringBuilder builder = new();
builder.AppendLine($"Address: {nrf.Address.ToHexString()}");
builder.AppendLine($"Channel: {nrf.Channel}");
builder.AppendLine($"PacketSize: {nrf.PacketSize}");
builder.AppendLine($"DataRate: {nrf.DataRate}");
builder.AppendLine($"OutputPower: {nrf.OutputPower}");
builder.AppendLine($"PowerMode: {nrf.PowerMode}");
builder.AppendLine($"WorkingMode: {nrf.WorkingMode}");
pipeSel ??= ((x) => x.Pipe0);
string mName = "Pipe";
if (pipeSel.Body is MemberExpression me)
mName = me.Member.Name;
Nrf24l01Pipe pipe = pipeSel.Compile().Invoke(nrf);
builder.AppendLine($"{mName}.Address: {pipe.Address.ToHexString()}");
builder.AppendLine($"{mName}.AutoAck: {pipe.AutoAck}");
builder.AppendLine($"{mName}.Enable: {pipe.Enable}");
builder.AppendLine($"{mName}.Payload: {pipe.Payload}");
return builder.ToString();
}
}
The radio seems to initialize fine, as I can write/read values from the nrf registers without issue, but I am unable to transmit or receive anything from the raspberry pi.
I have tried using the GettingStarted example with an arduino nano every and an arduino uno, using the same nrf modules+adapters and that works fine.
I've tried receiving/transmitting to/from the pi using both the nano every and the uno with no success.
Is this a power issue with the pi? Is this an issue with the dotnet iot library? I was unable to get the nrf24 library by tmrh working on my pi as I get g++ compilation errors from the install.sh provided, so I haven't been able to test a different library yet.
Has anyone run into similar issues, or has anyone made this setup work?

Related

COM: Device only sends data when things are changing. How to deal with that?

So I want to connect to a device via Serial that only sends data when things are changing with the settings on the device (a measuring device).
I use C# and .Net's SerialPort.
I am able to read data and it looks kind of good. But there are a few problems I encountered.
I realized my reading- method (ReadExistingData()) so that it will constantly use the SerialDataReceivedEventHandler when there's new data.
Unfortunately, when I read it like that (probably because of varying package sizes) it will read very chaotically and thus I need to "catch" the first initiating byte (here it's 0xA5).
That means, I always check whether the byte I just received is a 0xA5 and if it is, I read the rest.
But I feel like that way I am missing some commands my device sends me and thats why I cant display the data consistently right, only from time to time.
On a side note: The device sends the device time and a value. The value is delayed and kind of unaccurate, but the time is always right on spot. The other parameters it sends are always weirded out and dont seem to be recognized and thus changed at all.
To display data I use the console for testing purposes, and the whole construct seems to be very reactive to Console outputs.
Here's a little code snippet:
class Device
{
private int stdMessageLengthInBytes = 5;
public DeviceData processedData;
byte[] dataBuffer;
int receivedMessages = 0;
public Device()
{
// Initialize BaseClass (SerialPort derivative)
this.port = new System.IO.Ports.SerialPort();
// Initialize Device
this.data = new byte[stdMessageLengthInBytes];
this.processedData = new P8005_Data();
dataBuffer = new byte[stdMessageLengthInBytes];
}
// Is supposed to read the data from serial port
protected override void ReadExistingData()
{
// Check whether buffer is empty -> Try to catch a 0xA5
if (dataBuffer[0] == 0x00)
{
port.Read(dataBuffer, 0, 1);
}
// If no 0xA5 was catched, restart
if (dataBuffer[0] != 0xA5)
{
dataBuffer = new byte[stdMessageLengthInBytes]; // Reset buffer
return;
}
// Read next byte -> Command byte
port.Read(dataBuffer, 1, 1);
// If command was empty, restart
if (dataBuffer[1] == 0x00)
{
dataBuffer = new byte[stdMessageLengthInBytes]; // Reset buffer
return;
}
// If its time that is communicated: Read 3 bytes
if (dataBuffer[1] == 0x06)
{
// 4 ms delay seems to be needed otherwise it wont function correctly somehow
System.Threading.Thread.Sleep(5);
port.Read(dataBuffer, 2, 3);
// Write buffer to actual raw data byte array
this.data = dataBuffer;
dataBuffer = new byte[stdMessageLengthInBytes]; // Reset buffer
}
// Otherwise: Just read 2 bytes
System.Threading.Thread.Sleep(5); // Needed delay
port.Read(dataBuffer, 2, 2);
// Write buffer to actual raw data byte array
this.data = dataBuffer;
dataBuffer = new byte[stdMessageLengthInBytes]; // Reset buffer
}
// Method called by SerialDataReceivedEventHandler
protected override void DataReceivedOnComPort(object sender, SerialDataReceivedEventArgs e)
{
bool valid = false;
ReadExistingData(); // Read data from COM- Port
lock (processedData)
{
switch (data[1]) // Check command byte
{
// Time (3 btyes)
case (0x06):
processedData.currentTime = String.Format("{0:D2}:{1:D2}:{2:D2}", DecodeBcd(data[2]), DecodeBcd(data[3]), DecodeBcd(data[4]));
valid = true;
receivedMessages++;
break;
// Value (2 bytes)
case (0x0D):
double val = 0;
val += DecodeBcd(data[2]) * 100;
val += DecodeBcd(data[3]);
val /= 10;
processedData.currentValue = val;
valid = true;
receivedMessages++;
break;
// ... here are various other hex- code that represent a command from the device (2 btyes)
default:
valid = false;
break;
}
}
// only to check when
if (valid)
{
Console.WriteLine("Received Valid Messages: {0}", receivedMessages);
ConsoleOutput();
}
}
}
On a note: The initialization of the port happens in another method from the base class and works fine.
Is there anything I am missing? How to deal with something like that? Are there any improvements that would help improving my performance? I thought about threading with locks, but I dont think that is the solution somehow... Or maybe everything is just a console problem?
EDIT:
I know changed my code (as #jdweng suggested) so that I put everything in a buffer (basically List<byte> mainBuffer. Then, I take all bytes in the buffer whenever its possbile and work with them, skimming it for 0xA5. When one is found, I read the command and determine how long the "message" has to be according to it (Time -> +3 bytes, Data -> +2 bytes, Other -> +1 byte). Then I can work off those messages (I put them into a List<byte[]>) and determine my output to my screen.
However, even after outsourcing the chopping up into messages and processing the messages, I still seem to either miss some messages, since some action are just not registered and have a big delay, or my processing is wrong. What I can think of is that because I lock my mainBuffer maybe some data isnt written to it.
Is this really this time critical? There is a software that comes with the device and it doesnt seem to have such big problems with delay and slightly wrong values...
Since you don't have the exact specs and/or an unreliable connection (which with serial data has to be expected) you need to sync to the 0xa5 at every message. I would just run every single byte you receive through a parser while keeping the state of the currently received message.
Make sure you validate your input since there are a bunch of things that can go wrong if you get messed up serial data. For example if there is an 0xa5 in the other message types, you might miss your next message. To prevent that I strongly recommend to either get to the specs if possible or code more logic based on data observations.
private const int MESSAGE_LENGTH = 5;
private const int VALUE_COMMAND = 0x0D;
private const int VALUE_SIZE = 4;
private const int TIME_COMMAND = 0x06;
private const int TIME_SIZE = 5;
private byte[] _message = new byte[MESSAGE_LENGTH];
private int _messagePos = 0;
private void port_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
var data = new byte[_serialPort.BytesToRead];
_serialPort.Read(data, 0, data.Length);
foreach (var b in data)
{
_message[_messagePos] = b;
if (_messagePos == 0 && b != 0xa5)
continue;
++_messagePos;
if (_messagePos > 2) // if command byte present, process command of any size
ProcessCommand(_message[1]);
}
}
private void ProcessCommand(byte command)
{
if (_messagePos == VALUE_SIZE && command == VALUE_COMMAND)
{
// parse value...
_messagePos = 0;
}
else if (_messagePos == TIME_SIZE && _message[1] == TIME_COMMAND)
{
// parse time...
_messagePos = 0;
}
}

Windows IoT Raspberry Pi 3 C# RTC DS3231

this post may seems duplicate as Windows IoT and DS3231 RTC clock
but it doesn't seem to work for me. i don't have experience using i2c in this environment.
My intended functionality is,
at startup check if there is any network connectivity to update system clock
if offline the system will read datetime from DS3231 and update
the system datetime
any changes of datetime from datepicker or
timepicker it will update DS3231
My problem is
How to check for network availibility to update system clock.
to read from DS3231
using i1cdevice.writeread requires to write read address separately?
does the i2c automatically reads all the data until stop bit is received or i have to setup a counter ?
private const byte DS3231_I2C_WADDR = 0xD0;
private const byte DS3231_I2C_RADDR = 0xD1;
private I2cDevice DS3231_RTC;
byte[] i2CWriteBuffer;
byte[] i2CReadBuffer;
private async void Read_DS3231_RTC()
{
var settings = new I2cConnectionSettings(DS3231_I2C_RADDR);
settings.BusSpeed = I2cBusSpeed.StandardMode;
var controller = await I2cController.GetDefaultAsync();
DS3231_RTC = controller.GetDevice(settings);
try
{
DS3231_RTC.WriteRead(new byte[] { DS3231_I2C_RADDR }, i2CReadBuffer);
}
catch (Exception e)
{
StatusMessage.Text = "Fail to Init I2C:" + e.Message;
return;
}
}
to write to DS3231
there are dateicker & timepicker for time setting
upon setting the datetime how could I update to DS3231
private void DatePicker_DateChanged(object sender, DatePickerValueChangedEventArgs e)
{
DateTimeSettings.SetSystemDateTime(e.NewDate.UtcDateTime);
SetTime_DS3231();
}
private void TimePicker_TimeChanged(object sender, TimePickerValueChangedEventArgs e)
{
var currentDate = DateTime.Now.ToUniversalTime();
var newDateTime = new DateTime(currentDate.Year,
currentDate.Month,
currentDate.Day,
e.NewTime.Hours,
e.NewTime.Minutes,
e.NewTime.Seconds);
DateTimeSettings.SetSystemDateTime(newDateTime);
}
Thank you.
1.How to check for network availibility to update system clock.
You can use GetIsNetworkAvailable method of NetworkInterface class to check whether internet connected or not. You can get more knowleage about how to check internet connectivity type in Universal Windows Platform from this topic
.
bool isInternetConnected = NetworkInterface.GetIsNetworkAvailable();
2.to read from DS3231 using i1cdevice.writeread requires to write read address separately? does the i2c automatically reads all the data
until stop bit is received or i have to setup a counter ?
It is not necessary to separate write read. WriteRead method Performs an atomic operation to write data to and then read data from the inter-integrated circuit (I2 C) bus on which the device is connected, and sends a restart condition between the write and read operations. The second parameter is the buffer to which you want to read the data from the I2 C bus. The length of the buffer determines how much data to request from the device.It does not stop automatically until stop bit is received.If the I2 C device negatively acknowledged the data transfer before the entire buffer was read, there will be error(Error Code 0x8007045D).
3.to write to DS3231 there are dateicker & timepicker for time setting upon setting the datetime how could I update to DS3231
As TRS replied in the topic Windows IoT and DS3231 RTC clock
, he/she provided the method to set clock.
New Update:
private async void SetTime_DS3231(DateTime dt)
{
int SlaveAddress = 0x68;
try
{
// Initialize I2C
var Settings = new I2cConnectionSettings(SlaveAddress);
Settings.BusSpeed = I2cBusSpeed.StandardMode;
if (AQS == null || DIS == null)
{
AQS = I2cDevice.GetDeviceSelector("I2C1");
DIS = await Windows.Devices.Enumeration.DeviceInformation.FindAllAsync(AQS);
}
using (I2cDevice Device = await I2cDevice.FromIdAsync(DIS[0].Id, Settings))
{
byte write_seconds = decToBcd((byte)dt.Second);
byte write_minutes = decToBcd((byte)dt.Minute);
byte write_hours = decToBcd((byte)dt.Hour);
byte write_dayofweek = decToBcd((byte)dt.DayOfWeek);
byte write_day = decToBcd((byte)dt.Day);
byte write_month = decToBcd((byte)dt.Month);
byte write_year = decToBcd((byte)(dt.Year%100));
byte[] write_time = { 0x00, write_seconds, write_minutes, write_hours, write_dayofweek, write_day, write_month, write_year };
Device.Write(write_time);
}
}
catch (Exception ex)
{
System.Diagnostics.Debug.Write(ex.Message);
}
}
private static byte decToBcd(byte val)
{
return (byte)(((int)val / 10 * 16) + ((int)val % 10));
}

How to encode an RFID UHF tag only once using Impinj speedway

Im using ocatne SDK C# and impinj speedway R420 to encode RFID UHF gen2 tags.
I used the samples of the SDK to write to the tags and it is working, my problems start when i want encode continuous and i will explain.
I want to put a single tag in the reader field encode it and remove it and then to wait for 2nd tag encode it and so on....
I was tring to set Search Mode to 'Single Target' and use Session 2 but it is only reading the tag and not encoding it, i never get the encode seq to run.
any other option it just keep encoding and encoding very fast and i dont know when to remove the tag so i can control the encoding data.
my code here:
using System;
using System.Threading;
using Impinj.OctaneSdk;
using System.Windows.Threading;
namespace OctaneSdkExamples
{
class Program
{
// Create an instance of the ImpinjReader class.
static ImpinjReader reader = new ImpinjReader();
const ushort EPC_OP_ID = 123;
const ushort PC_BITS_OP_ID = 321;
static Random random = new Random((int)DateTime.Now.Ticks);
public static void DelayAction(int millisecond)
{
var timer = new DispatcherTimer();
timer.Tick += delegate
{
timer.Stop();
};
timer.Interval = TimeSpan.FromMilliseconds(millisecond);
timer.Start();
}
static string GetRandomEpc()
{
string epc = "";
int numWords = random.Next(1, 7);
for (int i = 0; i < numWords; i++)
epc += random.Next(0, ushort.MaxValue + 1).ToString("X4");
return epc;
}
static void ProgramEpc(string currentEpc, ushort currentPcBits, string newEpc)
{
// Check that the specified EPCs are a valid length
if ((currentEpc.Length % 4 != 0) || (newEpc.Length % 4 != 0))
throw new Exception("EPCs must be a multiple of 16 bits (4 hex chars)");
Console.WriteLine("\nAdding a write operation to change the EPC from :");
Console.WriteLine("{0} to {1}\n", currentEpc, newEpc);
// Create a tag operation sequence.
// You can add multiple read, write, lock, kill and QT
// operations to this sequence.
TagOpSequence seq = new TagOpSequence();
// Specify a target tag based on the EPC.
seq.TargetTag.MemoryBank = MemoryBank.Epc;
seq.TargetTag.BitPointer = BitPointers.Epc;
seq.TargetTag.Data = currentEpc;
// If you are using Monza 4, Monza 5 or Monza X tag chips,
// uncomment these two lines. This enables 32-bit block writes
// which significantly improves write performance.
//seq.BlockWriteEnabled = true;
//seq.BlockWriteWordCount = 2;
// Create a tag write operation to change the EPC.
TagWriteOp writeEpc = new TagWriteOp();
// Set an ID so we can tell when this operation has executed.
writeEpc.Id = EPC_OP_ID;
// Write to EPC memory
writeEpc.MemoryBank = MemoryBank.Epc;
// Specify the new EPC data
writeEpc.Data = TagData.FromHexString(newEpc);
// Starting writing at word 2 (word 0 = CRC, word 1 = PC bits)
writeEpc.WordPointer = WordPointers.Epc;
// Add this tag write op to the tag operation sequence.
seq.Ops.Add(writeEpc);
// Is the new EPC a different length than the current EPC?
if (currentEpc.Length != newEpc.Length)
{
// We need adjust the PC bits and write them back to the
// tag because the length of the EPC has changed.
// Adjust the PC bits (4 hex characters per word).
ushort newEpcLenWords = (ushort)(newEpc.Length / 4);
ushort newPcBits = PcBits.AdjustPcBits(currentPcBits, newEpcLenWords);
Console.WriteLine("Adding a write operation to change the PC bits from :");
Console.WriteLine("{0} to {1}\n", currentPcBits.ToString("X4"), newPcBits.ToString("X4"));
TagWriteOp writePc = new TagWriteOp();
writePc.Id = PC_BITS_OP_ID;
// The PC bits are in the EPC memory bank.
writePc.MemoryBank = MemoryBank.Epc;
// Specify the data to write (the modified PC bits).
writePc.Data = TagData.FromWord(newPcBits);
// Start writing at the start of the PC bits.
writePc.WordPointer = WordPointers.PcBits;
// Add this tag write op to the tag operation sequence.
seq.Ops.Add(writePc);
}
// Add the tag operation sequence to the reader.
// The reader supports multiple sequences.
reader.AddOpSequence(seq);
}
static void Main(string[] args)
{
try
{
reader.Connect("10.0.1.201");
// Assign the TagsReported event handler.
// This specifies which method to call
// when tags reports are available.
reader.TagsReported += OnTagsReported;
reader.TagOpComplete += OnTagOpComplete;
Settings settings = reader.QueryDefaultSettings();
settings.Report.IncludeAntennaPortNumber = true;
settings.Report.IncludePcBits = true;
settings.ReaderMode = ReaderMode.AutoSetDenseReader;
settings.Antennas.DisableAll();
settings.Antennas.GetAntenna(1).IsEnabled = true;
settings.Antennas.GetAntenna(1).MaxRxSensitivity = true;
settings.Antennas.GetAntenna(1).TxPowerInDbm = 10;
settings.SearchMode = SearchMode.SingleTarget;
settings.Session =2;
settings.TagPopulationEstimate = 1;
reader.ApplySettings(settings);
// Start reading.
reader.Start();
// Wait for the user to press enter.
Console.WriteLine("Press enter to exit.");
Console.ReadLine();
// Stop reading.
reader.Stop();
// Disconnect from the reader.
reader.Disconnect();
}
catch (OctaneSdkException e)
{
// Handle Octane SDK errors.
Console.WriteLine("Octane SDK exception: {0}", e.Message);
}
catch (Exception e)
{
// Handle other .NET errors.
Console.WriteLine("Exception : {0}", e.Message);
}
}
static void OnTagsReported(ImpinjReader sender, TagReport report)
{
// This event handler is called asynchronously
// when tag reports are available.
// Loop through each tag in the report
// and print the data.
reader.TagsReported -= OnTagsReported;
Tag tag = report.Tags[0];
ProgramEpc(tag.Epc.ToHexString(), tag.PcBits, GetRandomEpc());
}
static void OnTagOpComplete(ImpinjReader reader, TagOpReport report)
{
// Loop through all the completed tag operations.
foreach (TagOpResult result in report)
{
// Was this completed operation a tag write operation?
if (result is TagWriteOpResult)
{
// Cast it to the correct type.
TagWriteOpResult writeResult = result as TagWriteOpResult;
if (writeResult.OpId == EPC_OP_ID)
Console.WriteLine("Write to EPC complete : {0}", writeResult.Result);
else if (writeResult.OpId == PC_BITS_OP_ID)
Console.WriteLine("Write to PC bits complete : {0}", writeResult.Result);
// Print out the number of words written
Console.WriteLine("Number of words written : {0}", writeResult.NumWordsWritten);
}
}
//DelayAction(3000);
//Thread.Sleep(3000);
reader.TagsReported += OnTagsReported;
}
}
}
When you use Session 2 and Single Target, the tag will respond only once, until it has been out of the field for more than a certain amount of time. That means that when you read it, and then try to program it, it doesn't respond anymore. Therefore it is necessary in this set-up to use Dual Target.
To figure out whether you already have programmed a specific tag, keep track of the TID of a tag: for most tags this contains a unique serial number programmed on IC production that will never change, even if you change the EPC. You can watch this value for a new tag to be entered in the field.

Wrong data transfered via USB control transfer in Linux/Mono

We have a USB device here which has a EZ-USB FX chip on it and we "talk" to it via libusb-1.0 using LibUsbDotNet. Using Windows everything works fine, but using Mono 3.12.1 under Ubuntu 14.04 it does not work. I did some investigation and testing and found out it can't initialize the device, where we use the following logic (this is from my test program, but the "real logic" is equivalent):
protected bool ResetDevice(UsbDevice Device)
{
Console.WriteLine("First ensure that the EZ-USB 8051 is RESET (CPUCS=1)");
if (!ControlTransfer(Device, new byte[] { 1 }))
return false;
Console.WriteLine ("Then allow the EZ-USB CPU to 're-enumerate' (CPUCS=0)");
if (!ControlTransfer(Device, new byte[] { 0 }))
return false;
Console.WriteLine("Reset done...");
return true;
}
public bool ControlTransfer(UsbDevice Device, byte[] data, short? value = null)
{
int written;
var setupPacket = SetupPacket(value);
return Device.ControlTransfer(ref setupPacket, data, data.Length, out written);
}
internal UsbSetupPacket SetupPacket(short? value = null)
{
var controlPacket = new UsbSetupPacket();
controlPacket.Request = 0xA0;
controlPacket.RequestType = 64;
controlPacket.Value = value ?? 0x07F92;
controlPacket.Index = 0;
return controlPacket;
}
I then used an USB analyzer to profile the commands sent via the USB-Port.
Using Windows I get the following:
which is correct and as you can see the device resets an can be used, but when using Linux I get the following:
Now instead of 01 and 00 the command sends 68 and A8 and so the device does nothing.
Does anyone have an idea what could be the reason of that? Why does it send the wrong data packet under Linux?
It seems this is a Bug of LibUsbDotNet (very likely THIS one), as a build of the current trunk (v2.2.9) did solve this problem.

ZeroMQ C# client doesnt receive messages from C++ server

I've tried to program sending messages from one server to multiple clients.
I have to use C# on client side, C++ on server side.
I took example from http://zguide.zeromq.org/page:all#toc8 for server:
#define within(num) (int) ((float) num * rand () / (RAND_MAX + 1.0))
int main () {
// Prepare our context and publisher
zmq::context_t context (1);
zmq::socket_t publisher (context, ZMQ_PUB);
publisher.bind("tcp://*:5556");
//publisher.bind("ipc://weather.ipc");
// Initialize random number generator
srand ((unsigned) time (NULL));
while (1) {
int zipcode, temperature, relhumidity;
// Get values that will fool the boss
zipcode = within (100000);
temperature = within (215) - 80;
relhumidity = within (50) + 10;
// Send message to all subscribers
zmq::message_t message(20);
_snprintf ((char *) message.data(), 20 ,
"%05d %d %d", zipcode, temperature, relhumidity);
publisher.send(message);
}
return 0;
}
And for client:
namespace ZMQGuide
{
internal class Program
{
public static void Main(string[] args) {
Console.WriteLine("Collecting updates from weather server…");
// default zipcode is 10001
string zipcode = "10001 "; // the reason for having a space after 10001 is in case of the message would start with 100012 which we are not interested in
if (args.Length > 0)
zipcode = args[1] + " ";
using (var context = new Context(1))
{
using (Socket subscriber = context.Socket(SocketType.SUB))
{
subscriber.Subscribe(zipcode, Encoding.Unicode);
subscriber.Connect("tcp://localhost:5556");
const int updatesToCollect = 100;
int totalTemperature = 0;
for (int updateNumber = 0; updateNumber < updatesToCollect; updateNumber++)
{
string update = subscriber.Recv(Encoding.Unicode);
totalTemperature += Convert.ToInt32(update.Split()[1]);
}
Console.WriteLine("Average temperature for zipcode {0} was {1}F", zipcode, totalTemperature / updatesToCollect);
}
}
}
}
}
They don't communicate with each other.
On the client side (C++) I commented line with ipc interaction because on Windows client with ipc is failed.
C# - C#, C++ - C++ interactions works correctly in this case.
I use clrzmq 2.2.5.
I would appreciate any help.
C# client is using Encoding.Unicode, which is a 2-byte unicode representation (UTF-16). C++ server is using ASCII.
ZMQ subscription matching works on the byte level and does not convert between character encodings, so this is where my issue is. Switching to Encoding.ASCII or Encoding.UTF8 in C# client solves this issue.

Categories