Embedded Quisk

classic Classic list List threaded Threaded
21 messages Options
12
Reply | Threaded
Open this post in threaded view
|

Embedded Quisk

YO5RXM
Hi Jim,
Last year, with your help, I managed to configure quisk for an embedded Raspberry + Softrock standalone transceiver, with external encoder and pushbuttons for various functions (tune, PTT etc).
Ever since I had to patch all relevant python files on every Quisk update and sometimes, even re-write the necessary files because the patch reference mismatch.
Can you please tell me if you're considering adding support for external input (maybe via API?) at least for encoder based tuning? That would help a lot for embedded Quisk setups.
Thank you very much, have a nice day, 73!
Reply | Threaded
Open this post in threaded view
|

Re: Embedded Quisk

ahlstromjc
Administrator
Hello,

I thought that external input could be put into your hardware file, and so subsequent Quisk releases would not overwrite your hardware file and there would be no problems. If that is not the case we need a new API for external input. But I can not design it unless I have your physical hardware, and I do not.

Could you design an external input API? Could you send me your Quisk patches so I can see what you are doing?

Jim
N2ADR
Reply | Threaded
Open this post in threaded view
|

Re: Embedded Quisk

YO5RXM
Actually you are right. I am patching hardware_usb.py (the patch at the end of the reply) for the rotary encoder tunning and PTT, but also the main quisk.py to add some usefull stuff (I added a shutdown button directly from Quisk and some info like the IP address). Indeed the hardware_usb.py file is not changed, therefore I don't really need to patch it, just make sure that file is not overwritten on updates.
Now, in order to interface some buttons with Quisk (eq switching bands, activating VOX, NB, changing modes) I found a way to use GPIO buttons on raspberry as standard keyboard inputs, then I don't need to change anything in Quisk itself, but just assign keyboard shortcuts for different functions.
Is this possible? Can I assign keyboard shortcuts for Quisk?
Thank you very much for quick reply!

--- hardware_usb.py.orig 2015-10-26 21:19:57.000000000 +0200
+++ hardware_usb.py 2016-02-28 23:30:56.693936686 +0200
@@ -12,6 +12,22 @@
 #   len(string_msg) = dev.ctrl_transfer (OUT, bmRequest, wValue, wIndex, string_msg, timout)
 
 import usb.core, usb.util
+import RPi.GPIO as GPIO
+from rotary_class import RotaryEncoder
+GPIO.setmode(GPIO.BCM)
+GPIO.setwarnings(False)
+
+# Define GPIO inputs
+PIN_A = 17 # Pin A enconder
+PIN_B = 27 # Pin B encoder
+BUTTON = 18 # PTT button
+
+#PTT command
+GPIO.setup(23, GPIO.OUT)
+GPIO.output(23, False)
+#Band select, 1 is 80m, 0 is 40m
+GPIO.setup(24, GPIO.OUT)
+GPIO.output(24, False)
 
 DEBUG = 0
 
@@ -46,7 +62,13 @@
     self.is_cw = False
     self.key_thread = None
     self.si570_i2c_address = conf.si570_i2c_address
+    self.EncMod = conf.mouse_wheelmod # Round frequency when using mouse wheel
+    # Keep track of the current tune frequency and VFO
+    self.tune_freq = 0
+    self.vfo_freq = 0
   def open(self): # Called once to open the Hardware
+    # Make a rotary control when opening the hardware
+    self.rswitch = RotaryEncoder(PIN_A, PIN_B, BUTTON, self.EncTune)
     # find our device
     usb_dev = usb.core.find(idVendor=self.conf.usb_vendor_id, idProduct=self.conf.usb_product_id)
     if usb_dev is None:
@@ -87,10 +109,14 @@
       print ('Smooth tune', sm)
     return text
   def close(self): # Called once to close the Hardware
+    self.rswitch.event_removal(PIN_A, PIN_B, BUTTON)
     if self.key_thread:
       self.key_thread.stop()
       self.key_thread = None
   def ChangeFrequency(self, tune, vfo, source='', band='', event=None):
+    # When Quisk changes the frequency, record the new frequency
+    self.tune_freq = tune
+    self.vfo_freq = vfo
     if self.usb_dev and self.vfo != vfo:
       if self.conf.si570_direct_control:
         if self.SetFreqByDirect(vfo - self.transverter_offset):
@@ -105,7 +131,27 @@
     # Return the current tuning and VFO frequency.  If neither have changed,
     # you can return (None, None).  This is called at about 10 Hz by the main.
     # return (tune, vfo) # return changed frequencies
-    return None, None # frequencies have not changed
+    #return None, None # frequencies have not changed
+    #return self.tune_freq, self.vfo_freq
+    if self.tune_freq:
+ return self.tune_freq, self.vfo_freq
+    else:
+ return None, None
+  def EncTune(self, event):
+    # When the control changes the frequency, adjust it
+    if event == RotaryEncoder.CLOCKWISE:
+ self.tune_freq += self.EncMod
+    elif event == RotaryEncoder.ANTICLOCKWISE:
+ self.tune_freq -= self.EncMod
+    elif event == RotaryEncoder.BUTTONDOWN:
+ self.ptt_button = 1
+ GPIO.output(23, True)
+    elif event == RotaryEncoder.BUTTONUP:
+ self.ptt_button = 0
+ GPIO.output(23, False)
+    if self.key_thread:
+      self.key_thread.OnPTT(self.ptt_button)
+    self.tune_freq = self.tune_freq // self.EncMod * self.EncMod
   def RepeaterOffset(self, offset=None): # Change frequency for repeater offset during Tx
     if offset is None: # Return True if frequency change is complete
       if time.time() > self.repeater_time0 + self.repeater_delay:
