Hold/Push Button with Raspberry Pi GPIO - c#

I would like my button to do 2 of the following things;
Do something whenever a button is pushed
Do something whenever a button is held for a certain amount of time (2seconds)
The current code that I'm working with looks a little like this:
//Comfirming a letter or sending the word.
private void btnRightValueChanged(GpioPin sender, GpioPinValueChangedEventArgs e)
{
//if button is pressed it will confirm a letter
if (e.Edge == GpioPinEdge.FallingEdge)
{
//code to confirm letter
ConfirmLetter();
//if(buttonHeldForAWhile)
//{
//Send message
//SendWord();
//}
}
}
But how can I check whether the button is held for 2 or 3 seconds?

I found a way to fix my problem by using a Stopwatch that measures the time that the button is being pressed.
Above our namespace we need to add this in order for us to use the Stopwatch class.
using System.Diagnostics;
Now we want to declare a Stopwatch by:
Stopwatch stopWatch;
When the button is pressed and held my code will pick that up with the FallingEdge. When it is pressed I also want it to create a new Stopwatch and start it.
When the button is released, which is checked by RisingEdge. I stop the timer and get the time between the 2 events. I then compare the time pressed in an if statement so I can decide what to do with the buttonpress. In this case SendWord, or Append current char and preview it.
//Comfirming the chosen letter.
private void btnRightValueChanged(GpioPin sender, GpioPinValueChangedEventArgs e)
{
if (e.Edge == GpioPinEdge.FallingEdge)
{
stopWatch = new Stopwatch();
stopWatch.Start();
}
if (e.Edge == GpioPinEdge.RisingEdge)
{
stopWatch.Stop();
long duration = stopWatch.ElapsedMilliseconds;
if (duration > 2000 )
{
SendWord();
}
else
{
//Add the current character to the word
_currentWordSB.Append(Convert.ToString(_currentChar));
// //Reset currentChar aswell
_currentChar = ' ';
// //The user confirmed the morse sequence and wants to start a new one, so we reset it.
_morseCode.Clear();
// //Preview the word
PreviewLetter();
}
}
}
If there is any better way to tackle my problem, please let me know but so far this solution works for me.
I needed this as I was working on a Raspberry Pi project with Morse code input via buttons. That input then had to be displayed on a LCD screen. If the user was satisfied with his input he could then send it to the other user(s) by holding the Right button for 2 seconds.

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.

PictureBox doesn't appear

I have an if statement, inside that if statement is a foreach, for accessing each string from a string[].
The strings are some parameters for an NPC which are read from a file. The first one represents the NPC type which are two : "battle" and "teach", the last string[] for a "teach" NPC is "end", and the rest of parameters represents photo names, which I want to load in a "dialog" PictureBox.
My test file looks like this:
teach
poza1
poza2
end
So I have 2 photos to load in the dialog PictureBox. The idea is that I must pause for 5 seconds that foreach statement, otherwise the dialog PictureBox pictures will be loaded too fast, and I won't see them.
So I tried to do that, and here is how the code looks:
if (date[0].Equals("teach")) //the first line of the date[] string, date represent the text from the file
{
foreach (string parametru in date) // i think that you know what this does
{
if (parametru != "teach" && parametru != "end") // checking if the parameter isn't the first or the last line of the file
{
dialog.ImageLocation = folder + "/npc/" + score_npc + "/" + parametru + ".png"; //loading the photo
System.Threading.Thread.Sleep(5000);
}
}
//other instructions , irelevants in my opinion
}
In my attempt of debugging this, I realised that if I use a MessageBox, the function will load the both photos. Also I'm sure of the fact that the parameters will pass the if statement.
It seems so easy to fix this error, but I can't figure out how to do it.
What you're doing now just freezes the UI. Use a System.Windows.Forms.Timer instead. Drop a Timer from the toolbox onto your Form.
Then create some fields that the Timer can access, to store your pics and the current pic position:
private List<string> pics = new List<string>();
private int currentPic = 0;
Finally, load it up with the pics you want to display, and start the Timer to go through them:
pics.Clear();
pics.AddRange(date.Where(x => x != "teach" && x != "end"));
timer1.Interval = 5000;
timer1.Start();
Then you'll have to tell your Timer to display the next picture. Increase the counter, and reset it when necessary. Something like this should work. Modify as necessary.
private void timer1_Tick(object sender, EventArgs e)
{
dialog.ImageLocation = string.Format("{0}/npc/{1}/{2}.png", folder, score_npc, pics[currentPic]);
currentPic++;
if (currentPic >= pics.Count)
currentPic = 0;
// Alternatively, stop the Timer when you get to the end, if you want
// if (currentPic >= pics.Count)
// timer1.Stop();
}
You probably need to issue a PictureBox.Refresh and/or a DoEvents command for the picture box to actually get a chance to load and display the picture.
The MessageBox automatically performs a DoEvents ... which is why it is working during debugging.

