Talk:DPF with AppoTech AX203

From ST2205u wiki
Revision as of 12:27, 9 December 2010 by Hackfin (talk | contribs) (Datasheets, etc)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)

Hi, created a small Windows tool to DUMP the device( read/erase/write flash also possible)

dpf_scsi.h

/////////////////////
/// ** DERMAIK ** ///
/////////////////////

#ifndef _DPF_SCSI_H_INCLUDED_
#define _DPF_SCSI_H_INCLUDED_

#include <windows.h>
#include <winioctl.h>

typedef struct {
  USHORT Length;
  UCHAR  ScsiStatus;
  UCHAR  PathId;
  UCHAR  TargetId;
  UCHAR  Lun;
  UCHAR  CdbLength;
  UCHAR  SenseInfoLength;
  UCHAR  DataIn;
  ULONG  DataTransferLength;
  ULONG  TimeOutValue;
  ULONG  DataBufferOffset;
  ULONG  SenseInfoOffset;
  UCHAR  Cdb[16];
} SCSI_PASS_THROUGH, *PSCSI_PASS_THROUGH;


typedef struct {
  USHORT Length;
  UCHAR  ScsiStatus;
  UCHAR  PathId;
  UCHAR  TargetId;
  UCHAR  Lun;
  UCHAR  CdbLength;
  UCHAR  SenseInfoLength;
  UCHAR  DataIn;
  ULONG  DataTransferLength;
  ULONG  TimeOutValue;
  PVOID  DataBuffer;
  ULONG  SenseInfoOffset;
  UCHAR  Cdb[16];
} SCSI_PASS_THROUGH_DIRECT, *PSCSI_PASS_THROUGH_DIRECT;


typedef struct {
  SCSI_PASS_THROUGH spt;
  ULONG Filler;
  UCHAR ucSenseBuf[32];
  UCHAR ucDataBuf[512];
} SCSI_PASS_THROUGH_WITH_BUFFERS, *PSCSI_PASS_THROUGH_WITH_BUFFERS;


typedef struct {
  SCSI_PASS_THROUGH_DIRECT spt;
  ULONG Filler;
  UCHAR ucSenseBuf[32];
} SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER, *PSCSI_PASS_THROUGH_DIRECT_WITH_BUFFER;

#define IOCTL_SCSI_BASE    0x00000004

#define  SCSI_IOCTL_DATA_OUT          0
#define  SCSI_IOCTL_DATA_IN           1
#define  SCSI_IOCTL_DATA_UNSPECIFIED  2

#define IOCTL_SCSI_PASS_THROUGH         CTL_CODE( IOCTL_SCSI_BASE, 0x0401, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS )
#define IOCTL_SCSI_MINIPORT             CTL_CODE( IOCTL_SCSI_BASE, 0x0402, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS )
#define IOCTL_SCSI_GET_INQUIRY_DATA     CTL_CODE( IOCTL_SCSI_BASE, 0x0403, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_SCSI_GET_CAPABILITIES     CTL_CODE( IOCTL_SCSI_BASE, 0x0404, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_SCSI_PASS_THROUGH_DIRECT  CTL_CODE( IOCTL_SCSI_BASE, 0x0405, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS )
#define IOCTL_SCSI_GET_ADDRESS          CTL_CODE( IOCTL_SCSI_BASE, 0x0406, METHOD_BUFFERED, FILE_ANY_ACCESS )

BOOL FlashRead( HANDLE hDevice, LPBYTE pBuf, DWORD dwLength, DWORD dwAddress );
BOOL FlashErasePage( HANDLE hDevice, BYTE page );
BOOL FlashWrite( HANDLE hDevice, LPBYTE pBuf, DWORD dwLength, DWORD dwAddress );

#endif //_DPF_SCSI_H_INCLUDED_

dpf_scsi.cpp

/////////////////////
/// ** DERMAIK ** ///
/////////////////////

#include "dpf_scsi.h"
#include <stddef.h>

//"special" SCSI commands used by DPF, each command has exact 0x10 bytes of payload
//CA = ??? used once at startup, sends something like a response / maybe timesync
//CB = ERASE/WRITE
//CC = ??? never used
//CD = READ

