{ _clkfreq = 96_000_000 ' Hybrid _clkmode = xtal1 + pll16x tvPins = 24 kbPins = 12 sdPins = 8 } _clkfreq = 80_000_000 ' Hydra _clkmode = xtal1 + pll8x tvPins = 24 kbPins = 13 sdPins = 16 { Simple command line 2009 April 15 Adding file transfer to/from PC via serial 16 0.02 SendFile bugfix (while blksize == 1024) Tries to run .bin before .eep now. June 4 Changing name from cl to sphinx. Converting to use sxfs, sxtv. 15 sxkb; adding c and cl commands 23 Corrected clock mode calculation. 2010 Feb 25 New version number } obj kb: "sxkb" term: "sxtv" sxfs: "sxfs" f: "sxfile" ser: "fdserial" con SXTVRENDEZVOUS = $8000 - 4 SXKBRENDEZVOUS = SXTVRENDEZVOUS - 4 SDSPIRENDEZVOUS = SXKBRENDEZVOUS - 3 * 4 SXFS2RENDEZVOUS = SDSPIRENDEZVOUS - 4 * 4 ' four rendezvous variables SXFSRENDEZVOUS = SXFS2RENDEZVOUS - 4 * 4 ' four rendezvous variables METADATABUFFER = SXFSRENDEZVOUS - 512 _free = ($8000 - METADATABUFFER) / 4 pub Main | err, p if term.start( tvPins, SXTVRENDEZVOUS ) term.str( string("============= Sphinx 100225 ============", 13) ) term.str( string("video @ pin ") ) term.dec( tvPins ) term.str( string(13, "keyboard @ pin ") ) term.dec( kbPins ) term.str( string(13, "SD @ pin ") ) term.dec( sdPins ) term.out( 13 ) sxfs.start( sdPins ) kb.start( kbPins ) repeat if ina[31] ' USB cable connected? ser.start( 31, 30, %0000, 19200 ) f.Close err := \DoIt if err if err > 0 term.str( err ) else term.str( string("Error ") ) term.dec( err ) term.out( 13 ) else term.str( string("Normal exit") ) ' This never happens pri DoIt | ch term.out( ">" ) term.out( "_" ) term.out( 8 ) repeat if kb.peekkey EditCmdLine Execute term.out( ">" ) term.out( "_" ) term.out( 8 ) if (ch := ser.rxcheck) <> -1 term.out( 8 ) FileTransfer( ch ) term.out( ">" ) term.out( "_" ) term.out( 8 ) con MAXCMDLINELENGTH = 78 ' some arbitray limit. CR = $0d BKSP = $c8 var byte cmdLine[MAXCMDLINELENGTH+1] ' +1 for null terminator long cmdLineLength pri EditCmdLine | key cmdLineLength~ ' cursor is always at end of command line repeat case key := kb.key $20..$7f: if cmdLineLength < MAXCMDLINELENGTH cmdLine[ cmdLineLength++ ] := key term.out( key ) term.out( "_" ) term.out( 8 ) CR: term.out( " " ) term.out( 13 ) cmdLine[ cmdLineLength ]~ return true BKSP: if cmdLineLength --cmdLineLength term.out( " " ) term.out( 8 ) term.out( 8 ) term.out( "_" ) term.out( 8 ) pri FileTransfer( cmd ) | ch, i if cmd <> "G" and cmd <> "P" term.out( cmd ) abort string(" -- unrecognized command from PC") i~ repeat ch := RxSerByte if i => FILENAMEBUFFERSIZE abort string("Filename too long") filename[i++] := ch while ch if cmd == "G" term.str( string("sending ") ) term.str( @filename ) term.out( 13 ) SendFileToPC else term.str( string("receiving ") ) term.str( @filename ) term.out( 13 ) ReceiveFileFromPC pri SendFileToPC | blksize, i, chksum, b, n if f.Open( @filename, "R" ) <> 0 term.str( @filename ) abort string(" -- can't open file for reading") TxSerByte( "A" ) ' ack n~ repeat blksize := f.Read( @buffer, 1024 ) if blksize == -1 blksize~ TxSerByte( blksize.byte[0] ) TxSerByte( blksize.byte[1] ) i~ chksum~ repeat blksize b := buffer[i++] chksum += b TxSerByte( b ) n += blksize if chksum & $ff <> RxSerByte abort string("Checksum error") while blksize == 1024 f.Close term.dec( n ) term.str( string(" bytes sent", 13) ) pri ReceiveFileFromPC | blksize, i, chksum, b, n if f.Open( @filename, "W" ) <> 0 term.str( @filename ) abort string(" -- can't open file for writing") TxSerByte( "A" ) ' ack n~ repeat blksize~ blksize.byte[0] := RxSerByte blksize.byte[1] := RxSerByte if blksize > 1024 abort string("Block size > 1024") i~ chksum~ repeat blksize b := RxSerByte buffer[i++] := b chksum += b n += blksize f.Write( @buffer, blksize ) TxSerByte( chksum ) while blksize == 1024 f.Close term.dec( n ) term.str( string(" bytes received", 13) ) pri RxSerByte : b ' ser.rx with timeout b := ser.rxtime( TIMEOUT ) if b == -1 abort string("RxSerByte timed out") pri TxSerByte( b ) ' just for symmetry with RxSerByte ser.tx( b ) con TIMEOUT = 500 var byte buffer[1024] pri Execute | n, p, q, run, c c~ ifnot n := ParseCmdLine return p := @cmdLine ToUpper(p) if run := strcomp( @cmdLine, string("RUN") ) --n p += strsize(p) + 1 elseif strcomp( @cmdLine, string("C") ) c := 1 --n p += strsize(p) + 1 ' command arg1 arg2... elseif strcomp( @cmdLine, string("CL") ) ' run command arg1 arg2... c := 2 ' c arg1 arg2... --n ' cl arg1 arg2... p += strsize(p) + 1 ifnot n abort string("No file specified") f.Open( string("args.d8a"), "W" ) ' write args if c == 0 q := p + strsize(p) + 1 ' for run and plain command, skip first arg (command name) --n f.Write( @n, 1 ) repeat n f.Write( q, strsize(q) + 1 ) q += strsize(q) + 1 else ' for c and cl, ++n ' add extra arg (/c or /l) f.Write( @n, 1 ) repeat n-1 f.Write( p, strsize(p) + 1 ) p += strsize(p) + 1 if c == 1 f.Write( string("/c"), 3 ) else f.Write( string("/l"), 3 ) n~ f.Write( @n, 1 ) ' final terminating null f.Close if c if f.Open( string("lex.bin"), "R" ) <> 0 abort string("lex.bin not found") ser.stop f.Execute( 0 ) if EndsWith( p, string(".BIN") ) or EndsWith( p, string(".EEP") ) if f.Open( p, "R" ) <> 0 term.str( p ) abort string(" -- not found") else if strsize(p) > MAXFILENAMELENGTH - 4 term.str( p ) abort string(" -- filename too long") bytemove( @filename, p, strsize(p) + 1 ) bytemove( @filename + strsize(p), string(".BIN"), 5 ) if f.Open( @filename, "R" ) <> 0 bytemove( @filename + strsize(p), string(".EEP"), 5 ) if f.Open( @filename, "R" ) <> 0 term.str( p ) abort string(" -- no .bin or .eep found") ser.stop f.Execute( run ) pri ToUpper( p ) repeat while byte[p] if "a" =< byte[p] and byte[p] =< "z" byte[p] += "A" - "a" ++p pri EndsWith( p, s ) if strsize(p) < strsize(s) return false p += strsize(p) - strsize(s) repeat while byte[p] if byte[p++] <> byte[s++] return false return true con MAXFILENAMELENGTH = 12 ' 8 + . + 3 FILENAMEBUFFERSIZE = MAXFILENAMELENGTH + 1 ' 8 + . + 3 + null CMDNAMEBUFFERSIZE = 9 ' 8 + null var byte filename[MAXFILENAMELENGTH+1] ' 8 + . + 3 + null pri ParseCmdLine : n | pSrc, pDst, state {{ Converts cmdLine from " ab de fg \" to "ab\de\fg\" ('\' = null). Returns # of "words". }} { state whitespace null other char 0 ++pSrc; append \0; quit append char; => 1 1 append \0; ++n; => 0 append \0; ++n; quit append char; } pSrc := @cmdLine pDst := @cmdLine state~ repeat if state == 0 if byte[pSrc] == " " ++pSrc elseif byte[pSrc] == 0 byte[pDst++]~ quit else byte[pDst++] := byte[pSrc++] state := 1 elseif state == 1 if byte[pSrc] == " " ++pSrc byte[pDst++]~ ++n state~ elseif byte[pSrc] == 0 byte[pDst++]~ ++n quit else byte[pDst++] := byte[pSrc++] {{ Copyright (c) 2009 Michael Park +------------------------------------------------------------------------------------------------------------------------------+ | 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. | +------------------------------------------------------------------------------------------------------------------------------+ }}