How can I play a sound with defined start- and end-time in .Net

In my C# project I want to play a sound with a specified start- and end time.
I used the System.Media.SoundPlayer with the .Play() function. But with this function I can only play the whole sound file or can abort it after I have counted the runtime.
In fact I want to say, that the given sound file should start for example at time 1m:25s:30ms and should end at time 1m:50s:00ms or after a duration of 10s or so.
Does anybody know a simple solution for his problem?
Thanks 4 help.
Not really an answer, but this question got me wondering if you can do something like this:
long startPositionInBytes = 512;
long endPositionInBytes = 2048;
using ( var audioStream = File.OpenRead(#"audio.wav") )
{
audioStream.Position = startPositionInBytes;
using ( var player = new SoundPlayer(audioStream) )
{
player.Play();
do
{
Thread.Sleep(1);
} while ( audioStream.Position <= endPositionInBytes );
player.Stop();
}
}
In case you want to play a Background Media Player (for e.g., an audio file) which would start from a specific time and would work for a certain duration, then this code snippet could also be useful:
StorageFile mediaFile = await KnownFolders.VideosLibrary.GetFileAsync(fileName);//the path
BackgroundMediaPlayer.Current.SetFileSource(mediaFile);
BackgroundMediaPlayer.Current.Position = TimeSpan.FromMilliseconds(3000/*enter the start time here*/);
BackgroundMediaPlayer.Current.Play();
await Task.Delay(TimeSpan.FromMilliseconds(10000/*for how long you want to play*/));
BackgroundMediaPlayer.Shutdown();//stops the player
**But this would only work for Windows 8.1 and above.
For more information, click here...
In the End I use the NAudio library. That can handle this - not in a perfect way but ok.
see https://stackoverflow.com/a/13372540/2936206
I got it to work by using Windows Media Player in a C sharp program with a timer control and an open dialog.
I followed a sample that used buttons on the form and made the media player invisible.
After opening the file with an Open button that used the open dialog to open the mp3 file, on the Play button I put this code [the end effect is that it started the file in position 28.00 and ended it in position 32.50]:
private void button2_Click(object sender, EventArgs e)
{
axWindowsMediaPlayer1.URL = openFileDialog1.FileName;
timer1.Start();
axWindowsMediaPlayer1.Ctlcontrols.currentPosition = 28.00;
axWindowsMediaPlayer1.Ctlcontrols.play();
}
Then in the timer tick event:
private void timer1_Tick(object sender, EventArgs e)
{
if (axWindowsMediaPlayer1.Ctlcontrols.currentPosition >= 32.50)
{ axWindowsMediaPlayer1.Ctlcontrols.pause(); }
label1.Text = String.Format("{0:0.00}",
axWindowsMediaPlayer1.Ctlcontrols.currentPosition);
}

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.

Dynamic Search Result C#

i'm try to develope a list of result by a dynamic search in a text box.
Now i update the record when:
SearchBox.TextChanged += new EventHandler(SearchBox_TextChanged);`
But i have to wait every char that i write for the complete result of the list.
so if i search for example "com" the result is not words that contains "com" but only "c".
For have the result of "com" i need to write:
"c" -> Wait to complete search
"o" -> Wait to complete search
"m" -> Wait to complete search
How can i do for wait some time that the user write the word and then search?
Thanks.
You are not aware what user want to insert in text box, so may be is Cat, Contact, Com, Computer,... So you should restrict the search list by each keyword from user, also you can set a policy for example just search when the input length is at least 3.
Edit: The other way is to use Lazy pattern, means keep the last time of text changed, then in another thread (like timer) check if there is more than 2 second between last user change to current time, update your search: (timer interval is 2 second).
private DateTime lastChange = DateTime.Now;
private bool textChanged = false;
object lockObject = new object();
private void textChanged(object sender, EventArg e)
{
lock(lockObject)
{
lastChange = DateTime.Now;
textChanged = true;
}
}
private void timer1_Tick(object sender, EventArgs ะต)
{
lock(lockObject)
{
if (textChanged && lastChange > DateTime.Now.AddSeconds(-2)) // wait 2 second for changes
{
UpdateList(); // or the method for searching.
textChanged = false;
lastChange = DateTime.Now;
}
}
}
the easiest way is to add into the event handler a condition like a minimum length
private void SearchBox_TextChanged(Event e,...){
if(e.text.Length > 3)
search(e.text);
}
Use a Timer. On every TextChanged event,
start that timer if not running,
restart (stop & start) if already running,
On Timer's Tick event, write your code to update Search Results and stop timer.
This will give your users some time to write complete search key-words.
Usually Timer Interval can be around 1 Second.
You can create a Timer when your application starts, and then on every keystroke simply reset and re-start the timer.
When the user stops typing, the timer will execute and perform the search.
You can use timer with an Interval of some like 2 seconds and implement search within timer's Tick event. Enable timer within TextChanged event and once search completed then disable timer within Tick event.

Categories