Updated IAP commands.
Originally written and uploaded by Lalufu (Ralf Ertzinger) in Feb 2012. They have been condensed into a single patch and some further additions by Andy Potter. Currently includes Authentication V2 support from iPod to Accessory, RF/BlueTooth transmitter support, selecting a playlist and selecting a track from the current playlist. Does not support uploading Album Art or podcasts. Has been tested on the following iPods, 4th Gen Grayscale, 4th Gen Color/Photo, Mini 2nd Gen, Nano 1st Gen and Video 5.5Gen. Change-Id: Ie8fc098361844132f0228ecbe3c48da948726f5e Co-Authored by: Andy Potter <liveboxandy@gmail.com> Reviewed-on: http://gerrit.rockbox.org/533 Reviewed-by: Frank Gevaerts <frank@gevaerts.be>
This commit is contained in:
parent
500b137308
commit
b170c73f92
21 changed files with 10629 additions and 1125 deletions
|
@ -62,7 +62,11 @@ tagtree.c
|
|||
filetree.c
|
||||
scrobbler.c
|
||||
#ifdef IPOD_ACCESSORY_PROTOCOL
|
||||
iap.c
|
||||
iap/iap-core.c
|
||||
iap/iap-lingo0.c
|
||||
iap/iap-lingo2.c
|
||||
iap/iap-lingo3.c
|
||||
iap/iap-lingo4.c
|
||||
#endif
|
||||
|
||||
screen_access.c
|
||||
|
|
1110
apps/iap.c
1110
apps/iap.c
File diff suppressed because it is too large
Load diff
1392
apps/iap/iap-core.c
Normal file
1392
apps/iap/iap-core.c
Normal file
File diff suppressed because it is too large
Load diff
250
apps/iap/iap-core.h
Normal file
250
apps/iap/iap-core.h
Normal file
|
@ -0,0 +1,250 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2002 by Alan Korr & Nick Robinson
|
||||
*
|
||||
* All files in this archive are subject to the GNU General Public License.
|
||||
* See the file COPYING in the source tree root for full license agreement.
|
||||
*
|
||||
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
****************************************************************************/
|
||||
#ifndef _IAP_CORE_H
|
||||
#define _IAP_CORE_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include "timefuncs.h"
|
||||
#include "metadata.h"
|
||||
#include "playlist.h"
|
||||
#include "iap.h"
|
||||
|
||||
#define LOGF_ENABLE
|
||||
/* #undef LOGF_ENABLE */
|
||||
#ifdef LOGF_ENABLE
|
||||
#include "logf.h"
|
||||
#endif
|
||||
|
||||
/* The Model ID of the iPod we emulate. Currently a 160GB classic */
|
||||
#define IAP_IPOD_MODEL (0x00130200U)
|
||||
|
||||
/* The firmware version we emulate. Currently 2.0.3 */
|
||||
#define IAP_IPOD_FIRMWARE_MAJOR (2)
|
||||
#define IAP_IPOD_FIRMWARE_MINOR (0)
|
||||
#define IAP_IPOD_FIRMWARE_REV (3)
|
||||
|
||||
/* Status code for IAP ack messages */
|
||||
#define IAP_ACK_OK (0x00) /* Success */
|
||||
#define IAP_ACK_UNKNOWN_DB (0x01) /* Unknown Database Category */
|
||||
#define IAP_ACK_CMD_FAILED (0x02) /* Command failed */
|
||||
#define IAP_ACK_NO_RESOURCE (0x03) /* Out of resources */
|
||||
#define IAP_ACK_BAD_PARAM (0x04) /* Bad parameter */
|
||||
#define IAP_ACK_UNKNOWN_ID (0x05) /* Unknown ID */
|
||||
#define IAP_ACK_PENDING (0x06) /* Command pending */
|
||||
#define IAP_ACK_NO_AUTHEN (0x07) /* Not authenticated */
|
||||
#define IAP_ACK_BAD_AUTHEN (0x08) /* Bad authentication version */
|
||||
/* 0x09 reserved */
|
||||
#define IAP_ACK_CERT_INVAL (0x0A) /* Certificate invalid */
|
||||
#define IAP_ACK_CERT_PERM (0x0B) /* Certificate permissions invalid */
|
||||
/* 0x0C-0x10 reserved */
|
||||
#define IAP_ACK_RES_INVAL (0x11) /* Invalid accessory resistor value */
|
||||
|
||||
/* Add a button to the remote button bitfield. Also set iap_repeatbtn=1
|
||||
* to ensure a button press is at least delivered once.
|
||||
*/
|
||||
#define REMOTE_BUTTON(x) do { \
|
||||
iap_remotebtn |= (x); \
|
||||
iap_timeoutbtn = 3; \
|
||||
iap_repeatbtn = 2; \
|
||||
} while(0)
|
||||
|
||||
/* States of the extended command support */
|
||||
enum interface_state {
|
||||
IST_STANDARD, /* General state, support lingo 0x00 commands */
|
||||
IST_EXTENDED, /* Extended Interface lingo (0x04) negotiated */
|
||||
};
|
||||
|
||||
/* States of the authentication state machine */
|
||||
enum authen_state {
|
||||
AUST_NONE, /* Initial state, no message sent */
|
||||
AUST_INIT, /* Remote side has requested authentication */
|
||||
AUST_CERTREQ, /* Remote certificate requested */
|
||||
AUST_CERTBEG, /* Certificate is being received */
|
||||
AUST_CERTDONE, /* Certificate received */
|
||||
AUST_CHASENT, /* Challenge sent */
|
||||
AUST_CHADONE, /* Challenge response received */
|
||||
AUST_AUTH, /* Authentication complete */
|
||||
};
|
||||
|
||||
/* State of authentication */
|
||||
struct auth_t {
|
||||
enum authen_state state; /* Current state of authentication */
|
||||
unsigned char max_section; /* The maximum number of certificate sections */
|
||||
unsigned char next_section; /* The next expected section number */
|
||||
};
|
||||
|
||||
/* State of GetAccessoryInfo */
|
||||
enum accinfo_state {
|
||||
ACCST_NONE, /* Initial state, no message sent */
|
||||
ACCST_INIT, /* Send out initial GetAccessoryInfo */
|
||||
ACCST_SENT, /* Wait for initial RetAccessoryInfo */
|
||||
ACCST_DATA, /* Query device information, according to capabilities */
|
||||
};
|
||||
|
||||
/* A struct describing an attached device and it's current
|
||||
* state
|
||||
*/
|
||||
struct device_t {
|
||||
struct auth_t auth; /* Authentication state */
|
||||
enum accinfo_state accinfo; /* Accessory information state */
|
||||
uint32_t lingoes; /* Negotiated lingoes */
|
||||
uint32_t notifications; /* Requested notifications. These are just the
|
||||
* notifications explicitly requested by the
|
||||
* device
|
||||
*/
|
||||
uint32_t changed_notifications; /* Tracks notifications that changed since the last
|
||||
* call to SetRemoteEventNotification or GetRemoteEventStatus
|
||||
*/
|
||||
bool do_notify; /* Notifications enabled */
|
||||
bool do_power_notify; /* Whether to send power change notifications.
|
||||
* These are sent automatically to all devices
|
||||
* that used IdentifyDeviceLingoes to identify
|
||||
* themselves, independent of other notifications
|
||||
*/
|
||||
|
||||
uint32_t trackpos_ms; /* These fields are to save the current state */
|
||||
uint32_t track_index; /* of various fields so we can send a notification */
|
||||
uint32_t chapter_index; /* if they change */
|
||||
unsigned char play_status;
|
||||
bool mute;
|
||||
unsigned char volume;
|
||||
unsigned char power_state;
|
||||
unsigned char battery_level;
|
||||
uint32_t equalizer_index;
|
||||
unsigned char shuffle;
|
||||
unsigned char repeat;
|
||||
struct tm datetime;
|
||||
unsigned char alarm_state;
|
||||
unsigned char alarm_hour;
|
||||
unsigned char alarm_minute;
|
||||
unsigned char backlight;
|
||||
bool hold;
|
||||
unsigned char soundcheck;
|
||||
unsigned char audiobook;
|
||||
uint16_t trackpos_s;
|
||||
uint32_t capabilities; /* Capabilities of the device, as returned by type 0
|
||||
* of GetAccessoryInfo
|
||||
*/
|
||||
uint32_t capabilities_queried; /* Capabilities already queried */
|
||||
};
|
||||
|
||||
extern struct device_t device;
|
||||
#define DEVICE_AUTHENTICATED (device.auth.state == AUST_AUTH)
|
||||
#define DEVICE_AUTH_RUNNING ((device.auth.state != AUST_NONE) && (device.auth.state != AUST_AUTH))
|
||||
#define DEVICE_LINGO_SUPPORTED(x) (device.lingoes & BIT_N((x)&0x1f))
|
||||
|
||||
extern unsigned long iap_remotebtn;
|
||||
extern unsigned int iap_timeoutbtn;
|
||||
extern int iap_repeatbtn;
|
||||
|
||||
extern unsigned char* iap_txpayload;
|
||||
extern unsigned char* iap_txnext;
|
||||
|
||||
/* These are a number of helper macros to manage the dynamic TX buffer content
|
||||
* These macros DO NOT CHECK for buffer overflow. iap_send_tx() will, but
|
||||
* it might be too late at that point. See the current size of TX_BUFLEN
|
||||
*/
|
||||
|
||||
/* Initialize the TX buffer with a lingo and command ID. This will reset the
|
||||
* data pointer, effectively invalidating unsent information in the TX buffer.
|
||||
* There are two versions of this, one for 1 byte command IDs (all Lingoes except
|
||||
* 0x04) and one for two byte command IDs (Lingo 0x04)
|
||||
*/
|
||||
#define IAP_TX_INIT(lingo, command) do { \
|
||||
iap_txnext = iap_txpayload; \
|
||||
IAP_TX_PUT((lingo)); \
|
||||
IAP_TX_PUT((command)); \
|
||||
} while (0)
|
||||
|
||||
#define IAP_TX_INIT4(lingo, command) do { \
|
||||
iap_txnext = iap_txpayload; \
|
||||
IAP_TX_PUT((lingo)); \
|
||||
IAP_TX_PUT_U16((command)); \
|
||||
} while (0)
|
||||
|
||||
/* Put an unsigned char into the TX buffer */
|
||||
#define IAP_TX_PUT(data) *(iap_txnext++) = (data)
|
||||
|
||||
/* Put a 16bit unsigned quantity into the TX buffer */
|
||||
#define IAP_TX_PUT_U16(data) do { \
|
||||
put_u16(iap_txnext, (data)); \
|
||||
iap_txnext += 2; \
|
||||
} while (0)
|
||||
|
||||
/* Put a 32bit unsigned quantity into the TX buffer */
|
||||
#define IAP_TX_PUT_U32(data) do { \
|
||||
put_u32(iap_txnext, (data)); \
|
||||
iap_txnext += 4; \
|
||||
} while (0)
|
||||
|
||||
/* Put an arbitrary amount of data (identified by a char pointer and
|
||||
* a length) into the TX buffer
|
||||
*/
|
||||
#define IAP_TX_PUT_DATA(data, len) do { \
|
||||
memcpy(iap_txnext, (unsigned char *)(data), (len)); \
|
||||
iap_txnext += (len); \
|
||||
} while(0)
|
||||
|
||||
/* Put a NULL terminated string into the TX buffer, including the
|
||||
* NULL byte
|
||||
*/
|
||||
#define IAP_TX_PUT_STRING(str) IAP_TX_PUT_DATA((str), strlen((str))+1)
|
||||
|
||||
/* Put a NULL terminated string into the TX buffer, taking care not to
|
||||
* overflow the buffer. If the string does not fit into the TX buffer
|
||||
* it will be truncated, but always NULL terminated.
|
||||
*
|
||||
* This function is expensive compared to the other IAP_TX_PUT_*
|
||||
* functions
|
||||
*/
|
||||
#define IAP_TX_PUT_STRLCPY(str) iap_tx_strlcpy(str)
|
||||
|
||||
extern unsigned char lingo_versions[32][2];
|
||||
#define LINGO_SUPPORTED(x) (LINGO_MAJOR((x)&0x1f) > 0)
|
||||
#define LINGO_MAJOR(x) (lingo_versions[(x)&0x1f][0])
|
||||
#define LINGO_MINOR(x) (lingo_versions[(x)&0x1f][1])
|
||||
|
||||
void put_u16(unsigned char *buf, const uint16_t data);
|
||||
void put_u32(unsigned char *buf, const uint32_t data);
|
||||
uint32_t get_u32(const unsigned char *buf);
|
||||
uint16_t get_u16(const unsigned char *buf);
|
||||
void iap_tx_strlcpy(const unsigned char *str);
|
||||
|
||||
void iap_reset_auth(struct auth_t* auth);
|
||||
void iap_reset_device(struct device_t* device);
|
||||
|
||||
void iap_shuffle_state(bool state);
|
||||
void iap_repeat_state(unsigned char state);
|
||||
void iap_repeat_next(void);
|
||||
void iap_fill_power_state(void);
|
||||
|
||||
void iap_send_tx(void);
|
||||
|
||||
extern enum interface_state interface_state;
|
||||
void iap_interface_state_change(const enum interface_state new);
|
||||
|
||||
extern bool iap_btnrepeat;
|
||||
extern bool iap_btnshuffle;
|
||||
|
||||
uint32_t iap_get_trackpos(void);
|
||||
uint32_t iap_get_trackindex(void);
|
||||
void iap_get_trackinfo(const unsigned int track, struct mp3entry* id3);
|
||||
|
||||
#endif
|
23
apps/iap/iap-lingo.h
Normal file
23
apps/iap/iap-lingo.h
Normal file
|
@ -0,0 +1,23 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2002 by Alan Korr & Nick Robinson
|
||||
*
|
||||
* All files in this archive are subject to the GNU General Public License.
|
||||
* See the file COPYING in the source tree root for full license agreement.
|
||||
*
|
||||
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
void iap_handlepkt_mode0(const unsigned int len, const unsigned char *buf);
|
||||
void iap_handlepkt_mode2(const unsigned int len, const unsigned char *buf);
|
||||
void iap_handlepkt_mode3(const unsigned int len, const unsigned char *buf);
|
||||
void iap_handlepkt_mode4(const unsigned int len, const unsigned char *buf);
|
1035
apps/iap/iap-lingo0.c
Normal file
1035
apps/iap/iap-lingo0.c
Normal file
File diff suppressed because it is too large
Load diff
278
apps/iap/iap-lingo2.c
Normal file
278
apps/iap/iap-lingo2.c
Normal file
|
@ -0,0 +1,278 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2002 by Alan Korr & Nick Robinson
|
||||
*
|
||||
* All files in this archive are subject to the GNU General Public License.
|
||||
* See the file COPYING in the source tree root for full license agreement.
|
||||
*
|
||||
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
/* Lingo 0x02, Simple Remote Lingo
|
||||
*
|
||||
* TODO:
|
||||
* - Fix cmd 0x00 handling, there has to be a more elegant way of doing
|
||||
* this
|
||||
*/
|
||||
|
||||
#include "iap-core.h"
|
||||
#include "iap-lingo.h"
|
||||
#include "system.h"
|
||||
#include "button.h"
|
||||
#include "audio.h"
|
||||
#include "settings.h"
|
||||
|
||||
/*
|
||||
* This macro is meant to be used inside an IAP mode message handler.
|
||||
* It is passed the expected minimum length of the message buffer.
|
||||
* If the buffer does not have the required lenght an ACK
|
||||
* packet with a Bad Parameter error is generated.
|
||||
*/
|
||||
#define CHECKLEN(x) do { \
|
||||
if (len < (x)) { \
|
||||
cmd_ack(cmd, IAP_ACK_BAD_PARAM); \
|
||||
return; \
|
||||
}} while(0)
|
||||
|
||||
static void cmd_ack(const unsigned char cmd, const unsigned char status)
|
||||
{
|
||||
IAP_TX_INIT(0x02, 0x01);
|
||||
IAP_TX_PUT(status);
|
||||
IAP_TX_PUT(cmd);
|
||||
|
||||
iap_send_tx();
|
||||
}
|
||||
|
||||
#define cmd_ok(cmd) cmd_ack((cmd), IAP_ACK_OK)
|
||||
|
||||
void iap_handlepkt_mode2(const unsigned int len, const unsigned char *buf)
|
||||
{
|
||||
unsigned int cmd = buf[1];
|
||||
|
||||
/* We expect at least three bytes in the buffer, one for the
|
||||
* lingo, one for the command, and one for the first button
|
||||
* state bits.
|
||||
*/
|
||||
CHECKLEN(3);
|
||||
|
||||
/* Lingo 0x02 must have been negotiated */
|
||||
if (!DEVICE_LINGO_SUPPORTED(0x02)) {
|
||||
cmd_ack(cmd, IAP_ACK_BAD_PARAM);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (cmd)
|
||||
{
|
||||
/* ContextButtonStatus (0x00)
|
||||
*
|
||||
* Transmit button events from the device to the iPod
|
||||
*
|
||||
* Packet format (offset in buf[]: Description)
|
||||
* 0x00: Lingo ID: Simple Remote Lingo, always 0x02
|
||||
* 0x01: Command, always 0x00
|
||||
* 0x02: Button states 0:7
|
||||
* 0x03: Button states 8:15 (optional)
|
||||
* 0x04: Button states 16:23 (optional)
|
||||
* 0x05: Button states 24:31 (optional)
|
||||
*
|
||||
* Returns: (none)
|
||||
*/
|
||||
case 0x00:
|
||||
{
|
||||
iap_remotebtn = BUTTON_NONE;
|
||||
iap_timeoutbtn = 0;
|
||||
|
||||
if(buf[2] != 0)
|
||||
{
|
||||
if(buf[2] & 1)
|
||||
REMOTE_BUTTON(BUTTON_RC_PLAY);
|
||||
if(buf[2] & 2)
|
||||
REMOTE_BUTTON(BUTTON_RC_VOL_UP);
|
||||
if(buf[2] & 4)
|
||||
REMOTE_BUTTON(BUTTON_RC_VOL_DOWN);
|
||||
if(buf[2] & 8)
|
||||
REMOTE_BUTTON(BUTTON_RC_RIGHT);
|
||||
if(buf[2] & 16)
|
||||
REMOTE_BUTTON(BUTTON_RC_LEFT);
|
||||
}
|
||||
else if(len >= 4 && buf[3] != 0)
|
||||
{
|
||||
if(buf[3] & 1) /* play */
|
||||
{
|
||||
if (audio_status() != AUDIO_STATUS_PLAY)
|
||||
REMOTE_BUTTON(BUTTON_RC_PLAY);
|
||||
}
|
||||
if(buf[3] & 2) /* pause */
|
||||
{
|
||||
if (audio_status() == AUDIO_STATUS_PLAY)
|
||||
REMOTE_BUTTON(BUTTON_RC_PLAY);
|
||||
}
|
||||
if(buf[3] & 128) /* Shuffle */
|
||||
{
|
||||
if (!iap_btnshuffle)
|
||||
{
|
||||
iap_shuffle_state(!global_settings.playlist_shuffle);
|
||||
iap_btnshuffle = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(len >= 5 && buf[4] != 0)
|
||||
{
|
||||
if(buf[4] & 1) /* repeat */
|
||||
{
|
||||
if (!iap_btnrepeat)
|
||||
{
|
||||
iap_repeat_next();
|
||||
iap_btnrepeat = true;
|
||||
}
|
||||
}
|
||||
|
||||
/* Power off
|
||||
* Not quite sure how to react to this, but stopping playback
|
||||
* is a good start.
|
||||
*/
|
||||
if (buf[4] & 0x04)
|
||||
{
|
||||
if (audio_status() == AUDIO_STATUS_PLAY)
|
||||
REMOTE_BUTTON(BUTTON_RC_PLAY);
|
||||
}
|
||||
|
||||
if(buf[4] & 16) /* ffwd */
|
||||
REMOTE_BUTTON(BUTTON_RC_RIGHT);
|
||||
if(buf[4] & 32) /* frwd */
|
||||
REMOTE_BUTTON(BUTTON_RC_LEFT);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
/* ACK (0x01)
|
||||
*
|
||||
* Sent from the iPod to the device
|
||||
*/
|
||||
|
||||
/* ImageButtonStatus (0x02)
|
||||
*
|
||||
* Transmit image button events from the device to the iPod
|
||||
*
|
||||
* Packet format (offset in buf[]: Description)
|
||||
* 0x00: Lingo ID: Simple Remote Lingo, always 0x02
|
||||
* 0x01: Command, always 0x02
|
||||
* 0x02: Button states 0:7
|
||||
* 0x03: Button states 8:15 (optional)
|
||||
* 0x04: Button states 16:23 (optional)
|
||||
* 0x05: Button states 24:31 (optional)
|
||||
*
|
||||
* This command requires authentication
|
||||
*
|
||||
* Returns on success:
|
||||
* IAP_ACK_OK
|
||||
*
|
||||
* Returns on failure:
|
||||
* IAP_ACK_*
|
||||
*/
|
||||
case 0x02:
|
||||
{
|
||||
if (!DEVICE_AUTHENTICATED) {
|
||||
cmd_ack(cmd, IAP_ACK_NO_AUTHEN);
|
||||
break;
|
||||
}
|
||||
|
||||
cmd_ack(cmd, IAP_ACK_CMD_FAILED);
|
||||
break;
|
||||
}
|
||||
|
||||
/* VideoButtonStatus (0x03)
|
||||
*
|
||||
* Transmit video button events from the device to the iPod
|
||||
*
|
||||
* Packet format (offset in buf[]: Description)
|
||||
* 0x00: Lingo ID: Simple Remote Lingo, always 0x02
|
||||
* 0x01: Command, always 0x03
|
||||
* 0x02: Button states 0:7
|
||||
* 0x03: Button states 8:15 (optional)
|
||||
* 0x04: Button states 16:23 (optional)
|
||||
* 0x05: Button states 24:31 (optional)
|
||||
*
|
||||
* This command requires authentication
|
||||
*
|
||||
* Returns on success:
|
||||
* IAP_ACK_OK
|
||||
*
|
||||
* Returns on failure:
|
||||
* IAP_ACK_*
|
||||
*/
|
||||
case 0x03:
|
||||
{
|
||||
if (!DEVICE_AUTHENTICATED) {
|
||||
cmd_ack(cmd, IAP_ACK_NO_AUTHEN);
|
||||
break;
|
||||
}
|
||||
|
||||
cmd_ack(cmd, IAP_ACK_CMD_FAILED);
|
||||
break;
|
||||
}
|
||||
|
||||
/* AudioButtonStatus (0x04)
|
||||
*
|
||||
* Transmit audio button events from the device to the iPod
|
||||
*
|
||||
* Packet format (offset in buf[]: Description)
|
||||
* 0x00: Lingo ID: Simple Remote Lingo, always 0x02
|
||||
* 0x01: Command, always 0x04
|
||||
* 0x02: Button states 0:7
|
||||
* 0x03: Button states 8:15 (optional)
|
||||
* 0x04: Button states 16:23 (optional)
|
||||
* 0x05: Button states 24:31 (optional)
|
||||
*
|
||||
* This command requires authentication
|
||||
*
|
||||
* Returns on success:
|
||||
* IAP_ACK_OK
|
||||
*
|
||||
* Returns on failure:
|
||||
* IAP_ACK_*
|
||||
*/
|
||||
case 0x04:
|
||||
{
|
||||
unsigned char repeatbuf[6];
|
||||
|
||||
if (!DEVICE_AUTHENTICATED) {
|
||||
cmd_ack(cmd, IAP_ACK_NO_AUTHEN);
|
||||
break;
|
||||
}
|
||||
|
||||
/* This is basically the same command as ContextButtonStatus (0x00),
|
||||
* with the difference that it requires authentication and that
|
||||
* it returns an ACK packet to the device.
|
||||
* So just route it through the handler again, with 0x00 as the
|
||||
* command
|
||||
*/
|
||||
memcpy(repeatbuf, buf, 6);
|
||||
repeatbuf[1] = 0x00;
|
||||
iap_handlepkt_mode2((len<6)?len:6, repeatbuf);
|
||||
|
||||
cmd_ok(cmd);
|
||||
break;
|
||||
}
|
||||
|
||||
/* The default response is IAP_ACK_BAD_PARAM */
|
||||
default:
|
||||
{
|
||||
#ifdef LOGF_ENABLE
|
||||
logf("iap: Unsupported Mode02 Command");
|
||||
#else
|
||||
cmd_ack(cmd, IAP_ACK_BAD_PARAM);
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
1508
apps/iap/iap-lingo3.c
Normal file
1508
apps/iap/iap-lingo3.c
Normal file
File diff suppressed because it is too large
Load diff
3153
apps/iap/iap-lingo4.c
Normal file
3153
apps/iap/iap-lingo4.c
Normal file
File diff suppressed because it is too large
Load diff
|
@ -607,14 +607,6 @@ long default_event_handler_ex(long event, void (*callback)(void *), void *parame
|
|||
unplug_change(false);
|
||||
return SYS_PHONE_UNPLUGGED;
|
||||
#endif
|
||||
#ifdef IPOD_ACCESSORY_PROTOCOL
|
||||
case SYS_IAP_PERIODIC:
|
||||
iap_periodic();
|
||||
return SYS_IAP_PERIODIC;
|
||||
case SYS_IAP_HANDLEPKT:
|
||||
iap_handlepkt();
|
||||
return SYS_IAP_HANDLEPKT;
|
||||
#endif
|
||||
#if CONFIG_PLATFORM & (PLATFORM_ANDROID|PLATFORM_MAEMO)
|
||||
/* stop playback if we receive a call */
|
||||
case SYS_CALL_INCOMING:
|
||||
|
|
|
@ -22,7 +22,9 @@
|
|||
|
||||
#include <stdbool.h>
|
||||
|
||||
#define RX_BUFLEN 512
|
||||
/* This is just the payload size, without sync, length and checksum */
|
||||
#define RX_BUFLEN (64*1024)
|
||||
/* This is the entire frame length, sync, length, payload and checksum */
|
||||
#define TX_BUFLEN 128
|
||||
|
||||
extern bool iap_getc(unsigned char x);
|
||||
|
|
|
@ -79,8 +79,6 @@
|
|||
#define SYS_REMOTE_PLUGGED MAKE_SYS_EVENT(SYS_EVENT_CLS_PLUG, 4)
|
||||
#define SYS_REMOTE_UNPLUGGED MAKE_SYS_EVENT(SYS_EVENT_CLS_PLUG, 5)
|
||||
#define SYS_CAR_ADAPTER_RESUME MAKE_SYS_EVENT(SYS_EVENT_CLS_MISC, 0)
|
||||
#define SYS_IAP_PERIODIC MAKE_SYS_EVENT(SYS_EVENT_CLS_MISC, 1)
|
||||
#define SYS_IAP_HANDLEPKT MAKE_SYS_EVENT(SYS_EVENT_CLS_MISC, 2)
|
||||
#define SYS_CALL_INCOMING MAKE_SYS_EVENT(SYS_EVENT_CLS_MISC, 3)
|
||||
#define SYS_CALL_HUNG_UP MAKE_SYS_EVENT(SYS_EVENT_CLS_MISC, 4)
|
||||
#define SYS_VOLUME_CHANGED MAKE_SYS_EVENT(SYS_EVENT_CLS_MISC, 5)
|
||||
|
|
|
@ -155,9 +155,12 @@ bool dbg_ports(void)
|
|||
|
||||
#if defined(IPOD_ACCESSORY_PROTOCOL)
|
||||
const unsigned char *serbuf = iap_get_serbuf();
|
||||
lcd_putsf(0, line++, "IAP: %02x %02x %02x %02x %02x %02x %02x %02x",
|
||||
serbuf[0], serbuf[1], serbuf[2], serbuf[3], serbuf[4], serbuf[5],
|
||||
serbuf[6], serbuf[7]);
|
||||
if (serbuf)
|
||||
{
|
||||
lcd_putsf(0, line++, "IAP: %02x %02x %02x %02x %02x %02x %02x %02x",
|
||||
serbuf[0], serbuf[1], serbuf[2], serbuf[3], serbuf[4], serbuf[5],
|
||||
serbuf[6], serbuf[7]);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(IRIVER_H10) || defined(IRIVER_H10_5GB)
|
||||
|
|
386
tools/iap/Device/iPod.pm
Normal file
386
tools/iap/Device/iPod.pm
Normal file
|
@ -0,0 +1,386 @@
|
|||
package Device::iPod;
|
||||
|
||||
use Device::SerialPort;
|
||||
use POSIX qw(isgraph);
|
||||
use strict;
|
||||
|
||||
sub new {
|
||||
my $class = shift;
|
||||
my $port = shift;
|
||||
my $self = {};
|
||||
my $s;
|
||||
|
||||
$self->{-serial} = undef;
|
||||
$self->{-inbuf} = '';
|
||||
$self->{-error} = undef;
|
||||
$self->{-baudrate} = 57600;
|
||||
$self->{-debug} = 0;
|
||||
|
||||
return bless($self, $class);
|
||||
}
|
||||
|
||||
sub open {
|
||||
my $self = shift;
|
||||
my $port = shift;
|
||||
|
||||
$self->{-serial} = new Device::SerialPort($port);
|
||||
unless(defined($self->{-serial})) {
|
||||
$self->{-error} = $!;
|
||||
return undef;
|
||||
}
|
||||
|
||||
$self->{-serial}->parity('none');
|
||||
$self->{-serial}->databits(8);
|
||||
$self->{-serial}->stopbits(1);
|
||||
$self->{-serial}->handshake('none');
|
||||
return $self->baudrate($self->{-baudrate});
|
||||
}
|
||||
|
||||
sub baudrate {
|
||||
my $self = shift;
|
||||
my $baudrate = shift;
|
||||
|
||||
if ($baudrate < 1) {
|
||||
$self->{-error} = "Invalid baudrate";
|
||||
return undef;
|
||||
}
|
||||
|
||||
$self->{-baudrate} = $baudrate;
|
||||
if (defined($self->{-serial})) {
|
||||
$self->{-serial}->baudrate($baudrate);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
sub sendmsg {
|
||||
my $self = shift;
|
||||
my $lingo = shift;
|
||||
my $command = shift;
|
||||
my $data = shift || '';
|
||||
|
||||
return $self->_nosetup() unless(defined($self->{-serial}));
|
||||
|
||||
if (($lingo < 0) || ($lingo > 255)) {
|
||||
$self->{-error} = 'Invalid lingo';
|
||||
return undef;
|
||||
}
|
||||
|
||||
if ($command < 0) {
|
||||
$self->{-error} = 'Invalid command';
|
||||
return undef;
|
||||
}
|
||||
|
||||
if ($lingo == 4) {
|
||||
if ($command > 0xffff) {
|
||||
$self->{-error} = 'Invalid command';
|
||||
return undef;
|
||||
}
|
||||
return $self->_send($self->_frame_cmd(pack("Cn", $lingo, $command) . $data));
|
||||
} else {
|
||||
if ($command > 0xff) {
|
||||
$self->{-error} = 'Invalid command';
|
||||
return undef;
|
||||
}
|
||||
return $self->_send($self->_frame_cmd(pack("CC", $lingo, $command) . $data));
|
||||
}
|
||||
}
|
||||
|
||||
sub sendraw {
|
||||
my $self = shift;
|
||||
my $data = shift;
|
||||
|
||||
return $self->_nosetup() unless(defined($self->{-serial}));
|
||||
|
||||
return $self->_send($data);
|
||||
}
|
||||
|
||||
sub recvmsg {
|
||||
my $self = shift;
|
||||
my $m;
|
||||
my @m;
|
||||
|
||||
return $self->_nosetup() unless(defined($self->{-serial}));
|
||||
|
||||
$m = $self->_fillbuf();
|
||||
unless(defined($m)) {
|
||||
# Error was set by lower levels
|
||||
return wantarray?():undef;
|
||||
}
|
||||
|
||||
printf("Fetched %s\n", $self->_hexstring($m)) if $self->{-debug};
|
||||
|
||||
@m = $self->_unframe_cmd($m);
|
||||
|
||||
unless(@m) {
|
||||
return undef;
|
||||
}
|
||||
|
||||
if (wantarray()) {
|
||||
return @m;
|
||||
} else {
|
||||
return {-lingo => $m[0], -cmd => $m[1], -payload => $m[2]};
|
||||
}
|
||||
}
|
||||
|
||||
sub emptyrecv {
|
||||
my $self = shift;
|
||||
my $m;
|
||||
|
||||
while ($m = $self->_fillbuf()) {
|
||||
printf("Discarded %s\n", $self->_hexstring($m)) if (defined($m) && $self->{-debug});
|
||||
}
|
||||
}
|
||||
|
||||
sub error {
|
||||
my $self = shift;
|
||||
|
||||
return $self->{-error};
|
||||
}
|
||||
|
||||
sub _nosetup {
|
||||
my $self = shift;
|
||||
|
||||
$self->{-error} = 'Serial port not setup';
|
||||
return undef;
|
||||
}
|
||||
|
||||
sub _frame_cmd {
|
||||
my $self = shift;
|
||||
my $data = shift;
|
||||
my $l = length($data);
|
||||
my $csum;
|
||||
|
||||
if ($l > 0xffff) {
|
||||
$self->{-error} = 'Command too long';
|
||||
return undef;
|
||||
}
|
||||
|
||||
if ($l > 255) {
|
||||
$data = pack("Cn", 0, length($data)) . $data;
|
||||
} else {
|
||||
$data = pack("C", length($data)) . $data;
|
||||
}
|
||||
|
||||
foreach (unpack("C" x length($data), $data)) {
|
||||
$csum += $_;
|
||||
}
|
||||
$csum &= 0xFF;
|
||||
$csum = 0x100 - $csum;
|
||||
|
||||
return "\xFF\x55" . $data . pack("C", $csum);
|
||||
}
|
||||
|
||||
sub _unframe_cmd {
|
||||
my $self = shift;
|
||||
my $data = shift;
|
||||
my $payload = '';
|
||||
my ($count, $length, $csum);
|
||||
my $state = 0;
|
||||
my $c;
|
||||
my ($lingo, $cmd);
|
||||
|
||||
return () unless(defined($data));
|
||||
|
||||
foreach $c (unpack("C" x length($data), $data)) {
|
||||
if ($state == 0) {
|
||||
# Wait for sync
|
||||
next unless($c == 255);
|
||||
$state = 1;
|
||||
} elsif ($state == 1) {
|
||||
# Wait for sop
|
||||
next unless($c == 85);
|
||||
$state = 2;
|
||||
} elsif ($state == 2) {
|
||||
# Length (short frame)
|
||||
$csum = $c;
|
||||
if ($c == 0) {
|
||||
# Large frame
|
||||
$state = 3;
|
||||
} else {
|
||||
$state = 5;
|
||||
}
|
||||
$length = $c;
|
||||
$count = 0;
|
||||
next;
|
||||
} elsif ($state == 3) {
|
||||
# Large frame, hi
|
||||
$csum += $c;
|
||||
$length = ($c << 8);
|
||||
$state = 4;
|
||||
next;
|
||||
} elsif ($state == 4) {
|
||||
# Large frame, lo
|
||||
$csum += $c;
|
||||
$length |= $c;
|
||||
if ($length == 0) {
|
||||
$self->{-error} = 'Length is 0';
|
||||
return ();
|
||||
}
|
||||
$state = 5;
|
||||
next;
|
||||
} elsif ($state == 5) {
|
||||
# Data bytes
|
||||
$csum += $c;
|
||||
$payload .= chr($c);
|
||||
$count += 1;
|
||||
if ($count == $length) {
|
||||
$state = 6;
|
||||
}
|
||||
} elsif ($state == 6) {
|
||||
# Checksum byte
|
||||
$csum += $c;
|
||||
if (($csum & 0xFF) != 0) {
|
||||
$self->{-error} = 'Invalid checksum';
|
||||
return ();
|
||||
}
|
||||
$state = 7;
|
||||
last;
|
||||
} else {
|
||||
$self->{-error} = 'Invalid state';
|
||||
return ();
|
||||
}
|
||||
}
|
||||
|
||||
# If we get here, we either have data or not. Check.
|
||||
if ($state != 7) {
|
||||
$self->{-error} = 'Could not unframe data';
|
||||
return ();
|
||||
}
|
||||
|
||||
$lingo = unpack("C", $payload);
|
||||
if ($lingo == 4) {
|
||||
return unpack("Cna*", $payload);
|
||||
} else {
|
||||
return unpack("CCa*", $payload);
|
||||
}
|
||||
}
|
||||
|
||||
sub _send {
|
||||
my $self = shift;
|
||||
my $data = shift;
|
||||
my $l = length($data);
|
||||
my $c;
|
||||
|
||||
printf("Sending %s\n", $self->_hexstring($data)) if $self->{-debug};
|
||||
|
||||
$c = $self->{-serial}->write($data);
|
||||
unless(defined($c)) {
|
||||
$self->{-error} = 'write failed';
|
||||
return undef;
|
||||
}
|
||||
|
||||
if ($c != $l) {
|
||||
$self->{-error} = 'incomplete write';
|
||||
return undef;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
sub _fillbuf {
|
||||
my $self = shift;
|
||||
my $timeout = shift || 2;
|
||||
my $to;
|
||||
|
||||
# Read from the port until we have a complete message in the buffer,
|
||||
# or until we haven't read any new data for $timeout seconds, whatever
|
||||
# comes first.
|
||||
|
||||
$to = $timeout;
|
||||
|
||||
while(!$self->_message_in_buffer() && $to > 0) {
|
||||
my ($c, $s) = $self->{-serial}->read(255);
|
||||
if ($c == 0) {
|
||||
# No data read
|
||||
select(undef, undef, undef, 0.1);
|
||||
$to -= 0.1;
|
||||
} else {
|
||||
$self->{-inbuf} .= $s;
|
||||
$to = $timeout;
|
||||
}
|
||||
}
|
||||
if ($self->_message_in_buffer()) {
|
||||
# There is a complete message in the buffer
|
||||
return $self->_message();
|
||||
} else {
|
||||
# Timeout occured
|
||||
$self->{-error} = 'Timeout reading from port';
|
||||
return undef;
|
||||
}
|
||||
}
|
||||
|
||||
sub _message_in_buffer {
|
||||
my $self = shift;
|
||||
my $sp = 0;
|
||||
my $i;
|
||||
|
||||
$i = index($self->{-inbuf}, "\xFF\x55", $sp);
|
||||
while ($i != -1) {
|
||||
my $header;
|
||||
my $len;
|
||||
my $large = 0;
|
||||
|
||||
|
||||
$header = substr($self->{-inbuf}, $i, 3);
|
||||
if (length($header) != 3) {
|
||||
# Runt frame
|
||||
return ();
|
||||
}
|
||||
$len = unpack("x2C", $header);
|
||||
if ($len == 0) {
|
||||
# Possible large frame
|
||||
$header = substr($self->{-inbuf}, $i, 5);
|
||||
if (length($header) != 5) {
|
||||
# Runt frame
|
||||
return ();
|
||||
}
|
||||
$large = 1;
|
||||
$len = unpack("x3n", $header);
|
||||
}
|
||||
|
||||
# Add framing, checksum and length
|
||||
$len = $len+3+($large?3:1);
|
||||
|
||||
if (length($self->{-inbuf}) < ($i+$len)) {
|
||||
# Buffer too short to hold rest of frame. Try again.
|
||||
$sp = $i+1;
|
||||
$i = index($self->{-inbuf}, "\xFF\x55", $sp);
|
||||
} else {
|
||||
return ($i, $len);
|
||||
}
|
||||
}
|
||||
|
||||
# No complete message found
|
||||
return ();
|
||||
}
|
||||
|
||||
|
||||
sub _message {
|
||||
my $self = shift;
|
||||
my $start;
|
||||
my $len;
|
||||
my $m;
|
||||
|
||||
# Return the first complete message in the buffer, removing the message
|
||||
# and everything before it from the buffer.
|
||||
($start, $len) = $self->_message_in_buffer();
|
||||
unless(defined($start)) {
|
||||
$self->{-error} = 'No complete message in buffer';
|
||||
return undef;
|
||||
}
|
||||
$m = substr($self->{-inbuf}, $start, $len);
|
||||
$self->{-inbuf} = substr($self->{-inbuf}, $start+$len);
|
||||
|
||||
return $m;
|
||||
}
|
||||
|
||||
sub _hexstring {
|
||||
my $self = shift;
|
||||
my $s = shift;
|
||||
|
||||
return join("", map { (($_ == 0x20) || isgraph(chr($_)))?chr($_):sprintf("\\x%02x", $_) }
|
||||
unpack("C" x length($s), $s));
|
||||
}
|
||||
|
||||
1;
|
7
tools/iap/Makefile
Normal file
7
tools/iap/Makefile
Normal file
|
@ -0,0 +1,7 @@
|
|||
default: test
|
||||
|
||||
test:
|
||||
perl -MTest::Harness -e '$$Test::Harness::verbose=1; runtests @ARGV' ipod*.t
|
||||
|
||||
moduletest:
|
||||
perl -MTest::Harness -e '$$Test::Harness::verbose=1; runtests @ARGV' device-ipod.t
|
23
tools/iap/README
Normal file
23
tools/iap/README
Normal file
|
@ -0,0 +1,23 @@
|
|||
These are perl test scripts for validating the IAP implementation.
|
||||
Also included is a perl class for talking to an iPod via the serial
|
||||
port. You will probably need Linux to use this.
|
||||
|
||||
Run "make moduletest" to test the perl module itself. This will not
|
||||
require any serial connection, or even an iPod, for that matter.
|
||||
|
||||
Run "make test" to run the iPod communication tests themselves.
|
||||
|
||||
In order to test make sure
|
||||
|
||||
- the iPod is connected to a serial port
|
||||
- the test scripts assume that this port is /dev/ttyUSB0. Change
|
||||
as neccessary
|
||||
|
||||
Sometimes, tests will time out instead of giving the desired result.
|
||||
As long as the timeouts are not reproducable this is usually not a
|
||||
problem. The serial port is known to be unreliable, and devices will
|
||||
retransmit. This happens even with the OF.
|
||||
|
||||
The tests were designed against an iPod Touch 2G as a reference device.
|
||||
Some older iPods fail some of the test, even with the OF, because of
|
||||
behaviour changes in later firmware releases by Apple.
|
74
tools/iap/device-ipod.t
Normal file
74
tools/iap/device-ipod.t
Normal file
|
@ -0,0 +1,74 @@
|
|||
use Test::More qw( no_plan );
|
||||
use strict;
|
||||
|
||||
BEGIN { use_ok('Device::iPod'); }
|
||||
require_ok('Device::iPod');
|
||||
|
||||
my $ipod = Device::iPod->new();
|
||||
my $m;
|
||||
my ($l, $c, $p);
|
||||
|
||||
isa_ok($ipod, 'Device::iPod');
|
||||
|
||||
# Frame a short command
|
||||
$m = $ipod->_frame_cmd("\x00\x02\x00\x06");
|
||||
ok(defined($m) && ($m eq "\xFF\x55\x04\x00\x02\x00\x06\xF4"), "Framed command valid");
|
||||
|
||||
# Frame a long command
|
||||
$m = $ipod->_frame_cmd("\x00" x 1024);
|
||||
ok(defined($m) && ($m eq "\xFF\x55\x00\x04\x00" . ("\x00" x 1024) . "\xFC"), "Long framed command valid");
|
||||
|
||||
# Frame an overly long command
|
||||
$m = $ipod->_frame_cmd("\x00" x 65537);
|
||||
ok(!defined($m) && ($ipod->error() =~ 'Command too long'), "Overly long command failed");
|
||||
|
||||
# Unframe a short command
|
||||
($l, $c, $p) = $ipod->_unframe_cmd("\xFF\x55\x04\x00\x02\x00\x06\xF4");
|
||||
ok(defined($l) && ($l == 0x00) && ($c == 0x02) && ($p eq "\x00\x06"), "Unframed short command");
|
||||
|
||||
# Unframe a long command
|
||||
($l, $c, $p) = $ipod->_unframe_cmd("\xFF\x55\x00\x04\x00" . ("\x00" x 1024) . "\xFC");
|
||||
ok(defined($l) && ($l == 0x00) && ($c == 0x00) && ($p eq "\x00" x 1022), "Unframed long command");
|
||||
|
||||
# Frame without sync byte
|
||||
($l, $c, $p) = $ipod->_unframe_cmd("\x00");
|
||||
ok(!defined($l) && ($ipod->error() =~ /Could not unframe data/), "Frame without sync byte failed");
|
||||
|
||||
# Frame without SOP byte
|
||||
($l, $c, $p) = $ipod->_unframe_cmd("\xFF");
|
||||
ok(!defined($l) && ($ipod->error() =~ /Could not unframe data/), "Frame without SOP byte failed");
|
||||
|
||||
# Frame with length 0
|
||||
($l, $c, $p) = $ipod->_unframe_cmd("\xFF\x55\x00\x00\x00");
|
||||
ok(!defined($l) && ($ipod->error() =~ /Length is 0/), "Frame with length 0 failed");
|
||||
|
||||
# Too short frame
|
||||
($l, $c, $p) = $ipod->_unframe_cmd("\xFF\x55\x03\x00\x00");
|
||||
ok(!defined($l) && ($ipod->error() =~ /Could not unframe data/), "Too short frame failed");
|
||||
|
||||
# Invalid checksum
|
||||
($l, $c, $p) = $ipod->_unframe_cmd("\xFF\x55\x03\x00\x00\x00\x00");
|
||||
ok(!defined($l) && ($ipod->error() =~ /Invalid checksum/), "Invalid checksum failed");
|
||||
|
||||
# Find a message in a string
|
||||
$ipod->{-inbuf} = "\x00\xFF\x55\x00\xFF\xFF\xFF\x55\x04\x00\x02\x00\x06\xF4";
|
||||
($c, $l) = $ipod->_message_in_buffer();
|
||||
ok(defined($l) && ($c == 6) && ($l == 8), "Found message in buffer");
|
||||
|
||||
# Return message from a string
|
||||
$ipod->{-inbuf} = "\x00\xFF\x55\x00\xFF\xFF\xFF\x55\x04\x00\x02\x00\x06\xF4\x00";
|
||||
$m = $ipod->_message();
|
||||
ok(defined($m) && ($ipod->{-inbuf} eq "\x00"), "Retrieved message from buffer");
|
||||
|
||||
# Return two messages from buffer
|
||||
$ipod->{-inbuf} = "\xffU\x04\x00\x02\x00\x13\xe7\xffU\x02\x00\x14\xea";
|
||||
$m = $ipod->_message();
|
||||
subtest "First message" => sub {
|
||||
ok(defined($m), "Message received");
|
||||
is($m, "\xffU\x04\x00\x02\x00\x13\xe7");
|
||||
};
|
||||
$m = $ipod->_message();
|
||||
subtest "Second message" => sub {
|
||||
ok(defined($m), "Message received");
|
||||
is($m, "\xffU\x02\x00\x14\xea");
|
||||
};
|
1856
tools/iap/iap-verbose.pl
Normal file
1856
tools/iap/iap-verbose.pl
Normal file
File diff suppressed because it is too large
Load diff
133
tools/iap/ipod-001-general.t
Normal file
133
tools/iap/ipod-001-general.t
Normal file
|
@ -0,0 +1,133 @@
|
|||
use Test::More qw( no_plan );
|
||||
use strict;
|
||||
|
||||
BEGIN { use_ok('Device::iPod'); }
|
||||
require_ok('Device::iPod');
|
||||
|
||||
my $ipod = Device::iPod->new();
|
||||
my $m;
|
||||
my ($l, $c, $p);
|
||||
|
||||
isa_ok($ipod, 'Device::iPod');
|
||||
|
||||
$ipod->{-debug} = 1;
|
||||
$ipod->open("/dev/ttyUSB0");
|
||||
|
||||
$m = $ipod->sendraw("\xFF" x 16); # Wake up and sync
|
||||
ok($m == 1, "Wakeup sent");
|
||||
|
||||
# Empty the buffer
|
||||
$ipod->emptyrecv();
|
||||
|
||||
# Send a command with wrong checksum
|
||||
# We expect no response (Timeout)
|
||||
$m = $ipod->sendraw("\xff\x55\x02\x00\x03\x00");
|
||||
ok($m == 1, "Broken checksum sent");
|
||||
($l, $c, $p) = $ipod->recvmsg();
|
||||
subtest "Timeout" => sub {
|
||||
ok(!defined($l), "No response received");
|
||||
like($ipod->error(), '/Timeout/', "Timeout reading response");
|
||||
};
|
||||
|
||||
# Empty the buffer
|
||||
$ipod->emptyrecv();
|
||||
|
||||
# Send a too short command
|
||||
# We expect an ACK Bad Parameter as response
|
||||
$m = $ipod->sendmsg(0x00, 0x13, "");
|
||||
ok($m == 1, "Short command sent");
|
||||
($l, $c, $p) = $ipod->recvmsg();
|
||||
subtest "ACK Bad Parameter" => sub {
|
||||
ok(defined($l), "Response received");
|
||||
is($l, 0x00, "Response lingo");
|
||||
is($c, 0x02, "Response command");
|
||||
is($p, "\x04\x13", "Response payload");
|
||||
};
|
||||
|
||||
# Empty the buffer
|
||||
$ipod->emptyrecv();
|
||||
|
||||
# Send an undefined lingo
|
||||
# We expect a timeout
|
||||
$m = $ipod->sendmsg(0x1F, 0x00);
|
||||
ok($m == 1, "Undefined lingo sent");
|
||||
($l, $c, $p) = $ipod->recvmsg();
|
||||
subtest "Timeout" => sub {
|
||||
ok(!defined($l), "No response received");
|
||||
like($ipod->error(), '/Timeout/', "Timeout reading response");
|
||||
};
|
||||
|
||||
# Empty the buffer
|
||||
$ipod->emptyrecv();
|
||||
|
||||
# IdentifyDeviceLingoes(lingos=0x80000011, options=0x00, deviceid=0x00)
|
||||
# We expect an ACK Command Failed message as response
|
||||
$m = $ipod->sendmsg(0x00, 0x13, "\x80\x00\x00\x11\x00\x00\x00\x00\x00\x00\x00\x00");
|
||||
ok($m == 1, "IdentifyDeviceLingoes(lingos=0x80000011, options=0x00, deviceid=0x00) sent");
|
||||
($l, $c, $p) = $ipod->recvmsg();
|
||||
subtest "ACK Command Failed" => sub {
|
||||
ok(defined($l), "Response received");
|
||||
is($l, 0x00, "Response lingo");
|
||||
is($c, 0x02, "Response command");
|
||||
is($p, "\x02\x13", "Response payload");
|
||||
};
|
||||
|
||||
# Empty the buffer
|
||||
$ipod->emptyrecv();
|
||||
|
||||
# Identify(lingo=0xFF)
|
||||
# We expect no response (timeout)
|
||||
$m = $ipod->sendmsg(0x00, 0x01, "\xFF");
|
||||
ok($m == 1, "Identify(lingo=0xFF) sent");
|
||||
($l, $c, $p) = $ipod->recvmsg();
|
||||
subtest "Timeout" => sub {
|
||||
ok(!defined($l), "No response received");
|
||||
like($ipod->error(), '/Timeout/', "Timeout reading response");
|
||||
};
|
||||
|
||||
# Empty the buffer
|
||||
$ipod->emptyrecv();
|
||||
|
||||
# IdentifyDeviceLingoes(lingos=0x10, options=0x00, deviceid=0x00)
|
||||
# We expect an ACK Command Failed message as response
|
||||
$m = $ipod->sendmsg(0x00, 0x13, "\x00\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x00");
|
||||
ok($m == 1, "IdentifyDeviceLingoes(lingos=0x10, options=0x00, deviceid=0x00) sent");
|
||||
($l, $c, $p) = $ipod->recvmsg();
|
||||
subtest "ACK Command Failed" => sub {
|
||||
ok(defined($l), "Response received");
|
||||
is($l, 0x00, "Response lingo");
|
||||
is($c, 0x02, "Response command");
|
||||
is($p, "\x02\x13", "Response payload");
|
||||
};
|
||||
|
||||
# Empty the buffer
|
||||
$ipod->emptyrecv();
|
||||
# IdentifyDeviceLingoes(lingos=0x00, options=0x00, deviceid=0x00)
|
||||
# We expect an ACK Command Failed message as response
|
||||
$m = $ipod->sendmsg(0x00, 0x13, "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00");
|
||||
ok($m == 1, "IdentifyDeviceLingoes(lingos=0x00, options=0x00, deviceid=0x00) sent");
|
||||
($l, $c, $p) = $ipod->recvmsg();
|
||||
subtest "ACK Command Failed" => sub {
|
||||
ok(defined($l), "Response received");
|
||||
is($l, 0x00, "Response lingo");
|
||||
is($c, 0x02, "Response command");
|
||||
is($p, "\x02\x13", "Response payload");
|
||||
};
|
||||
|
||||
# Empty the buffer
|
||||
$ipod->emptyrecv();
|
||||
|
||||
# RequestLingoProtocolVersion(lingo=0xFF)
|
||||
# We expect an ACK Bad Parameter message as response
|
||||
$m = $ipod->sendmsg(0x00, 0x0F, "\xFF");
|
||||
ok($m == 1, "RequestLingoProtocolVersion(lingo=0xFF) sent");
|
||||
($l, $c, $p) = $ipod->recvmsg();
|
||||
subtest "ACK Bad Parameter" => sub {
|
||||
ok(defined($l), "Response received");
|
||||
is($l, 0x00, "Response lingo");
|
||||
is($c, 0x02, "Response command");
|
||||
is($p, "\x04\x0F", "Response payload");
|
||||
};
|
||||
|
||||
# Empty the buffer
|
||||
$ipod->emptyrecv();
|
277
tools/iap/ipod-002-lingo0.t
Normal file
277
tools/iap/ipod-002-lingo0.t
Normal file
|
@ -0,0 +1,277 @@
|
|||
use Test::More qw( no_plan );
|
||||
use strict;
|
||||
|
||||
BEGIN { use_ok('Device::iPod'); }
|
||||
require_ok('Device::iPod');
|
||||
|
||||
my $ipod = Device::iPod->new();
|
||||
my $m;
|
||||
my ($l, $c, $p);
|
||||
|
||||
isa_ok($ipod, 'Device::iPod');
|
||||
|
||||
$ipod->{-debug} = 1;
|
||||
$ipod->open("/dev/ttyUSB0");
|
||||
|
||||
$m = $ipod->sendraw("\xFF" x 16); # Wake up and sync
|
||||
ok($m == 1, "Wakeup sent");
|
||||
|
||||
# Empty the buffer
|
||||
$ipod->emptyrecv();
|
||||
|
||||
# IdentifyDeviceLingoes(lingos=0x01, options=0x00, deviceid=0x00)
|
||||
# We expect an ACK OK message as response
|
||||
$m = $ipod->sendmsg(0x00, 0x13, "\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00");
|
||||
ok($m == 1, "IdentifyDeviceLingoes(lingos=0x01, options=0x00, deviceid=0x00) sent");
|
||||
($l, $c, $p) = $ipod->recvmsg();
|
||||
subtest "ACK OK" => sub {
|
||||
ok(defined($l), "Response received");
|
||||
is($l, 0x00, "Response lingo");
|
||||
is($c, 0x02, "Response command");
|
||||
is($p, "\x00\x13", "Response payload");
|
||||
};
|
||||
|
||||
# Empty the buffer
|
||||
$ipod->emptyrecv();
|
||||
|
||||
# RequestRemoteUIMode
|
||||
# We expect an ACK Bad Parameter as response, as we have not
|
||||
# negotiated lingo 0x04
|
||||
$m = $ipod->sendmsg(0x00, 0x03);
|
||||
ok($m == 1, "RequestRemoteUIMode sent");
|
||||
($l, $c, $p) = $ipod->recvmsg();
|
||||
subtest "ACK Bad Parameter" => sub {
|
||||
ok(defined($l), "Response received");
|
||||
is($l, 0x00, "Response lingo");
|
||||
is($c, 0x02, "Response command");
|
||||
is($p, "\x04\x03", "Response payload");
|
||||
};
|
||||
|
||||
# Empty the buffer
|
||||
$ipod->emptyrecv();
|
||||
|
||||
# EnterRemoteUIMode
|
||||
# We expect an ACK Bad Parameter as response, as we have not
|
||||
# negotiated lingo 0x04
|
||||
$m = $ipod->sendmsg(0x00, 0x05);
|
||||
ok($m == 1, "EnterRemoteUIMode sent");
|
||||
($l, $c, $p) = $ipod->recvmsg();
|
||||
subtest "ACK Bad Parameter" => sub {
|
||||
ok(defined($l), "Response received");
|
||||
is($l, 0x00, "Response lingo");
|
||||
is($c, 0x02, "Response command");
|
||||
is($p, "\x04\x05", "Response payload");
|
||||
};
|
||||
|
||||
# Empty the buffer
|
||||
$ipod->emptyrecv();
|
||||
|
||||
# ExitRemoteUIMode
|
||||
# We expect an ACK Bad Parameter as response, as we have not
|
||||
# negotiated lingo 0x04
|
||||
$m = $ipod->sendmsg(0x00, 0x06);
|
||||
ok($m == 1, "ExitRemoteUIMode sent");
|
||||
($l, $c, $p) = $ipod->recvmsg();
|
||||
subtest "ACK Bad Parameter" => sub {
|
||||
ok(defined($l), "Response received");
|
||||
is($l, 0x00, "Response lingo");
|
||||
is($c, 0x02, "Response command");
|
||||
is($p, "\x04\x06", "Response payload");
|
||||
};
|
||||
|
||||
# Empty the buffer
|
||||
$ipod->emptyrecv();
|
||||
|
||||
# RequestiPodName
|
||||
# We expect a ReturniPodName packet
|
||||
$m = $ipod->sendmsg(0x00, 0x07);
|
||||
ok($m == 1, "RequestiPodName sent");
|
||||
($l, $c, $p) = $ipod->recvmsg();
|
||||
subtest "ReturniPodName" => sub {
|
||||
ok(defined($l), "Response received");
|
||||
is($l, 0x00, "Response lingo");
|
||||
is($c, 0x08, "Response command");
|
||||
like($p, "/^[^\\x00]*\\x00\$/", "Response payload");
|
||||
};
|
||||
|
||||
# Empty the buffer
|
||||
$ipod->emptyrecv();
|
||||
|
||||
# RequestiPodSoftwareVersion
|
||||
# We expect a ReturniPodSoftwareVersion packet
|
||||
$m = $ipod->sendmsg(0x00, 0x09);
|
||||
ok($m == 1, "RequestiPodSoftwareVersion sent");
|
||||
($l, $c, $p) = $ipod->recvmsg();
|
||||
subtest "ReturniPodSoftwareVersion" => sub {
|
||||
ok(defined($l), "Response received");
|
||||
is($l, 0x00, "Response lingo");
|
||||
is($c, 0x0A, "Response command");
|
||||
like($p, "/^...\$/", "Response payload");
|
||||
};
|
||||
|
||||
# Empty the buffer
|
||||
$ipod->emptyrecv();
|
||||
|
||||
# RequestiPodSerialNumber
|
||||
# We expect a ReturniPodSerialNumber packet
|
||||
$m = $ipod->sendmsg(0x00, 0x0B);
|
||||
ok($m == 1, "RequestiPodSerialNumber sent");
|
||||
($l, $c, $p) = $ipod->recvmsg();
|
||||
subtest "ReturniPodSerialNumber" => sub {
|
||||
ok(defined($l), "Response received");
|
||||
is($l, 0x00, "Response lingo");
|
||||
is($c, 0x0C, "Response command");
|
||||
like($p, "/^[^\\x00]*\\x00\$/", "Response payload");
|
||||
};
|
||||
|
||||
# Empty the buffer
|
||||
$ipod->emptyrecv();
|
||||
|
||||
# RequestiPodModelNum
|
||||
# We expect a ReturniPodModelNum packet
|
||||
$m = $ipod->sendmsg(0x00, 0x0D);
|
||||
ok($m == 1, "RequestiPodModelNum sent");
|
||||
($l, $c, $p) = $ipod->recvmsg();
|
||||
subtest "ReturniPodModelNum" => sub {
|
||||
ok(defined($l), "Response received");
|
||||
is($l, 0x00, "Response lingo");
|
||||
is($c, 0x0E, "Response command");
|
||||
like($p, "/^....[^\\x00]*\\x00\$/", "Response payload");
|
||||
};
|
||||
|
||||
# Empty the buffer
|
||||
$ipod->emptyrecv();
|
||||
|
||||
# RequestLingoProtocolVersion(lingo=0x00)
|
||||
# We expect a ReturnLingoProtocolVersion packet
|
||||
$m = $ipod->sendmsg(0x00, 0x0F, "\x00");
|
||||
ok($m == 1, "RequestLingoProtocolVersion(lingo=0x00) sent");
|
||||
($l, $c, $p) = $ipod->recvmsg();
|
||||
subtest "ReturnLingoProtocolVersion" => sub {
|
||||
ok(defined($l), "Response received");
|
||||
is($l, 0x00, "Response lingo");
|
||||
is($c, 0x10, "Response command");
|
||||
like($p, "/^\\x00..\$/", "Response payload");
|
||||
};
|
||||
|
||||
# Empty the buffer
|
||||
$ipod->emptyrecv();
|
||||
|
||||
# IdentifyDeviceLingoes(lingos=0x11, options=0x00, deviceid=0x00)
|
||||
# We expect an ACK OK message as response
|
||||
$m = $ipod->sendmsg(0x00, 0x13, "\x00\x00\x00\x11\x00\x00\x00\x00\x00\x00\x00\x00");
|
||||
ok($m == 1, "IdentifyDeviceLingoes(lingos=0x11, options=0x00, deviceid=0x00) sent");
|
||||
($l, $c, $p) = $ipod->recvmsg();
|
||||
subtest "ACK OK" => sub {
|
||||
ok(defined($l), "Response received");
|
||||
is($l, 0x00, "Response lingo");
|
||||
is($c, 0x02, "Response command");
|
||||
is($p, "\x00\x13", "Response payload");
|
||||
};
|
||||
|
||||
# Empty the buffer
|
||||
$ipod->emptyrecv();
|
||||
|
||||
# RequestRemoteUIMode
|
||||
# We expect an ReturnRemoteUIMode packet specifying standard mode
|
||||
$m = $ipod->sendmsg(0x00, 0x03);
|
||||
ok($m == 1, "RequestRemoteUIMode sent");
|
||||
($l, $c, $p) = $ipod->recvmsg();
|
||||
subtest "ReturnRemoteUIMode" => sub {
|
||||
ok(defined($l), "Response received");
|
||||
is($l, 0x00, "Response lingo");
|
||||
is($c, 0x04, "Response command");
|
||||
is($p, "\x00", "Response payload");
|
||||
};
|
||||
|
||||
# Empty the buffer
|
||||
$ipod->emptyrecv();
|
||||
|
||||
# EnterRemoteUIMode
|
||||
# We expect an ACK Pending packet, followed by an ACK OK packet
|
||||
$m = $ipod->sendmsg(0x00, 0x05);
|
||||
ok($m == 1, "EnterRemoteUIMode sent");
|
||||
($l, $c, $p) = $ipod->recvmsg();
|
||||
subtest "ACK Pending" => sub {
|
||||
ok(defined($l), "Response received");
|
||||
is($l, 0x00, "Response lingo");
|
||||
is($c, 0x02, "Response command");
|
||||
like($p, "/^\\x06\\x05/", "Response payload");
|
||||
};
|
||||
($l, $c, $p) = $ipod->recvmsg();
|
||||
subtest "ACK OK" => sub {
|
||||
ok(defined($l), "Response received");
|
||||
is($l, 0x00, "Response lingo");
|
||||
is($c, 0x02, "Response command");
|
||||
is($p, "\x00\x05", "Response payload");
|
||||
};
|
||||
|
||||
# Empty the buffer
|
||||
$ipod->emptyrecv();
|
||||
|
||||
# RequestRemoteUIMode
|
||||
# We expect an ReturnRemoteUIMode packet specifying extended mode
|
||||
$m = $ipod->sendmsg(0x00, 0x03);
|
||||
ok($m == 1, "RequestRemoteUIMode sent");
|
||||
($l, $c, $p) = $ipod->recvmsg();
|
||||
subtest "ReturnRemoteUIMode" => sub {
|
||||
ok(defined($l), "Response received");
|
||||
is($l, 0x00, "Response lingo");
|
||||
is($c, 0x04, "Response command");
|
||||
isnt($p, "\x00", "Response payload");
|
||||
};
|
||||
|
||||
# Empty the buffer
|
||||
$ipod->emptyrecv();
|
||||
|
||||
# ExitRemoteUIMode
|
||||
# We expect an ACK Pending packet, followed by an ACK OK packet
|
||||
$m = $ipod->sendmsg(0x00, 0x06);
|
||||
ok($m == 1, "ExitRemoteUIMode sent");
|
||||
($l, $c, $p) = $ipod->recvmsg();
|
||||
subtest "ACK Pending" => sub {
|
||||
ok(defined($l), "Response received");
|
||||
is($l, 0x00, "Response lingo");
|
||||
is($c, 0x02, "Response command");
|
||||
like($p, "/^\\x06\\x06/", "Response payload");
|
||||
};
|
||||
($l, $c, $p) = $ipod->recvmsg();
|
||||
subtest "ACK OK" => sub {
|
||||
ok(defined($l), "Response received");
|
||||
is($l, 0x00, "Response lingo");
|
||||
is($c, 0x02, "Response command");
|
||||
is($p, "\x00\x06", "Response payload");
|
||||
};
|
||||
|
||||
# Empty the buffer
|
||||
$ipod->emptyrecv();
|
||||
|
||||
# RequestRemoteUIMode
|
||||
# We expect an ReturnRemoteUIMode packet specifying standard mode
|
||||
$m = $ipod->sendmsg(0x00, 0x03);
|
||||
ok($m == 1, "RequestRemoteUIMode sent");
|
||||
($l, $c, $p) = $ipod->recvmsg();
|
||||
subtest "ReturnRemoteUIMode" => sub {
|
||||
ok(defined($l), "Response received");
|
||||
is($l, 0x00, "Response lingo");
|
||||
is($c, 0x04, "Response command");
|
||||
is($p, "\x00", "Response payload");
|
||||
};
|
||||
|
||||
# Empty the buffer
|
||||
$ipod->emptyrecv();
|
||||
|
||||
# Send an undefined command
|
||||
# We expect an ACK Bad Parameter as response
|
||||
$m = $ipod->sendmsg(0x00, 0xFF);
|
||||
ok($m == 1, "Undefined command sent");
|
||||
($l, $c, $p) = $ipod->recvmsg();
|
||||
subtest "ACK Bad Parameter" => sub {
|
||||
ok(defined($l), "Response received");
|
||||
is($l, 0x00, "Response lingo");
|
||||
is($c, 0x02, "Response command");
|
||||
is($p, "\x04\xFF", "Response payload");
|
||||
};
|
||||
|
||||
# Empty the buffer
|
||||
$ipod->emptyrecv();
|
220
tools/iap/ipod-003-lingo2.t
Normal file
220
tools/iap/ipod-003-lingo2.t
Normal file
|
@ -0,0 +1,220 @@
|
|||
use Test::More qw( no_plan );
|
||||
use strict;
|
||||
|
||||
BEGIN { use_ok('Device::iPod'); }
|
||||
require_ok('Device::iPod');
|
||||
|
||||
my $ipod = Device::iPod->new();
|
||||
my $m;
|
||||
my ($l, $c, $p);
|
||||
|
||||
isa_ok($ipod, 'Device::iPod');
|
||||
|
||||
$ipod->{-debug} = 1;
|
||||
$ipod->open("/dev/ttyUSB0");
|
||||
|
||||
$m = $ipod->sendraw("\xFF" x 16); # Wake up and sync
|
||||
ok($m == 1, "Wakeup sent");
|
||||
|
||||
# Empty the buffer
|
||||
$ipod->emptyrecv();
|
||||
|
||||
# IdentifyDeviceLingoes(lingos=0x01, options=0x00, deviceid=0x00)
|
||||
# We expect an ACK OK message as response
|
||||
$m = $ipod->sendmsg(0x00, 0x13, "\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00");
|
||||
ok($m == 1, "IdentifyDeviceLingoes(lingos=0x01, options=0x00, deviceid=0x00) sent");
|
||||
($l, $c, $p) = $ipod->recvmsg();
|
||||
subtest "ACK OK" => sub {
|
||||
ok(defined($l), "Response received");
|
||||
is($l, 0x00, "Response lingo");
|
||||
is($c, 0x02, "Response command");
|
||||
is($p, "\x00\x13", "Response payload");
|
||||
};
|
||||
|
||||
# Empty the buffer
|
||||
$ipod->emptyrecv();
|
||||
|
||||
# ContextButtonStatus(0x00)
|
||||
# We expect an ACK Bad Parameter message as response
|
||||
$m = $ipod->sendmsg(0x02, 0x00, "\x00");
|
||||
ok($m == 1, "ContextButtonStatus(0x00)");
|
||||
($l, $c, $p) = $ipod->recvmsg();
|
||||
subtest "ACK Bad Parameter" => sub {
|
||||
ok(defined($l), "Response received");
|
||||
is($l, 0x02, "Response lingo");
|
||||
is($c, 0x01, "Response command");
|
||||
is($p, "\x04\x00", "Response payload");
|
||||
};
|
||||
|
||||
# Empty the buffer
|
||||
$ipod->emptyrecv();
|
||||
|
||||
# Identify(lingo=0x00)
|
||||
# We expect no response (timeout)
|
||||
$m = $ipod->sendmsg(0x00, 0x01, "\x00");
|
||||
ok($m == 1, "Identify(lingo=0x00) sent");
|
||||
($l, $c, $p) = $ipod->recvmsg();
|
||||
subtest "Timeout" => sub {
|
||||
ok(!defined($l), "No response received");
|
||||
like($ipod->error(), '/Timeout/', "Timeout reading response");
|
||||
};
|
||||
|
||||
# Empty the buffer
|
||||
$ipod->emptyrecv();
|
||||
|
||||
# ContextButtonStatus(0x00)
|
||||
# We expect a timeout as response
|
||||
$m = $ipod->sendmsg(0x02, 0x00, "\x00");
|
||||
ok($m == 1, "ContextButtonStatus(0x00)");
|
||||
($l, $c, $p) = $ipod->recvmsg();
|
||||
subtest "Timeout" => sub {
|
||||
ok(!defined($l), "Response received");
|
||||
like($ipod->error(), '/Timeout/', "Timeout reading response");
|
||||
};
|
||||
|
||||
# Empty the buffer
|
||||
$ipod->emptyrecv();
|
||||
|
||||
# Identify(lingo=0x02)
|
||||
# We expect no response (timeout)
|
||||
$m = $ipod->sendmsg(0x00, 0x01, "\x02");
|
||||
ok($m == 1, "Identify(lingo=0x02) sent");
|
||||
($l, $c, $p) = $ipod->recvmsg();
|
||||
subtest "Timeout" => sub {
|
||||
ok(!defined($l), "No response received");
|
||||
like($ipod->error(), '/Timeout/', "Timeout reading response");
|
||||
};
|
||||
|
||||
# Empty the buffer
|
||||
$ipod->emptyrecv();
|
||||
|
||||
# ContextButtonStatus(0x00)
|
||||
# We expect a timeout as response
|
||||
$m = $ipod->sendmsg(0x02, 0x00, "\x00");
|
||||
ok($m == 1, "ContextButtonStatus(0x00)");
|
||||
($l, $c, $p) = $ipod->recvmsg();
|
||||
subtest "Timeout" => sub {
|
||||
ok(!defined($l), "Response received");
|
||||
like($ipod->error(), '/Timeout/', "Timeout reading response");
|
||||
};
|
||||
|
||||
# Empty the buffer
|
||||
$ipod->emptyrecv();
|
||||
|
||||
# IdentifyDeviceLingoes(lingos=0x05, options=0x00, deviceid=0x00)
|
||||
# We expect an ACK OK message as response
|
||||
$m = $ipod->sendmsg(0x00, 0x13, "\x00\x00\x00\x05\x00\x00\x00\x00\x00\x00\x00\x00");
|
||||
ok($m == 1, "IdentifyDeviceLingoes(lingos=0x05, options=0x00, deviceid=0x00) sent");
|
||||
($l, $c, $p) = $ipod->recvmsg();
|
||||
subtest "ACK OK" => sub {
|
||||
ok(defined($l), "Response received");
|
||||
is($l, 0x00, "Response lingo");
|
||||
is($c, 0x02, "Response command");
|
||||
is($p, "\x00\x13", "Response payload");
|
||||
};
|
||||
|
||||
# Empty the buffer
|
||||
$ipod->emptyrecv();
|
||||
|
||||
# RequestLingoProtocolVersion(lingo=0x02)
|
||||
# We expect a ReturnLingoProtocolVersion packet
|
||||
$m = $ipod->sendmsg(0x00, 0x0F, "\x02");
|
||||
ok($m == 1, "RequestLingoProtocolVersion(lingo=0x02) sent");
|
||||
($l, $c, $p) = $ipod->recvmsg();
|
||||
subtest "ReturnLingoProtocolVersion" => sub {
|
||||
ok(defined($l), "Response received");
|
||||
is($l, 0x00, "Response lingo");
|
||||
is($c, 0x10, "Response command");
|
||||
like($p, "/^\\x02..\$/", "Response payload");
|
||||
};
|
||||
|
||||
# Empty the buffer
|
||||
$ipod->emptyrecv();
|
||||
|
||||
# Send an undefined command
|
||||
# We expect an ACK Bad Parameter as response
|
||||
$m = $ipod->sendmsg(0x02, 0xFF);
|
||||
ok($m == 1, "Undefined command sent");
|
||||
($l, $c, $p) = $ipod->recvmsg();
|
||||
subtest "ACK Bad Parameter" => sub {
|
||||
ok(defined($l), "Response received");
|
||||
is($l, 0x02, "Response lingo");
|
||||
is($c, 0x01, "Response command");
|
||||
is($p, "\x04\xFF", "Response payload");
|
||||
};
|
||||
|
||||
# Empty the buffer
|
||||
$ipod->emptyrecv();
|
||||
|
||||
# ContextButtonStatus(0x00)
|
||||
# We expect a timeout as response
|
||||
$m = $ipod->sendmsg(0x02, 0x00, "\x00");
|
||||
ok($m == 1, "ContextButtonStatus(0x00)");
|
||||
($l, $c, $p) = $ipod->recvmsg();
|
||||
subtest "Timeout" => sub {
|
||||
ok(!defined($l), "Response received");
|
||||
like($ipod->error(), '/Timeout/', "Timeout reading response");
|
||||
};
|
||||
|
||||
# Empty the buffer
|
||||
$ipod->emptyrecv();
|
||||
|
||||
# Send a too short command
|
||||
# We expect an ACK Bad Parameter as response
|
||||
$m = $ipod->sendmsg(0x02, 0x00, "");
|
||||
ok($m == 1, "Short command sent");
|
||||
($l, $c, $p) = $ipod->recvmsg();
|
||||
subtest "ACK Bad Parameter" => sub {
|
||||
ok(defined($l), "Response received");
|
||||
is($l, 0x02, "Response lingo");
|
||||
is($c, 0x01, "Response command");
|
||||
is($p, "\x04\x00", "Response payload");
|
||||
};
|
||||
|
||||
# Empty the buffer
|
||||
$ipod->emptyrecv();
|
||||
|
||||
# ImageButtonStatus(0x00)
|
||||
# We expect an ACK Not Authenticated as response
|
||||
$m = $ipod->sendmsg(0x02, 0x02, "\x00");
|
||||
ok($m == 1, "ImageButtonStatus(0x00)");
|
||||
($l, $c, $p) = $ipod->recvmsg();
|
||||
subtest "ACK Not Authenticated" => sub {
|
||||
ok(defined($l), "Response received");
|
||||
is($l, 0x02, "Response lingo");
|
||||
is($c, 0x01, "Response command");
|
||||
is($p, "\x07\x02", "Response payload");
|
||||
};
|
||||
|
||||
# Empty the buffer
|
||||
$ipod->emptyrecv();
|
||||
|
||||
# VideoButtonStatus(0x00)
|
||||
# We expect an ACK Not Authenticated as response
|
||||
$m = $ipod->sendmsg(0x02, 0x03, "\x00");
|
||||
ok($m == 1, "VideoButtonStatus(0x00)");
|
||||
($l, $c, $p) = $ipod->recvmsg();
|
||||
subtest "ACK Not Authenticated" => sub {
|
||||
ok(defined($l), "Response received");
|
||||
is($l, 0x02, "Response lingo");
|
||||
is($c, 0x01, "Response command");
|
||||
is($p, "\x07\x03", "Response payload");
|
||||
};
|
||||
|
||||
# Empty the buffer
|
||||
$ipod->emptyrecv();
|
||||
|
||||
# AudioButtonStatus(0x00)
|
||||
# We expect an ACK Not Authenticated as response
|
||||
$m = $ipod->sendmsg(0x02, 0x04, "\x00");
|
||||
ok($m == 1, "AudioButtonStatus(0x00)");
|
||||
($l, $c, $p) = $ipod->recvmsg();
|
||||
subtest "ACK Not Authenticated" => sub {
|
||||
ok(defined($l), "Response received");
|
||||
is($l, 0x02, "Response lingo");
|
||||
is($c, 0x01, "Response command");
|
||||
is($p, "\x07\x04", "Response payload");
|
||||
};
|
||||
|
||||
# Empty the buffer
|
||||
$ipod->emptyrecv();
|
Loading…
Reference in a new issue