Registered a URL and setup a forum as the IPCam stuff really needed its own site vs my irregular blog posts about IPCam hacking at

Author Topic: GPIO and Camera executable reversing.  (Read 33930 times)

  • No avatar
  • *****
February 21, 2011, 02:08:06 pm
As one of the things that kills projects like this is working on the same stuff forever and ever, I thought I'd take a look at an area I haven't looked at before.

Namely the PTZ (point tilt zoom) functionality.

In theory, we have a few possible ways that this can be implemented.

First of all is using GPIO (General Purpose IO).  Second option is via i2c, and yet another option is via USB driver.

Lets take a look at GPIO first.

We have the datasheet for the CPU, so we know that the GPIO ports are situated in the 0xFFF83000 area.

So, knowing that, lets take a look at the disassembly for the camera executable, and see if we can spot any calls to that area.

A quick grep of the code shows we have one location for something in that area:

Code: [Select]
006b04:  fff83010 swinv f83010

This has been given a disassembly of software interrupt never SWI NV, but thats the decompiler not realizing its actually data.
So, we now have a location for where the GPIO is.

If we take a look at the W90N745 programming guide PDF (page 146), we see that 0xFFF8.3010 maps out to GPIO_CFG1, which means we have some code for Port 1 on the chip.

Port one has 2 pins, GPIO18 (Port1.0) and GPIO19 (Port 1.1)
These sit at
0xFFF83010 - 0xFFF8301C

Lets take a look at the camera disassembly again, and see if we can correlate that to anything or not.

We'll need to look for references to 06b04 as thats where the value for our GPIO port is stored in the disassembly.

If we search for that, we see a good looking potential candidate.