BOOL FlashRead( HANDLE hDevice, LPBYTE pBuf, DWORD dwLength, DWORD dwAddress )
{
  SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER swb;
  memset( &swb, 0, sizeof(SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER) );

  swb.spt.Length = sizeof(SCSI_PASS_THROUGH);
  swb.spt.TimeOutValue = 2;
  swb.spt.DataBuffer = pBuf;
  swb.spt.SenseInfoOffset = offsetof(SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER, ucSenseBuf);

  swb.spt.DataIn = SCSI_IOCTL_DATA_IN;
  swb.spt.DataTransferLength = dwLength;

  swb.spt.CdbLength = 0x10;

  swb.spt.Cdb[0x00] = 0xCD;
  swb.spt.Cdb[0x01] = 0;
  swb.spt.Cdb[0x02] = 0;
  swb.spt.Cdb[0x03] = 0;
  swb.spt.Cdb[0x04] = 0;
  swb.spt.Cdb[0x05] = 0;
  swb.spt.Cdb[0x06] = 0x04;
  swb.spt.Cdb[0x07] = (BYTE)((dwLength>>16)&0xFF);
  swb.spt.Cdb[0x08] = (BYTE)((dwLength>> 8)&0xFF);
  swb.spt.Cdb[0x09] = (BYTE)((dwLength>> 0)&0xFF);
  swb.spt.Cdb[0x0A] = 0x03;
  swb.spt.Cdb[0x0B] = (BYTE)((dwAddress>>16)&0xFF);
  swb.spt.Cdb[0x0C] = (BYTE)((dwAddress>> 8)&0xFF);
  swb.spt.Cdb[0x0D] = (BYTE)((dwAddress>> 0)&0xFF);
  swb.spt.Cdb[0x0E] = 0;
  swb.spt.Cdb[0x0F] = 0;

  DWORD dwReturned;
  return DeviceIoControl( hDevice, IOCTL_SCSI_PASS_THROUGH_DIRECT, &swb, sizeof(swb), &swb, sizeof(swb), &dwReturned, NULL );
}

BOOL _WritePrep( HANDLE hDevice )
{
  DWORD dwReturned;
  SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER swb;
  memset( &swb, 0, sizeof(SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER) );

  swb.spt.Length = sizeof(SCSI_PASS_THROUGH);
  swb.spt.TimeOutValue = 5;
  swb.spt.DataBuffer = NULL;
  swb.spt.SenseInfoOffset = offsetof(SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER, ucSenseBuf);

  swb.spt.DataIn = SCSI_IOCTL_DATA_OUT;
  swb.spt.DataTransferLength = 0;

  swb.spt.CdbLength = 0x10;

  swb.spt.Cdb[0x00] = 0xCB;
  swb.spt.Cdb[0x01] = 0;
  swb.spt.Cdb[0x02] = 0;
  swb.spt.Cdb[0x03] = 0;
  swb.spt.Cdb[0x04] = 0;
  swb.spt.Cdb[0x05] = 0;
  swb.spt.Cdb[0x06] = 0x01;
  swb.spt.Cdb[0x07] = 0;
  swb.spt.Cdb[0x08] = 0;
  swb.spt.Cdb[0x09] = 0;
  swb.spt.Cdb[0x0A] = 0x06;
  swb.spt.Cdb[0x0B] = 0;
  swb.spt.Cdb[0x0C] = 0;
  swb.spt.Cdb[0x0D] = 0;
  swb.spt.Cdb[0x0E] = 0;
  swb.spt.Cdb[0x0F] = 0;

  return( DeviceIoControl( hDevice, IOCTL_SCSI_PASS_THROUGH_DIRECT, &swb, sizeof(swb), &swb, sizeof(swb), &dwReturned, NULL ) );
}

BOOL FlashErasePage( HANDLE hDevice, BYTE page )
{
  if( page<5 )  //device doesn't start if you "silly" mod data in region 0-0x50000, so be carefully!
    return FALSE;

  if( !_WritePrep( hDevice ) )
    return FALSE;

  DWORD dwReturned;
  SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER swb;

  memset( &swb, 0, sizeof(SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER) );

  swb.spt.Length = sizeof(SCSI_PASS_THROUGH);
  swb.spt.TimeOutValue = 5;
  swb.spt.DataBuffer = NULL;
  swb.spt.SenseInfoOffset = offsetof(SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER, ucSenseBuf);

  swb.spt.DataIn = SCSI_IOCTL_DATA_IN;
  swb.spt.DataTransferLength = 0;

  swb.spt.CdbLength = 0x10;

  swb.spt.Cdb[0x00] = 0xCB;
  swb.spt.Cdb[0x01] = 0;
  swb.spt.Cdb[0x02] = 0;
  swb.spt.Cdb[0x03] = 0;
  swb.spt.Cdb[0x04] = 0;
  swb.spt.Cdb[0x05] = 0;
  swb.spt.Cdb[0x06] = 0x04;
  swb.spt.Cdb[0x07] = 0;
  swb.spt.Cdb[0x08] = 0;
  swb.spt.Cdb[0x09] = 0;
  swb.spt.Cdb[0x0A] = 0xD8;
  swb.spt.Cdb[0x0B] = page;
  swb.spt.Cdb[0x0C] = 0;
  swb.spt.Cdb[0x0D] = 0;
  swb.spt.Cdb[0x0E] = 0;
  swb.spt.Cdb[0x0F] = 0;

  if( !DeviceIoControl( hDevice, IOCTL_SCSI_PASS_THROUGH_DIRECT, &swb, sizeof(swb), &swb, sizeof(swb), &dwReturned, NULL ) )
    return FALSE;

  return TRUE;
}

