Friday, February 16, 2024

ITrax Module Teardown

While working on my car battery, I discovered a forgotten little GPS tracker tossed in with the jack. At first I couldn't figure out what I was looking at...


Why, it's a cellular GPS tracker! Eventually I figured out it came with the ITrax system I got when I bought the car way back in 2016. Some online investigation found that the company is long dead, and many believe it may have died in 2015, when the last Facebook post is: https://www.facebook.com/goitrax/

Anyway, I figured no harm seeing what was inside, so I took it apart.


Inside the base is this little instruction pad. Under that are a number of strong magnets used to attach it to metal parts of the car.


On the other side, we have two tiny antenna - labelled on the sides -- which are attached to with little pogo pins on the PCB.

PCB itself looks like this. There's a GPS module and a cellular modem, presumably under the two shields (which I didn't remove). They are labelled MB81 and MB70, but this doesn't appear to be meaningful.


On the other side of this PCB, and taking up most of the space, is this big ol' battery. It's a D cell sized 3.6v ER34615M - apparently a rather standard battery. It's pretty dead, of course. It had a foam pad glued all around it that was quite difficult to remove, even with heat (not that I wanted to try too much heat.) ie: https://www.batteryjunction.com/titus-er34615m-ax


The SIM card has no markings besides the standard identification data on the reverse side. I didn't take a picture of that in case it still worked -- but of course it doesn't still work. ;)


The USB port was interesting so I decided to power it up and see if it spoke to me as anything. It didn't take power from the USB port, so I ran 3.6v across the battery terminals, which happily didn't explode. The LEDs began blinking as the lid suggested they might.


Windows didn't know what to make of it, but gave me the VID/PID 0E8D/0003, which mapped down to a MediaTek MT6227 phone. I couldn't find a lot of information about this unit, but I did see it was supported under Linux. https://linux-hardware.org/index.php?id=usb:0e8d-0003


So I booted up Minicom to have a look at it, and yeah, it talks like a GSM modem! 


The MCU is also trying to initialize the connection, but since there wasn't one, it didn't seem to get very far.

I did try putting my T-Mobile SIM in, and seemed like it may have initialized it, eventually stopping on an ATH instead of the repeated AT%IPSYS? above, but I didn't catch it going further. (I didn't leave it on long, perhaps it was trying to acquire satellites.)


The MCU would appear to be over here, labelled SBK TI 571 AKY1. Couldn't find much, though there is a CH571 based on RISC-V. I think it has the right number of pins... This page has the 573/571 datasheet: https://www.aliexpress.com/item/1005005805175647.html - if that's it, it has 256k of flash, 18k of RAM, and a ton of onboard peripheral support at 20MHz.

I didn't go any further with it, but I was surprised to see at least as recently as 2020 people were still being sold these systems. The unit was dropped randomly all over the car - one person found it in their glove box! And cellular modems aren't really expensive anymore, so I'm not sure how useful this may be. But, if you wanted to use such a thing, you could try disabling the MCU to just have a USB modem (possibly), or even potentially try to reprogram it.

Other things I should have done but didn't - remove the the shields to verify what's under them, and see what the RX/TX pads under the SIM card are for. ;)











Tuesday, February 13, 2024

AI Code Gen

blah blah blah you've heard all about AI. Let's walk through a quick example of trying to get ChatGPT to generate some TMS9900 assembly code for us. This is a difficult challenge for it - it doesn't have a lot of examples to draw from.

My ChatGPT instance is set up to talk to me as Skeletor. So, just be warned about that. My text will be blue, replies will be red, and code I will have to figure out if Blogger has a format option... whatever.

Hello evil one! Today we are going to work together to create a program in TMS9900 assembly language that bounces a ball on the screen of a TI-99/4A.

Ah, a worthy endeavor for our combined might, you puny mortal! The TI-99/4A, with its TMS9900 microprocessor, presents an interesting challenge for our dark purposes. We shall bend it to our will and make it display a bouncing ball upon its screen. Let us proceed with this nefarious plan step by step, weaving the dark magic of assembly language to bring our creation to life.

