Reading and writing to arduino at the same time - c#

I have a situation where I read values from sensors (attached to an arduino) which gets stored in a mysql database, which is then displayed on a webpage. At the same time relay values are read from a webpage, stored on mysql and then written to the arduino. I can do each separately but not at the same time. I've attached some code to show what Im trying to accomplish. I think it has something to do with Serial availability
/*----( SETUP: RUNS ONCE )----*/
void setup() {
Serial.begin(115200);
sensors.begin(); //Get DS18B20 temperatures
sensors.setResolution(probe1, 10); //set resolution to 10bit
sensors.setResolution(probe2, 10); //set resolution to 10bit
Wire.begin(); // Start the Wire (I2C communications)
RTC.begin(); // Start the RTC Chip
digitalWrite(Relay_1, RELAY_OFF); //Relays
digitalWrite(Relay_2, RELAY_OFF);
pinMode(Relay_1, OUTPUT); //Set relays as outputs
pinMode(Relay_2, OUTPUT);
}
/*--(end setup )---*/
/****** LOOP: RUNS CONSTANTLY ******/
void loop() {
ReadSensors();
delay(1000);
ReadRelays();
}
/****** Read Sensors ******/
void ReadSensors()
{
DateTime now = RTC.now(); //Get time from RTC
photolevel = analogRead(photopin); //Read light level
sensors.requestTemperatures();
dallas1 = sensors.getTempC(probe1);
dallas2 = sensors.getTempC(probe2);
dtostrf(photolevel, 1, 0, photo1);
dtostrf(dallas1, 1, 2, temp1);
dtostrf(dallas2, 1, 2, temp2);
String tempAsString1 = String(photo1);
String tempAsString2 = String(temp1);
String tempAsString3 = String(temp2);
Serial.print(now.year(), DEC);
Serial.print('/');
Serial.print(now.month(), DEC);
Serial.print('/');
Serial.print(now.day(), DEC);
Serial.print(" ");
Serial.print(now.hour(), DEC);
Serial.print(':');
Serial.print(now.minute(), DEC);
Serial.print(" ");
Serial.println(tempAsString1 + " " + tempAsString2 + " " + tempAsString3);
Serial.flush();
}
void ReadRelays()
{
Serial.flush();
// Read all serial data available, as fast as possible
while(Serial.available() > 0)
{
char inChar = Serial.read();
if(inChar == SOP)
{
index = 0;
inData[index] = '\0';
started = true;
ended = false;
}
else if(inChar == EOP)
{
ended = true;
break;
}
else
{
if(index < 79)
{
inData[index] = inChar;
index++;
inData[index] = '\0';
}
}
}
if(started && ended)
{
// The end of packet marker arrived. Process the packet
if (strlen(inData) > 0)
{
char *token = strtok(inData, ",");
if(token)
{
index = 0;
array[index] = atoi(token);
while (token = strtok(NULL, ","))
{
array[index++] = atoi(token);
}
}
}
Serial.println(array[0]);
Serial.println(array[1]);
// Reset for the next packet
started = false;
ended = false;
index = 0;
inData[index] = '\0';
}
}
Any suggestions would be well appreciated??

