tag:blogger.com,1999:blog-21756253845412165222024-02-19T01:50:45.550-08:00robj retro applerobjhttp://www.blogger.com/profile/16498154202278388762noreply@blogger.comBlogger9125tag:blogger.com,1999:blog-2175625384541216522.post-14930046083784713292020-05-20T06:07:00.001-07:002020-05-22T23:11:55.507-07:00Apple /// Horses DemoThe most widely known demo for the Apple /// is the 'Running Horses' demo. The Horses demo is one of a suite of demos included on the 'Apple3 System Demonstration' disk. Here is a screenshot of it running in MAME:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhWRTevJ5J8MeiVKki0VEvBmUC-zohjzEVvcayLU0hGnyPMoLMH8Q5SBcQUS1y4MifWS7RDETO5l5GFrNDHSWQW1DBIdsPjZ77UcYBUJ2_zqHw_gXmhWM8qnKMw1gvvfZRQDm2XPKRTCQ/s1600/horses.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="512" data-original-width="643" height="317" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhWRTevJ5J8MeiVKki0VEvBmUC-zohjzEVvcayLU0hGnyPMoLMH8Q5SBcQUS1y4MifWS7RDETO5l5GFrNDHSWQW1DBIdsPjZ77UcYBUJ2_zqHw_gXmhWM8qnKMw1gvvfZRQDm2XPKRTCQ/s400/horses.JPG" width="400" /></a></div>
<br />
You can grab the original demo disk image from here: <a href="https://github.com/robjustice/Apple3/blob/master/horses/Apple3SystemDemoUnProtected.dsk">Apple3SystemDemo</a><br />
<br />
And you can run it here on the Internet Archive: <a href="https://archive.org/details/Apple_3_Systems_Demonstration_Disk">Apple_3_Systems_Demonstration_Disk</a><br />
(You'll need to be patient, the horses part is after all the graphs) <br />
<br />
<br />
This was written by Andy Hertzfeld, and used the downloadable fonts of the Apple /// to help do the heavy lifting. The main code is contained in an 'invokable module' that can be loaded in with Business Basic and called by Basic programs. I have been interested to see how it was done, so decided to dig into the demo and see what makes it tick. Lets see what we find.<br />
<br />
<br />
The first part was to look into the basic program side of the demo. The Invokable module is loaded in by the 'HELLO' Basic program which contains this line:<br />
<span style="font-size: x-small;"><span style="font-family: "courier new" , "courier" , monospace;"> 95 INVOKE "bgraf.inv","Horses.inv"</span> </span><br />
<br />
This tells Business basic to load these files from disk into memory, relocate the code, and setup the entry points for each of the procedures/functions included in each of them. The "Horses.inv" is the one that includes the main code for the demo.<br />
<br />
Next, the actual basic code that creates and runs the demo, is included in the 'SHOW' file:<br />
<br />
<span style="font-size: x-small;"><span style="font-family: "courier new" , "courier" , monospace;"> 9000 REM --- Now run the horse race! --- <br /> 9005 PRINT CHR$(16);CHR$(1);<br /> 9010 PERFORM hinit<br /> 9020 PRINT CHR$(15);<br /> 9030 FOR a=1 TO 20<br /> 9050 FOR i=0 TO 4<br /> 9070 PERFORM hframe(%i)<br /> 9090 NEXT i<br /> 9110 NEXT a<br /> 9120 FOR lap=1 TO 40<br /> 9125 secs=.007*(20-lap)+.01<br /> 9130 FOR i=0 TO 4<br /> 9150 PERFORM hframe(%i)<br /> 9170 PERFORM hscroll<br /> 9190 IF secs>0 THEN GOSUB 350<br /> 9210 NEXT i<br /> 9250 NEXT lap<br /> 10000 TEXT:HOME</span></span><br />
<br />
The line '<span style="font-size: small;"><span style="font-family: "courier new" , "courier" , monospace;">PRINT CHR$(16);CHR$(1);</span></span>' is the .CONSOLE drivers code for setting the display mode to 40x24 color. This is a 40 column text mode that each character can have its foreground and background colors set from any of 16 colors.<br />
<br />
Next we need to look into the 'Horses.inv' module. This must have the code for the three functions, <b>hinit</b>, <b>hframe </b>and <b>hscroll</b> that the basic program uses. The first thing I did was to extract the horses.inv file from the demo disk and have a look with a hex editor. This led to an interesting find, there was some text in there that looked like the initial part of the source code:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh45DaSncm19XbBph8Jz1INy63TKK-D7RjVn67OKlYDsJyUUcEGmD32cypow6v3jSU1wGBbPANrpMpwuZKqgi9gou8YtUjr1IEjijoVhFLwd2TyMZOFY7namrCLL55FrMO59JlBq9jNCg/s1600/header.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="516" data-original-width="634" height="325" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh45DaSncm19XbBph8Jz1INy63TKK-D7RjVn67OKlYDsJyUUcEGmD32cypow6v3jSU1wGBbPANrpMpwuZKqgi9gou8YtUjr1IEjijoVhFLwd2TyMZOFY7namrCLL55FrMO59JlBq9jNCg/s400/header.JPG" width="400" /></a></div>
<br />
<br />
Here it is taken out, looks like the source code has the date of 9/4/1980 on it, so just over 40 years ago!!<br />
<br />
<span style="font-size: x-small;"><span style="font-family: "courier new" , "courier" , monospace;"> .PAGE<br /> ;<br /> ;-----------------------------------------------------------------------<br /> ;<br /> ; "Horse Demo" Invokable Module for Business Basic<br /> ;<br /> ; by Andy Hertzfeld 09/04/80<br /> ;<br /> ;----------------------------------------------------------------------<br /> ;<br /> .PROC HINIT<br /> ;<br /> ; First get the device number of the console<br /> ;<br /> BRK<br /> .BYTE 084 ;GETDEVNUM SOS call<br /> .WORD DEVBLOCK<br /> ;<br /> LDA CDEVNUM<br /> STA WDEVNUM ;Update the device number<br /> ;</span></span><br />
<br />
Next step was to disassemble the code. This proved somewhat difficult as the modules are assembled into a Pascal PCD file which also includes relocation and linker info. I tried to decode that, but will need some more work before I understand that fully. I ended up extracting the code block and disassembling with SourceGen (That Fantastic Disassembler from Andy McFadden). Using that as a start, I was able to trap it in Mame and then dump it from memory after it had been relocated and loaded by BusinessBasic. After quite a bit more work, I was able to take the reconstructed source, assemble it with the A3 Pascal assembler, and successfully use it to run the demo!<br />
<br />
<br />
Here is a summary of the functions included the Horses.inv invokable module.<br />
<br />
<b>HINIT</b><br />
Loads the text screen memory with the grid of character codes for the horses and loads the colorful foreground/background colors. Each horse consists of 8 characters wide x 4 lines. Codes 00 - 31 are used with the high bit set, so $80 to $9F.<br />
<br />
<b>HFRAME(frame)</b><br />
Takes the frame number as input and then downloads updated font data based on this. Frame=0 is the only frame with all 32 characters included and is the first frame set. The others only update the required characters that change for each animation frame. See pictures below for each frame (8 x 4).<br />
This uses a SOS Device Control call to the .CONSOLE device to load up to eight characters font data at a time. <br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi_HEbv0ODgcueemh1n6m0CFoqWDMvxei-3OV-sYPfqwgCxo4MBqu_jsxE_hZ9uZtrAGifo2QUqVO5ZqReWQUbN8moRptODHrzwDxMJttqKtfQvj5wVDdoHIsHrZDO_fYK9AjSyq3OlTQ/s1600/frame1.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="287" data-original-width="501" height="183" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi_HEbv0ODgcueemh1n6m0CFoqWDMvxei-3OV-sYPfqwgCxo4MBqu_jsxE_hZ9uZtrAGifo2QUqVO5ZqReWQUbN8moRptODHrzwDxMJttqKtfQvj5wVDdoHIsHrZDO_fYK9AjSyq3OlTQ/s320/frame1.JPG" width="320" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgSp8NmW7pxlEhoHipEa0QH8P25Ci52SR2A7jNWthzecaiXvvVlcjX7gdLP_IzoqiM3UtAWROQGH4bjQWevLd36o27yxV7xroTuioMqdF2xXrcOQ2T4TAVoNH2vWzlkuiyhoZ4LgJY-Yg/s1600/frame2.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="287" data-original-width="501" height="183" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgSp8NmW7pxlEhoHipEa0QH8P25Ci52SR2A7jNWthzecaiXvvVlcjX7gdLP_IzoqiM3UtAWROQGH4bjQWevLd36o27yxV7xroTuioMqdF2xXrcOQ2T4TAVoNH2vWzlkuiyhoZ4LgJY-Yg/s320/frame2.JPG" width="320" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEik6VmnLZAcaqVKxLsGJj9H5NfIy79bInjm55nvhWJ9nMpirYClbVNFxnbMBQUJBxa97qtQDx8tYHIU8AbQQfK9Pvqw67xa68aRc5pnTcIf3yYYQGy4GgQPvCOvR7ZRSYW3S9TzC_haug/s1600/frame3.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="284" data-original-width="501" height="181" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEik6VmnLZAcaqVKxLsGJj9H5NfIy79bInjm55nvhWJ9nMpirYClbVNFxnbMBQUJBxa97qtQDx8tYHIU8AbQQfK9Pvqw67xa68aRc5pnTcIf3yYYQGy4GgQPvCOvR7ZRSYW3S9TzC_haug/s320/frame3.JPG" width="320" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiByUe3jhpzeqZnWyiP4UqDj5_dpa0aqoV39QL_96OKwxBL8FDVIBpo_-CWT9yg9z96s2LClreGFxIj3J_J9n4xfjAGsbkruTJDEzxW5uHpJZ9TcSxy1WyjtEl1T9D2Tjou6IoAs1MJCw/s1600/frame4.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="285" data-original-width="501" height="182" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiByUe3jhpzeqZnWyiP4UqDj5_dpa0aqoV39QL_96OKwxBL8FDVIBpo_-CWT9yg9z96s2LClreGFxIj3J_J9n4xfjAGsbkruTJDEzxW5uHpJZ9TcSxy1WyjtEl1T9D2Tjou6IoAs1MJCw/s320/frame4.JPG" width="320" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgPFOuDnkHFW0wgPTB2bj3rdMXEtVxfREl96BcGjtfMeqyV0LV6SYVvrhc3WALSHCDyZ_wPHHsqVtTqhka0xBl2mZ9loieu-LnzEZ4GrnZSXgHjYjFCB5dsvZKAykW7M2oJ28gGJfss8Q/s1600/frame0.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="283" data-original-width="498" height="181" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgPFOuDnkHFW0wgPTB2bj3rdMXEtVxfREl96BcGjtfMeqyV0LV6SYVvrhc3WALSHCDyZ_wPHHsqVtTqhka0xBl2mZ9loieu-LnzEZ4GrnZSXgHjYjFCB5dsvZKAykW7M2oJ28gGJfss8Q/s320/frame0.JPG" width="320" /></a></div>
<br />
<br />
<b>HSCROLL</b><br />
Moves the text screen bytes across one character with wrap around. Steps through each line from 1 to 24.<br />
<br />
<br />
<br />
Now we have the source code rebuilt and preserved for this classic Apple /// demo. I have tried to add enough comments to understand the code. Let me know if you have any feedback.<br />
<br />
<br />
You can grab the disassembled source code from github here:<br />
<a href="https://github.com/robjustice/Apple3/tree/master/horses">https://github.com/robjustice/Apple3/tree/master/horses</a><br />
<br />
There is also a bootable disk image on there with the source code included, the assembled invokable module, and the basic program to run the Horses demo. Boot it up, and then type 'run horsedemo'<br />
<br />
Enjoy!robjhttp://www.blogger.com/profile/16498154202278388762noreply@blogger.com1tag:blogger.com,1999:blog-2175625384541216522.post-9944457169806259352019-02-10T03:30:00.001-08:002019-02-10T03:30:26.820-08:00Resurrecting Apple /// SOS copy protected disksThere are a few Apple /// disk images around that won't work due the SOS copy protection failing. I described this in an earlier <a href="https://robjapple.blogspot.com/2017/10/apple-advanced-visicalc-and-interesting.html" target="_blank">post</a>, and its due to the volume numbers for specific sectors not matching with the ones that SOS is expecting. The dsk/po disk format does not include this information, just the sector data itself. So they are never going to be able to work for SOS protected disk images.<br /><br />As an example, the <a href="http://www.apple3.org/Software/system/Apple3SystemDemo.dsk" target="_blank">Apple3SystemDemo.dsk</a> disk image on <a href="http://www.apple3.org/">apple3.org</a>, will not boot and gives 'SYSTEM FAILURE = $06'<br />
<br />
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiQkZ61rqI5q44NJ1_2csCv-Z2_rXPXrGeiFwdQwSZEeFBovnxjus4tvi8SAtGB60caiBFk51gKbiT3yEe_VQwdQYd0UCePNSjZw5ZmN9z1g0mX6AEkcrbUX6frRxNUxmx6c8QEi1yTIw/s1600/system_error_06.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="522" data-original-width="644" height="259" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiQkZ61rqI5q44NJ1_2csCv-Z2_rXPXrGeiFwdQwSZEeFBovnxjus4tvi8SAtGB60caiBFk51gKbiT3yEe_VQwdQYd0UCePNSjZw5ZmN9z1g0mX6AEkcrbUX6frRxNUxmx6c8QEi1yTIw/s320/system_error_06.JPG" width="320" /></a></div>
<br />I did find a reference to this error code in the Apple /// technotes, see:<br />
<a href="http://www.apple3.org/Documents/Technotes/TA32241.html" target="_blank">TA32241 Apple III: System Failure Errors</a><br /><br /> <i> "Copying certain protected diskettes will cause an error $06 when the copy is booted. This <br /> is a normal effect of the protection scheme."</i><br />
<br />
This is an interesting way of way of saying if you copy it, it's not going to work.<br />
<br />
<br />
<br />To resurrect these disks, there are two possible ways we could achieve this:<br />
<ol>
<li>Convert the disk image to a format that includes the necessary information to look like the original disk.</li>
<li>Read in the SOS.INTERP file and then decrypt it with the known SOS key, and then write it back out to disk.</li>
</ol>
I decided to have a look at the first option. I'll try and come back to the second option at a later date. <br />
<br />
There are two things we need to achieve to satisfy the SOS copy protection, the specific volumes numbers, and synchronisation of the tracks. The synchronisation is needed as SOS reads the first specific track/sector to get the first key/volume number and then just steps to the next track and reads the first sector it finds. At the last track, the sector number that is found and read first is compared with the expected one and if it does not match, then the protection check fails.<br />
<br />We now have available the woz disk image format that will work perfectly for this. If we image the original disks directly to woz format, then they work correctly. (thanks Jorma for imaging Apple /// software to woz format)<br /><br />But what about our disk images that we do not have the original disk for. If we had a way to convert the dsk image to a woz format and add back the required volume numbers and track synchronisation, then we should be able to get a working disk image. I remembered reading that someone had written a <a href="https://github.com/TomHarte/dsk2woz" target="_blank">dsk2woz </a>program to do this exact thing (thanks Tom). All we need to do is modify it to meet the requirements needed for the SOS protection check.<br /><br />
<h3>
Step 1 - add the volume numbers</h3>
The first thing to add are the volume numbers we need. I looked back at the previous blog post and this is the list, the first value is the required volume number.<br /><br /><span style="font-size: x-small;"><span style="font-family: "Courier New", Courier, monospace;">VISIKEY: .byte $7C ;track 16, Sector 6<br /> .byte $BD ;track 15, Sector 10<br /> .byte $BD ;track 14, Sector 14<br /> .byte $9B ;track 13, Sector 2<br /> .byte $F3 ;track 12, Sector 6<br /> .byte $E4 ;track 11, Sector 10<br /> .byte $C1 ;track 10, Sector 14<br /> .byte $B4 ;track 9, Sector 2</span></span><br /><br />There is a part of the code in dsk2woz that builds the bitstream for each track. It just adds 254 as the default volume number for each track/sector. I then updated the code in this part to check if its one of the track and sectors in the list, and then add the expected volume number for these. Other wise, we just put in the default value for the volume number.<br />
<br />I converted the dsk image and then tried this in MAME to see if it would load. It still gave the same System failure $06 error. The synchronisation part needed sorting out now.<br />
<br />
<h3>
Step 2 - add the correct positioning of the tracks with respect to each other</h3>
dsk2woz builds each track with the sector data in the same order and position, as usually we don't need to worry about any special track alignment for non protected disks, so we end up with all tracks the same. <br /><br />To check what SOS is getting when we boot this disk up, I referred back to the listing of <a href="https://www.dropbox.com/s/erfwa9vxd75h4b4/bfm.init2.lst?dl=0" target="_blank">BFM_INIT2</a> module. Looks like the check is done at the end of the key reading and its looking for sector number 06<br /><br /><span style="font-size: x-small;"><span style="font-family: "Courier New", Courier, monospace;">00B8F3 1 A5 98 LDA SECTOR<br />00B8F5 1 C9 <span style="color: red;">06</span> CMP #<span style="color: red;">ENDSECT</span> ;TRACKS SYNC'ED?<br />00B8F7 1 D0 08 BNE NOTPROT</span></span><br /><br />Next was to startup MAME with the debugger active and set a break point at $B8F5 and see which sector is actually getting read. Turns out it was reading sector number 3.<br /><br />Then I needed to add into dsk2woz some different alignment of the track data. The trackdata in a woz is the complete bitstream, and the length of the actual data is 6288 bytes long in the dsk2woz generated woz file tracks. All we really need to do is rotate the data for each track after its been prepared, before writing it out to the woz file. We will also need to keep track of this offset, so the next track is offset from the last tracks starting position and then 'rotated' by the same amount.<br /><br />I added this to the code, and then just picked an arbitrary value of 600 bytes to shift the tracks by. Sure enough, SOS found a different sector, but not the correct one. I ended up just using trial and error to work out the offset needed to get SOS to end up reading the correct sector number at the end. There was around 400 bytes of range that resulted in the correct one being read, so i settled on a value in the middle of the range that worked. <br /><br />The end result was the disk I started with now successfully boots now in MAME using the created woz file!<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEica17qpTEoA7TLOvdRm0CLdZho6dpLMrTHcfAZXEjc3sWny10z8xm5i3YKOvlggkhooZJSYfCSl3aQ3Xb7uoXL_xnBBW1hGq6n9lTVBtmjTPQxC4pBC5FJB4DefZcuWLo2J4Ji6FWbAw/s1600/Disk+booting+successfully.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="523" data-original-width="644" height="259" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEica17qpTEoA7TLOvdRm0CLdZho6dpLMrTHcfAZXEjc3sWny10z8xm5i3YKOvlggkhooZJSYfCSl3aQ3Xb7uoXL_xnBBW1hGq6n9lTVBtmjTPQxC4pBC5FJB4DefZcuWLo2J4Ji6FWbAw/s320/Disk+booting+successfully.JPG" width="320" /></a></div>
<br />
<br />
The converted file is available here <a href="https://www.dropbox.com/s/mg0dzae41imumdz/Apple3SystemDemo.woz?dl=0">Apple3SystemDemo.woz</a><br />
<br />
The updated dsk2woz program is available here <a href="https://github.com/robjustice/a3dsk2woz">a3dsk2woz</a><br /><br />
<h3>
Summary</h3>
This method will give the ability to run some disks in the emulator now, that have not been able to be run from the dsk images due to the copy protection info missing. I don't think we are missing any of this software, but its been an interesting project to see if this was possible. It also shows the beauty and power of the woz file format and how it caters for so much more than we have had before. Thanks John! and thanks to the MAME team for adding woz support in.<br />
<br /><br />robjhttp://www.blogger.com/profile/16498154202278388762noreply@blogger.com0tag:blogger.com,1999:blog-2175625384541216522.post-15720562512530621292018-12-19T03:21:00.001-08:002018-12-19T03:21:25.407-08:00Apple /// Drivers, and a new way of cross compiling themThis is a bit of a long lead in story, its been awhile since I have done a blog update..<br />
<br />
It started out when I was thinking about the Apple /// bootup and wondering about a small file selector that could be used, something like Selector ///. I had some ideas that if we had a tiny one like ProDOS Bitsy Bye, then maybe we could build that into SOS. I don't think the source code is released yet for Bitsy Bye, maybe in the future it looks like this will happen. I did some looking around and came across a ProDOS one called Squirt.<br />
<br />
I then started to 'port' this over to SOS for fun. One bigger change was the move for the screen output from direct video memory manipulation and A2 rom calls to using the SOS .CONSOLE driver. Like everything, its always a lot more work. The other part was mapping the ProDOS calls to SOS calls. These have some differences, more than I was expecting as ProDOS's calls are based on the SOS calls. It has a lot more to go, so not much use yet. You can view volumes online, navigate folders, and view text files. I was next going to add viewing A3 fonts, and that's when the story runs off on a tangent... <br />
<br />
I thought I would use the .GRAFIX driver for the graphics output. Well, this had me stuck. I kept getting a device error ($30) back when ever I tried to send commands to it. I can open the .GRAFIX driver ok, but nothing more. I spent quite some time searching for info on what this error might be, and trying other things. There is an invokable module called bgraf.inv that works fine with the .GRAFIX driver. I did a test in Business Basic with this and all works as expected. So it must be possible to get it to work.<br />
<br />
After some searching through the aIII wap dvd again, I found some very useful driver disassemblies in the 3's company BBS files. In there was one for the .GRAFIX driver. This has some clues, it seems there is some SOS global flag for memory allocation that the .GRAFIX driver uses, but this needs to be set by the calling program. I still have not got back to this, but this seems the main reason it was not working.<br />
<br />
I have put up a disk image and the current source code for Squirt3 on github here:<br />
<a href="https://github.com/robjustice/Squirt3" target="_blank">robjustice/Squirt3</a> <br />
For anyone interested to have a look. I'm not sure when I will put some more time into this, but it was a great learning exercise with what I have done so far.<br />
<br />
Somehow while looking at the .GRAFIX driver source, I rekindled an old thought on trying to get a relocatable file format converted for use as a Apple /// driver, to help with cross platform development. I had come across the o65 file format and this looked like a possibility, and the ca65 assembler supports this. I have been trying to learn Python more, so this looked like a good fit. I had also helped with some debugging of the <a href="https://github.com/thecompu/Driv3rs" target="_blank">Driv3rs</a> program, and this also helped understand the driver file format. (thanks Guys)<br />
<br />
The o65 file includes the code and relocation information to allow the file to be loaded and relocated, similar to the PCD file that the Pascal assembler creates. The Apple 3 System Utilities SCP program takes the PCD files and converts these to a raw format. The SOS 1.3 source code contains in file SOSLDR.C.SRC.TEXT a brief note on this:<br />
<br />
<span style="font-size: xx-small;"><span style="font-family: "courier new" , "courier" , monospace;"> * SOS.DRIVER FILE FORMAT<br /> *<br /> * (8) LABEL<br /> * = "SOS DRVR"<br /> *<br /> * (2) HEADER COUNT<br /> * = # OF FLOPPY DRIVES<br /> * = CHARACTER SET TABLE<br /> * = KEYBOARD TABLE<br /> * ...<br /> * +---------------------------------------+<br /> * (2) DM #N TITLE COUNT <---+ ! RELOCATION FIELD FORMAT !<br /> * TITLE FIELD ! ! ----------------------- !<br /> * (2) DM #N CODE COUNT ! DRIVER MODULE #N ! CONSISTS OF A LIST OF 2 BYTE POINTERS !<br /> * CODE FIELD ! ! WHICH POINT TO THE LOW BYTE OF A TWO !<br /> * (2) DM #N RELOC COUNT ! ! BYTE QUANTITY TO BE RELOCATED. !<br /> * RELOC FIELD <---+ +---------------------------------------+<br /> * ...<br /> *<br /> * $FFFF = THE END</span></span><br />
<br />
Explaining this a little more, for each of the drivers, they have the following:<br />
word - length of the comment<br />
bytes - comment<br />
word - length of the code<br />
bytes - code<br />
word - length of the relocation table<br />
bytes - list of addresses that need relocating<br />
<br />
The program I have
written decodes the input o65 file and converts it to this Apple3 driver
format consisting of the three parts.<br />
<br />
The latest version of the program is available here:<br />
<a href="https://github.com/robjustice/a3driverutil" target="_blank">robjustice/a3driverutil</a><br />
<br />
There is some more detail in the readme there of the various functions available and how to run it. I have added a few more than I initially thought, so it has a bit of SCP functions in there now to add/list/extract drivers.<br />
<br />
This allows a driver to be assembled with the ca65 assembler and then added or updated to a SOS.DRIVER file. With the use of a disk image util, then this process can be automated in a script to allow one command to do driver assembly, updating in a SOS.DRIVER file and launching in an emulator.<br />
<br />
One other function it includes that I wanted to talk about here, is extracting a driver from a SOS.DRIVER file. I have done some disassembly of a few drivers and wanted a nice easy way to get the code out. While doing this I found that without 'relocating' the code, the origin of the code is address 0000. I found that this causes confusion with zero page locations and instructions when disassembling. To get around this, I have added the option of extracting and relocating the code to base address $2000.<br />
<br />
hope you enjoy this.<br />
<br />robjhttp://www.blogger.com/profile/16498154202278388762noreply@blogger.com0tag:blogger.com,1999:blog-2175625384541216522.post-58745677753491634012017-10-16T05:16:00.003-07:002017-10-16T05:16:53.345-07:00Apple /// Copy protection - some further investigationI did some further reading and it seemed that the On Three Uncopyprotect driver would also work for Apple Writer /// (version3.0). I found a copy of the disk images for this on the apple3.org website and booted up the first disk, <a href="http://www.apple3.org/Software/productivity/word_processing/AppleWriter30MSTR.dsk">AppleWriter30MSTR.dsk</a>, in Mess. It failed to start, but came up with a different error message than Visicalc, SYSTEM FAILURE = $06. <br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEigTIjTLscReWHJa88xc0CkXvlzRQiSkNxOawyBPu6Ol0FBIwxUJ0e_zAVaviyZFTUGM6qhWxHgLM9miZEJO8qOxDfHVHn7Y8peceorjYZtxpHcKCNUYzL_ZXE9GsAikRqkTeI2uaulZg/s1600/applewritererror.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="487" data-original-width="617" height="252" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEigTIjTLscReWHJa88xc0CkXvlzRQiSkNxOawyBPu6Ol0FBIwxUJ0e_zAVaviyZFTUGM6qhWxHgLM9miZEJO8qOxDfHVHn7Y8peceorjYZtxpHcKCNUYzL_ZXE9GsAikRqkTeI2uaulZg/s320/applewritererror.JPG" width="320" /></a></div>
<br />
<br />
<br />
<br />
I then used the SCP and added the uncopyprotect driver to the disk image and then booted it again in Mess. This time success!<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh_uaFTVX6IDn3bG_XLVAEqD2usGw5f1TrJOh8F5UHGWrvj2VuUg_XAlsEm7PbMkzLxfPq_pvdSpYQFRUb12iX7dB1csDKWhcxlUTVCxveXpXZBLx_nWB0_2v393e8SwDbuqAXxBoT9-A/s1600/applewriterworking.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="488" data-original-width="615" height="253" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh_uaFTVX6IDn3bG_XLVAEqD2usGw5f1TrJOh8F5UHGWrvj2VuUg_XAlsEm7PbMkzLxfPq_pvdSpYQFRUb12iX7dB1csDKWhcxlUTVCxveXpXZBLx_nWB0_2v393e8SwDbuqAXxBoT9-A/s320/applewriterworking.JPG" width="320" /></a></div>
<br />
<br />
AppleWriter /// is using the same inbuilt copy protection and the same key as Visicalc. Interesting that it gives a different error. This would depend on the the jump taken in the still encrypted sos.interp file after the protection validation has failed. I traced with the Mess debugger and it jumps to the NMI handler routine, and then jumps to the system death routine which gives the above error.<br />
I have seen this error for other disk images and had wondered why they gave that error. Looks like it could be due to copy protection failing for the disks.<br />
<br />
I did some more searching and there is a copy of AppleWriter /// v4.1 in the WAP disks (<a href="http://www.apple3.org/Software/wap/images/APPLE-3-WAP-wdp-01a.dsk" target="_blank">APPLE-3-WAP-wdp-01a.dsk</a>), and this one is not copy protected. So that's the easiest option to get it running and avoid this problem. Though we really need some NIB or better format images of the original v3.0 disks to preserve them in running condition.<br />
<br />
Another disk image that I have seen reported before as broken, is the Apple3SystemDemo disk. I downloaded the disk image of this from apple3.org, <a href="http://www.apple3.org/Software/system/Apple3SystemDemo.dsk" target="_blank">Apple3SystemDemo.dsk</a> and booted it in Mess. This also gives the same SYSTEM FAILURE=$06.<br />
<br />
I then thought I would try to copy in the uncopyprotect driver to the disk and see if this would also work. One catch though, from the disassembly in the previous blog entry, it needs SOS1.3 to work, and this disk has SOS1.1 on it. I used the Apple3SystemUtilities to copy over the SOS1.3 and driver file with the uncopyprotectdriver on it. (for some reason Ciderpress complains about a damaged directory entry, so i had to do this the long way)<br />
<br />
With the new sos.kernel file and the sos.driver file, the disk actually boots. but.. then gives an error about a sos call. I suspect this is due to the change from SOS1.1 to 1.3. The uncopyprotect driver did however, help to successfully decode the sos.interp file (which is business basic) and was able to run it. It must therefore use the same protection key as the other programs. I think this also means that SOS 1.1 had the same copy protection support built in.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiz0TmRwBlLFr9TcaIbSXcmPTeVJaVV9f0WrKB3N738Iw6RAsZON8hGK2p2rsvL00m4HxlnKi2k1GtWUgSwZJjIfKMC1m4TDcOCpq-pX5Ba40w-Q7vRdY6jtWSRPrqtjCnVT_kvpdNfxA/s1600/demososerror.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="515" data-original-width="647" height="254" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiz0TmRwBlLFr9TcaIbSXcmPTeVJaVV9f0WrKB3N738Iw6RAsZON8hGK2p2rsvL00m4HxlnKi2k1GtWUgSwZJjIfKMC1m4TDcOCpq-pX5Ba40w-Q7vRdY6jtWSRPrqtjCnVT_kvpdNfxA/s320/demososerror.JPG" width="320" /></a></div>
The easier way to fix this would be to copy in a unprotected version of the Business Basic sos.interp into this disk. I used the Apple3SystemUtils disk and copied one over from a working Business basic disk. Success, the demo works now, here is the classic running Horses :-) (disk image <a href="https://www.dropbox.com/s/rb12auzoe4t0dfx/Apple3SystemDemoUnProtected.dsk?dl=0" target="_blank">here</a>)<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgOphRNobnksg4SUtbGsZH_0sc7x3zkyUQ2QXyhUbMT7GpkPjcC8FaN4K_pMa-RnvWuUAgSRAKkN5hDLZwsFpfzQULTVfXOnFl18RH8gLotFNXeza6SWZCgF8EH5BtvNXhb5G4_rUyjgw/s1600/horse.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="729" data-original-width="937" height="248" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgOphRNobnksg4SUtbGsZH_0sc7x3zkyUQ2QXyhUbMT7GpkPjcC8FaN4K_pMa-RnvWuUAgSRAKkN5hDLZwsFpfzQULTVfXOnFl18RH8gLotFNXeza6SWZCgF8EH5BtvNXhb5G4_rUyjgw/s320/horse.JPG" width="320" /></a></div>
It looks like Apple used the same protection Key for Visicalc, AppleWriter, and this demodisk. I would have thought they may have used individual ones for each program, but seems this is not the case. Also looks like if any disk gives these errors, then it may be due to copy protection failing.<br />
<br />
<br />
<br />
robjhttp://www.blogger.com/profile/16498154202278388762noreply@blogger.com0tag:blogger.com,1999:blog-2175625384541216522.post-61600832916685455172017-10-13T04:01:00.000-07:002017-10-21T04:55:27.636-07:00Apple /// Advanced Visicalc and an interesting discoveryI recently purchased a copy of the Apple /// version of Advanced VisiCalc on ebay. It has since arrived and is a nice and complete setup, with the manual, command helper sheet, pocket reference and two sets of disks.<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjljo2gFw4zjltJYiTdtMBEEER8qYBQW0T04rcLKXWOL1olBd5Mgf5t_XRzoK5gl_N7hSOYyUtLBFkTvsuJq3leowtIwYa6ba29YyS7Q4r72gVSakjy-x0ia9Vavf0SPas37kvWKBbyUw/s1600/Visicalc1.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="960" data-original-width="1280" height="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjljo2gFw4zjltJYiTdtMBEEER8qYBQW0T04rcLKXWOL1olBd5Mgf5t_XRzoK5gl_N7hSOYyUtLBFkTvsuJq3leowtIwYa6ba29YyS7Q4r72gVSakjy-x0ia9Vavf0SPas37kvWKBbyUw/s320/Visicalc1.JPG" width="320" /></a><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjA3UlGdfjrpaB3ut2yLyIXQGLucjrDhn-7Jkg4MbHr9OaLMWVN-qZFt2f3oLbWYnPqIUgx7aJLoK_QKcJinwGpjvgAGd9EjHuEvn9KDTKsIgwZGAIT7KLMfbYElpARJlAmhJ6rdoemUQ/s1600/Visicalc2.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="960" data-original-width="1280" height="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjA3UlGdfjrpaB3ut2yLyIXQGLucjrDhn-7Jkg4MbHr9OaLMWVN-qZFt2f3oLbWYnPqIUgx7aJLoK_QKcJinwGpjvgAGd9EjHuEvn9KDTKsIgwZGAIT7KLMfbYElpARJlAmhJ6rdoemUQ/s320/Visicalc2.JPG" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg0uxh_lxzw_LnZWF5MpAacsQIALf_GhvDNEOKzdvwki9jk2wqP-FT_2O0aFJKo_jEbCepb2NXXpw3Xo-BJVa9l6P4sD_vrsWsbZtRUyqZ6DoPFd8x_UkYY38SsFJ6BY2reLsWEu_vIQA/s1600/Visicalc3.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="960" data-original-width="1280" height="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg0uxh_lxzw_LnZWF5MpAacsQIALf_GhvDNEOKzdvwki9jk2wqP-FT_2O0aFJKo_jEbCepb2NXXpw3Xo-BJVa9l6P4sD_vrsWsbZtRUyqZ6DoPFd8x_UkYY38SsFJ6BY2reLsWEu_vIQA/s320/Visicalc3.JPG" width="320" /></a></div>
<br />
I went to look for some disk images to have a quick play with it on the Mess emulator. I could not find any in any of the usual places, but did remember seeing it in the apple3rtr package. So some time later and some reading of the manual, I was quite impressed at how many features it had back then compared to what I am used to with the current version of Excel. Although no mouse support, so lots of key commands to learn.<br />
<br />
I then thought I would image the disks that came with the package, with some suspicion that there might be some copy protection involved. My goto setup for imaging is ADT using my IIc, as this can be setup/removed on my desk quickly. I then tried the newly created disk images on the Mess emulator, and looks like there is some copy protection as the program will not run. SOS boots ok, and then when the application goes to run (sos.interp), you just get the following screen.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhuew5FcWm_w66PfKChfouIJNlFW9uRmV_emhSH5cs6g1ruMgge6W0n4N9aYCoSZdKlr6iztRKJQkpIFsu-Ti-gHkset6dEaMX95UieD-bam8-Ff13peBNw7-kut5cGluHSAHdAdQkjkg/s1600/soserror.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="451" data-original-width="568" height="254" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhuew5FcWm_w66PfKChfouIJNlFW9uRmV_emhSH5cs6g1ruMgge6W0n4N9aYCoSZdKlr6iztRKJQkpIFsu-Ti-gHkset6dEaMX95UieD-bam8-Ff13peBNw7-kut5cGluHSAHdAdQkjkg/s320/soserror.JPG" width="320" /></a></div>
<br />
<br />
I did some basic comparison of the sos.kernal file (v1.3) to check it is not changed, and it was the same as others I had, so not that. I started Mess with the debugger enabled and looked to find out when SOS jumps to the interpreter, and then see what happens there to look for any clues. A quick look at the SOS source code to find a starting point and address $1EB0 is the address in SOS that it jumps to the interpreter. (in sosldr)<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgs6Btw2RzIG4ycXmGT34qjIry61Hd0_ML9gnYWN-0CwSh7tx1mMyq_Rh3T4ZTUYcMP6UXVKxnBjwwXdwOZKOwvUct4BMcMd1t8_GY5G4f9Y0lyScnll-uX3kh-T8vkK3QsYJr9xpLrmw/s1600/jmptointerp.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="130" data-original-width="1079" height="75" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgs6Btw2RzIG4ycXmGT34qjIry61Hd0_ML9gnYWN-0CwSh7tx1mMyq_Rh3T4ZTUYcMP6UXVKxnBjwwXdwOZKOwvUct4BMcMd1t8_GY5G4f9Y0lyScnll-uX3kh-T8vkK3QsYJr9xpLrmw/s640/jmptointerp.JPG" width="640" /></a></div>
<br />
That jumped to $2007 (in the sos.interp for Visicalc), which contains an indirect JMP to the address at $FFFC. This turns out to contain address $E833, this looked to be within SOS. A further look through the SOS source code and we find that's the SOS system Cold Start routine, which is what we end up with when we run with the copied disks.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjJeXemlX82HgyFDWb32S-lO7JiaNa8pByJkIot_dfA7fbcMSuk8lCZSlawT0cktxGul2xuLDK7JAfjGCWgHIi3z7Nd_qPRhVveO3tlqI_NjH9JorOv36ak6mjwmYbTkgi-7wJKl8cTHQ/s1600/coldstart.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="259" data-original-width="1023" height="162" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjJeXemlX82HgyFDWb32S-lO7JiaNa8pByJkIot_dfA7fbcMSuk8lCZSlawT0cktxGul2xuLDK7JAfjGCWgHIi3z7Nd_qPRhVveO3tlqI_NjH9JorOv36ak6mjwmYbTkgi-7wJKl8cTHQ/s640/coldstart.JPG" width="640" /></a></div>
<br />
Something strange going on here. It all boots as described in the SOS manuals, but just ends up at the cold start routine.<br />
<br />
I left it there, as I remembered the On Three 'uncopyprotect' driver. It allows Visicalc to run and bypass the copy protection. I wonder what this could be doing, it may give some clues. I then ran the SCP and added the uncopyprotect driver to the VisiCalc Loader disk image, and then the disk boots up fine.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiG-CoyxcRvr3SIuum-zYmhWUIJFr5ueNdCp_E0_lXjgWVz8MNx1PU0NPDxzxtsSegwcogfpsibHYok31MxU-sDX13yvGe-hzfBRkBI_SMI4ZJAmK1ivIETEzTg75mCenxpMOybw5rjKw/s1600/visicalcworking.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="455" data-original-width="572" height="254" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiG-CoyxcRvr3SIuum-zYmhWUIJFr5ueNdCp_E0_lXjgWVz8MNx1PU0NPDxzxtsSegwcogfpsibHYok31MxU-sDX13yvGe-hzfBRkBI_SMI4ZJAmK1ivIETEzTg75mCenxpMOybw5rjKw/s320/visicalcworking.JPG" width="320" /></a></div>
<br />
So what does this driver do to bypass the protection. I then did a disassembly of the uncopyprotect driver. This takes a little bit to extract the relocatable code part and disassemble, the details for that will be for another blog post.<br />
<br />
It was a very small driver so not too much work to decode. The disassembly listing is here <a href="https://www.dropbox.com/s/g40kzxfkqkm3tq4/uncopy.asm?dl=0" target="_blank">uncopy.asm</a> It still needs some finishing off, but the big clue is that it patches the SOS BFM_INIT2 module (<a href="https://www.dropbox.com/s/erfwa9vxd75h4b4/bfm.init2.lst?dl=0" target="_blank">bfm_init2.lst</a>). This is very interesting as I had not looked at this in detail, but seems SOS has some copy protection support built in to the operating system! Sounds very similar to some discussion papers that surfaced recently on SSAFE!<br />
<br />
The BFM_INIT2 module is run as part of the SOS loader during startup. The module reads the disk from Track 9, Sector 2, and grabs the volume number from the sector. It then waits a set time and seeks to the next track, reads a sector, again grabbing the volume number. And so on until Track 16. It then checks if the last Sector read was 6, and errors if its not. So it needs the sectors synchronized on the disk! (and the volume number preserved, so a DSK image was never going to work) This leaves us with an 8 byte Key made up of 8 volume numbers, one read from each track. It then uses this key to <b>decrypt </b>the sos.interp file in memory, and then does some modification of the start pointer and then runs the interpreter.<br />
<br />
A look back at the uncopyprotect driver and it has the specific Key hardcoded into it for visicalc. And the driver patches it into SOS when the driver is initialised. Then when Visicalc is run, SOS thinks it has read the correct key and decrypts and run Visicalc ok.<br />
<br />
To summarise things:<br />
- SOS has copy protection support built into the operating system (aka SSAFE)<br />
- For programs using the protection, the sos.interp file is encrypted with a key stored on the original disk <br />
- SOS uses eight volume numbers stored across eight track/sectors to 'hide' the key- The tracks are read in sequential order via a timed routine, and this expects a particular sector to be read on the last track, so they must be synced!<br />
- When the disk is booted, the key is read and then the sos.interp file is decrypted with the key, and then run.<br />
- without the key, the software cannot be decrypted and run!<br />
<br />
I wonder how many other Apple /// software packages used this support. I could see it possible to read the key from the original disk and decrypt the sos.interp file and then make a new disk with this on it. Then the software would be permanently unprotected. This may be worthwhile if there are a few disks that have this protection used.<br />
<br />
Wow, not how I thought this journey would have ended.<br />
<br />
Update with additional info:<br />
NIB image of the original disk: <a href="https://www.dropbox.com/s/vdmkacav8gciao0/AVCLOADER.NIB?dl=0" target="_blank">AVCLOADER.NIB</a><br />
Volume numbers extracted from the NIB image: <a href="https://www.dropbox.com/s/dttw8vh5u14aea5/AVCLOADER_volume%20numbers.txt?dl=0" target="_blank">Volume Number list</a><br />
<br />
Link to <a href="https://archive.org/details/AppleSSAFEProject" target="_blank">AppleSSAFEProject</a> Documents<br />
<br />robjhttp://www.blogger.com/profile/16498154202278388762noreply@blogger.com0tag:blogger.com,1999:blog-2175625384541216522.post-51487480665850680002016-10-06T04:19:00.002-07:002016-10-06T04:19:32.102-07:00RetroChallenge_201610 #2<div class="separator" style="clear: both; text-align: center;">
</div>
Sometimes you need to read the manual...<br />
<br />
The idea I was thinking of was to be able to enter the music notes and the lyrics either directly into the basic program, or enter them as a text file and have the program read it. I think I'll use this as a good easy song to start with. :-)<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi-wqAgYmrMBvQb4teleEYH2vmoCCHOnFg4gr_PZpt5Bjv3ERlsyBlu9wEjwQ2WcnrGyDu3ye6WdqgDMIbUnpcOr-TT1j3hGlQ1oLNbqrCRMfln8ADpHy2YZAsm6IPajzk_hbVN2lHSTA/s1600/Happy-Birthday_F_Singing-Bell.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="185" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi-wqAgYmrMBvQb4teleEYH2vmoCCHOnFg4gr_PZpt5Bjv3ERlsyBlu9wEjwQ2WcnrGyDu3ye6WdqgDMIbUnpcOr-TT1j3hGlQ1oLNbqrCRMfln8ADpHy2YZAsm6IPajzk_hbVN2lHSTA/s400/Happy-Birthday_F_Singing-Bell.jpg" width="400" /></a></div>
<br />
<br />
Then have a file something like this, notes, then duration, and the lyrics lined up possibly to get the timing. <br />
<span style="font-family: "Courier New",Courier,monospace;"> c.5 c.5 d1 c1 f1 e2 c.5 c.5 d1 c1 f1 e2 </span><br />
<span style="font-family: "Courier New",Courier,monospace;"> Hap-py birth-day to you Hap-py birth-day to you</span><br />
<br />
I need to try and work out some ways to transfer the music notes to the speech to bring the tune into it. And play with some of the other features of SAM to see what adds to this. First thing was to enter the text and convert using the new function on my driver. The first line converted to phonemes ends up like this.<br />
<span style="font-family: "Courier New",Courier,monospace;"> /HAEPIY BERTH DEY5 TUX YUW</span><br />
<br />
SAM supports setting the pitch, the standard pitch used is 120 in the examples, so the first thought was to make this C, and then add 10 for each note. ie D becomes 110, E = 120, and so on. rolled out, it becomes like this.<br />
<span style="font-family: "Courier New",Courier,monospace;"> "#P120" (C)</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> "/HAE"</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> "#P120" (C)</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> "PIY"</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> "#P130" (D)</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> " BERTH"</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> "#P120" (C)</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> " DEY5"</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> "#P150" (F)</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> " TUX"</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> "#P140" (E)</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> " YUW"</span><br />
<br />
Well, here is how that sounds, not to good at all.<br />
<a href="https://www.dropbox.com/s/fj09kh70i5bom0d/happy1.mp3?dl=0" target="_blank">Happy1.mp3</a><br />
<br />
Now remember the opening line of the blog, a quick look at the SAM manual and it looks like the pitch is the other way around, smaller value is higher pitch.<br />
<span style="font-family: "courier new" , "courier" , monospace;"> PITCH<br /> 00-20 impractical<br /> 20-30 very high<br /> 30-40 high<br /> 40-50 high normal<br /> 50-70 normal<br /> 70-80 low normal<br /> 80-90 low<br /> 90-255 very low<br /> default = 64</span><br />
<br />
A quick swap around and this was the modified test program:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgxdKrmh8le6_wN-zk6UtruPZC30kMCubOX8GU5kRPp1SYLcF5K-B97Hbqxgh0DPtsaqaTJvEXYJA3B0QsDycb5t5NQ9mpX0NDTSzxE9lZnzLQa8x9WvM1TVXpb0Y4xRq99bY6H24BdVA/s1600/happy2.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="317" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgxdKrmh8le6_wN-zk6UtruPZC30kMCubOX8GU5kRPp1SYLcF5K-B97Hbqxgh0DPtsaqaTJvEXYJA3B0QsDycb5t5NQ9mpX0NDTSzxE9lZnzLQa8x9WvM1TVXpb0Y4xRq99bY6H24BdVA/s400/happy2.JPG" width="400" /></a></div>
<br />
and this was the result. Still not to good.<br />
<a href="https://www.dropbox.com/s/64kctx6uctdzl1g/happy2.mp3?dl=0" target="_blank">Happy2.mp3</a><br />
<br />
SAM supports adding a stress value after the phoneme to add some expression. From the manual:<br />
<span style="font-family: "Courier New",Courier,monospace;"> 1 = very emotional stress</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> 2 = very emphatic stress</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> 3 = rather strong stress</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> 4 = ordinary stress</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> 5 = tight stress</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> 6 = neutral (no pitch change) stress</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> 7 = pitch-dropping stress</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> 8 = extreme pitch-dropping stress</span><br />
<br />
I then added a value of 5, need to have a play with these more, they might be quite useful.<br />
This was the modified test program with an arbitrary stress value after the last phoneme:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgl2gr-BcLGIAjZdft84Dl_oWhENUUgCnrOZzc7C5Lr5W5pamjBtOa1HPPQDqrmqT0XWAoOMLrElPz0Pf1FoENTTeQni5HSg4RSjLXd-xkfPBHMK0UhvyZrb3NbyXSlCo6DRql_WZiGLw/s1600/happy3.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="317" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgl2gr-BcLGIAjZdft84Dl_oWhENUUgCnrOZzc7C5Lr5W5pamjBtOa1HPPQDqrmqT0XWAoOMLrElPz0Pf1FoENTTeQni5HSg4RSjLXd-xkfPBHMK0UhvyZrb3NbyXSlCo6DRql_WZiGLw/s400/happy3.JPG" width="400" /></a></div>
<br />
<br />
and this was the result. Not to sure if this is better, I think it is improving.<br />
<a href="https://www.dropbox.com/s/lvzkt75hpgq7z5q/happy3.mp3?dl=0" target="_blank">Happy3.mp3</a><br />
<br />
Then the next thing was to extend the words, based on timing. I did this by just repeating the phonemes. Although the last word 'you' should probably be extended more, but it does not sound to good like that. Need to try some other ideas for it.<br />
This is the test program with these changes:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjWj7Om3E-YBMAijAhzJel5hTa1v-WqG7OJaQ47lDBBXxUf5m6pEqgTK4tEvH_P_zYuqao5QAKmvI-1HvDxvntKUD1WlypMzL8arE7eJD49TsRES67bU_v6n5jH7j2l4qmLxwuol7REyQ/s1600/happy4.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjWj7Om3E-YBMAijAhzJel5hTa1v-WqG7OJaQ47lDBBXxUf5m6pEqgTK4tEvH_P_zYuqao5QAKmvI-1HvDxvntKUD1WlypMzL8arE7eJD49TsRES67bU_v6n5jH7j2l4qmLxwuol7REyQ/s400/happy4.JPG" width="400" /></a></div>
<br />
and here is the result, its starting to get there!<br />
<a href="https://www.dropbox.com/s/zyozekzr326hzac/happy4.mp3?dl=0" target="_blank">Happy4.mp3</a><br />
<br />
I need to play some more with this, but I have some ideas now on how to translate from the music/lyrics to SAM. <br />
<br />
<br />
<br />
<br />
<br />robjhttp://www.blogger.com/profile/16498154202278388762noreply@blogger.com0tag:blogger.com,1999:blog-2175625384541216522.post-2738088893571687062016-10-04T04:51:00.000-07:002016-10-04T04:51:17.823-07:00RetroChallenge_201610 #1Time to get started on this challenge! <br /><br />To be able to work with and manipulate the speech output, I need to work with Phonemes, rather than plain text. This will allow me to extend the words and 'hold a note' for longer (or sing!). But working with them would take a lot of manual work to convert them from the text of the song lyrics. So the first thing I want to do is extend my Apple/// SAM driver to help with this.<br /><br />First, some background on SAM. The original SAM software came with two binary programs, SAM and RECITER.<br /><br />SAM is the actual speech program that takes Phonemes as input, and outputs speech from these through the 8 bit DAC card. Phonemes are speech sounds made by the mouth. Put together these make up words or speech. The full list of Phonemes that SAM supports are available in the user manual, linked here:<br />
<br />
<a href="http://mirrors.apple2.org.za/Apple%20II%20Documentation%20Project/Interface%20Cards/Speech/Don't%20Ask%20Software%20Automated%20Mouth/Manuals/S.A.M.%20-%20Owner's%20Manual.pdf" target="_blank">SAM Owner Manual</a><br />
<br />As an example, to say "Hello There" would need the following input " /HEHLOW DHEHR" to SAM.<br /><br />The other program RECITER takes plain text as input and using rule based conversion, converts these to Phonemes. It then passes the output to SAM to speak them. Reciter has a large table of rules that it uses to look at letters preceding and after to work out the Phonemes it should use. Some of these are for specific words, and some are building blocks, eg sounds for word. I just noticed it has a table entry for Atari! ".ASCII "(ATARI)=AHTAA4RI""<br />
<br />
<br />
My Apple/// driver implementation is done as a SOS character mode driver. A character mode driver supports reading and writing character strings. Currently I have two 'sub' drivers implemented, .SAM to support Phonemes, and .RECITER to support plain text.<br />
<br />
For both of these 'sub' drivers, you first open them. And then just write a string to them, and they will speak the string. To check for errors, you can read from these, and the error code is returned. If its 255, then all went ok. Other wise, it will return the character position in the string where the error occured. eg when an incorrect phoneme is found.<br /><br />What I want to be able to do is after the .RECITER has converted the plain text to Phonemes, I want to be able to read this back. The way i will implement this is to detect when a second read occurs, then return the converted string.<br /><br />I have added a variable to monitor the number of reads:<br /><span style="font-size: xx-small;"><span style="font-family: "Courier New",Courier,monospace;"> READNUM .BYTE 000 ;flag to determine number of reads after write, 0=none</span></span><br />Whenever a write occurs, I will clear this back to zero:<br /><span style="font-family: "Courier New",Courier,monospace;"><span style="font-size: xx-small;"> SPEAK LDA #000<br /> STA 014FC ;disable extended indirect addressing for FB/FC<br /> STA READNUM ;clear previous reads number<br /> LDA EReg</span></span><br /> <br />Then in the READ part, i have added a check and then either return the error code for the first read<br />or return the converted string.<br /><span style="font-size: xx-small;"><span style="font-family: "Courier New",Courier,monospace;"><br /> </span><span style="font-family: "Courier New",Courier,monospace;">$010 LDA READNUM ;check number of previous reads<br /> BNE RETPHONM ;yes, there has been, return converted string<br /> ;otherwise, return error code<br /> ;<br /> ;return error code<br /> ;<br /> <br /> ....<br /> <br /> ;<br /> ;return converted string containing Phonemes<br /> ;<br /> RETPHONM LDY #00<br /> $020 LDA INPUTBUF,Y ;read converted text from INPUTBUF<br /> STA (BUFFER),Y ;store in read buffer<br /> INY<br /> CMP #ASC_CR ;if CR then this is the end of the string<br /> BNE $020 ;no, next<br /> TYA ;yes, ret count = index +1<br /> LDY #00<br /> STA (RTNCNT),Y ;actual characters read count, low byte<br /> LDA #00<br /> INY<br /> STA (RTNCNT),Y ;actual characters read count, high byte<br /> RTS</span></span><br />One issue with this is it will actually speak the output each time your convert. If I have time, I will come back and improve this.<br /> <br />I have updated the changes into my github repository for this here:<br /><a href="https://github.com/robjustice/Apple3SAM" target="_blank">https://github.com/robjustice/Apple3SAM</a> <br /><br />To test this out, I have updated one of my test programs to check the driver operation. The disk image is available here with the updated driver and Basic test program.<br /><a href="https://www.dropbox.com/s/a4kkmlfoapyyedx/demo2.dsk?dl=0" target="_blank">demo2.dsk</a><br /><br />its quite simple, here is the output show the program and the output from it running in MESS:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgbJC_AuvIA3rwklM5SsTZD_uIfFTg_GEBRY08vqmoKOH7BjXia4jT1XJ0l1xsbiHg6jQNsClHigq35Zp-NF5m8KpmQkzrAzUbbGToqZOWfTdRz2SO8Yom5SL6_7OtBlo3GtijfhFu-kQ/s1600/Convert_Test.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="315" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgbJC_AuvIA3rwklM5SsTZD_uIfFTg_GEBRY08vqmoKOH7BjXia4jT1XJ0l1xsbiHg6jQNsClHigq35Zp-NF5m8KpmQkzrAzUbbGToqZOWfTdRz2SO8Yom5SL6_7OtBlo3GtijfhFu-kQ/s400/Convert_Test.JPG" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<br /><br />Next step will be to add pitch statements to see if SAM can start to sing.. <br /><br /><br /><br /><br />robjhttp://www.blogger.com/profile/16498154202278388762noreply@blogger.com0tag:blogger.com,1999:blog-2175625384541216522.post-31020663464561950152016-09-23T05:01:00.000-07:002016-09-23T05:01:17.881-07:00RetroChallenge_201610 #0While working on porting the Software Automatic Mouth (SAM) software to the Apple ///, see <a href="https://github.com/robjustice/Apple3SAM" target="_blank">https://github.com/robjustice/Apple3SAM</a> . I came across a demo for SAM that someone had made getting SAM to sing the American National Anthem. SAM supports setting the pitch and speed for the speech output, so setting this and lengthening the phonemes allows some sort of singing to be achieved.<br />
<br />
What I want to do for the RetroChallenge is to make a basic program to convert music and lyrics into a format that SAM could play or maybe that should be sing. (hopefully something like that :-) ) This might end up more of a helper program, and then some manual editing of the resultant phonemes to get it to sound better might be more likely.<br />
<br />
I'm thinking I will add the ability to my Apple /// driver to be able to use it to convert text to phonemes. Currently you can send text to it, but it just converts and speaks it. Then write a Basic program to read notes and text and convert to pitch statements/phonemes, and then play them.<br />
<br />
That's the idea, lets see how it goes once I get into it.robjhttp://www.blogger.com/profile/16498154202278388762noreply@blogger.com0tag:blogger.com,1999:blog-2175625384541216522.post-39757313743950019782016-07-08T05:27:00.000-07:002016-07-08T05:31:07.157-07:00iMC Portcom II<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgNGvzVqGhJ7gbPHc-009_LZBcfwTPlw1y7iQQtfTw1FariyJmwhk_KSjJ3-OgD2WPg_7BujWDgO-jgKxXNPLKEROwiuYHY1csb496qb2gR5JyFSYTOes3enJxxh9_xrOiLnNQTcLHjgA/s1600/IMG_2865.JPG" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"></a>This is my iMC Portcom II Apple II clone. Its more of a luggable type portable apple II. I purchased this recently off ebay. It looks like its an Apple II plus clone. (not IIe)<br />
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgW1c1p9P0WE9ZLUMAAjM6-qTePFwBezzKi1WWr46H9olVMjA9jm3ppKV21qd0m8yuaygXwGvWlNhFHxP1_AYUu2yNOeZm8DRcdZ9isCxhJbefCfvpkUTpRfZ1myo3hW8B3RNQew47cdg/s1600/IMG_2865.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="300" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgW1c1p9P0WE9ZLUMAAjM6-qTePFwBezzKi1WWr46H9olVMjA9jm3ppKV21qd0m8yuaygXwGvWlNhFHxP1_AYUu2yNOeZm8DRcdZ9isCxhJbefCfvpkUTpRfZ1myo3hW8B3RNQew47cdg/s400/IMG_2865.JPG" width="400" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjzuzmfxm0XAXSyVrgMqY5wybU8E-jnk4tbXgxXmYcwZMCZ1l_hcXYCi4v5tyDWYpAivF0syfiab4l069xmCehItGKUCUnhea8FaAnGpqFLHJqzKaZ0sACBOH-49Cv1w27jJZn0-SBQPA/s1600/IMG_2866.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="300" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjzuzmfxm0XAXSyVrgMqY5wybU8E-jnk4tbXgxXmYcwZMCZ1l_hcXYCi4v5tyDWYpAivF0syfiab4l069xmCehItGKUCUnhea8FaAnGpqFLHJqzKaZ0sACBOH-49Cv1w27jJZn0-SBQPA/s400/IMG_2866.JPG" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi4JjsZmA8mqCUFnX0LxpBTBRL-bInv_ex_03YUIfA0GUKCZyEgA4RswhXEdHD9jBDcCjUxYSBX2cZ3dR4WiZu8OpGzF991gdjNk6VaQD4aiqrHRyYXgbt5oXoVdP331WgM7nQAycYaLQ/s1600/IMG_2867.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="300" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi4JjsZmA8mqCUFnX0LxpBTBRL-bInv_ex_03YUIfA0GUKCZyEgA4RswhXEdHD9jBDcCjUxYSBX2cZ3dR4WiZu8OpGzF991gdjNk6VaQD4aiqrHRyYXgbt5oXoVdP331WgM7nQAycYaLQ/s400/IMG_2867.JPG" width="400" /></a></div>
<br />
<br />
It has some power supply issues as it causes my house RCD to trip when I turn it on now. It did have some signs of life for a little while until the power supply failed. The screen is an Amber colour monochrome type.<br />
<br />
It has 64k of memory on board and 5 apple slots. The one and only thing I can find on the internet about the iMC Portcom II says that they are slots 0,3,4,5,7. My board does not have any silkscreen on it at all.<br />
<br />
It has two ROMs on the motherboard, they are both 2716 eproms (2k x 8). ROM1 is for $F800-FF00. It has just the basics to display the message on the screen, wait for a keypress, and then jump to the disk controller firmware at $C600. The other rom looks like it has the IO card firmware for the disk controller and I assume for the inbuilt serial and parallel ports.<br />
<br />
<br />
This is my dump of the ROMs and a quick dissassembly of ROM1.<br />
<a href="https://www.dropbox.com/sh/jdc0s0993x4ob3q/AABDrRQgei2M_mFqyN5Ph92Va?dl=0" target="_blank">iMC Portcom II roms and dissassembly</a><br />
<br />
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgP9CqNIgU88zvckFwdcX_2I-2KRdHxluthSF8MZA69mVVklPt548icfszfMAJHPqFOP8Eo10F-S4dqcUAK-26kKTud5PEfsitFFJkU1N7Ze1XZeENhJ8bXiNK72_0h8BRcydO8r1cpQA/s1600/IMG_2881.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgP9CqNIgU88zvckFwdcX_2I-2KRdHxluthSF8MZA69mVVklPt548icfszfMAJHPqFOP8Eo10F-S4dqcUAK-26kKTud5PEfsitFFJkU1N7Ze1XZeENhJ8bXiNK72_0h8BRcydO8r1cpQA/s400/IMG_2881.JPG" width="300" /></a></div>
<br />
<br />
<br />
I have connected another power supply to test the main board and see if it works. It does, it displays this message now when i turn it on:<br />
<br />
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgfnmKKkP4yt5YGf9CXHr7pjpG70VsIuS8fNfT4JAyxpOHsSTOlT6afECXDRJAChLbYrlp5IuBBC8LYuRgXnoP6Pqf3hdUd4b8BMVpj4y-9tWaKXOMXoHslUDugiftpuKfmg5EPgTYPVg/s1600/IMG_2918.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="300" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgfnmKKkP4yt5YGf9CXHr7pjpG70VsIuS8fNfT4JAyxpOHsSTOlT6afECXDRJAChLbYrlp5IuBBC8LYuRgXnoP6Pqf3hdUd4b8BMVpj4y-9tWaKXOMXoHslUDugiftpuKfmg5EPgTYPVg/s400/IMG_2918.JPG" width="400" /></a></div>
<br />
The next issue encountered was trying to press a key :-( The keyboard was unresponsive. This required that the keyboard needed to be opened up. The keyboard encoder has a Z80, 2k eprom and 1k ram. I tried to read the eprom to see if it looked ok, and some bad news. It looks like has been erased over time. (there was no sticker over the window. The reader was not able to read anything useful This will take some reverse engineering to get it going...<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgeofv3cyUVJ-VU2e3y_j4wydR4-4WRFu-AK033-he8JNaZrD92fkRu3zNkir7uIL2oh5GkthJ1k-2IdCkskF702ZgyNQsDdqjSzWNrN61msYcg0JTxjALdtyv55GVOw0gXTk_dm8E-5A/s1600/IMG_2917.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgeofv3cyUVJ-VU2e3y_j4wydR4-4WRFu-AK033-he8JNaZrD92fkRu3zNkir7uIL2oh5GkthJ1k-2IdCkskF702ZgyNQsDdqjSzWNrN61msYcg0JTxjALdtyv55GVOw0gXTk_dm8E-5A/s400/IMG_2917.JPG" width="300" /></a></div>
<br />robjhttp://www.blogger.com/profile/16498154202278388762noreply@blogger.com1