mirror of
https://github.com/curioustorvald/tsvm.git
synced 2026-03-14 15:06:05 +09:00
partially implemented SGR seq; DECTCEM cursor show/hide
This commit is contained in:
@@ -29,7 +29,7 @@ class VMGUI(val appConfig: LwjglApplicationConfiguration) : ApplicationAdapter()
|
||||
override fun create() {
|
||||
super.create()
|
||||
|
||||
gpu = GraphicsAdapter(vm, lcdMode = true)
|
||||
gpu = GraphicsAdapter(vm, lcdMode = false)
|
||||
|
||||
vm.peripheralTable[1] = PeripheralEntry(
|
||||
VM.PERITYPE_TERM,
|
||||
@@ -53,13 +53,20 @@ class VMGUI(val appConfig: LwjglApplicationConfiguration) : ApplicationAdapter()
|
||||
// TEST PRG
|
||||
//val fr = FileReader("./assets/tvdos/command.js")
|
||||
//val fr = FileReader("./assets/jscon.js")
|
||||
|
||||
//val fr1 = FileReader("./assets/bios1.js")
|
||||
val fr1 = FileReader("./assets/phototest.js")
|
||||
val bios = fr1.readText()
|
||||
fr1.close()
|
||||
|
||||
//val fr = FileReader("./assets/tvdos/command.js")
|
||||
val fr = FileReader("./assets/tbas/basic.js")
|
||||
val prg = fr.readText()
|
||||
fr.close()
|
||||
|
||||
vmRunner = VMRunnerFactory(vm, "js")
|
||||
coroutineJob = GlobalScope.launch {
|
||||
//vmRunner.executeCommand(sanitiseJS(gpuTestPaletteJs))
|
||||
vmRunner.executeCommand(sanitiseJS(bios))
|
||||
vmRunner.executeCommand(sanitiseJS(prg))
|
||||
}
|
||||
|
||||
|
||||
@@ -65,7 +65,6 @@ object VMRunnerFactory {
|
||||
}
|
||||
|
||||
override suspend fun executeCommand(command: String) {
|
||||
//(engine as Compilable).compile(command).eval(context) // compiling does not work with bindings in kts
|
||||
engine.eval("\"use strict\";{$command}", context)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,7 +18,10 @@ abstract class BlockTransferInterface(val isMaster: Boolean, val isSlave: Boolea
|
||||
open fun areYouReady(): Boolean = recipient?.ready ?: false
|
||||
open fun areYouBusy(): Boolean = recipient?.busy ?: false
|
||||
|
||||
open fun startSend(sendfun: ((BlockTransferInterface) -> Unit)? = null) {
|
||||
/** A method exposed to outside of the box */
|
||||
abstract fun startSend()
|
||||
/** The actual implementation */
|
||||
protected fun startSend(sendfun: ((BlockTransferInterface) -> Unit)? = null) {
|
||||
if (areYouReady()) {
|
||||
busy = true
|
||||
ready = false
|
||||
@@ -36,8 +39,10 @@ abstract class BlockTransferInterface(val isMaster: Boolean, val isSlave: Boolea
|
||||
recipient?.startSend(null)
|
||||
}
|
||||
|
||||
/** must be called by a sender class */
|
||||
open fun writeout(inputData: ByteArray, writeoutfun: (() -> Unit)? = null) {
|
||||
/** A method exposed to outside of the box */
|
||||
abstract fun writeout(inputData: ByteArray)
|
||||
/** The actual implementation; must be called by a sender class */
|
||||
protected fun writeout(inputData: ByteArray, writeoutfun: (() -> Unit)? = null) {
|
||||
busy = true
|
||||
ready = false
|
||||
blockSize = minOf(inputData.size, BLOCK_SIZE)
|
||||
|
||||
@@ -10,8 +10,8 @@ internal class BlockTransferPort(val vm: VM, val portno: Int) : BlockTransferInt
|
||||
|
||||
internal var hasNext = false
|
||||
|
||||
override fun startSend(sendfun: ((BlockTransferInterface) -> Unit)?) {
|
||||
super.startSend { recipient ->
|
||||
override fun startSend() {
|
||||
startSend { recipient ->
|
||||
val ba = ByteArray(BLOCK_SIZE) { vm.getIO().blockTransferRx[portno][it.toLong()] }
|
||||
recipient.writeout(ba)
|
||||
}
|
||||
@@ -19,8 +19,8 @@ internal class BlockTransferPort(val vm: VM, val portno: Int) : BlockTransferInt
|
||||
|
||||
override fun hasNext(): Boolean = hasNext
|
||||
|
||||
override fun writeout(inputData: ByteArray, writeoutfun: (() -> Unit)?) {
|
||||
super.writeout(inputData) {
|
||||
override fun writeout(inputData: ByteArray) {
|
||||
writeout(inputData) {
|
||||
val copySize = minOf(BLOCK_SIZE, inputData.size).toLong()
|
||||
val arrayOffset = UnsafeHelper.getArrayOffset(inputData).toLong()
|
||||
UnsafeHelper.memcpyRaw(inputData, arrayOffset, null, vm.getIO().blockTransferRx[portno].ptr, copySize)
|
||||
|
||||
@@ -116,6 +116,7 @@ abstract class GlassTty(val TEXT_ROWS: Int, val TEXT_COLS: Int) {
|
||||
'S' -> return accept { scrollUp() }
|
||||
'T' -> return accept { scrollDown() }
|
||||
'm' -> return accept { sgrOneArg() }
|
||||
'?' -> ttyEscState = TTY_ESC_STATE.PRIVATESEQ
|
||||
';' -> {
|
||||
ttyEscArguments.push(0)
|
||||
ttyEscState = TTY_ESC_STATE.SEP1
|
||||
@@ -124,6 +125,20 @@ abstract class GlassTty(val TEXT_ROWS: Int, val TEXT_COLS: Int) {
|
||||
else -> return reject()
|
||||
}
|
||||
}
|
||||
TTY_ESC_STATE.PRIVATESEQ -> {
|
||||
when (char.toChar()) {
|
||||
in '0'..'9' -> registerNewNumberArg(char, TTY_ESC_STATE.PRIVATENUM)
|
||||
else -> return reject()
|
||||
}
|
||||
}
|
||||
TTY_ESC_STATE.PRIVATENUM -> {
|
||||
when (char.toChar()) {
|
||||
'h' -> return accept { privateSeqH(ttyEscArguments.pop()) }
|
||||
'l' -> return accept { privateSeqL(ttyEscArguments.pop()) }
|
||||
in '0'..'9' -> appendToExistingNumber(char)
|
||||
else -> return reject()
|
||||
}
|
||||
}
|
||||
TTY_ESC_STATE.NUM1 -> {
|
||||
when (char.toChar()) {
|
||||
'A' -> return accept { cursorUp(ttyEscArguments.pop()) }
|
||||
@@ -231,6 +246,8 @@ abstract class GlassTty(val TEXT_ROWS: Int, val TEXT_COLS: Int) {
|
||||
abstract fun insertTab()
|
||||
abstract fun crlf()
|
||||
abstract fun backspace()
|
||||
abstract fun privateSeqH(arg: Int)
|
||||
abstract fun privateSeqL(arg: Int)
|
||||
|
||||
abstract fun getPrintStream(): OutputStream
|
||||
abstract fun getErrorStream(): OutputStream
|
||||
@@ -244,7 +261,7 @@ abstract class GlassTty(val TEXT_ROWS: Int, val TEXT_COLS: Int) {
|
||||
private val ESC = 0x1B.toByte()
|
||||
|
||||
private enum class TTY_ESC_STATE {
|
||||
INITIAL, ESC, CSI, NUM1, SEP1, NUM2, SEP2, NUM3
|
||||
INITIAL, ESC, CSI, NUM1, SEP1, NUM2, SEP2, NUM3, PRIVATESEQ, PRIVATENUM
|
||||
}
|
||||
|
||||
|
||||
@@ -283,6 +300,13 @@ digraph G {
|
||||
CSI -> SGR [label="m"]
|
||||
CSI -> separator1 [label="; (zero)"]
|
||||
|
||||
CSI -> privateseq [label="?"]
|
||||
|
||||
privateseq -> privatenum [label="0..9"]
|
||||
|
||||
privatenum -> privateSeqH [label=h]
|
||||
privatenum -> privateSeqL [label=l]
|
||||
|
||||
numeral -> numeral [label="0..9"]
|
||||
numeral -> CursorUp [label="A"]
|
||||
numeral -> CursorDown [label="B"]
|
||||
|
||||
@@ -15,7 +15,7 @@ import java.io.InputStream
|
||||
import java.io.OutputStream
|
||||
import kotlin.experimental.and
|
||||
|
||||
class GraphicsAdapter(val vm: VM, val lcdMode: Boolean = false) : GlassTty(Companion.TEXT_ROWS, Companion.TEXT_COLS), PeriBase {
|
||||
class GraphicsAdapter(val vm: VM, val lcdMode: Boolean = false, lcdInvert: Boolean = true) : GlassTty(Companion.TEXT_ROWS, Companion.TEXT_COLS), PeriBase {
|
||||
|
||||
override fun getVM(): VM {
|
||||
return vm
|
||||
@@ -34,8 +34,8 @@ class GraphicsAdapter(val vm: VM, val lcdMode: Boolean = false) : GlassTty(Compa
|
||||
internal val spriteAndTextArea = UnsafeHelper.allocate(10660L)
|
||||
private val unusedArea = ByteArray(92)
|
||||
|
||||
private val paletteShader = AppLoader.loadShaderInline(DRAW_SHADER_VERT, if (lcdMode) DRAW_SHADER_FRAG_LCD else DRAW_SHADER_FRAG)
|
||||
private val textShader = AppLoader.loadShaderInline(DRAW_SHADER_VERT, if (lcdMode) TEXT_TILING_SHADER_LCD else TEXT_TILING_SHADER)
|
||||
private val paletteShader = AppLoader.loadShaderInline(DRAW_SHADER_VERT, if (lcdMode && !lcdInvert) DRAW_SHADER_FRAG_LCD_NOINV else if (lcdMode) DRAW_SHADER_FRAG_LCD else DRAW_SHADER_FRAG)
|
||||
private val textShader = AppLoader.loadShaderInline(DRAW_SHADER_VERT, if (lcdMode && !lcdInvert) TEXT_TILING_SHADER_LCD_NOINV else if (lcdMode) TEXT_TILING_SHADER_LCD else TEXT_TILING_SHADER)
|
||||
|
||||
override var blinkCursor = true
|
||||
override var ttyRawMode = false
|
||||
@@ -111,6 +111,10 @@ class GraphicsAdapter(val vm: VM, val lcdMode: Boolean = false) : GlassTty(Compa
|
||||
// -1 is preferred because it points to the colour CLEAR, and it's constant.
|
||||
spriteAndTextArea.fillWith(-1)
|
||||
|
||||
unusedArea[0] = 0
|
||||
unusedArea[1] = 2
|
||||
unusedArea[2] = 14
|
||||
|
||||
setCursorPos(0, 0)
|
||||
|
||||
println(framebuffer.pixels.limit())
|
||||
@@ -331,28 +335,57 @@ class GraphicsAdapter(val vm: VM, val lcdMode: Boolean = false) : GlassTty(Compa
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Color table for default palette
|
||||
|
||||
Black 240
|
||||
Red 160
|
||||
Green 30
|
||||
Yellow 230
|
||||
Blue 19
|
||||
Magenta 199
|
||||
Cyan 74
|
||||
White 254
|
||||
*/
|
||||
private val sgrDefault8ColPal = intArrayOf(240,160,30,230,19,199,74,254)
|
||||
|
||||
override fun sgrOneArg(arg: Int) {
|
||||
TODO("Not yet implemented")
|
||||
|
||||
if (arg in 30..37) {
|
||||
ttyFore = sgrDefault8ColPal[arg - 30]
|
||||
}
|
||||
else if (arg in 40..47) {
|
||||
ttyBack = sgrDefault8ColPal[arg - 40]
|
||||
}
|
||||
else if (arg == 0) {
|
||||
ttyFore = TTY_FORE_DEFAULT
|
||||
ttyBack = TTY_BACK_DEFAULT
|
||||
}
|
||||
}
|
||||
|
||||
override fun sgrTwoArg(arg1: Int, arg2: Int) {
|
||||
/*
|
||||
Color table for default palette
|
||||
|
||||
Black 240
|
||||
Red 160
|
||||
Green 30
|
||||
Yellow 230
|
||||
Blue 19
|
||||
Magenta 199
|
||||
Cyan 74
|
||||
White 254
|
||||
*/
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun sgrThreeArg(arg1: Int, arg2: Int, arg3: Int) {
|
||||
TODO("Not yet implemented")
|
||||
if (arg1 == 38 && arg2 == 5) {
|
||||
ttyFore = arg3
|
||||
}
|
||||
else if (arg1 == 48 && arg2 == 5) {
|
||||
ttyBack = arg3
|
||||
}
|
||||
}
|
||||
|
||||
override fun privateSeqH(arg: Int) {
|
||||
when (arg) {
|
||||
25 -> blinkCursor = true
|
||||
}
|
||||
}
|
||||
|
||||
override fun privateSeqL(arg: Int) {
|
||||
when (arg) {
|
||||
25 -> blinkCursor = false
|
||||
}
|
||||
}
|
||||
|
||||
/** The values are one-based
|
||||
@@ -497,6 +530,9 @@ class GraphicsAdapter(val vm: VM, val lcdMode: Boolean = false) : GlassTty(Compa
|
||||
|
||||
|
||||
outFBOs[0].inUse {
|
||||
val clearCol = Color(unusedArea[0].toInt().and(15).toFloat() / 15f,
|
||||
unusedArea[1].toInt().and(15).toFloat() / 15f,
|
||||
unusedArea[2].toInt().and(15).toFloat() / 15f, 1f)
|
||||
Gdx.gl.glClearColor(0f, 0f, 0f, 0f)
|
||||
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT)
|
||||
|
||||
@@ -504,7 +540,7 @@ class GraphicsAdapter(val vm: VM, val lcdMode: Boolean = false) : GlassTty(Compa
|
||||
batch.inUse {
|
||||
|
||||
// clear screen
|
||||
batch.color = if (lcdMode) LCD_BASE_COL else Color.BLACK
|
||||
batch.color = if (lcdMode) LCD_BASE_COL else clearCol
|
||||
batch.draw(faketex, 0f, 0f, WIDTH.toFloat(), HEIGHT.toFloat())
|
||||
|
||||
|
||||
@@ -532,7 +568,7 @@ class GraphicsAdapter(val vm: VM, val lcdMode: Boolean = false) : GlassTty(Compa
|
||||
// prepare char buffer texture
|
||||
for (y in 0 until TEXT_ROWS) {
|
||||
for (x in 0 until TEXT_COLS) {
|
||||
val drawCursor = textCursorIsOn && cx == x && cy == y
|
||||
val drawCursor = blinkCursor && textCursorIsOn && cx == x && cy == y
|
||||
val addr = y.toLong() * TEXT_COLS + x
|
||||
val char =
|
||||
if (drawCursor) 0xDB else spriteAndTextArea[memTextOffset + addr].toInt().and(255)
|
||||
@@ -709,15 +745,32 @@ uniform vec4 pal[256];
|
||||
float intensitySteps = 4.0;
|
||||
uniform vec4 lcdBaseCol;
|
||||
|
||||
float rand(vec2 co){
|
||||
return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 43758.5453);
|
||||
}
|
||||
|
||||
void main(void) {
|
||||
vec4 palCol = pal[int(texture2D(u_texture, v_texCoords).a * 255.0)];
|
||||
float lum = floor((3.0 * palCol.r + 4.0 * palCol.g + palCol.b) / 8.0 * intensitySteps) / intensitySteps;
|
||||
vec4 outIntensity = vec4(vec3(1.0 - lum), palCol.a);
|
||||
|
||||
// LCD output will invert the luminosity. That is, normally white colour will be black on PM-LCD.
|
||||
gl_FragColor = lcdBaseCol * outIntensity;
|
||||
}
|
||||
""".trimIndent()
|
||||
|
||||
val DRAW_SHADER_FRAG_LCD_NOINV = """
|
||||
#version 120
|
||||
|
||||
varying vec4 v_color;
|
||||
varying vec2 v_texCoords;
|
||||
uniform sampler2D u_texture;
|
||||
uniform vec4 pal[256];
|
||||
|
||||
float intensitySteps = 4.0;
|
||||
uniform vec4 lcdBaseCol;
|
||||
|
||||
void main(void) {
|
||||
vec4 palCol = pal[int(texture2D(u_texture, v_texCoords).a * 255.0)];
|
||||
float lum = floor((3.0 * palCol.r + 4.0 * palCol.g + palCol.b) / 8.0 * intensitySteps) / intensitySteps;
|
||||
vec4 outIntensity = vec4(vec3(lum), palCol.a);
|
||||
|
||||
// LCD output will invert the luminosity. That is, normally white colour will be black on PM-LCD.
|
||||
gl_FragColor = lcdBaseCol * outIntensity;
|
||||
}
|
||||
@@ -924,6 +977,103 @@ void main() {
|
||||
// LCD output will invert the luminosity. That is, normally white colour will be black on PM-LCD.
|
||||
gl_FragColor = lcdBaseCol * outIntensity;
|
||||
}
|
||||
""".trimIndent()
|
||||
|
||||
val TEXT_TILING_SHADER_LCD_NOINV = """
|
||||
#version 120
|
||||
#ifdef GL_ES
|
||||
precision mediump float;
|
||||
#endif
|
||||
#extension GL_EXT_gpu_shader4 : enable
|
||||
|
||||
//layout(origin_upper_left) in vec4 gl_FragCoord; // commented; requires #version 150 or later
|
||||
// gl_FragCoord is origin to bottom-left
|
||||
|
||||
varying vec4 v_color;
|
||||
varying vec2 v_texCoords;
|
||||
uniform sampler2D u_texture;
|
||||
|
||||
|
||||
uniform vec2 screenDimension;
|
||||
uniform vec2 tilesInAxes; // size of the tilemap texture; vec2(tiles_in_horizontal, tiles_in_vertical)
|
||||
|
||||
uniform sampler2D tilesAtlas;
|
||||
uniform sampler2D foreColours;
|
||||
uniform sampler2D backColours;
|
||||
uniform sampler2D tilemap;
|
||||
|
||||
uniform vec2 tilesInAtlas = ivec2(16.0, 16.0);
|
||||
uniform vec2 atlasTexSize = ivec2(128.0, 224.0);
|
||||
vec2 tileSizeInPx = atlasTexSize / tilesInAtlas; // should be like ivec2(16, 16)
|
||||
|
||||
ivec2 getTileXY(int tileNumber) {
|
||||
return ivec2(tileNumber % int(tilesInAtlas.x), tileNumber / int(tilesInAtlas.x));
|
||||
}
|
||||
|
||||
// return: int=0xaarrggbb
|
||||
int _colToInt(vec4 color) {
|
||||
return int(color.b * 255) | (int(color.g * 255) << 8) | (int(color.r * 255) << 16) | (int(color.a * 255) << 24);
|
||||
}
|
||||
|
||||
// 0x0rggbb where int=0xaarrggbb
|
||||
// return: [0..1048575]
|
||||
int getTileFromColor(vec4 color) {
|
||||
return _colToInt(color) & 0xFFFFF;
|
||||
}
|
||||
|
||||
float intensitySteps = 4.0;
|
||||
uniform vec4 lcdBaseCol;
|
||||
|
||||
void main() {
|
||||
|
||||
// READ THE FUCKING MANUAL, YOU DONKEY !! //
|
||||
// This code purposedly uses flipped fragcoord. //
|
||||
// Make sure you don't use gl_FragCoord unknowingly! //
|
||||
// Remember, if there's a compile error, shader SILENTLY won't do anything //
|
||||
|
||||
|
||||
// default gl_FragCoord takes half-integer (represeting centre of the pixel) -- could be useful for phys solver?
|
||||
// This one, however, takes exact integer by rounding down. //
|
||||
vec2 flippedFragCoord = vec2(gl_FragCoord.x, screenDimension.y - gl_FragCoord.y); // NO IVEC2!!; this flips Y
|
||||
|
||||
// get required tile numbers //
|
||||
|
||||
vec4 tileFromMap = texture2D(tilemap, flippedFragCoord / screenDimension); // raw tile number
|
||||
vec4 foreColFromMap = texture2D(foreColours, flippedFragCoord / screenDimension);
|
||||
vec4 backColFromMap = texture2D(backColours, flippedFragCoord / screenDimension);
|
||||
|
||||
int tile = getTileFromColor(tileFromMap);
|
||||
ivec2 tileXY = getTileXY(tile);
|
||||
|
||||
// calculate the UV coord value for texture sampling //
|
||||
|
||||
// don't really need highp here; read the GLES spec
|
||||
vec2 uvCoordForTile = (mod(flippedFragCoord, tileSizeInPx) / tileSizeInPx) / tilesInAtlas; // 0..0.00390625 regardless of tile position in atlas
|
||||
vec2 uvCoordOffsetTile = tileXY / tilesInAtlas; // where the tile starts in the atlas, using uv coord (0..1)
|
||||
|
||||
// get final UV coord for the actual sampling //
|
||||
|
||||
vec2 finalUVCoordForTile = uvCoordForTile + uvCoordOffsetTile;// where we should be actually looking for in atlas, using UV coord (0..1)
|
||||
|
||||
// blending a breakage tex with main tex //
|
||||
|
||||
vec4 tileCol = texture2D(tilesAtlas, finalUVCoordForTile);
|
||||
|
||||
vec4 palCol = vec4(1.0);
|
||||
// apply colour
|
||||
if (tileCol.r > 0) {
|
||||
palCol = foreColFromMap;
|
||||
}
|
||||
else {
|
||||
palCol = backColFromMap;
|
||||
}
|
||||
|
||||
float lum = floor((3.0 * palCol.r + 4.0 * palCol.g + palCol.b) / 8.0 * intensitySteps) / intensitySteps;
|
||||
vec4 outIntensity = vec4(vec3(lum), palCol.a);
|
||||
|
||||
// LCD output will invert the luminosity. That is, normally white colour will be black on PM-LCD.
|
||||
gl_FragColor = lcdBaseCol * outIntensity;
|
||||
}
|
||||
""".trimIndent()
|
||||
|
||||
val DEFAULT_PALETTE = intArrayOf( // 0b rrrrrrrr gggggggg bbbbbbbb aaaaaaaa
|
||||
|
||||
@@ -8,6 +8,14 @@ class SerialDiskDrive : BlockTransferInterface(false, true) {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun startSend() {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun writeout(inputData: ByteArray) {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
val diskID: UUID = UUID(0, 0)
|
||||
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ package net.torvald.tsvm.peripheral
|
||||
|
||||
class TestFunctionGenerator : BlockTransferInterface(true, false) {
|
||||
|
||||
val msg = """Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi ipsum magna, ultrices eu leo eu, consequat eleifend arcu. Nam tempor nunc aliquam mi cursus mollis. Aenean dictum iaculis dolor eget porttitor. Fusce vulputate dui id mauris ultricies, non aliquet nulla pulvinar. Integer consectetur nulla at cursus cursus. Nullam enim nisl, elementum a fermentum sed, suscipit id sapien. Duis eget enim lacinia, aliquam sapien ac, commodo risus. Morbi at enim sem. Aenean sollicitudin purus et sem porttitor, convallis ultricies nulla posuere. Suspendisse euismod sagittis vestibulum. Mauris lorem nisl, placerat et finibus non, cursus non ex. Interdum et malesuada fames ac ante ipsum primis in faucibus. Suspendisse finibus non dui vel tempor. Nam rhoncus ligula et massa sagittis fringilla. Cras convallis pellentesque nulla in rutrum.
|
||||
val filecontent_lorem = """Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi ipsum magna, ultrices eu leo eu, consequat eleifend arcu. Nam tempor nunc aliquam mi cursus mollis. Aenean dictum iaculis dolor eget porttitor. Fusce vulputate dui id mauris ultricies, non aliquet nulla pulvinar. Integer consectetur nulla at cursus cursus. Nullam enim nisl, elementum a fermentum sed, suscipit id sapien. Duis eget enim lacinia, aliquam sapien ac, commodo risus. Morbi at enim sem. Aenean sollicitudin purus et sem porttitor, convallis ultricies nulla posuere. Suspendisse euismod sagittis vestibulum. Mauris lorem nisl, placerat et finibus non, cursus non ex. Interdum et malesuada fames ac ante ipsum primis in faucibus. Suspendisse finibus non dui vel tempor. Nam rhoncus ligula et massa sagittis fringilla. Cras convallis pellentesque nulla in rutrum.
|
||||
|
||||
Quisque ac orci sodales, semper neque eu, consequat lacus. Nulla suscipit orci felis, id tempor quam ultrices quis. Integer eu vulputate risus. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Maecenas posuere sem sed erat tristique laoreet. Sed in ante est. Fusce nec est ut nunc aliquam condimentum viverra non ex. Pellentesque nisi ante, efficitur id neque sit amet, convallis tincidunt sapien. Nunc condimentum rutrum nisi, eu lobortis libero tempor non. Morbi euismod venenatis tincidunt. Nulla facilisi. Ut interdum nec nisi pharetra pretium.
|
||||
|
||||
@@ -14,13 +14,50 @@ Nam in aliquet velit, vitae aliquam sapien. Phasellus imperdiet nulla augue, fer
|
||||
|
||||
Nunc mollis nibh vitae sapien consequat, ut vestibulum sem pharetra. Aliquam iaculis, felis ut auctor porta, ipsum diam laoreet ex, sed egestas lacus est at neque. Aenean venenatis blandit arcu at porta. Nunc sed est magna. Duis pulvinar, nulla eu tristique mattis, dui diam malesuada sem, ac condimentum turpis nunc iaculis urna. Nam et ligula aliquet, fermentum lectus nec, consectetur ipsum. Proin convallis, mi id consectetur lobortis, urna nulla pellentesque odio, a finibus tortor nisl nec tortor. Suspendisse blandit nisl in magna hendrerit tristique. Cras sit amet metus et lacus rutrum tempus. In sapien elit, facilisis quis tristique a, vestibulum a massa. Donec ligula diam, posuere ac velit eget, lobortis tincidunt ante. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nullam lectus massa, egestas eu urna id, tempor pulvinar odio. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Aliquam in suscipit mauris, quis faucibus dui. Cras tincidunt turpe es.""".toByteArray(Charsets.US_ASCII)
|
||||
|
||||
override fun startSend(sendfun: ((BlockTransferInterface) -> Unit)?) {
|
||||
super.startSend { it.writeout(msg) }
|
||||
private var fileOpen = false
|
||||
|
||||
private var readModeLength = -1
|
||||
|
||||
fun composeSerialAns(vararg msg: String): ByteArray {
|
||||
val sb = ArrayList<Byte>()
|
||||
sb.addAll(msg[0].toByteArray().toTypedArray())
|
||||
for (k in 1 until msg.lastIndex) {
|
||||
sb.add(0x1F)
|
||||
sb.addAll(msg[k].toByteArray().toTypedArray())
|
||||
}
|
||||
sb.add(0x17)
|
||||
return sb.toByteArray()
|
||||
}
|
||||
|
||||
override fun startSend() {
|
||||
if (readModeLength > 0) {
|
||||
readModeLength = 0
|
||||
startSend { it.writeout(filecontent_lorem) }
|
||||
}
|
||||
}
|
||||
|
||||
override fun hasNext(): Boolean = false
|
||||
|
||||
override fun writeout(inputData: ByteArray, writeoutfun: (() -> Unit)?) {
|
||||
override fun writeout(inputData: ByteArray) {
|
||||
val inputString = inputData.toString()
|
||||
|
||||
if (inputString.startsWith("DEVRST\u0017")) {
|
||||
readModeLength = -1
|
||||
fileOpen = false
|
||||
}
|
||||
else if (inputString.startsWith("DEVTYP\u0017"))
|
||||
startSend { it.writeout(composeSerialAns("STOR")) }
|
||||
else if (inputString.startsWith("DEVNAM\u0017"))
|
||||
startSend { it.writeout(composeSerialAns("Testtec Virtual Disk Drive")) }
|
||||
else if (inputString.startsWith("OPENR\""))
|
||||
fileOpen = true
|
||||
else if (inputString.startsWith("CLOSE"))
|
||||
fileOpen = false
|
||||
else if (inputString.startsWith("READ"))
|
||||
readModeLength = inputString.substring(4 until inputString.length).toInt()
|
||||
else if (inputString.startsWith("LIST"))
|
||||
startSend { it.writeout("\"LOREM.TXT\" TXT\nTotal 1 files on the disk".toByteArray()) }
|
||||
|
||||
}
|
||||
|
||||
override fun setMode(sendmode: Boolean) {
|
||||
|
||||
Reference in New Issue
Block a user