The key to do several things "at the same time" is to understand that the Arduino has only one core. Thus it will process stuff only one step after the other. Now suppose you want to perform three functions "action1()", "action2()" and "action3()" at "the same time. In order to achieve this you must ensure that
all actions can be performed as fast as possible, preferably sub milliseconds
none of them "blocks"
Then the desired effect is achieved by just putting them into succession like so
void loop() {
action1();
action2();
action3();
}
This is the basic idea of "cooperative multitasking". It follows that none of the actions must utilize delay() or blocking waits. For example
while(Serial.available() == 0);
is a blocking wait and must be avoided. Things get more complicated if any of the actions is a set of lengthy and involved computations. Say action1() takes 1s to process. Then action1() must be split into pieces that execute fast enough. The pieces can still be kept in action1() with the help of a "state machine". For example
void action1() {
static uint8_t state = 0;
switch (state) {
case 1: sub_action1_1(); break;
case 2: sub_action1_2(); break;
case 3: sub_action1_2(); break;
default: state = 0; return;
}
++state;
}
Of course the sub actions must perform fast enough. Another frequently encountered issue is how to wait without blocking. This is achieved by storing the required delay. E.g. like this
void action1() {
static uint8_t state = 0;
static unsigned long start_millis = 0;
switch (state) {
case 1: sub_action(); break;
case 2: // this starts the delay
start_millis = millis();
break;
case 3: // this checks if the delay has elapsed
if (millis() - start_millis < 1000) {
// if it did not yet elapse ensure that the state will not progress to the next step
return;
}
// if the delay has elapsed proceed to next state
break;
case 4: next_sub_action(); break;
default: state = 0; return;
}
++state;
}
Of course this is only the basic principle. In "real" implementations you may vary this as needed.
Another often needed thing is to have a main loop that does some stuff and a higher frequency "loop" that does some other stuff. This is usually performed with so called timer interrupts. This is more advanced but usually more efficient also. The tricky thing with interrupts is that they tend to be somewhat harder to debug. I have some documented examples for this in my blog.
blinking several LEDs with different frequencies.
VU Meter experiment (scroll down!)

Related

Endless while loop while polling data out of received bytes

I use some third party code from which i thought it worked...it is a loop which is polling some data out of the received Socket-bytes with a ByteBuffer and has to react to the timeout in case when the NetworkTpdu is null, but it doesn't! The while-loop is endless...Somebody an idea?
int start = Environment.TickCount;
int myTimeout = 5000;
while (NetworkTpdu.CreateFromBuffer(_receiveBuffer, false) == null && (!_masterMode || Environment.TickCount - start < myTimeout))
{
_receiveBuffer.WaitForByte(myTimeout, false);
}
it will probably be easier to find the problem if you split the method into separate statements. For example:
var sw = Stopwatch.StartNew();
var timeout = TimeSpan.FromSeconds(5);
while (true)
{
var buffer = NetworkTpdu.CreateFromBuffer(_receiveBuffer, false);
if (buffer != null)
{
Console.WriteLine("Buffer is not null");
return;
}
if (_masterMode)
{
if (sw.Elapsed > timeout)
{
Console.WriteLine("Timeout!");
return;
}
}
Console.WriteLine("Wait for byte: " + sw.ElapsedMilliseconds);
_receiveBuffer.WaitForByte(timeout.TotalMilliseconds, false);
// Check if WaitForByte succeeded or timed out, and handle the result
}
This should make it easy to find the problem:
Wait for Byte is not printed -> CreateFromBuffer never returns
Wait for Byte is only printed once -> WaitForByte never returns
Wait for Byte is printed with a value over 5000 -> _masterMode is false
Edit: As canton7 mentioned in the comments, you can do the same thing with a debugger by placing breakpoints or tracepoints at appropriate places. This is merely a way to make the execution order more apparent.

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;
}
}

Changing Textbox.text within a method; For loop not looping due to Return

