Greg's Scratchpad Thread on Roomba Comm Hacking

Inside the Roomba and Scooba and more, Cool mods, Repair and Upgrades - including the all new iRobot Create Kit. Let's void that warranty baby!
User avatar
gssincla
Robot Addict
Posts: 111
Joined: July 19th, 2006, 3:26 pm
Location: Chicago

Post by gssincla »

Excellent Howard! Thanks. I was actually posting something similar to that when i got the notice of your reply. I'd not made the XOR connection though. I was thinking that 0x80 was escape-type character but didnt know how it translated. So not only did you beat me to it, but you totally bested me :)

Thanks for the info!!

Do you have any ideas how to decode the rest of it? ;-)

I'm still working under the impression that this data stream is encoded. And since the processor is rather weak and there is no flow control, i'm assuming that the encoding is rather simplistic and computationally inexpensive. My current theories are:

1) Simple one byte XOR
2) Key/Block based XOR
3) Some sort of summation or shift

I'm 99% certain that since the data field is 0x22 characters long, the last two characters are probably some sort of checksum for the string. Or maybe the first two. Typically the checksum is done after the data field to provide more reliability to the value.

I'm also curious about the first two 0x05 commands that are present. They are 6 bytes long which would make for a DWORD + checksum. They are repeated twice which is odd.

Also, the first two sequences in Stage 5 (0x07 80 87 00 00 and 07 80 85 01 01) are shorter than the other 07 80 87 sequences. I wonder if these are establishing a loading address, a data length or a encoding key.

Again, excellent find Howard!
Howard
Posts: 35
Joined: June 15th, 2006, 2:18 am

Post by Howard »

In a typical line

Code: Select all

07 80 87 22 02 02 aa 6a d2 f8 65 5e cd 84 14 e0 2a 8e 9e 35 75 6c ed cd a9 61 70 73 ef 94 46 03 4c 1c b3 06 ec ea 7b 18 
Byte 3 (22) is the length of the data probably including the checksum.

Byte 4 (02) is a sequence number. This number is sent back as the fouth byte with each acknowelagement that the message was recieved.

Their doesent appear to be any flow control which is resulting in a high percentage of resent data.
User avatar
gssincla
Robot Addict
Posts: 111
Joined: July 19th, 2006, 3:26 pm
Location: Chicago

Post by gssincla »

It kind of reminds you of the TCP/IP sequence numbers scheme, doesn't it?


I've rescanned the original hex files and filtered the 0x80 sequences into their proper meanings. Attached are the new files.

Whats interesting also is that OSMO commands tend to be ODD whereas the Roomba replies are EVEN and sequential. For example you have

>03
<04
>05
<06
>07
<08

where < is the roomba reply and > is the osmo command. The only outlier is the 0x09 reply from the roomba. A quick glance through shows a sequence of 08 08 09 replies coming from the roomba.

Also interesting is the content of these replies.

Code: Select all

10 08 01 00 0f f9 
10 08 01 01 0a 6e 
10 08 01 02 0e d7 
10 08 01 03 0b 40 
10 09 01 04 c0 55 
10 08 01 04 0d a5 
10 08 01 05 08 32 
10 09 01 06 c1 7b 
10 08 01 06 0c 8b 
10 08 01 07 09 1c 
10 09 01 08 c6 b1 
10 08 01 08 0b 41 
10 08 01 09 0e d6 
10 09 01 0a c7 9f 
10 08 01 0a 0a 6f 
10 08 01 0b 0f f8 
10 09 01 0c c4 ed 
10 08 01 0c 09 1d 
10 08 01 0d 0c 8a 
10 09 01 0e c5 c3 
10 08 01 0e 08 33 
10 08 01 0f 0d a4 
10 09 01 10 c1 79 
10 08 01 10 0c 89 
Take this block for instance. If you have a 09 reply, the high nibble of byte 5 will be C (bits 15 and 14 set) otherwise it will be 0. This is constent throughout the flashing process (cmd 07).

Looking at the sequence numbers, it looks like 09 represents a "resend packet" command.

Now, reorder the packets into sets of three... starting with the first 08 reply and label that sequence 1, label the next sequence 2 and the next sequence (which should be a 09 reply) as 3. Repeat the labeling starting at 1. You get the following patterns:

Code: Select all

10	08	01	04	0d	a5
10	08	01	06	0c	8b
10	08	01	08	0b	41
10	08	01	0a	0a	6f
10	08	01	0c	09	1d
10	08	01	0e	08	33
10	08	01	10	0c	89
10	08	01	12	0d	a7
10	08	01	14	0e	d5
10	08	01	16	0f	fb
10	08	01	18	08	31
10	08	01	1a	09	1f
10	08	01	1c	0a	6d
10	08	01	1e	0b	43
10	08	01	20	09	19
10	08	01	22	08	37
10	08	01	24	0b	45
10	08	01	26	0a	6b
10	08	01	28	0d	a1
10	08	01	2a	0c	8f
10	08	01	2c	0f	fd
10	08	01	2e	0e	d3
10	08	01	30	0a	69

10	08	01	03	0b	40
10	08	01	05	08	32
10	08	01	07	09	1c
10	08	01	09	0e	d6
10	08	01	0b	0f	f8
10	08	01	0d	0c	8a
10	08	01	0f	0d	a4
10	08	01	11	09	1e
10	08	01	13	08	30
10	08	01	15	0b	42
10	08	01	17	0a	6c
10	08	01	19	0d	a6
10	08	01	1b	0c	88
10	08	01	1d	0f	fa
10	08	01	1f	0e	d4
10	08	01	21	0c	8e
10	08	01	23	0d	a0
10	08	01	25	0e	d2
10	08	01	27	0f	fc
10	08	01	29	08	36
10	08	01	2b	09	18
10	08	01	2d	0a	6a
10	08	01	2f	0b	44
10	08	01	31	0f	fe
					
					
10	09	01	04	c0	55
10	09	01	06	c1	7b
10	09	01	08	c6	b1
10	09	01	0a	c7	9f
10	09	01	0c	c4	ed
10	09	01	0e	c5	c3
10	09	01	10	c1	79
10	09	01	12	c0	57
10	09	01	14	c3	25
10	09	01	16	c2	0b
10	09	01	18	c5	c1
10	09	01	1a	c4	ef
10	09	01	1c	c7	9d
10	09	01	1e	c6	b3
10	09	01	20	c4	e9
10	09	01	22	c5	c7
10	09	01	24	c6	b5
10	09	01	26	c7	9b
10	09	01	28	c0	51
10	09	01	2a	c1	7f
10	09	01	2c	c2	0d
10	09	01	2e	c3	23
10	09	01	30	c7	99
10	09	01	32	c6	b7
with the first block being your "1" blocks, the second your "2" blocks and the last your "3" block.

In this example you can see that you 1 block sequences never reach a value under 8 in byte 5. In the 2 block sequences byte 5 never falls below 8. And finally, your retransmit request block (block 3) never exceed 7.

Now look at part of this in context with the OSMO commands:

Code: Select all

>07 07 0a 00 00 1e 9f 70 5f 54 a4 8e cb f9 4a 
<10 08 01 00 0f f9 
>07 07 0a 01 01 63 39 e0 62 97 7d 45 40 a0 a6 
<10 08 01 01 0a 6e 
>07 07 22 02 02 aa 6a d2 f8 65 5e cd 84 14 e0 2a 8e 9e 35 75 6c ed cd a9 61 70 73 ef 94 46 03 4c 1c b3 06 ec ea 7b 18 
<10 08 01 02 0e d7 
>07 07 22 03 02 7e 7a 17 d5 fc 6e 7c 27 30 8e 2a 1e 5e 50 6c 74 ee ca 82 07 4f da 70 1c a1 2a 87 d0 84 4c f5 5e 58 f2 
<10 08 01 03 0b 40 
>07 07 22 04 02 fa 25 3a 73 73 0a 7d 2c e6 5b 08 72 ce b2 ab df 66 08 3d 56 b5 61 f6 fb ab 06 a7 9e e2 b4 89 fe 88 13 
>07 07 22 05 02 73 fb c9 ad 3e a9 db 7d 4e ec ef 87 0e 83 30 56 bc 97 c7 f5 b3 6f 00 15 e0 b9 2a cc 08 87 1f 2b e9 7a 
<10 09 01 04 c0 55 
>07 07 22 04 02 fa 25 3a 73 73 0a 7d 2c e6 5b 08 72 ce b2 ab df 66 08 3d 56 b5 61 f6 fb ab 06 a7 9e e2 b4 89 fe 88 13 
<10 08 01 04 0d a5 
>07 07 22 05 02 73 fb c9 ad 3e a9 db 7d 4e ec ef 87 0e 83 30 56 bc 97 c7 f5 b3 6f 00 15 e0 b9 2a cc 08 87 1f 2b e9 7a 
<10 08 01 05 08 32 
>07 07 22 06 02 42 07 b8 70 63 3f d5 e1 80 90 41 28 42 5c a5 53 d9 2f 47 78 63 f7 3a a8 5f e6 e3 ae c3 7f 00 07 22 f7 
>07 07 22 07 02 87 ea 6c e6 1f a1 74 a8 ca 19 75 52 f0 b1 25 0c 23 05 11 96 dc 8a 44 79 ee 00 44 38 93 a5 dc a5 f3 5f 
<10 09 01 06 c1 7b 
>07 07 22 06 02 42 07 b8 70 63 3f d5 e1 80 90 41 28 42 5c a5 53 d9 2f 47 78 63 f7 3a a8 5f e6 e3 ae c3 7f 00 07 22 f7 
<10 08 01 06 0c 8b 
>07 07 22 07 02 87 ea 6c e6 1f a1 74 a8 ca 19 75 52 f0 b1 25 0c 23 05 11 96 dc 8a 44 79 ee 00 44 38 93 a5 dc a5 f3 5f 
<10 08 01 07 09 1c 
what seems to be happening is that the roomba simply can't keep up with OSMO. The OSMO is transmitting data 1.5 times the rate that the roomba can accept. This could be the result of flashing the memory. Could be the result of decoding the packets. Dunno yet.

