Thanks. I do know the proper way to solve this problem already though. My undergraduate degree is electrical engineering and I my graduate work is in a field called Digital Signal Processing. I did not implement a more complicated streaming solution because I don't want to load the iPhone down, this is just to control a program that does something else - and currently I only need to enter two sequential characters for all control options, although I have decoded sentences with my current Morse Code decoder.
If I were to implement a full streaming solution, I'd create a separate processing thread to decode the Morse code (or up and down button events with times). The UI would write the up and down events to a thread-safe queue, and the decoder thread would read from that queue. The decode would write characters to a thread-safe output queue, which would be read by the UI thread.
This would allow decoding while doing other processing. Perhaps I'll implement that someday.
Currently there is no point in doing a dynamic adaptation to sending speed variations when I am only decoding very short blocks - currently only two characters.
I did find that podcast interesting and entertaining though. Also, I had purchased the "Natural Language" Python book he mentioned over a year ago. It's a great book. The best part of that book is that it provides sources to various online resources, including a word corpus.
Bjucha, I am presenting a sheet.
The code is:
if __name__ == "__main__": v = FSButtonView() v.present('sheet', title_bar_color='#334444', hide_close_button=True, orientation=['portrait'])
The FSButtonView class derives from the ui.View class.
In the code, I add an ImageView instance as a subview of the main view to show an image that covers all the screen except the title bar. I want the title bar so the cell signal strength, the time, etc. are visible at the top of my iPhone screen. I also want the background of the title bar to match the background of the image. The image background is approximately the color '#334444'.
By tapping the screen (using Morse code) I can control various functions, including removing the subview (image) from the view, and later adding it back. When it's removed, the screen becomes black (minimum battery power), and I want the title bar to become black too. When I add the image back, I want the title bar to return to the image background color, not to the view background color).
The problem now is that the title bar is always the image background color. It do not know how to change the title bar to be black, and then how to change it back to the image color if the image (sub-view) is added back to the view.
If I hide the title bar by using a key argument (I think it was "hide_title_bar") in the "present" methods, then the image covers the entire screen, and then the cell signal strength, time, etc.., are not visible. I want those to remain visible.
I'm not sure what would happen if I hid the title bar when the image was removed, and showed the title bar when the image was put back. I also don't know how to hide/show the title bar dynamically, or if that's even possible.
If not running the Pythonista 3 beta, you can get periodic updates with the code below.
This is not my idea, I just simplified an idea in the TimedRefreshView.py example program, written by cclauss, that I found at:
My program, named "say_random_digit.py", says a random digit from 0 to 9 every 5 seconds.
I had to change the data member "self.update_interval" to "self.updatex_interval" and the method "update" to "updatex" so as not to conflict with the names in the Pythonista 3 beta, which I am currently running.
I like having this functionality built into the ui.View class much more than having to implement it, so I look forward to the beta becoming the released product.
import ui import threading import speech from random import randint class TimedUpdateView(ui.View): """ This class contains a method named updatex, which is periodically called. """ def __init__(self): self.updatex_interval = 5 self.update_after_delay() def updatex(self): """ Say a random digit from 0 to 9 every 5 seconds. """ speech.say('%s' % (randint(0, 9))) def update_after_delay(self): """ This method calls the updatex method periodically """ self.updatex() update_thread = threading.Timer(self.updatex_interval, self.update_after_delay).run() if __name__ == "__main__": v = TimedUpdateView() v.present('sheet')
If not running the Pythonista 3 beta, someone can also have an update method be periodically called as shown below.
This is not my idea, I just simplified an idea in the TimedRefreshView.py example program that I found at:
This program below, named say_random_digit.py, says a random digit from 0 to 9 every 5 seconds.
I had to change the data member "self.update_interval" to "self.updatex_interval" and the method "update" to "updatex" so as not to conflict with the names in the Pythonista 3 beta, which I am running.
I like having this functionality built into the class much more than having to implement it, so I look forward to the beta becoming the released product.
import ui import threading import speech from random import randint class TimedUpdateView(ui.View): def __init__(self): self.updatex_interval = 5 self.update_after_delay() def updatex(self): """ Say a random digit from 0 to 9 every 5 seconds. """ speech.say('%s' % (randint(0, 9))) def update_after_delay(self): """ This just method calls the updatex method periodically """ self.updatex() update_thread = threading.Timer(self.updatex_interval, self.update_after_delay).run() if __name__ == "__main__": v = TimedUpdateView() v.present('sheet')
I considered two buttons early on, however, that's not necessary. The issue isn't separating dots from dashes. That part works very well - in fact, I don't recall the decoder making an error between a dot and a dash in a very long time.
The code even handles when there are only dots, or only dashes now, such as:
. . . .
which is "se" and:
- - - -
which is "oe"
The issue is the spaces between symbols, letters, and words. Theses are all multiples of the dot-length. If sending a lot of text, and the sending speed changes over time, then the symbol-space, the letter-space, and the word-space, can become ambiguous across the entire message. (Usually, the symbol space is fine, but the letter space and word space can drift close together).
There really needs to be a mix of short-term and long-term tracking of space lengths, so if the sending speed drifts, the code adapts in real time.
The downside of the poor space tracking that sentences can end up as:
"T h e dow nsi deof thep o o r sp ace t ra ckin g th at s en t en ces ca n endup as:"
It's not usually that bad though, the typical case is that a few extra spaces, which are due to word separations, are thrown in the middle of the text. Usually all the letters are correct, because the symbol space is the same as a dot, and that's usually about a third of the letter spacing. If sending very fast, even the symbol space can get messed up though, which results in combining letters, sometimes changing a letter, and sometimes producing an invalid character. Invalid characters are currently silently discarded. That could be improved too, by having the code try to parse the combined invalid symbols into one or more valid characters. (I probably will never do this though, as that's compute-intensive, and requires a dictionary and even could require natural language analysis).
The space threshold problem can be alleviated by exaggerating the separation between letters and words when sending the text, but this sounds unnatural to someone familiar with Morse code. It also feels very unnatural to change the proper flow of Morse code. Imagine reciting letters, and doing really long pauses between letters and really, really long pauses between spelled words.
Also, if I work very hard at having a consistent sending speed, the program does much better. But human beings typically allow their speed to vary, just as they do when speaking, particularly if there are distractions, so that's not a good long-term solution.
The human brain has an easy time doing real-time tracking of the spaces between symbols, letters, and words in Morse code, and adjusting based on sending speed and content.
I think if I work on it long enough, I can get the space tracking to work much better. I have a number of ideas I think that will improve that.
Also, right now, I enter Morse code data on the screen, stop entering data, and then wait two seconds for the system to recognized I've stopped and process all the data. A better system would be real-time decoding as the data flows in, with some buffering to allow estimation of thresholds in real-time.
Another competently different idea I want to try is to be able to draw individual characters on the screen, and having those get recognized, i.e. crude OCR of large hand drawn characters. That would be a fun and challenging project. I saw the Sketch.py sample program. That's a good starting point for the input part of that program. For now though, I want to improve the Morse Code decoder.
This worked for me using Pythonista 3, where v is an instance of a class derived from ui.View.
v.present(title_bar_color='#000000', hide_close_button=True, orientations=['portrait'])
Obviously, you only need the "hide_close_button=True" part.
By the way, I'm relatively new here, and I still don't know how to post code so the formatting remains intact. I just searched for how to do that for 5 minutes and was unsuccessful. If anyone replies how to do that, I'll fix this post.
Update: Thanks dgelessus.
@ccc - Yes, I saw that post about controlling the light. I saw the part about reading Morse Code.
My goal was different. It's to covertly enter information. I really only need to enter a two characters for my application at a time. And, the output is done using text-to-speech,.
The output is not what I entered - my input just controls what the spoken text is.
While I have successfully entered a sentence, the current decoder is very touchy. I build a histogram of "up" times, and "down" times. The "up" histogram is used to determine the threshold between dots and dashes. That works very well. The "down" histogram has to determine a threshold for regular space between symbols, the space between letters, and the space that separates words. That doesn't work well. The problem is that people drift in their sending speed, so these things really need to be dynamically updated - and my program doesn't do that. I don't think the code would help the guy in the "light" topic, particularly for his application. It messes up word spaces right now. Since I'm just entering two letters, that's not an issue.
I'd really like to be able to use a hidden switch that plugs into the iPhone USB port. That could be made smaller than the screen. I'm looking at:
However, the application I have now using a full-screen button is sufficient for my needs.
I've hidden the title (status?) bar, I found out how to do that in another post here. I saw something about adding an image to a button (or "view" in this case) in another post, but I'm having difficulty finding that now. If I can add a full-screen image, I'll do that. That would just be icing on the cake.
I just looked at the "Scene" code above, but I seem to recall just being able to add an image to a regular view.
Eventually, I'll post some code here, although probably not this application.
Pythonista is awesome.
Pure functional languages can be more easily proven correct than languages that have more degrees of freedom.
If your friend is doing computer science research, F# is fine.
The discipline one needs to write in a pure functional language makes it very easy to later write in a language like Python, so I wouldn't worry. An F# programmer could become a good Python programmer in a relatively short amount of time, probably much less time than a Python programmer could learn F#.
Python is very popular for science research though, and of course it's used at Google and other companies. I suspect either choice is a good choice - it just depends on what your friend wants to do.
By the way, I used time.perf_counter() to get high resolution times, so I could enter the Morse code at about 20 words-per-minute.
I store "up" and "down" intervals in parallel lists, and process them after having at least one "up interval in the "up" list and when the update handler is in the "down" state for at least 2 seconds - so that when I stop entering Morse code, the message is processed roughly 2 seconds later.
Thanks again for saving me so much time.