├── .github └── FUNDING.yml ├── README.md ├── docs └── ft817nd_cat_system.pdf ├── images ├── 73s.jpg ├── ft817_acc.png ├── ft817_cat_output.png ├── ft817_connection.png ├── ft817_sql_off.png └── ft817_sql_on.png └── src ├── ft817.py └── trx_monitor.py /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | # github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] 4 | # patreon: # Replace with a single Patreon username 5 | # open_collective: # Replace with a single Open Collective username 6 | ko_fi: 4x1md 7 | # tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | # community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | # liberapay: # Replace with a single Liberapay username 10 | #issuehunt: # Replace with a single IssueHunt username 11 | # otechie: # Replace with a single Otechie username 12 | # lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry 13 | custom: ['https://www.buymeacoffee.com/4x1md'] 14 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Yaesu FT-817ND CAT Display In Python 2 | Python implementation of CAT system for Yaesu FT-817ND. 3 | 4 | ## Overview 5 | According to Yaesu FT-817ND's manual, the CAT System allows the transceiver to be controlled by a personal computer. The purpose of this project is to learn this system for later implementing it using an AVR microcontroller. 6 | 7 | The program is written in Python and uses ```serial``` library to connect to the transceiver. It runs as console application in text mode. 8 | 9 | ## :warning: Important Warning! 10 | 11 | 1. This program is provided as is and I'm not responsible for any damage it may cause. 12 | 2. Before using this program make sure you completely understand what you are doing. 13 | 3. Before sending any commands to your transceiver make a backup copy of factory calibration settings in service menu. There are [sources](http://www.ka7oei.com/ft817_meow.html) which state that some commands may completely erase it. This may result in need to send the transceiver to Yaesu for realignment. 14 | 15 | ## Connecting to PC 16 | 17 | Yaesu FT-817ND's is connected to PC through a COM port. I used one of many USB to COM boards available on eBay and AliExpress for a couple of dollars. The port is connected to ```TXD``` and ```RXD``` pins of the ```ACC``` connector located on the rear panel of the transceiver. Refer to [Yaesu FT-817ND's Operation Manual](http://www.yaesu.co.uk/files/FT-817ND_Operating%20Manual.pdf) for more details. 18 | 19 | ![ACC plug](https://raw.githubusercontent.com/4x1md/ft817_cat_python/master/images/ft817_connection.png) 20 | 21 | Programming cable can also be used and will work fine with this program. 22 | 23 | ## Program Structure 24 | 25 | The program is implemented as ```FT817``` class with following methods: 26 | 27 | ```__init__(self, serial_port, serial_speed, serial_stopbits)```: constructor which starts serial connection and resets transceiver state variables ```self._freq```, ```self._mode```, ```self._squelch``` and ```self._s_meter```. 28 | 29 | ```read_frequency(self)```: reads frequency and mode data and stores it in ```self._freq``` and ```self._mode``` variables. 30 | 31 | ```read_rx_status(self)```: reads receiver status (S-level, squelch state, CTCSS/DCS code match and discriminator centering) and stores S-level and squelch state in ```self._s_meter``` and ```self._squelch``` variables. 32 | 33 | ```get_s_meter_string(self, s_meter)```: generates S-meter string for second line of output. 34 | 35 | ```get_trx_state_string(self)```: generates two lines of text which include frequency, modulation, squelch level and S-meter data. 36 | 37 | ```loop(self, samples_per_sec)```: reads data from the transceiver as many times per second as defined in ```samples_per_sec``` variable. 38 | 39 | ## Program Settings And Constants 40 | 41 | ### FT817() Class 42 | 43 | ```FT817``` class contains the following settings and constants: 44 | 45 | ```SERIAL_SPEED```, ```SERIAL_STOPBITS```: COM port speed and stopbits accordingly. By default FT-817 CAT interface is set to 4800 bps with two stop bits. 46 | 47 | ```SERIAL_TIMEOUT```: sets COM port reading timeout to avoid program blocking if the transceiver is not connected to the port or is turned off. 48 | 49 | ```CMD_READ_FREQ```, ```CMD_READ_RX_STATUS```: byte sequences to send to the trasceiver to read frequency and RX status accordingly. 50 | 51 | ### trx_monitor.py 52 | 53 | ```SERIAL_PORT```: COM port name where FT-817ND transceiver is connected. 54 | 55 | ```SAMPLES_PER_SEC```: number of times per second to query the transceiver. 56 | 57 | ## Running the program 58 | 59 | Run the ```trx_monitor.py``` file in Python interpreter. 60 | 61 | ## Program Output 62 | 63 | The output consists of two lines which are pretty self explanatory. 64 | 65 | ```43872500Hz FM SQL: OFF``` 66 | 67 | ```S3+00 |||............``` 68 | 69 | The first line shows frequency, mode (AM, FM, SSB, PKT etc.) and squelch state. The second line is S-Meter which shows S-level and dB over S9 and a simple scale where 15 dots correspond to S0 and 15 pipes correspond to S9+20dB. 70 | 71 | Program output in console with no signal and squelch on (left) and with squelch off (right): 72 | 73 | ![Squelch on](https://raw.githubusercontent.com/4x1md/ft817_cat_python/master/images/ft817_cat_output.png) 74 | 75 | ## Questions? Suggestions? 76 | You are more than welcome to contact me with any questions, suggestions or propositions regarding this project. You can: 77 | 78 | 1. Visit [my QRZ.COM page](https://www.qrz.com/db/4X1MD) 79 | 2. Visit [my Facebook profile](https://www.facebook.com/Dima.Meln) 80 | 3. :email: Write me an email to iosaaris =at= gmail dot com 81 | 82 | ## How to Support or Say Thanks 83 | 84 | If you like this project, or found here some useful information and want to say thanks, or encourage me to do more, you can buy me a coffee! 85 | 86 | [![ko-fi](https://ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/Q5Q4ITR7J) 87 | 88 | [!["Buy Me A Coffee"](https://www.buymeacoffee.com/assets/img/custom_images/orange_img.png)](https://www.buymeacoffee.com/4x1md) 89 | 90 | You can aslo make a donation with PayPal: 91 | 92 | [!["Donate with PayPal"](https://www.paypalobjects.com/en_US/i/btn/btn_donateCC_LG.gif)](https://www.paypal.com/donate/?hosted_button_id=NZZWZFH5ZBCCU) 93 | 94 | 73 de 4X1MD ex 4X5DM 95 | 96 | ![73's](https://raw.githubusercontent.com/4x1md/ft817_cat_python/master/images/73s.jpg) 97 | -------------------------------------------------------------------------------- /docs/ft817nd_cat_system.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/4x1md/ft817_cat_python/7885aaf9d9c8ce1db26795e5bf62cad88a2ea2d0/docs/ft817nd_cat_system.pdf -------------------------------------------------------------------------------- /images/73s.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/4x1md/ft817_cat_python/7885aaf9d9c8ce1db26795e5bf62cad88a2ea2d0/images/73s.jpg -------------------------------------------------------------------------------- /images/ft817_acc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/4x1md/ft817_cat_python/7885aaf9d9c8ce1db26795e5bf62cad88a2ea2d0/images/ft817_acc.png -------------------------------------------------------------------------------- /images/ft817_cat_output.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/4x1md/ft817_cat_python/7885aaf9d9c8ce1db26795e5bf62cad88a2ea2d0/images/ft817_cat_output.png -------------------------------------------------------------------------------- /images/ft817_connection.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/4x1md/ft817_cat_python/7885aaf9d9c8ce1db26795e5bf62cad88a2ea2d0/images/ft817_connection.png -------------------------------------------------------------------------------- /images/ft817_sql_off.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/4x1md/ft817_cat_python/7885aaf9d9c8ce1db26795e5bf62cad88a2ea2d0/images/ft817_sql_off.png -------------------------------------------------------------------------------- /images/ft817_sql_on.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/4x1md/ft817_cat_python/7885aaf9d9c8ce1db26795e5bf62cad88a2ea2d0/images/ft817_sql_on.png -------------------------------------------------------------------------------- /src/ft817.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Created on 06 May 2016 3 | Updated on 31 Dec 2016 4 | 5 | @author: Dmitry Melnichansky 4X5DM ex 4Z7DTF 6 | https://github.com/4x5dm 7 | http://www.qrz.com/db/4X5DM 8 | 9 | @note: FT817 class which communicates with FT-817 using serial library, 10 | queries and sets transceiver's frequency and state and generates 11 | transceiver state strings for printing. 12 | 13 | ''' 14 | 15 | import serial 16 | 17 | class FT817(object): 18 | 19 | # Constants 20 | # Serial port settings 21 | SERIAL_SPEED = 4800 22 | SERIAL_STOPBITS = serial.STOPBITS_TWO 23 | SERIAL_TIMEOUT = 1.0 24 | # Transceiver modes and commands 25 | MODES = ["LSB", "USB", "CW", "CWR", "AM", None, "WFM", None, "FM", None, "DIG", None, "PKT"] 26 | CMD_READ_FREQ = [0x00, 0x00, 0x00, 0x00, 0x03] 27 | CMD_READ_RX_STATUS = [0x00, 0x00, 0x00, 0x00, 0xE7] 28 | 29 | def __init__(self, serial_port, serial_speed=SERIAL_SPEED, serial_stopbits=SERIAL_STOPBITS): 30 | self._serial = serial.Serial(serial_port, serial_speed, stopbits=serial_stopbits, timeout=FT817.SERIAL_TIMEOUT) 31 | self._frequency = "" 32 | self._mode = "" 33 | self._squelch = True 34 | self._s_meter = "" 35 | 36 | def read_frequency(self): 37 | '''Queries transceiver RX frequency and mode. 38 | The response is 5 bytes: first four store frequency and 39 | the fifth stores mode (AM, FM, SSB etc.) 40 | ''' 41 | cmd = FT817.CMD_READ_FREQ 42 | self._serial.write(cmd) 43 | resp = self._serial.read(5) 44 | resp_bytes = (ord(resp[0]), ord(resp[1]), ord(resp[2]), ord(resp[3])) 45 | self._frequency = "%02x%02x%02x%02x" % resp_bytes 46 | self._mode = FT817.MODES[ord(resp[4])] 47 | 48 | def read_rx_status(self): 49 | '''Queries transceiver RX status. 50 | The response is 1 byte: 51 | bit 7: Squelch status: 0 - off (signal present), 1 - on (no signal) 52 | bit 6: CTCSS/DCS Code: 0 - code is matched, 1 - code is unmatched 53 | bit 5: Discriminator centering: 0 - discriminator centered, 1 - uncentered 54 | bit 4: Dummy data 55 | bit 3-0: S Meter data 56 | ''' 57 | cmd = FT817.CMD_READ_RX_STATUS 58 | self._serial.write(cmd) 59 | resp = self._serial.read(1) 60 | resp_byte = ord(resp[0]) 61 | self._squelch = True if (resp_byte & 0B10000000) else False 62 | self._s_meter = resp_byte & 0x0F 63 | 64 | def get_s_meter_string(self, s_meter): 65 | '''Generates S-Meter string for printing. The string includes 66 | S value with decibels over 9 is printed and a simple 15 symbols scale. 67 | Examples: 68 | S0: S0+00 ............... 69 | S3: S3+00 |||............ 70 | S9: S9+00 |||||||||...... 71 | S9+20dB: S9+00 |||||||||||.... 72 | ''' 73 | res = "S9" if s_meter >= 9 else "S" + str(s_meter) 74 | above_nine = s_meter - 9 75 | if above_nine > 0: 76 | res += "+%s" % (10 * above_nine) 77 | else: 78 | res += "+00" 79 | res += " " 80 | res += "|" * s_meter 81 | res += "." * (15 - s_meter) 82 | return res 83 | 84 | def get_trx_state_string(self): 85 | '''Returns transceiver state data for printing. 86 | ''' 87 | s_meter_str = self.get_s_meter_string(self._s_meter) 88 | sql_str = 'SQL: ON' if self._squelch else 'SQL: OFF' 89 | res = "%sHz %s %s\r\n%s" % (self._frequency, self._mode, sql_str, s_meter_str) 90 | return res 91 | 92 | def __str__(self): 93 | '''Overrides __str__() method for using FT817 class with print command. 94 | ''' 95 | return self.get_trx_state_string() 96 | 97 | # def loop(self, samples_per_sec): 98 | # '''Infinite loop which queries the transceiver and prints the data. 99 | # Number of queries per second is passed in samples_per_sec variable. 100 | # ''' 101 | # delay = 1.0 / samples_per_sec 102 | # while True: 103 | # self.read_frequency() 104 | # self.read_rx_status() 105 | # self.print_data() 106 | # time.sleep(delay) 107 | # 108 | # if __name__ == '__main__': 109 | # ft817 = FT817() 110 | # ft817.loop(SAMPLES_PER_SEC) 111 | -------------------------------------------------------------------------------- /src/trx_monitor.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Created on Dec 31, 2016 3 | 4 | @author: 4X5DM 5 | 6 | @note: The program uses the FT817 class to query the transceiver and to print 7 | its state. 8 | Serial port name is defined by SERIAL_PORT constant. 9 | Number of queries per second is defined by SAMPLES_PER_SEC constant. 10 | ''' 11 | 12 | from ft817 import FT817 13 | import time 14 | 15 | # Constants 16 | SERIAL_PORT = "COM8" 17 | SAMPLES_PER_SEC = 5 18 | 19 | if __name__ == '__main__': 20 | print "Starting FT-817ND monitor..." 21 | 22 | try: 23 | ft817 = FT817(SERIAL_PORT) 24 | delay = 1.0 / SAMPLES_PER_SEC 25 | while True: 26 | ft817.read_frequency() 27 | ft817.read_rx_status() 28 | print 29 | print ft817 30 | time.sleep(delay) 31 | except KeyboardInterrupt: 32 | # KeyboardInterrupt exception is thrown when CTRL-C or CTRL-Break is pressed. 33 | pass 34 | except Exception, msg: 35 | print "\r\nError has occured. Error message:" 36 | print msg 37 | print "\r\n" 38 | finally: 39 | print "See you later. 73!" 40 | --------------------------------------------------------------------------------