So I guess the question we all have to ask is, how well does it work?
The best way to simulate a real calculator would be to go into wabbitemu and set the grayscale on steady freq at ~63Hz with 4 shades. (From my experience, 63 is average with the upperbound at 66 and lower at 59).
For comparison, here's chess at 63Hz with 4 shades:
arrays filled with "switches"(basically if it's on, 1. If it's off, 0) will help you a lot. Also, something dynamic, like chests, could be drawn over tilemap based on the "event switch" is 0 or 1.
Building on this, here's by far the best way to actually do this. If you look at the list of memory addresses, you see this:
Now, of course to you, this doesn't mean that much. But what's neat about this is that IY points to flags. Whenever you go to use a system flag, what you are doing is accessing $89F0 + [flag offset]. Now, this is what everyone is used to. But, look what comes before flags, 2 random addresses, and then saveSScreen! What makes this great is that IY can actually address backwards.
Ok, so to put some numbers on this.
IY is pointing to $89F0 The last byte of saveSScreen is at $89EB The gap there is 4 garbage bytes IY can go as far back as -128
So, put these numbers together and you can have 124 bytes of flag data. That's 992 flags.
Implementing this: First of all, your flag data will be from $8970 to $89EB.
To access it, you would use "bit flag_bit, (iy - flag_offset)". Now, this works fine and dandy, but to be honest, remembering both the bit and the offset is rather annoying. This is in my opinion one of the pitfalls of TI's flags. So, a better solution is to create a macro.
This macro is for SPASM, if you use TASM then toggle won't work, and if you use Brass, I doubt any of it will work.
#macro toggle_(flag) ld a, (ix + f_(flag)) xor 1 << b_(flag) ld(ix + f_(flag)), a #endmacro
That probably scares you, so let me explain. - bit_(flag_name) is just like bit - res_(flag_name) is just like res - set_(flag_name) is just like set - toggle_(flag_name) will toggle that bit
The first number is the offset, and the second number is the bit. You can just keep this general pattern up for a while. I have to go now, but if you run out of flags using this method (the highest is $F7, let me know and I'll tell you how to continue).
Anyways, I would guess that if you uninstall and reinstall ti-connect, it will work. If you are on a 32 bit machine, then you can completely uninstall ti-connect by following the instructions in that tutorial the squidgetx mentioned. Sometimes the drivers get a little screwy. (You can even uninstall the drivers on a 64 bit machine, but so far, I don't think any one has had any trouble with that.)
Without modifying Axe, here's what the solution would look like:
First, you would have to make the information that's going to go on the data page. I'm not exactly sure how you would go about doing this in a nice manner, but I guess your choices would be an all data axe program, making an all data asm program (easier than you think), or hex editing a file (scary).
At this point, you would have to know the locations of all of the data structures in this file. So data1 at 0000, data2 at 0010, data3 at 001A, etc. This would be a rather mess to do by hand, which is why I suggested the asm program. (You could simply .echo all of the labels for the data).
An axiom would have to be created to access this data. What you would do is pass the axiom the pointer to the data, the size of the data, and where you want to put it in ram. The main problem here is that these would have to be static addresses, you could make them all variables, but every time you mess with the data page, you're going to have to resynchronize.
The last step, which is also the sketchiest step, would be to compile you program with axe, and then use another program to slap the data onto the back of the app and fix all the header information. This can be done, it's just a little messy.
So, without modifying axe, that's what the solution would be. I could do it, but I feel like the manual data location thing would get annoying really fast. Imaging having 100 different data segments and you add a byte to the first one, that's a lot of number changing. (Though, xeda could do it)
And of course, since it's me, I'll offer the alternative of fullrene.
Edit: I suppose an Axe include file could fix the label issue, I'm just not sure how to generate one from the input data.
So why not combine the 2? You would have a program that downloads "chunks" of data from the drive, plays them, and then deletes them. This would obviously have problems, the first coming to mind is speed, but does this seem like a possiblity?
Well, first of all, I'd like to point out that the "MP3's" you are talking about are similar to MIDI files. (Old cell phone ringtones).
The 84+ has been able to play music for quite some time now. It started real Real Sound (the video is gone) which could only work on the calculators with the extra ram. Then I made TruSound (youtube) which allowed the newer calculators to play sounds as well.
Now, both of these programs played .WAV files. If you know much about song formats, you know that .WAV files can be around 5x as big as MP3 files. The reason for this is that MP3 files are compressed to a smaller size. Like shmibs said, this compression algorithm is very complex and some computers running windows 2000 cannot even play them properly without skipping. What makes .WAV files convenient is that they are already in the format that is required to play sound while MP3 is not.
The obvious solution to the MP3 problem would be to decode the files ahead of time, but the 84+ only has 48KB or 128KB of ram (HW differences) and at 128Kbps, that means you'll get either 3 seconds or 8 seconds of song before the program would have to decode the next section which could take another 3 to 8 seconds. (TruSound uses a little compression, but it only cuts off around 20% of the file size)
Anyways, that's why MP3 doesn't work. As far as the USB half of it, I didn't think it was possible, but SirCmpwn proved us wrong. The trouble with sound over USB is that you have to try to get the USB port to cooperate with you fast enough to keep up with the song. Not only that, but you have to manage your cpu time because playing sound requires around 60% of the processor time when optimally configured and USB is a finicky thing that doesn't like to be interrupted.
Now, I say SirCmpwn proved us wrong, but like everyone has said, he never actually released his program. So while his youtube video made the music sound nice, I would honestly bet that it was a little scratchy. But, to be fair, he did manage to play recognizable music from a flash drive.
Finally, since you seem to be excited about playing songs on your calculator, I'll have to point you to another one of my projects, TruVid. (youtube)
I got a idea how to make it moar awesome! Well, i have that one program run on zstart you made ages ago penguin aaaaaaand, i have symbolic symbolic doesn't play nice with it but if i run graph3in on homescreen and then enter graph3 menu everything is working fine so, why not add a option for a program to run on homescreen?
I run them in exactly the same way, I'm not sure why it would make a difference.
My best guess is that symbolic and graph3 are fighting with hooks, so I don't think you are going to have a nice fix for this.
Off to make an Impossible Game! Someone else, if anyone's interested, should probably do this because it's gonna take me A LONG TIME
Yeah, the source isn't going to help you in the slightest. It's written in asm which means there's going to be a lot different, a few problems:
It's a foreign language to you (unless you know x86 asm or something)
Asm is structured soooo much differently than Lua
It's specifically optimized for the structure of asm (in fact, most of the code that draws the sprites is generated at run-time)
Lastly, it's not all that difficult of a game to make
So, I would recommend you try to make it yourself and find a way to use my level data (that would be a lot of typing (though, I had to do it from a youtube video so...)).
However, if you want the source, it's somewhere on this thread.
First of all, I love that you've lurked long enough to know about calc84 and I. But anyways:
1. For inputting stuff in asm, really, you're going to have to write it yourself. There aren't really any OS routines you could use that will give you what you want.
So, for my example, I'm going to use bcall(_getCSC) and I'm going to ignore 2nd related stuff. (Pressing [,] will just be E).
;##################################### ;Type name ;output: HL = pointer to input string ; carry = user quit
bufSizeequ10;this is how long you want the buffer to be bufferequsaveSScreen;put this wherever you want
typeName: bcall(_clrTxtShd);if you don't do this, letters will appear under the cursor ei setcurAble, (iy + curFlags);we'll use the OS's cursor since it's easier ldde, buffer;de is going to be the pointer ldb, 0;b will be how many characters have been entered ldhl, 0*256+0;this is going to start at (0,0), change this to whatever you want ld(curRow), hl typeLoop: halt;putting a halt in this loop decreases battery use by like 90% bcall(_GetCSC);this gets whatever key was press (physical key, no 2nd crap) ora;was a key pressed jrz, typeLoop;no go back around
cpskEnter;sk[Key pressed] because we're using getCSC jrnz, notaEnter
lda, b ora jrz, notAEnter;0 length input is silly xora ld(de), a;null terminator turns this into a string, you don't have to do this callcurOff rescurAble, (iy + curFlags);kill the cursor ldhl, buffer;might as well return a pointer ora;this resets the carry flag, carry means user quit ret
notaEnter: cpskDel jrz, delTa cpskLeft;since we're not the OS, pressing left is going to delete a number jrnz, notBackSpace delTa: lda, b ora jrz, typeLoop;don't do it if there's nothing there callcurOff;prevent hanging cursor
ldhl, curCol;move the cursor back dec(hl)
decde;move the pointer back decb;decrease the number of letters lda, ' ' bcall(_PutMap);put a blank without moving the cursor callcursorOn jrtypeLoop
notBackSpace: cpskClear jrnz, notClearz;I have clear quitting, you can do other stuff if you want
callcurOff rescurAble, (iy + curFlags)
scf;this lets the calling routine know you quit ret notClearz: ldc, a lda, b cpbufSize jrz, typeLoop;if it's too big, accept no more input lda, c
subskChs;this is the neg button, it's the lowest value key we want (sk value) jrc, typeLoop;if it's under skChs ($11) we don't want the key cpskComma-skChs+1;skComma ($25) is the highest value we will accept jrnc, typeLoop
ldhl, charTable
adda, l;this little section is HL + A ldl, a jrnc, $+3;after this, HL holds a pointer the the character we need to display inch ;$$;this is just a comment for clarity on the jump, could have used a label
callcurOff;destroys A not HL (this is an actual comment from this code :D ) lda, (hl) ora jrz, justKidding;the button pressed was in the correct range, it just wasn't a key we wanted ld(de), a;add it to the buffer incde;increase the buffer pointer incb;increase the counter for the bufer
bcall(_PutC);type the character and increase (curCol)
callcursorOn jptypeLoop
justKidding: callcursorOn jptypeLoop
cursorOn: rescurOn, (iy + curFlags) jrreadyk curOff: setcurOn, (iy + curFlags) readyk: lda, 1;this is a clever little hack, you set the wrong cursor state ld(curTime), a;set the curTime to 1, and let an interrupt occur ei;since the OS decreases curTime by one every interrupt, it will halt;reach zero and the OS will flip the cursor over to the correct state ret
charTable:;these are the letters as they appear in order of scan code .db$1A, "369", 0, 0, 0, 0;1A is neg .db".258", 0, 0, 0, 0 .db"0147", $1B;1B is E
So after this is run, if it comes back with carry not set (NC) you will know that you should then parse the buffer for the floating point number. I don't think parsing will be that hard, so I left that up to you If you totally understand this routine, you can rework it to use bcall(_getKey) which will allow for the user to press 2nd. But I don't see the point in this other than to prevent confusion with the E button.
As for part 2 of your post, I'll have to get to that another day. Right now I don't have the time. But, from a quick glance, you might want to check out bcall(_putS) and bcall(_vPutS). The reason is that every bcall is rather slow to call, so calling these single ones that display a whole string can speed things up.
(Where do you look them up? wikiTi and TI's TI-83 Plus System Routines (this link is to the page, you'll have to download the pdf))
The reason that your routine was so slow was that you were displaying all of those spaces. Never display spaces in small font like that because it's slow as balls. Also, whenever you run bcall(_vPutS) or bcall(_putS), HL returns pointing to the byte after the zero. This allows you to display all the strings one after another.
If you want even more speed, there is an option. First you "set textWrite, (iy + sgrFlags)". This will allow you to write the small font directly to plotSScreen without writing it to the screen. After it's all there, you can then do bcall(_grBufCpy) (or your own version) to write it to the screen. This is faster because writing to the screen is slow so doing it all at once is faster. The only trouble, (and why I didn't do it to yours), is that it doesn't affect the large font. To get that to work, you'd have to "set fracDrawLFont, (iy + fontFlags)" and then use bcall(_vPutS) to write it to the buffer. But that's a little messy (though not really).
it's possible, and it should be easy enough to manage in lua, even if you add in all the fancy effects =) thepenguin, do you have the level data for these in a readable format so it would ease the process?
Hmm, so if I am reading your post properly, the first code sends 8 bytes to port $A0, and the second writes all the bytes being received, to HL, and then returns the number of bytes that were received? Is USB control that easy?
The one that reads all of the data is that easy. The driver basically says, "I got some data for you" and you read it all.
The output one is super simplified, but this small section of code does appear in most data transfer code.