1
0
mirror of https://github.com/peterantypas/maiana.git synced 2025-05-18 00:10:08 -07:00

Checkpoint

This commit is contained in:
Peter Antypas 2022-01-27 20:01:23 -08:00
parent 043c7a4be3
commit c36c89e604
5 changed files with 2920 additions and 0 deletions

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,9 @@
import wx
from mainwindow import MainWindow
if __name__ == '__main__':
app = wx.App()
window = MainWindow()
window.Show(True)
app.MainLoop()

View File

@ -0,0 +1,267 @@
# -*- coding: utf-8 -*-
###########################################################################
## Python code generated with wxFormBuilder (version 3.10.1-39-g978478d5-dirty)
## http://www.wxformbuilder.org/
##
## PLEASE DO *NOT* EDIT THIS FILE!
###########################################################################
import wx
import wx.xrc
###########################################################################
## Class MainFrame
###########################################################################
class MainFrame ( wx.Frame ):
def __init__( self, parent ):
wx.Frame.__init__ ( self, parent, id = wx.ID_ANY, title = u"MAIANA Transponder Manager ver 0.1", pos = wx.DefaultPosition, size = wx.Size( 605,300 ), style = wx.CAPTION|wx.CLOSE_BOX|wx.MINIMIZE_BOX|wx.TAB_TRAVERSAL )
self.SetSizeHints( wx.DefaultSize, wx.DefaultSize )
bSizer1 = wx.BoxSizer( wx.VERTICAL )
self.m_notebook2 = wx.Notebook( self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, 0 )
self.m_StatusPnl = wx.Panel( self.m_notebook2, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.TAB_TRAVERSAL )
gSizer1 = wx.GridSizer( 5, 2, 0, 0 )
self.m_staticText1 = wx.StaticText( self.m_StatusPnl, wx.ID_ANY, u"Serial Port", wx.DefaultPosition, wx.DefaultSize, 0 )
self.m_staticText1.Wrap( -1 )
gSizer1.Add( self.m_staticText1, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5 )
bSizer4 = wx.BoxSizer( wx.HORIZONTAL )
m_SerialPortChoiceChoices = []
self.m_SerialPortChoice = wx.Choice( self.m_StatusPnl, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, m_SerialPortChoiceChoices, 0 )
self.m_SerialPortChoice.SetSelection( 0 )
self.m_SerialPortChoice.SetMinSize( wx.Size( 150,-1 ) )
bSizer4.Add( self.m_SerialPortChoice, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5 )
self.m_SerialBtn = wx.Button( self.m_StatusPnl, wx.ID_ANY, u"Connect", wx.DefaultPosition, wx.DefaultSize, 0 )
self.m_SerialBtn.Enable( False )
bSizer4.Add( self.m_SerialBtn, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5 )
gSizer1.Add( bSizer4, 1, wx.EXPAND, 5 )
self.m_staticText7 = wx.StaticText( self.m_StatusPnl, wx.ID_ANY, u"CPU", wx.DefaultPosition, wx.DefaultSize, 0 )
self.m_staticText7.Wrap( -1 )
gSizer1.Add( self.m_staticText7, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5 )
self.m_CPULbl = wx.StaticText( self.m_StatusPnl, wx.ID_ANY, u"(unknown)", wx.DefaultPosition, wx.DefaultSize, 0 )
self.m_CPULbl.Wrap( -1 )
self.m_CPULbl.SetFont( wx.Font( wx.NORMAL_FONT.GetPointSize(), wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL, False, wx.EmptyString ) )
gSizer1.Add( self.m_CPULbl, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5 )
self.m_staticText3 = wx.StaticText( self.m_StatusPnl, wx.ID_ANY, u"Hardware Revision", wx.DefaultPosition, wx.DefaultSize, 0 )
self.m_staticText3.Wrap( -1 )
gSizer1.Add( self.m_staticText3, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5 )
self.m_HWRevLbl = wx.StaticText( self.m_StatusPnl, wx.ID_ANY, u"(unknown)", wx.DefaultPosition, wx.DefaultSize, 0 )
self.m_HWRevLbl.Wrap( -1 )
self.m_HWRevLbl.SetFont( wx.Font( wx.NORMAL_FONT.GetPointSize(), wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL, False, wx.EmptyString ) )
gSizer1.Add( self.m_HWRevLbl, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5 )
self.m_staticText5 = wx.StaticText( self.m_StatusPnl, wx.ID_ANY, u"Firmware Revision", wx.DefaultPosition, wx.DefaultSize, 0 )
self.m_staticText5.Wrap( -1 )
gSizer1.Add( self.m_staticText5, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5 )
self.m_FWRevLbl = wx.StaticText( self.m_StatusPnl, wx.ID_ANY, u"(unknown)", wx.DefaultPosition, wx.DefaultSize, 0 )
self.m_FWRevLbl.Wrap( -1 )
self.m_FWRevLbl.SetFont( wx.Font( wx.NORMAL_FONT.GetPointSize(), wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL, False, wx.EmptyString ) )
gSizer1.Add( self.m_FWRevLbl, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5 )
self.m_StatusPnl.SetSizer( gSizer1 )
self.m_StatusPnl.Layout()
gSizer1.Fit( self.m_StatusPnl )
self.m_notebook2.AddPage( self.m_StatusPnl, u"Status", True )
self.m_StationPnl = wx.Panel( self.m_notebook2, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.TAB_TRAVERSAL )
self.m_StationPnl.Enable( False )
gSizer2 = wx.GridSizer( 0, 4, 0, 0 )
self.m_staticText101 = wx.StaticText( self.m_StationPnl, wx.ID_ANY, u"MMSI", wx.DefaultPosition, wx.DefaultSize, 0 )
self.m_staticText101.Wrap( -1 )
gSizer2.Add( self.m_staticText101, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5 )
self.m_MMSIText = wx.TextCtrl( self.m_StationPnl, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.Size( 100,-1 ), 0 )
gSizer2.Add( self.m_MMSIText, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5 )
self.m_staticText11 = wx.StaticText( self.m_StationPnl, wx.ID_ANY, u"Call Sign", wx.DefaultPosition, wx.DefaultSize, 0 )
self.m_staticText11.Wrap( -1 )
gSizer2.Add( self.m_staticText11, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5 )
self.m_CallsignText = wx.TextCtrl( self.m_StationPnl, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, 0 )
gSizer2.Add( self.m_CallsignText, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5 )
self.m_staticText12 = wx.StaticText( self.m_StationPnl, wx.ID_ANY, u"Name", wx.DefaultPosition, wx.DefaultSize, 0 )
self.m_staticText12.Wrap( -1 )
gSizer2.Add( self.m_staticText12, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5 )
self.m_NameText = wx.TextCtrl( self.m_StationPnl, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, 0 )
self.m_NameText.SetMaxLength( 20 )
self.m_NameText.SetMinSize( wx.Size( 140,-1 ) )
gSizer2.Add( self.m_NameText, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5 )
self.m_staticText13 = wx.StaticText( self.m_StationPnl, wx.ID_ANY, u"Vessel Type", wx.DefaultPosition, wx.DefaultSize, 0 )
self.m_staticText13.Wrap( -1 )
gSizer2.Add( self.m_staticText13, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5 )
m_VesselTypeChoiceChoices = [ u"Fishing", u"Diving", u"Sailing", u"Pleasure" ]
self.m_VesselTypeChoice = wx.Choice( self.m_StationPnl, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, m_VesselTypeChoiceChoices, 0 )
self.m_VesselTypeChoice.SetSelection( 0 )
gSizer2.Add( self.m_VesselTypeChoice, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5 )
self._ = wx.StaticText( self.m_StationPnl, wx.ID_ANY, u"Length (m)", wx.DefaultPosition, wx.DefaultSize, 0 )
self._.Wrap( -1 )
gSizer2.Add( self._, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5 )
self.m_LengthText = wx.TextCtrl( self.m_StationPnl, wx.ID_ANY, u"0", wx.DefaultPosition, wx.DefaultSize, 0 )
gSizer2.Add( self.m_LengthText, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5 )
self.m_staticText15 = wx.StaticText( self.m_StationPnl, wx.ID_ANY, u"Beam (m)", wx.DefaultPosition, wx.DefaultSize, 0 )
self.m_staticText15.Wrap( -1 )
gSizer2.Add( self.m_staticText15, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5 )
self.m_BeamText = wx.TextCtrl( self.m_StationPnl, wx.ID_ANY, u"0", wx.DefaultPosition, wx.DefaultSize, 0 )
gSizer2.Add( self.m_BeamText, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5 )
self.m_staticText17 = wx.StaticText( self.m_StationPnl, wx.ID_ANY, u"Port Offset (m)", wx.DefaultPosition, wx.DefaultSize, 0 )
self.m_staticText17.Wrap( -1 )
gSizer2.Add( self.m_staticText17, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5 )
self.m_PortOffsetText = wx.TextCtrl( self.m_StationPnl, wx.ID_ANY, u"0", wx.DefaultPosition, wx.DefaultSize, 0 )
gSizer2.Add( self.m_PortOffsetText, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5 )
self.m_staticText16 = wx.StaticText( self.m_StationPnl, wx.ID_ANY, u"Bow Offset (m)", wx.DefaultPosition, wx.DefaultSize, 0 )
self.m_staticText16.Wrap( -1 )
gSizer2.Add( self.m_staticText16, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5 )
self.m_BowOffsetText = wx.TextCtrl( self.m_StationPnl, wx.ID_ANY, u"0", wx.DefaultPosition, wx.DefaultSize, 0 )
gSizer2.Add( self.m_BowOffsetText, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5 )
self.m_staticText18 = wx.StaticText( self.m_StationPnl, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, 0 )
self.m_staticText18.Wrap( -1 )
gSizer2.Add( self.m_staticText18, 0, wx.ALL, 5 )
self.m_staticText19 = wx.StaticText( self.m_StationPnl, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, 0 )
self.m_staticText19.Wrap( -1 )
gSizer2.Add( self.m_staticText19, 0, wx.ALL, 5 )
self.m_staticText20 = wx.StaticText( self.m_StationPnl, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, 0 )
self.m_staticText20.Wrap( -1 )
gSizer2.Add( self.m_staticText20, 0, wx.ALL, 5 )
self.m_StationSaveBtn = wx.Button( self.m_StationPnl, wx.ID_ANY, u"Save", wx.DefaultPosition, wx.DefaultSize, 0 )
gSizer2.Add( self.m_StationSaveBtn, 0, wx.ALL|wx.ALIGN_BOTTOM, 5 )
self.m_StationPnl.SetSizer( gSizer2 )
self.m_StationPnl.Layout()
gSizer2.Fit( self.m_StationPnl )
self.m_notebook2.AddPage( self.m_StationPnl, u"Station Data", False )
self.m_FWUpdatePnl = wx.Panel( self.m_notebook2, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.TAB_TRAVERSAL )
self.m_FWUpdatePnl.Enable( False )
bSizer41 = wx.BoxSizer( wx.VERTICAL )
gSizer4 = wx.GridSizer( 1, 2, 0, 0 )
gSizer4.SetMinSize( wx.Size( -1,90 ) )
self.m_staticText28 = wx.StaticText( self.m_FWUpdatePnl, wx.ID_ANY, u"Binary File:", wx.DefaultPosition, wx.Size( 80,-1 ), 0 )
self.m_staticText28.Wrap( -1 )
gSizer4.Add( self.m_staticText28, 1, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5 )
self.m_FWBinaryPicker = wx.FilePickerCtrl( self.m_FWUpdatePnl, wx.ID_ANY, wx.EmptyString, u"Select a file", u"*.bin", wx.DefaultPosition, wx.Size( -1,-1 ), wx.FLP_CHANGE_DIR|wx.FLP_DEFAULT_STYLE|wx.FLP_FILE_MUST_EXIST|wx.FLP_OPEN )
gSizer4.Add( self.m_FWBinaryPicker, 1, wx.ALL|wx.ALIGN_CENTER_VERTICAL|wx.EXPAND, 5 )
bSizer41.Add( gSizer4, 1, wx.EXPAND, 5 )
gSizer5 = wx.GridSizer( 1, 2, 0, 0 )
self.m_FWProgress = wx.Gauge( self.m_FWUpdatePnl, wx.ID_ANY, 100, wx.DefaultPosition, wx.Size( 350,-1 ), wx.GA_HORIZONTAL )
self.m_FWProgress.SetValue( 0 )
gSizer5.Add( self.m_FWProgress, 0, wx.ALL, 5 )
self.m_FWUpdateBtn = wx.Button( self.m_FWUpdatePnl, wx.ID_ANY, u"Update", wx.DefaultPosition, wx.DefaultSize, 0 )
self.m_FWUpdateBtn.Enable( False )
gSizer5.Add( self.m_FWUpdateBtn, 0, wx.ALL|wx.ALIGN_RIGHT, 5 )
bSizer41.Add( gSizer5, 1, wx.EXPAND, 5 )
bSizer41.Add( ( 0, 0), 1, wx.EXPAND, 5 )
self.m_FWUpdatePnl.SetSizer( bSizer41 )
self.m_FWUpdatePnl.Layout()
bSizer41.Fit( self.m_FWUpdatePnl )
self.m_notebook2.AddPage( self.m_FWUpdatePnl, u"FW Update", False )
bSizer1.Add( self.m_notebook2, 1, wx.EXPAND |wx.ALL, 5 )
self.SetSizer( bSizer1 )
self.Layout()
self.Centre( wx.BOTH )
# Connect Events
self.m_SerialPortChoice.Bind( wx.EVT_CHOICE, self.onSerialPortSelection )
self.m_SerialBtn.Bind( wx.EVT_BUTTON, self.onSerialBtnClick )
self.m_StationSaveBtn.Bind( wx.EVT_BUTTON, self.onStationSaveBtnClick )
self.m_FWBinaryPicker.Bind( wx.EVT_FILEPICKER_CHANGED, self.onFWBinarySelection )
self.m_FWUpdateBtn.Bind( wx.EVT_BUTTON, self.onFWUpdateBtnClick )
def __del__( self ):
pass
# Virtual event handlers, override them in your derived class
def onSerialPortSelection( self, event ):
event.Skip()
def onSerialBtnClick( self, event ):
event.Skip()
def onStationSaveBtnClick( self, event ):
event.Skip()
def onFWBinarySelection( self, event ):
event.Skip()
def onFWUpdateBtnClick( self, event ):
event.Skip()

