Windows IoT Raspberry Pi 3 C# RTC DS3231 - c#

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

Related

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

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?

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

NetworkStream.ReadTimeout failing to block on NetworkStream.Read(...) when daylight savings are applied and clock moves backwards

I'm hoping someone can explain this behaviour, or if it's maybe a bug in .NET.
Moving backwards in time due to daylight savings means that NetworkStream pays no attention to its property ReadTimeout, and in the case of this code causes the loops to spin. (This is just an example to prove it's happening).
To reproduce the problem I am seeing, you will need to be set to a timezone that uses daylight savings, e.g. The United Kingdom.
Set your TimeZone to UTC London and make sure the daylight savings time is ticked.
Change your date back to 29th October 2017
Set your time to 01:58:50 am
Run code below and watch it spin when it applies the daylight saving time at what would be 2am, if it applies it correctly time should move back to 1am.
Make sure you wait, it can take up to 30 seconds for it to start spinning.
Edit: After deeping investigation, after 1 hour, it stops spinning and the behaviour returns to normal and honours the ReadTimeout.
Any thoughts would be appreciated!
Client code:
class Program
{
static bool running = false;
static void Main(string[] args)
{
running = true;
Task.Factory.StartNew(() => Run());
Console.ReadKey();
running = false;
}
static void Run()
{
TcpClient connection = new TcpClient("127.0.0.1", 1234);
while (running)
{
if (connection != null && connection.Connected)
{
try
{
NetworkStream stream = connection.GetStream();
stream.ReadTimeout = 1000;
byte[] buffer = new byte[1024];
int readCount = stream.Read(buffer, 0, 1024); // Should block here for the ReadTimeout duration if nothing received
// However when daylight savings is applied and time moves backwards an hour, the stream.ReadTimeout = 1000;
// is not honoured and it falls through and spins
if (readCount > 0)
{
Console.WriteLine("Received some data");
//process read here
}
else
{
Console.WriteLine("ReadTimeout was not honoured");
}
}
catch (IOException)
{
Console.WriteLine("Read timed out");
}
}
}
}
}
Server Code:
class Program
{
static bool running = false;
public static void Main()
{
TcpListener server = null;
try
{
// Set the TcpListener on port 13000.
Int32 port = 5000;
IPAddress localAddr = IPAddress.Parse("192.168.1.69");
// TcpListener server = new TcpListener(port);
server = new TcpListener(localAddr, port);
// Start listening for client requests.
server.Start();
// Enter the listening loop.
while (true)
{
Console.Write("Waiting for a connection... ");
// Perform a blocking call to accept requests.
// You could also user server.AcceptSocket() here.
TcpClient client = server.AcceptTcpClient();
Console.WriteLine("Connected!");
// Get a stream object for reading and writing
NetworkStream stream = client.GetStream();
running = true;
Task.Factory.StartNew(() => Run(stream));
Console.ReadKey();
// Shutdown and end connection
client.Close();
}
}
catch (SocketException e)
{
Console.WriteLine("SocketException: {0}", e);
}
finally
{
// Stop listening for new clients.
server.Stop();
}
Console.WriteLine("\nHit enter to continue...");
Console.Read();
}
static async Task Run(NetworkStream stream)
{
byte[] stuffToSend = Encoding.ASCII.GetBytes("Stuff to send");
while (running)
{
stream.Write(stuffToSend, 0, stuffToSend.Length);
await Task.Delay(1000);
}
}
}
There are some very important notes in the OS documentation that aren't mentioned in the .NET ReadTimeout property:
SO_RCVTIMEO and SO_SNDTIMEO
When using the recv function, if no data arrives during the period specified in SO_RCVTIMEO, the recv function completes. In Windows versions prior to Windows 2000, any data received subsequently fails with WSAETIMEDOUT. In Windows 2000 and later, if no data arrives within the period specified in SO_RCVTIMEO, the recv function returns WSAETIMEDOUT, and if data is received, recv returns SUCCESS.
If a send or receive operation times out on a socket, the socket state is indeterminate, and should not be used; TCP sockets in this state have a potential for data loss, since the operation could be canceled at the same moment the operation was to be completed.
Currently, after each timeout you are looping and trying another receive operation on the same socket. But this note makes it very clear that you need to create a new connection.
Please read this. https://msdn.microsoft.com/en-us/library/ms973825.aspx
In general, if you are dealing with absolute elapsed time, such as
measuring a timeout, performing arithmetic, or doing comparisons of
different DateTime values, you should try and use a Universal time
value if possible so that you get the best possible accuracy without
effects of time zone and/or daylight savings having an impact.
Just adjust the thread to use universal time.
Edit 1.
I failed to understand your question. You did not want a workaround.
Its a known bug related to how .net manages the, and related discussion has been done before here.
Cache.Add absolute expiration - UTC based or not?
During one hour at the end of daylight savings time, your local time
is ambiguous, so you can get unexpected results, i.e. the absolute
expiration can be one hour longer than expected.
Edit 2.
Added another discussion thread more in context with the OP question.
https://social.msdn.microsoft.com/Forums/vstudio/en-US/cb0369f4-8c96-484a-a33e-5e4c850b995e/wcf-channels-and-datetime-change?forum=wcf
Here is the sourced code :http://referencesource.microsoft.com/#mscorlib/system/io/stream.cs,f956b0c07e86df64
[ComVisible(false)]
public virtual int ReadTimeout {
get {
Contract.Ensures(Contract.Result<int>() >= 0);
throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_TimeoutsNotSupported"));
}
set {
throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_TimeoutsNotSupported"));
}
}
[ComVisible(false)]
public virtual int WriteTimeout {
get {
Contract.Ensures(Contract.Result<int>() >= 0);
throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_TimeoutsNotSupported"));
}
set {
throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_TimeoutsNotSupported"));
}
}

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.

How to call a function between two WinForm applications over the network?

I have a video kiosk setup in my lobby, it lets people check in and print a badge with their picture, name, etc. There is also a remote support tool that unfortunately crashes sometimes. I have a function on the kiosk that fixes this issue but you must go to the kiosk to trigger it right now.
I have also written a management tool that uses WMI to monitor and manage some other aspects of the kiosk. I would like to be able to trigger this repair function via this application. I have spent countless hours on google trying to figure this out with no luck. Maybe I am not searching for the right things.
My question is this. In C# how can I call the repair function in my kiosk application from the admin application over the network?
OK, on my Server form, I have a BackgroundWorker that runs a TcpListener. You will want to put this TcpListener in a BackgroundWorker, otherwise you will never be able to stop it from executing until it accepts a TcpClient.
Also, you will want to process any data you receive from this background thread in the main thread of execution to prevent cross thread exceptions:
private TcpListener _listener;
private const int port = 8000;
private void Worker_TcpListener(object sender, DoWorkEventArgs e) {
BackgroundWorker worker = sender as BackgroundWorker;
do {
try {
_listener = new TcpListener(IPAddress.Any, port);
_listener.Start();
TcpClient client = _listener.AcceptTcpClient(); // waits until data is avaiable
int MAX = client.ReceiveBufferSize;
NetworkStream stream = client.GetStream();
Byte[] buffer = new Byte[MAX];
int len = stream.Read(buffer, 0, MAX);
if (0 < len) {
string data = Encoding.UTF8.GetString(buffer);
worker.ReportProgress(len, data.Substring(0, len));
}
stream.Close();
client.Close();
} catch (SocketException) {
// See MSDN: Windows Sockets V2 API Error Code Doc for details of error code
} catch (ThreadAbortException) { // If I have to call Abort on this thread
return;
} finally {
_listener.Stop();
}
} while (!worker.CancellationPending);
}
This would not be good for large messages (like JPEG files and such), but works great for short strings where I have coded in special data to look for.
This data is sent back to my main thread of execution (using the ReportProcess method) where the data is processed:
private void Worker_TcpListener(object sender, ProgressChangedEventArgs e) {
if (e.UserState != null) {
int len = e.ProgressPercentage;
string data = e.UserState.ToString();
if (!String.IsNullOrEmpty(data) && (3 < len)) {
string head = data.Substring(0, 3);
string item = data.Substring(3);
if (!String.IsNullOrEmpty(item)) {
if (head == "BP:") {
string[] split = data.Split(';');
if (2 < split.Length) {
string box = split[0].Substring(3); // Box Number
string qty = split[1].Substring(2); // Quantity
string customer = split[2].Substring(2); // Customer Name
MyRoutine(box, qty, customer);
}
}
}
}
}
}
The code above just sits and runs all day long.
Meanwhile, I have about 10 Pocket PC devices in our plant that could send data at any time. The code for them is written in VB, and I really hope I have time to finish my C# version one of these days, but here it is:
Private Sub SendToServer(string serialNum, int qty, string customer)
Cursor.Current = Cursors.WaitCursor
Try
Dim strPacket As String = String.Format("BP:{0};Q:{1};C:{2};", serialNum, qty, customer)
Dim colon As Integer = p7_txtIPAddress.Text.IndexOf(":")
Dim host As String = p7_txtIPAddress.Text.Substring(0, colon)
Dim port As Integer = CInt(p7_txtIPAddress.Text.Substring(colon + 1))
Dim dataPacket As [Byte]() = Encoding.ASCII.GetBytes(strPacket)
Using client As New TcpClient(host, port)
Dim stream As NetworkStream = client.GetStream()
stream.Write(dataPacket, 0, dataPacket.Length)
End Using
Catch err As Exception
MessageBox.Show(err.Message, "Print To Server TCP Error")
Finally
Cursor.Current = Cursors.Default
End Try
End Function
I don't know if that is what you are trying to do, but it works and is reliable.
Obviously, the code I have in production is larger and includes other things (i.e. employee validation, error loggers, etc.) that you would not find useful. I have cut a lot of those out, and I hope I did not cut out anything necessary.
This should give you an idea of how to move forward, at least.

Categories