diff --git a/assets/disk0/tvdos/TVDOS.SYS b/assets/disk0/tvdos/TVDOS.SYS index e948768..653576a 100644 --- a/assets/disk0/tvdos/TVDOS.SYS +++ b/assets/disk0/tvdos/TVDOS.SYS @@ -261,8 +261,20 @@ _TVDOS.DRV.FS.SERIAL.getFileLen = (fd) => { } return Number(com.pullMessage(port[0])) } -// TODO pread replaces DMA.comToRam -// TODO pwrite replaces DMA.ramToCom +_TVDOS.DRV.FS.SERIAL.pread = (fd, ptr, count, offset) => { + if (129 == _TVDOS.DRV.FS.SERIAL._openr(fd)) throw Error(`No such file: ${fd.fullPath}`) + + let port = _TVDOS.DRV.FS.SERIAL._toPorts(fd.driveLetter) + com.sendMessage(port[0], "READ") + let response = com.getStatusCode(port[0]) + if (135 == response) { + throw Error("File not opened") + } + if (response < 0 || response >= 128) { + throw Error("Reading a file failed with "+response) + } + dma.comToRam(port[0], offset, ptr, count) +} _TVDOS.DRV.FS.SERIAL.sread = (fd) => { if (129 == _TVDOS.DRV.FS.SERIAL._openr(fd)) throw Error(`No such file: ${fd.fullPath}`) @@ -277,6 +289,15 @@ _TVDOS.DRV.FS.SERIAL.sread = (fd) => { } return com.pullMessage(port[0]) } +_TVDOS.DRV.FS.SERIAL.pwrite = (fd, ptr, count, offset) => { + if (offset) throw Error(`Write offset not supported on Serial device such as disk drives`) + + let rrrr = _TVDOS.DRV.FS.SERIAL._openw(fd); if (rrrr != 0) throw Error("Writing a file failed with "+rrrr) + + let port = _TVDOS.DRV.FS.SERIAL._toPorts(fd.driveLetter) + dma.ramToCom(ptr, port[0], count) + +} _TVDOS.DRV.FS.SERIAL.swrite = (fd, string) => { let rrrr = _TVDOS.DRV.FS.SERIAL._openw(fd); if (rrrr != 0) throw Error("Writing a file failed with "+rrrr) @@ -399,6 +420,7 @@ _TVDOS.DRV.FS.DEVRND.pread = (fd, ptr, count, offset) => { for (let i = 0; i < count; i++) { sys.poke(ptr + i, bytes[offset + i]) } + } _TVDOS.DRV.FS.DEVRND.pwrite = (fd, ptr, count, offset) => {} @@ -570,8 +592,8 @@ Object.freeze(_TVDOS.DRV.FS.DEVFBIPF) // Legacy Serial filesystem, !!pending for removal!! -/* -const filesystem = {}; + +/*const filesystem = {}; filesystem._toPorts = (driveLetter) => { if (driveLetter.toUpperCase === undefined) { @@ -692,8 +714,8 @@ filesystem.remove = (driveLetter) => { var response = com.getStatusCode(port[0]); return (response === 0); }; -Object.freeze(filesystem); -*/ +Object.freeze(filesystem);*/ + /////////////////////////////////////////////////////////////////////////////// diff --git a/assets/disk0/tvdos/bin/decodeipf.js b/assets/disk0/tvdos/bin/decodeipf.js new file mode 100644 index 0000000..b29eb01 --- /dev/null +++ b/assets/disk0/tvdos/bin/decodeipf.js @@ -0,0 +1,47 @@ +if (exec_args[1] == undefined) { + println("decodeipf ") + return 1 +} + +let infile = files.open(_G.shell.resolvePathInput(exec_args[1]).full) + +// read input file +let infilePtr = sys.malloc(infile.size) +infile.pread(infilePtr, infile.size, 0) + +// check if magic number matches + +const MAGIC = [0x1F, 0x54, 0x53, 0x56, 0x4D, 0x69, 0x50, 0x46] +let magicMatching = true + +MAGIC.forEach((b,i) => { + let testb = sys.peek(infilePtr + i) & 255 // for some reason this must be located here + if (testb != b) { + magicMatching = false + } +}) +if (!magicMatching) { + println("Not an iPF file (MAGIC mismatch)") + return 1 +} + +// decode input image +let width = sys.peek(infilePtr+8) | (sys.peek(infilePtr+9) << 8) +let height = sys.peek(infilePtr+10) | (sys.peek(infilePtr+11) << 8) +let hasAlpha = (sys.peek(infilePtr+12) != 0) +let ipfType = sys.peek(infilePtr+13) +let imgLen = sys.peek(infilePtr+24) | (sys.peek(infilePtr+25) << 8) | (sys.peek(infilePtr+26) << 16) | (sys.peek(infilePtr+27) << 24) +let decodefun = undefined +if (ipfType == 1) decodefun = graphics.decodeIpf1 +if (ipfType == 2) decodefun = graphics.decodeIpf2 +if (decodefun === undefined) throw Error(`Unknown IPF format: ${ipfType}`) + +let ipfbuf = sys.malloc(imgLen) +gzip.decompFromTo(infilePtr + 28, infile.size - 28, ipfbuf) // should return FBUF_SIZE +sys.free(infilePtr) + +graphics.setGraphicsMode(4) +graphics.clearText(); graphics.clearPixels(0); graphics.clearPixels2(0) +decodefun(ipfbuf, -1048577, -1310721, width, height, hasAlpha) + +sys.free(ipfbuf) \ No newline at end of file diff --git a/assets/disk0/tvdos/bin/encodeipf.js b/assets/disk0/tvdos/bin/encodeipf.js new file mode 100644 index 0000000..ee799a9 --- /dev/null +++ b/assets/disk0/tvdos/bin/encodeipf.js @@ -0,0 +1,57 @@ +if (exec_args[3] == undefined) { + println("encodeipf <1/2> [/noalpha]") + return 1 +} + +let noalpha = exec_args[4] != undefined && exec_args[4].toLowerCase() == "/noalpha" + +let infile = files.open(_G.shell.resolvePathInput(exec_args[2]).full) +let outfile = files.open(_G.shell.resolvePathInput(exec_args[3]).full) + +let ipfType = exec_args[1]|0 +let encodefun = undefined +if (1 == exec_args[1]) encodefun = graphics.encodeIpf1 +if (2 == exec_args[1]) encodefun = graphics.encodeIpf2 +if (encodefun === undefined) throw Error(`Unknown IPF format: ${exec_args[1]}`) + +// read input file +let infilePtr = sys.malloc(infile.size) +infile.pread(infilePtr, infile.size, 0) + +// decode input image +const [imgw, imgh, channels, imageDataPtr] = graphics.decodeImage(infilePtr, infile.size) // stored as [R | G | B | (A)] +sys.free(infilePtr) +let hasAlpha = (4 == channels) && !noalpha + +// encode image +let ipfBlockCount = Math.ceil(imgw / 4.0) * Math.ceil(imgh / 4.0) +let ipfSizePerBlock = 12 + 4*(ipfType - 1) + 8*hasAlpha +let ipfRawSize = ipfSizePerBlock * ipfBlockCount +let ipfarea = sys.malloc(ipfRawSize) +let gzippedImage = sys.malloc(28 + ipfRawSize+8) // ipf file header + somewhat arbitrary number. Get the actual count using 28+gzlen +encodefun(imageDataPtr, ipfarea, imgw, imgh, channels, hasAlpha, 0) +let gzlen = gzip.compFromTo(ipfarea, ipfRawSize, gzippedImage + 28) + + +sys.free(ipfarea) + +// write to the output bin +//// write header +;[ + 0x1F, 0x54, 0x53, 0x56, 0x4D, 0x69, 0x50, 0x46, // magic + imgw & 255, (imgw >> 8) & 255, // width + imgh & 255, (imgh >> 8) & 255, // height + 0+hasAlpha, // has alpha + ipfType, // ipf type + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // reserved + (gzlen >>> 0) & 255, // uncompressed size + (gzlen >>> 8) & 255, + (gzlen >>> 16) & 255, + (gzlen >>> 24) & 255 +].forEach((b,i) => sys.poke(gzippedImage + i, b)) + +outfile.mkFile() +outfile.pwrite(gzippedImage, 28 + gzlen, 0) +//dma.ramToCom(writeBuf, 0, writeCount) +sys.free(gzippedImage) +println(`Wrote ${28 + gzlen} bytes to the file`) \ No newline at end of file diff --git a/assets/disk0/ycocg.ipf1 b/assets/disk0/ycocg.ipf1 new file mode 100644 index 0000000..9925ccf Binary files /dev/null and b/assets/disk0/ycocg.ipf1 differ diff --git a/assets/disk0/ycocg.ipf2 b/assets/disk0/ycocg.ipf2 new file mode 100644 index 0000000..297f363 Binary files /dev/null and b/assets/disk0/ycocg.ipf2 differ diff --git a/assets/disk0/ycocg2.ipf1 b/assets/disk0/ycocg2.ipf1 new file mode 100644 index 0000000..4b7a0dc Binary files /dev/null and b/assets/disk0/ycocg2.ipf1 differ diff --git a/assets/disk0/ycocg2.ipf2 b/assets/disk0/ycocg2.ipf2 new file mode 100644 index 0000000..9d24f5c Binary files /dev/null and b/assets/disk0/ycocg2.ipf2 differ diff --git a/terranmon.txt b/terranmon.txt index acfbcc3..52f3ec0 100644 --- a/terranmon.txt +++ b/terranmon.txt @@ -413,13 +413,13 @@ TYPE 255 FRAME - TSVM Interchangeable Picture Format (aka iPF Type 1/2) -Image is divided into 4x4 blocks and each block is serialised, then the entire file is gzipped +Image is divided into 4x4 blocks and each block is serialised, then the entire iPF blocks are gzipped # File Structure \x1F T S V M i P F [HEADER] -[Blocks.gz] or [Blocks] // gzipping is optional and only done for videos +[Blocks.gz] - Header uint16 WIDTH diff --git a/tsvm_core/src/net/torvald/tsvm/CompressorDelegate.kt b/tsvm_core/src/net/torvald/tsvm/CompressorDelegate.kt index 8a606d4..77ea419 100644 --- a/tsvm_core/src/net/torvald/tsvm/CompressorDelegate.kt +++ b/tsvm_core/src/net/torvald/tsvm/CompressorDelegate.kt @@ -6,7 +6,7 @@ import java.io.ByteArrayOutputStream import java.util.zip.GZIPInputStream import java.util.zip.GZIPOutputStream -class CompressorDelegate(val vm: VM) { +class CompressorDelegate(private val vm: VM) { fun comp(str: String) = Companion.comp(str) fun comp(ba: ByteArray) = Companion.comp(ba) diff --git a/tsvm_core/src/net/torvald/tsvm/DMADelegate.kt b/tsvm_core/src/net/torvald/tsvm/DMADelegate.kt index 0d289a9..c130045 100644 --- a/tsvm_core/src/net/torvald/tsvm/DMADelegate.kt +++ b/tsvm_core/src/net/torvald/tsvm/DMADelegate.kt @@ -6,7 +6,7 @@ import net.torvald.tsvm.peripheral.GraphicsAdapter /** * Created by minjaesong on 2021-10-15. */ -class DMADelegate(val vm: VM) { +class DMADelegate(private val vm: VM) { private val READ = "READ".toByteArray(VM.CHARSET) private val FLUSH = "FLUSH".toByteArray(VM.CHARSET) diff --git a/tsvm_core/src/net/torvald/tsvm/GraphicsJSR223Delegate.kt b/tsvm_core/src/net/torvald/tsvm/GraphicsJSR223Delegate.kt index 91e47f7..2f886fd 100644 --- a/tsvm_core/src/net/torvald/tsvm/GraphicsJSR223Delegate.kt +++ b/tsvm_core/src/net/torvald/tsvm/GraphicsJSR223Delegate.kt @@ -8,7 +8,7 @@ import net.torvald.tsvm.peripheral.GraphicsAdapter import net.torvald.tsvm.peripheral.fmod import kotlin.math.roundToInt -class GraphicsJSR223Delegate(val vm: VM) { +class GraphicsJSR223Delegate(private val vm: VM) { private fun getFirstGPU(): GraphicsAdapter? { return vm.findPeribyType(VM.PERITYPE_GPU_AND_TERM)?.peripheral as? GraphicsAdapter diff --git a/tsvm_core/src/net/torvald/tsvm/SerialHelper.kt b/tsvm_core/src/net/torvald/tsvm/SerialHelper.kt index 28c39b6..04535b8 100644 --- a/tsvm_core/src/net/torvald/tsvm/SerialHelper.kt +++ b/tsvm_core/src/net/torvald/tsvm/SerialHelper.kt @@ -137,7 +137,7 @@ object SerialHelper { data class DeviceStatus(val code: Int, val message: String) } -class SerialHelperDelegate(val vm: VM) { +class SerialHelperDelegate(private val vm: VM) { fun sendMessage(portNo: Int, message: String) = SerialHelper.sendMessage(vm, portNo, message.toByteArray(VM.CHARSET)) fun pullMessage(portNo: Int) = SerialHelper.pullMessage(vm, portNo).toString(VM.CHARSET) fun sendMessageGetBytes(portNo: Int, message: String) = SerialHelper.sendMessageGetBytes(vm, portNo, message.toByteArray(VM.CHARSET)).toString(VM.CHARSET) diff --git a/tsvm_core/src/net/torvald/tsvm/VMJSR223Delegate.kt b/tsvm_core/src/net/torvald/tsvm/VMJSR223Delegate.kt index c07d889..ac3bf8a 100644 --- a/tsvm_core/src/net/torvald/tsvm/VMJSR223Delegate.kt +++ b/tsvm_core/src/net/torvald/tsvm/VMJSR223Delegate.kt @@ -11,7 +11,7 @@ import java.nio.charset.Charset /** * Pass the instance of the class to the ScriptEngine's binding, preferably under the namespace of "vm" */ -class VMJSR223Delegate(val vm: VM) { +class VMJSR223Delegate(private val vm: VM) { fun poke(addr: Int, value: Int) = vm.poke(addr.toLong(), value.toByte()) fun peek(addr: Int) = vm.peek(addr.toLong())!!.toInt().and(255) @@ -186,13 +186,13 @@ class VMJSR223Delegate(val vm: VM) { } } -class VMSerialDebugger(val vm: VM) { +class VMSerialDebugger(private val vm: VM) { fun print(s: Any?) = System.out.print("$s") fun println(s: Any?) = System.out.println("$s") fun printerr(s: Any?) = System.err.println("$s") } -class Parallel(val vm: VM) { +class Parallel(private val vm: VM) { fun spawnNewContext(): VMRunner { return VMRunnerFactory(vm.assetsDir, vm, "js") }