View File

@ -0,0 +1,94 @@
from mainframe import MainFrame
from model import MaianaClient
import serial
import wx
class MainWindow(MainFrame):
def __init__(self):
MainFrame.__init__(self, None)
self.m_SerialPortChoice.Set(MaianaClient.serial_ports())
self.port = None
self.data = None
def onSerialPortSelection(self, event):
self.m_SerialBtn.Enable()
def onSerialBtnClick(self, event):
if self.port is None:
self.port = serial.Serial(self.m_SerialPortChoice.GetString(self.m_SerialPortChoice.GetSelection()), 38400, timeout=2)
if self.port is None:
wx.MessageBox(b'Unable to open port, it may be in use', 'Info', wx.OK | wx.ICON_ERROR)
else:
self.m_SerialBtn.SetLabel(b'Disconnect')
self.enableUI()
self.refreshSys()
self.refreshStation()
else:
self.port.close()
self.port = None
self.m_SerialBtn.SetLabel(b'Connect')
self.disableUI()
def onStationSaveBtnClick(self, event):
# Let's validate
if not self.validateStationInputs():
return
newdata = {'mmsi': int(self.m_MMSIText.Value),
'name': self.m_NameText.Value,
'callsign': self.m_CallsignText.Value,
'len': int(self.m_LengthText.Value),
'beam': int(self.m_BeamText.Value),
'portoffset': int(self.m_PortOffsetText.Value),
'bowoffset': int(self.m_BowOffsetText.Value),
'type': MaianaClient.VESSEL_TYPES[self.m_VesselTypeChoice.Selection]}
print(newdata)
if MaianaClient.setStationData(self.port, newdata):
self.stationdata = newdata
def onFWBinarySelection(self, event):
event.Skip()
def onFWUpdateBtnClick(self, event):
event.Skip()
def enableUI(self):
self.m_StationPnl.Enable()
self.m_FWUpdatePnl.Enable()
def disableUI(self):
self.m_StationPnl.Disable()
self.m_FWUpdatePnl.Disable()
def refreshSys(self):
self.sysdata = MaianaClient.loadSys(self.port)
self.renderSys()
def refreshStation(self):
self.stationdata = MaianaClient.loadStation(self.port)
self.renderStation()
def renderSys(self):
self.m_HWRevLbl.SetLabel(self.sysdata['hw'])
self.m_FWRevLbl.SetLabel(self.sysdata['fw'])
self.m_CPULbl.SetLabel(self.sysdata['cpu'])
def renderStation(self):
self.m_MMSIText.SetValue('{}'.format(self.stationdata['mmsi']))
self.m_NameText.SetValue(self.stationdata['name'])
self.m_CallsignText.SetValue(self.stationdata['callsign'])
self.m_LengthText.SetValue('{}'.format(self.stationdata['len']))
self.m_BeamText.SetValue('{}'.format(self.stationdata['beam']))
self.m_PortOffsetText.SetValue('{}'.format(self.stationdata['portoffset']))
self.m_BowOffsetText.SetValue('{}'.format(self.stationdata['bowoffset']))
t = self.stationdata['type']
i = MaianaClient.VESSEL_TYPES.index(t)
self.m_VesselTypeChoice.SetSelection(i)
def validateStationInputs(self):
return True