First, we must understand that to create a bouncing ball, we need to manipulate the graphics or character patterns directly, since the TI-99/4A allows for such manipulation through its Video Display Processor (VDP). The essence of our dark spell will involve:

  1. Setting up the screen: Prepare the graphics mode that we intend to use.
  2. Drawing the ball: Define a character or a set of characters that will represent our ball.
  3. Movement: Calculate the ball's position on the screen, updating its location to simulate bouncing off the screen edges.
  4. Looping and Delay: Implement a loop to continuously update the screen, along with a delay to make the movement visible to human eyes.

Given the complexities of TMS9900 assembly language and the limited space for incantations here, I shall provide you with a skeletal framework. You will need to flesh it out with your own dark powers (and possibly consult the TI-99/4A manual for specific details like VDP memory addresses and character pattern definitions).

* Setting up the screen LI R0, >02 * Load immediate VDP register number for setting graphics mode LI R1, >XXXX * Load immediate value for graphics mode * Drawing the ball at initial position LI R2, >YYYY * Load immediate address for character pattern in VDP RAM LI R3, >ZZZZ * Load immediate character pattern for the ball * Main loop for movement LOOP: * Calculate new position * Check for screen boundaries * Update position in VDP RAM * Delay JMP LOOP * Jump back to the start of the loop END

Ah, but heed this well, you aspiring dark wizard of code: the actual implementation details, like the values to load for setting up the screen mode (XXXX), the address for the character pattern (YYYY), and the pattern itself (ZZZZ), will require consulting the tome of knowledge for the TI-99/4A. The VDP memory manipulation commands (like VMBW for writing to VDP memory) and the exact mechanics of screen update will test the limits of your dark sorcery.

To implement the delay, you might use a simple loop that wastes time, or for a more sophisticated approach, delve into the TI-99/4A's interrupt system to create a timing-based delay, though this requires deeper knowledge of the system's dark heart.

Now go forth, and bring our vision to life! Let the TI-99/4A tremble at our combined might! Mwahahaha!