BOOL FlashWrite( HANDLE hDevice, LPBYTE pBuf, DWORD dwLength, DWORD dwAddress )
{
  //device doesn't start if you "silly" mod data in region 0-0x50000, so be carefully!
  if( dwAddress<0x50000 )
    return FALSE;

  if( !_WritePrep( hDevice ) )
    return FALSE;

  DWORD dwReturned;
  SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER swb;

  memset( &swb, 0, sizeof(SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER) );

  swb.spt.Length = sizeof(SCSI_PASS_THROUGH);
  swb.spt.TimeOutValue = 5;
  swb.spt.DataBuffer = pBuf;
  swb.spt.SenseInfoOffset = offsetof(SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER, ucSenseBuf);

  swb.spt.DataIn = SCSI_IOCTL_DATA_OUT;
  swb.spt.DataTransferLength = dwLength;

  swb.spt.CdbLength = 0x10;

  swb.spt.Cdb[0x00] = 0xCB;
  swb.spt.Cdb[0x01] = 0;
  swb.spt.Cdb[0x02] = 0;
  swb.spt.Cdb[0x03] = 0;
  swb.spt.Cdb[0x04] = 0;
  swb.spt.Cdb[0x05] = 0;
  swb.spt.Cdb[0x06] = 0x04;
  swb.spt.Cdb[0x07] = (BYTE)((dwLength>>16)&0xFF);
  swb.spt.Cdb[0x08] = (BYTE)((dwLength>> 8)&0xFF);
  swb.spt.Cdb[0x09] = (BYTE)((dwLength>> 0)&0xFF);
  swb.spt.Cdb[0x0A] = 0x02;
  swb.spt.Cdb[0x0B] = (BYTE)((dwAddress>>16)&0xFF);
  swb.spt.Cdb[0x0C] = (BYTE)((dwAddress>> 8)&0xFF);
  swb.spt.Cdb[0x0D] = (BYTE)((dwAddress>> 0)&0xFF);
  swb.spt.Cdb[0x0E] = 0;
  swb.spt.Cdb[0x0F] = 0;

  if( !DeviceIoControl( hDevice, IOCTL_SCSI_PASS_THROUGH_DIRECT, &swb, sizeof(swb), &swb, sizeof(swb), &dwReturned, NULL ) )
    return FALSE;

  return TRUE;
}

dpf_tool.cpp

/////////////////////
/// ** DERMAIK ** ///
/////////////////////

#define _CRT_SECURE_NO_WARNINGS
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <stdio.h>

#include "dpf_scsi.h"

int main (int argc, char * argv [])
{
  if( 2 != argc )
  {
    printf( "Usage: %s DRIVELETTER:\r\n       %s I:\r\n\r\n", argv[0], argv[0] );
    return -1;
  }

  char szDrivePath[MAX_PATH];
  sprintf( szDrivePath, "\\\\.\\%s", argv[1] );

  HANDLE hDevice = CreateFile( szDrivePath, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
  if( INVALID_HANDLE_VALUE != hDevice )
  {
    BYTE buffer[0x1000];
    memset( buffer,0, sizeof(buffer));

    // full dump
    FILE *f = fopen( "dpf_dump.bin", "wb" );
    if( !f )
    {
      printf( "ERROR: Could not open output file 'dpf_dump.bin' for writing\r\n\r\n" );
      return -1;
    }

    DWORD dwAddress;
    for( dwAddress = 0; dwAddress<(2*1024*1024); dwAddress+= 0x1000 )
    {
      if( !FlashRead( hDevice, buffer, 0x1000, dwAddress ) )
        break;

      fwrite( buffer, 1, 0x1000, f );
    }

    fclose(f);

/*
    memset( buffer, 'M', sizeof(buffer) );
    FlashErasePage( hDevice, 0x5 );                //erase will always destroy complete page (64kB)
    FlashWrite( hDevice, buffer, 0x100, 0x52000 ); //write can handle 0x100 (256) bytes maximum only
*/

    CloseHandle( hDevice );
  }
  else
    printf( "ERROR: Could not open drive %s\r\n\r\n", argv[1] );

  return 0;
}

notes.txt

"special" SCSI commands used by DPF, each command has exact 0x10 bytes of payload
CA = ??? used once at startup, sends something like a response / maybe timesync
CB = ERASE/WRITE
CC = ??? never used
CD = READ

device communication when starting DPFMate.exe
#1
CB 00 00 00 00 00 01 00 00 00 AB 00 00 00 00 00   ..........«.....

#2 
CD 00 00 00 00 04 00 29 48 23 18 BE 67 84 E1 00   .......)H#.¾g?á.
==> 5 bytes back !!DIFFERENT!!
90 A1 5F BE 99                                                                        ¡_¾?

