I have a C# Class Library, that reads Bluetooth LE Characteristics. I want to use this DLL to get the read values in my VB6 app.
My Problem is: I need the complete code to get the result. That means i have to call the main function from my VB6 program, but i have no idea what parameters i have to use and how i can get the right return value.
My Dll:
using SDKTemplate;
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using Windows.Devices.Bluetooth;
using Windows.Devices.Bluetooth.GenericAttributeProfile;
using Windows.Devices.Enumeration;
using Windows.Storage.Streams;
using System.Threading.Tasks;
using System.Runtime.Remoting.Messaging;
using System.Runtime.InteropServices;
namespace BleSirLo
{
public class Program
{
public byte[] ret = new byte[6];
static void Main(string[] args)
{
Task t = MainAsync(args);
t.Wait();
// or, if you want to avoid exceptions being wrapped into AggregateException:
// MainAsync().GetAwaiter().GetResult();
}
static async Task MainAsync(string[] args)
{
Program p = new Program();
p.StartBleDeviceWatcher();
}
private List<DeviceInformation> UnknownDevices = new List<DeviceInformation>();
private List<DeviceInformation> _knownDevices = new List<DeviceInformation>();
private IReadOnlyList<GattCharacteristic> characteristics;
private IReadOnlyList<GattDeviceService> services;
private GattDeviceService currentSelectedService = null;
private GattCharacteristic currentSelectedCharacteristic = null;
private DeviceWatcher deviceWatcher;
public bool done = false;
private void StartBleDeviceWatcher()
{
// Additional properties we would like about the device.
// Property strings are documented here https://msdn.microsoft.com/en-us/library/windows/desktop/ff521659(v=vs.85).aspx
string[] requestedProperties = { "System.Devices.Aep.DeviceAddress", "System.Devices.Aep.IsConnected", "System.Devices.Aep.Bluetooth.Le.IsConnectable" };
// BT_Code: Example showing paired and non-paired in a single query.
string aqsAllBluetoothLEDevices = "(System.Devices.Aep.ProtocolId:=\"{bb7bb05e-5972-42b5-94fc-76eaa7084d49}\")";
deviceWatcher =
DeviceInformation.CreateWatcher(
aqsAllBluetoothLEDevices,
requestedProperties,
DeviceInformationKind.AssociationEndpoint);
// Register event handlers before starting the watcher.
deviceWatcher.Added += DeviceWatcher_Added;
deviceWatcher.Updated += DeviceWatcher_Updated;
deviceWatcher.Removed += DeviceWatcher_Removed;
deviceWatcher.EnumerationCompleted += DeviceWatcher_EnumerationCompleted;
deviceWatcher.Stopped += DeviceWatcher_Stopped;
// Start over with an empty collection.
_knownDevices.Clear();
//deviceWatcher.Stop();
deviceWatcher.Start();
while(true)
if (done == true)
break;
}
private void DeviceWatcher_Added(DeviceWatcher sender, DeviceInformation deviceInfo)
{
//Debug.WriteLine(String.Format("Device Found!" + Environment.NewLine + "ID:{0}" + Environment.NewLine + "Name:{1}", deviceInfo.Id, deviceInfo.Name));
//notify user for every device that is found
if (sender == deviceWatcher)
{
if ((deviceInfo.Name == "Ei Gude, wie?") || (deviceInfo.Name == "Ei Gude, Wie?"))
{
sender.Stop();
ConnectDevice(deviceInfo);
}
}
}
private void DeviceWatcher_Updated(DeviceWatcher sender, DeviceInformationUpdate deviceInfo)
{
}
private void DeviceWatcher_Removed(DeviceWatcher sender, DeviceInformationUpdate deviceInfo)
{
}
private void DeviceWatcher_EnumerationCompleted(DeviceWatcher sender, object args)
{
}
private void DeviceWatcher_Stopped(DeviceWatcher sender, object args)
{
}
//trigger StartBleDeviceWatcher() to start bluetoothLe Operation
private void Scan()
{
//empty devices list
_knownDevices.Clear();
UnknownDevices.Clear();
//finally, start scanning
StartBleDeviceWatcher();
}
private async void ConnectDevice(DeviceInformation deviceInfo)
{
//get bluetooth device information
BluetoothLEDevice bluetoothLeDevice = await BluetoothLEDevice.FromIdAsync(deviceInfo.Id);
//Respond(bluetoothLeDevice.ConnectionStatus.ToString());
//get its services
GattDeviceServicesResult result = await bluetoothLeDevice.GetGattServicesAsync();
//verify if getting success
if (result.Status == GattCommunicationStatus.Success)
{
//store device services to list
services = result.Services;
//loop each services in list
foreach (var serv in services)
{
//get serviceName by converting the service UUID
string ServiceName = Utilities.ConvertUuidToShortId(serv.Uuid).ToString();
//if current servicename matches the input service name
if (ServiceName == "65520") //ServiceTxtBox.Text)
{
//store the current service
currentSelectedService = serv;
//get the current service characteristics
GattCharacteristicsResult resultCharacterics = await serv.GetCharacteristicsAsync();
//verify if getting characteristics is success
if (resultCharacterics.Status == GattCommunicationStatus.Success)
{
//store device services to list
characteristics = resultCharacterics.Characteristics;
//loop through its characteristics
foreach (var chara in characteristics)
{
//get CharacteristicName by converting the current characteristic UUID
string CharacteristicName = Utilities.ConvertUuidToShortId(chara.Uuid).ToString();
//if current CharacteristicName matches the input characteristic name
if (CharacteristicName == "65524")//CharacteristicsTxtBox.Text)
{
//store the current characteristic
currentSelectedCharacteristic = chara;
//stop method execution
readBuffer();
return;
}
}
}
}
}
}
}
//function that handles the read button event
private async void readBuffer()
{
{
if (currentSelectedService != null && currentSelectedCharacteristic != null)
{
GattCharacteristicProperties properties = currentSelectedCharacteristic.CharacteristicProperties;
//if selected characteristics has read property
if (properties.HasFlag(GattCharacteristicProperties.Read))
{
//read value asynchronously
GattReadResult result = await currentSelectedCharacteristic.ReadValueAsync();
if (result.Status == GattCommunicationStatus.Success)
{
int a, b, c, d, e, f;
var reader = DataReader.FromBuffer(result.Value);
//byte [] input = new byte[reader.UnconsumedBufferLength];
reader.ReadBytes(ret);
a = ret[0];
b = ret[1];
c = ret[2];
d = ret[3];
e = ret[4];
f = ret[5];
Ret_val(ret);
}
}
}
}
}
private void Response_TextChanged(object sender, EventArgs e)
{
}
}
In my VB6 program I call the Library like this: (It is obviously not working, but i dont know how i should do it.
Dim WithEvents CSharpInteropServiceEvents As CSharpInteropService.LibraryInvoke
Dim load As New LibraryInvokeparam(0) = Me.hwnd
Dim sa as variant
Set CSharpInteropServiceEvents = load
sa = load.GenericInvoke("C:\Program Files (x86)\Microsoft Visual Studio\VB98\WINCOM\BleSirLo.dll", "BleSirLo.Program", "Main", param)
Related
I want to make call with sip using Ozeki library.
But this library throws me state excepton.
I use asteriks telephony in the server.
My code is below:
class Program
{
static ISoftPhone softphone; // softphone object
static IPhoneLine phoneLine; // phoneline object
static IPhoneCall call;
static Microphone microphone;
static Speaker speaker;
static MediaConnector connector;
static PhoneCallAudioSender mediaSender;
static PhoneCallAudioReceiver mediaReceiver;
public static void Main(string[] args)
{
// Create a softphone object with RTP port range 5000-10000
softphone = SoftPhoneFactory.CreateSoftPhone(1, 10000);
// SIP account registration data, (supplied by your VoIP service provider)
var registrationRequired = true;
var userName = "111";
var displayName = "111";
var authenticationId = "111";
var registerPassword = "pin111";
var domainHost = "localhost";
var domainPort = 5038;
var account = new SIPAccount(registrationRequired, displayName, userName, authenticationId, registerPassword, domainHost, domainPort);
// Send SIP regitration request
RegisterAccount(account);
microphone = Microphone.GetDefaultDevice();
speaker = Speaker.GetDefaultDevice();
mediaSender = new PhoneCallAudioSender();
mediaReceiver = new PhoneCallAudioReceiver();
connector = new MediaConnector();
// Prevents the termination of the application
Console.WriteLine("\nDone");
Console.ReadLine();
}
static void RegisterAccount(SIPAccount account)
{
try
{
phoneLine = softphone.CreatePhoneLine(account);
phoneLine.RegistrationStateChanged += line_RegStateChanged;
softphone.RegisterPhoneLine(phoneLine);
}
catch (Exception ex)
{
Console.WriteLine("Error during SIP registration: " + ex);
}
}
static void line_RegStateChanged(object sender, RegistrationStateChangedArgs e)
{
if (e.State == RegState.NotRegistered || e.State == RegState.Error)
Console.WriteLine("Registration failed!");
if (e.State == RegState.RegistrationSucceeded)
{
Console.WriteLine("Registration succeeded - Online!");
CreateCall();
}
}
private static void CreateCall()
{
var numberToDial = "00994122000020";
call = softphone.CreateCallObject(phoneLine, numberToDial);
call.CallStateChanged += call_CallStateChanged;
call.Start();
}
private static void SetupDevices()
{
connector.Connect(microphone, mediaSender);
connector.Connect(mediaReceiver, speaker);
mediaSender.AttachToCall(call);
mediaReceiver.AttachToCall(call);
microphone.Start();
speaker.Start();
}
static void call_CallStateChanged(object sender, CallStateChangedArgs e)
{
Console.WriteLine("Call state: {0}.", e.State);
if (e.State == CallState.Answered)
SetupDevices();
}
}
This code show me this error message:
Registration succeeded - Online!
Call state: Setup.
Call state: Error.
What is the problem? What must I chane for working this code?
P.S Please, If you know the better library for making call with asteriks you can tell me.
I'm working on a Project (Console-Application .NET Framework 4.7.2 c#) to find nearby BLE devices and it's working well, the device(The device is just an Arduino with a BLE shield.) is discovered and i was able to read values from it. so the problem is that i wanted to do the same but on another PC (Same Code, Conditions, everything the same). it showed me that the pc is with the device connected but unreachable here on this place of the code :
GattDeviceServicesResult result = await bluetoothLeDevice.GetGattServicesAsync();
So i tried again and again on 3 different PCs and Laptops but it didn't work.
On the pc first i got connected to, it works well without problems. Can someone pls help me and say what is the matter. Here is my Code:
namespace QuickBlueToothLE
{
class Program
{
static public readonly Dictionary<string, DeviceInformation> mDiscoveredDevices = new Dictionary<string, DeviceInformation>();
static DeviceInformation device = null;
public static string HEG_Service_ID = "00001826-0000-1000-8000-00805f9b34fb";
public static DeviceWatcher deviceWatcher = null;
// Abfrage nach zusätzlichen Eigenschaften, die zurückgegeben werden sollen
public static string[] requestedProperties =
{
"System.Devices.Aep.DeviceAddress",
"System.Devices.Aep.IsConnected",
"System.Devices.Aep.Bluetooth.Le.IsConnectable"
};
static async Task Main(string[] args)
{
deviceWatcher = DeviceInformation.CreateWatcher
(BluetoothLEDevice.GetDeviceSelectorFromPairingState(false),
requestedProperties,
DeviceInformationKind.AssociationEndpoint);
// Register event handlers before starting the watcher.
// Added, Updated and Removed are required to get all nearby devices
deviceWatcher.Added += DeviceWatcher_Added;
deviceWatcher.Updated += DeviceWatcher_Updated;
deviceWatcher.Removed += DeviceWatcher_Removed;
// EnumerationCompleted and Stopped are optional to implement.
deviceWatcher.EnumerationCompleted += DeviceWatcher_EnumerationCompletedAsync;
deviceWatcher.Stopped += DeviceWatcher_Stopped;
// Start the watcher.
deviceWatcher.Start();
while (true)
{
if (device == null)
Thread.Sleep(2000);
else
{
Console.WriteLine("Press Any Key to connect to HEG-900725");
Console.ReadKey();
BluetoothLEDevice bluetoothLeDevice = await BluetoothLEDevice.FromIdAsync(device.Id);
Console.WriteLine("Attempting to connect with device");
GattDeviceServicesResult result = await bluetoothLeDevice.GetGattServicesAsync();
var services = result.Services;
if (result.Status == GattCommunicationStatus.Success)
{
Console.WriteLine("Connection succeeded" + " "+ bluetoothLeDevice.DeviceInformation.Pairing.IsPaired);
Console.WriteLine(device.Id);
foreach (var service in services)
{
if (service.Uuid.ToString() == HEG_Service_ID)
{
Console.WriteLine("Found Heg Service");
GattCharacteristicsResult charactiristicResult = await service.GetCharacteristicsAsync();
if (charactiristicResult.Status == GattCommunicationStatus.Success)
{
var characteristics = charactiristicResult.Characteristics;
foreach (var characteristic in characteristics)
{
Console.WriteLine("---------------");
GattCharacteristicProperties properties = characteristic.CharacteristicProperties;
Console.WriteLine("CharactesticHandle:"+characteristic.AttributeHandle +"\r\n"+"UUID"+characteristic.Uuid);
if (properties.HasFlag(GattCharacteristicProperties.Notify))
{
Console.WriteLine("Notify poroperty found");
GattCommunicationStatus status =
await characteristic.WriteClientCharacteristicConfigurationDescriptorAsync(
GattClientCharacteristicConfigurationDescriptorValue.Notify);
if (status == GattCommunicationStatus.Success)
{
characteristic.ValueChanged += Characteristic_ValueChanged;
// Server has been informed of clients interest.
}
}
}
}
}
}
}
Console.WriteLine("Press Any Key to Exit application");
Console.WriteLine("\r\n" + "Values" + "\r\n");
Console.ReadKey();
foreach (var service in services)
{
service.Dispose();
}
bluetoothLeDevice.Dispose();
bluetoothLeDevice = null;
device = null;
Console.WriteLine(mDiscoveredDevices);
Console.WriteLine(mDiscoveredDevices.Count());
break;
}
}
Console.ReadKey();
deviceWatcher.Stop();
deviceWatcher = null;
}
private static void TXCharacteristic_ValueChanged(GattCharacteristic sender, GattValueChangedEventArgs args)
{
byte[] buffer = args.CharacteristicValue.ToArray();
}
private static void Characteristic_ValueChanged(GattCharacteristic sender, GattValueChangedEventArgs args)
{
var reader = DataReader.FromBuffer(args.CharacteristicValue);
var flags = reader.ReadByte();
var value = reader.ReadByte();
Console.WriteLine($"{flags} - {value}");
}
private static void DeviceWatcher_Stopped(DeviceWatcher sender, object args)
{
}
private static void DeviceWatcher_EnumerationCompletedAsync(DeviceWatcher sender, object args)
{
}
private static void DeviceWatcher_Removed(DeviceWatcher sender, DeviceInformationUpdate args)
{
}
private static void DeviceWatcher_Updated(DeviceWatcher sender, DeviceInformationUpdate args)
{
//throw new NotImplementedException();
}
private static void DeviceWatcher_Added(DeviceWatcher sender, DeviceInformation args)
{
Console.WriteLine(args.Name);
if (args.Name == "HEG_100053" || args.Name =="Arduino")
{
Console.WriteLine("Found: " + args.Name);
device = args;
bool keyExists = mDiscoveredDevices.ContainsKey(device.Id);
if (!keyExists)
{
mDiscoveredDevices.Add(device.Id, device);
}
}
}
//900725
//|| args.Name == "HEG_100053"
}
}
I have a problem. I made a service which monitoring printing jobs in real time. It didn't worked perfect, but I had no big problem. Now I need to change service into Windows Forms program. And I've got a problem with threads.
Error:
System.InvalidOperationException: 'The calling thread cannot access this object because a different thread owns it.'
This error appears on string "PrintQueue.Refresh()".
I can't find where the other thread tries to run.
I tried to set the other thread and start it with MonitoringJobs() procedure but it doesn't work.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO;
using System.Collections.Concurrent;
using System.Data.SqlClient;
using System.Diagnostics;
using System.ServiceProcess;
using System.Management;
using System.Windows;
using System.Printing;
using System.Configuration;
using System.Collections.Specialized;
using System.Threading;
namespace MonitoringPrintJobs
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
timer.Elapsed += GetJobs;
timer.AutoReset = true;
timer.Enabled = true;
}
System.Timers.Timer timer = new System.Timers.Timer(5);
int writeInterval = 1000;
int DefaultWriteInterval = 1000;
bool Logging;
SelectPrinter fSelectPrinter = new SelectPrinter();
ConcurrentDictionary<string, string> QueueJobs = new ConcurrentDictionary<string, string>();//declaration printers jobs dictionary
ConcurrentDictionary<string, DateTime> PrintedJobs = new ConcurrentDictionary<string, DateTime>();
PrintServer printServer = null;
PrintQueueCollection QueuesOnLocalServer = null;
List<PrintQueue> queues = new List<PrintQueue>();
public void MonitoringJobs()
{
//if(queues != null)
foreach (var PrintQueue in queues)
{
PrintQueue.Refresh();
using (var jobs = PrintQueue.GetPrintJobInfoCollection())//wait until collection updates!!!
foreach (var job in jobs)
{
if (!QueueJobs.ContainsKey(job.Name))//if list with printer jobs doesn't contain found job (name)
{//then put name in list with printer jobs
QueueJobs.TryAdd(job.Name, job.JobStatus.ToString());
if (Logging == true)
{
File.AppendAllText(#"D:\Logs\Logging.txt", String.Format("{0} - {1} - {2}{3}", DateTime.Now, job.Name, job.JobStatus, Environment.NewLine));
}
}
else//if list with printer jobs contains found job name
{
if (QueueJobs[job.Name] != job.JobStatus.ToString() && !QueueJobs[job.Name].ToLower().Contains("error"))//if status for this job doesn't exist
{
QueueJobs[job.Name] = job.JobStatus.ToString();//replace job's status
if (Logging == true)
{
File.AppendAllText(#"D:\Logs\Logging.txt", String.Format("{0} - {1} - {2}{3}", DateTime.Now, job.Name, job.JobStatus, Environment.NewLine));
}
}
if (job.JobStatus.ToString().ToLower().Contains("error") && PrintedJobs.ContainsKey(job.Name))
{
var someVar = new DateTime();
PrintedJobs.TryRemove(job.Name, out someVar);
}
}
if (QueueJobs[job.Name].ToLower().Contains("print") && !QueueJobs[job.Name].ToLower().Contains("error"))//if successfully printed
{
PrintedJobs.TryAdd(job.Name, DateTime.Now);
}
}
}
}
private void GetJobs(Object source, System.EventArgs e)
{
writeInterval--;
MonitoringJobs();
if (writeInterval <= 0)
{
writeInterval = DefaultWriteInterval;
PrintedJobs.Clear();
QueueJobs.Clear();
}
}
protected void OnStart()
{
QueuesOnLocalServer = printServer.GetPrintQueues();
writeInterval = 120000;
foreach (var item in fSelectPrinter.SelectetPrinters)
Logging = true;
foreach (var printer in fSelectPrinter.SelectetPrinters)
{
if (string.IsNullOrEmpty(printer))
{
timer.Stop();
Environment.Exit(0);
}
var queue = QueuesOnLocalServer.FirstOrDefault(o => o.FullName.ToUpper() == printer.ToUpper());
if (queue == null)
{
timer.Stop();
Environment.Exit(0);
}
queues.Add(queue);
}
timer.Start();
}
private void button2_Click(object sender, EventArgs e)
{
fSelectPrinter.ShowDialog();
}
private void Form1_Load(object sender, EventArgs e)
{
printServer = new PrintServer();
foreach (PrintQueue pq in printServer.GetPrintQueues())
fSelectPrinter.listBox1.Items.Add(pq.Name);
}
private void button1_Click_1(object sender, EventArgs e)
{
bool StartPrinting = button2.Enabled = false;//turn of select printers form button
if (StartPrinting == false)//StartPrinting == monitoring == true
{
OnStart();
}
else
{
StartPrinting = true;//StartPrinting == monitoring == false
timer.Stop();
}
}
}
}
In this program I tried to get printing jobs statuses and output them in listbox1 and write results with string.Format in file.
On Form1_Load event you are adding things to your fSelectedPrinter.Listbox.
If you items you are adding are coming from a different thread, that will cause an error. Only UI thread can update objects on a form without using SynchornizationContext.
private readonly SynchronizationContext synchronizationContext;
InitializeComponent();
synchronizationContext = SynchronizationContext.Current;
Here is an example:
private async void btnListFiles1_Click(object sender, EventArgs e)
{
if (txtDirectory1.Text == "")
{
MessageBox.Show(InfoDialog.SELECT_DIRECTORY,PROGRAM_NAME);
return;
}
if (!Directory.Exists(txtDirectory1.Text))
{
MessageBox.Show(InfoDialog.DIRECTORY_NOT_EXIST, PROGRAM_NAME);
return;
}
try
{
string fileTypes = (txtFileTypes1.Text == "") ? "" : txtFileTypes1.Text;
string[] files = Directory.GetFiles(txtDirectory1.Text.TrimEnd(),
(fileTypes == "") ? "*.*" : fileTypes,
(chkSub1.Checked) ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly);
listBoxFiles.Items.Clear();
progressBar.Step = 1;
progressBar.Value = 1;
progressBar.Maximum = files.Length + 1;
listBoxFiles.BeginUpdate();
if (txtSearchPattern1.Text != "")
{
string searchPattern = txtSearchPattern1.Text.ToLower();
await System.Threading.Tasks.Task.Run(() =>
{
foreach (string file in files)
{
if (file.ToLower().Contains(searchPattern))
{
AddToListBox(file);
}
}
});
}
else
{
await System.Threading.Tasks.Task.Run(() =>
{
foreach(string file in files)
{
AddToListBox(file);
}
});
}
listBoxFiles.EndUpdate();
progressBar.Value = 0;
}
private void AddToListBox(string item)
{
synchronizationContext.Send(new SendOrPostCallback(o =>
{
listBoxFiles.Items.Add((string)o);
progressBar.Value++;
}), item);
}
I have a function called getMessages that can be called by a Button click (using the RelayCommand trigger) or that is called in a timer every 15s.
The desired behavior is:
webservice > deserialize answer > system notification > updatelistview > insert localDB
But when the function is called by the timer the updatelistview is not done. Why does this happen if the function is the same and works perfectly in the button command?
CODE:
// Get messages for the logged in user
public async void getMessages()
{
try
{
List<FriendGetMessage> msg = new List<FriendGetMessage>();
var response = await CommunicationWebServices.GetCHAT("users/" + au.idUser + "/get", au.token);
if (response.StatusCode == HttpStatusCode.OK) // If there are messages for me.
{
var aux = await response.Content.ReadAsStringAsync();
IEnumerable<FriendGetMessage> result = JsonConvert.DeserializeObject<IEnumerable<FriendGetMessage>>(aux);
if (result != null)
{
foreach (var m in result)
{
msg.Add(m);
}
//MsgList=msg;
foreach (var f in Friends)
{
if (f.msg == null || f.msg.Count() == 0)
{
f.msg = new ObservableCollection<Messages>();
}
foreach (var mess in msg)
{
if (mess.idUser == f.idUser)
{
Messages mm = new Messages();
mm.received = mess.message;
mm.timestamp = "Received " + mess.serverTimestamp;
mm.align = "Right";
// Add to the friend list.
f.msg.Add(mm);
// Add to Local DB
InsertMessage(null, au.idUser.ToString(), f.idUser, mess.message, mess.serverTimestamp);
var notification = new System.Windows.Forms.NotifyIcon()
{
Visible = true,
Icon = System.Drawing.SystemIcons.Information,
BalloonTipIcon = System.Windows.Forms.ToolTipIcon.Info,
BalloonTipTitle = "New Message from " + f.name,
BalloonTipText = "Message: " + mess.message,
};
// Display for 5 seconds.
notification.ShowBalloonTip(5);
// The notification should be disposed when you don't need it anymore,
// but doing so will immediately close the balloon if it's visible.
notification.Dispose();
}
}
}
counterChat = 1; // resets the counter
}
}
else {
counterChat = counterChat * 2;
}
//var sql = "select * from chat";
//var respo = GetFromDatabase(sql);
OnPropertyChanged("Friends");
}
catch (Exception e)
{
MessageBox.Show("GetMessages: " + e);
Debug.WriteLine("{0} Exception caught.", e);
}
}
CODE TIMER:
public void chatUpdate()
{
_timerChat = new DispatcherTimer(DispatcherPriority.Render);
_timerChat.Interval = TimeSpan.FromSeconds(15);
_timerChat.Tick += new EventHandler(timerchat_Tick);
_timerChat.Start();
}
public void timerchat_Tick(object sender, EventArgs e)
{
if (counterChat != incChat)
{
incChat++;
}
else
{
getMessages();
OnPropertyChanged("Friends");
incChat = 0;
}
}
ADDED - I've also tried this and didn't worked (it seems that is some kind of concurrency problem to the ObservableCollection called Friends (is a friendslist) each friend has an ObservableCollection of messages (is a chat))
public void chatUpdate()
{
_timerChat = new DispatcherTimer(DispatcherPriority.Render);
_timerChat.Interval = TimeSpan.FromSeconds(15);
_timerChat.Tick += new EventHandler(timerchat_Tick);
_timerChat.Start();
}
public async void timerchat_Tick(object sender, EventArgs e)
{
if (counterChat != incChat)
{
incChat++;
}
else
{
Application.Current.Dispatcher.Invoke((Action)async delegate { await getMessages(); });
incChat = 0;
}
}
Best regards,
I think you need to make the timer handler be an async method as follows:
public async void timerchat_Tick(object sender, EventArgs e)
{
if (counterChat != incChat)
{
incChat++;
}
else
{
await getMessages();
OnPropertyChanged("Friends");
incChat = 0;
}
}
This way OnPropertyChanged("Friends") is guaranteed to fire after the work in getMessages is done.
The methods need to change to:
DispatcherTimer _timerChat = new DispatcherTimer(DispatcherPriority.Render);
_timerChat.Interval = TimeSpan.FromSeconds(15);
_timerChat.Tick += new EventHandler(timerchat_Tick);
_timerChat.Start();
public async void timerchat_Tick(object sender, EventArgs e)
{
//...
await getMessages();
//...
}
public async Task getMessages()
{
try
{
// ... your code here
string result = await response.Content.ReadAsStringAsync();
// .... rest of your code
}
catch (Exception e)
{
MessageBox.Show("GetMessages: " + e);
}
}
It is solved. The problem was in my ViewModels I was opening multiple threads and sometimes the right one would update the UI and sometimes no.
Thanks for all the answers.
I'm currently working on a project with a FTDI chip.
I'm programming in C# and I tried one of the examples (the 3rd one with the data loopback) on the FTDI website.
The code is working, I'm able to write "Hello world" and read it back. In this case, we know how much data we're expecting to get back from the buffer :
// Perform loop back - make sure loop back connector is fitted to the device
// Write string data to the device
string dataToWrite = "Hello world!";
UInt32 numBytesWritten = 0;
// Note that the Write method is overloaded, so can write string or byte array data
ftStatus = myFtdiDevice.Write(dataToWrite, dataToWrite.Length, ref numBytesWritten);
if (ftStatus != FTDI.FT_STATUS.FT_OK)
{
// Wait for a key press
Console.WriteLine("Failed to write to device (error " + ftStatus.ToString() + ")");
Console.ReadKey();
return;
}
// Check the amount of data available to read
// In this case we know how much data we are expecting,
// so wait until we have all of the bytes we have sent.
UInt32 numBytesAvailable = 0;
do
{
ftStatus = myFtdiDevice.GetRxBytesAvailable(ref numBytesAvailable);
if (ftStatus != FTDI.FT_STATUS.FT_OK)
{
// Wait for a key press
Console.WriteLine("Failed to get number of bytes available to read (error " + ftStatus.ToString() + ")");
Console.ReadKey();
return;
}
Thread.Sleep(10);
} while (numBytesAvailable < dataToWrite.Length);
// Now that we have the amount of data we want available, read it
string readData;
UInt32 numBytesRead = 0;
// Note that the Read method is overloaded, so can read string or byte array data
ftStatus = myFtdiDevice.Read(out readData, numBytesAvailable, ref numBytesRead);
if (ftStatus != FTDI.FT_STATUS.FT_OK)
{
// Wait for a key press
Console.WriteLine("Failed to read data (error " + ftStatus.ToString() + ")");
Console.ReadKey();
return;
}
Console.WriteLine(readData);
But what if I want to read all the data and I don't how much data I can expect to get back from the buffer ?
Thanks
Use event driven methodology;
using System;
using System.Timers;
namespace Example
{
public class Program
{
private Timer m_timer;
private event EventHandler<EventArgs<string>> ReadingAvailable;
protected virtual void OnReadingAvailable(string value)
{
EventHandler<EventArgs<string>> handler = ReadingAvailable;
if (handler != null)
{
handler(this, new EventArgs<string>(value));
}
}
public static void Main(string[] args)
{
var foo = new Program();
foo.Initialise();
Console.ReadLine();
}
private void Initialise()
{
ReadingAvailable += Program_ReadingAvailable;
m_timer = new Timer {Interval = 1000};
m_timer.Elapsed +=timer_Elapsed;
m_timer.Enabled = true;
m_timer.Start();
}
private void timer_Elapsed(object sender, ElapsedEventArgs e)
{
string readData;
UInt32 numBytesRead = 0;
// Note that the Read method is overloaded, so can read string or byte array data
ftStatus = myFtdiDevice.Read(out readData, numBytesAvailable, ref numBytesRead);
// add the condition checking here to validate that the readData in not empty.
OnReadingAvailable(readData);
}
private void Program_ReadingAvailable(object sender, EventArgs<string> e)
{
string readData= e.Value;
Console.WriteLine(readData);
}
}
///
/// Helper class to parse argument in the EventArg
public class EventArgs<T> : EventArgs
{
private readonly T m_value;
protected EventArgs()
: base()
{
m_value = default(T);
}
public EventArgs(T value)
{
m_value = value;
}
public T Value
{
get { return m_value; }
}
}
}
Another option to use event-driven methodology is to use the actual event notification mechanism from the FTDI library, which is particularly well-suited for streaming:
Task.Run(() => ReceiveLoop());
void ReceiveLoop()
{
var receivedDataEvent = new AutoResetEvent(false);
myFtdiDevice.SetEventNotification(FT_EVENTS.FT_EVENT_RXCHAR, receivedDataEvent);
var cancellation = new CancellationTokenSource(); // should be declared in a broader scope
while (!_cancellation.IsCancellationRequested)
{
receivedDataEvent.WaitOne();
ReadAvailable();
}
}
void ReadAvailable()
{
uint rxBytesAvailable = 0;
myFtdiDevice.GetRxBytesAvailable(ref rxBytesAvailable);
if (rxBytesAvailable < 1)
return;
byte[] bytes = new byte[rxBytesAvailable];
uint numBytesRead = 0;
myFtdiDevice.Read(bytes, rxBytesAvailable, ref numBytesRead);
if (rxBytesAvailable != numBytesRead)
logger.Warn("something happened")
DoSomething(bytes);
}