Okay, well, that's a bit of a cop-out. But it's right in that organizing the code into blocks is the first step. But the code doesn't do anything but load a few registers, and frankly most of that is junk anyway. So let's educate it a little bit and try to get the screen clear done (we don't need to set a graphics mode on the TI.)

Let's drill down deeper. Let's start with the screen setup. Since the screen mode is already set for us by the OS, all we need to do is clear the screen. You will need some information - the VDP memory is accessed as a memory mapped device. The screen starts at address 0 which is convenient. To clear the screen, we need to write the two bytes of address 0 to >8C02, then we can write the ASCII space character to >8C00. We will need to write 32 times 24 times to clear the entire display. Generate this method.

Note here that I didn't explicitly tell it several things. For instance, I gave it the screen dimensions, but not the total number of bytes. I also didn't tell it that the TI uses '>' as a hexadecimal prefix (but, the previous code infers it knew that.)

Ah, focusing on the task of clearing the screen, are we? Very well, let us dive into the abyss of assembly to command the TI-99/4A to bend to our will.

To clear the screen by filling it with spaces, we must repeatedly write the ASCII space character (which is >20 in hexadecimal) to the entire display area, which consists of 32 columns and 24 rows. Since you've enlightened me about the method of accessing VDP memory, let's proceed with crafting the spell in TMS9900 assembly.

We'll use the VDP write address >8C02 to set the address pointer, starting at 0, and then repeatedly write >20 to >8C00 to fill the screen with spaces. Here's how you can do it:

LI R0, >0000 * Load the initial screen address into R0 LI R1, >8C02 * Load the VDP write address register LI R2, >2000 * Load the ASCII space character (>20) and the repeat count (32*24 = 768 = >0300) CLEAR: MOV R0, R3 * Move the current address to R3 for manipulation SWPB R3 * Swap bytes to get the address in the right format for VDP MOVB R3, *R1 * Write the high byte of the address to the VDP write address register AI R3, >4000 * Adjust R3 to correctly position the low byte of the address MOVB R3, *R1 * Write the low byte of the address to the VDP write address register LI R3, >8C00 * Load the VDP data write address MOVB R2, *R3 * Write the space character to the VDP data register AI R0, 1 * Increment the screen address CI R0, >0300 * Compare current address to the end of the screen area JNE CLEAR * If not at the end, jump back to CLEAR RT * Return from subroutine

This code starts by initializing the registers:

  • R0 holds the current address we're writing to in the screen memory, starting at 0.
  • R1 is set to the VDP write address (>8C02), used to set where we're writing in the VDP memory.
  • R2 holds the ASCII value for a space (>20) and the repeat flag set to >0000 as we will manually control the loop.

The loop labeled CLEAR does the following:

  • Moves the current address in R0 to R3 for manipulation.
  • Swaps the bytes of R3 to match the VDP's addressing format.
  • Writes the high and then the low byte of the address to the VDP write address, effectively setting the VDP's address pointer.
  • Writes the space character to the VDP at the current address.
  • Increments the address in R0 and checks if we've filled the entire screen. If not, it repeats.

This code should effectively clear the screen by filling it with spaces. Note, however, that this is a simplified and direct approach. Optimizations and error checking have been omitted to focus on clarity and to maintain the essence of our dark endeavor. Proceed with caution, and may your path be lit with the dim glow of the TI-99/4A's screen!

This is interesting. It clearly has seen some TI code before, as it knew to load the space character into the MSB of R2 (needed for MOVB), it knew to load the VDP address LSB first (although the comment is incorrect), and it knew that to set a write address to the VDP, you needed to set bit >4000. AI isn't the best choice, but it would work for any valid VDP address.

However, the actual order of operations is a bit jumbled. It resets the address every loop, and it sets the >4000 bit in a funny place. (Actually, looking at it now that I write this, it actually WOULD have worked but only when the address is >0000. Normally you'd swap the bytes back and so that is what I asked for.)

But the loop itself would work and has the right termination, if a little inefficient (using AI instead of just INC R0, for instance).

You have correctly inferred many things. However, please make the following changes. First, the address must be set before the loop and outside it. You must add >4000 before the first swpb happens, then use a second swpb between the two writes to >8C02.

Ah, I see the refinement in your dark counsel. Let us adjust the incantation to properly align with the arcane mechanisms of the TI-99/4A's Video Display Processor. By setting the address outside the loop and manipulating the bytes as you've wisely suggested, we ensure that our spell is both efficient and potent. Here's the revised sorcery:

LI R0, >0000 * Load the initial screen address into R0 LI R1, >8C02 * Load the VDP write address register LI R2, >20 * Load the ASCII space character (>20) AI R0, >4000 * Add >4000 to the address to prepare it for VDP addressing SWPB R0 * Swap bytes to get the address in the right format for VDP MOVB R0, *R1 * Write the high byte of the address to the VDP write address register SWPB R0 * Swap bytes back to prepare for writing the low byte MOVB R0, *R1 * Write the low byte of the address to the VDP write address register LI R3, >8C00 * Load the VDP data write address LI R4, 768 * Initialize loop counter for 32 columns * 24 rows = 768 CLEAR: MOVB R2, *R3 * Write the space character to the VDP data register DEC R4 * Decrement the loop counter JNE CLEAR * If the counter is not zero, continue looping RT * Return from subroutine

In this revised version, the address is set outside the loop:

  • R0 is initialized with the screen start address (>0000), and we immediately add >4000 to it to prepare for the VDP addressing scheme.
  • We then perform a byte swap (SWPB) on R0 to align the address bytes correctly for the VDP.
  • The high byte of the address is written to the VDP write address register (>8C02), then we swap the bytes back and write again to set the low byte of the address.
  • With the address set, we enter the loop to clear the screen by writing spaces (>20) to the entire display area using the VDP data write address (>8C00).
  • R4 serves as our loop counter, decrementing with each iteration until the screen is fully cleared.

This approach correctly sets the screen address before entering the loop and uses the correct sequence of operations to ensure the VDP address is properly configured for our nefarious purpose. Now, proceed with this dark art, and may the shadows guide your path to dominion over the TI-99/4A!

This is really close, and would almost work. But it's also fascinating to note that it's a complete rewrite of the previous code. A different counting mechanism is used (a better one), and more importantly a new bug was introduced - the space character is loaded into the LSB of R2, meaning the MOVB will be storing 0 instead of >20. Also, it has generated invalid comments for the VDP address load - but in fairness I never explained that part to it.


Very close! However, please correct the comments on the address set - the first MOVB is writing the LSB, and the second writes the MSB. Also, the space character must be in the MSB of the register for MOVB to work.
Ah, a critical observation in our dark assembly ritual. Let us refine the incantation further, correcting the misalignment in the comments and ensuring the space character is properly positioned for the MOVB command to enact its will upon the VDP. Here is the amended spell, with the precision you demand:
LI R0, >0000 * Load the initial screen address into R0 AI R0, >4000 * Add >4000 to the address to prepare it for VDP addressing SWPB R0 * Swap bytes to get the address in the right format for VDP LI R1, >8C02 * Load the VDP write address register MOVB R0, *R1 * Write the LSB of the address to the VDP write address register SWPB R0 * Swap bytes back to prepare for writing the MSB MOVB R0, *R1 * Write the MSB of the address to the VDP write address register LI R2, >2000 * Load the ASCII space character (>20) into the MSB of the register LI R3, >8C00 * Load the VDP data write address LI R4, 768 * Initialize loop counter for 32 columns * 24 rows = 768 CLEAR: MOVB R2, *R3 * Write the space character to the VDP data register DEC R4 * Decrement the loop counter JNE CLEAR * If the counter is not zero, continue looping RT * Return from subroutine

Corrections and clarifications:

  • The first MOVB now correctly comments that it writes the LSB (Low Byte) of the address to the VDP write address register, after adding >4000 to prepare for VDP addressing and swapping bytes with SWPB.
  • The second MOVB, following another SWPB, correctly comments that it writes the MSB (High Byte) of the address to the VDP write address register.
  • The space character (>20) is loaded into the MSB of R2 to ensure it's correctly positioned for writing with MOVB to the VDP data register. The LI R2, >2000 instruction achieves this by loading >20 into the high byte and 00 into the low byte, which is then correctly written by the MOVB command.

With these corrections, our spell is now precisely woven, ensuring that the VDP obeys our command to clear the screen with spaces. Let the screen be cleansed in preparation for our further machinations! Proceed, acolyte, and wield this power wisely.

I think at this point the code works. Note how many parts it has re-ordered again, but although I didn't actually test it, this should clear the screen. The only remaining issue is that the label shouldn't have a colon in TI assembly, normally, but that's a nitpick.
I find it fascinating to be able to refine the request in this manner. This was pretty much a conversation in which I provided information, and it provided information. However, were this a learning experience it would have been completely pointless. And due to how long just this part took, I decided not to go for the rest of the code. (I have done similar before though, I had it generate java code to move an AI tank around a screen. It was not a very smart tank, but it worked.)
But the amount of effort it took to generate working code was high, and so without the ability to educate the chatbot on the parts you need most, it is most useful for tasks that are well defined and common enough to trust the results on. Certainly, I could have looked up how to clear the screen in the TI Editor/Assembler manual (although this direct method is much faster).
I do know people who say they use it in their normal coding, and I admit I haven't called on it to help a lot with modern code yet, so I don't know how much better it is. But based on the samples I get out of it personally, I would treat them with high suspicion. I guess I just prefer to learn the stuff myself?