@@ -134,6 +180,10 @@
   def ChangeBand(self, band):
     # band is a string: "60", "40", "WWV", etc.
     BaseHardware.ChangeBand(self, band)
+    if band in ('160', '80', '60'):
+ GPIO.output(24, False)
+    else:
+ GPIO.output(24, True)
   def OnSpot(self, level):
     if self.key_thread:
       self.key_thread.OnSpot(level)
@@ -143,8 +193,10 @@
     if event:
       if event.GetEventObject().GetValue():
         self.ptt_button = 1
+ GPIO.output(23, True)
       else:
         self.ptt_button = 0
+ GPIO.output(23, False)
     if self.key_thread:
       self.key_thread.OnPTT(self.ptt_button)
     elif self.usb_dev:
Reply | Threaded
Open this post in threaded view
|

Re: Embedded Quisk

ahlstromjc
Administrator
Hello,

If you alter hardware_usb.py, it will be overwritten with each Quisk release. You should create your own hardware file and enter its path on the config/radio/hardware screen. It should start with:

from softrock.hardware_usb import Hardware as BaseHardware

Then you create methods that call the base and add more code of your own, like this:

  def close(self): # Called once to close the Hardware
    self.rswitch.event_removal(PIN_A, PIN_B, BUTTON)
    BaseHardware.close(self)

I made a hardware file for you and attached it. Let me know if you can't get it.
testusb.py

Jim
N2ADR
Reply | Threaded
Open this post in threaded view
|

Re: Embedded Quisk

ahlstromjc
Administrator
In reply to this post by YO5RXM
Hello,

Regarding the keyboard shortcuts, Quisk already has a shortcut for PTT. Please test that. If it does what you want, we can add more.

Jim
N2ADR
Reply | Threaded
Open this post in threaded view
|

Re: Embedded Quisk

YO5RXM
I just tested it and it works perfectly! I've configured GPIO keyboard input for key "q" and I used it in PTT key configuration.
If possible, it would be great to have a key to toggle the bands, one for VOX, one for modes (ideally each mode a different key, at least for the most important ones LSB, USB, AM, FM, FDV, CW) and one to toggle NB.
Thank you very much, 73'!
Reply | Threaded
Open this post in threaded view
|

Re: Embedded Quisk

YO5RXM
Thanks Jim, it works perfect with version 4.1.16.
Is it possible to have keyboard shortcuts for Modes as well?
Have a great day, 73!
Reply | Threaded
Open this post in threaded view
|

Re: Embedded Quisk

ahlstromjc
Administrator
Hello,

There are shortcuts for all modes. CW, SSB, AM, atc.

Jim
N2ADR
Reply | Threaded
Open this post in threaded view
|

Re: Embedded Quisk

YO5RXM
Oh I found the issue, some of the keyboard shortcuts (eq "modes") do not work in Small Form window. Unfortunately I can't use the full view on the 800x600 LCD screen, therefore I can't use the keyboard shortcuts for modes etc.
Is there a way to have keyboard shortcuts on Small form window mode?
Thank you again!
Reply | Threaded
Open this post in threaded view
|

Re: Embedded Quisk

ahlstromjc
Administrator
Hello,

I did not add keyboard shortcuts to the Small Form window because I thought that a small window would be a touch screen. Are you using a keyboard with a small screen, and it is not a touch screen?

Jim
N2ADR
Reply | Threaded
Open this post in threaded view
|

Re: Embedded Quisk

YO5RXM
I am using the touch screen with small window settings, however I want also to be able to use external buttons for the common used functions for faster access. On a 800x600 LCD, the Quisk own buttons are quite small and sometimes prone for errors (eq pressing the wrong button), this is why I want to use external buttons for them.
Thank you for your patience and great work!
Reply | Threaded
Open this post in threaded view
|

Re: Embedded Quisk

ahlstromjc
Administrator
Hello,

Using shortcut keys for mode in the Small Screen does not work well. Instead, you can call this method directly from your hardware file to change modes.

self.application.OnBtnMode(None, "USB")

Use the string "USB", "LSB", "AM" according to the mode you want.

Jim
N2ADR
Reply | Threaded
Open this post in threaded view
|

Re: Embedded Quisk

