Serial Communication in C# using arduino, android, winform - c#

I have a program that is similar to an ATM application. I use my android device a the Keypad. No problem with transmitting data from phone to my C# program. I use threading. I have a problem on how to really "start" the ATM application.
The only input device is the android device. I will not use computer keyboard or anything. So once the program is shown, the first thing is that the program will ask what kind of transaction is it.
private void FrontPage_Shown(object sender, EventArgs e)
{
Ask_Transaction();
}
and inside that... (Edited part)
public void Ask_Transaction()
{
string decoded_input = "";
decoded_input = KT.CheckPress(input); //"input" is the data from the arduino. the checkpress will decode it.
do
{
try
{
//input = serialPort.ReadLine();
switch (KT.CheckPress(input))
{
case "S5": //Card;
break;
case "S6": //Cardless
{
PF.Format_Cardless();
AskLanguage(); //if cardless, it will now ask the language. Once again, another input from serial is needed
}
break;
case "Cancel": PF.Format_TransactionCancelled();
break;
default:
break;
}
}
catch
{
//To catch ReadTimeout after 6 seconds
//"You do not respond to the alloted time.."
}
}
while (decoded_input != "S5"
|| decoded_input != "S6"
|| decoded_input != "Cancel");
}
my problem is that when I try to loop Ask_Transaction until I get the correct inputs (S5 or S6 or cancel) using a do-while loop, my program is lagging and eventually crashing. No errors displaying.
EDIT:
Of course we cannot assure that the user will input the correct key. And usually when you click just numbers on the keypad, ATM program will not notify you at first. It will just wait for possible correct inputs. Also, if the user enters S6, the program will now ask another input using those keypad numbers s5 and s6. the problem is that the program is not "continuous". Any kind of help will be appreciated.

Related

Execute specific blocks of code based on which key on the keyboard is pressed

I am very new to the programming world and recently dove into c#. I don't want to waste your time so I'll get right to it. I wanted to create a program just to test my knowledge, and thought I could attempt to execute specific blocks of code based on which key on the keyboard is pressed by the user. I tried doing this by creating an event handler that contained if statements, but then realized I didn't know how to have the event handler active in the program.
For example, and as you can see in the below snippet, after the WriteLine in Line 5 lets say I wanted to raise the EventKeyPress event so that it waits for user input and reads the key they have pressed and reacts accordingly, how would I do that?
Again, I'm almost a complete beginner and have searched around for explanations about event handlers for hours and still can't wrap my head around what I am supposed to do or if I am even using the event handler correctly. Thanks in advance!
static void Main();
{
if (search == "Ball")
{
Console.WriteLine("Press enter to exit or backspace to return to the search bar")
// RIGHT HERE
}
else
{
Console.WriteLine("Sorry, I don't recognize {0}", search);
}
void EventKeyPress(object sender, KeyPressEventArgs e)
{
for (int i = 0; i < 1;)
{
if (e.KeyChar == (char)Keys.Enter)
{
// exit app
}
else if (e.KeyChar == (char)Keys.Back)
{
// go back to search
}
else
{
i = 0; // error
}
}
}
}
So, you're asking for something that involves Threading which is not a beginner thing to accomplish at all. The best way to do this for a beginner is to ask for a prompt, then accept as an input. For example.
Console.WriteLine("Hello, what's your name?");
string nameStr = Console.ReadLine();
Console.WriteLine($"Hello, {nameStr}");
You can then use your variable and apply it to an if/while or whatever kind of conditional.
if (nameStr == "Matt"){
//Do This Code.
}
Once you have that code, add a sequential method that will ask the user to return to the main menu or whatever you want it to do.
Main.ReturnMenu(); //Or whatever you want to use.

Strange behaviour when communicating over serial from VS WPF to Arduino

