From edcfc92d0fda102b348f28a2b01ce58fb370d21b Mon Sep 17 00:00:00 2001 From: Nicolas Benezan Date: Mon, 13 Jul 2020 15:59:29 +0200 Subject: [PATCH] Spi_RdByte() timing fixed, FlashDemo added (by VonSzarvas) --- .../p2/All/Simple_SpiFlash/FlashDemo.spin2 | 74 +++ .../p2/All/Simple_SpiFlash/SpiFlash.spin2 | 141 ++--- .../p2/All/Simple_SpiFlash/_README_.txt | Bin 0 -> 1056 bytes .../p2/All/Simple_SpiFlash/jm_nstr.spin2 | 1 + .../p2/All/Simple_SpiFlash/jm_serial.spin2 | 541 ++++++++++++++++++ 5 files changed, 693 insertions(+), 64 deletions(-) create mode 100644 libraries/community/p2/All/Simple_SpiFlash/FlashDemo.spin2 create mode 100644 libraries/community/p2/All/Simple_SpiFlash/_README_.txt create mode 100644 libraries/community/p2/All/Simple_SpiFlash/jm_nstr.spin2 create mode 100644 libraries/community/p2/All/Simple_SpiFlash/jm_serial.spin2 diff --git a/libraries/community/p2/All/Simple_SpiFlash/FlashDemo.spin2 b/libraries/community/p2/All/Simple_SpiFlash/FlashDemo.spin2 new file mode 100644 index 00000000..62da984f --- /dev/null +++ b/libraries/community/p2/All/Simple_SpiFlash/FlashDemo.spin2 @@ -0,0 +1,74 @@ +' Flash Demo +' Run on P2 EVAL board with FLASH Dip Switch set ON +' Run this code, then within 2 seconds open Parallax Serial Terminal (or equivalent) at 115200 baud + +CON + + CLK_FREQ = 180_000_000 ' system freq as a constant + _clkfreq = CLK_FREQ + + BR_TERM = 230_400 ' terminal baud rate + + FLASH_ADR = $60000 + + MAXCHK = 255 + + +OBJ + + com : "jm_serial.spin2" + spi : "SpiFlash.spin2" + + +VAR + + byte buffer[4096] + + +PUB main() | i + + com.start(BR_TERM) + + waitms(2000) ' 2 second pause; allow user to open serial debug terminal + + com.str (string(13, 10, "erase...", 13, 10)) + spi.Erase (FLASH_ADR, $2000) + + + com.str (string("read before: ")) + + ' clear buffer + repeat i from 0 to 255 + buffer[i]:= -2 + + + spi.Read (@buffer, FLASH_ADR, 256) + + repeat i from 0 to MAXCHK + com.dec (buffer[i]) + com.tx (" ") + com.tx(10) + com.tx(13) + + repeat i from 0 to 255 + buffer[i]:= i + + spi.WritePage (@buffer, FLASH_ADR) + + + + + com.str (string("read after write: ")) + + ' clear buffer + repeat i from 0 to 255 + buffer[i]:= -2 + + + spi.Read (@buffer, FLASH_ADR, 256) + + repeat i from 0 to MAXCHK + com.dec (buffer[i]) + com.tx (" ") + com.tx(10) + com.tx(13) diff --git a/libraries/community/p2/All/Simple_SpiFlash/SpiFlash.spin2 b/libraries/community/p2/All/Simple_SpiFlash/SpiFlash.spin2 index e93e420c..327cbf83 100644 --- a/libraries/community/p2/All/Simple_SpiFlash/SpiFlash.spin2 +++ b/libraries/community/p2/All/Simple_SpiFlash/SpiFlash.spin2 @@ -13,6 +13,7 @@ ' author: Nicolas Benezan (nicolas@benezan.de, forum: ManAtWork) ' bene 07-May-2020 Spi_WrLong() fixed (little endian) +' bene 09-Jul-2020 Spi_RdByte() fixed, waitx CON spi_cs = 61 spi_ck = 60 @@ -26,28 +27,28 @@ CON spi_cs = 61 Read_Data = $03 Read_Status = $05 -PUB start ()' Dummy to avoid compiling as top +PUB start() ' Dummy to avoid compiling as top repeat -PUB Erase (flashAdr, size) | cmd +PUB Erase(flashAdr, size) | cmd ' size can be 4kB or 64kB cmd:= Erase_4k if size > $1000 cmd:= Erase_64k - Spi_Init () + Spi_Init() Spi_Cmd8 (Write_Enable) Spi_Cmd32 (cmd, flashAdr) - Spi_Wait () + Spi_Wait() -PUB WritePage (hubAdr, flashAdr) +PUB WritePage(hubAdr, flashAdr) ' writes a page of 256 bytes - Spi_Init () - Spi_Cmd8 (Write_Enable) - Spi_Cmd32 (Write_Page, flashAdr) + Spi_Init() + Spi_Cmd8(Write_Enable) + Spi_Cmd32(Write_Page, flashAdr) repeat 64 Spi_WrLong (long[hubAdr]) hubAdr+= 4 - Spi_Wait () + Spi_Wait() PUB Read (hubAdr, flashAdr, size) ' read any number of bytes @@ -58,19 +59,22 @@ PUB Read (hubAdr, flashAdr, size) ORG drvh #spi_cs END - -PUB Verify (hubAdr, flashAdr, size) : ok + +PUB Verify(hubAdr, flashAdr, size) : ok ' compare HUBRAM to flash contents, true means match ok:= true - Spi_Init () - Spi_Cmd32 (Read_Data, flashAdr) + Spi_Init() + Spi_Cmd32(Read_Data, flashAdr) repeat size - ok&= byte[hubAdr++] == Spi_RdByte () + ok&= byte[hubAdr++] == Spi_RdByte() + ORG drvh #spi_cs END -PRI Spi_Init () + return ok + +PRI Spi_Init() ORG drvh #spi_cs 'spi_cs high fltl #spi_ck 'reset smart pin spi_ck @@ -80,19 +84,21 @@ PRI Spi_Init () drvl #spi_di END -PRI Spi_Cmd8 (cmd) +PRI Spi_Cmd8(cmd) ' outputs 8 bits command, MSB first ORG drvh #spi_cs shl cmd,#24 'shift command up drvl #spi_cs END - Spi_WrByte (cmd) + + Spi_WrByte(cmd) + ORG drvl #spi_di END -PRI Spi_WrByte (cmd) : r +PRI Spi_WrByte(cmd) : result ORG shl cmd,#1 wc outc #spi_di @@ -114,7 +120,7 @@ PRI Spi_WrByte (cmd) : r END return cmd -PRI Spi_Cmd32 (cmd, adr) +PRI Spi_Cmd32(cmd, adr) ' outputs 4 bytes: 8 bit command + 24 bits adr ORG drvh #spi_cs @@ -122,69 +128,76 @@ PRI Spi_Cmd32 (cmd, adr) or cmd,adr 'or in address drvl #spi_cs END + repeat 4 - cmd:= Spi_WrByte (cmd) + cmd:= Spi_WrByte(cmd) + ORG drvl #spi_di END -PRI Spi_WrLong (l) +PRI Spi_WrLong(l) ' outputs 32 bits while spi_cs stays low - Spi_WrByte (l<<24) - Spi_WrByte (l<<16) - Spi_WrByte (l<<8) - Spi_WrByte (l) + Spi_WrByte(l<<24) + Spi_WrByte(l<<16) + Spi_WrByte(l<<8) + Spi_WrByte(l) PRI Spi_RdByte (): b ' read 8 bits ORG - wypin #16,#spi_ck 'start 16 clock transitions - mov b,#0 - nop - nop 'read later to compensate input/output delay - nop - nop - testp #spi_do wc - rcl b,#1 - testp #spi_do wc - rcl b,#1 - testp #spi_do wc - rcl b,#1 - testp #spi_do wc - rcl b,#1 - testp #spi_do wc - rcl b,#1 - testp #spi_do wc - rcl b,#1 - testp #spi_do wc - rcl b,#1 - testp #spi_do wc - rcl b,#1 + wypin #16,#spi_ck 'start 16 clock transitions + mov b,#0 + waitx #4 ' 3..6 works for me + 'nop 'read later to compensate input/output delay + 'nop ' 2 or 3 nops works, 1+4 nops don't + 'nop + testp #spi_do wc + rcl b,#1 + testp #spi_do wc + rcl b,#1 + testp #spi_do wc + rcl b,#1 + testp #spi_do wc + rcl b,#1 + testp #spi_do wc + rcl b,#1 + testp #spi_do wc + rcl b,#1 + testp #spi_do wc + rcl b,#1 + testp #spi_do wc + rcl b,#1 END + return b + + +PRI Spi_Wait() | st -PRI Spi_Wait ()| st ' waits until busy flag == 0, drives spi_cs high when done repeat - Spi_Cmd8 (Read_Status) - st:= Spi_RdByte () + Spi_Cmd8(Read_Status) + st:= Spi_RdByte() until st & $01 == 0 + ORG drvh #spi_cs END +{ +------------------------------------------------------------------------------------------------------------------------------+ -¦ TERMS OF USE: MIT License ¦ -+------------------------------------------------------------------------------------------------------------------------------¦ -¦Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation ¦ -¦files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, ¦ -¦modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software¦ -¦is furnished to do so, subject to the following conditions: ¦ -¦ ¦ -¦The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.¦ -¦ ¦ -¦THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE ¦ -¦WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR ¦ -¦COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ¦ -¦ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ¦ +¦ TERMS OF USE: MIT License ¦ ++------------------------------------------------------------------------------------------------------------------------------¦ +¦Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation ¦ +¦files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, ¦ +¦modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software¦ +¦is furnished to do so, subject to the following conditions: ¦ +¦ ¦ +¦The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.¦ +¦ ¦ +¦THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE ¦ +¦WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR ¦ +¦COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ¦ +¦ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ¦ +------------------------------------------------------------------------------------------------------------------------------+ - +} diff --git a/libraries/community/p2/All/Simple_SpiFlash/_README_.txt b/libraries/community/p2/All/Simple_SpiFlash/_README_.txt new file mode 100644 index 0000000000000000000000000000000000000000..421f60ae4f1c52eee6bf3a8e2c32ddfab6b7baf1 GIT binary patch literal 1056 zcmb`GOH0F05QPt23hrFGxD>LJ5Q_-9vM7RrAk@8tv|vk2LK0tpUj62Vw8p5lP=;wT zuXE0w-h8|(*rx4jN4JVq;wcvERgO%lT!m&nHzRU7*MsKd+UkO8qMCS2J@M6Na)!7~ zg$fMOyw7|}&S|Jiue?IT1qvR~KJ*hd)m1m8znPkF)>=n>t9+V{6_!H)02HRW@ZrD)xRrNvy&HwfC^y)Voe zY&G1Qv93FP!!YsNTJ7;WhoPAN_l{d{{|md~|47hp)faCeyxs3Gq$6k3)>Cma3oPf< Jwa$L+{RCX1e6s)m literal 0 HcmV?d00001 diff --git a/libraries/community/p2/All/Simple_SpiFlash/jm_nstr.spin2 b/libraries/community/p2/All/Simple_SpiFlash/jm_nstr.spin2 new file mode 100644 index 00000000..fbe449ac --- /dev/null +++ b/libraries/community/p2/All/Simple_SpiFlash/jm_nstr.spin2 @@ -0,0 +1 @@ +'' ================================================================================================= '' '' File....... jm_nstr.spin2 '' Purpose.... Convert numbers to strings '' Authors.... Jon McPhalen '' -- Copyright (c) 2020 Jon McPhalen '' -- see below for terms of use '' E-mail..... jon.mcphalen@gmail.com '' Started.... '' Updated.... 28 JUN 2020 '' '' ================================================================================================= con NBUF_SIZE = 33 PBUF_SIZE = 81 var byte nbuf[NBUF_SIZE] ' number conversions byte pbuf[PBUF_SIZE] ' padded strings pub null() '' This is not a top level object pub fmt_number(value, radix, digits, width, pad) : p_str '' Return pointer to string of value converted to number in padded field '' -- value is converted using radix '' -- digits is max number of digits to use '' -- width is width of final fields (max) '' -- pad is character used to pad final field (if needed) case_fast radix 02 : p_str := padstr(itoa(value, 2, digits), width, pad) 04 : p_str := padstr(itoa(value, 4, digits), width, pad) 08 : p_str := padstr(itoa(value, 8, digits), width, pad) 10 : p_str := padstr(itoa(value, 10, digits), width, pad) 16 : p_str := padstr(itoa(value, 16, digits), width, pad) 99 : p_str := padstr(dpdec(value, digits), width, pad) ' special case other : p_str := string("?") pub dec(value, digits) : p_str | sign, len '' Convert decimal value to string '' -- digits is 0 (auto size) to 10 p_str := itoa(value, 10, digits) pub dpdec(value, dp) : p_str | len, byte scratch[12] '' Convert value to string with decimal point '' -- dp is digits after decimal point '' -- returns pointer to updated fp string '' -- modifies original string '' -- return pointer to converted string p_str := itoa(value, 10, 0) if (dp <= 0) ' abort if no decimal point return p_str len := strsize(p_str) ' digits bytefill(@scratch, 0, 12) ' clear scratch buffer if (value < 0) ' ignore "-" if present ++p_str --len if (len < (dp+1)) ' insert 0s? bytemove(@scratch, p_str, len) ' move digits to scratch buffer bytefill(p_str, "0", dp+2-len) ' pad string with 0s bytemove(p_str+dp+2-len, @scratch, len+1) ' move digits back byte[p_str+1] := "." ' insert dpoint else bytemove(@scratch, p_str+len-dp, dp) ' move decimal part to buffer byte[p_str+len-dp] := "." ' insert dpoint bytemove(p_str+len-dp+1, @scratch, dp+1) ' move decimal part back if (value < 0) ' fix pointer for negative #s --p_str pub itoa(value, radix, digits) : p_str | sign, len, d '' Convert integer to string '' -- supports radix 10, 2, 4, 8, and 16 '' -- digits is 0 (auto size) to limit for long using radix bytefill(@nbuf, 0, NBUF_SIZE) ' clear buffer p_str := @nbuf ' point to it case radix ' fix digits 02 : digits := 0 #> digits <# 32 04 : digits := 0 #> digits <# 16 08 : digits := 0 #> digits <# 11 10 : digits := 0 #> digits <# 10 16 : digits := 0 #> digits <# 8 other : byte[p_str] := 0 return if ((radix == 10) && (value < 0)) ' deal with negative decimals if (value == negx) sign := 2 value := posx else sign := 1 value := -value else sign := 0 len := 0 repeat d := value +// radix ' get digit (1s column) byte[p_str++] := (d < 10) ? d + "0" : d - 10 + "A" ' convert to ASCII value +/= radix ' remove digit if (digits) ' length limited? if (++len == digits) ' check size quit else if (value == 0) ' done? quit if (sign) byte[p_str++] := "-" ' add sign if needed if (sign == 2) nbuf[0] := "8" ' fix negx if needed byte[p_str++] := 0 ' terminate string return revstr(@nbuf) ' fix order (reverse) pub revstr(p_str) : result | first, len, last '' Reverse the order of characters in a string. result := first := p_str ' start len := strsize(p_str) ' length last := first + len - 1 ' end repeat (len >> 1) ' reverse them byte[first++], byte[last--] := byte[last], byte[first] pub padstr(p_str, width, padchar) : p_pad | len '' Pad string with padchar character '' -- positive width uses left pad, negative field width uses right pad '' -- truncate if string len > width '' -- input string is not modified '' -- returns pointer to padded string bytefill(@pbuf, 0, PBUF_SIZE) ' clear padded buffer len := strsize(p_str) ' get length of input width := -PBUF_SIZE+1 #> width <# PBUF_SIZE-1 ' constrain to buffer size if (width > 0) ' right-justify in padded field if (width > len) bytefill(@pbuf, padchar, width-len) bytemove(@pbuf+width-len, p_str, len) p_pad := @pbuf else bytemove(@pbuf, p_str+len-width, width) ' truncate to right-most characters p_pad := @pbuf elseif (width < 0) ' left-justify in padded field width := -width if (width > len) bytemove(@pbuf, p_str, len) bytefill(@pbuf+len, padchar, width-len) p_pad := @pbuf else bytemove(@pbuf, p_str, width) ' truncate to leftmost characters p_pad := @pbuf else p_pad := p_str con { license } {{ Terms of Use: MIT License Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. }} \ No newline at end of file diff --git a/libraries/community/p2/All/Simple_SpiFlash/jm_serial.spin2 b/libraries/community/p2/All/Simple_SpiFlash/jm_serial.spin2 new file mode 100644 index 00000000..8e2e66d6 --- /dev/null +++ b/libraries/community/p2/All/Simple_SpiFlash/jm_serial.spin2 @@ -0,0 +1,541 @@ +'' ================================================================================================= +'' +'' File....... jm_serial.spin2 +'' Purpose.... True mode, unbuffererd serial coms using smart pins +'' -- same features as original P1 FDS with minor enhancements +'' Authors.... Eric Smith, Chip Gracey, and Jon McPhalen +'' -- see below for terms of use +'' E-mail..... jon.mcphalen@gmail.com +'' Started.... +'' Updated.... 28 JUN 2020 +'' +'' ================================================================================================= + + +con { fixed io pins } + + RX1 = 63 { I } ' programming / debug + TX1 = 62 { O } + + FS_CS = 61 { O } ' flash storage + FS_CLK = 60 { O } + FS_MOSI = 59 { O } + FS_MISO = 58 { I } + + +con { pst formatting } + + HOME = 1 + CRSR_XY = 2 + CRSR_LF = 3 + CRSR_RT = 4 + CRSR_UP = 5 + CRSR_DN = 6 + BELL = 7 + BKSP = 8 + TAB = 9 + LF = 10 + CLR_EOL = 11 + CLR_DN = 12 + CR = 13 + CRSR_X = 14 + CRSR_Y = 15 + CLS = 16 + + +obj + + nstr : "jm_nstr" ' number-to-string + + +var + + long rxp + long txp + + byte pbuf[80] ' padded strings + + +pub null() + + '' This is not a top level object + + +pub start(baudrate) + +'' Start simple serial coms on default pins at baudrate + + startx(RX1, TX1, baudrate) ' use programming port + + +pub startx(rxpin, txpin, baud) | bitmode + +'' Start simple serial coms on rxpin and txpin at baud + + longmove(@rxp, @rxpin, 2) ' save pins + + bitmode := muldiv64(clkfreq, $1_0000, baud) & $FFFFFC00 ' set bit timing + bitmode |= 7 ' set bits (8) + + org + fltl rxpin ' configure rx smart pin + wrpin ##P_ASYNC_RX, rxpin + wxpin bitmode, rxpin + drvl rxpin + fltl txpin ' configure tx smart pin + wrpin ##(P_ASYNC_TX | P_OE), txpin + wxpin bitmode, txpin + drvl txpin + end + + +pub rxflush() + +'' Clear serial input + + repeat + while (rxcheck() >= 0) + + +pub rxcheck() : rxbyte | check + +'' Check for serial input +'' -- returns -1 if nothing available + + rxbyte := -1 + check := pinr(rxp) + if (check) + rxbyte := rdpin(rxp) >> 24 + + +pub rxtime(ms) : b | mstix, t + +'' Wait ms milliseconds for a byte to be received +'' -- returns -1 if no byte received, $00..$FF if byte + + mstix := clkfreq / 1000 + + t := getct() + repeat + until ((b := rxcheck()) >= 0) or (((getct() - t) / mstix) > ms) + + +pub rx() : rxbyte + +'' Wait for serial input +'' -- blocks! + + repeat + rxbyte := rxcheck() + until (rxbyte >= 0) + + +pub tx(b) + +'' Emit byte + + wypin(txp, b) + txflush() + + +pub txn(b, n) + +'' Emit byte n times + + repeat n + tx(b) + + +pub txflush() | check + +'' Wait until last byte has finished + + repeat + check := pinr(txp) + while (check == 0) + + +pub str(p_str) + +'' Emit z-string at p_str + + repeat (strsize(p_str)) + tx(byte[p_str++]) + + +pub substr(p_str, len) | b + +'' Emit len characters of string at p_str +'' -- aborts if end of string detected + + repeat len + b := byte[p_str++] + if (b > 0) + tx(b) + else + quit + + +pub padstr(p_str, width, pad) + +'' Emit p_str as padded field of width characters +'' -- pad is character to use to fill out field +'' -- positive width causes right alignment +'' -- negative width causes left alignment + + str(nstr.padstr(p_str, width, pad)) + + +con { formatted strings } + +{{ + Escaped characters + + \\ backslash char + \% percent char + \q double quote + \b backspace + \t tab (horizontal) + \n new line (vertical tab) + \r carriage return + \nnn arbitrary ASCII value (nnn is decimal) + + Formatted arguments + + %w.pf print argument as decimal width decimal point + %[w[.p]]d print argument as decimal + %[w[.p]]x print argument as hex + %[w[.p]]o print argument as octal + %[w[.p]]q print argument as quarternary + %[w[.p]]b print argument as binary + %[w]s print argument as string + %[w]c print argument as character ( + + -- w is field width + * positive w causes right alignment in field + * negative w causes left alignment in field + -- %ws aligns s in field (may truncate) + -- %wc prints w copies of c + -- p is precision characters + * number of characters to use, aligned in field + -- prepends 0 if needed to match p + -- for %w.pf, p is number of digits after decimal point +}} + + +pub fstr0(p_str) + +'' Emit string with formatting characters. + + format(p_str, 0) + + +pub fstr1(p_str, arg1) + +'' Emit string with formatting characters and one argument. + + format(p_str, @arg1) + + +pub fstr2(p_str, arg1, arg2) + +'' Emit string with formatting characters and two arguments. + + format(p_str, @arg1) + + +pub fstr3(p_str, arg1, arg2, arg3) + +'' Emit string with formatting characters and three arguments. + + format(p_str, @arg1) + + +pub fstr4(p_str, arg1, arg2, arg3, arg4) + +'' Emit string with formatting characters and four arguments. + + format(p_str, @arg1) + + +pub fstr5(p_str, arg1, arg2, arg3, arg4, arg5) + +'' Emit string with formatting characters and five arguments. + + format(p_str, @arg1) + + +pub fstr6(p_str, arg1, arg2, arg3, arg4, arg5, arg6) + +'' Emit string with formatting characters and six arguments. + + format(p_str, @arg1) + + +pub format(p_str, p_args) | idx, c, asc, field, digits + +'' Emit formatted string with escape sequences and embedded values +'' -- p_str is a pointer to the format control string +'' -- p_args is pointer to array of longs that hold field values +'' * field values can be numbers, characters, or pointers to strings + + idx := 0 ' value index + + repeat + c := byte[p_str++] + if (c == 0) + return + + elseif (c == "\") + c := byte[p_str++] + if (c == "\") + tx("\") + elseif (c == "%") + tx("%") + elseif (c == "q") + tx(34) + elseif (c == "b") + tx(BKSP) + elseif (c == "t") + tx(TAB) + elseif (c == "n") + tx(LF) + elseif (c == "r") + tx(CR) + elseif ((c >= "0") and (c <= "9")) + --p_str + p_str, asc, _ := get_nargs(p_str) + if ((asc >= 0) and (asc <= 255)) + tx(asc) + + elseif (c == "%") + p_str, field, digits := get_nargs(p_str) + c := byte[p_str++] + if (c == "f") + str(nstr.fmt_number(long[p_args][idx++], 99, digits, field, " ")) + elseif (c == "d") + str(nstr.fmt_number(long[p_args][idx++], 10, digits, field, " ")) + elseif (c == "x") + str(nstr.fmt_number(long[p_args][idx++], 16, digits, field, " ")) + elseif (c == "o") + str(nstr.fmt_number(long[p_args][idx++], 08, digits, field, " ")) + elseif (c == "q") + str(nstr.fmt_number(long[p_args][idx++], 04, digits, field, " ")) + elseif (c == "b") + str(nstr.fmt_number(long[p_args][idx++], 02, digits, field, " ")) + elseif (c == "s") + str(nstr.padstr(long[p_args][idx++], field, " ")) + elseif (c == "c") + txn(long[p_args][idx++], (abs field) #> 1) + + else + tx(c) + + +pri get_nargs(p_str) : p_str1, val1, val2 | c, sign + +'' Parse one or two numbers from string in n, -n, n.n, or -n.n format +'' -- dpoint separates values +'' -- only first # may be negative +'' -- returns pointer to 1st char after value(s) + + c := byte[p_str] ' check for negative on first value + if (c == "-") + sign := -1 + ++p_str + else + sign := 0 + + repeat ' get first value + c := byte[p_str++] + if ((c >= "0") and (c <= "9")) + val1 := (val1 * 10) + (c - "0") + else + if (sign) + val1 := -val1 + quit + + if (c == ".") ' if dpoint + repeat ' get second value + c := byte[p_str++] + if ((c >= "0") and (c <= "9")) + val2 := (val2 * 10) + (c - "0") + else + quit + + p_str1 := p_str - 1 ' back up to non-digit + + +pub fmt_number(value, base, digits, width, pad) + +'' Emit value converted to number in padded field +'' -- value is converted using base as radix +'' * 99 for decimal with digits after decimal point +'' -- digits is max number of digits to use +'' -- width is width of final field (max) +'' -- pad is character that fills out field + + str(nstr.fmt_number(value, base, digits, width, pad)) + + +pub dec(value) + +'' Emit value as decimal + + str(nstr.itoa(value, 10, 0)) + + +pub fdec(value, digits) + +'' Emit value as decimal using fixed # of digits +'' -- may add leading zeros + + str(nstr.itoa(value, 10, digits)) + + +pub jdec(value, digits, width, pad) + +'' Emit value as decimal using fixed # of digits +'' -- aligned in padded field (negative width to left-align) +'' -- digits is max number of digits to use +'' -- width is width of final field (max) +'' -- pad is character that fills out field + + str(nstr.fmt_number(value, 10, digits, width, pad)) + + +pub dpdec(value, dp) + +'' Emit value as decimal with decimal point +'' -- dp is number of digits after decimal point + + str(nstr.dpdec(value, dp)) + + +pub jdpdec(value, dp, width, pad) + +'' Emit value as decimal with decimal point +'' -- aligned in padded field (negative width to left-align) +'' -- dp is number of digits after decimal point +'' -- width is width of final field (max) +'' -- pad is character that fills out field + + str(nstr.fmt_number(value, 99, dp, width, pad)) + + +pub hex(value) + +'' Emit value as hexadecimal + + str(nstr.itoa(value, 16, 0)) + + +pub fhex(value, digits) + +'' Emit value as hexadecimal using fixed # of digits + + str(nstr.itoa(value, 16, digits)) + + +pub jhex(value, digits, width, pad) + +'' Emit value as quarternary using fixed # of digits +'' -- aligned inside field +'' -- pad fills out field + + str(nstr.fmt_number(value, 16, digits, width, pad)) + + +pub oct(value) + +'' Emit value as octal + + str(nstr.itoa(value, 8, 0)) + + +pub foct(value, digits) + +'' Emit value as octal using fixed # of digits + + str(nstr.itoa(value, 8, digits)) + + +pub joct(value, digits, width, pad) + +'' Emit value as octal using fixed # of digits +'' -- aligned inside field +'' -- pad fills out field + + str(nstr.fmt_number(value, 8, digits, width, pad)) + + +pub qrt(value) + +'' Emit value as quarternary + + str(nstr.itoa(value, 4, 0)) + + +pub fqrt(value, digits) + +'' Emit value as quarternary using fixed # of digits + + str(nstr.itoa(value, 4, digits)) + + +pub jqrt(value, digits, width, pad) + +'' Emit value as quarternary using fixed # of digits +'' -- aligned inside field +'' -- pad fills out field + + str(nstr.fmt_number(value, 4, digits, width, pad)) + + +pub bin(value) + +'' Emit value as binary + + str(nstr.itoa(value, 2, 0)) + + +pub fbin(value, digits) + +'' Emit value as binary using fixed # of digits + + str(nstr.itoa(value, 2, digits)) + + +pub jbin(value, digits, width, pad) + +'' Emit value as binary using fixed # of digits +'' -- aligned inside field +'' -- pad fills out field + + str(nstr.fmt_number(value, 2, digits, width, pad)) + + +con { license } + +{{ + + Terms of Use: MIT License + + Permission is hereby granted, free of charge, to any person obtaining a copy of this + software and associated documentation files (the "Software"), to deal in the Software + without restriction, including without limitation the rights to use, copy, modify, + merge, publish, distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to the following + conditions: + + The above copyright notice and this permission notice shall be included in all copies + or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A + PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE + OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +}} \ No newline at end of file