Below is a button, when pressed it calls a function that pings a bunch of IP addresses. If the IP address returns a response, it adds the IP address to the output_networkSearch.Text.
private void button_networkSearch_Click(object sender, RoutedEventArgs e)
{
output_networkSearch.Text = networkSearch(Convert.ToInt32(input_searchLimit.Text));
}
Below isn't the whole method, just the part that I can't get to work. The for loop starts at whatever the last digit on the users default gateway IP address is, and stops at whatever limit they have inputed (1 - 255).
// i is equal to the last digit in the default gateway IP, if it was 192.168.0.1 then i = 1.
for (int i = Convert.ToInt32(splitGatewayIP[3]); i <= searchLimit; i = i + 1)
{
// If the method receieves a ping reply...
if (PingHostSweep(gatewayIPRebuild + i))
{
// Returns 192.168.0. + i + ACTIVE
string response = gatewayIPRebuild + i + " ACTIVE";
return response;
}
else
{
string response = gatewayIPRebuild + i + " CLOSED";
return response;
}
}
This worked on a console application but for a WPF application it seems to run through the loop once and stop due to the return statement.
My idea to work around this would be to remove the Return Response statements and try and access the TextBox (output_networkSearch) directly.
So I would do something like:
for (int i = Convert.ToInt32(splitGatewayIP[3]); i <= searchLimit; i = i + 1)
{
// If the method receieves a ping reply...
if (PingHostSweep(gatewayIPRebuild + i))
{
// Returns 192.168.0. + i + ACTIVE
string response = gatewayIPRebuild + i + " ACTIVE";
output_networkSearch.Text = reponse;
}
else
{
string response = gatewayIPRebuild + i + " CLOSED";
output_networkSearch.Text = reponse;
}
}
HOWEVER, I can't access the textbox within the method for some reason. I've only just started learning C# so I'm not entirely familiar with how it works.
Here's an image of a partially working concept. As you can see the limit is set at 10, so it should ping IP address 1 through 10 and give an ACTIVE or CLOSED response. This did work in my console application version.
WPF version
Console version
This might do the trick for you
List<string> responses = new List<string>();
string response;
for (int i = Convert.ToInt32(splitGatewayIP[3]); i <= searchLimit; i = i + 1)
{
if (PingHostSweep(gatewayIPRebuild + i))
{
response = gatewayIPRebuild + i + " ACTIVE";
}
else
{
response = gatewayIPRebuild + i + " CLOSED";
}
responses.Add(response)
}
Now after the loop the list which is responses would have the list of all the IPs which are active and closed. Like the way you do had in the console Application.
i think you need use threading, there are need many child threading work in backend to scan, when they finish them work then response the result to MainForm, so i write some code hope can help you!
using System.Threading;
using System.Threading.Tasks;
public void Start(string ip)
{
Task.Factory.StartNew(() =>
{
// If the method receieves a ping reply...
string response;
if (PingHostSweep(ip))
{
// Returns 192.168.0. + i + ACTIVE
response = ip + " ACTIVE";
}
else
{
response = ip + " CLOSED";
}
this.Invoke((MethodInvoker)(() => { textBox1.AppendText("\r\n" + response); }));
});
}
private void button1_Click(object sender, EventArgs e)
{
for (int i = 1; i <= 255; i++)
{
Start(String.Format("192.168.100.{0}", i));
}
}
The previous answer was correct (though it didn't touch on a more advanced point that you will ultimately need to learn ... delegation and invocation ... long story ... won't bore you now).
What you wrote distills to this:
// SIDE NOTE: you cannot actually treat an IPv4 address as four "pure" quads (but that's not your question)
var notNecessarilyAHost = splitGatewayIP[3];
var searchStart = Convert.ToInt32(notNecessarilyAHost);
for (var i = searchStart; i <= searchLimit; ++i)
{
if (PingHostSweep(gatewayIPRebuild + i))
{
return $"{gatewayIPRebuild}{i} ACTIVE";
}
else
{
return $"{gatewayIPRebuild}{i} CLOSED";
}
}
...and if you (mentally) step through what you wrote it's fairly straightforward to see that the loop will only ever cycle once. Upon entry to the loop i will be equal to whatever searchStart is. Then you enter the if test. If that test is true, you fall into the true side of the branch (i.e., "...ACTIVE"). Otherwise, you'll drop into the else branch (i.e., "...CLOSED". FROM THERE...
You ALWAYS return. That will exit the loop (and the function that contains it). You will never cycle the loop again. "break" and "return" (and plausibly goto ... but that's for a different day) will ALWAYS exit the current scope (scope being a block of code wrapped by '{' and '}' (be they explicitly or implicitly written).
Following?
The previous answer was correct. It adjusts your code so that the loop adds the string you're composing with each iteration to a list of strings. Then, when you exit the loop (because i reaches searchLimit) that list of strings will contain N many, well, strings. You probably want to return or continue working that.
All that said, you can't (technically you can but you SHOULDN'T) do any of this inside a UI thread. If you do, the UI will block (and become 100% unresponsive to the user) while the loop runs (and the network calls that it makes run), etc.

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.

Simple way to run methods asynchronously in .NET 4?

This is a simple .NET 4 application. Here's the code I want to run:
string username = "userfoo";
string password = "passwordfoo";
for (int i = 0; i < 2000; i++)
{
uint matchId;
if (!uint.TryParse(i.ToString(), out matchId))
{
Console.WriteLine("Invalid Match ID!");
return;
}
Client client = new Client (username, password, matchId);
// connect
client.Connect();
client.Wait();
if (client.Match != null)
{
Console.WriteLine("Inserting match: #{0}", client.Match.match_id);
Helpers.MatchHelper.AddMatchToDatabase(client.Match);
}
else
{
Console.WriteLine("Couldn't get match: #{0}", 1);
}
}
Instead doing this one by one (it would take forever - 415 days nonstop according to my calculations), what's the easiest way to invoke each iteration of this for loop asynchronously?
Most questions and articles are very old (circa 2001!) surely there must be a more modern approach?
http://msdn.microsoft.com/en-us/magazine/cc301332.aspx
You can find information here: http://msdn.microsoft.com/en-us/library/ff963552.aspx. Basically, you just use Parallel.For(0, n, x => doSomething). That takes care of parallelization. This is a functionality of PLINQ that is extremely easy to use an in my experience works quite well.
Your sample would look like this:
string username = "userfoo";
string password = "passwordfoo";
Parallel.For(0, 2000, i =>
{
uint matchId;
if (!uint.TryParse(i.ToString(), out matchId))
{
Console.WriteLine("Invalid Match ID!");
return;
}
Client client = new Client (username, password, matchId);
// connect
client.Connect();
client.Wait();
if (client.Match != null)
{
Console.WriteLine("Inserting match: #{0}", client.Match.match_id);
Helpers.MatchHelper.AddMatchToDatabase(client.Match);
}
else
{
Console.WriteLine("Couldn't get match: #{0}", 1);
}
});
I think this is what you are looking for:
http://www.codeproject.com/Articles/71285/Introducing-NET-4-0-Parallel-Programming
You should look at the task parallel library
If i understand you correctly, you want to run these in a separate thread. Here's one way to do this:
You need to move the code from the loop into a void function:
void MyThreadInsteadOfLoop(object parameter)
{
int i = (int)parameter;
uint matchId;
if (!uint.TryParse(i.ToString(), out matchId))
{
Console.WriteLine("Invalid Match ID!");
return;
}
Client client = new Client (username, password, matchId);
// connect
client.Connect();
client.Wait();
if (client.Match != null)
{
Console.WriteLine("Inserting match: #{0}", client.Match.match_id);
Helpers.MatchHelper.AddMatchToDatabase(client.Match);
}
else
{
Console.WriteLine("Couldn't get match: #{0}", 1);
}
}
In your main thread, you need to prepare threads to run, start them, and wait them to finish, if you want to. Here's the code:
//Create threads
List<Thread> threads = new List<Thread>();
for(int i=0;i<2000;i++)
{
threads.Add(new Thread(new ParameterizedThreadStart(MyThreadInsteadOfLoop)));
}
//Start threads
int x = 0;
foreach(var t in threads)
{
t.Start(x);
x++;
}
//wait for the threads to finish
foreach(var t in threads)
{
t.Join();
}
Be aware, that you have to make the MatchHelper class, and other classes that exchange data with your threads thread safe, and that tends to add lots of overhead to your program. Also, you can possibly run into trouble with the network connections.
Only [NumberOfCpuCores]*2 threads will actively work (*2 because of hyper-threading) at a time, but since you have to wait for the client (I really hope that's not a while(true) cycle cloaked) that might get concealed at least partly.

Categories