.. include:: header.txt .. comment Heading levels: *** top and bottom , === bottom , --- bottom, +++ bottom *************** AUXROM Keywords *************** .. csv-table:: :widths: 20, 80 :align: left :ref:`AUXERRN ` , "AUXROM Error number when Error 109 is reported" :ref:`AUXREV ` , "Returns the AUX ROMs revision number" :ref:`BOOT ` , "Restarts EBTKS and the Series80 Computer" :ref:`CRTCOLS ` , "Returns # of columns on CRT display" :ref:`CRTCURSCOL ` , "Returns cursor column number" :ref:`CRTCURSOR ` , "Sets cursor to REPLACE/INSERT" :ref:`CRTCURSROW ` , "Returns absolute cursor row number" :ref:`CRTGETTOP ` , "Returns the row# of top of the CRT display" :ref:`CRTON ` , "Blanks/Unblanks CRT" :ref:`CRTREAD$ ` , "Reads from CRT" :ref:`CRTROWS ` , "Returns # of rows on CRT display" :ref:`CRTSETTOP ` , "Sets CRT start row" :ref:`CRTWRITE ` , "Writes to CRT" :ref:`DATETIME ` , "Read the Real Time Clock" :ref:`EBTKSREV$ ` , "Returns a string with EBTKS firmware build date and time" :ref:`HELP ` , "Built-in HELP (in development)" :ref:`KBDBUFFER ` , "Takes over keyboard" :ref:`KBDISKEY ` , "Test if keys in buffer" :ref:`KBDKEY ` , "Returns the next keycode from the keyboard buffer" :ref:`LISTROMS ` , "List all ROMs or just active ROMs" :ref:`MEDIA$ ` , "Returns the name of a LIF image" :ref:`MOUNT ` , "Mount a LIF image on a msus$" :ref:`PEEK ` , "Read a byte from memory or I/O space" :ref:`POKE ` , "Write a byte to memory or I/O space" :ref:`RPEEK ` , "Read a byte from a bank switched ROM" :ref:`RPOKE ` , "Write a byte to a bank switched ROM (dangerous)" :ref:`RSECTOR ` , "Reads a raw 256-byte sector" :ref:`SDATTR ` , "Returns attribute status for a file or directory" :ref:`SDBATCH ` , "Start reading keyboard input from a batch file" :ref:`SDCAT ` , "Display a catalog of the current SD Card directory" :ref:`SDCD ` , "Change the current SD Card directory" :ref:`SDCHAIN ` , "Like the normal CHAIN command, but for the SD Card" :ref:`SDCLOSE ` , "Close an SD Card file" :ref:`SDCOPY ` , "Copy an SD Card file to another SD Card file" :ref:`SDCUR$ ` , "Returns the current SD Card directory" :ref:`SDDEL ` , "Delete an SD Card file" :ref:`SDEOF ` , "Test an open SD Card file for End Of File" :ref:`SDEOL ` , "Set the End Of Line character sequence" :ref:`SDEOL$ ` , "Return the End Of Line character sequence" :ref:`SDEXISTS ` , "Test an SD Card file for existence" :ref:`SDEXPORTLIF ` , "Exports a file from a LIF disk to an SD Card file" :ref:`SDFFIRST ` , "Initializes reading a directory" :ref:`SDFLUSH ` , "Flush any un-written data to an open SD Card file" :ref:`SDFNEXT ` , "Iterative reading of directory entries" :ref:`SDGET ` , "Read a BASIC source file from the SD Card" :ref:`SDHOME$ ` , "Returns the path for the root directory" :ref:`SDIMPORTLIF ` , "Imports a LIF file from the SD Card and write it to a LIF disk" :ref:`SDLOAD ` , "Load a program from the SD Card" :ref:`SDLOADBIN ` , "Load a binary program from the SD Card" :ref:`SDMKDIR ` , "Make a new directory on the SD Card" :ref:`SDMORE ` , "Display a text file, with pagination" :ref:`SDOPEN ` , "Open an SD Card file" :ref:`SDPATH$ ` , "Return a piece of a path" :ref:`SDRDLINE ` , "Read from an SD Card file, End Of Line aware" :ref:`SDREAD ` , "Read from an SD Card file" :ref:`SDREN ` , "Rename (and/or move) an SD Card file" :ref:`SDRMDIR ` , "Delete a directory on the SD Card" :ref:`SDSAVE ` , "Save a BASIC program to the SD Card as ASCII text" :ref:`SDSEEK ` , "Position the read/write pointer for an open SD Card file" :ref:`SDSIZE ` , "Returns the size of an SD Card file" :ref:`SDSLASH ` , "Set the path separation character" :ref:`SDSLASH$ ` , "Report the path separation character" :ref:`SDSTORE ` , "Store a BASIC program as a LIF file on the SD Card" :ref:`SDSTOREBIN ` , "Store a Binary program as a LIF file on the SD Card" :ref:`SDWRITE ` , "Write to an SD Card file" :ref:`SETLED ` , "Set the color and intensity of the two RGB LEDs" :ref:`SPRINTF ` , "Complete control of formatted output, using C sprintf()" :ref:`UNMOUNT ` , "Unmount the LIF image from a msus$" :ref:`WSECTOR ` , "Writes a raw 256-byte sector" :ref:`AUXBUF$ ` , "Low Level AUXROM Interface for developers" :ref:`AUXCMD ` , "Low Level AUXROM Interface for developers" :ref:`AUXOPT$ ` , "Low Level AUXROM Interface for developers" .. comment: :ref:`FLAGS ` , "Low Level internal function" .. index:: AUXROM AUXROM ====== AUXROM is a set of 8 kb ROM images that are the companion firmware for the HP Series 80 computers when the EBTKS board is installed. The primary author of AUXROM is Everett Kaser, and the companion software on EBTKS that AUXROM communicates with was authored by Philip. This page documents the functions that AUXROM implements and also covers the internal architecture of how AUXROMs and EBTKS communicate The AUXROM(s) like all other optional ROMS on the HP-85 execute in an address space window from 060000 to 077777 (octal). This is 8K bytes. At any time only one option ROM can be active, and the ROM is selected by an I/O register named RSELEC. In almost every other respect, the AUXROM is different than any ROM for the HP-85. Some of these differences will be seen by the user, and some just make what happens behind the curtain easier to implement, or allow much faster operation. See :ref:`Memory Map ` for more details Compatibility with Everett's Series 80 Emulator ----------------------------------------------- Many of these features are available in Everett Kaser's Series 80 Emulator, as well as in a real HP-85 with an EBTKS. Some functionality may be slightly different between the two environments, due to differences in the environments. BEWARE: With great power comes great responsibility. You could very easily (were you a person liable to moments of criminal carelessness) delete entire LIF volumes, your configuration file, or your entire hard disk (if you're running this in the Emulator). Be wary. AUXROM Function Overview ------------------------ AUXROM is identified as ROM 361 (octal), but it may also claim adjacent ROM numbers up to 376 (octal), but these additional IDs do not get detected when the HP-85 starts up, and they do not add any new function names or keywords. The AUXROM has many functions for accessing and manipulating files stored on the 16 GB SD card's FAT32 file system. Most of these new Keywords can be included in your programs. They provide the ability to directly use the FAT32 file system, including reading, writing, creating, and deleting both files and directories. File names can be as long as you want (within reason), and you can have nested directories, with long sub-directory names. The FAT32 file access functions are a reasonable subset of the Posix file manipulation functions. For most of the SDxxxx keywords that involve a filename or path, the system (EBTKS or Emulator) keeps track of the "current path," much as MS-DOS or a Windows command line or a unix shell keeps track of a current working directory. The filenames or paths specified in these SDxxxx keywords (functions and statements) may be ABSOLUTE paths (ones starting with a '/' or \\'\\\\' ), or they may be RELATIVE (NOT starting with a slash). RELATIVE paths will automatically be appended, internally, to the "current path" to make them an ABSOLUTE path. By default, the path separator is '/' .. index:: Unquotes file paths and file names Unquoted file paths and file names ++++++++++++++++++++++++++++++++++ In some SDxxxx statements, the filename can be specified either quoted or unquoted. You can't use unquoted if the filename contains a SPACE, @, $, COMMA, or EXCLAMATION POINT character. If it contains one of those, then you'll have to " " the filename to avoid confusing the parser. The SDxxxx statements that will accept either a quoted or unquoted string are: * SDMKDIR * SDRMDIR * SDDEL * SDCD * UNMOUNT * SDSAVE * SDGET * SDMORE * SDLOAD * SDSTORE These statements all have one string argument, with no options for other arguments that could confuse the parser. Other SDxxxx statements that have more than a single string argument MUST use quoted strings. .. index:: AUXROM Error messages AUXROM Error messages ===================== In all of the following documentation, error status is returned in the following ways. **Standard error messages** are from the system ROMs and have values from 1 to 92 and are listed in Apendix E of the HP85A Owner's manual and Programming Guide (page 307). The HP85B manual has the same information (page 381), and the HP86/87 manual has the same information (page 343). EBTKS uses these error numbers where appropriate, and the error numbers are returned in ERRN. **Standard EBTKS error messages** are from 108 (a warning) through to 128 (currently). These error numbers are fairly general and are shared across many EBTKS Keywords. The error numbers are returned in ERRN. **Custom EBTKS error messages** use the Standard EBTKS error messages 109 as a starting point, then add an error message that is specific to the keyword. These error messages display as follows: **Error 109 : Custom text message** For these error messages, as well as ERRN being set to 109, an additional variable AUXERRN is set to a number that is specific to the custom error message. These start at 300. For each keyword on the rest of this page, when an error messages is shown with custom text and an AUXERRN value, it is reported as per the above example, with ERRN set to 109 and AUXERRN set to the listed value. .. index:: Loading emulated LIF disk and tape images .. index:: Unloading emulated LIF disk and tape images Loading and Unloading emulated LIF disk and tape images ======================================================= Throughout this page, the references to msus$ is the same as the traditional Series 80 usage. See the HP Series 80 documentation for details of legal msus$ strings. For MOUNT and UNMOUNT, the "msus$" may refer to EITHER an emulated disk drive (:Dxxx) OR the emulated TAPE drive (:T). The MEDIA for an emulated disk drive is an SD file that emulates the contents of a disk, whereas the MEDIA for the emulated tape drive is an SD file that emulates the contents of a tape. These are NOT interchangeable: a MEDIA created for one device (disk or tape) cannot be loaded into the other emulated device. If the MEDIA gets created, it will be the proper length (containing the proper amount of physical 'records'), and it will be 'initialized'. There is no need to INITIALIZE a new disk image or ERASETAPE for a new tape image. NOTE: With Everett Kaser's HP8X Emulator, all disk images must exist in one of the DISKS0 to DISKS9 sub-folders. For the emulator, Disk images need to be INITIALIZE-ed and Tape images need to be ERASETAPE-ed. There is also a special mode to :ref:`Mount/Unmount the SD Card. ` .. _MOUNT: .. index:: MOUNT MOUNT |_3| msus$, |_| filePath$ |_| [, |_| modeFlag] ---------------------------------------------------- :ref:`Top ` Associate the specified LIF image file with msus$ * msus$ specifies the emulated disk/tape drive that will be associated with the LIF image * filePath$ is the name (maybe with path) of the emulated MEDIA (LIF image). Typically disk LIF images are in the /disks/ directory, and tape images are in the /tapes/ directory. * modeFlag controls what happens if emulated MEDIA exists or not - 0 = error if doesn't exist, else MOUNT (this is the default if not specified) - 1 = if exists, MOUNT, else create blank and MOUNT - 2 = if exists, error, else create blank and MOUNT * There is a special case of the msus$ parameter being "SDCARD" to mount the SD Card, see :ref:`below `. .. note:: **Warning:** |br| (1) There may be a limit to the number of files per directory on the SD Card. On 2023_06_27 during some testing, a directory was created with over 2643 floppy images (files of 270,336 Bytes (264 kB), so treat this as a suggested upper limit, or do your own testing. |br| (2) Restriction: MOUNT can only create new 3.5" floppy images. If you need additional 5 Mb virtual disks, you can create them manually by copying the file /Original_images/Blank_5MB.dsk to /disks/ and re-naming it. An example is /disks/5MB_scr.dsk **Possible Errors** * "Can't resolve path" , AUXERRN will be 330 * "Invalid MOUNT mode" , AUXERRN will be 410 * "MOUNT file does not exist" , AUXERRN will be 411 * "MOUNT MSU$ error" , AUXERRN will be 412 * "MOUNT Filename must end in .tap" , AUXERRN will be 413 * "MOUNT HPIB Select must match" , AUXERRN will be 414 * "MOUNT failed" , AUXERRN will be 415 * "MOUNT Filename must end in .dsk" , AUXERRN will be 416 * "Couldn't open Ref Disk" , AUXERRN will be 417 * "Couldn't open New Disk" , AUXERRN will be 418 * "Couldn't init New Disk" , AUXERRN will be 419 * "While MOUNTing an SD card, failed", AUXERRN will be 406 * "Mounting virtual drives failed", AUXERRN will be 407 * "Couldn't read Ref Disk" , AUXERRN will be 408 * "MOUNT File already exists" , AUXERRN will be 409 * "Couldn't open Ref Tape" , AUXERRN will be 426 * "Couldn't open New Tape" , AUXERRN will be 427 * "Couldn't init New Tape" , AUXERRN will be 428 * "Device code not supported", AUXERRN will be 512 **Examples** - MOUNT ":D300", "/disks/85AssemblerROMdisc.dsk" Uses 0 as the default modeFlag. - MOUNT ":D300", "/disks/NewDisk.dsk", 2 Errors if NewDisk already exists, otherwise creates and MOUNTs it. - MOUNT ":T", "/tapes/DataTape.tap", 1 If "DataTape" exists, MOUNT it, otherwise create a blank SD file called "DataTape" and mount it. .. _UNMOUNT: .. index:: UNMOUNT UNMOUNT |_3| msus$ ---------------------- :ref:`Top ` * msus$ specifies the emulated disk or tape drive from which to remove the current 'emulated' MEDIA file. * There is a special case of the msus$ parameter being "SDCARD" to unmount the SDCard, see :ref:`below `. :ref:`This Keyword supports unquoted names ` (but still needs the :D or equivalent) **Possible Errors** * "UNMOUNT MSU$ error" , AUXERRN will be 490 * "UNMOUNT Disk error" , AUXERRN will be 491 **Examples** * 10 UNMOUNT ":D300" * 20 UNMOUNT ":T" .. _SDCARDMOUNT: .. index:: Mounting the SD Card .. index:: Unmounting the SD Card Mounting and Unmounting the SD Card ----------------------------------- :ref:`Top ` MOUNT and UNMOUNT also support an msus$ of "SDCard" (not case sensitive) that allows removing and installing the SD Card without having to turn the power to the HP85 off and back on. For the MOUNT keyword, it requires a second parameter, which for this usage, can be any string or string variable, since the value is ignored. * UNMOUNT "sdcard" will close all the LIF files for each of the current emulated disk and tape drives. After this keyword is run, it is safe to unplug the SD Card. * MOUNT "SDCard", "A" This keyword should be run after the SD Card is plugged back into the EBTKS. The CONFIG.TXT file is read, and unlike system boot where all the sections of the file are used (setting options, loading ROMs, setting up virtual disks, etc...), re-mounting the SD Card and running the above line, will only process the disk and tape specifications, re-associating the relevant LIF files with their respective msus$. The second parameter is needed to meet the requirements of the Mount keyword, but in this case it isn't used. Any non-empty string will do. .. _MEDIA$: .. index:: MEDIA$ MEDIA$(msus$) ------------- :ref:`Top ` Report the filename of the LIF image associated with the msus$ * msus$ specifies the emulated disk or tape drive for which the currently 'emulated' MEDIA file's name should be returned. **Return Value** * Returns a string that is the full path to the LIF image **Possible Errors** * "MEDIA$ MSU$ error" , AUXERRN will be 510 * "MEDIA$ HPIB Select must match" , AUXERRN will be 511 * "Device code not supported" , AUXERRN will be 512 **Examples** * A$ = MEDIA$(":T") * A$ = MEDIA$(":D301") .. index:: SD Card File Manipulation SD Card File Manipulation ========================= .. _SDATTR: .. index:: SDATTR SDATTR(filePathName$) --------------------- :ref:`Top ` Returns a value that encodes the Attributes of a file or a directory. There are only two types of attributes: * Whether the object is a file or a directory, encoded in bit 0 * Whether the object is normal access, or it is read-only, encoded in bit 1 The two independent attributes are combined into a single returned integer in the range 0 to 3 **Return Value** .. csv-table:: :header: "Bit 1" , "Bit 0", "Return Value", "Meaning" :widths: 10 , 10, 20, 70 :align: center "0","0","0","filePathName$ is a normal read/write access **file**" "0","1","1","filePathName$ is a normal **directory**" "1","0","2","filePathName$ is a **file** with read-only access" "1","1","3","filePathName$ is a **directory** with read-only access" **Possible Errors** * "SD Error" ERRN will be 113. Bad file/pathname or includes wild cards or file/path name not found **Examples** * Example: A = SDATTR("ZINK") .. _SDSIZE: .. index:: SDSIZE SDSIZE(filePathName$) --------------------- :ref:`Top ` **Return Value** * Returns the size of the specified SD file. **Possible Errors** * "SD Error" ERRN will be 113. Bad file/pathname or includes wild cards or file/path name not found .. _SDDEL: .. index:: SDDEL SDDEL |_3| fileSpec$ ------------------------ :ref:`Top ` Deletes the specified SD file (does not work on sub-directories, yet). |br| Wild cards (* and ?) may be used in the filename part of fileSpec$, but not in the path part. :ref:`This Keyword supports unquoted names ` **Possible Errors** * "Can't resolve path" , AUXERRN will be 330 * "SDDEL no file specified" , AUXERRN will be 370 * "Couldn't delete file" , AUXERRN will be 371 * "SDDEL no wildcards in path" , AUXERRN will be 372 * "SDDEL problem with path" , AUXERRN will be 373 .. _SDREN: .. index:: SDREN SDREN |_3| oldName$, |_| newName$ ------------------------------------- :ref:`Top ` Renames the specified file or directory to the new name. Can be used to move files between directories **Possible Errors** * "Can't resolve Old path" , AUXERRN will be 450 * "Can't resolve New path" , AUXERRN will be 451 * "SDREN rename failed" , AUXERRN will be 452 * "SDREN Mystery bug" , AUXERRN will be 453 * "SDREN Old file doesn't exist" , AUXERRN will be 454 .. _SDCOPY: .. index:: SDCOPY SDCOPY |_3| SourceName$, |_| DestinationName$ |_| [, |_| Overwrite] ----------------------------------------------------------------------- :ref:`Top ` Copies the specified Source file to the specified Destination file. If the Overwrite option is not given, or it is 0, then overwriting an existing file is an error. If the Overwrite option is provided and is 1, then an existing file will be overwritten/replaced. |br| Does not support wild cards, yet. |br| Does not support copying a complete directory, yet. |br| SourceName$ and DestinationName$ must be string variables or quoted strings. **Possible Errors** * "Can't resolve Source path" , AUXERRN will be 520 * "Can't resolve Destination path" , AUXERRN will be 521 * "SDCOPY bug in code" , AUXERRN will be 522 * "Source file doesn't exist" , AUXERRN will be 523 * "Couldn't open Source File" , AUXERRN will be 524 * "Couldn't open Destination File" , AUXERRN will be 525 * "File copy failed" , AUXERRN will be 526 * "SDCOPY File already Exists" , AUXERRN will be 527 .. _SDMORE: .. index:: SDMORE SDMORE |_3| SourceName$ |_| [, |_| Paginate] ------------------------------------------------ :ref:`Top ` Displays (types) the SD file to the CRT, optionally 'paginating' it (ala the unix MORE command) if 'paging' is 1. If 'paging' is not specified, then the default is 0 (no paging). This dumps the file to the CRT as fast as it can, and it is NOT redirectable by using the CRT IS statement, it will still go to the CRT. When paging and paused at a page boundary, the RUN key will dump the rest of the file with no further paging/pausing, while -LINE, BACKSPACE, -CHAR, and PAUSE will quit the SDMORE immediately. :ref:`This Keyword supports unquoted names ` **Possible Errors** * "Open failed Mode 0" , AUXERRN will be 422 * "Invalid Mode" , ERRN will be 114 , Paginate should be 0 or 1 .. index:: SD Card File Access SD Card File Access =================== .. _SDOPEN: .. index:: SDOPEN SDOPEN |_3| filePathName$, |_| mode#, |_| file# --------------------------------------------------- :ref:`Top ` Opens a file on the SD card for read/write access. Three different modes support opening existing files for reading-only, or for reading & writing, or for creating or truncating the file. The file is always opened in 'binary' mode, no 'text' mode is supported, except via the SDRDLINE statement. * filePathName$ may be an absolute path to the file or a path relative to the current folder (returned via SDCUR$ and set via SDCD). * mode# - 0 = Error if doesn't exist, else open for READ-ONLY set to START of file. - 1 = Open if exists, create if doesn't, set position to END of file. - 2 = Truncate if exists, create if doesn't, set position to START of file. * file#: A number from 1 to 10. SD file access supports having up to 10 files open at the same time, and each one gets assigned to a file# from 1 to 10. These numbers are different and not related to the Basic ASSIGN buffer numbers, although they serve the same general purpose, just for the SD file system rather than for the Series 80 tape and disk file system. **Possible Errors** * "File is already open" , AUXERRN will be 420 * "Parsing problems with path" , AUXERRN will be 421 * "Open failed Mode 0" , AUXERRN will be 422 * "Open failed Mode 1" , AUXERRN will be 423 * "Open failed Mode 2" , AUXERRN will be 424 * "Open failedIllegal Mode" , AUXERRN will be 425 * "Couldn't open Ref Tape" , AUXERRN will be 426 * "Couldn't open New Tape" , AUXERRN will be 427 * "Couldn't init New Tape" , AUXERRN will be 428 .. _SDCLOSE: .. index:: SDCLOSE SDCLOSE |_3| file# ------------------ :ref:`Top ` Closes a previously opened file. * file# is a file number from 1 to 10 that was used to open the file. * file# is 0 to close all open files **Possible Errors** when file# is 1 to 10 * SD ERROR (213D) if file# was not open ##### needs to be fixed once Auxroms fixed ##### **Possible Errors** when file# is 0 * None. No error is reported if there were no files open **Examples** * 10 SDCLOSE 0 * 20 B = 4 @ SDCLOSE B .. _SDREAD: .. index:: SDREAD SDREAD |_3| dst$Var, |_| bytesReadVar, |_| maxBytes, |_| file# -------------------------------------------------------------- :ref:`Top ` Reads some number of bytes from the already opened SD file, placing the bytes into the destination string variable and the number of bytes read into the bytesReadVar. The number of bytes read will be either maxBytes or the remaining number of bytes in the file, whichever is smaller. .. code-block:: text dst$Var Where the data that is read is stored bytesReadVar Variable that is set to the actual number of bytes read maxBytes Requested number of bytes to read file# File Number **Possible Errors** * "SDREAD File not open" , AUXERRN will be 440 **Example** .. code-block:: text DIM A$[500] SDOPEN "ZINK", 0, 5 SDREAD A$, L, 500, 5 .. _SDRDLINE: .. index:: SDRDLINE SDRDLINE |_3| dst$Var, |_| bytesReadVar, |_| maxBytes, |_| file# ---------------------------------------------------------------- :ref:`Top ` Reads bytes from the file into dst$Var until one of the following occurs: * maxBytes have been read (Note: can't be greater than 1500) * the end-of-file is reached * an EOL-sequence (CR/LF or LF or CR) is seen Sets bytesReadVar to the number of bytes stored into dst$Var. The EOL-sequence is NOT stored in dst$Var. Returns -1 if at end of file. **Possible Errors** * SD ERROR (213D) if file# not open, or general SEEK or READ error. **Example** .. code-block:: text DIM A$[256] SDOPEN "ZINK", 0, 5 SDRDLINE A$, L, 256, 5 .. _SDWRITE: .. index:: SDWRITE SDWRITE |_3| src$, |_| file# ---------------------------- :ref:`Top ` Writes a string to a previously opened SD file. This is a binary mode file operation, no EOL-sequence is automatically written. If you are writing text and wish an EOL-sequence, use SPRINTF and SDEOL$ to format the output string with an EOL-sequence on the end before writing the formatted string to the file. **Possible Errors** * "SDWRITE File not open for write" , AUXERRN will be 480 **Example** .. code-block:: text DIM F$[600] SDOPEN "ZINK",2,5 SPRINTF F$, "Hello, world!%s", SDEOL$ SDWRITE F$, 5 .. _SDEOF: .. index:: SDEOF SDEOF(file#) ------------ :ref:`Top ` A numeric function that tells you how many bytes from the current "file position pointer" to the "end of the file" **Return Value** * Returns 0 if the current file# position is at the end-of-the-file * Returns a positive number if there are bytes from the current file position to the end of the file. **Possible Errors** * SD ERROR (213D) if file# is not open or a general SEEK error occurs. **Example** .. code-block:: text (This needs to be checked) 10 DIM A$[200] 20 SDOPEN "ZINK",0,5 30 SDRDLINE A$, L, 200, 5 40 DISP A$ 50 IF SDEOF(5) THEN 30 60 SDCLOSE 5 70 END .. _SDEXISTS: .. index:: SDEXISTS SDEXISTS(filePathName$) ----------------------- :ref:`Top ` **Return Value** * Returns 0 if the specified file or sub-dir does not exist, otherwise returns 1. **Possible Errors** * none .. _SDFLUSH: .. index:: SDFLUSH SDFLUSH |_3| file# ------------------ :ref:`Top ` Forces any pending (buffered) writes to be flushed to storage. This has no effect when running on the Series 80 Emulator, but when running on the EBTKS, it causes buffers to be written to the SD card. If the file# is 0, then **all** open files are flushed. **Possible Errors** * none .. _SDSEEK: .. index:: SDSEEK SDSEEK(mode#, |_3| offset#, |_3| file#) --------------------------------------- :ref:`Top ` Moves the "current position" pointer in a file to a specified location. The new location can be specified in one of three relative offsets as specified by the mode#: **Return Value** * MODE 0: seek to absolute >=0 offset from start of file * MODE 1: seek to +/- relative position from current point in file * MODE 2: seek to absolute <=0 offset from end of file **Return Value** * New file position **Possible Errors** * "Seek on file that isn't open" , AUXERRN will be 470 * "Trying to seek before beginning" , AUXERRN will be 471 * "Trying to seek past EOF" , AUXERRN will be 472 * "SDSEEK failed somehow" , AUXERRN will be 473 .. _SDSTORE: .. index:: SDSTORE SDSTORE |_3| nameSD$ -------------------- :ref:`Top ` Stores the Basic program currently in memory to an SD file in tokenized form. A "LIF header" is included on the front of the file. This is essentially a shortcut way of doing STORE "filename" and then SDEXPORTLIF "filename","SDname". :ref:`This Keyword supports unquoted names ` **Possible Errors** * FILE/PATH (217D) error in file/path name, or error opening/creating the file * SD ERROR (213D) if write failed to write everything .. _SDLOAD: .. index:: SDLOAD SDLOAD |_3| nameSD$ ------------------- :ref:`Top ` Loads a Basic program into memory from an SD file that was SDSTORE'd. :ref:`This Keyword supports unquoted names ` **Possible Errors** * FILE/PATH (217D) error in file/path name, or error opening/creating the file .. index:: Directory Manipulation Directory Manipulation ====================== .. _SDCAT: .. index:: SDCAT SDCAT |_3| [fileSpec$] ---------------------- :ref:`Top ` Displays a catalog of the SD file system. If no fileSpec$ is provided, "*" is used. fileSpec$ is a string expression which may or may not include wild card characters ('*' and '?'). As much of the file name as possible will be shown on the left of the screen and the filesize on the right. If the file name gets truncated because it's too long to display, the last character that is shown will be underlined. If the file is READONLY, the size value will be underlined. If it's a sub-directory, a '/' is shown for the size, and if it's a READ-ONLY sub-directory the '/' will be underlined. - SDCAT - SDCAT fileSpec$ **Possible Errors** * "Can't resolve path" , AUXERRN will be 330 * "Can't list directory" , AUXERRN will be 331 * "SDCAT no wildcards in path" , AUXERRN will be 333 .. _SDFFIRST: .. index:: SDFFIRST SDFFIRST |_3| name$, |_| date$, |_| size, |_| attrib, |_| fileSpec$ ------------------------------------------------------------------- :ref:`Top ` This keyword initializes an iterative process that delivers catalog lines 1 per call. This command delivers the first catalog line that matches the fileSpec$, and the next command (SDFNEXT) is use to deliver the remainder by repetitive calls. The fileSpec$ is only needed for this keyword. It is remembered for the subsequent SDFNEXT calls. There can only be one active iterative catalog process. If another SDFFIRST occurs before the calls to SDFNEXT have exhausted the current catalog, a new iterative process is started. - SDFFIRST name$, date$, size, attrib, fileSpec$ **Return Values** .. code-block:: text name$ The first catalog entry that matches fileSpec$ An empty string if no catalog entries matches the fileSpec$ date$ The associated date and time size The file size (0 if a directory) attrib The file attributes :ref:`See this for a description of attributes ` **Possible Errors** (due to implementation details, the possible error messages are shared with SDCAT) * "Can't resolve path" , AUXERRN will be 330 * "Can't list directory" , AUXERRN will be 331 * "No SDCAT init or past end" , AUXERRN will be 332 * "SDCAT no wildcards in path" , AUXERRN will be 333 .. _SDFNEXT: .. index:: SDFNEXT SDFNEXT |_3| name$, |_| date$, |_| size, |_| attrib --------------------------------------------------- :ref:`Top ` This keyword must be preceded by a call to SDFFIRST to set up the fileSpec$ (that may include wild cards). The return values are the same as SDFFIRST. Successive calls to this keyword will return successive catalog entries until all have been returned. After the last entry has been returned, the next call will return a name$ that is a string of length 0. This concludes the iterative retrieval of catalog entries. If you make an additional call to SDFNEXT after it has indicated that there are no more entries (length 0 for name$), then an error is reported. **Possible Errors** (due to implementation details, the possible error messages are shared with SDCAT) * "Can't resolve path" , AUXERRN will be 330 * "Can't list directory" , AUXERRN will be 331 * "No SDCAT init or past end" , AUXERRN will be 332 * "SDCAT no wildcards in path" , AUXERRN will be 333 .. _SDCD: .. index:: SDCD SDCD |_3| pathDir$ ------------------ :ref:`Top ` Changes the "current SD directory" to pathDir$. pathDir$ may be a relative path (relative to the CURRENT "current directory," or it may be absolute (starting with a SLASH). :ref:`This Keyword supports unquoted directory paths ` **Possible Errors** * "Can't resolve path" , AUXERRN will be 330 * "Unable to open directory" , AUXERRN will be 340 * "Target path is not a directory" , AUXERRN will be 341 * "Couldn't change directory" , AUXERRN will be 342 .. note: don't need a label like elsewhere in this file because the title is the same .. index:: SDCUR$ SDCUR$ ------ :ref:`Top ` **Return Value** * Returns a string containing the current full (absolute) SD path. **Possible Errors** * none .. note: don't need a label like elsewhere in this file because the title is the same .. index:: SDHOME$ SDHOME$ ------- :ref:`Top ` **Return Value** * Returns a string containing the original starting full (absolute) SD path, the "home" directory. This NEVER changes during any given "power/run cycle." This is always "/" on EBTKS, but is a path on the Everett Kaser Series 80 Emulator **Possible Errors** * none .. _SDMKDIR: .. index:: SDMKDIR SDMKDIR |_3| folderName$ ------------------------ :ref:`Top ` Creates a sub-directory on the SD drive. If multiple sub-directories are included in "folderName$," all of the sub-directories except for the last one must already exist. In other words, you can only create ONE LEVEL of sub-directory at a time. :ref:`This Keyword supports unquoted names ` **Possible Errors** * FILE/PATH (217D) if too long or invalid * SD ERROR (213D) if failed * "SDMKDIR Dir already exists" , AUXERRN will be 400 (maybe some other error) .. _SDRMDIR: .. index:: SDRMDIR SDRMDIR |_3| folderName$ ------------------------ :ref:`Top ` Removes a sub-directory from the SD drive. The sub-directory MUST be empty, or the SDRMDIR will fail. :ref:`This Keyword supports unquoted sub-directories ` **Possible Errors** * FILE/PATH (217D) if too long or invalid * SD ERROR (213D) if failed .. index:: Export/Import Of Series 80 Files Export/Import Of Series 80 Files ================================ .. _SDSAVE: .. index:: SDSAVE SDSAVE |_3| filePath$ --------------------- :ref:`Top ` Saves the currently loaded program to an ASCII SD file (essentially, it lists the program to the file, appending the current SDEOL sequence to the end of each line. This is a non-programmable command. :ref:`This Keyword supports unquoted names ` **Possible Errors** * FILE/PATH (217D) error in file/path name, or error opening/creating the file various system listing errors, primarily ROM MISSING .. _SDGET: .. index:: SDGET SDGET |_3| filePath$ -------------------- :ref:`Top ` Reads a file (usually a file that was created with an SDSAVE command), and parses the lines, attempting to recreate the original program from the ASCII listing of it. This is a non-programmable command. :ref:`This Keyword supports unquoted names ` **Possible Errors** * FILE/PATH (217D) error in file/path name, or error opening the file * BUSY (221D) text buffering is already in use (only one at a time) * Various system parsing errors (could be almost anything if the file was hand edited) NOTE 1: SDGET does **not** do a SCRATCH, so the SDGET'd lines will be edited into the currently in-memory program. If you want a clean slate, do a SCRATCH first yourself. NOTE 2: Although SDGET **will** read in lines > 96 characters in length and parse them, keep in mind that when you list those lines on the screen, you won't be able to edit them on the screen (unless you can remove enough spaces to shrink the line down to what will fit on three lines of the display). Also, the maximum line length that SDGET will read in is 255 characters (which, of course, is WILDLY too long). NOTE 3: If you do an SDGET of assembly language code while in ASSEMBLER mode, you will see the lines echoed on the displayed, likely "inching their way" up the screen when lines with comments are encountered. So it goes. GENERAL FEATURES ================ .. _DATETIME: .. index:: DATETIME DATETIME |_3| Year, |_3| Month, |_3| Day, |_3| Seconds ------------------------------------------------------ :ref:`Top ` Returns four numeric values from the Real Time Clock (RTC). * Seconds is the number of seconds since midnight. Range is 0 to 86399 * Day is the day of the month. Range is 1 to 31 * Month is the month of the year. Range is 1 to 12 * Year is the current year. Range is 1970 to 2038 For example .. code-block:: text DATETIME A,B,C,D DISP "Year";A DISP "Month";B DISP "Day";C DISP "Hours";INT(D/3600) DISP "Minutes";INT(FP(D/3600)*60) DISP "Seconds";D-INT(D/3600)*3600-INT(FP(D/3600)*60)*60 **Possible Errors** * none .. note: don't need a label like elsewhere in this file because the title is the same .. index:: AUXERRN AUXERRN ------- :ref:`Top ` The AUXROM supports the ability for EBTKS to create custom error messages that are not in the original ROM. These custom error messages always have an error number of 109. To make it easier to distinguish errors (in a program), if you have an ON ERROR statement active, then the handler routine for the ON ERROR can check the error number for 109, and if so, check ERROM for 241 (the decimal# of the AUX ROM), and if so, it can then use AUXERRN to get a unique value that is set by the EBTKS error code, allowing you to easily differentiate between differentiate (programmatically) 'custom' error messages. **Possible Errors** * none .. _SPRINTF: .. index:: SPRINTF SPRINTF |_3| dst$Var, |_| format$ |_| [, |_| comma-separated-arg-list] ---------------------------------------------------------------------- :ref:`Top ` A reasonable facsimile of the **C** language/library sprintf() function. 'dst$Var' is the string into which the formatting output will be stored. 'format$' is the string that specifies the formatting, which will use the arguments in the comma-separated-arg-list to sequentially fill formatting parameters in the 'format$'. The comma-separated-arg-list entries can be numeric or string expressions, although the type **must** match the ones specified in 'format$'. NOTE: The behavior of this code is **very** dependent upon the library used. The behavior of SPRINTF may very possibly differ between EBTKS and the Series 80 Emulator, due to different sprintf() library routines being linked in for the different environments. Most of the more 'common' sprintf() options should behave the same and be supported. However, some of the less common ones may work differently **or** not work at all. Beware. The format$ string will simply output any normal text included, but whenever it sees a '%' character, that will start the formatting of an argument from the arg-list (unless the '%' is immediately followed by another '%', in which case the two are replaced by a single '%' character in the output and no arg-list items are used). The general format of the % formatting is: %[flags][width][.precision]type NOTE: The []'s in the above indicate **optional** things, they are not included in your format$. [flags] can be any (or none) of the following .. code-block:: text - left-align output rather than right-align output (the default) + prepends a plus for positive signed-numeric types (the default does not prepend anything for positive values) SPACE (space character, not the word SPACE) prepends a space for the sign of positive values 0 if [width] is specified, prepends zeros for numeric types instead of spaces # alternate forms: for g and G types, trailing zeros are not removed for f, F, e, E, g, G types, the output always contains a decimal point. for o, x, X types, 0, 0x, 0X respectively is prepended to non-zero numbers. . [width] is a number that specifies the MINIMUM NUMBER of characters to output, used to pad output of smaller numbers; no truncation, though, of numbers too large for the width specified. [.precision] is a number that specifies a MAXIMUM limit on the output, depending upon the 'type'. NOTE: Both [width] and [.precision] can either be a literal number included in the 'format$' OR they can be the '*' character, in which case the '*' gets replaced by a number from the arg-list. .. code-block:: text 'type' is a single letter indicating the desired formatting of the next item from the arg-list i or d format the next argument (MUST be numeric) as a signed integer. u formats the next argument (MUST be numeric) as an unsigned integer. f or F formats the next argument (MUST be numeric) as a REAL in fixed-point notation. The only difference is whether VERY large or VERY small numbers are output as upper or lowercase INF, INFINITY, or NAN. e or E formats the next argument (MUST be numeric) in standard "[-]d.ddd e[+/-]ddd" form. The only difference is the case of the 'e' or 'E' used for the exponent. g or G format the next argument (MUST be numeric) in either fixed-point or standard-exponential format, whichever is more appropriate for the magnitude. x or X formats the next argument (MUST be numeric) as a hexadecimal value. o formats the next argument (MUST be numeric) as an octal value. s copies the next argument (MUST be string) into the output. c outputs a single character to the output. The argument may be the NUMERIC value of the character, or the argument may be a STRING in which case the FIRST character is output. .. code-block:: text You can also include special characters in the output by placing these character strings in the 'format$': \\ outputs a single '\' character \r outputs a CR character \n outputs a LF character \t outputs a TAB character \xHH outputs a character who's value is specified by the two HH hexadecimal digits \nnn outputs a character who's value is specified by the three nnn octal digits For example .. code-block:: text SPRINTF A$, "\t\r\n" would achieve the exact same thing as SPRINTF A$, "%c%c%c",9,13,10 You could also achieve the same thing by: SDEOL 1 SPRINTF A$, "\t%s", SDEOL$ **Possible Errors** * SD ERROR (213D) formatted output length > 1024 characters * BAD FORMAT (219D) something wrong with format$ * FORMAT/ARG MISMATCH (220D) argument list doesn't line up with format$ .. _LISTROMS: .. index:: LISTROMS LISTROMS |_3| 0 |_| | |_| non-0 ------------------------------- :ref:`Top ` If the supplied argument is 0, then a reference listing will be sent to the CRT IS device, showing all known Series 80 ROMs, their ROM numbers (in both octal and decimal), and indicate whether each ROM was available for the HP-85 class of machines and/or for the 87 class of machines. If the supplied argument is non-0, then the same listing will be shown, but for ONLY the ROMs that are currently present in the system. When non-zero is used to list the INSTALLED ROMs, only AUX ROM 1 (361) will be listed, as it's the only one in the systems ROM table. But if AUX ROM 1 is there, you can count on AUX ROMs 2 (362) and 3 (363) being there as well, or you'll get an error when you try to use any AUX ROM features. **Possible Errors** * none .. _POKE: .. index:: POKE POKE |_3| address, |_| byteVal ------------------------------ :ref:`Top ` Writes the 'byteVal' to the 'address' in memory. Both values are decimal values. You can use the Assembler ROM's DEC() function to specify values in octal. **Possible Errors** * none .. _PEEK: .. index:: PEEK PEEK(address) ------------- :ref:`Top ` **Return Value** * Reads a byte from memory at 'address' and returns it as the function value. The 'address' is specified in decimal and the returned value is decimal. The Assembler ROM's DEC() and OCT() functions can be used to convert. **Possible Errors** * none .. _RPOKE: .. index:: RPOKE RPOKE |_3| rom#, |_| address, |_| byteVal ----------------------------------------- :ref:`Top ` Same as POKE, except a ROM number can be specified, which is useful for writing bytes to a bank-swapped ROM, which is normally not terribly useful, since ROMs can't be written to. However, the AUX ROMs are special in that they have 3 kb of RAM in the middle of the ROMs that is used for the AUX ROM code to communicate with EBTKS (and vice versa). So this function (and RPEEK) can be useful to AUX ROM / EBTKS developers. **Possible Errors** * none .. _RPEEK: .. index:: RPEEK RPEEK(rom#, |_3| address) ------------------------- :ref:`Top ` **Return Value** * Reads a byte from the specified bank-selected ROM. **Possible Errors** * none .. _HELPCMD: .. index:: HELP HELP |_3| [optional quoted or unquoted string] ---------------------------------------------- :ref:`Top ` EBTKS will have help screens that provide various information about the Series 80 computers, their keywords, and whatever people write up. The HELP keyword lets you request the help screen of your choice, and (assuming it's found) EBTKS will save the current CRT contents, display the help, then restore the CRT contents when you press a key. **Possible Errors** * NOT FOUND (224D) if requested help screen is not found .. index:: Keyboard Functions Keyboard Functionality ====================== .. _KBDBUFFER: .. index:: KBDBUFFER KBDBUFFER <0 | non-zero> ------------------------ :ref:`Top ` Takes over keyboard and buffers up to 16 keys at a time if arg==non-zero, else turns OFF keyboard buffering and releases the keyboard. **Possible Errors** * INV MODE (214D) if run in "calculator mode" (only valid in running program). .. note: don't need a label like elsewhere in this file because the title is the same .. index:: KBDISKEY KBDISKEY -------- :ref:`Top ` Returns 0 if no keys in buffer, else returns 1. **Possible Errors** * INV MODE (214D) if run in "calculator mode" (only valid in running program). .. note: don't need a label like elsewhere in this file because the title is the same .. index:: KBDKEY KBDKEY ------ :ref:`Top ` Returns the next keycode from the keyboard buffer. **Possible Errors** * INV MODE (214D) if run in "calculator mode" (only valid in running program). * NULL DATA (149D) if no keys in buffer. .. index:: CRT Functions CRT Functionality ================= **All of the following 'CRT' statements/functions apply ONLY to the ALPHA mode display.** .. _CRTSETTOP: .. index:: CRTSETTOP CRTSETTOP row ------------- :ref:`Top ` Sets CRT start row (0-63 on HP85, 0-53 (ALPHA) or 0-203 (ALPHALL) on HP87). This is the row# of CRT memory that appears on the top row of the CRT display. **Possible Errors** * none .. note: don't need a label like elsewhere in this file because the title is the same .. index:: CRTGETTOP CRTGETTOP --------- :ref:`Top ` Returns the current row# of display memory for the top row of the CRT display. **Possible Errors** * none .. _CRTREAD$: .. index:: CRTREAD$ CRTREAD$(row, column, len) -------------------------- :ref:`Top ` Reads from CRT at (row,col) and returns a string of 'len' length from that location. **Possible Errors** * none .. _CRTWRITE: .. index:: CRTWRITE CRTWRITE string, row, column ---------------------------- :ref:`Top ` Writes 'string' to CRT at (row,col). 'row' is absolute in CRT memory, NOT relative to CRT SETTOP 'row', so you can write to CRT memory that is not currently displayed. **Possible Errors** * none .. note: don't need a label like elsewhere in this file because the title is the same .. index:: CRTROWS CRTROWS ------- :ref:`Top ` Returns # of rows on CRT display (16 for HP85, 16 or 24 for HP87). **Possible Errors** * none .. note: don't need a label like elsewhere in this file because the title is the same .. index:: CRTCOLS CRTCOLS ------- :ref:`Top ` Returns # of columns on CRT display (32 for HP85, 80 for HP87). **Possible Errors** * none .. _CRTON: .. index:: CRTON CRTON <0 | non-zero> -------------------- :ref:`Top ` Blanks or unblanks CRT display (doesn't affect memory contents, just whether they're displayed or not). **Possible Errors** * none .. _CRTCURSOR: .. index:: CRTCURSOR CRTCURSOR state,[row,col] ------------------------- :ref:`Top ` Sets cursor to REPLACE (0) or INSERT (non-zero) mode, and optionally moves the cursor to (row,col). **Possible Errors** * none .. note: don't need a label like elsewhere in this file because the title is the same .. index:: CRTCURSCOL CRTCURSCOL ---------- :ref:`Top ` Returns cursor column number. **Possible Errors** * none .. index:: CRTCURSROW CRTCURSROW ---------- :ref:`Top ` Returns absolute (NOT relative to TOP row) cursor row number. **Possible Errors** * none .. note: don't need a label like elsewhere in this file because the title is the same .. index:: Options/Settings Options/Settings ================ .. _SDSLASH: .. index:: SDSLASH SDSLASH |_3| 0 |_| | |_| non-0 ------------------------------ :ref:`Top ` Controls whether '/' or \\'\\\\' is used in paths returned to the user. * SDSLASH 0 sets it to '/' (the default) * SDSLASH 1 sets it to \\'\\\\'. This setting is remembered via an SD file over a power cycle. **Possible Errors** * none .. note: don't need a label like elsewhere in this file because the title is the same .. index:: SDSLASH$ SDSLASH$ -------- :ref:`Top ` **Return Value** * Returns a 1-character string containing either '/' or \\'\\\\' **Possible Errors** * none .. _SDEOL: .. index:: SDEOL SDEOL |_3| 0 |_| | |_| non-0 ---------------------------- :ref:`Top ` Controls whether SDEOL$ returns LF or CR/LF as the EOL sequence. * SDEOL 0 sets it to LF (the default) * SDEOL 1 sets it to CR/LF. This setting is remembered via an SD file over a power cycle. **Possible Errors** * none .. note: don't need a label like elsewhere in this file because the title is the same .. index:: SDEOL$ SDEOL$ ------ :ref:`Top ` **Return Value** * Returns a 1-character or 2-character long string containing the current EOL sequence, either LF or CR/LF. Good for using in SPRINTF statements when writing text to an SD file. **Possible Errors** * none Miscellaneous Commands ====================== .. note: don't need a label like elsewhere in this file because the title is the same .. index:: AUXREV AUXREV ------ :ref:`Top ` **Return Value** * Returns the AUX ROMs revision number (from ROM 361) **Possible Errors** * none .. note: don't need a label like elsewhere in this file because the title is the same .. index:: EBTKSREV$ EBTKSREV$ --------- :ref:`Top ` **Return Value** * Returns a string containing a date and time of building the EBTKS firmware **Possible Errors** * none .. index:: RMIDLE RMIDLE ------ :ref:`Top ` This is not an actual command that can be typed at the Series 80 keyboard, it is used as a bidirectional channel between the Series 80 computer and EBTKS for tasks that involve passing data that is not a function of program execution, such as the EBTKS injecting characters into the keyboard stream, or intercepting keyboard character before the Series 80 computer \"sees them\" *more details later* .. _SETLED: .. index:: SETLED SETLED |_3| <1 |_| | |_| 2 |_| | |_| 3>, |_| R#, |_| G#, |_| B# --------------------------------------------------------------- :ref:`Top ` LED 1 is LED closest to the Power Inlet of the HP8x computer LED 2 is LED closest to the EBTKS SD Card First parameter: 1 |_| Set LED 1 2 |_| Set LED 2 3 |_| Set both LEDs to the same color Physically, LED 1 and 2 contain 3 internal LEDs and a controller integrated circuit (IC) within a 5 x 5 mm package, in the two back corners of the EBTKS circuit board. These 3 internal LEDs in each package emit light in either Red, Green, or Blue wavelength. By adjusting the brightness of these internal LEDs, a vast range of colors and brightnesses can be achieved. A web search for WS2812B or WS2812E datasheet can provide further technical information. The SETLED command sends the R, G, B values to the IC, which in turn adjusts the intensity of the respective LEDs. The LEDs can nominally show 16 million colors (a 24 bit value) but realistically very small changes in the control values will not be perceptible. This is particularly true at the brighter end of the brightness range. Each of the three parameters R, G, and B are numbers in the range 0 to 255. 0 is off, and 255 is full brightness for that color. Because the LEDs are not ideal, and they are not intensity matched, and are discrete with some gap between them (less than a mm), the mixing of the light is far from perfect and trying to get white light will be disappointing. Also the LEDs are quite bright and I find that values over 60 can be hard to look at directly. Your mileage may vary. **Possible Errors** * ARG OUT OF RANGE (system 11D) (if LED# is not 1,2, or 3) .. index:: BOOT BOOT ---- :ref:`Top ` This command will re-boot your system, resetting both the Series80 computer and EBTKS. Any modified program that is in the Series80 computer memory will be lost, just like the SCRATCH keyword. Save your programs often when doing development. .. index:: LIF DISK Raw Access LIF DISK FEATURES ================= .. _RSECTOR: .. index:: RSECTOR RSECTOR |_3| dstVar$, |_| sector#, |_| msus$ -------------------------------------------- :ref:`Top ` Reads a raw 256-byte sector from the specified drive. .. code-block:: text 'dstVar$' must be dimensioned to at least 256 bytes (which is where the sector will be read into). 'sector#' is a number from 0 to NumSectors-1 (where NumSectors is the number of sectors available on the disk). 'msus$' is the ":Dxxx" specification of the disk drive. **Possible Errors** * Typical Mass Storage ROM errors .. _WSECTOR: .. index:: WSECTOR WSECTOR |_3| src$, |_| sector#, |_| msus$ ----------------------------------------- :ref:`Top ` Writes a raw 256-byte sector to the specified drive. .. note:: **WARNING!!! Be VERRRRRRRY careful using this, as you can easily trash your disk and lose ALL files stored on it!!!!** **Possible Errors** * Typical Mass Storage ROM errors .. _SDEXPORTLIF: .. index:: SDEXPORTLIF SDEXPORTLIF |_3| LIFname$, |_| SDname$ |_| [, |_| headerFlag] ------------------------------------------------------------- :ref:`Top ` Exports a LIF file from a LIF disk to an SD file on the SD card. No translation of any sort is done on the contents of the file. If the LIFname$ contains only an MSUS rather than a filename, then the ENTIRE disk is output, including volume and directory sectors and ALL files, resulting in an "emulated disk file" that can be used with the Series 80 emulator or with EBTKS on the SD card, or shared with others. headerFlag: If 0, then no "LIF header" is written at the start of the SD file, and ONLY the 'valid' bytes from the LIF file are written. If non-0, then a 512-byte "LIF header" (on volume sector, one directory sector) is written to the file, followed by ALL the sectors from the LIF disk that were allocated to the file (which may include a bunch of 'empty' unused sectors). SDEXPORTLIF is a DISK-ONLY statement, it will result in an error 115: INVALID MSUS if attempted on the :T tape drive. **Possible Errors** * INVALID MSUS (115D) * FILE/PATH (217D) if disk is not LIF formatted * FILE NAME (167D) if LIF file is not found * FILE SIZE (223D) if the LIF file is >65536 bytes long .. _SDIMPORTLIF: .. index:: SDIMPORTLIF SDIMPORTLIF |_3| LIFname$, |_3| SDname$ --------------------------------------- :ref:`Top ` Single file version +++++++++++++++++++ Import a file on the SD Card named SDname$ that must be in LIF file format. Such files may be created by the `SDEXPORTLIF`_, but also the output of Everett Kaser's ASM85 program. The file is stored on a LIF disk, which could be a physical disk, or an emulated disk provided by EBTKS. LIFname$ can include an msus$. The LIF file format has a headerFlag=1 (i.e., with a "LIF header" included, containing volume and director 'sectors'). The SD file MUST be prefaced with a "LIF header" (a 256-byte "Volume sector" and a 256-byte "Directory sector"). **Examples** - SDIMPORTLIF "MYPROG:D300", "/SDDir/prog.bin" The imported BIN program created with ASM85 and in the directory SDDir on the SD Card will be stored on disk D300 with the name MYPROG and the CAT command will show that the type is BPGM - SDIMPORTLIF "data", "peoplesnames" The imported LIF file that is in the current working directory on the SD Card, named "peoplesnames" will be stored with the name "data" on the current MASS STORAGE IS drive. Remember, the imported file must be in LIF format, so probably originally written to the SD Card with the `SDEXPORTLIF`_ command Whole Disk version ++++++++++++++++++ If the LIFname$ doesn't include a filename, but rather is just an MSUS$, then the SDname$ file is expected to be a full "emulated LIF disk," such as `SDEXPORTLIF`_ would create if it is run with just an MSUS for the LIFname$. SDIMPORTLIF is a DISK-ONLY statement, it will result in an error 115: INVALID MSUS if attempted on the :T tape drive. **Possible Errors** * SD ERROR (213D) if error reading SD file * INVALID MSUS (115D) if problem with LIF file name * FILE/PATH (217D) if disk is not LIF formatted * FILE NAME (167D) if SD file is not found * FULL (MS ROM 128D) if the disk is too full .. _SDPATH$: .. index:: SDPATH$ SDPATH$(index#, path$) ---------------------- :ref:`Top ` **Return Value** * Returns one element of path$ * If index# is positive and non-zero, 1 returns 1st element, 2 returns 2nd, etc. * If index# is negative, -1 returns last element, -2 returns 2nd from last, etc. * If index# is ONE greater beyond the number of elements, "" (zero-len string) is returned. * Otherwise, error. **Possible Errors** 11 ARG OUT OF RANGE (if index# is out of range) .. note: don't need a label like elsewhere in this file because the title is the same .. _SDCHAIN: .. index:: SDCHAIN SDCHAIN |_3| name$ ------------------ :ref:`Top ` Same as system CHAIN, just from SD file (created via SDSTORE). **Caution:** * There is no file type checking. If you SDLOAD a file that was not SDSTORE'd, chaos will be unleashed and the end of the universe will be nigh. **Possible Errors** * FILE/PATH (217D) error in file/path name, or error opening/creating the file .. _SDSTOREBIN: .. index:: SDSTOREBIN SDSTOREBIN |_3| nameSD$ ----------------------- :ref:`Top ` Stores the Binary Program currently in memory to an SD file. A "LIF header" is included on the front of the file. This is essentially a shortcut way of doing STOREBIN "filename" and then SDEXPORTLIF "filename","SDname". **Possible Errors** * FILE/PATH (217D) error in file/path name, or error opening/creating the file * SD ERROR (213D) if write failed to write everything .. _SDLOADBIN: .. index:: SDLOADBIN SDLOADBIN |_3| nameSD$ ---------------------- :ref:`Top ` Loads a Binary Program into memory from an SD file that was SDSTOREBIN'd or SDEXPORTLIF'd. **Caution** * There is no file type checking. If you SDLOADBIN a file that was not SDSTOREBIN'd, or SDEXPORTLIF'd, chaos will be unleashed and the end of the universe will be nigh. **Possible Errors** * FILE/PATH (217D) error in file/path name, or error opening/creating the file .. _SDBATCH: .. index:: SDBATCH SDBATCH |_3| nameSD$ -------------------- :ref:`Top ` Reads characters from nameSD$ and types them on the display. End-of- lines (CR/LF or LF) cause the END LINE key to be sent. Other Series 80 specific keys can be sent using the \\ character followed by the three octal digits of the keycode. The CRT may have text on the cursor line, rather than a clear screen. As you know, when you type a command, if there are characters on the line after the command you have typed, it will mess up your command. For HP85A/B, you must also make sure that the previous line does not have a character in the last position (character position 32) as that will cause the previous line to be treated as part of the command too. Here are two strategies that could work: 1. Clear the screen before entering commands using octal |_3| \\222 |_3| at the beginning of the character sequence 2. Clear the current line with "-line" code |_3| \\240 |_3|, then move down 1 line (|_3| \\242 |_3|) and clear that line as well (|_3| \\240 |_3|), then enter the desired command. So the beginning of "command" would be |br| " |_3| \\240\\242\\240 |_3| rest of the command" |br| This sequence assumes the cursor is in column 1. You don't need to use |_3| \\232 |_3| for the end of line character, or |_3| \\042 |_3| for the double quote characters. Normal ends of lines in the batch file will be interpreted as the end line that the HP85 expects. The contents of the batch file could be: .. code-block:: text :linenos: LOAD "LEDTEST-1" RUN Unlike the batch files on Windows OS systems, this batch capability is very simple. Just the sequential transfer of text. Here is a link to a :ref:`table of Octal Codes ` . **Possible Errors** * FILE/PATH (217D) error in file/path name, or error opening/creating the file Other error messages ==================== AUXROM has some internal functions that are called by other functions, and these internal functions can also return error codes .. comment: FLAGS ----- This function is called by other Keywords that change flags. Examples are SDEOL and SDSLASH **Possible Errors** * "Can't open /AUXROM_FLAGS.TXT" , AUXERRN will be 310 * "Can't write /AUXROM_FLAGS.TXT" , AUXERRN will be 311 .. index:: LOW-LEVEL FUNCTIONS LOW-LEVEL FUNCTIONS =================== **For Diagnostics and testing new ideas** These three Keywords can be used for diagnostic purposes to test the AUXROM code and also as hooks to write EBTKS routines without writing new AUXROM code. For all three of these Keywords (AUXCMD, AUXBUF$, AUXOPT$) * 0-16 bytes of opt$ get written to A.BOPT00-A.BOPT15 * buf$ gets written to A.BUFx where 'x' is buf#. * A.BLENx gets set to the length of buf$. * usage# gets written to A.BUSEx. * MBx gets set to 1. * x gets written to HEYEBTKS to send the command. Note that the above memory references are in terms of the labels used in the AUXROM source code. The equivalent locations in EBTKS C code are as follows .. code-block:: text A.BOPT00-A.BOPT15 AUXROM_RAM_Window.as_struct.AR_Opts[16] A.BUFx AUXROM_RAM_Window.as_struct.AR_Buffer_0 AR_Buffer_1 AR_Buffer_2 AR_Buffer_3 AR_Buffer_4 AR_Buffer_5 AR_Buffer_6 A.BLENx AUXROM_RAM_Window.as_struct.AR_Lengths[8] A.BUSEx AUXROM_RAM_Window.as_struct.AR_Usages[8] MBx AUXROM_RAM_Window.as_struct.AR_Mailboxes[32] These are mostly of use to AUXROM and EBTKS devlopers. Avoid use, except for these specific cases: .. code-block:: text AUXCMD buf#, usage#, buf$ , opts$ AUXOPT$( buf#, usage#, buf$ , opts$) AUXBUF$( buf#, usage#, buf$ , opts$) .. _AUXCMD: .. index:: AUXCMD AUXCMD |_3| buf#, |_| usage#, |_| buf$, |_| opts$ ------------------------------------------------- :ref:`Top ` How to use AUXCMD: - A command is setup using the buffer (and matching mailbox and usage) specified by buf# (0..7) - The related usage[buf#] is set to usage# (this is the function code) - The string buf$ is copied to the designated buffer, and the related length values is set appropriately - At most 16 bytes from the string opt$ are copied to AUXROM_RAM_Window.as_struct.AR_Opts[16] - A call is made to EBTKS, specifying the buffer number buf# - EBTKS processes the specified command (in usage[buf#]). There is no return value - The appropriate usage location is set to 0 if there is no error, or an error code - EBTKS indicates completion by setting the appropriate mailbox to 0 **Possible Errors** * ARG OUT OF RANGE (system 11D) * INVALID PARAMETER (system 89D) * STRING OVERFLOW (system 56D) * MEMORY OVERFLOW (system 19D) * custom AUXROM msg (209D) **Possible Warning** * NULL DATA (system 7) .. _AUXOPT$: .. index:: AUXOPT$ AUXOPT$(buf#, |_| usage#, |_| buf$, |_| opt$) --------------------------------------------- :ref:`Top ` How to use AUXOPT$: - A command is setup using the buffer (and matching mailbox and usage) specified by buf# (0..7) - The related usage[buf#] is set to usage# (this is the function code) - The string buf$ is copied to the designated buffer, and the related length values is set appropriately - At most 16 bytes from the string opt$ are copied to AUXROM_RAM_Window.as_struct.AR_Opts[16] - A call is made to EBTKS, specifying the buffer number buf# - EBTKS processes the specified command (in usage[buf#]) and returns 16 bytes of data in AUXROM_RAM_Window.as_struct.AR_Opts[16] - The appropriate usage location is set to 0 if there is no error, or an error code - EBTKS indicates completion by setting the appropriate mailbox to 0 - The AUXROM code completes processing of AUXOPT$ by returning the options to the BASIC environment as the string result of making this call to AUXOPT$ **Return Value** * A 16-byte string is returned containing the bytes of A.BOPT00-A.BOPT15. **Possible Errors** * ARG OUT OF RANGE (system 11D) * INVALID PARAMETER (system 89D) * STRING OVERFLOW (system 56D) * MEMORY OVERFLOW (system 19D) * custom AUXROM msg (209D) **Possible Warning** * NULL DATA (system 7) .. _AUXBUF$: .. index:: AUXBUF$ AUXBUF$(buf#, |_| usage#, |_| buf$, |_| opts$) ---------------------------------------------- :ref:`Top ` How to use AUXBUF$: - A command is setup using the buffer (and matching mailbox and usage) specified by buf# (0..7) - The related usage[buf#] is set to usage# (this is the function code) - The string buf$ is copied to the designated buffer, and the related length values is set appropriately - At most 16 bytes from the string opt$ are copied to AUXROM_RAM_Window.as_struct.AR_Opts[16] - A call is made to EBTKS, specifying the buffer number buf# - EBTKS processes the specified command (in usage[buf#]) and returns a string in the same buffer that was use to pass buf$ to it. The appropriate length value is set to the length of the string. - The appropriate usage location is set to 0 if there is no error, or an error code - EBTKS indicates completion by setting the appropriate mailbox to 0 - The AUXROM code completes processing of AUXBUF$ by returning the string in the buffer to the BASIC environment as the string result of making this call to AUXBUF$ **Return Value** * A string is returned containing the A.BLENx bytes of A.BUFx. **Possible Errors** * ARG OUT OF RANGE (system 11D) * INVALID PARAMETER (system 89D) * STRING OVERFLOW (system 56D) * MEMORY OVERFLOW (system 19D) * custom AUXROM msg (209D) **Possible Warning** * NULL DATA (system 7) ADDING NEW FEATURES TO THE HP-85 AUX ROMS ========================================= .. index:: Adding New Keywords ADDING NEW KEYWORDS ------------------- In 85aux1.src, find these tables: * KEYWORDS ASCII keyword table * TROM#S single-byte values of the ROM# in which each keyword's runtime code exists * RUNTIM runtime routine table * PARSES parse routine table Find an appropriate open slot in these tables that: * Isn't in use (ALL of the following must be true): * It has a '200' in the KEYWORDS table * It has a '0' (or is bsz'd) in the TROM#S table * It is bsz'd in both RUNTIM and PARSES tables * Isn't marked RESERVED, *unless* you have to use one of those in order for your longer keyword to not be 'blocked' by an already existing shorter keyword. For example, the MOUNT keyword already exists. If you try to add the MOUNTAIN keyword AFTER the MOUNT keyword it will be 'blocked', the PARSER will never see the MOUNTAIN keyword, because it will find the MOUNT keyword first. Therefore, you'll need to use a RESERVED slot EARLIER in the table than the MOUNT keyword so that both MOUNTAIN and MOUNT will be spotted by the PARSER. This is the ONLY time you should use a keyword slot marked in the KEYWORDS table as RESERVED. NOTE: Finding or making an open slot in the above tables MAY involve moving the 377 marker at the end of the ASP keywords in the KEYWORDS table. Is is CRITICAL that this table not get longer or shorter (in terms of the number of ENTRIES, not in terms of the number of BYTES), as there are tokens at the very end of this table that are "hidden (or worker) tokens" that are parsed into the token stream by an actual keyword (a particular example, at this point in time, are the three tokens 374, 375, and 376 which are used by the SPRINTF keyword to do "hidden things" at runtime). So, to keep from screwing those up, if you want to add a new keyword and need to move the 377 end-of-table marker, for each keyword you add, you must: * Delete the first 200 byte immediately AFTER the 377 marker * Insert an ASP statement immediately BEFORE the 377 marker You may NOT insert new keywords in between existing ones, as that would change the old keywords' TOKEN#, which would cause any programs written using an older version of the AUX ROM to stop working and likely crash, because the parsed tokens in that stored program would no longer match the token numbers in the new AUX ROM. Once you've found your slot: #. Add the ASCII keyword to the KEYWORDS with an ASP opcode. #. Add the AUX ROM ROM#, in which the RUNTIME routine for the keyword is located, to the TROM#S table in the matching 'slot'. #. Add the address of the runtime routine in AUX ROM 1 to the RUNTIM table. For most STATEMENTS, this will be either "RUN1." (if it's a NON-programmable statement, i.e., a calculator-mode-only COMMAND) or "RUN2." (if it's a normal PROGRAMMABLE statement). The '1' in "RUN1." reminds you that the attribute is 141, whereas the '2' in "RUN2." reminds you that the attribute is 241. For most functions, there will probably already be an existing runtime entry point in AUX ROM 1 that has the right attributes for your function, and you can either use an already-existing label following those attributes, or add a new label. For example, if you're adding a numeric function with no arguments, the attributes your runtime entry point needs are "0,55", and searching through the function runtime entry points in AUX ROM 1, you'll find that AUXERRN. has those attributes. So, you could either just use "AUXERRN." as your runtime entry point, or add a new unique label immediately after the line containing the "AUXERRN." label, so that the "0,55" attributes are immediately before both labels. If you can't find an already existing function with the right attributes, then you'll need to create a new entry. Many of these function entry points have no code and so will simply "fall through" the attributes of following functions. As long as those attribute bytes are all <200 (octal), they will be executed as ARP and/or DRP instructions, causing no damage, taking very little time, and saving bytes in the ROM. All of these functions eventually wind up at "RUN2." at runtime, along with the normal STATEMENTS, and the "RUN2." routine uses the TROM#S table to call the F_RUN function in the appropriate AUX ROM to actually execute the REAL runtime code for that keyword. #. Add the address of the parse routine (if not a function) to the PARSES table. There are many 'common' parse routines already existing in the AUX ROM 1. If your new statement's argument list matches the argument list of a previously created keyword, then you can just add a label for it and use the same parse routine. If you have special parsing needs, then you'll need to add your own code, which may parse the whole statement (if it's VERY brief) or call the actual PARSE routine in the other AUX ROM via FUNTAB. #. In the other AUX ROM, where the actual runtime code for the keyword exists, be sure to add the address of the actual runtime routine to that AUX ROM's RUNTIM table. See AUXROM2 and AUXROM3 for examples. *As an alternative to all of the above, I have found that just asking Everett to do it for me has worked quite well. PMF 11/27/2020* ADDING NEW NON-KEYWORD FEATURES =============================== Some features that you might wish to add may involve taking over one or more system 'hooks'. Also, some keywords you add may need to do some form of initialization at power-on or other times. The AUXROM 1, which contains all of the keyword and runtime/parse tables that the system can 'see' also contains the INIT routine. This init routine, once it has done anything it needs to do, calls an INIT routine in each of the sub-AUXROMs, to give them a chance to do whatever. It does this by calling the function in each AUX ROM's FUNTAB (see F_INIT in 85auxdef.src and the FUNTAB in each AUXROM, the first entry of which is usually "def R_INIT". It's CRITICAL that you maintain the exact order and value of all of the F\_ equates in 85auxdef.src, and construct/edit the FUNTAB tables accordingly, or the Holy Howling Hounds of Hades will invade your workspace. .. _Octal_Codes: .. index:: Octal_Codes Octal Keycodes for Special Keys on HP 85 A/B Keyboard ===================================================== .. comment: table generator https://www.tablesgenerator.com/html_tables D:\2021\HP-85_Websites\EBTKS_Docs\Table_Sources\KeyboardOctal_85AB.tgn K1 200 INIT 214 -unused- 230 -CHR 244 K2 201 RUN 215 BKSPACE 231 HOMECURS 245 K3 202 PAUSE 216 ENDLINE 232 RESULT 246 K4 203 CONT 217 FASTBKSPACE 233 -unused- 247 K5 204 STEP 220 LFCURS 234 DELETE 250 K6 205 TEST 221 RTCURS 235 STORE 251 K7 206 CLEAR 222 ROLLUP 236 LOAD 252 K8 207 GRAPH 223 ROLLDN 237 -unused- 253 REW 210 LIST 224 -LINE 240 AUTO 254 COPY 211 PLIST 225 UPCURS 241 SCRATCH 255 PAPADV 212 KEYLABEL 226 DNCURS 242 RESET 213 -unused- 227 I/R 243 .. raw:: html
Key Octal Key Octal Key Octal Key Octal
K1 200 INIT 214 -unused- 230 -CHR 244
K2 201 RUN 215 BKSPACE 231 HOMECURS 245
K3 202 PAUSE 216 ENDLINE 232 RESULT 246
K4 203 CONT 217 FASTBKSPACE 233 -unused- 247
K5 204 STEP 220 LFCURS 234 DELETE 250
K6 205 TEST 221 RTCURS 235 STORE 251
K7 206 CLEAR 222 ROLLUP 236 LOAD 252
K8 207 GRAPH 223 ROLLDN 237 -unused- 253
REW 210 LIST 224 -LINE 240 AUTO 254
COPY 211 PLIST 225 UPCURS 241 SCRATCH 255
PAPADV 212 KEYLABEL 226 DNCURS 242
RESET 213 -unused- 227 INS/RPL 243
Octal Keycodes for Special Keys on HP 86 and 87 Keyboard ======================================================== .. comment: table generator https://www.tablesgenerator.com/html_tables D:\2021\HP-85_Websites\EBTKS_Docs\Table_Sources\KeyboardOctal_86_87.tgn K1 200 INIT 214 HCURS 230 DOWN CURSOR 244 K2 201 RUN 215 BKSPACE 231 K12 245 K3 202 PAUSE 216 ENDLINE 232 RESULT 246 K4 203 CONT 217 FASTBKSPACE 233 -unused- 247 K8 204 STEP 220 K7 234 A/G 250 K9 205 ROLL up 221 -LINE 235 ROLL down 251 K10 206 TEST 222 INS/RPL 236 RIGHT CURSOR 252 K11 207 K14 223 LEFT CURSOR 237 -unused- 253 -CHAR 210 LIST 224 E 240 K13 254 CLEAR 211 PLIST 225 K5 241 TRACE/NORMAL 255 -unused- 212 KEYLABEL 226 K6 242 RESET 213 -unused- 227 UP CURSOR 243 .. raw:: html
Key Octal Key Octal Key Octal Key Octal
K1 200 INIT 214 HCURS 230 DOWN CURSOR 244
K2 201 RUN 215 BKSPACE 231 K12 245
K3 202 PAUSE 216 ENDLINE 232 RESULT 246
K4 203 CONT 217 FASTBKSPACE 233 -unused- 247
K8 204 STEP 220 K7 234 A/G 250
K9 205 ROLL up 221 -LINE 235 ROLL down 251
K10 206 TEST 222 INS/RPL 236 RIGHT CURSOR 252
K11 207 K14 223 LEFT CURSOR 237 -unused- 253
-CHAR 210 LIST 224 E 240 K13 254
CLEAR 211 PLIST 225 K5 241 TRACE/NORMAL 255
-unused- 212 KEYLABEL 226 K6 242
RESET 213 -unused- 227 UP CURSOR 243