From this we can define the fields of the reply packets 08 and 09

Code: Select all

Byte 0:	Magic Byte (=0x10)
Byte 1: Reply Code (=0x08 for positive acknowledge, =0x09 for retransmit)
Byte 2: Data Field Size (=0x01)
Byte 3: Sequence Number
Byte 4: Status Field (bit 15,14 set on retransmit and bit 7 is cleared. Bit 7 is set on a positive ack.)
Byte 5: Data Field/Checksum??? (not 100% certain yet)

I'm going to rerun my parsing programs and strip the data down to its data field only starting at sequence number 02. This should be a pretty good example of what is actually being delievered. I'll do a frequency check on it after I have done this to give me a better idea of which values are truly outstanding.

greg.
Attachments
filtered.rar
Captures Filtered to handle control character (0x80)
(773.05 KiB) Downloaded 608 times
Last edited by gssincla on August 21st, 2006, 4:18 pm, edited 1 time in total.
User avatar
gssincla
Robot Addict
Posts: 111
Joined: July 19th, 2006, 3:26 pm
Location: Chicago

To the iRobot Team

Post by gssincla »

As we get closer to the interworkings of the Roomba I would like to make an open statement to any employees of iRobot who are reading this board.


If you believe that I or anyone else who is contributing to this thread is starting to get into the gray area of intellectual property laws or any other type of law that could get us sued or this board shut down I ask that you alert me now. I would not want our actions to in any way jeopardize this wonderful forum. So if you think we are getting too close, ok, that's fine.. just let me know before we go beyond the point of no return.

greg.
User avatar
gssincla
Robot Addict
Posts: 111
Joined: July 19th, 2006, 3:26 pm
Location: Chicago

Idea...

Post by gssincla »

what if the extra two bytes per flash packet aren't a checksum but rather an address? Who's to say that this thing is flashing sequentially. It'd make sense that you'd want the system to be intelligent enough to be able to selectively patch portions of memory. So what if the first two bytes of the data field or the last two bytes of the data field are the address for where this particular packet is updating?
User avatar
gssincla
Robot Addict
Posts: 111
Joined: July 19th, 2006, 3:26 pm
Location: Chicago

Post by gssincla »

EDIT: This content was removed by gssincla. Please see the post on 28 Sept 2006 for details.
Last edited by gssincla on September 28th, 2006, 3:35 pm, edited 1 time in total.
User avatar
gssincla
Robot Addict
Posts: 111
Joined: July 19th, 2006, 3:26 pm
Location: Chicago

Vigenere....

Post by gssincla »

EDIT: This content was removed by gssincla. Please see the post on 28 Sept 2006 for details.
Last edited by gssincla on September 28th, 2006, 3:33 pm, edited 1 time in total.
User avatar
gssincla
Robot Addict
Posts: 111
Joined: July 19th, 2006, 3:26 pm
Location: Chicago

VERSION ANALYSIS COMPLETED

Post by gssincla »

Ok, going to go back a few steps here and tie up a loose end... Version Packets.

In a previous post I defined the fields of the packet reply packet as

Code: Select all

Byte 0: Header (= 0x12) 
Byte 1: 2 digit Year 
Byte 2: Month 
Byte 3: Day 
Byte 4: Hour 
Byte 5: Minute 
Byte 6: ... (to be determined: probably model)
well, the answer to byte 6 is surprisingly simple... the 7th byte ("byte 6") is a checksum of bytes 0 through 5. This checksum is created by XOR'ing bytes 1->5 together. So byte 6 is defined as

Code: Select all

ChkSum = Year ^ Month ^ Day ^ Hour ^ Minute
so now the official packet definition is:

Code: Select all

Byte 0: Header (= 0x12) 
Byte 1: Year (2 digit Year)
Byte 2: Month 
Byte 3: Day 
Byte 4: Hour 
Byte 5: Minute 
Byte 6: ChkSum (XOR of Byte1->Byte 5)

Currently I'm aware of the following versions:

Scheduler Version:
2005-04-21-1834-L

Gen 1 OSMO Blue:
2005-08-11-1707-L

Gen 2 OSMO Blue:
2005-10-04-1308-L


If your roomba has another version besides those listed above, please let me know and i'll add it to the database.

greg.
User avatar
vic7767
Robot Master
Posts: 15556
Joined: January 14th, 2006, 7:31 pm
Location: Haughton Louisiana - USA

Post by vic7767 »

greg,

here's my OSMO Black/Gray Gen 2

codestick-lite 2005-10-13-1459-L

vic
User avatar
gssincla
Robot Addict
Posts: 111
Joined: July 19th, 2006, 3:26 pm
Location: Chicago

In BL or in Firmware?

Post by gssincla »

So I've been smashing my head against the wall for days now on these damned captures. Then it occurred to me to ask "are the ASCII output strings in the firmware or in the bootloader?"... We know that the bootloader does not get updated with OSMO and Scheduler firmware updates so if the ASCII strings presented to the console are different in anyway from version to version of the firmware then we can assume that we should be able to see SOME sort of ASCII string in the firmware.

I downgraded my roomba to the ver4 (scheduler version). I uploaded a schedule into the roomba via the remote, ran the diagnostics and reset the roomba. I saved this output into a text file. Then I upgraded to OSMO ver 8. I repeated the same process of captures. Finally I upgraded to OSMO ver 10. Again, I repeated the same process. I then did a string comparison between the captures looking for any significant difference that could not be contributed to "user error" or communication error. Below are my results for the ver4 and ver8 comparisons... I'm just focusing on the differences here...

from ver4
factory-test 15 int-charger-prep


factory-test 16 int-charger-on


factory-test 17 int-charger-trickle


factory-test 18 ext-charger-prep
from ver8
factory-test 15 int-charger-recovery


factory-test 16 int-charger-on


factory-test 17 int-charger-trickle


factory-test 18 ext-charger-recovery
Notice how tests 15 and 18 are different. I even highlighted the difference for you :)

This shows me that we should definitely see some ASCII strings in the data stream. Unless someone has a compelling reason why it isn't the case, I think I've proven that the stream is definitely encoded.

Now I'm still working on the decryptions. I'm trying two different methods. The first I mentioned earlier and the second I'm trying now is to look for patterns of numbers that differ by a given pattern. Since we know that "recovery" and "prep" are in the stream somewhere, we can focus on finding sequences of numbers that different by a specific sequence... (ie. r,e,c,o,v,e,r,y differ by 13, 2, -12, -7, 17, -13, -7). This last approach assumes a constant single byte key instead of a multibyte key like the first method i'm working on.

wish me luck :)
User avatar
gssincla
Robot Addict
Posts: 111
Joined: July 19th, 2006, 3:26 pm
Location: Chicago

Information Disclosure

Post by gssincla »

I did a capture of the Scheduler (ver 4) update. I found an interesting packet that might give us more information into the way the packet is structured...

This is the last flash packet sent to the Roomba (post-proceeded to remove the 0x80 control character):

Code: Select all

07 07 22 02 02 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 24 83
From this I can assume a few different things...

1) we are looking at a single byte key which could be either a shift, add, sub, negation or XOR
2) the last two bytes of the packet are either your address/offset bytes or your checksum.

As for #2, I tend to think we are looking an address of some sort because my guess is that the checksum would come from the roomba to verify to the OSMO that it recieved the correct packet. For example, if you do not send the proper reply to the OSMO from the roomba (or your roombaSim) the OSMO will resend the packet. But this is purely speculation at this point.


any thoughts on this??? anyone? Bueller? Bueller?


Also, its worth noting that the ver4 update is significantly smaller than ver8 or ver10. Almost half the size, actually. Looks like the SCI takes up a lot of space.
Attachments
Roomba-Scheduler 4.rar
Captures from Roomba-&gt;Scheduler (scheduler-rx.hex) and from Scheduler-&gt;Roomba (scheduler-tx.hex)
(455.42 KiB) Downloaded 536 times
User avatar
gssincla
Robot Addict
Posts: 111
Joined: July 19th, 2006, 3:26 pm
Location: Chicago

Cheating...

Post by gssincla »

Ok, so I'm cheating a bit, but I'm ok with that.

looks like the OSMO is not locked. The security bit on the device is not set and thus the entire flash is accessible. I'm disassembling the OSMO now.

Now I'm 100% sure I can't post the source to this device, but I will post the command sequences that can be used to unlock the OSMO upgrade packets.

I've not tried this technique on the roomba. And if all goes well, I won't. One of the founding principles of this project is that I wanted to reverse engineer the device without ever cracking the case... for a few reasons, most notibly my wife would kill me if i broke a $300 appliance "because i was curious how it worked.".... needless to say, i've had that conversation before :wink:


i'll keep you posted when i have more. should take a few days to decode. i've already found the comm routine. i'm working through the main loop right now.
User avatar
gssincla
Robot Addict
Posts: 111
Joined: July 19th, 2006, 3:26 pm
Location: Chicago

Post by gssincla »

Interesting enough, looks like these OSMOs have more than one platform in mind...

I'm still wading through the initialization code and I am to the point where the OSMO tells the world what version it is...

The OSMO uses a predefined ASCII string and picks out the pieces it wants to transmit. the string looks like this:

Code: Select all

codestick-lite   contains  image(s):: roombascoobaE128DG256
check out the fact that they list scooba in there. Also, the E128 and DG256 there too.

so I'm wondering if you could take a black OSMO and use it on a Disco or some other blue OSMO model?

Also, its funny that the scooba is listed because while it has a serial port, the configuration is a standard DIN5, not a mini DIN7. Has anyone hooked up a serial cable to the scooba?

and yes, it really is 4a CDT and i'm still screwing with this... i should be sleeping, but eh
User avatar
gssincla
Robot Addict
Posts: 111
Joined: July 19th, 2006, 3:26 pm
Location: Chicago

OSMO Comm handler

Post by gssincla »

Always one who believes that you can learn from examples, I have disassembled the comm interrupt handlers for the OSMO and I'll present that here for the group. I know this isn't exactly the firmware of the Roomba, but it gives you a good example of how it probably works since these are the same processors... also its good insight into how iRobot codes these things.

WARNING: This will be techy and boring. if this doesn't interest you, i'd skip this article

First off, lets take a look at how serial data enters and leaves the OSMO. The OSMO has a set of registers called the SCI (Serial Communications Interface) which is reponsible for standard serial communication. The only difference between this subsystem and the one on your PC is that it uses TTL levels versus RS232 levels... hence the reason we need the roo-devices from roombadevtools (Buy their stuff! these guys are very friendly.... ok, enough of my plug for this post. hehe).