#3 !!DIFFERENT!! **maybe TIME SYNC** ???
CA 00 00 00 00 09 01 03 15 11 37 36 00 00 00 00   ..........76....

#4
CD 00 00 00 00 00 01 00 00 40 9F 00 00 00 00 00   .........@?.....
==> 0x40 bytes back
7F 37 20 15 7F 37 20 15 7F 37 20 15 7F 37 20 15      ?7 .?7 .?7 .?7 .
7F 37 20 15 7F 37 20 15 7F 37 20 15 7F 37 20 15      ?7 .?7 .?7 .?7 .
7F 37 20 15 7F 37 20 15 7F 37 20 15 7F 37 20 15      ?7 .?7 .?7 .?7 .
7F 37 20 15 7F 37 20 15 7F 37 20 15 7F 37 20 15      ?7 .?7 .?7 .?7 .

#5 [special get version string]
CD 00 00 00 00 01 01 00 00 00 01 00 00 00 00 00   ................

==>0x40 bytes back (max) (got 0x1d):
46 45 44 50 46 33 2E 30 5F 53 54 41 4E 44 41 52   FEDPF3.0_STANDAR
44 5F 32 30 33 5F 56 33 2E 33 2E 35 00            D_203_V3.3.5.

#6 read data from @0x00040, length 0x40
CD 00 00 00 00 00 04 00 00 40 03 00 00 40 00 00   .........@...@..
==>0x40 bytes back *same*
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   ................
13 15 80 80 02 01 02 01 00 00 00 00 00 00 00 00   ..??............
05 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   ................
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   ................

************************

write data
#1 ????
CB 00 00 00 00 00 01 00 00 00 AB 00 00 00 00 00   ..........«.....

#2 (prepare flash command)
CB 00 00 00 00 00 01 00 00 00 06 00 00 00 00 00   ................

#3 (erase page @0x50000 ==> 0x5)
CB 00 00 00 00 00 04 00 00 00 D8 05 00 00 00 00   ..........Ø.....

#4 (read) ==> 0x40 back (all 0) [not needed...]
CD 00 00 00 00 00 01 00 00 40 05 00 00 00 00 00   .........@......

#5 (like#2, prepare flash command)
CB 00 00 00 00 00 01 00 00 00 06 00 00 00 00 00   ................

#6 (write @0x50000)
CB 00 00 00 00 00 04 00 01 00 02 05 00 00 00 00   ................
==> send 0x100 to device

#7 (like#2, prepare flash command)
CB 00 00 00 00 00 01 00 00 00 06 00 00 00 00 00   ................

#8 (like#6, write @0x50100)
CB 00 00 00 00 00 04 00 01 00 02 05 01 00 00 00   ................
==> send 0x100 to device

Datasheets, etc

I sent Appotech an email requesting more information regarding their AX203. I pointed out the datasheet (http://203.124.11.194/downloads/ds/ax203_factsheet.pdf) did not have enough details, and if they could kindly provide me any more information.

Well, not only did they rudely not reply, but the next day the ax203_factsheet.pdf (and all other appotech factsheets from that site) were removed. If you need them (and/or the CFP5102 datasheet), they are here: http://www.ccs.neu.edu/home/bchafy/ax203_info.zip

BTW, see Figure 6-3 of the CFP5102 Data Sheet, the chip is labeled AX203. :)

