From 55d94dd1f086e7cc89b57a7906f22ac80ffdb694 Mon Sep 17 00:00:00 2001 From: Terence Boldt Date: Thu, 3 Mar 2022 22:23:04 -0500 Subject: [PATCH] Update RPi.Command and driver for it --- Apple2/RPi.Command.asm | 64 ++--- Apple2/RPi.Command.bin | Bin 487 -> 431 bytes Apple2/RPi.Command.lst | 326 +++++++++++----------- Apple2/Shell.lst | 2 +- RaspberryPi/Apple2-IO-RPi.hdv | Bin 33553920 -> 33553920 bytes RaspberryPi/apple2driver/handlers/exec.go | 108 +++---- RaspberryPi/apple2driver/info/version.go | 2 +- 7 files changed, 236 insertions(+), 266 deletions(-) diff --git a/Apple2/RPi.Command.asm b/Apple2/RPi.Command.asm index 3be5270..0dac1f9 100644 --- a/Apple2/RPi.Command.asm +++ b/Apple2/RPi.Command.asm @@ -42,6 +42,13 @@ SlotL = $fe SlotH = $ff ESC = $9b +;macro for string with high-bit set +.macro aschi str +.repeat .strlen (str), c +.byte .strat (str, c) | $80 +.endrep +.endmacro + .org $2000 ldx #$07 ; start at slot 7 DetectSlot: @@ -78,21 +85,22 @@ nextSlot: rts Start: stx slotx + $1e01 ;set the slot for the driver + ldy #$00 +PrintString: + lda Text,y + beq copyDriver + ora #$80 + jsr PrintChar + iny + bne PrintString +copyDriver: ldx #$00 -copyDriver: +copyDriverByte: lda $2100,x sta $0300,x inx cpx #$e6 - bne copyDriver -end: - jmp $0300 - -.repeat 253-r-YOfdea96=pLpVBX2Vbh7sYhh{yHcjCgwl?*^y zVJGtj_LB@BBo*HN)nPaw@O~}B0U#5s2B=eF!aa$cr<2ne^;IYEfaJffl%Lyvz#?I9 Y-vJLWb8q(ntqH#}BoaP-c*(#30GZ88UjP6A diff --git a/Apple2/RPi.Command.lst b/Apple2/RPi.Command.lst index a692434..0c9dfdc 100644 --- a/Apple2/RPi.Command.lst +++ b/Apple2/RPi.Command.lst @@ -46,6 +46,13 @@ Current file: RPi.Command.asm 000300 1 SlotH = $ff 000300 1 ESC = $9b 000300 1 +000300 1 ;macro for string with high-bit set +000300 1 .macro aschi str +000300 1 .repeat .strlen (str), c +000300 1 .byte .strat (str, c) | $80 +000300 1 .endrep +000300 1 .endmacro +000300 1 000300 1 .org $2000 002000 1 A2 07 ldx #$07 ; start at slot 7 002002 1 DetectSlot: @@ -81,171 +88,164 @@ Current file: RPi.Command.asm 00202E 1 D0 D2 bne DetectSlot 002030 1 60 rts 002031 1 Start: -002031 1 8E 48 21 stx slotx + $1e01 ;set the slot for the driver -002034 1 A2 00 ldx #$00 -002036 1 copyDriver: -002036 1 BD 00 21 lda $2100,x -002039 1 9D 00 03 sta $0300,x -00203C 1 E8 inx -00203D 1 E0 E6 cpx #$e6 -00203F 1 D0 F5 bne copyDriver -002041 1 end: -002041 1 4C 00 03 jmp $0300 -002044 1 -002044 1 00 00 00 00 .repeat 253-RPI ; external command JMP +002063 1 8D 08 BE STA EXTRNCMD+2 ; vector. +002066 1 60 RTS +002067 1 ; +002067 1 +002067 1 Text: +002067 1 D2 D0 C9 A0 aschi "RPI command v000D" +00206B 1 E3 EF ED ED +00206F 1 E1 EE E4 A0 +002078 1 8D .byte $8d +002079 1 end: +002079 1 00 .byte $00 +00207A 1 +00207A 1 00 00 00 00 .repeat 255-RPI ; external command JMP -000313 1 8D 08 BE STA EXTRNCMD+2 ; vector. -000316 1 60 RTS -000317 1 ; -000317 1 A2 00 RPI: LDX #0 ;Check for our command. -000319 1 BD 00 02 NXTCHR: LDA INBUF,X ;Get first character. -00031C 1 09 20 ora #$20 ;Make it lower case -00031E 1 DD E2 03 CMP CMD,X ;Does it match? -000321 1 D0 29 BNE NOTOURS ;No, back to CI. -000323 1 E8 INX ;Next character -000324 1 E0 03 CPX #CMDLEN ;All characters yet? -000326 1 D0 F1 BNE NXTCHR ;No, read next one. -000328 1 ; -000328 1 A9 02 LDA #CMDLEN-1 ;Our cmd! Put cmd length-1 -00032A 1 ;lda #$8d -00032A 1 ;sta $02ff -00032A 1 ;lda #$fe -00032A 1 8D 52 BE STA XLEN ; in CI global XLEN. -00032D 1 A9 58 LDA #XRETURN ; at the time we intercept -000334 1 -000334 1 8D 51 BE STA XTRNADDR+1 ; our command. -000337 1 A9 00 LDA #0 ;Mark the cmd number as -000339 1 8D 53 BE STA XCNUM ; zero (external). -00033C 1 8D 54 BE STA PBITS ;And indicate no parameters -00033F 1 8D 55 BE STA PBITS+1 ; to be parsed. -000342 1 A9 8D lda #$8d -000344 1 20 ED FD jsr $fded -000347 1 A2 70 slotx: ldx #$70 ; set x to slot # in high nibble -000349 1 18 clc -00034A 1 90 04 bcc SendCommand -00034C 1 ; -00034C 1 38 NOTOURS: SEC ; ALWAYS SET CARRY IF NOT YOUR -00034D 1 6C E5 03 JMP (NXTCMD) ; CMD AND LET NEXT COMMAND TRY -000350 1 ; ; TO CLAIM IT. -000350 1 -000350 1 SendCommand: -000350 1 2C 10 C0 bit ClearKeyboard -000353 1 A9 05 lda #$05 ;send command 5 = exec -000355 1 20 9B 03 jsr SendByte -000358 1 A0 03 ldy #$03 ;skip over "RPI" -00035A 1 getInput: -00035A 1 B9 00 02 lda $0200,y -00035D 1 C9 8D cmp #$8d -00035F 1 F0 08 beq sendNullTerminator -000361 1 29 7F and #$7f -000363 1 20 9B 03 jsr SendByte -000366 1 C8 iny -000367 1 D0 F1 bne getInput -000369 1 sendNullTerminator: -000369 1 A9 00 lda #$00 -00036B 1 20 9B 03 jsr SendByte -00036E 1 DumpOutput: -00036E 1 20 B9 03 jsr GetByte -000371 1 B0 07 bcs skipOutput -000373 1 C9 00 cmp #$00 -000375 1 F0 19 beq endOutput -000377 1 20 ED FD jsr PrintChar -00037A 1 skipOutput: -00037A 1 2C 00 C0 bit Keyboard ;check for keypress -00037D 1 10 EF bpl DumpOutput ;keep dumping output if no keypress -00037F 1 AD 00 C0 lda Keyboard ;send keypress to RPi -000382 1 20 ED FD jsr PrintChar -000385 1 29 7F and #$7f -000387 1 20 9B 03 jsr SendByte -00038A 1 2C 10 C0 bit ClearKeyboard -00038D 1 18 clc -00038E 1 90 DE bcc DumpOutput -000390 1 endOutput: -000390 1 18 clc -000391 1 6C E5 03 jmp (NXTCMD) -000394 1 -000394 1 HelpCommand: -000394 1 61 32 68 65 .byte "a2help",$00 -000398 1 6C 70 00 -00039B 1 -00039B 1 SendByte: +000300 1 A2 00 RPI: LDX #0 ;Check for our command. +000302 1 BD 00 02 NXTCHR: LDA INBUF,X ;Get first character. +000305 1 09 20 ora #$20 ;Make it lower case +000307 1 DD AA 03 CMP CMD,X ;Does it match? +00030A 1 D0 29 BNE NOTOURS ;No, back to CI. +00030C 1 E8 INX ;Next character +00030D 1 E0 03 CPX #CMDLEN ;All characters yet? +00030F 1 D0 F1 BNE NXTCHR ;No, read next one. +000311 1 ; +000311 1 A9 02 LDA #CMDLEN-1 ;Our cmd! Put cmd length-1 +000313 1 ;lda #$8d +000313 1 ;sta $02ff +000313 1 ;lda #$fe +000313 1 8D 52 BE STA XLEN ; in CI global XLEN. +000316 1 A9 58 LDA #XRETURN ; at the time we intercept +00031D 1 +00031D 1 8D 51 BE STA XTRNADDR+1 ; our command. +000320 1 A9 00 LDA #0 ;Mark the cmd number as +000322 1 8D 53 BE STA XCNUM ; zero (external). +000325 1 8D 54 BE STA PBITS ;And indicate no parameters +000328 1 8D 55 BE STA PBITS+1 ; to be parsed. +00032B 1 A9 8D lda #$8d +00032D 1 20 ED FD jsr $fded +000330 1 A2 70 slotx: ldx #$70 ; set x to slot # in high nibble +000332 1 18 clc +000333 1 90 04 bcc SendCommand +000335 1 ; +000335 1 38 NOTOURS: SEC ; ALWAYS SET CARRY IF NOT YOUR +000336 1 6C AD 03 JMP (NXTCMD) ; CMD AND LET NEXT COMMAND TRY +000339 1 ; ; TO CLAIM IT. +000339 1 +000339 1 SendCommand: +000339 1 2C 10 C0 bit ClearKeyboard +00033C 1 A9 05 lda #$05 ;send command 5 = exec +00033E 1 20 6F 03 jsr SendByte +000341 1 A0 03 ldy #$03 ;skip over "RPI" +000343 1 getInput: +000343 1 B9 00 02 lda $0200,y +000346 1 C9 8D cmp #$8d +000348 1 F0 08 beq sendNullTerminator +00034A 1 29 7F and #$7f +00034C 1 20 6F 03 jsr SendByte +00034F 1 C8 iny +000350 1 D0 F1 bne getInput +000352 1 sendNullTerminator: +000352 1 A9 00 lda #$00 +000354 1 20 6F 03 jsr SendByte +000357 1 DumpOutput: +000357 1 20 8D 03 jsr GetByte +00035A 1 C9 00 cmp #$00 +00035C 1 F0 06 beq endOutput +00035E 1 20 ED FD jsr PrintChar +000361 1 18 clc +000362 1 90 F3 bcc DumpOutput +000364 1 endOutput: +000364 1 18 clc +000365 1 6C AD 03 jmp (NXTCMD) +000368 1 +000368 1 HelpCommand: +000368 1 61 32 68 65 .byte "a2help",$00 +00036C 1 6C 70 00 +00036F 1 +00036F 1 SendByte: +00036F 1 48 pha +000370 1 waitWrite: +000370 1 BD 8B C0 lda InputFlags,x +000373 1 2A rol +000374 1 2A rol +000375 1 B0 F9 bcs waitWrite +000377 1 68 pla +000378 1 9D 8D C0 sta OutputByte,x +00037B 1 A9 1E lda #$1e ; set bit 0 low to indicate write started +00037D 1 9D 87 C0 sta OutputFlags,x +000380 1 finishWrite: +000380 1 BD 8B C0 lda InputFlags,x +000383 1 2A rol +000384 1 2A rol +000385 1 90 F9 bcc finishWrite +000387 1 A9 1F lda #$1f +000389 1 9D 87 C0 sta OutputFlags,x +00038C 1 60 rts +00038D 1 +00038D 1 GetByte: +00038D 1 A9 1D lda #$1d ;set read flag low +00038F 1 9D 87 C0 sta OutputFlags,x +000392 1 waitRead: +000392 1 BD 8B C0 lda InputFlags,x +000395 1 2A rol +000396 1 B0 FA bcs waitRead +000398 1 readByte: +000398 1 BD 8E C0 lda InputByte,x 00039B 1 48 pha -00039C 1 waitWrite: -00039C 1 BD 8B C0 lda InputFlags,x -00039F 1 2A rol -0003A0 1 2A rol -0003A1 1 B0 F9 bcs waitWrite -0003A3 1 68 pla -0003A4 1 9D 8D C0 sta OutputByte,x -0003A7 1 A9 1E lda #$1e ; set bit 0 low to indicate write started -0003A9 1 9D 87 C0 sta OutputFlags,x -0003AC 1 finishWrite: -0003AC 1 BD 8B C0 lda InputFlags,x -0003AF 1 2A rol -0003B0 1 2A rol -0003B1 1 90 F9 bcc finishWrite -0003B3 1 A9 1F lda #$1f -0003B5 1 9D 87 C0 sta OutputFlags,x -0003B8 1 60 rts -0003B9 1 -0003B9 1 GetByte: -0003B9 1 A9 1D lda #$1d ;set read flag low -0003BB 1 9D 87 C0 sta OutputFlags,x -0003BE 1 waitRead: -0003BE 1 BD 8B C0 lda InputFlags,x -0003C1 1 2A rol -0003C2 1 90 0C bcc readByte -0003C4 1 2C 00 C0 bit Keyboard ;keypress will abort waiting to read -0003C7 1 10 F5 bpl waitRead -0003C9 1 A9 1F lda #$1f ;set all flags high and exit -0003CB 1 9D 87 C0 sta OutputFlags,x -0003CE 1 38 sec ;failure -0003CF 1 60 rts -0003D0 1 readByte: -0003D0 1 BD 8E C0 lda InputByte,x -0003D3 1 48 pha -0003D4 1 A9 1F lda #$1f ;set all flags high -0003D6 1 9D 87 C0 sta OutputFlags,x -0003D9 1 finishRead: -0003D9 1 BD 8B C0 lda InputFlags,x -0003DC 1 2A rol -0003DD 1 90 FA bcc finishRead -0003DF 1 68 pla -0003E0 1 18 clc ;success -0003E1 1 60 rts -0003E2 1 -0003E2 1 -0003E2 1 ;macro for string with high-bit set -0003E2 1 .macro aschi str -0003E2 1 .repeat .strlen (str), c -0003E2 1 .byte .strat (str, c) | $80 -0003E2 1 .endrep -0003E2 1 .endmacro -0003E2 1 -0003E2 1 F2 F0 E9 CMD: aschi "rpi" -0003E5 1 CMDLEN = 3 ;Our command length -0003E5 1 ; -0003E5 1 00 00 NXTCMD: .byte 0,0 ; STORE THE NEXT EXT CMD'S -0003E7 1 ; ADDRESS HERE. -0003E7 1 -0003E7 1 -0003E7 1 +00039C 1 A9 1F lda #$1f ;set all flags high +00039E 1 9D 87 C0 sta OutputFlags,x +0003A1 1 finishRead: +0003A1 1 BD 8B C0 lda InputFlags,x +0003A4 1 2A rol +0003A5 1 90 FA bcc finishRead +0003A7 1 68 pla +0003A8 1 18 clc ;success +0003A9 1 60 rts +0003AA 1 +0003AA 1 +0003AA 1 F2 F0 E9 CMD: aschi "rpi" +0003AD 1 CMDLEN = 3 ;Our command length +0003AD 1 ; +0003AD 1 00 00 NXTCMD: .byte 0,0 ; STORE THE NEXT EXT CMD'S +0003AF 1 ; ADDRESS HERE. +0003AF 1 +0003AF 1 +0003AF 1 diff --git a/Apple2/Shell.lst b/Apple2/Shell.lst index 16625ae..044b6b2 100644 --- a/Apple2/Shell.lst +++ b/Apple2/Shell.lst @@ -1,4 +1,4 @@ -ca65 V2.18 - N/A +ca65 V2.18 - Raspbian 2.19-1 Main file : Shell.asm Current file: Shell.asm diff --git a/RaspberryPi/Apple2-IO-RPi.hdv b/RaspberryPi/Apple2-IO-RPi.hdv index b5098eab73768fe3319e54664bc2beef15d0b0c8..e36d55f3fd80b445ad8b4a6b6197b06ac691b782 100755 GIT binary patch delta 2546 zcmY+^d6Z6d9Dwn6<~3u+60&B=t3+hazLz~^r$t1_zNRQ-(xUJp(xB8>GZ>}~BZj0h zsSF|ePN-q*J3UW-bWVSKp8Na$&Rx#A=iD22>u#<%B$toM*`r+9yd?w20wEXEYeyCS zcPH@QPWPz#c~(RO{&!mB^gJ+N5ft22%%$V4?P{!@e=@;h()&)w; z2?S3aKACgLYP%|l5F87ASsLxseC=A}{hGKMJ5A3gJE!MiCT6G2D;h2%!WXz=J4>hfoTo@i5AuEFM8Qlt%?r zL?u*46+DWnsD|pOftsj=+NguNsE7J!fQEPskE0P9qY0X#8JeR7ov;sta=cf5!m=!sr<3BAz=ebEp7F#rQG2!k;MLop05 zV>n*Hs~CZicnz;(6h>nV-oRMI;Z2OgTX-Aq;9ZQzdw3rcFcFgw#$-&vRD6JGn2rxI z10NwCGcgOZ@i9KZ9DIt;kbt?Ehxu55g;<2ou^5S1f~8o7BrL}YB;yNwiLdZAzQIbY z!fK>o4Zg)%tV1f+V*|d!MtqM=_yIrSCu~Lb37RY>%0!#2CdR~?Y$m(OVRD*#OfHk#OJrmT6ylr!Z`1yj*fGL=mg^Qft6s+sDh zhN)?4ncAj~scY()`lf+tXdW|W~Q`5{eH!aK)rlon(JY`y$)~1bVYucIi zri1BdI+>@@t6t-DZ#3YxbG_=72e94w=K|h&gJGnd9b! zIcfehr_5<{#{6aeHW}uuIcGA>d2_*BG?&a}bH!XW*UWWu!`w8t%x!ZgVm*Jqh)Qez E0mY@7HUIzs delta 2518 zcmY+^cbw049KiA4?|vP3MGkRC#u@#v4|>-+hBzVE+2kH_ab>dxIf&Yz#CFPE2J|^3$Y{B@Nc^Vd55ZDkXmJ$e^IeIGdTH`>7 zuj^yevZp6zh0-F@6HkRwqZ6~Ir-l+E(mOjF78!f!cyeUDVEGbRp}44w)bQ9@p?RS- zfv|0fmm4y-WJ7jDAQJcDKIA}7+>cy{LT=t^6hTqMq8N&!1WMu|l)}R(jWT!yWf6yRD31!Lh)RgZqo|C>@HncVDypG6YM>@+ zp*EgC9n{5>sE4QUH0q-P8ln-N!Lw+LCTNOgXpZO50xi)Bt?@kC;03frJG_YY=zxys z1kXPKUGNgRq8naDcl1C{^g?g+!7J#Ce&~+@cohTj8U|r7UdJ04f;TY~!!R5pFcPCM z8e=dP~MuHjEy#|_-XE!@T({Dr@9cM^AhGEA5WnR`sQ$!4;f z2oq`UHTRhuCa1aIiilix&}7*oI$G!L3Wrm!huiketc%oH~zOiA;Q zDPa{=5bTSR5jI1byLICG__1^^Mt8m>Y69b zzsLEMtEWwU)4((|jm$IVS<~1wF-=V~)7(5~T9}rmm1%9BH*L%drmbmbUNr4Z2h-7X zGM!C=>0(|oT}?OhvgvMmn4YGW>23O$S4>~i&-6C~%&TUgdCd$mgU##a4Ku{NX@;6% zX1Ez)Mw(G(v>9W@nsMeW^R^jp-Z2x*L^H{}YZA?SX0n-LrkZIc$xJsh%uJJP-ZvkZ z56vty+oYH|X0DlM=9>lPBlEHO#C&QNnnfnnEHy4h$l%qFwhd~Lol-%lsYO$lotmaqU0bQ-jO^ diff --git a/RaspberryPi/apple2driver/handlers/exec.go b/RaspberryPi/apple2driver/handlers/exec.go index c74d010..1acec00 100644 --- a/RaspberryPi/apple2driver/handlers/exec.go +++ b/RaspberryPi/apple2driver/handlers/exec.go @@ -10,15 +10,17 @@ package handlers import ( "errors" "fmt" - "io" "os" "os/exec" + "strconv" "strings" + "time" "github.com/tjboldt/Apple2-IO-RPi/RaspberryPi/apple2driver/info" ) var forceLowercase = false +var execTimeoutSeconds = int(10) // ExecCommand handles requests for the Apple II executing Linux commands func ExecCommand() { @@ -68,6 +70,10 @@ func ExecCommand() { a2wifi() return } + if strings.HasPrefix(linuxCommand, "a2timeout") { + a2timeout(linuxCommand) + return + } if linuxCommand == "a2prompt" { prompt := fmt.Sprintf("A2IO:%s ", workingDirectory) comm.WriteString(prompt) @@ -100,14 +106,7 @@ func execCommand(linuxCommand string, workingDirectory string) { comm.WriteString("Failed to set stdout\r") return } - stdin, err := cmd.StdinPipe() - if err != nil { - fmt.Printf("Failed to set stdin\n") - comm.WriteString("Failed to set stdin\r") - return - } - fmt.Printf("Command output:\n") err = cmd.Start() if err != nil { fmt.Printf("Failed to start command\n") @@ -115,73 +114,26 @@ func execCommand(linuxCommand string, workingDirectory string) { return } - outputComplete := make(chan bool) - inputComplete := make(chan bool) - userCancelled := make(chan bool) - - go getStdin(stdin, outputComplete, inputComplete, userCancelled) - go getStdout(stdout, outputComplete, userCancelled) + timeout := time.After(time.Duration(execTimeoutSeconds) * time.Second) for { select { - case <-outputComplete: - outputComplete <- true - cmd.Wait() - comm.WriteByte(0) - return - case <-userCancelled: - userCancelled <- true + case <-timeout: + comm.WriteString("\rCancelled by apple2driver\r") cmd.Process.Kill() return - case <-inputComplete: - cmd.Wait() - comm.WriteByte(0) - return - } - } -} - -func getStdout(stdout io.ReadCloser, outputComplete chan bool, userCancelled chan bool) { - for { - select { - case <-userCancelled: - fmt.Printf("User Cancelled stdout\n") - stdout.Close() - return default: bb := make([]byte, 1) - n, err := stdout.Read(bb) - if err != nil { - stdout.Close() - outputComplete <- true - return - } - if n > 0 { - b := bb[0] - comm.SendCharacter(b) - } - } - } -} - -func getStdin(stdin io.WriteCloser, done chan bool, inputComplete chan bool, userCancelled chan bool) { - for { - select { - case <-done: - stdin.Close() - inputComplete <- true - return - default: - b, err := comm.ReadByte() - if err == nil { - if b == 0x00 || b == 0x03 { - stdin.Close() - userCancelled <- true - fmt.Printf("\nUser cancelled stdin\n") - return + n, stdOutErr := stdout.Read(bb) + if stdOutErr == nil { + if n > 0 { + b := bb[0] + comm.SendCharacter(b) } - bb := make([]byte, 1) - stdin.Write(bb) + } else { + comm.WriteByte(0) + cmd.Wait() + return } } } @@ -195,14 +147,34 @@ func a2help() { comm.WriteString("\r" + "Built-in commands:\r" + "------------------\r" + - "a2version - display version number\r" + "a2help - display this message\r" + + "a2version - display version number\r" + "a2wifi - set up wifi\r" + + "a2timeout - seconds to timeout commands\r" + "A2LOWER - force lowercase for II+\r" + "a2lower - disable force lowercase for II+\r" + "\r") } +func a2timeout(linuxCommand string) { + params := strings.Fields(linuxCommand) + + switch len(params) { + case 1: + comm.WriteString("\rCommand timeout: " + strconv.FormatInt(int64(execTimeoutSeconds),10) + "\r") + case 2: + timeoutSeconds, err := strconv.ParseInt(params[1], 10, 32) + if err != nil { + comm.WriteString("\rFailed to parse timeout\r") + } else { + execTimeoutSeconds = int(timeoutSeconds) + comm.WriteString("\rCommand timeout set to: " + strconv.FormatInt(int64(execTimeoutSeconds),10) + "\r") + } + default: + comm.WriteString("\rToo many parameters\n") + } +} + func a2lower(enable bool) { forceLowercase = enable comm.WriteString(fmt.Sprintf("All commands will be converted to lowercase: %t\r", forceLowercase)) diff --git a/RaspberryPi/apple2driver/info/version.go b/RaspberryPi/apple2driver/info/version.go index 8668baf..dacfe24 100644 --- a/RaspberryPi/apple2driver/info/version.go +++ b/RaspberryPi/apple2driver/info/version.go @@ -8,4 +8,4 @@ package info // Version is the hexadecimal version number that // should be incremented with each driver update -const Version = "0024" +const Version = "0025"