YO5RXM
Hi Jim, thanks a lot for your support, prompt as always. Unfortunately my programming skills are quite basic, so your suggestion is helpful but too difficult for me to implement.
I managed to map all my 8 keys to the all the shortcuts of the small window version + PTT. I had to replace the wx.ACCEL_ALT with wx.ACCEL_NORMAL on quisk.py because I don't use a normal keyboard, therefore I don't use key modifiers (that would be really cool if one could select the modifier key in the menu).
Having so few keys at disposal, I can't really use the mode shortcut keys even in large window mode because I would consume all my keys :)))). The only way would be to have a key to toggle the modes or bands, but because modes and bands are dynamically defined (based on user's choices or availability of libraries) I don't thing it's worth it.
So for now I am really pleased, the only changes are the modifier keys in quisk.py and a custom hardware_usb.py file for the rotary encoder setup. All the rest it's being handled by the OS (mapped the  GPIO pins to keyboard codes), this means much less patching for newer versions of Quisk.
I know it might sound silly, but how can I use the FreeDV mode in Quisk?
Thanks again for great support! See my page on qrz.com for the first version of Quisk based transceiver, the version two is on the way ;).
Reply | Threaded
Open this post in threaded view
|

Re: Embedded Quisk

ahlstromjc
Administrator
Hello,

To use FreeDV, just select the FreeDV mode and talk. It is built in.

By the way, are you in Romania? I visited Romania and really liked it. I got quite fond of mamaliga.

Jim
N2ADR
Reply | Threaded
Open this post in threaded view
|

Re: Embedded Quisk

YO5RXM
Hahaha, just had one for dinner :)))). Yes, I am from Cluj, NW part of Romania. I am really glad you liked Romania, there are some nice scenery out here.
Thank you very much!
Reply | Threaded
Open this post in threaded view
|

Re: Embedded Quisk

YO5RXM
In reply to this post by ahlstromjc
Hi Jim,
Me again...
I was wondering if you could please include the patch below in the next versions of quisk. Basically it handles the telnet connection errors for dxcluster. What happends is that my Wifi board connects to the network after 30-40 seconds after Quisk is started, therefore quisk is throwing some errors (cannot resolve hostname) in separate windows which are really annoying.
Please have a look at the patch, it might be useful for other users as well. Maybe you can find a more elegant solution to this problem, I am not a very good programmer...
Thanks!

--- /home/pi/tmp/quisk-4.1.19/dxcluster.py 2015-11-28 13:40:34.000000000 +0000
+++ /home/pi/quisk/dxcluster.py 2018-06-24 20:48:15.182931927 +0000
@@ -4,6 +4,7 @@
 import time
 import telnetlib
 import quisk_conf_defaults as conf
+from time import sleep
 
 class DxEntry():
   def __init__(self):
@@ -105,10 +106,23 @@
   def telnetInit(self):
     self.tn = telnetlib.Telnet()
       
-  def telnetConnect(self):    
-    self.tn.open(conf.dxClHost, conf.dxClPort, 10)
-    self.tn.read_until('login:', 10)
-    self.tn.write(str(conf.user_call_sign) + "\n") # user_call_sign may be Unicode
+  def telnetConnect(self):
+    global str_error
+    for x in range (0, 10):
+        try:
+    self.tn.open(conf.dxClHost, conf.dxClPort, 10)
+    str_error = None
+        except Exception as str_error:
+    pass
+
+ if str_error:
+    sleep(.5)
+ else:
+        self.tn.read_until('login:', 10)
+    self.tn.write(str(conf.user_call_sign) + "\n") # user_call_sign may be Unicode
+    break
+
+
     if conf.dxClPassword:
       self.tn.read_until("Password: ")
       self.tn.write(str(conf.dxClPassword) + "\n")
Reply | Threaded
Open this post in threaded view
|

Re: Embedded Quisk

ahlstromjc
Administrator
Hello,

I will include a patch for this in the next release.

Jim
N2ADR
Reply | Threaded
Open this post in threaded view
|

Re: Embedded Quisk

YO5RXM
Super, thanks!!!
Reply | Threaded
Open this post in threaded view
|

Re: Embedded Quisk

YO5RXM
In reply to this post by ahlstromjc
Tested today 4.1.20. It works perfectly!!! Thank you so much!
Reply | Threaded
Open this post in threaded view
|

Re: Embedded Quisk

YO5RXM
In reply to this post by ahlstromjc
Sorry, I was too fast in jumping to conclusions.
After a couple of restarts, it still trows the error:

File ./dxcluster.py, line 115, in telnetConnect
 self.tn.read_until('login:', 10)
....
File "/usb/lib/python2.7/telnetlib.py", line 271, in fileno
  return self.sock.fileno()
Attribute error: 'NoneType' object has no attribute 'fileno'

But a very simple change solves the problem:

--- ../tmp/dxcluster.py 2018-06-25 16:57:40.000000000 +0000
+++ dxcluster.py 2018-07-02 17:14:20.524298790 +0000
@@ -109,11 +109,12 @@
     for i in range(10):
       try:
         self.tn.open(conf.dxClHost, conf.dxClPort, 10)
+        self.tn.read_until('login:', 10)
+  self.tn.write(str(conf.user_call_sign) + "\n") # user_call_sign may be Unicode
         break
       except:
         time.sleep(0.5)
-    self.tn.read_until('login:', 10)
-    self.tn.write(str(conf.user_call_sign) + "\n") # user_call_sign may be Unicode

Thanks for your patience!
12