When a comm event occurs, an interrupt is triggered (if it hasn't been masked.. but this is typically not the case). Depending on what interface you are looking at, there are two interrupt jump vectors

Code: Select all

seg000:0000FFD4                 fdb $FB71               ; Roomba serial interface (SCI1) comm handler vector
seg000:0000FFD6                 fdb $FC03               ; Test Point (SCI0) comm handler vector
I should point out that there are two ACTIVE comm interfaces on the OSMO... one is the standard Roomba-OSMO serial port which we all use to upgrade our roombas. The other is a set of test points (TP0, TP1 and TP2) on the PCB. These test points have a special purpose and do not transmit the same data as the Roomba interface. I haven't explored these points yet, but will later and let you know.

So focusing on the Roomba interface for now (the TP operates in the exact same fashion at this level).... once the interrupt has occurred, the vector is loaded into the PC register and execution jumps to the interrupt service routine (ISR). The code for the ISR is shown here... (with my notes)

Code: Select all

seg000:0000FB71 ; ??????????????? S U B R O U T I N E ???????????????????????????????????????
seg000:0000FB71
seg000:0000FB71 ; OSMO_RoombaCommISR:
seg000:0000FB71 ;
seg000:0000FB71 ; This function handles all of the interrupts generated
seg000:0000FB71 ; on SCI1 (the serial interface to the roomba/scooba).
seg000:0000FB71 ;
seg000:0000FB71 ; The RoombaComm subsystem contains two circular buffers
seg000:0000FB71 ; .. one for RX and one for TX. The RX buffer is 0x100
seg000:0000FB71 ; bytes long and the TX buffer is 0x200 bytes long.
seg000:0000FB71 ;
seg000:0000FB71 ; The RX/TX buffers are located at:
seg000:0000FB71 ;
seg000:0000FB71 ; RX Buffer: 0x24A0
seg000:0000FB71 ; TX Buffer: 0x229A
seg000:0000FB71 ;
seg000:0000FB71 ; Each buffer has an index and byte count.
seg000:0000FB71 ;
seg000:0000FB71 ; RX Index: 0x249C
seg000:0000FB71 ; TX Index: 0x2298
seg000:0000FB71 ;
seg000:0000FB71 ; RX Byte Count: 0x249A
seg000:0000FB71 ; TX Byte Count: 0x2294
seg000:0000FB71
seg000:0000FB71 OSMO_RoombaCommISR:
seg000:0000FB71                 leas    -6,sp           ; create temp stack
seg000:0000FB73                 ldab    SCI1SR1         ; get current value of Status Register 1
seg000:0000FB75                 clra                    ; set D = 0x00{SCI1SR1}
seg000:0000FB76                 std     4,sp            ; store value of Status Register 1 at time of ISR
seg000:0000FB76                                         ; entry to SP+4:SP+5
seg000:0000FB78                 ldab    #$20 ; ' '      ; determine if RDRF (receive data ready) int occurred
seg000:0000FB7A                 bsr     OSMO_RoombaFindCommInt ; This function will mask off the selected interrupt.
seg000:0000FB7A                                         ; The interrupt register (stored in SP+4:SP+5, precall)
seg000:0000FB7A                                         ; is masked with the register D. If the Z flag is
seg000:0000FB7A                                         ; 1 then the interrupt is cleared, else active
seg000:0000FB7C                 beq     loc_FBA4        ; nope, check next interrupt type
seg000:0000FB7E                 ldab    SCI1DRL         ; retrieve RX byte from register
seg000:0000FB80                 clra
seg000:0000FB81                 std     2,sp            ; and store at SP+2:SP+3 (SP+3 contains actual byte)
seg000:0000FB83                 ldx     iRoombaRXBufferIndex ; find current position in RX buffer
seg000:0000FB86                 ldab    3,sp
seg000:0000FB88                 stab    arrayRoombRXBuffer,x ; put the retrieved byte into the buffer at index X
seg000:0000FB88                                         ; (iRoombaRXBufferIndex)
seg000:0000FB8C                 ldy     iRoombaRXBufferCount ; increment the buffer size count
seg000:0000FB8F                 iny
seg000:0000FB90                 sty     iRoombaRXBufferCount
seg000:0000FB93                 inx                     ; move buffer index up by one
seg000:0000FB94                 stx     iRoombaRXBufferIndex
seg000:0000FB97                 clrb
seg000:0000FB98                 inca                    ; set D = 0100
seg000:0000FB99                 pshd
seg000:0000FB9A                 cpx     2,sp+           ; have we hit the end of the buffer? if not
seg000:0000FB9C                 bne     loc_FBAD        ; keep going
seg000:0000FB9E                 clra                    ; else, move indexer to head of buffer (wrap index)
seg000:0000FB9F                 std     iRoombaRXBufferIndex
seg000:0000FBA2                 bra     loc_FBAD
seg000:0000FBA4 ; ---------------------------------------------------------------------------
seg000:0000FBA4
seg000:0000FBA4 loc_FBA4:                               ; CODE XREF: OSMO_RoombaCommISR+Bj
seg000:0000FBA4                 ldab    #8              ; see if we have an OR (overrun) interrupt...
seg000:0000FBA4                                         ; this shouldn't happen unless we are being very
seg000:0000FBA4                                         ; slow grabbing data off the line
seg000:0000FBA6                 clra
seg000:0000FBA7                 bsr     OSMO_RoombaFindCommInt ; This function will mask off the selected interrupt.
seg000:0000FBA7                                         ; The interrupt register (stored in SP+4:SP+5, precall)
seg000:0000FBA7                                         ; is masked with the register D. If the Z flag is
seg000:0000FBA7                                         ; 1 then the interrupt is cleared, else active
seg000:0000FBA9                 beq     loc_FBAD        ; nope, keep going
seg000:0000FBAB                 ldab    SCI1DRL         ; yep... we missed some. just grab the byte and discard
seg000:0000FBAD
seg000:0000FBAD loc_FBAD:                               ; CODE XREF: OSMO_RoombaCommISR+2Bj
seg000:0000FBAD                                         ; OSMO_RoombaCommISR+31j ...
seg000:0000FBAD                 ldab    #$80            ; see if we have a TX Register Empty (TX Ready) interrupt
seg000:0000FBAF                 clra
seg000:0000FBB0                 bsr     OSMO_RoombaFindCommInt ; This function will mask off the selected interrupt.
seg000:0000FBB0                                         ; The interrupt register (stored in SP+4:SP+5, precall)
seg000:0000FBB0                                         ; is masked with the register D. If the Z flag is
seg000:0000FBB0                                         ; 1 then the interrupt is cleared, else active
seg000:0000FBB2                 beq     loc_FBEF        ; nope, so end ISR
seg000:0000FBB4                 ldd     iRoombaTXBufferCount ; see if we have any more bytes to transmit
seg000:0000FBB7                 clr     1,sp
seg000:0000FBB9                 clr     ,sp
seg000:0000FBBB                 cpd     ,sp             ; iRoombaTXBufferCount == 0?
seg000:0000FBBD                 bne     loc_FBC8        ; nope... so lets clean house and end ISR
seg000:0000FBBF                 clrb                    ; set D = 0
seg000:0000FBC0                 clra
seg000:0000FBC1                 std     2,sp
seg000:0000FBC3                 bclr    SCI1CR2, #$80   ; turn off TDRE interrupts until futher notice
seg000:0000FBC6                 bra     loc_FBF3        ; end ISR
seg000:0000FBC8 ; ---------------------------------------------------------------------------
seg000:0000FBC8
seg000:0000FBC8 loc_FBC8:                               ; CODE XREF: OSMO_RoombaCommISR+4Cj
seg000:0000FBC8                 ldx     iRoombaTXBufferIndex ; get current index into TX buffer
seg000:0000FBCB                 ldab    arrayRoombTXBuffer,x ; get next byte to transmit
seg000:0000FBCF                 clra
seg000:0000FBD0                 std     2,sp            ; store byte in temp space
seg000:0000FBD2                 ldy     iRoombaTXBufferCount ; decrement byte count
seg000:0000FBD5                 dey
seg000:0000FBD6                 sty     iRoombaTXBufferCount
seg000:0000FBD9                 inx
seg000:0000FBDA                 stx     iRoombaTXBufferIndex ; increment buffer index
seg000:0000FBDD                 ldaa    #2
seg000:0000FBDF                 clrb
seg000:0000FBE0                 pshd
seg000:0000FBE1                 cpx     2,sp+           ; index = 0x200?
seg000:0000FBE3                 bne     loc_FBE9
seg000:0000FBE5                 clra                    ; yes, wrap index to head of buffer
seg000:0000FBE6                 std     iRoombaTXBufferIndex
seg000:0000FBE9
seg000:0000FBE9 loc_FBE9:                               ; CODE XREF: OSMO_RoombaCommISR+72j
seg000:0000FBE9                 ldab    3,sp            ; transmit byte (stored in SP+3)
seg000:0000FBEB                 stab    SCI1DRL
seg000:0000FBED                 bra     loc_FBF3
seg000:0000FBEF ; ---------------------------------------------------------------------------
seg000:0000FBEF
seg000:0000FBEF loc_FBEF:                               ; CODE XREF: OSMO_RoombaCommISR+41j
seg000:0000FBEF                 clrb
seg000:0000FBF0                 clra
seg000:0000FBF1                 std     2,sp            ; clear out temp value
seg000:0000FBF3
seg000:0000FBF3 loc_FBF3:                               ; CODE XREF: OSMO_RoombaCommISR+55j
seg000:0000FBF3                                         ; OSMO_RoombaCommISR+7Cj
seg000:0000FBF3                 ldd     2,sp
seg000:0000FBF5                 leas    6,sp            ; reset sp to original position
seg000:0000FBF7                 rti                     ; go home
seg000:0000FBF7 ; End of function OSMO_RoombaCommISR
seg000:0000FBF7
seg000:0000FBF8
seg000:0000FBF8 ; ??????????????? S U B R O U T I N E ???????????????????????????????????????
seg000:0000FBF8
seg000:0000FBF8 ; This function will mask off the selected interrupt.
seg000:0000FBF8 ; The interrupt register (stored in SP+4:SP+5, precall)
seg000:0000FBF8 ; is masked with the register D. If the Z flag is
seg000:0000FBF8 ; 1 then the interrupt is cleared, else active
seg000:0000FBF8
seg000:0000FBF8 OSMO_RoombaFindCommInt:                 ; CODE XREF: OSMO_RoombaCommISR+9p
seg000:0000FBF8                                         ; OSMO_RoombaCommISR+36p ...
seg000:0000FBF8                 andb    7,sp
seg000:0000FBFA                 anda    6,sp
seg000:0000FBFC                 clr     3,sp
seg000:0000FBFE                 clr     2,sp
seg000:0000FC00                 cpd     2,sp
seg000:0000FC02                 rts
seg000:0000FC02 ; End of function OSMO_RoombaFindCommInt
seg000:0000FC02
As you can see there are two circular buffers .. one for the TX and RX. Strangely the transmission buffer is twice the size of the receiver buffer.

Remember when I was speculating that I thought the comm system on the roomba was interrupt driven, well I think I can safely say this is the case.

Assume for a moment that the roomba comm system is exactly the same as it is for the OSMO (which is probably not the case since the roomba has an interrupt for the DD line and the OSMO does not). Then we can now see how the roomba is handling comm events. They get buffered until they are either overwritten in the buffer or pulled off the buffer.

Now, notice how there is no boundary checking for the byte counter. In theory if you sent 0xffff bytes to it before it could read them off the buffer, you'd have the system reading the same data 0xff times. not really important, but interesting that they didnt do bound checking... especially when dealing with flashing.
User avatar
gssincla
Robot Addict
Posts: 111
Joined: July 19th, 2006, 3:26 pm
Location: Chicago

OSMO Comm Traffic, part 2: How to send serial data out

Post by gssincla »

So now that we know how the comm traffic is handled via the ISR, lets look at how data is actually transmitted from the OSMO to its serial interfaces.


The OSMO provides 7 communication modes for transmitting data. Of these modes, 4 are distinct. In a nutshell the modes are a combination of which serial port to transmit through and if the transmission is buffered or sent immediately.

I've identified what appears to be the primary transmission routine which I've labeled OSMO_TransmitDataByte. The code for this is as follows

Code: Select all

seg000:0000C9BA OSMO_TransmitDataByte:                  ; CODE XREF: CalculateValuetoDecimalandTX+66p
seg000:0000C9BA                                         ; OSMO_TransmitASCIIString+20p ...
seg000:0000C9BA                 std     6,-sp
seg000:0000C9BC                 jsr     sub_C9F7        ; this doesnt actually return anything
seg000:0000C9BF                 ldd     ,sp
seg000:0000C9C1                 jsr     TX_OutputPortSelector
seg000:0000C9C4                 std     4,sp            ; store output port (0 or 1) in SP+4:SP+5
seg000:0000C9C6                 ldd     ,sp
seg000:0000C9C8                 jsr     TX_SelecttBufferOrImmMode
seg000:0000C9CB                 tbeq    d, loc_C9D0
seg000:0000C9CE                 clrb
seg000:0000C9CF                 skip2
seg000:0000C9D0
seg000:0000C9D0 loc_C9D0:                               ; CODE XREF: OSMO_TransmitDataByte+11j
seg000:0000C9D0                 ldab    #1
seg000:0000C9D2                 clra
seg000:0000C9D3                 tbne    d, loc_C9E0
seg000:0000C9D6                 ldd     4,sp            ; port to use (TP or roomba/DIN7)
seg000:0000C9D8                 pshd
seg000:0000C9D9                 ldd     $A,sp
seg000:0000C9DB                 jsr     OSMO_SendByteToTXBuffer
seg000:0000C9DE                 bra     loc_C9E8
seg000:0000C9E0 ; ---------------------------------------------------------------------------
seg000:0000C9E0
seg000:0000C9E0 loc_C9E0:                               ; CODE XREF: OSMO_TransmitDataByte+19j
seg000:0000C9E0                 ldd     4,sp
seg000:0000C9E2                 pshd
seg000:0000C9E3                 ldd     $A,sp           ; D = byte to transmit
seg000:0000C9E5                 jsr     OSMO_TXByteImmediately
seg000:0000C9E8
seg000:0000C9E8 loc_C9E8:                               ; CODE XREF: OSMO_TransmitDataByte+24j
seg000:0000C9E8                 leas    2,sp
seg000:0000C9EA                 std     2,sp
seg000:0000C9EC                 leas    6,sp
seg000:0000C9EE                 rts
seg000:0000C9EE ; End of function OSMO_TransmitDataByte
The subroutine is called by pushing the byte to send onto the stack at positions SP+2:SP+3 (where only SP+3 is actually used... iRobot does a lot of 16 bit operations when only 8 bits are needed). When called the D register selects the communication mode to be used. The table below details each communication mode for the TX subsystem.

Code: Select all

MODE  TxMode  Port
  0      1     0     Buffer byte to TP 
  1      1     0     Buffer byte to TP 
  2      0     0     Transmit byte to TP immediately
  3      0     0     Transmit byte to TP immediately
  4      1     0     Buffer byte to TP 
  5      0     1     Transmit byte to Roomba immediately
  6      1     1     Buffer byte to Roomba 
(EDIT: Had TxMode description backwards)

In this case when TxMode is set to 1 the byte being sent is buffered into the circular buffer detailed in the previous post. If TxMode is set to 0, the byte is immediately transmitted. The Port number corresponds to the SCI port being used (0 for TP, 1 for Roomba/OSMO serial port).


EDIT: You'll see later on that the above mode table is used in a similar fashion for the RX side of the communication subsystem. Instead of using the TX buffers or ports, they use the RX buffers and ports



I find it interesting that iRobot originally called their open interface SCI since this is the exact name of the port on the processor.


Example time....

Lets say you wanted to send the byte 0x08 to the Roomba immediately. the code to do this would look like

Code: Select all

LDAB #08
CLRA
PUSD
LDAB #05
JSR OSMO_TransmitDataByte
What happened here is that LDAB ("load accumulator B") sets the lower byte of D (16bit) to the desired value while CLRA ("clear accumulator A") clears the upper byte of D. This is then pushed to the stack (via "PUSD" or "push D"). Then the next LDAB opcode loads the mode (mode 5). Since A is still 0, D is now equal to 0x0005 and finally the subroutine is called via JSR ("jump to subroutine")

and thats now data is transmitted.

greg.

PS. If people want, I can continue to detail these subsystems as I learn then... let me know if this is of interest to anyone.

EDIT: modified mode table to add descriptions
Last edited by gssincla on August 31st, 2006, 1:42 am, edited 2 times in total.
User avatar
vic7767
Robot Master
Posts: 15556
Joined: January 14th, 2006, 7:31 pm
Location: Haughton Louisiana - USA

Post by vic7767 »

Greg,

great work on the comm machine code. By the way, I've tried inserting my Black OSMO on a couple of Blue OSMO roombas to no avail.. Of course this was before I had the knowledge or the ability to monitor the SCI comm port. It will be interesting to see what messages are exchanged when a non compatible OSMO is inserted into the roomba SCI.
User avatar
gssincla
Robot Addict
Posts: 111
Joined: July 19th, 2006, 3:26 pm
Location: Chicago

For Howard

Post by gssincla »

I found this subroutine and wanted to post it as a "thank you" to Howard.... This subroutine is used to send data to the Roomba from the OSMO but takes into consideration the 0x80, 0x10 and 0x07 values. These values get XOR'd and split into two values. I'm assuming there is a complimentary function somewhere... i'll find it later on i'm sure.

Code: Select all

seg000:0000D76F ; Sends the value in B to Roomba in Mode 6
seg000:0000D76F ; (send immediately). If the value to be sent is
seg000:0000D76F ; 0x80, 0x10 or 0x07, the value is XOR'd with 0x80
seg000:0000D76F ; and sent as 0x80 <XOR of Value>
seg000:0000D76F
seg000:0000D76F OSMO_SendByteToRoombaWithCtrlChar:      ; CODE XREF: sub_D677+66p
seg000:0000D76F                                         ; sub_D677+77p ...
seg000:0000D76F                 std     8,-sp
seg000:0000D771                 ldx     #$80
seg000:0000D774                 pshx
seg000:0000D775                 cpd     2,sp+
seg000:0000D777                 beq     loc_D77B
seg000:0000D779                 clrb
seg000:0000D77A                 skip2
seg000:0000D77B
seg000:0000D77B loc_D77B:                               ; CODE XREF: OSMO_SendByteToRoombaWithCtrlChar+8j
seg000:0000D77B                 ldab    #1
seg000:0000D77D                 clra
seg000:0000D77E                 std     2,sp
seg000:0000D780                 beq     loc_D784
seg000:0000D782                 bra     loc_D7A9
seg000:0000D784 ; ---------------------------------------------------------------------------
seg000:0000D784
seg000:0000D784 loc_D784:                               ; CODE XREF: OSMO_SendByteToRoombaWithCtrlChar+11j
seg000:0000D784                 ldd     ,sp
seg000:0000D786                 leax    -$70,x
seg000:0000D789                 pshx
seg000:0000D78A                 cpd     2,sp+
seg000:0000D78C                 beq     loc_D790
seg000:0000D78E                 clrb
seg000:0000D78F                 skip2
seg000:0000D790
seg000:0000D790 loc_D790:                               ; CODE XREF: OSMO_SendByteToRoombaWithCtrlChar+1Dj
seg000:0000D790                 ldab    #1
seg000:0000D792                 clra
seg000:0000D793                 std     4,sp
seg000:0000D795                 beq     loc_D799
seg000:0000D797                 bra     loc_D7A7
seg000:0000D799 ; ---------------------------------------------------------------------------
seg000:0000D799
seg000:0000D799 loc_D799:                               ; CODE XREF: OSMO_SendByteToRoombaWithCtrlChar+26j
seg000:0000D799                 ldd     ,sp
seg000:0000D79B                 leax    -9,x
seg000:0000D79D                 pshx
seg000:0000D79E                 cpd     2,sp+
seg000:0000D7A0                 beq     loc_D7A4
seg000:0000D7A2                 clrb
seg000:0000D7A3                 skip2
seg000:0000D7A4
seg000:0000D7A4 loc_D7A4:                               ; CODE XREF: OSMO_SendByteToRoombaWithCtrlChar+31j
seg000:0000D7A4                 ldab    #1
seg000:0000D7A6                 clra
seg000:0000D7A7
seg000:0000D7A7 loc_D7A7:                               ; CODE XREF: OSMO_SendByteToRoombaWithCtrlChar+28j
seg000:0000D7A7                 std     6,sp
seg000:0000D7A9
seg000:0000D7A9 loc_D7A9:                               ; CODE XREF: OSMO_SendByteToRoombaWithCtrlChar+13j
seg000:0000D7A9                 std     4,sp
seg000:0000D7AB                 beq     loc_D7C3
seg000:0000D7AD                 ldab    #$80
seg000:0000D7AF                 clra
seg000:0000D7B0                 pshd
seg000:0000D7B1                 ldab    #6
seg000:0000D7B3                 jsr     OSMO_TransmitDataByte ; D = mode value
seg000:0000D7B3                                         ;
seg000:0000D7B3                                         ; calling SP+2:SP+3(before jsr) = offset of byte to
seg000:0000D7B3                                         ; transmit from ASCII set
seg000:0000D7B6                 ldd     2,+sp
seg000:0000D7B8                 std     2,sp
seg000:0000D7BA                 ldab    3,sp
seg000:0000D7BC                 eorb    #$80
seg000:0000D7BE                 stab    3,sp
seg000:0000D7C0                 ldd     2,sp
seg000:0000D7C2                 skip2
seg000:0000D7C3
seg000:0000D7C3 loc_D7C3:                               ; CODE XREF: OSMO_SendByteToRoombaWithCtrlChar+3Cj
seg000:0000D7C3                 ldd     ,sp
seg000:0000D7C5                 pshd
seg000:0000D7C6                 ldab    #6
seg000:0000D7C8                 clra
seg000:0000D7C9                 jsr     OSMO_TransmitDataByte ; D = mode value
seg000:0000D7C9                                         ;
seg000:0000D7C9                                         ; calling SP+2:SP+3(before jsr) = offset of byte to
seg000:0000D7C9                                         ; transmit from ASCII set
seg000:0000D7CC                 leas    2,sp
seg000:0000D7CE                 std     2,sp
seg000:0000D7D0                 leas    8,sp
seg000:0000D7D2                 rts
seg000:0000D7D2 ; End of function OSMO_SendByteToRoombaWithCtrlChar
User avatar
gssincla
Robot Addict
Posts: 111
Joined: July 19th, 2006, 3:26 pm
Location: Chicago

Holy Crap Batman! (Encryption algorithm)

Post by gssincla »

Ok... I'm not 100% certain on this yet, but I think I found the encoding scheme for packet transmission from the OSMO... and let me just say "damn thats nasty"


It looks like it uses a block cipher.. while a computationally simple cipher, i think it would have taken me months to crack (i'm only so-so at cipher cracking... and that's be kind to myself)


The encryption algorithm is depended on a predefined hash table of 16 words (32 bytes). Before any encoding can be done, the hash table is checked to make sure it's been initialized. The initialization routine for the Hash Table works like this (this is my pseudo-code in C)

Code: Select all

void InitializeHashTable(void)
{

 unsigned char var8_msb;
 unsigned char var8_lsb;
 unsigned char var4_msb;
 unsigned char var4_lsb;
 unsigned char var0_msb;
 unsigned char var0_lsb;
  
 for (unsigned int pos=0; pos < 16; pos++) 
 { 
   var4_lsb = pos; 
   var4_msb = pos;
   var0_msb = 0; 
   var0_lsb = 0;

   for (unsigned int indexer = 0; indexer < 4; indexer++) 
   {
	   unsigned int itmp = 0;
	   unsigned char btmp = 0;

	   var8_msb = var0_msb;
	   var8_lsb = var0_lsb;

	   if (var0_msb & 0x01)
	   {
		   // there is a carry involved
			var0_msb = var0_msb >> 1;
			var0_lsb = (var0_lsb >> 1) | 0x80;	// add the carry from MSB
	   }
	   else
	   {
		   var0_msb = var0_msb >> 1;
		   var0_lsb = var0_lsb >> 1;
	   }

	   if ((var4_lsb & 0x01) != (var8_lsb & 0x01))
	   {
		   var0_msb = var0_msb ^ 0x80;
		   var0_lsb = var0_lsb ^ 0x05;
	   }

	   if (var4_msb & 0x01)
	   {
		   // there is a carry involved
			var4_msb = var4_msb >> 1;
			var4_lsb = (var4_lsb >> 1) | 0x80;	// add the carry from MSB
	   }
	   else
	   {
		   var4_msb = var4_msb >> 1;
		   var4_lsb = var4_lsb >> 1;
	   }

    } 


  } 

  HashTable[pos*2] = var0_msb;
  HashTable[(pos*2)+1] = var0_lsb;
}
The table comes out to be (if i did this right)

Code: Select all

0000 7003 e006 9005 
c007 b004 2001 5002 
8005 f006 6003 1000 
4002 3001 a004 d007
once the table is initialized, things get fun! ...

The hashing algorithm seems to be some sort of block cipher... what this means is that if you think of the cipher as a black box where you input into the box the plaintext and a key, you are given an encoded output. Now, this box is then fed into a second black box to produce another output. In our case we repeat the black box twice.. fortunately they are the same black box!

Again, examples are better than paragraphs...here's the pseudo-code of the encoding algorithm...

Code: Select all

// d = D register on call, s = Stack Value on call
unsigned int encode(unsigned int d, unsigned int s)
{
	unsigned char d_lsb;
	unsigned char d_msb;
	unsigned char s_lsb;
	unsigned char s_msb;

	for (unsigned int x = 0; x < 2; x++)
	{
		unsigned char b;
		unsigned char a;
		unsigned int tmpD;
		unsigned int y;

		d_lsb = (unsigned char)(d & 0x00FF);
		d_msb = (unsigned char)((d & 0xFF00) >> 8);

		s_lsb = (unsigned char)(s & 0x00FF);
		s_msb = (unsigned char)((s & 0xFF00) >> 8);


		tmpD = (unsigned int)((d_lsb ^ s_lsb) & 0x0F) << 1;


		b = HashTable[tmpD+1];
		a = HashTable[tmpD];
	
		s = (s >> 4) ^ ((a*0x100) + b);
		d = d >> 4;
	}

	return s;
}
EDIT: Changed out code. Fixed programming error.

now i'm not exactly sure if D is your plaintext value or if the value pushed on the stack is your plaintext value. looking at the code i'm going to say that d is probably the seed and s is probably your plaintext. i'm still disassembling, so i'll let you know more when i know more.

EDIT: remove "symmetric encoding" guess... this is obviously a hash and not encoding.


For an example, I've taken the above code and run it through 32 sequential values... this was done twice.. once holding d constant and once holding s constant. Here's the output

Code: Select all

value in  (0000, 5555). Out 7b56
value in  (0001, 5555). Out ec53
value in  (0002, 5555). Out 5557
value in  (0003, 5555). Out c252
value in  (0004, 5555). Out 2754
value in  (0005, 5555). Out b051
value in  (0006, 5555). Out 0955
value in  (0007, 5555). Out 9e50
value in  (0008, 5555). Out c352
value in  (0009, 5555). Out 5457
value in  (000a, 5555). Out ed53
value in  (000b, 5555). Out 7a56
value in  (000c, 5555). Out 9f50
value in  (000d, 5555). Out 0855
value in  (000e, 5555). Out b151
value in  (000f, 5555). Out 2654
value in  (0010, 5555). Out 0b55
value in  (0011, 5555). Out 9c50
value in  (0012, 5555). Out 2554
value in  (0013, 5555). Out b251
value in  (0014, 5555). Out 5757
value in  (0015, 5555). Out c052
value in  (0016, 5555). Out 7956
value in  (0017, 5555). Out ee53
value in  (0018, 5555). Out b351
value in  (0019, 5555). Out 2454
value in  (001a, 5555). Out 9d50
value in  (001b, 5555). Out 0a55
value in  (001c, 5555). Out ef53
value in  (001d, 5555). Out 7856
value in  (001e, 5555). Out c152
value in  (001f, 5555). Out 5657
value in  (5555, 0000). Out 7b03
value in  (5555, 0001). Out ec06
value in  (5555, 0002). Out 5502
value in  (5555, 0003). Out c207
value in  (5555, 0004). Out 2701
value in  (5555, 0005). Out b004
value in  (5555, 0006). Out 0900
value in  (5555, 0007). Out 9e05
value in  (5555, 0008). Out c307
value in  (5555, 0009). Out 5402
value in  (5555, 000a). Out ed06
value in  (5555, 000b). Out 7a03
value in  (5555, 000c). Out 9f05
value in  (5555, 000d). Out 0800
value in  (5555, 000e). Out b104
value in  (5555, 000f). Out 2601
value in  (5555, 0010). Out 0b00
value in  (5555, 0011). Out 9c05
value in  (5555, 0012). Out 2501
value in  (5555, 0013). Out b204
value in  (5555, 0014). Out 5702
value in  (5555, 0015). Out c007
value in  (5555, 0016). Out 7903
value in  (5555, 0017). Out ee06
value in  (5555, 0018). Out b304
value in  (5555, 0019). Out 2401
value in  (5555, 001a). Out 9d05
value in  (5555, 001b). Out 0a00
value in  (5555, 001c). Out ef06
value in  (5555, 001d). Out 7803
value in  (5555, 001e). Out c107
value in  (5555, 001f). Out 5602
EDIT: removed paragraph about 16 cycle repeats. I had a programming error that caused that.

anyway, enjoy.. let me know what you think, etc, etc.


TO THE iROBOT PEOPLE READING THIS: Seriously, let me know if i'm publishing too much information here. I do not want to step on any toes or get anyone into trouble... mainly me, i dont want to get me in trouble.


EDIT: Doing further disassembly reveals that this encodes the checksum. Not the full packet. What worries me is that Packet 0x07's data field isn't encoded by the OSMO meaning that it's encoded beforehand which would suck!
Last edited by gssincla on September 8th, 2006, 8:26 pm, edited 1 time in total.
User avatar
gssincla
Robot Addict
Posts: 111
Joined: July 19th, 2006, 3:26 pm
Location: Chicago

How packets are born...

Post by gssincla »

Ok, here's the pseudo-code for how packets are sent.

As you can see, the official packet format is as follows:

Code: Select all

Byte0: magic byte (0x07)
Byte1: cmdID byte
Byte2: data field length (may be 0)
Byte3 -> (n+2): data field IF data field length > 0
Byte(n+3): LSB of packet HASH
Byte(n+4): MSB of packet HASH
If the packet length is greater than 0xFF this seems to cause an error packet to be sent to the test pad port (TPx or SCI0). Also, it looks like the system is keeping a running count on the number of packets it transmits.

Let me know if you have any questions about how this works. As for now, its 2:20a and I have to work tomorrow morning so I'm crashing for a few hours.

greg.

Code: Select all

void OSMO_SendCmdPacketToRoomba(unsigned int cmdID)
{

	unsigned int seed = 0x5555;  // initialized value
	
	if (iPacketLength > 0xFF)
	{
		unsigned int tmpPktLen = iPacketLengh - 0xF9;
		
		OSMO_TransmitDataByte(0x06, MODE_1);
		OSMO_Send00ToTPImmediately();
		OSMO_SendByteToTPImmediately_002(0x04);
		OSMO_TransmitDataByte(word_2252, MODE_0);
		OSMO_TransmitDataByte(MSB(word_2252), MODE_0);
		OSMO_SendByteToTPImmediately_002(0x06);
		OSMO_SendByteToTPImmediately_002(0x01);
		OSMO_SendByteToTPImmediately_002(0x04);
		OSMO_SendByteToTPImmediately_002(0xFF);
		OSMO_Send00ToTPImmediately(0x00);
		OSMO_SendByteToTPImmediately_002(0x21);
	}
		
	OSMO_TransmitDataByte(0x07, MODE_6);
	
	OSMO_SendByteToRoombaWithCtrlChar(cmdID);
	seed = OSMO_HashWord(cmdID, seed);
	
	OSMO_SendByteToRoombaWithCtrlChar(iPacketLength);
	seed = OSMO_HashWord(iPacketLength, seed);
	
	if (iPacketLength)
	{
		for (unsigned int i = 0; i < iPacketLength - 1; i++)
		{
			unsigned char dataByte = arrayPacketDataBuffer[i];
			
			OSMO_SendByteToRoombaWithCtrlChar(dataByte);
			seed = OSMO_HashWord(dataByte, seed);
		}
	}
	
	// remember seed is the running hash in this configuration
	OSMO_SendByteToRoombaWithCtrlChar(LSB(seed));
	OSMO_SendByteToRoombaWithCtrlChar(MSB(seed));
	
	iPacketsSent++;	// increase the global packet count
}
User avatar
gssincla
Robot Addict
Posts: 111
Joined: July 19th, 2006, 3:26 pm
Location: Chicago

Cmd07: Pseudo-Analysis

Post by gssincla »

Well, its been a few days and I didnt want my loyal readers to think I was sleeping on the job :wink: So here's the actual code used to transmit the Cmd07 packets. I've commented a good bit of it.

Code: Select all

seg000:0000D56E ; ??????????????? S U B R O U T I N E ???????????????????????????????????????
seg000:0000D56E
seg000:0000D56E ; Upon entry D specifies the packet sequence number.
seg000:0000D56E ; the sequence number also determines the size of the
seg000:0000D56E ; packet as packets 0 and 1 are 0x08 bytes long while
seg000:0000D56E ; all other packets are 0x20 bytes long (plus the
seg000:0000D56E ; 2 bytes for the seq num and subCmd)
seg000:0000D56E
seg000:0000D56E OSMO_SendCmd07:                         ; CODE XREF: sub_D1A1+221p
seg000:0000D56E                                         ; sub_D1A1+290p
seg000:0000D56E                 leas    -$A,sp
seg000:0000D570                 pshd                    ; save original packet sequence number at call time to var0
seg000:0000D571                 jsr     OSMO_DetermineCmd07PktLength
seg000:0000D574                 std     $A,sp           ; set varA to packet length for data segment of Cmd07
seg000:0000D576                 addd    #2              ; add space for sequence number and subcommand ID
seg000:0000D579                 std     iPacketLength   ; save full data field length to variable
seg000:0000D57C                 ldd     ,sp             ; store Cmd 07 sequence number to var2
seg000:0000D57E                 std     2,sp
seg000:0000D580                 ldab    3,sp            ; get LSB of seq num
seg000:0000D582                 stab    arrayPacketDataBuffer ; put the value in the first position of the packet's data field
seg000:0000D585                 ldd     2,sp
seg000:0000D587                 jsr     OSMO_Cmd07DetermineSubcommand ; Sets byte 1 of the Cmd 07 data field equal to the following
seg000:0000D587                                         ; 0 - if seq num = 0x0000
seg000:0000D587                                         ; 1 - if seq num = 0x0001
seg000:0000D587                                         ; 2 - if seq num greater than 0x0001
seg000:0000D58A                 std     2,sp            ; var2 set to subcommand ID
seg000:0000D58C                 ldab    3,sp
seg000:0000D58E                 stab    arrayPacketDataBuffer+1 ; store in packet's data buffer at second position
seg000:0000D591                 ldd     ,sp
seg000:0000D593                 jsr     OSMO_CalcFlashImageMemOffset ; Calculates memory displacement for Firmware image
seg000:0000D593                                         ; based on sequence number
seg000:0000D596                 std     iFlashImageMemOffset ; store output in RAM variable
seg000:0000D599                 ldd     ,sp
seg000:0000D59B                 jsr     OSMO_CalcFlashImageParagraph ; Calculates the paragraph number for the current
seg000:0000D59B                                         ; seq num. Paragraphs are 256bytes. Calculation is:
seg000:0000D59B                                         ;
seg000:0000D59B                                         ; paragraph = (seqNum - 2)/256
seg000:0000D59E                 std     iFlashImageParagraph ; store output in RAM variable
seg000:0000D5A1                 clrb
seg000:0000D5A2                 clra
seg000:0000D5A3                 std     2,sp            ; clear var2
seg000:0000D5A5
seg000:0000D5A5 loc_D5A5:                               ; CODE XREF: OSMO_SendCmd07+94j
seg000:0000D5A5                 ldd     $A,sp
seg000:0000D5A7                 ldx     #2
seg000:0000D5AA                 idivs
seg000:0000D5AC                 ldy     2,sp
seg000:0000D5AE                 dex
seg000:0000D5AF                 pshx
seg000:0000D5B0                 cpy     2,sp+
seg000:0000D5B2                 bhi     loc_D604
seg000:0000D5B4                 ldd     iCmd07FlashAddrAdjustIndex
seg000:0000D5B7                 pshd
seg000:0000D5B8                 ldd     iFlashImageParagraph
seg000:0000D5BB                 pshd
seg000:0000D5BC                 ldd     iFlashImageMemOffset
seg000:0000D5BF                 jsr     OSMO_GetFirmwareWordFromFlash
seg000:0000D5C2                 leas    4,sp            ; clean up stack
seg000:0000D5C4                 tfr     d, y
seg000:0000D5C6                 exg     a, d
seg000:0000D5C8                 std     8,sp
seg000:0000D5CA                 bsr     sub_D60D
seg000:0000D5CC                 ldab    #2
seg000:0000D5CE                 clra
seg000:0000D5CF                 addd    4,sp
seg000:0000D5D1                 std     6,sp
seg000:0000D5D3                 ldab    7,sp
seg000:0000D5D5                 ldaa    9,sp
seg000:0000D5D7                 ldx     #arrayPacketDataBuffer
seg000:0000D5DA                 staa    b,x
seg000:0000D5DC                 sty     8,sp
seg000:0000D5DE                 bsr     sub_D60D
seg000:0000D5E0                 ldab    #2
seg000:0000D5E2                 clra
seg000:0000D5E3                 addd    4,sp
seg000:0000D5E5                 addd    #1
seg000:0000D5E8                 std     6,sp
seg000:0000D5EA                 ldab    7,sp
seg000:0000D5EC                 ldaa    9,sp
seg000:0000D5EE                 staa    b,x
seg000:0000D5F0                 ldd     #iFlashImageMemOffset
seg000:0000D5F3                 pshd
seg000:0000D5F4                 ldab    #2              ; D = 0x0002
seg000:0000D5F6                 clra
seg000:0000D5F7                 sex     a, x            ; X = 0x0000
seg000:0000D5F9                 jsr     sub_C3B8
seg000:0000D5FC                 pulx
seg000:0000D5FD                 ldx     2,sp
seg000:0000D5FF                 inx
seg000:0000D600                 stx     2,sp
seg000:0000D602                 bra     loc_D5A5
seg000:0000D604 ; ---------------------------------------------------------------------------
seg000:0000D604
seg000:0000D604 loc_D604:                               ; CODE XREF: OSMO_SendCmd07+44j
seg000:0000D604                 ldab    #7
seg000:0000D606                 clra
seg000:0000D607                 jsr     OSMO_SendCmdPacketToRoomba ; D = PacketID a.k.a Command Number
seg000:0000D607                                         ; (NOT sequence number)
seg000:0000D60A                 leas    $C,sp
seg000:0000D60C                 rts
seg000:0000D60C ; End of function OSMO_SendCmd07
seg000:0000D60C
seg000:0000D60D
seg000:0000D60D ; ??????????????? S U B R O U T I N E ???????????????????????????????????????
seg000:0000D60D
seg000:0000D60D
seg000:0000D60D sub_D60D:                               ; CODE XREF: OSMO_SendCmd07+5Cp
seg000:0000D60D                                         ; OSMO_SendCmd07+70p
seg000:0000D60D                 ldd     4,sp
seg000:0000D60F                 std     6,sp
seg000:0000D611                 lsl     7,sp
seg000:0000D613                 rol     6,sp
seg000:0000D615                 rts
seg000:0000D615 ; End of function sub_D60D
seg000:0000D615


seg000:0000C3B8 sub_C3B8:                               ; CODE XREF: OSMO_SendCmd07+8Bp
seg000:0000C3B8                 leas    -8,sp
seg000:0000C3BA                 pshd
seg000:0000C3BB                 pshx                    ; STACK:
seg000:0000C3BB                                         ; F  iFlashMemoryOffset Addr- MSB
seg000:0000C3BB                                         ; E  iFlashMemoryOffset Addr- LSB
seg000:0000C3BB                                         ; D  -- return PC (RTS)
seg000:0000C3BB                                         ; C  -- return PC (RTS)
seg000:0000C3BB                                         ; B  varA - MSB
seg000:0000C3BB                                         ; A  varA - LSB
seg000:0000C3BB                                         ; 9  var8 - MSB
seg000:0000C3BB                                         ; 8  var8 - LSB
seg000:0000C3BB                                         ; 7  var6 - MSB
seg000:0000C3BB                                         ; 6  var6 - LSB
seg000:0000C3BB                                         ; 5  var4 - MSB
seg000:0000C3BB                                         ; 4  var4 - LSB
seg000:0000C3BB                                         ; 3  o_D - MSB
seg000:0000C3BB                                         ; 2  o_D - LSB
seg000:0000C3BB                                         ; 1  o_X - MSB
seg000:0000C3BB                                         ; 0  o_X - LSB

seg000:0000C3BC                 ldx     $E,sp           ; X = iFlashMemoryOffset
seg000:0000C3BE                 ldd     ,x              ; D = iFlashMemoryOffset[0]
seg000:0000C3C0                 std     6,sp            ; var6 = iFlashMemoryOffset[0]
seg000:0000C3C2                 clrb
seg000:0000C3C3                 clra                    ; D = 0
seg000:0000C3C4                 std     4,sp            ; var4 = 0
seg000:0000C3C6                 ldd     2,x             ; D = iFlashMemoryOffset[2]
seg000:0000C3C8                 jsr     OSMO_IsMSbOfASet ; IsMSBofASet: returns 0xFFFF is bit7 of A is set, else
seg000:0000C3C8                                         ; returns 0x0000 if bit 7 of A is cleared
seg000:0000C3CB                 ldy     #0              ; y = 0
seg000:0000C3CE                 xgdy                    ; Y <==> D
seg000:0000C3D0                 addd    6,sp            ; CF = 0
seg000:0000C3D2                 std     6,sp            ; var6 = Y = var6
seg000:0000C3D4                 xgdy                    ; ***D back to D, Y back to Y
seg000:0000C3D6                 adcb    5,sp
seg000:0000C3D8                 adca    4,sp            ; D = var4 + iFlashMemoryOffset[2]
seg000:0000C3DA                 std     4,sp            ; var4 = D = var4 + iFlashMemoryOffset[2]
seg000:0000C3DC                 xgdy                    ; Y <==> D
seg000:0000C3DE                 addd    2,sp            ; Y = var6 + o_D
seg000:0000C3E0                 std     $A,sp           ; varA = var6 + o_d
seg000:0000C3E0                                         ; --- CF = 1 IF (MSb(var6) & MSb(o_d)) or
seg000:0000C3E0                                         ;               (MSb(var6) or MSb(o_d)) & !(MSb(result))
seg000:0000C3E2                 xgdy                    ; ***D back to D, Y back to Y
seg000:0000C3E4                 adcb    1,sp            ; D = D + o_X + CF
seg000:0000C3E6                 adca    ,sp
seg000:0000C3E8                 std     8,sp            ; var8 = D = var4 + o_X + CF
seg000:0000C3EA                 ldx     $E,sp           ; X = iFlashMemoryOffset
seg000:0000C3EC                 sty     ,x              ; iFlashMemoryOffset[0] = varA
seg000:0000C3EE                 ldd     8,sp            ; D = var8
seg000:0000C3F0                 std     2,x             ; iFlashMemoryOffset[2] = D = var8
seg000:0000C3F2                 ldd     8,sp            ; D = var8
seg000:0000C3F4                 cpd     4,sp            ; compare (var8, var4)
seg000:0000C3F6                 bcs     loc_C402
seg000:0000C3F8                 bne     loc_C400
seg000:0000C3FA                 ldd     $A,sp
seg000:0000C3FC                 cpd     6,sp
seg000:0000C3FE                 bcs     loc_C402
seg000:0000C400
seg000:0000C400 loc_C400:                               ; CODE XREF: sub_C3B8+40j
seg000:0000C400                 clrb
seg000:0000C401                 skip2
seg000:0000C402
seg000:0000C402 loc_C402:                               ; CODE XREF: sub_C3B8+3Ej
seg000:0000C402                                         ; sub_C3B8+46j
seg000:0000C402                 ldab    #1
seg000:0000C404                 clra
seg000:0000C405                 leas    $C,sp
seg000:0000C407                 rts
seg000:0000C407 ; End of function sub_C3B8
As of right now, here is the C code I've produced to figure out what was going on:

Code: Select all

#define MSB(x)	(unsigned char)((x >> 8) & 0x00FF)

void OSMO_SendCmd07(unsigned int seqNum)
{

/* translations:

dataLength = varA
seqNum = var0
indexer = var2

*/
	unsigned int dataLength, var8, var6, var4, indexer;
	
	// determine the packet length based on subCmd type
	dataLength = OSMO_DetermineCmd07PktLength(seqNum)

	iPacketLength = dataLength + 2;		// add space for additional fields
	
	arrayPacketDataBuffer[0] = iPacketLength;
	
	subCommand = OSMO_Cmd07DetermineSubcommand(seqNum);
	
	iFlashImageMemOffset = OSMO_CalcFlashImageMemOffset(seqNum);
	iFlashImageParagraph = OSMO_CalcFlashImageParagraph(seqNum);
	
	indexer = 0;
	
		
	while (indexer < (dataLength/2) - 1)
	{
		value =	OSMO_GetFirmwareWordFromFlash(iFlashImageMemOffset, 
																					iFlashImageParagraph, 
																					iCmd07FlashAddrAdjustIndex);
	
			
		// store value into packetBuffer... offset of +2 is used to skip over
		// the subCmd and sequence number
		pktbuffer[LSB((indexer * 2) + 2)] = MSB(value)		
		pktbuffer[LSB((indexer * 2) + 3)] = LSB(value)
		
		
		call sub_c3b8(D=0x0002, X=0x0000, iFlashImageMemOffset)
		
		indexer ++;		
	}
	
	OSMO_SendCmdPacketToRoomba(0x07);
	
}
The first part of this looks pretty straightforward.. you figure out how big your packet is going to be... put the pktlength and subcommand fields in place and then you get into the loop where you fill the pktBuffer up. Once you have the packet buffer properly filled, you send the command to the Roomba. Like I said, pretty straight forward stuff.

HOWEVER... the C3B3 function is odd. I can't figure out what exactly it's doing. I've decoded it about 4 times now and somehow I keep mixing up variables or something. This is what is taking me so long get you a proper analysis. Actually, while putting this all together in a post it just dawned on me that they aren't passing the value of iFlashImageMemOffset, but are passing the address of the variable. duh, Greg!

At this point however, we can determine the following about Cmd 07 packets..
* the packets are based on the standard template pattern I described earlier
* the data field of the standard packet model is broken into three subfields: sequence number, subcommand, flash data (in that order)
Anyway, I'm still working on this. Feel free to comment on the code if you like. I would appreciate any help and feedback that you are willing to give.

greg.

PS. I'll post the code for the subroutine that retrieves the byte from memory later. It's messy.. looks pretty in a flowchart, but not pretty in pseudo C. If you want to see the assembly code, here it is...

Code: Select all

seg000:0000C240 OSMO_GetFirmwareWordFromFlash:          ; CODE XREF: OSMO_SendCmd07+51p
seg000:0000C240                 std     6,-sp           ; Pulls a word of the firmware from flash memory and
seg000:0000C240                                         ; return in D
seg000:0000C242                 ldy     8,sp
seg000:0000C244                 ldx     #0
seg000:0000C247                 tfr     x, d
seg000:0000C249                 pshd
seg000:0000C24A                 ldd     2,sp
seg000:0000C24C                 orab    1,sp
seg000:0000C24E                 oraa    ,sp
seg000:0000C250                 std     6,sp
seg000:0000C252                 sty     4,sp
seg000:0000C254                 ldd     $C,sp
seg000:0000C256                 lsld
seg000:0000C257                 lsld
seg000:0000C258                 tfr     d, y
seg000:0000C25A                 ldd     6,sp
seg000:0000C25C                 addd    (arrayCmd07CoefficientTable+2),y
seg000:0000C260                 std     6,sp
seg000:0000C262                 ldd     4,sp
seg000:0000C264                 adcb    (arrayCmd07CoefficientTable+1),y
seg000:0000C268                 adca    arrayCmd07CoefficientTable,y
seg000:0000C26C                 std     4,sp
seg000:0000C26E                 ldx     6,sp
seg000:0000C270                 lsrd
seg000:0000C271                 xgdx
seg000:0000C273                 rora
seg000:0000C274                 rorb
seg000:0000C275                 std     6,sp
seg000:0000C277                 stx     4,sp
seg000:0000C279                 leas    2,sp
seg000:0000C27B                 bne     loc_C28C
seg000:0000C27D                 cpd     #$2000
seg000:0000C280                 bcc     loc_C28C
seg000:0000C282                 lsld
seg000:0000C283                 addd    #$8000
seg000:0000C286                 tfr     d, y
seg000:0000C288                 ldab    #$38
seg000:0000C28A                 bra     loc_C2B2
seg000:0000C28C ; ---------------------------------------------------------------------------
seg000:0000C28C
seg000:0000C28C loc_C28C:                               ; CODE XREF: OSMO_GetFirmwareWordFromFlash+3Bj
seg000:0000C28C                                         ; OSMO_GetFirmwareWordFromFlash+40j
seg000:0000C28C                 tbne    x, loc_C2A0
seg000:0000C28F                 ldd     4,sp
seg000:0000C291                 cpd     #$4000
seg000:0000C294                 bcc     loc_C2A0
seg000:0000C296                 lsld
seg000:0000C297                 addd    #$4000
seg000:0000C29A                 tfr     d, y
seg000:0000C29C                 ldab    #$39
seg000:0000C29E                 bra     loc_C30D
seg000:0000C2A0 ; ---------------------------------------------------------------------------
seg000:0000C2A0
seg000:0000C2A0 loc_C2A0:                               ; CODE XREF: OSMO_GetFirmwareWordFromFlash:loc_C28Cj
seg000:0000C2A0                                         ; OSMO_GetFirmwareWordFromFlash+54j
seg000:0000C2A0                 tbne    x, loc_C2B4
seg000:0000C2A3                 ldd     4,sp
seg000:0000C2A5                 cpd     #$6000
seg000:0000C2A8                 bcc     loc_C2B4
seg000:0000C2AA                 lsld
seg000:0000C2AB                 addd    #0
seg000:0000C2AE                 tfr     d, y
seg000:0000C2B0                 ldab    #$3A
seg000:0000C2B2
seg000:0000C2B2 loc_C2B2:                               ; CODE XREF: OSMO_GetFirmwareWordFromFlash+4Aj
seg000:0000C2B2                 bra     loc_C30D
seg000:0000C2B4 ; ---------------------------------------------------------------------------
seg000:0000C2B4
seg000:0000C2B4 loc_C2B4:                               ; CODE XREF: OSMO_GetFirmwareWordFromFlash:loc_C2A0j
seg000:0000C2B4                                         ; OSMO_GetFirmwareWordFromFlash+68j
seg000:0000C2B4                 tbne    x, loc_C2C7
seg000:0000C2B7                 brset   4,sp, #$80, loc_C2C7
seg000:0000C2BB                 ldd     4,sp
seg000:0000C2BD                 lsld
seg000:0000C2BE                 addd    #$C000
seg000:0000C2C1                 tfr     d, y
seg000:0000C2C3                 ldab    #$3B
seg000:0000C2C5                 bra     loc_C30D
seg000:0000C2C7 ; ---------------------------------------------------------------------------
seg000:0000C2C7
seg000:0000C2C7 loc_C2C7:                               ; CODE XREF: OSMO_GetFirmwareWordFromFlash:loc_C2B4j
seg000:0000C2C7                                         ; OSMO_GetFirmwareWordFromFlash+77j
seg000:0000C2C7                 tbne    x, loc_C2DB
seg000:0000C2CA                 ldd     4,sp
seg000:0000C2CC                 cpd     #$A000
seg000:0000C2CF                 bcc     loc_C2DB
seg000:0000C2D1                 lsld
seg000:0000C2D2                 addd    #$8000
seg000:0000C2D5                 tfr     d, y
seg000:0000C2D7                 ldab    #$3C
seg000:0000C2D9                 bra     loc_C30D
seg000:0000C2DB ; ---------------------------------------------------------------------------
seg000:0000C2DB
seg000:0000C2DB loc_C2DB:                               ; CODE XREF: OSMO_GetFirmwareWordFromFlash:loc_C2C7j
seg000:0000C2DB                                         ; OSMO_GetFirmwareWordFromFlash+8Fj
seg000:0000C2DB                 tbne    x, loc_C2EF
seg000:0000C2DE                 ldd     4,sp
seg000:0000C2E0                 cpd     #$C000
seg000:0000C2E3                 bcc     loc_C2EF
seg000:0000C2E5                 lsld
seg000:0000C2E6                 addd    #$4000
seg000:0000C2E9                 tfr     d, y
seg000:0000C2EB                 ldab    #$3D
seg000:0000C2ED                 bra     loc_C30D
seg000:0000C2EF ; ---------------------------------------------------------------------------
seg000:0000C2EF
seg000:0000C2EF loc_C2EF:                               ; CODE XREF: OSMO_GetFirmwareWordFromFlash:loc_C2DBj
seg000:0000C2EF                                         ; OSMO_GetFirmwareWordFromFlash+A3j
seg000:0000C2EF                 tbne    x, loc_C303
seg000:0000C2F2                 ldd     4,sp
seg000:0000C2F4                 cpd     #$E000
seg000:0000C2F7                 bcc     loc_C303
seg000:0000C2F9                 lsld
seg000:0000C2FA                 addd    #0
seg000:0000C2FD                 tfr     d, y
seg000:0000C2FF                 ldab    #$3E
seg000:0000C301                 bra     loc_C30D
seg000:0000C303 ; ---------------------------------------------------------------------------
seg000:0000C303
seg000:0000C303 loc_C303:                               ; CODE XREF: OSMO_GetFirmwareWordFromFlash:loc_C2EFj
seg000:0000C303                                         ; OSMO_GetFirmwareWordFromFlash+B7j
seg000:0000C303                 ldd     4,sp
seg000:0000C305                 lsld
seg000:0000C306                 addd    #$1B5B
seg000:0000C309                 tfr     d, y
seg000:0000C30B                 ldab    #0
seg000:0000C30D
seg000:0000C30D loc_C30D:                               ; CODE XREF: OSMO_GetFirmwareWordFromFlash+5Ej
seg000:0000C30D                                         ; OSMO_GetFirmwareWordFromFlash:loc_C2B2j ...
seg000:0000C30D                 jsr     OSMO_ReadWordFromFlashPage ; Reads the word located at address Y on PPAGE B
seg000:0000C310                 tfr     y, d            ; return read word in D
seg000:0000C312                 leas    6,sp
seg000:0000C314                 rts
seg000:0000C314 ; End of function OSMO_GetFirmwareWordFromFlash
Post Reply