View File

@ -0,0 +1,91 @@
import serial
import sys
import glob
import time
import re
class MaianaClient:
VESSEL_TYPES = [30, 34, 36, 37]
@staticmethod
def serial_ports():
""" Lists serial port names
:raises EnvironmentError:
On unsupported or unknown platforms
:returns:
A list of the serial ports available on the system
"""
if sys.platform.startswith('win'):
ports = ['COM%s' % (i + 1) for i in range(256)]
elif sys.platform.startswith('linux') or sys.platform.startswith('cygwin'):
# this excludes your current terminal "/dev/tty"
ports = glob.glob('/dev/tty[A-Za-z]*')
elif sys.platform.startswith('darwin'):
ports = glob.glob('/dev/tty\..*')
else:
raise EnvironmentError('Unsupported platform')
result = []
for port in ports:
# print port
try:
s = serial.Serial(port)
s.close()
result.append(port)
except (OSError, Exception):
pass
return result
@staticmethod
def sendCmdWithResponse(port, cmd, resp):
port.write(cmd + b'\r\n')
for i in range(10):
s = port.readline().strip()
if resp in s:
return s
return None
@staticmethod
def loadSys(port):
sysline = MaianaClient.sendCmdWithResponse(port, b'sys?', b'$PAISYS')
if sysline is None:
return {}
systokens = re.split(',|\\*', sysline.decode('utf-8'))
sysd = {'fw': systokens[2], 'hw': systokens[1], 'cpu': systokens[4]}
return sysd
@staticmethod
def loadStation(port):
stationline = MaianaClient.sendCmdWithResponse(port, b'station?', b'$PAISTN')
if stationline is None:
return {}
stationtokens = re.split(',|\\*', stationline.decode('utf-8'))
stad = {'mmsi': int(stationtokens[1]), 'name': stationtokens[2], 'callsign': stationtokens[3],
'type': int(stationtokens[4]), 'len': int(stationtokens[5]), 'beam': int(stationtokens[6]),
'portoffset': int(stationtokens[7]), 'bowoffset': int(stationtokens[8])}
return stad
@staticmethod
def setStationData(port, data):
line = 'station {},{},{},{},{},{},{},{}\r\n'.format(
data['mmsi'],
data['name'],
data['callsign'],
data['type'],
data['len'],
data['beam'],
data['portoffset'],
data['bowoffset']
)
resp = MaianaClient.sendCmdWithResponse(port, line.encode('utf-8'), b'$PAISTN')
if resp:
return MaianaClient.sendCmdWithResponse(port, b'reboot', b'$PAISTN')
return False