Code: [Select]
005c34:  440c9abd strmi r9, [ip], -#2749
005c38:  e1a0c00d mov ip, sp
005c3c:  e92dddf0 stmdb sp!, {r4, r5, r6, r7, r8, r10, fp, ip, lr, pc}
005c40:  e24cb004 sub fp, ip, #4 ; 0x4
005c44:  e24dd020 sub sp, sp, #32 ; 0x20
005c48:  e3a06001 mov r6, #1 ; 0x1
005c4c:  e3a034ff mov r3, #-16777216 ; 0xff000000
005c50:  e283360f add r3, r3, #15728640 ; 0xf00000
005c54:  e2833030 add r3, r3, #48 ; 0x30 '0'
005c58:  e5836000 str r6, [r3, #0]
005c5c:  e3a05000 mov r5, #0 ; 0x0
005c60:  e59f3e9c ldr r3, [pc, #3740] ; [006b04]
005c64:  e4835004 str r5, [r3], #4
005c68:  e5835000 str r5, [r3, #0]
005c6c:  e3a024ff mov r2, #-16777216 ; 0xff000000
005c70:  e282273e add r2, r2, #16252928 ; 0xf80000
005c74:  e2822dc1 add r2, r2, #12352 ; 0x3040
005c78:  e5923000 ldr r3, [r2, #0]
005c7c:  e3c33603 bic r3, r3, #3145728 ; 0x300000
005c80:  e5823000 str r3, [r2, #0]
005c84:  e3a02b01 mov r2, #1024 ; 0x400
005c88:  e3e0391f mvn r3, #507904 ; 0x7c000
005c8c:  e2433efb sub r3, r3, #4016 ; 0xfb0
005c90:  e243300b sub r3, r3, #11 ; 0xb
005c94:  e5832000 str r2, [r3, #0]
005c98:  e3e0291f mvn r2, #507904 ; 0x7c000
005c9c:  e2422efa sub r2, r2, #4000 ; 0xfa0
005ca0:  e242200f sub r2, r2, #15 ; 0xf
005ca4:  e5923000 ldr r3, [r2, #0]
005ca8:  e3c337ff bic r3, r3, #66846720 ; 0x3fc0000
005cac:  e3c33bc3 bic r3, r3, #199680 ; 0x30c00
005cb0:  e3c33e3f bic r3, r3, #1008 ; 0x3f0
005cb4:  e4823004 str r3, [r2], #4
005cb8:  e5923000 ldr r3, [r2, #0]
005cbc:  e3833f8f orr r3, r3, #572 ; 0x23c
005cc0:  e5823000 str r3, [r2, #0]
005cc4:  e5923000 ldr r3, [r2, #0]
005cc8:  e3c33c1d bic r3, r3, #7424 ; 0x1d00
005ccc:  e5823000 str r3, [r2, #0]
005cd0:  e59f0e30 ldr r0, [pc, #3632] ; [006b08] "no support"
005cd4:  eb00aacc bl 03080c(aacc)
005cd8:  e59f4e2c ldr r4, [pc, #3628] ; [006b0c]
005cdc:  e5943000 ldr r3, [r4, #0] ; [P_JASPER+5050f0ff]
005ce0:  e1833006 orr r3, r3, r6
005ce4:  e5843000 str r3, [r4, #0] ; [P_JASPER+5050f0ff]
005ce8:  e1a00006 mov r0, r6
005cec:  eb00be37 bl 0355d0(be37)
005cf0:  e5943000 ldr r3, [r4, #0] ; [P_JASPER+5050f0ff]
005cf4:  e3833801 orr r3, r3, #65536 ; 0x10000
005cf8:  e5843000 str r3, [r4, #0] ; [P_JASPER+5050f0ff]
005cfc:  e3a00002 mov r0, #2 ; 0x2
005d00:  eb00be32 bl 0355d0(be32)
005d04:  e59f0e04 ldr r0, [pc, #3588] ; [006b10]
005d08:  e1a01005 mov r1, r5
005d0c:  eb008ec2 bl 02981c(8ec2)
005d10:  e59f0dfc ldr r0, [pc, #3580] ; [006b14]
005d14:  e1a01005 mov r1, r5
005d18:  eb008ebf bl 02981c(8ebf)
005d1c:  e59f0df4 ldr r0, [pc, #3572] ; [006b18]
005d20:  e1a01005 mov r1, r5
005d24:  eb008ebc bl 02981c(8ebc)
005d28:  e59f0dec ldr r0, [pc, #3564] ; [006b1c]
005d2c:  e1a01005 mov r1, r5
005d30:  eb008eb9 bl 02981c(8eb9)
005d34:  e59f0de4 ldr r0, [pc, #3556] ; [006b20]
005d38:  e1a01005 mov r1, r5
005d3c:  eb008eb6 bl 02981c(8eb6)
005d40:  e59f0ddc ldr r0, [pc, #3548] ; [006b24]
005d44:  e1a01005 mov r1, r5
005d48:  eb008eb3 bl 02981c(8eb3)
005d4c:  e3a0047f mov r0, #2130706432 ; 0x7f000000
005d50:  e280097e add r0, r0, #2064384 ; 0x1f8000
005d54:  e3a01a01 mov r1, #4096 ; 0x1000
005d58:  e2811004 add r1, r1, #4 ; 0x4
005d5c:  e59f2dc4 ldr r2, [pc, #3524] ; [006b28]
005d60:  ebfff3f2 bl 002d30(fff3f2)
005d64:  e1500005 cmp r0, r5
005d68:  aa000002 bge 005d78(2) ; jump

The bit we are interested in is from here 0x005c5c

Code: [Select]
005c5c:  e3a05000 mov r5, #0 ; 0x0
005c60:  e59f3e9c ldr r3, [pc, #3740] ; [006b04]
005c64:  e4835004 str r5, [r3], #4
005c68:  e5835000 str r5, [r3, #0]

Clear the contents of register 5 (r5).
Point register 3 (r3) at our gpio port
Then we reset GPIO_DIR1 (r5=0 currently, put r5 into r3+4 aka 0xFFF83014) which basically does a GPIO_PORT1 reset Port1 direction control register.
Then we reset the GPIO_CFG1 config register (r5=0, put that into r3+0 aka 0FFF83010)

Clearly that looks like initialization code for the GPIO port, so we seem to have the right bits so far.

The next part loads up GPIO_CFG4 / 0xFFF8.3040 which is for Port 4 (GPIO30 page 146), and clears it.

Code: [Select]
005c6c:  e3a024ff mov r2, #-16777216 ; 0xff000000
005c70:  e282273e add r2, r2, #16252928 ; 0xf80000
005c74:  e2822dc1 add r2, r2, #12352 ; 0x3040
005c78:  e5923000 ldr r3, [r2, #0]

0xff000000 + 0xf80000 + 0x3040 = 0xFFF83040...

The rest of the code does similar initialization code, including some of the USB hub status (0xFFF05050).

If we check the output of the camera exec we can correlate some of that output with where we are above.

We reset our gpio port1,4, at this point usually the unit makes a click sound.
It then spits out no support (after some checks I need to throw into something like IDA, as I'm not working out what its pointing at from the BIC and other bits), then resets the USB.

Which does look similar to what happens in sequence below
Code: [Select]
no support
/> hub.c: connect-debounce failed, port 1 disabled
new USB device :80fb2004-fed6c0
hub.c: new USB device 1, assigned address 2
probing sonix288 usb camera ...
dvm camera registered as video0
new USB device :80fb2604-fed6c0
hub.c: new USB device 2, assigned address 3
idVendor = 0x148f, idProduct = 0x2573
aw version is
aw version is

Though, it rather looks like from a hardware point of view that the GPIO we've identified is going to turn out to be for something else.

If we look at the board, we have JP5 (labelled Left), JP8 which connects to our stepper motor, and lest we not forget, the alarm ports in green at the back.

If we take a look at the connection for JP5, we see an arm and 3 wires, so this is more likely to be a position sensor for our left/right.
I'll bet this is tied into port 4 (which is 1 i/o, and probably does our where is the camera rotated to right now).

I'll have to make a quick program to read those values from Port4 and then play with that arm and see what happens.

Our other gpio also doesn't feel like its running the PTZ either, its probably tied into the green i/o at the back.

So, we're still looking, but we're definitely identifying possibilities.

Code for GPIO access is in this post here if anyone wants to try before I do, and see.

Guess the next little utility I write will be to pull GPIO4, and GPIO1 values while I play with those possible inputs...

ARM7TDMI Instruction light bedtime reading -
ARM assembly instructions reference -

February 21, 2011, 05:57:08 pm
The camera binary also has a mention of:

can not open ptz device !!!

so maybe the implemented it via a kernel driver somehow and aren't using the GPIO directly?

  • No avatar
  • *****
February 21, 2011, 10:20:38 pm
I'm trying to walk people through the investigation process, Mr wants to run before he can walk.

I know that we have a kernel driver for this, and a device node too.

crw-------  1 root root 200,  0 1969-12-31 18:00 ptz0

However, you still need to walk through how to find out what is getting done.

February 23, 2011, 10:01:13 am
Oh! lol; I thought you where documenting your investigation steps! I just mentioned something I noticed to help in the investigation :(

So what haven't you investigated yet so I can poke around somewhere too :)

I do love the posts however!

  • No avatar
  • *****
February 23, 2011, 10:34:51 am
I'm pretty much done with what I need to find out for everything else, this was really the last piece.

I have my own custom kernel with drivers running, I have the necessary bits and bobs to grab video etc already running.
Next up is integration, and as you keep pushing me on it, motion detection.

I also want to look at a packaging system - eg opkg.

I spoke today at length to someone at Maygion and had a chat about what I'm doing etc, they're doing the motion sensing manually also; they also don't have a datasheet for the camera.  Their code runs slower than real time, which is what I was thinking might happen given cpu and other limits (small cache size, floating point etc)

If someone wants to work on a simple algorithm for that, wouldn't be a bad idea.  I think my proposed method is probably the fastest.  Its either that, or base off the luminance changes in an image.

There is some existing code that *will* work on our platform (although I don't know how slow processing will be)

and another similar idea using Python (we'd need to recode it in C, but its quite straightforward)

and I better not forget the intel opencv stuff (which is too large for us, but looking at implementations is always a good idea)


« Last Edit: February 23, 2011, 10:37:41 am by admin »

  • No avatar
  • *****
June 02, 2011, 10:05:46 pm
Movement - or how the software meets the hardware

Our board uses a ULN2803AG to drive a 5v Unipolar Stepper Motor for our Left / Right movement.

Pin 1 is 5v
Pin 2,3
Pin 4,5 are our movement for coil1, coil2 in our motor.

We need 4 i/o pins to drive a motor forward or backwards.
Lets take a look at the datasheet for a UL2803AG.
It says the ULN2803A handles 5v TTL and CMOS inputs, to drive a 500ma load on the outputs.

Input Pins 1 - 8 map to output pins 18 - 11
If Pin1 is pulled high, then pin 18 goes high.
If Pin8 is pulled high, then pin 11 goes high.

To turn a stepper motor, we need to pulse  our 4 pins connected to the stepper motor in series

Stepper Motor Wire
1   2   3   4
On Off Off Off
Off On Off Off
Off Off On Off
Off Off Off On

So, which pins are we using on the ULN2803 Chip?

According to my trusty multimeter on the stepper motor
Pin1 is 5v
Pin2 is connected to pin 14 (out 5)
pin3 is connected to pin 13 (out 6)
pin4 is connected to pin 12 (out 7)
pin5 is connected to pin 11 (out 8)

So, our inputs are on 5,6,7,8 on the ULN2803, but what drives those pins?

Lets follow the circuit board - from there, that goes into an 8 bit addressable latch - 74HC259
This runs at CMOS voltage levels.

Pins 5,6,7,8 map to Q4 , Q5, Q6, Q7 (pins 9,10,11,12)

Pins 14,15 set the mode on the 74HC259

I haven't checked those in a live machine, but they map as follows:
L = low, H = high
L, H = Addressable Latch
H, H = Memory
L, L = 8 line demux
H, L = Reset

I'll hazard a guess that its set to addressable latch mode, as A0, A1, A2 (pins 1,2,3) map to our CPU i/o pins

A0 goes on Pin 12 on the CPU aka GPIO[7]
A1 "" "" GPIO[8]
A2 "" "" GPIO[9]

Which map to Port 5

Pulling these high / low as follows has the following effect (in theory)

5_2 5_3 5_4
H    L   L    Q4 -> high?
H    L   H    Q5 -> high?
H    H   L    Q6 -> high?
H    H   H    Q7 -> high?

So, I guess I need to make some code now based on writing GPIO Port 5_2, 5_3, 5_4 as per that to move the motor.

  • No avatar
  • *****
June 03, 2011, 06:56:28 am
may I remid you of one important fact in the "addressable latch mode"?

it outputs the state of data input (D, pin13) on the addressed output.

So to be able to output H and L you have to be able to change pin 13.

at the moment you are asuming it is fixed to H, since you only give examples for pulling output high.
How exactly are you going to set them to L?

your example is more like 3-8 decoder mode since it will only drive exactly the adressed pin to H if pin13=H, seting all others to L (forever inhibiting halfstep mode). This would be the worst example of engineering but wouldn't surprise me, having seen lots of chinatech.

I hope that at least pin13 (data) is connected to a gpio too, more favourably pin14 (latch) also, to enable changing of the states without having "glitches" on the outputs.


  • No avatar
  • *****
June 04, 2011, 01:36:37 pm
Have to be honest hardware isn't my strong point  :-[
I can read a datasheet though, and I do have some background in embedded development, so its not totally gobbledygook  ;D

Pin 13 goes to Pin15 on the CPU
Pin 14 doesn't appear to get used by a GPIO port.

So -

A0 goes on Pin 12 on the CPU aka GPIO[7]
A1 "" "" GPIO[8]
A2 "" "" GPIO[9]
Data Input (Latch mode High / Low)  goes to Pin 15 aka GPIO [10] (GPIO 5_5)

5_2 5_3 5_4
H    L   L    Q4 set to Data Input (GPIO 5_5)
H    L   H    Q5 set to Data Input
H    H   L    Q6 set to Data Input
H    H   H    Q7 set to Data Input


Looks like we would do something like:

(Psuedo pseudo code haha)

Pull GPIO[10] high.            5_5 high
Trigger Q4 (Q4 goes high) 5_2 high, 5_3 low, 5_4 low
Pull GPIO[10] low
Trigger Q4 (off?)
Pull GPIO[10] high
Trigger Q5

Sound good?

I guess I'll knock up some code now and see if that will work.

  • No avatar
  • *****
June 04, 2011, 03:34:19 pm

depending on the settings on pins 14 & 15 of '259 I would say the sequence would be like:

Code: [Select]
output 0000 to gpio[7..10]  'clear all
output 0001 to gpio[7..10]  'set address 000 aka pin 4'259 to high
delay x                     'pulse width
output 0000 to gpio[7..10]  'set address 000 aka pin4'259 to low
output 1001 to gpio[7..10]  'set address 001 aka pin5'259 to high
delay x                     'pulse width
output 1000 to gpio[7..10]  'set address 001 aka pin5'259 to low

if the second motor is on the other half of the '259 outputs, this design wouldn't allow for h and v movement at the same time (or only with very complex logic), because you can't have power to two coils at the same time....


P.S.: on my cam, pin14'259 (LE) has a cap to vcc and resistor to gnd, what I would expect at the reset pin...
the reset pin seems to be floating and looks like it has originaly been connected to gnd and only the film has been corrected. So somehow it looks like someone during design miexd up the pins....

so it could be that we are operating in addressable latch instead of demux mode. This shouldn't make any difference for the simple code above, but may make it easier to operate both motors at the same time.
« Last Edit: June 04, 2011, 04:10:32 pm by schufti »

  • No avatar
  • *****
June 04, 2011, 04:29:49 pm
I think its addressable latch mode - I haven't got a scope to check though - mine is in Cape Town, and I'm in Shanghai at the moment.

Right now I have a multimeter that goes beep - a borked board, and a soon to be reflashed unit for testing.
Making progress today though.

  • No avatar
  • *****
June 04, 2011, 06:10:43 pm
hmmm rethinking adressable latch mode and the fact that we can't steer the timing of the latching, the code should look like like this to be on the safe side

Code: [Select]
output 0000 to gpio[7..10]  'clear all
output 0001 to gpio[7..10]  'set address 000 aka pin 4'259 to high
delay x                     'pulse width
output 0000 to gpio[7..10]  'set address 000 aka pin4'259 to low
output 1000 to gpio[7..10]  'prepare next address without changing data
output 1001 to gpio[7..10]  'set address 001 aka pin5'259 to high
delay x                     'pulse width
output 1000 to gpio[7..10]  'set address 001 aka pin5'259 to low
output 0100 to gpio[7..10]  'prepare next address without changing data

February 14, 2012, 08:09:24 pm
any progress on this yet???

February 26, 2012, 06:47:39 pm
did anyone manage to get a test program going to try getting the GPI/Pan-tilt motors to work?
if not, can someone at least provide some (pseudo) code or some tips on how to go about coding something? please help, thanks...

  • No avatar
  • *****
March 04, 2012, 08:34:48 am

March 07, 2012, 08:37:34 pm
uhhh huh???  ???

Ive gone over the posts in this thread a bunch of times, and I still cant figure out exactly what needs to be done... I see the example where gpio pins 7-10 are pulled high&low in sequence, but this doesnt explain clearly how to control a single motor (or both), or how to change the direction the motor is spinning.

Also, I struggled to get the gpio lib loaded into my 3.1 kernel. I managed to get it to load through /sys/class/gpio interface (built sysfs support into my kernel), but the examples above seem to use some other (older?) method to interface the gpio pins.

can you please help by elaborating on what should be done in order to get this to work?