The Command Extension feature of MIRTOS allows you to implement changes to the command set supported by MIRTOS. The new commands can be executed using MIRTOS scripting, just as the built-in system commands can. As the Purpose: section of the header below explains, new commands can be added, and any existing commands that are part of the MIRTOS Operating System can be either skipped entirely or modified.
The documentation and source code below can be used to recreate the Command Extensions that came with your MIRTOS-based device. Before copying it into a text file, please read through each section and try to understand what it is doing. This code is meant to be both starting point and example. The online documentation (using '?') can be changed or deleted. Please change or delet the examples provided by the '4' through '8' commands, for example. They are only there to provide simple examples.
The source code file name DefCmdExts.Asm (for Default Command Extensions) is used by this example. You may want to add a blank line or two between blocks of copied code in order to improve readability.
/****************************************************************************** * * Command Extensions * * Purpose: Allow interception of any command passed to the Operating System's * Command Processor, so the command can be selectively inspected, * augmented, discarded, replaced, or otherwise handled before the * system parses and takes any action upon that command. * * Assumes: The original Command Extensions that came with MIRTOS begin at * FLASH adddress 0x2C00 for the help strings and at 0x3600 for the * the start of the code in the 328P. In both the 1284P and 2560, * help strings begin at address 0x0E400 and the code at 0x0EE00. * * This is more of a reminder, actually. Preserve Register R26 when * when changing it to set a 3-BYTE FLASH pointer in the 1284P or * 2560 (i.e., when RAMPZ is defined.) Also, do not assume that * R27:R26 points to the beginning of the parsing buffer. If there * are spaces preceding the first command character, for example, * R27:R26 will be advanced to account for the number of spaces to * be skipped. * * Passed: R31:R30 *CommandExtensions (this subroutine's address via ICALL) * R29:R28 pointer to uVars.B[0] * R27:R26 pointer to the bBuffer being parsed (format notes below): * R23 third buffered character3, uppercase (but may be 0) * R22 second buffered character, uppercase (but may be 0) * R21 first buffered character, uppercase; the command byte * R20 string length, or buffered byte count * R19:R18 the WORD address of the jump table handler * * Returns: ZERO FLAG TRUE (or set) if NOT handled, FALSE if it was handled * (Note that the very first command upon return is a BRNE past * the default Operating System command handler to the EXIT.) * * Alters: If desiring the default command processor to handle it in its * usual way (i.e., not intercepted), the only changes that can be * safely made are to the FLAGs, R0, R18, R19, R24, R25, R30, and * R31. When no further system command processing is to be done, * all of those plus R20 to R23 may be changed without consequence. * Save and restore the state of all other Registers used. With * the exception of R26 and R27 also being available, these are * the customary Register usage rules for all subroutines. * * Notes: If unit serial number is invalid, this routine is not be called. * * The expected buffer format on entry: * +-------+-------+------+------+-/ /-+----+-/ /-+---+---+ * R27:R26 --> | Byte |Command| Byte | Byte | |NULL| | | | * pointer | Count | Char | #2 | #3 | ... |(=0)| ... | 0 | 0 | * +-------+-------+------+------+-/ /-+----+-/ /-+---+---+ * in: R20 R21 R22 R23 ^ string terminator * * To activate this code, first write the iHEX image to FLASH then * update the WORD pointer at EEPROM address 0x46 (= 70 decimal) to * point to the start of the code, NOT where the help strings begin. * When using the addresses below, this MIRTOS command would be: * "EW 70 = 0x3600" in the 328P MCU or, * "EW 70 = 0xEE00" in the 1284P or 2560. * Enter the address of CommandExtensions, not CSZ_HelpStrings. * * The code may be placed at another non-system address in FLASH, * as long as it is above address 0x0100 and below address 0x3FAD * in the 328P and 0x0FFFF in either the 1284P or 2560. * ******************************************************************************/
The Assembler instructions begin at the start of the next block. Notice that the first few lines verify that some target microcontroller is specified. Multiple MCUs are supported through conditional assembly. The .ORGs allow you to change where the Assembler is to begin placing code in FLASH memory. All of the character strings are placed after that. None of them include a Carriage Return or a New Line ("\r\n" = 0x0D, 0x0A) character, since MIRTOS automatically sends both characters after each NULL-terminated string is output. It stops upon encountering the first empty string (i.e., a string of zero length, which is when the first BYTE is zero.) That means that the help string block must end with two (2) consecutive NULL BYTEs in order to terminate help output.
.IFNDEF PROCESSOR ; You may want to explicitly specify an MCU PROCESSOR = 328 ; above, but if not ... .PRINT "Default 328P processor selected." .ENDIF .INCLUDE "CommonDefs.Def" ; TRUE, FALSE, YES, NO, BIT_PV_*, et.al. .INCLUDE "BinDefs.Def" ; The B0 to B11111111 definitions .IF PROCESSOR == 328 .INCLUDE "IOM328P.Def" ; Register definitions for the ATmega328P .INCLUDE "Addresses328.Def" ; All 328P system routines' Jump Table addresses .INCLUDE "SystemSRAM328.Def" ; Names & addresses of 328P system SRAM variables .ORG 0x02C00 .ELSE .ORG 0x0E400 .IF PROCESSOR == 1284 .INCLUDE "IOM1284P.Def" .INCLUDE "Addresses1284.Def" .INCLUDE "SystemSRAM1284.Def" .ELSE .INCLUDE "IOM2560.Def" .INCLUDE "Addresses2560.Def" .INCLUDE "SystemSRAM2560.Def" .ENDIF .ENDIF .INCLUDE "SystemEEPROM.Def" ; Names and addresses of system EEPROM variable .INCLUDE "SystemFLASH.Def" ; Names and addresses of system FLASH constants
The next source code block is rather long, but it contains all of the online help strings which are output in response to the "?" command. Since strings take up so much FLASH, the online help was done this way so they are more easily removed or changed. Be sure to copy the entire block below.
/****************************************************************************** * * Assumes: The HelpStringTable and all the strings pointers which is contains * all point into the same segment (i.e., the same ACSZ_* >> 16.) * * Notes: This series of constant Help Strings leaves only a few BYTEs * between itself and the CommandExtensions() subroutine. An easy * way to allocate more FLASH for help strings is to change the .ORG * statements in the conditional above to lower addresses. * ******************************************************************************/ CSZ_HelpStrings: ; Each an ASCIIz string (i.e., NULL terminated) .STRING "? displays this help sequence (** - means intercepted)" .STRING "0 turns all 3 EISP test outputs (B0, B1, and B2) OFF" .STRING "1 turns those same 3 EISP test outputs all ON" .STRING "2 integer to 2 post-decimal digits formatting example" .STRING "3 same as '2', except to 3 digits" .STRING "4 same as '2', except to 4 digits (**)" .STRING "5 same as '2', except to 5 digits (**)" .STRING "6 same as '2', except to 6 digits (**)" .STRING "7 was unused (**)" .STRING "8 was unused (**)" .STRING "9 displays command line parsing results" .STRING "A displays an Analog value (0 to 10)" .STRING "B0 (in Manager mode) reloads Boot Block at FLASH address 0" .STRING "C calculates a CRC over a string" .STRING "D displays EEPROM, SRAM or FLASH memory contents" .STRING "E allows EEPROM or SRAM to be edited, copied, filled, or zeroed" .STRING "F displays the MCU fuse (0, 2, 3) or lock (1) bytes" .STRING "G displays the MCU signature (0, 2, 4) or OSCCAL (1) bytes" .STRING "H displays last 10 (H*) or all 24 (H**) MCU signature bytes" .STRING "I (unused)" .STRING "J first letter of input for the Admin level password" .STRING "K signed LONG division example with results in Registers" .STRING "L ULONG division example (or) lock/logout/logoff" .STRING "M displays HEAP and STACK memory usage and slack bytes" .STRING "N accesses the nRF24L01+ command set" .STRING "O sends ON or OFF commands to outputs 0 through 5" .STRING "P accesses the WS2812 pixel command set" .STRING "Q example of the PushAll() and PopAll() subroutines" .STRING "R displays the MCU Registers, and (optionally) the stack contents" .STRING "S displays the script pointer and/or allows it to be changed" .STRING "T updates the system time, weekday, date, and year" .STRING "U is the same as typing \"DU\" - display uVars.B[] array" .STRING "V (same as 'U')" .STRING "W (unused)" .IF PROCESSOR == 328 .STRING "X erases a 128-byte block of FLASH" .ELSE .STRING "X erases a 256-byte block of FLASH" .ENDIF .STRING "Y tests the Watchdog timer function (only in Admin mode)" .STRING "Z allows access to the sleep mode BYTE" .STRING ": parses iHex strings into EEPROM, SRAM or FLASH memory" .STRING "; starts a comment; disregards the line that point on" .STRING "< decreases the CPU speed and revises UBRR to maintain the COM rate" .STRING "= displays the Registers, with R24 = CPU MHz" .STRING "> increases the CPU speed and adjusts UBRR to keep the same COM rate" .STRING "@ call a subroutine (in Manager mode) or single step a Pixel sequence" .STRING " " ; (this is just a spacing line) .STRING " toggle keys (first byte on a line; display suppressed):" .STRING "_ serial port received character echoing" ; BIT_SER_ECHO .STRING "' show command before processing" ; BIT_SER_SHOWCMD .STRING "# EEPROM write access notifications" ; BIT_DDT_EEPROM .STRING "[ suppress script change info" ; BIT_SER_QUIET .STRING "] reports as script lines are processed" ; BIT_DDT_SCRIPT .STRING "\" shows nRF block details (with ICALLs)" ; BIT_DDT_DETAILS .STRING "+ shows sequencer mode change summaries" ; BIT_DDT_SEQCHG .STRING ") shows sequencer search details" ; BIT_DDT_SEARCH .STRING "} register dump and optional stack dump" ; BIT_DDT_REGS .STRING " reserved user-defined firstkeys (MIRTOS only toggles them)" .STRING "* in bFlags_Debug (meant for LEDs)" ; BIT_DDT_LEDS .STRING "% in bFlags_Debug" ; BIT_DDT_USER .STRING "^ in bFlags_Serial" ; BIT_SER_UPARROW .STRING "| in bFlags_Serial" ; BIT_SER_VERTBAR HelpStringTrailer: .BALIGN 256, 0, 255 .INCLUDE "DefCmdExts.Ptr" ; Or the file name which you've chosen .IFNDEF ACSZ_HelpStrings .PRINT "Assemble again to initialize label addresses." ACSZ_HelpStrings = 0x2D00 AHelpStringTrailer = 0x3600 .ENDIF .IF PROCESSOR != 328 ; Not needed for the 328P (Max = 0x7FFF) AHH_FirstHelpString = ACSZ_HelpStrings >> 16 AHH_HelpTrailer = AHelpStringTrailer >> 16 .IF AHH_FirstHelpString != AHH_HelpTrailer .ERROR "BYTE 3 of first Help String and Help Trailer differ!" .ENDIF .ENDIF
In this next short section, there are two additional "First Key" selection options which have been commented out and are shown as "greyed out" text. This is the only place in this example where this is done. It is just intended to be a reminder to discern lines which might look like code, but are really just comments. It also shows the use of bFlags_Debug, which is another system BYTE that has flags (i.e., BITs) for your use.
Source code for the "DumpParsingBuffer" routine is also included as part of the published Command Extension source made available.
/****************************************************************************** * * Note: The term "command buffer" is also be called the "parsing buffer", * although those terms might not ALWAYS be synonymous. * ******************************************************************************/ .IF PROCESSOR == 328 .ORG 0x03600 .ELSE .ORG 0x0EE00 .ENDIF CommandExtensions: ; Example of how to use debugging output CALL ADumpRegisters ; The firstkey "}" toggles DumpRegisters() PUSH R31 ; Optional code to dump the parsing buffer ;---------- ;UserFlag_Option1: ; on one of three user firstkey toggles; IN R31, bFlags_Serial ; bFlags_Serial = GPIOR2 (at SRAM 0x4B); SBRC R31, BIT_SER_UPARROW ; The "^" firstkey toggles this flag;UserFlag_Option2: IN R31, bFlags_Serial ; The "|" firstkey toggles this flag SBRC R31, BIT_SER_VERTBAR;UserFlag_Option3: ; LDS R31, bFlags_Debug ; The "%" firstkey toggles this flag; SBRC R31, BIT_DDT_USER ; If the flag is OFF, skip over the RCALL;---------- RCALL ADumpParsingBuffer ; Display the parsing (or command) buffer POP R31 ; Restore the stack
This is where the first character of the commands to intercept or add are
checked and the service routine for each selected. Since each check is
followed by a
CmdExt_CheckCommand: CPI R21, '?' ; If the command began with the key '?' BREQ ACmdExt_Question ; jump to that subroutine CPI R21, '4' ; If it was a '4', suppress whatever that BREQ ACmdExt_Handled ; key did CPI R21, '5' ; If it was a '5', check a little further BREQ ACmdExt_5 ; before deciding what to do CPI R21, '6' ; If it was '6', jump there BREQ ACmdExt_6 CPI R21, '7' ; Similiarly, if it was '7', jump there BREQ ACmdExt_7 ; (and so on) CPI R21, '8' BREQ ACmdExt_8 CPI R21, 'U' ; uVars.B (or "V Register") indexed access BREQ ACmdExt_UorV CPI R21, 'V' BREQ ACmdExt_UorV ; CPI R21, 'W' ; Call a subroutine at a specific address ; BREQ ACmdExt_W ; in FLASH (at 0x1000, as coded below) CmdExt_NotHandled: SEZ ; Set the ZERO flag to inform the calling RET ; subroutine "NOT HANDLED" (you do it)
The code below causes all of the help strings to be output to the COM1 serial port. It "blocks", meaning that that it completes execution before returning to the caller. It continues looping and printing strings until the first zero-length string (or "NULL string") is encountered. This method allows the help string block to be easily changed.
;------------ CmdExt_Question: CPI R20, 1 ; If the command was the single character, BRNE ACmdExt_NotHandled ; '?', handle it here, otherwise, just AHH_FirstHelpString = ACSZ_HelpStrings >> 16 AHi_FirstHelpString = (ACSZ_HelpStrings >> 8) & 0xFF ALo_FirstHelpString = ACSZ_HelpStrings & 0xFF .IF PROCESSOR > 328 LDI R26, AHH_FirstHelpString ; Needed if FLASH address can be > 0xFFFF .ENDIF LDI R31, AHi_FirstHelpString ; Point 'Z' at the first help string LDI R30, ALo_FirstHelpString ; Note: print routines leave 'Z' unchanged CmdExt_HelpPrintLoop: MOVW R24, R30 ; Point R25:R24 at the next string and CALL AstrlenPGM ; determine its length; if the ZERO flag BREQ ACmdExt_Handled ; is set upon return, its a NULL string MOVW R22, R30 ; Save the pointer to the string that was ADD R30, R24 ; just checked and add the string length ADC R31, R25 ; + 1 (for the NULL) to 'Z' to set it up ADIW R30, 1 ; for the next loop MOVW R24, R22 ; Restore the pointer to the string which CALL APrintASCIIz ; was just checked then print it CALL APrintNewLine ; After each string, print a CR then a LF RJMP ACmdExt_HelpPrintLoop ; Loop back to check the next string
The next little block only generates six (6) BYTEs into the assembly
image downloaded to the device. It shows how the
Register R1 is used for zero comparisons since it should always have the value zero, or if used, the value zero restored into it. R22 contains the second BYTE in the command buffer, which is the NULL command string terminator for single-character commands. If it is a multiple-character command, the first RJMP is taken, otherwise, for single-character commands, the second RJMP is taken.
;------------ CmdExt_5: ; This is as terse as it can be CPSE R22, R1 ; Process as before if a nonzero character RJMP ACmdExt_NotHandled ; is found after the '5', otherwise RJMP ACmdExt_Handled ; suppress the prior keystoke handling
Next is the code which handles any commands that begin with the number "6". To support multiple processors and multiple possible source code locations, this code has nested conditional assembly blocks. Precisely one (1) of the five (5) RCALLs below is assembled into the output image. Like the "5" command above, this only generates six (6) BYTEs in the assembled image, regardless of the processor selected.
;------------ .IFNDEF ACSZ_Key6 ACSZ_Key6 = 0 ACSZ_Key7 = 0 .ENDIF AHH_CSZ_Key6 = ACSZ_Key6 >> 16 AHi_CSZ_Key6 = (ACSZ_Key6 >> 8) & 0xFF ALo_CSZ_Key6 = ACSZ_Key6 & 0xFF CmdExt_6: LDI R25, AHi_CSZ_Key6 ; Method 1: limited Register access LDI R24, ALo_CSZ_Key6 .IF PROCESSOR == 328 RCALL ACmdExt_PrintASCIIz .ELSE .IF AHH_CSZ_Key6 == 0 RCALL ACmdExt_PrintASCIIz_0 .ENDIF ; of ".IF AHH_CSZ_Key6 == 0" .IF AHH_CSZ_Key6 == 1 RCALL ACmdExt_PrintASCIIz_1 .ENDIF ; of ".IF AHH_CSZ_Key6 == 1" .IF AHH_CSZ_Key6 == 2 RCALL ACmdExt_PrintASCIIz_2 .ENDIF ; of ".IF AHH_CSZ_Key6 == 2" .IF AHH_CSZ_Key6 == 3 RCALL ACmdExt_PrintASCIIz_3 .ENDIF ; of ".IF AHH_CSZ_Key6 == 3" .ENDIF ; of ".IF PROCESSOR == 328"
These are the last two (2) of the four (4) exit points shared among the Command Extension routines. The first one is CmdExt_NotHandled, which was already encountered above. The last one is CmdExt_HandledPopAll, which is the CmdExt_7 subroutine exit in the code block after this one.
CmdExt_Handled: CLZ ; Set ZERO to indicate the "command was CmdExt_JustReturn: ; handled" in the return (or if the flag RET ; is already set, just exit)
This subroutine handles any commands that begin with the number "7". Compare it with CmdExt_6 above. Notice how this subroutine starts with a CALL to PushAll and ends with a JUMP to PopAll. This is a good method when more than just a few Registers need to be preserved using PUSH and POP, and execution time is not of higher importance. This is often the case in a command handler. This routine and the one above each just print a string and exit. They are provided as examples and starting points for your command extensions.
;------------ AHH_CSZ_Key7 = ACSZ_Key7 >> 16 AHi_CSZ_Key7 = (ACSZ_Key7 >> 8) & 0xFF ALo_CSZ_Key7 = ACSZ_Key7 & 0xFF CmdExt_7: ; Method 2: for access to all Registers, RCALL ACmdExt_PushAll ; start with PushAll() LDI R25, AHi_CSZ_Key7 LDI R24, ALo_CSZ_Key7 .IF PROCESSOR == 328 RCALL ACmdExt_PrintASCIIz .ELSE .IF AHH_CSZ_Key7 == 0 RCALL ACmdExt_PrintASCIIz_0 .ENDIF ; of ".IF AHH_CSZ_Key7 == 0" .IF AHH_CSZ_Key7 == 1 RCALL ACmdExt_PrintASCIIz_1 .ENDIF ; of ".IF AHH_CSZ_Key7 == 1" .IF AHH_CSZ_Key7 == 2 RCALL ACmdExt_PrintASCIIz_2 .ENDIF ; of ".IF AHH_CSZ_Key7 == 2" .IF AHH_CSZ_Key7 == 3 RCALL ACmdExt_PrintASCIIz_3 .ENDIF ; of ".IF AHH_CSZ_Key7 == 3" .ENDIF ; of ".IF PROCESSOR == 328" CmdExt_HandledPopAll: CLZ ; Set "command handled" before jumping to RJMP ACmdExt_PopAll ; PopAll(), which preserves all FLAGs
The next example is the extension executed when "8" is entered.
The
Rather than blindly calling Display_Vin, this example demonstrates the
use of the MIRTOS ICALL_IfValid_PGM function. The target subroutine's
address is loaded into R25:R24 and checked; if the WORD at that address
(presumed to be an instruction opcode) is neither 0x0000 or 0xFFFF, that
routine will be called. The value 0x0000 is a
;------------ .IFNDEF ADisplay_Vin .IF PROCESSOR == 328 ADisplay_Vin = 0x3840 .PRINT "Setting address ADisplay_Vin = 0x3840." .ELSE ADisplay_Vin = 0xF040 .PRINT "Setting address ADisplay_Vin = 0xF040." .ENDIF .ENDIF AHH_Display_Vin = ADisplay_Vin >> 16 AHi_Display_Vin = (ADisplay_Vin >> 8) & 0xFF ALo_Display_Vin = ADisplay_Vin & 0xFF CmdExt_8: ; Replace the '8' keypress ;---------- ; CALL ADisplay_Vin ; Rather than call it directly, ... ; RJMP ACmdExt_Handled ;------ better: LDI R25, AHi_Display_Vin ; Use the system routine which will first LDI R24, ALo_Display_Vin ; verify that that address is not 0xFFFF CmdExt_IfValidPGM: ; Call the subroutine which displays the CALL AICALL_IfValid_PGM ; value the Vcc, as the MCU chip sees it RJMP ACmdExt_Handled ; This is the common If_Valid exit point ; The ICALL_IfValid_PGM above uses a 2-BYTE (i.e., R25:R24) pointer. ; Either of these accept a 3-BYTE (i.e., R26:R25:R24) pointer: ; CALL AICALL_IfValid3BYTE_PGM ; To address 0x3A400 ; CALL AICALL_IfV3_PGM ; To address 0x3AD00 (in hidden FLASH) ; RJMP ACmdExt_Handled
This was simply a single-letter shortcut that was used to execute a longer command. Every line contained in this code block is a comment.
;---------- ;CmdExt_W: ; Replace the 'W' command (now unused) ; LDI R25, 0x12 ; LDI R24, 0x34 ; Point to the address 0x1234 and use the ; RJMP ACmdExt_IfValidPGM ; existing code (so no login is needed)
The default U and V commands built into MIRTOS also have a Command Extension that comes with the Operating System. Due mainly to size and the ability to seperate them into another file, the source code and documentation for these subroutines is contained on a separate U or V Command Extension page.
If you have no need for these commands, omit the next block as can bu
;---------- .INCLUDE "CmdExtUorV.Asm" ; The Assembly command to pull the file in
Rather than have multiple inline 4-BYTE FAR CALLs to and JMPs into the Operating System, this block contains a single FAR JMPs to each of those used above. If access to one of these system routine targets is required twice, using NEAR RCALLs or RJMPs with these generates the same amount of image code, which is 8 BYTEs. After any needs to be accessed more than twice, less code is generated by using these than by using multiple inline FAR CALLs and JMPs. The comment below, embedded in the source code, explains the purpose.
/****************************************************************************** * * These single, shared, local, FAR JMPs to system routine can be reached by * any subroutine in the Command Extensions code using a 2-BYTE RCALL. * ******************************************************************************/ .IF PROCESSOR == 328 ; OPT They do NOT have to be located at these .ORG 0x03776 ; OPT particular addresses; they were placed .ENDIF ; OPT here so they immediately precede the .IF PROCESSOR == 1284 ; OPT the CSZ_Key? strings and the .ORG 0x0EF58 ; OPT DumpParsingBuffer() routine .ENDIF ; OPT Placing them here allows additional .IF PROCESSOR == 2560 ; OPT CmdExt_CheckCommand comparisons and .ORG 0x0EF4C ; OPT 2-BYTE jumps (BREQs) as used above to .ENDIF ; OPT more easily be added later CmdExt_PushAll: JMP APushAll ; Push Registers R31, R30, ... , R1, R0 CmdExt_PopAll: JMP APopAll ; Pop Registers R0, R1, ... , R30, R31 CmdExt_DumpRegisters: JMP ADumpRegisters ; Dump Registers, toggled by '}' firstkey CmdExt_DumpRegs_Begin: JMP ADumpRegs_Begin ; Unconditional Register dump CmdExt_strchr: JMP Astrchr ; Search for a character in a string CmdExt_strcpy: JMP Astrcpy ; Copy a string from SRAM to SRAM
These print subroutines are available to be used by all routines within the Command Extension block. Conditional assembly is used so only those for the target processor are assembled into the output file. The last two lines generate the character strings that two of the extension subroutines above output.
.IF PROCESSOR == 328 CmdExt_PrintASCIIz: ; Print a string that is in FLASH memory, JMP APrintASCIIz ; passing the pointer to it in R25:R24 .ELSE ; These two are for both 1284P and 2560 CmdExt_PrintASCIIz_0: PUSH R26 ; Set the MSByte of the string's address LDI R26, 0 ; to 0 CmdExt_PrintASCIIz_Common: CALL APrintASCIIz ; Print a string that is in FLASH that POP R26 ; is in FLASH using R26:R25:R24 as the RET ; pointer to it, restore R26, and exit CmdExt_PrintASCIIz_1: PUSH R26 LDI R26, 1 ; Set the string address MSByte to 1 RJMP ACmdExt_PrintASCIIz_Common; .IF PROCESSOR == 2560 CmdExt_PrintASCIIz_2: ; For the 2560, the other 2 possibilities PUSH R26 ; are addresses at 2:R25:R24 and ... LDI R26, 2 ; RJMP ACmdExt_PrintASCIIz_Common; CmdExt_PrintASCIIz_3: PUSH R26 LDI R26, 3 ; ... and 3:R25:R24 RJMP ACmdExt_PrintASCIIz_Common; .ENDIF ; of ".IF PROCESSOR == 2560" .ENDIF ; of ".IF PROCESSOR == 328" ;----------------------------------- CSZ_Key6: .STRING "Keypress '6' handler\r\n" CSZ_Key7: .STRING "Keypress '7' handler\r\n"
DumpParsingBuffer is an optional subroutine included in the default MIRTOS Command Extensions. You might have noticed the call to it between the blocks of greyed out comments at the at the beginning of this page. It can be toggled on or off using the "|" (vertical bar) firstkey as it is shown there in the source code.
The DumpParsingBuffer source code and documentation are contained on a different page. In order to build the Command Extensions image file to the same image that it came in MIRTOS, this subroutine should be included in the DefCmdExts.Asm source code file at this point, as shown in this last block.
.INCLUDE "DumpParsingBuffer.Asm" ; The Assembly command to pull the file in .BALIGN 16, 0xFF, 15 ; Pad out to sentence boundary with 0xFFs
The next step is to create the source code file from the sixteen (16) source code blocks above. One way to do it without using a word processing program is shown below. After all of the source code blocks have been copied and the file closed (using Control-Z), the file size of the resulting DefCmdExts.Asm should be about 21,500 BYTEs. Certainly, if you're more familiar with a word processing program that can create pure text, by all means, use it.
The second step is to create the initial DefCmdExts.Ptr file. It can contain a single blank line or a comment line. It will get rebuilt by the Assembly batch process but needs to have an initial file to open or the Assembler will exit with "Error: can't open DefCmdExts.Ptr" and create nothing.
C:\TestDir> Copy CON DefCmdExts.Asm (copy and paste all sixteen (16) code blocks above) ^Z 1 file(s) copied. C:\TestDir>Copy CON DefCmdExts.Ptr ; (a single space or this line then Enter and Control-Z) ^Z 1 file(s) copied. C:\TestDir>
If CmdExtUorV.Asm and DefCmdExts.Asm are to be included, be sure that they have been created before issuing the first Assemble command below. Remember to Assemble three times. The first time should recreate the DefCmdExts.Ptr file with all labeled addresses. The second time imports all of those addresses constants and inserts them into JUMP, CALL, and STRING addresses. If any JMP or CALL changed to a RJMP or RCALL, some labeled address might change. This will be reflected in the .Ptr file. The third Assembly should create the final downloadable image. The three (3) Assemble commands should result in screen output similar to the results shown below.
C:\TestDir> Assemble DefCmdExts Default 328P processor selected. Assemble again to initialize label addresses. Setting address ADisplay_Vin = 0x3840. Assemble again to define ACSZ_PBHeader. C:\TestDir>Assemble DefCmdExts Default 328P processor selected. Setting address ADisplay_Vin = 0x3840. C:\TestDir>Assemble DefCmdExts Default 328P processor selected. Setting address ADisplay_Vin = 0x3840. C:\TestDir>
It's always a good practice to search the resulting .Dmp Assemble listing file for any unresolved NEAR RJMP or RCALL instructions. Simply search for the string ".+0" to do that. There should be none in the CmdExtUorV.Dmp file created.
To change the target processor, open DefCmdExts.Asm in a text processor and find the line that with ".IFNDEF PROCESSOR" (above line 68.) This should be the first line which is not a part of the header comment. Insert a line before that and put "PROCESSOR = 1284" or "PROCESSOR = 2560" on that line, save, and close the file. All constants are case sensitive. Replace the DefCmdExts.Ptr with a one again containing the single blank line. Run the Assemble batch file three times.
* in the 328P and 0x0FFFF in either the 1284P or 2560. * ******************************************************************************/ .IFNDEF PROCESSOR ; You may want to explicitly specify an MCU PROCESSOR = 328 ; above, but if not ... .PRINT "Default 328P processor selected." .ENDIF
Before and after example.
* in the 328P and 0x0FFFF in either the 1284P or 2560. * ******************************************************************************/ PROCESSOR = 1284 ; Insert this line to select the MCU .IFNDEF PROCESSOR ; You may want to explicitly specify an MCU PROCESSOR = 328 ; above, but if not ... .PRINT "Default 328P processor selected." .ENDIF
The DefCmdExts.Hex file contains the final iHex image and its trimmed version is in the DefCmdExts.Trm file. Its memory usage is from 0x2C00 through 0x37FF (3,072 BYTES) in the 328P and from 0x0E400 to 0x0EFEF (3,056 BYTEs) in both the 1284P and 2560.
For .TRM files which contain only a few lines, it's simplest just to copy and paste into the CommTool terminal buffer. But for larger files like this one (over 9,000 BYTEs), it easier to configure CommTool to send the file to the your device. To do that, open the CommTool.Cfg file and add a line similar to one of these:
F6=Send DefCmdExts.Trm AF6=Send C:\TestDir\DefCmdExts.Trm ; Accepts Fully Qualified Filenames CF6=Bytewise DefCmdExts.Trm ; Waits for a reply to each BYTE
Use "Bytewise" in place of "Send" if there are synchronization issues when using the "Send" keyword. Of course, you can select which soft Function key to use. "AF6" means Alt-F6, "CF6" is Control-F6 and "SF6" would select Shift-F6. All of the function keys and their Alt, Shift, and Control modified versions can usually be specified. One you've restarted CommTool, make sure that you're logged on in Manager Mode and press the specified function key to transmit the file.