Anyway, I checked the pinouts on my board against the CFP5102 datasheet and they match up. I think the AX203 is the CFP5102, or very nearly the same thing. Strangely, I could not locate any information about the CFP5102 on the Chip For People main website. I recommend reading section 8. But I think it's doubtful that the entire code is inside the 16K OTP.

Digging a little deeper, the data from 0 - 0x8000 in the flash is the most interesting. If you look at ax_data.bin with a hex editor at around 0x6000 (showing 16 bytes per line), you see a kind of regular pattern, 4 lines of repeating hex values. This is only conjecture, but ordinarily code ends with a sequence of unused 0's or F's until the last byte. But here, we see a pattern. It is also evident near the beginning at around 0x140. This *could* be some kind of obfuscation pattern revealing itself. I cannot get any reasonable 8051 dissassembly from 0 - 0x8000 as it stands.

  • Amendment: It can be disassembled using the d52 disassembler. I will post a control file and some instructions soon, on how to make the dump kinda human readable. Then, a lot of guessing will have to be done how the chip actually loads/executes the program stored in SPI -- hackfin
  • Hmm, I'm not really sure if the CFP5102/AX203 are usable for anything but their photoframe use... as far as I can glance from the datasheet, the internal ROM is OTP and thus not flashable, and chances that the main SPI flash contains code isn't great either: for execution, the chip would have to store it in ram first, but it only has 300bytes or so of that, making that idea kinda unfeasible -- Sprite_tm

Additional information regarding new device

I've bough the following device: http://www.dealextreme.com/details.dx/sku.17456

It seems to belong to this category of devices as well. It presents itself as a CD device with only Windows software (DPFMate.exe). Here's the output of the About box:

DPFMate v3.8.2.9
Copyright (C) 2007 AppoTech Corporation
Flash Type: Winbond W25x16
Flash Size: 2048 KB
Firmware Ver: DPF203_V3.4.7.1
Flash ID: 0xEF301500
http://www.buildwin.com.cn

I have compiled the following program and the 2 MB dump is pretty much close to the one provided here (it has the DPF203_V3.4.7 080507-0 string). It has some differences at the following offsets (probably timestamp/checksums):

0x04
0x06
0x56
0x60
0x62

Two sectors with huge differences:

0x10e - 0x140
0x201 - 0x6c40

All other first 0x8000 bytes are the same.

I have modified program a little to play with different reads (different offsets and block sizes). It seems that everything wraps nicely around 2 MB, the "negative" offset 0x80000000 was properly detected, too. The block size can't be higher than 0x1000 (device IO fails) and lower than 0x40 (partial reads, no meaningful "garbage" data detected).

Other interesting facts:

