Skip to main content

The swiss_micros packages

I wrote these two packages so I would only have to parse the console once. dm_set_time already uses them; dm_receive and dm_send will. If you only wanted to set the clock, the section index is enough.

Two packages, one rule #

I keep calculator-facing literals in Swiss_Micros.Console_IO. I keep flags in the GetOpt hierarchy that starts at Swiss_Micros.Command_Line.

Serial console (Swiss_Micros.Console_IO) #

The calculator presents a line-oriented console at 38400 8N1, no flow control. It emit the prompt twice on purpose so a it’s easier for a line-based reader to parse. AdaCL.Serial_IO.Expect can do both: Line and character based prompts.

VOYAGER >>
VOYAGER >>

UART parameters and the console verbs live in Swiss_Micros.Console_IO:

Constant Console text Meaning
Help ? List console commands
Key_Press p Inject a key
Dump_Memory s Save memory toward the host (dm_receive)
Load_Memory l Load memory from the host (dm_send)
Console_Timeout ct Console idle timeout (minutes)
Invoke_Bootloader bootloader Enter the firmware bootloader
Get_Time t Read the clock. Reply: 2026-09-22 18:09:26 TUE
Set_Time ts Set an absolute clock. Argument: compact YYYYMMDD HHMMSS
Update_Time td Shift the clock by a minute offset (DST). Not a timestamp
Toggle_Keyboard_Output kb Keyboard trace
Toggle_Display_Output d Display trace
Read_Battery_Voltage b Battery voltage

Get_Time and Set_Time do not share a format. I learned that the hard way. t prints %Y-%m-%d %H:%M:%S %a with the weekday upper-cased. ts accepts only the fifteen-character compact stamp. td is a minute delta, not a third layout.

Date_Time_Image builds only the ts stamp. Pass Use_UTC => True when I want GMT instead of the local offset.

I open the port with USB_Serial_Speed, Bits, Stop_Bits, Parity, and Flow. I wait for Prompt, write a verb plus arguments, wait for the prompt again. That is the whole protocol. dm_set_time also drops ct 1 first so the console does not sit open after the programme leaves.

Command line (Swiss_Micros.Command_Line) #

AdaCL.Command_Line.GetOpt is object-oriented, re-entrant, and hierarchical. The second property is the one that pays off here: common options live on a shared tagged type; each tool extends that type instead of copy-and-pasting flags.

AdaCL.Command_Line.GetOpt.Object
        ↑
Swiss_Micros.Command_Line.Object     --  -d / --device / DM_SERIAL_DEVICE
        ↑
<tool-specific Object>               --  e.g. -u / --utc on dm_set_time

Swiss_Micros.Command_Line.Object already:

  • accepts -d / --device;
  • seeds Device from DM_SERIAL_DEVICE if the flag is absent;
  • raises Option_Missing_Error when neither source supplies a device;
  • prints the device help block, then calls the inherited Write_Help.

A new tool therefore:

  1. derives its options type from Swiss_Micros.Command_Line.Object;
  2. extends Pattern with any extra short flags (dm_set_time appends UTC_Short);
  3. overrides Analyze_GNU / Analyze_Without_Argument / Analyze_File only for new tokens, calling Super in the final else;
  4. calls Super.Parse and Super.Write_Help at the end of its own;
  5. opens the port on This.Device at the Console_IO settings;
  6. speaks the verbs in Console_IO.

I do not copy the device parser. I extend it.

Writing your own tool #

dm_set_time is the working specimen. The child type adds -u / --utc and one operand. Analyze_File is the operand hook — not a file name. It demands length 15 and a Spitbol match: eight decimal digits, a space, six decimal digits. Time returns that operand when it is set; otherwise it calls Date_Time_Image. --utc is ignored once a stamp is present.

The main programme then:

  1. wakes the console with a blank line;
  2. sends ct 1 and waits for the confirmation line plus Prompt;
  3. sends ts and the compact stamp;
  4. sends t and prints whatever came back — that line is the hyphenated form, not the stamp just written.

Sketch of the GetOpt override:

type Object is new Swiss_Micros.Command_Line.Object with record
   Use_UTC : Boolean := False;
end record;

overriding procedure Analyze_GNU (This : in out Object) is
   Super : Swiss_Micros.Command_Line.Object renames
      Swiss_Micros.Command_Line.Object (This);
begin
   if This.Get_GNU_Option = "utc" then
      This.Use_UTC := True;
   else
      Super.Analyze_GNU;
   end if;
end Analyze_GNU;

Worked example: The dm_set_time packages.