@@ -391,6 +391,8 @@ def __init__(self):
391391 self .main_layout = QVBoxLayout (self .central_widget )
392392
393393 self .auto_scroll_enabled = True
394+ self .message_to = "NOCALL-0"
395+ self .messsage_msg = "Hello, HamMessenger."
394396
395397 self .create_control_panel ()
396398 self .create_command_panel ()
@@ -402,14 +404,15 @@ def __init__(self):
402404 self .msg_entries = []
403405
404406 self .log_tag_colors = {
405- "Sent" : "blue" ,
407+ "Sent" : "blue" , # deepskyblue
406408 "Received" : "green" ,
407409 "Modem" : "orange" ,
408410 "SD" : "red"
409411 }
410412
411413 self .msg_tag_colors = {
412- "Received" : "deepskyblue" ,
414+ "Sent" : "blue" , # deepskyblue
415+ "Received" : "green" ,
413416 "Message" : "purple" ,
414417 }
415418
@@ -586,7 +589,6 @@ def create_tabs(self):
586589 log_center_layout .addWidget (self .auto_scroll_checkbox )
587590 self .log_layout .addLayout (log_center_layout )
588591
589-
590592 # Filter dropdown
591593 self .filter_box = QComboBox ()
592594 self .filter_box .addItems (["All" , "Sent" , "Received" , "Modem" , "SD" ])
@@ -600,6 +602,37 @@ def create_tabs(self):
600602 filter_row .addStretch ()
601603 self .log_layout .addLayout (filter_row )
602604
605+ #
606+ message_send_qbox = QHBoxLayout ()
607+ message_send_qbox .addStretch ()
608+ #
609+ label = QLabel ("To:" )
610+ movable_widget (message_send_qbox , label , [0 ,5 ,0 ,0 ], Qt .AlignmentFlag .AlignRight , Qt .AlignmentFlag .AlignTop )
611+ #
612+ self .message_to = QLineEdit ()
613+ self .message_to .setMaximumWidth (80 )
614+ self .message_to .setFont (self .mono_font )
615+ self .message_to .setMaxLength (9 ) # 2x3 callsing with a dash and 2 digit ssid is 9 chars
616+ movable_widget (message_send_qbox , self .message_to , [0 ,30 ,0 ,0 ], Qt .AlignmentFlag .AlignLeft )
617+ #
618+ label = QLabel ("Message:" )
619+ movable_widget (message_send_qbox , label , [0 ,5 ,0 ,0 ], Qt .AlignmentFlag .AlignRight , Qt .AlignmentFlag .AlignTop )
620+ #
621+ self .message_msg = QLineEdit ()
622+ self .message_msg .setMinimumWidth (400 )
623+ self .message_msg .setFont (self .mono_font )
624+ self .message_to .setMaxLength (99 ) # max message length for HamMessenger is 99 chars for now
625+ movable_widget (message_send_qbox , self .message_msg , [0 ,30 ,0 ,0 ], Qt .AlignmentFlag .AlignLeft )
626+ #
627+ button = QPushButton ("Send" )
628+ button .clicked .connect (self .send_message )
629+ movable_widget (message_send_qbox , button , [0 ,0 ,0 ,3 ], Qt .AlignmentFlag .AlignLeft )
630+ #
631+ message_send_qbox .setSpacing (0 )
632+ message_send_qbox .addStretch ()
633+ #
634+ self .msg_layout .addLayout (message_send_qbox )
635+
603636 def filter_log_entries (self , selected_tag ):
604637 self .log_output .clear ()
605638 for entry in self .log_entries :
@@ -640,6 +673,44 @@ def toggle_connection(self):
640673 self .connect_button .setText ("Disconnect" )
641674 self .status_label .setText (f"Connected to { port } " )
642675
676+ def parse_callsign_ssid (self , s ):
677+ # Normalize dash types: convert en dash (–) to hyphen (-)
678+ s = s .replace ("–" , "-" )
679+
680+ # Match callsign and SSID
681+ match = re .match (r"^([A-Z0-9]+)-(\d+)$" , s , re .IGNORECASE )
682+ if match :
683+ callsign , ssid = match .groups ()
684+ return callsign .upper (), ssid
685+ else :
686+ return s .upper (), "" # If no SSID, return full string as callsign
687+
688+ def send_message (self ):
689+ to = self .message_to
690+ msg = self .message_msg
691+ if not to or not msg :
692+ return
693+ if self .serial_thread and self .serial_thread .isRunning ():
694+ # CMD:Message:<Recipient Callsign>:<Recipient SSID>:<Message>
695+ callsign , ssid = self .parse_callsign_ssid (to .text ())
696+ text = f"CMD:Message:{ callsign } :{ ssid } :{ msg .text ()} "
697+
698+ self .serial_thread .write (text + "\n " )
699+
700+ timestamp = datetime .now ().strftime ("[%H:%M:%S]" )
701+ msg_entry = {
702+ "text" : f"{ timestamp } TX: From: { self .my_callsign } To: { to .text ()} Message: { msg .text ()} \n " ,
703+ "tag" : "Sent"
704+ }
705+ self .msg_entries .append (msg_entry )
706+ self .render_msg_entry (msg_entry )
707+
708+ self .message_msg .clear ()
709+ self .message_msg .setFocus ()
710+
711+ else :
712+ QMessageBox .warning (self , "Not Connected" , "No serial connection is active." )
713+
643714 def send_serial_command (self ):
644715 text = self .command_input .currentText ().strip ()
645716 if not text :
@@ -748,7 +819,7 @@ def handle_serial_data(self, line):
748819 if packet .data_type_id == ":" : # is a message
749820 # :NOCALL-3 :Hi!{006
750821 msg_entry = {
751- "text" : f"{ timestamp } From: { packet .source } To: { packet .addressee } Message: { packet .message } \n " ,
822+ "text" : f"{ timestamp } RX: From: { packet .source } To: { packet .addressee } Message: { packet .message } \n " ,
752823 "tag" : "Received" if packet .addressee == self .my_callsign else "Message"
753824 }
754825 self .msg_entries .append (msg_entry )
0 commit comments