At 0x08000 starts CD image (Windows reports 204 KB usage)
At 0x50000 starts picture frame file system (string ID: "ABFS")
At 0x50005 contains number of stored pictures (0x50004 might be reserved as well)
At 0x50020 (two bytes) Offset to the data of picture 1
At 0x50022 (two bytes) Offset to the data of picture 2, etc.
At 0x51004 (two bytes) 16-bit RGB of background colour
At 0x51006 (two bytes) 16-bit RGB of foreground colour
At 0x52000 (0x4000 bytes) Data of picture 1 (weird encoding, only 1 byte per pixel, haven't looked much into it)

Settings that can be set on device (backlight, contrast, clock) are not written to the flash.

I haven't located any interesting 8051 code in the first 0x8000 bytes.

For more info, contact me: b00mer -at- mail386.com



ABFS from my device is the following with three pictures on it:

41 42 46 53 00 00 00 00 00 00 00 07 00 10 00 00 ABFS............

01 00 10 07 00 BE 0D 00 01 BE 1D 07 00 AE 0D 00 .....¾...¾...®..

01 6C 2B 07 00 AE 0D 00 00 00 00 00 00 00 00 00 .l+..®..........

Then everything 0x00 up to 0x71001, where first two 16-bit integers are LCD height and width (i don't know in what order :/)

Some new (AFAIK) Information

Apparently there´s a Distribution of DPFMate for Mac available. http://www.nrponline.com/Uploads/123/MiniPic/MacDPFmate.zip

Inside the zip-File there are actually some source Files which might contain some valuable information. --ViRuZ360

New DPF variant

Moved to Talk:DPF_with_AppoTech_AX206


AX20? Linux FLASH Dumper

/* Written by Maurus Cuelenaere */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <scsi/sg.h>

typedef struct
{
    char            typeName[32];
    unsigned char   memsize[4];
    unsigned char   devID[4];
    unsigned char   eraseCMD;
    unsigned char   writeCMD;
    unsigned char   readCMD;
    char            data;
    unsigned char   iWriteByByte[4];
} FLASH_TYPE_STRUCT;

unsigned char* scsi_read(int fd, unsigned char *cmd_buffer, size_t cmd_size, size_t read_size)
{
    sg_io_hdr_t io_hdr;
    unsigned char sense_buffer[32];
    unsigned char* read_data = malloc(read_size * sizeof(unsigned char));

    if(read_data == NULL)
        return NULL;

    memset(read_data, 0, read_size * sizeof(unsigned char));
    memset(&io_hdr, 0, sizeof(sg_io_hdr_t));
    io_hdr.interface_id = 'S';
    io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
    io_hdr.dxfer_len = read_size;
    io_hdr.dxferp = read_data;
    io_hdr.cmdp = cmd_buffer;
    io_hdr.cmd_len = cmd_size;
    io_hdr.sbp = sense_buffer;
    io_hdr.mx_sb_len = sizeof(sense_buffer);
    io_hdr.timeout = 200;

    if(ioctl(fd, SG_IO, &io_hdr) < 0)
    {
        printf("%d %s\n", io_hdr.status, strerror(errno));
        free(read_data);
        return NULL;
    }
    else
        return read_data;
}

unsigned char* flash_read(int fd, int addr, int size)
{
    unsigned char cmd_buffer[16];

    memset(cmd_buffer, 0, sizeof(cmd_buffer));
    cmd_buffer[0] = 0xCD;
    cmd_buffer[6] = 0x04;
    cmd_buffer[7] = (size >> 16) & 0xFF;
    cmd_buffer[8] = (size >>  8) & 0xFF;
    cmd_buffer[9] = (size >>  0) & 0xFF;
    cmd_buffer[10] = 0x03;
    cmd_buffer[11] = (addr >> 16) & 0xFF;
    cmd_buffer[12] = (addr >>  8) & 0xFF;
    cmd_buffer[13] = (addr >>  0) & 0xFF;

    return scsi_read(fd, cmd_buffer, 16, size);
}

unsigned char* get_flash_id(int fd)
{
    unsigned char cmd_buffer[16];

    memset(cmd_buffer, 0, sizeof(cmd_buffer));
    cmd_buffer[0] = 0xCD;
    cmd_buffer[6] = 0x01;
    cmd_buffer[9] = 0x40;
    cmd_buffer[10] = 0x9F;

    return scsi_read(fd, cmd_buffer, 16, 0x40);
}

void get_lcd_param(int fd, short *x, short *y)
{
    unsigned char cmd_buffer[16], *ret;

    memset(cmd_buffer, 0, sizeof(cmd_buffer));
    cmd_buffer[0] = 0xCD;
    cmd_buffer[5] = 0x02;
    cmd_buffer[6] = 0x01;
    cmd_buffer[10] = 0x02;

    ret = scsi_read(fd, cmd_buffer, 16, 0x40);

    *x = ret[0] | (ret[1] << 8);
    *y = ret[2] | (ret[3] << 8);
}

unsigned char* get_version(int fd)
{
    unsigned char cmd_buffer[16];

    memset(cmd_buffer, 0, sizeof(cmd_buffer));
    cmd_buffer[0] = 0xCD;
    cmd_buffer[5] = 0x01;
    cmd_buffer[6] = 0x01;
    cmd_buffer[10] = 0x01;

    return scsi_read(fd, cmd_buffer, 16, 0x40);
}

long filesize(FILE* fd)
{
    long cur = ftell(fd);
    fseek(fd, 0, SEEK_END);
    long size = ftell(fd);
    fseek(fd, cur, SEEK_SET);
    return size;
}

static FLASH_TYPE_STRUCT* flashlib;
static int flashlib_count;
int load_flashlib(void)
{
    FILE* fd = fopen("flashlib.dat", "r");
    if(fd < 0)
        return -1;

    flashlib_count = filesize(fd) / sizeof(FLASH_TYPE_STRUCT);
    flashlib = malloc(sizeof(FLASH_TYPE_STRUCT) * flashlib_count);
    if(flashlib == NULL)
        return -2;

    fread(flashlib, sizeof(FLASH_TYPE_STRUCT) * flashlib_count, 1, fd);
    fclose(fd);
    return 0;
}

int main(int argc, char* argv[])
{
    int fd;
    FILE* out;

    if(load_flashlib() < 0)
    {
        printf("Cannot load flashlib!\n");
        exit(-1);
    }

    int j;
    for(j=0; j<flashlib_count; j++)
    {
        FLASH_TYPE_STRUCT* flash = &flashlib[j];
        printf("%s: %x%x%x%x [%d]\n", flash->typeName, flash->devID[0], flash->devID[1], flash->devID[2], flash->devID[3],
                                      flash->memsize[2] | (flash->memsize[1] << 8) | (flash->memsize[3] << 16) | (flash->memsize[0] << 24));
    }

    fd = open(argv[1], O_RDONLY);
    if(fd < 0)
    {
        printf("Cannot open %s: %s\n", argv[1], strerror(errno));
        exit(-1);
    }

#if 1
    unsigned char* flash_id = get_flash_id(fd);
    printf("%x%x%x%x\n", flash_id[0], flash_id[1], flash_id[2], flash_id[3]);

    short x, y;
    get_lcd_param(fd, &x, &y);
    printf("%dx%d\n", x, y);

    unsigned char* d = get_version(fd);
    int i;
    for(i=0; i<0x40; i+=4)
        printf("%02x %02x %02x %02x %c %c %c %c\n",
               d[i], d[i+1], d[i+2], d[i+3],
               d[i], d[i+1], d[i+2], d[i+3]);
/*
    int i;
    unsigned char* d = get_version(fd);
    for(i=0; i<0x40; i+=4)
        printf("%02x %02x %02x %02x %c %c %c %c\n",
               d[i], d[i+1], d[i+2], d[i+3],
               d[i], d[i+1], d[i+2], d[i+3]);
    printf("%s", d);
*/

#else
    out = fopen("dump2.bin", "w");

    int i;
    unsigned char* data;
    for(i = 0; i<(2*1024*1024); i += 0x1000)
    {
        if((data = flash_read(fd, i, 0x1000)) == NULL)
            break;

        fwrite(data, 1, 0x1000, out);
    }

    fclose(out);
#endif
    close(fd);
}

CD 00 00 00 00 00 01 00 00 00 00 00 00 00 00 00 seems to give the string 'USBS' + some garbage

CB 00 00 00 00 00 01 00 00 00 06 00 00 00 00 00 is CProcessFlash::FlashWREN (write enable?)

Maurus Cuelenaere

image http://images43.fotosik.pl/327/e1539c3f70f1863bmed.jpg

OK I've just bough 2 of these 1.5 inch picture frames and they're using the AX203 for sure. I found the DPFMate program and when using the about it gives the same message as posted here before: About
I'm sure that AX203 is actually the same as CPF5102. Therefore I'm pretty sure all the code is in the OTP memory and there isn't any in the SPI attached flash chip. The only way to actually run some code on these frames according to the CPF5102 would be to attach an external memory and make the AX203 use only that ( pull some pin to low I think ). However this would prove too difficult I think given the fact that these pins aren't easily accessible. 
I do have another question , does anyone have any info about the LCD used. This seems to be the only thing that can be used, this and the battery. Where is the LCD controller for one ? Is it on the LCD glass somewhere because I couldn't see it on the PCB. Can the LCD be used for other projects ? Someone mentioned a 20 pin cable being used but I even saw some code posted online but I don't really understand why 20 pins are needed and how they are connected.

Marius


Marius, I've found a site that took the DPF and used it's LCD for a project, maybe you can get your info there LINK BinAm


I have a request , could anyone post a newer, Vista compatible, version of dpfmate.exe on www.speedyshare.com or some other site. @BinAm , thanks for the info. I'll look into it if I have some time. Marius

@Marius: Where does the flashlib.dat come from? Alex


Mine is the same, but with a glob-top IC. It has 1MB FLASH instead of 2MB. I found many things in my device:

Offset: 0x23 - Size: 16 bit - Description: LCD size (height?)

Offset: 0x25 - Size: 16 bit - Description: LCD size (width?)

Offset: 0x2F - Size: 16 bit - Description: FLASH size (in KB)

Offset: 0x40 - Size: 16 bytes (empty space filled with 0xFF) - Description: DPF Version (mine is "DPFv1.0")

Offset: 0x50 - Size: 16 bytes (empty space filled with 0xFF) - Description: Firmware Build date? (YYYYMMDD. mine is 20090113)

Offset: 0x60 - Size: 16 bytes (empty space filled with 0xFF) - Description: Manufacturing date? (mine is Jul 22 2010)

Offset: 0x70 - Size: 8 bytes - Description: Manufacturing time? (mine is 19:03:33)

Offset: in mine is 0x52A3, I think this can vary - Size: variable 0x00 terminated - Description: Firmware version (this what you can see on DPFMate About Window - mine is DPF_V3.5.0)

The Dump can be found right here: [1]

--Socram8888 19:42, 11 August 2010 (CEST)

Decoding and encoding of the images

Hi,

I've been working on writing software to actually use st2205 picture frames as picture frame under Linux (IOW download / upload / delete photos) to verify that my code worked with different devices I bought a few others which have .... an ax203 or some such chip.

So now I'm working on making download / upload / delete to those work under Linux too. The store I bought them had 2 versions, one which can hold 100 images and one which can hold 138 images.

The 100 images one uses a compression which compresses down to 1 byte per pixel and identifies itself as: usb 2-3: New USB device found, idVendor=1908, idProduct=1315 usb 2-3: New USB device strings: Mfr=1, Product=2, SerialNumber=0 usb 2-3: Product: Photo Frame usb 2-3: Manufacturer: BUILDWIN

Code for decoding and coding the images can be found here.

The 138 images one uses a compression which compresses down to 3/4 byte per pixel and identifies itself as: usb 2-3: new full speed USB device using ohci_hcd and address 5 usb 2-3: New USB device found, idVendor=1908, idProduct=1320 usb 2-3: New USB device strings: Mfr=1, Product=2, SerialNumber=0 usb 2-3: Product: Photo Frame usb 2-3: Manufacturer: BUILDWIN

This one has a "FAT" table starting at 0x50000, which contains:

0x50000 "ABFS\0"
0x50005 number of files in FAT
0x50020 pointers to files, 2 bytes per pointer 16 bits little endian actual address is contents of the uint16_t * 256. For example the first entry contains 0x20 0x05, so it points to address 0x052000

(I've not yet checked for a FAT on the 100 images one).

Code for decoding and coding the images can be found here.

More details on the scsi commands

SCSI Command structure: Always 16 bytes, padded with 00 bytes if needed to fill 16 bytes.

Known commands:

dir 00 00 00 00 00 cmdlen dlen16-23 dlen8-15 dlen0-7 cmdbyte0 .. cmdbyte5

Communicate directly to eeprom over SPI, this sends an EEPROM command of noargs bytes size, using arg0 .. arg5 as EEPROM command bytes and then sends (dir == CB) or receives (dir == CD) dlen bytes to / from the EEPROM. See the EEPROM data sheet for available commands.

CD 00 00 00 00 01 01 00 00 00 01 00 00 00 00 00

Get version string, receive upto 0x40 bytes, returned data is a 0 terminated string

CD 00 00 00 00 02 01 00 00 00 02 00 00 00 00 00

Get LCD information, receive 0x40 bytes, first 2 bytes received are the horizontal resolution in LSB order, the next 2 are the vertical resolution in LSB order.

HID mode

I have a Sweex MM004V5 which normally is detected by Linux as follows(dmesg output):

usb 1-1: New USB device found, idVendor=177f, idProduct=0004
usb 1-1: New USB device strings: Mfr=2, Product=3, SerialNumber=0
usb 1-1: Product: MM004V5 1.5" Digital Photo Key Chain
usb 1-1: Manufacturer: Sweex
usb-storage: device scan complete
scsi 7:0:0:0: CD-ROM            buildwin  Photo Frame     1.01 PQ: 0 ANSI: 2

But if the device is reset (with the recessed reset switch) while the Menu button is held in then the screen goes blank and Linux detects an HID device instead (dmesg output):

usb 1-1: new full speed USB device using uhci_hcd and address 12
usb 1-1: configuration #1 chosen from 1 choice
usbhid: timeout initializing reports
hiddev96hidraw0: USB HID v2.01 Device [BUILDWIN BL206v1.0.0] on usb-0000:00:10.0-1
usb 1-1: New USB device found, idVendor=1908, idProduct=3318
usb 1-1: New USB device strings: Mfr=2, Product=1, SerialNumber=3
usb 1-1: Product: BL206v1.0.0
usb 1-1: Manufacturer: BUILDWIN
usb 1-1: SerialNumber: 000001

Could be interesting!

Also the information at this page in Russian with the help of Google Translate looks useful.

Alex

Alex,

Interesting to hear that you have an ax205 based picture frame with an as of yet unknown ubs id. Can you see if uploading / downloading works with the libgphoto driver, see UsingAsPicframe. Note that you will need to edit camlibs/ax203/library.c to include your pictureframe. Your frame has v3.5 firmware.

Please let me know if the libgphoto driver works with your frame then I can add its usb-id to libgphoto.

Thanks,

Hans