A basic overview. I am sending serial data from an Arduino Due to WPF application. Up until now this has all been working perfectly. Today I implemented a loop into the Arduino code that looks for a "Y" (ascii 89) in the serial port, if received it leaves the loop and returns back into what I am calling offline mode and stops sending over data, via online = false.
Now what is strange about this is that...
It was working fine before this loop so it must be something to do with trying to resend new data once it has left the 'online loop'.
It works perfectly from the Arduino serial monitor, which suggests it's a WPF problem, although the code hasn't changed on the upload section.
The code for both of these programmes is pretty big so I will try and keep it concise whilst providing all the information necessary.
void loop() {
// Check to see if the testbench is in offline mode and run the respective code.
if (Online == false) {
OfflineMode();
}
// Check to see if the testbench is in online mode and run the respective code.
if (Online == true) {
OnlineMode();
}
}
void OfflineMode() {
while (Serial.available())
processlncomingByte(Serial.read());
}
I then have switch cases to handle incoming settings - I know this works fine as it will also upload after the Arduino is reset.
void processlncomingByte (const byte c) {
if (isdigit (c)) {
currentValue *= 10;
currentValue += c - '0';
} else {
// end of digit
// The end of the number signals a state change
handlePreviousState ();
// set the new state, if we recognize it
switch (c) {
case 'A':
state = GOT_A;
break;
etc...
Online Mode
void OnlineMode() {
CheckForStop();
SendSerialData();
}
void CheckForStop() {
//Serial.println("...");
if (Serial.available() > 0) {
//Serial.println("getting something");
ch = (char)Serial.read();
inputString = ch;
if (ch == 89) {
//Serial.end();
Online = false;
//Serial.begin(9600);
exit;
//return;
}
} else
delay(5);
}
SendSerialData() consists of just a range of serial.print, outputting into one large string for WPF to handle.
Here is a screenshot of the serial monitor working
As you will see from the link above the monitor spits out a load of data, stops when I send a Y and finally I send a Q to 'question' whether the Arduino is ready to receive settings and S signifies a Yes. Great stuff it works!
However as you can see from the link below this isn't the case in WPF. Sorry, I can only upload 2 images at the moment so had to combine them.
Combo of screenshots
Here is the loop it is currently getting stuck in
private bool checkArduinoisReady() {
Stopwatch Uploadtimer = new Stopwatch();
if (!myPort.IsOpen)
return false;
// Debug.Print("port is ready to be opened");
string tempdata;
Uploadtimer.Start();
myPort.DiscardInBuffer();
Start:
myPort.WriteLine("Q" + Environment.NewLine);
Debug.Print("sent Q");
tempdata = myPort.ReadExisting();
Debug.Print("tempdata_" + tempdata.ToString());
if (Uploadtimer.ElapsedMilliseconds > 5000)
return false;
if (tempdata.Contains("S"))
return true;
else
goto Start;
}
And on a separate page this is how I am stopping the incoming data.
private void StopTest(object sender, RoutedEventArgs e) {
MessageBoxResult StopConfirm = MessageBox.Show("Are you sure you want to stop the test?", "Stop the test", MessageBoxButton.YesNo, MessageBoxImage.Question);
if (StopConfirm == MessageBoxResult.Yes) {
Timer.Stop();
Debug.Print("Timer Stopped");
myPort.DiscardInBuffer();
Start:
for (int i = 0; i < 100; i++) {
myPort.WriteLine("Y");
}
string tempData = myPort.ReadExisting();
Debug.Print("Checking...");
Debug.Print("tempData_" + tempData);
if (string.IsNullOrWhiteSpace(tempData)) {
Debug.Print("Its null!!");
comments_textbox.Text = comments_textbox.Text + "Test Aborted";
MessageBoxResult SaveCurrentData = MessageBox.Show("Would you like to save the data collected up until this point?", "Save", MessageBoxButton.YesNo, MessageBoxImage.Question);
if (SaveCurrentData == MessageBoxResult.Yes) {
SaveFile();
}
if (SaveCurrentData == MessageBoxResult.No) {
myPort.Close();
NavigationService.Navigate(new Uri("testSettings.xaml", UriKind.RelativeOrAbsolute));
}
} else {
Debug.Print("Still going...");
goto Start;
}
}
}
The biggest stumbling block for me is why this works over the serial monitor but not within the application. And it also works as soon as I reset the Arduino. I have also tried the resetFunc() in Arduino but this didn't help either.
Thanks in advance.
It turns out i still had a resetFunc() in my switch case which was preventing the serial monitor from continuing to send data!

Bluetooth Pairing (SSP) on Windows 10 with 32feet.NET

I've just started a project that will require me to pair a Windows 10 tablet with another bluetooth device.
I decided to start with a simple windows forms app to familiarise myself with the process. I added the 32feet.NET NuGet package to my solution, and quickly had success with searching for devices and populating a listbox.
client = new BluetoothClient();
devices = client.DiscoverDevices();
if (devices.Length > 0)
{
foreach (var device in devices)
{
lstBTDevices.Items.Add(device.DeviceName);
}
}
else
{
MessageBox.Show("Unable to detect any bluetooth devices");
}
I then added an event handler so I could select a detected device and attempt to pair with it.
private void LstBTDevices_SelectedIndexChanged(object sender, EventArgs e)
{
BluetoothDeviceInfo selectedDevice = devices[lstBTDevices.SelectedIndex];
if (MessageBox.Show(String.Format("Would you like to attempt to pair with {0}?", selectedDevice.DeviceName), "Pair Device", MessageBoxButtons.YesNo) == DialogResult.Yes)
{
if (BluetoothSecurity.PairRequest(selectedDevice.DeviceAddress, "123456"))
{
MessageBox.Show("We paired!");
}
else
{
MessageBox.Show("Failed to pair!");
}
}
}
On my Windows7 desktop PC with cheap Bluetooth 2.0 adaptor this causes a popup to appear on my phone requesting I enter the pincode. When I enter "123456" the pairing is successful.
However, this is where the problem starts. I then take my application and run it on my Windows10 tablet, and now when I select my phone it causes a popup to appear on my phone with a random 6 digit pincode, and a message that it should match what is displayed on my tablet screen, with pair/cancel buttons as the options. Pressing either button results in a fail.
Is this something i'm doing wrong? A driver not supported by 32feet.NET?
Any advice would be much appreciated.
UPDATE: The comment from bare_metal has helped me get a bit further
I added a BluetoothWin32Authentication event handler and added a button to initiate an SSP pairing:
EventHandler<BluetoothWin32AuthenticationEventArgs> authHandler = new EventHandler<BluetoothWin32AuthenticationEventArgs>(handleAuthRequests);
BluetoothWin32Authentication authenticator = new BluetoothWin32Authentication(authHandler);
private void btnPairSSP_Click(object sender, EventArgs e)
{
BluetoothDeviceInfo selectedDevice = devices[lstBTDevices.SelectedIndex];
if (MessageBox.Show(String.Format("Would you like to attempt to pair with {0}?", selectedDevice.DeviceName), "Pair Device", MessageBoxButtons.YesNo) == DialogResult.Yes)
{
Task t = new Task(PairBluetoothTask);
t.Start();
}
}
private void PairBluetoothTask()
{
BluetoothDeviceInfo selectedDevice = devices[lstBTDevices.SelectedIndex];
if (BluetoothSecurity.PairRequest(selectedDevice.DeviceAddress, null))
{
MessageBox.Show("We paired!");
}
else
{
MessageBox.Show("Failed to pair!");
}
}
private void handleAuthRequests(object sender, BluetoothWin32AuthenticationEventArgs e)
{
switch (e.AuthenticationMethod)
{
case BluetoothAuthenticationMethod.Legacy:
MessageBox.Show("Legacy Authentication");
break;
case BluetoothAuthenticationMethod.OutOfBand:
MessageBox.Show("Out of Band Authentication");
break;
case BluetoothAuthenticationMethod.NumericComparison:
if(e.JustWorksNumericComparison == true)
{
MessageBox.Show("Just Works Numeric Comparison");
}
else
{
MessageBox.Show("Show User Numeric Comparison");
if (MessageBox.Show(e.NumberOrPasskeyAsString, "Pair Device", MessageBoxButtons.YesNo) == DialogResult.Yes)
{
e.Confirm = true;
}
else
{
e.Confirm = false;
}
}
break;
case BluetoothAuthenticationMethod.PasskeyNotification:
MessageBox.Show("Passkey Notification");
break;
case BluetoothAuthenticationMethod.Passkey:
MessageBox.Show("Passkey");
break;
default:
MessageBox.Show("Event handled in some unknown way");
break;
}
}
When I initiate pairing from my phone, this works fine, the event is triggered, the message box pops and pairing is successful.
However when I initiate pairing from the tablet, the event handler is never triggered, so pairing fails.
I believe the problem here is that the 32feet library is built around legacy pairing, so that you either need to know the pin of the device you are connecting to, or you supply it with a null to get a popup window to enter a pin. That dialog may not have made it through to the new version of windows -
Not sure on this, but the documentation for the native function that the 32feet library wraps, says to call another method if developing for newer than Vista.
https://msdn.microsoft.com/en-us/library/windows/desktop/aa362770(v=vs.85).aspx
From my research browsing through the decompiled sources of 32feet, it may look like 32feet doesn't support SSP, just others - but that may only be that the supplied bluetooth stack implementations need updating - or you need to create your own - again I am not sure.
You may want to look into Microsoft supplied libraries for .NET instead of this 3rd party, I was able to use their example from Github to successfully connect and pair with all my devices.
https://msdn.microsoft.com/en-us/library/windows/apps/mt168401.aspx
https://github.com/Microsoft/Windows-universal-samples/tree/master/Samples/DeviceEnumerationAndPairing/cs

C# - How to read from a SerialPort for an infinite amount of time

I have an arduino connected to my serialport, which generates numbers from 0 to 64 all the time.
I wanted to read these signals in c# and managed to attach them to a richtextbox.
Unfortunately at some point they stop being written in the box and i have to open the port again to append the text again to the box.
Here is a sample of the code:
private void btnOpenPort_Click(object sender, EventArgs e)
{
if (Arduino.IsOpen == false)
{
Arduino.BaudRate = 115200;
Arduino.PortName = cBPortWaehlen.SelectedItem.ToString();
Arduino.Open();
}
while (Arduino.BytesToRead != 0)
{
richTextBox1.AppendText(Arduino.ReadExisting());
}
}
I assumed the statement Arduino.BytesToRead would never turn false, as long as my arduino sends signals, but this seems not to be the case. How can I achieve that instead?
First of all, about any serial connection made in C# has a default event handler, called DataReceived. I believe that you can use it, and delete the while code block you have there.
Second, I think that the while block is too operation-intensive, so if you don't go with my first suggestion, try and place a Thread.Sleep(1000) inside your while, so it won't execute that many times. If you want to refresh the data every few milliseconds, replace Thread.Sleep(1000) by giving the amount of milliseconds that your prefer.
Hope this answered your question.
Later Edit:
The code you can have looks like this:
public void OpenArduinoConnection()
{
if(!arduinoBoard.IsOpen)
{
arduinoBoard.DataReceived += arduinoBoard_DataReceived;
arduinoBoard.PortName = "yourportname";
arduinoBoard.Open();
}
else
{
throw new InvalidOperationException("The Serial Port is already open!");
}
}
void arduinoBoard_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
// your code here
}

Chip8 Emulator - User Input

I have been writing a chip8 Emulator -- http://en.wikipedia.org/wiki/CHIP-8
I have tested all of the opcodes as well as the graphics calculations and I am now struggling with the user input. I have the following method monitoring user input and altering the registers as needed (When using the chip8 the user input alters the corresponding memory register - E.G. hitting '0' sets the V0 register to 0.
My problem is that I have the following code fetching and calculating each opcode and its operation contained in a while loop. And while this is running my application cannot detect user input. So the ROMS start and just stay locked in place waiting on a register change or user input. It keeps getting stuck in an infinite loop, I tried to implement a global Boolean RUN, and it is not detected after the while loop is initiated. I'm assuming it is out of the scope of the loop, but from what I have read, the keyboard event triggers an interrupt that should be visible from almost anywhere, any Thoughts?
This is what calculates and parses the opcode
private void button1_Click(object sender, EventArgs e)
{
// This will become the run function
do{
for (int i = 0; i < 2; i++)
{
opc[i] = mem[mc]; // fetching the instruction from the memory array
mc++;
}
cibox.Clear(); // Just clearing Debugging text boxes in the UI
pcbox.Clear();
pc++;
pcbox.Text += pc;
cibox.Text += opc[0].ToString("X2") + "-" + opc[1].ToString("X2");
calculations(opc); // Parses the Opcode and does the corresponding operation
}while(run);
}
And this method is controlling the user input...
protected override void OnKeyDown(KeyEventArgs keyEvent) // Listens for Keyboard events! Read More: http://www.geekpedia.com/tutorial53_Getting-input-from-keyboard.html
{
keyPress = true;
//Gets the key code found at keyEvent...
MessageBox.Show("KeyCode: " + keyEvent.KeyCode.ToString());
String register = keyEvent.KeyCode.ToString();
if (register == "Escape")
{
Application.Exit();
run = false;
}
try
{
registerVal = int.Parse(register, System.Globalization.NumberStyles.HexNumber); // Second Nibble! --> Int Format
}
catch (System.ArgumentNullException e)
{
return;
}
catch (System.ArgumentException)
{
return;
}
catch (System.FormatException)
{
return;
}
catch (System.OverflowException)
{
return;
}
if (registerVal >= 208)
{
registerVal = registerVal - 208;
}
if (registerVal <= 15)
{
mem[registerVal] = (byte)registerVal;
}
display(); // Alters UI to display state of registers, etc
}
So I have now tried the Game Loop Idea, but I cannot find a way to make a method in C# that will return a key press. Maybe I am missing something here, but I cannot seem to figure it out!
I also tried another method involving running the CPU calculations in a separate thread, and this is causing a slight delay issue.
I would really like to see an example of a method in C# that returns the value of a key being pressed that I can call within the While loop!
I suggest you set up your emulator's loop like a game loop. You have one global loop which triggers updates to each module in your emulator. In the loop, you call your input (or generic "event") processor, then your opcode/hardware emulation, then your screen update.
Here's some pseudo-code.
while (True):
processInput()
updateCPU()
outputGraphics()
I don't know how the key input works in C#, if it's an asynchronous event trigger (i.e. the "OnKeyDown" method gets called outside of your loop), you can set up "OnKeyDown" to just send the key events to an intermediate event manager, then in "processInput()" you actually resolve the events and use them to update registers on the emulated CPU etc.

Categories