First shot at bluetooth support (turned off in Makefile by default).

A full robot vs. robot game now works between two Treos.  Added UI to
choose BT as transport mechanism, and added new send proc to establish
socket connection between host and guest.  Works only for two devices:
no piconet yet.  No error recovery, ability to quit game in middle,
start new game, etc.
This commit is contained in:
ehouse 2006-08-23 04:44:55 +00:00
parent b99f993760
commit 3c6405d0d1
17 changed files with 793 additions and 55 deletions

View file

@ -459,13 +459,15 @@ comms_setAddr( CommsCtxt* comms, const CommsAddrRec* addr )
{
XP_ASSERT( comms != NULL );
#ifdef BEYOND_IR
util_addrChange( comms->util, &comms->addr, addr );
util_addrChange( comms->util, &comms->addr, addr, comms->isServer );
#endif
XP_MEMCPY( &comms->addr, addr, sizeof(comms->addr) );
#ifdef BEYOND_IR
/* We should now have a cookie so we can connect??? */
relayConnect( comms );
if ( addr->conType == COMMS_CONN_RELAY ) {
relayConnect( comms );
}
#endif
} /* comms_setAddr */
@ -1133,7 +1135,7 @@ static void
relayConnect( CommsCtxt* comms )
{
XP_LOGF( "relayConnect called" );
if ( !comms->connecting ) {
if ( comms->addr.conType == COMMS_CONN_RELAY && !comms->connecting ) {
comms->connecting = XP_TRUE;
send_via_relay( comms,
comms->connName[0] == '\0' ?
@ -1148,9 +1150,11 @@ relayDisconnect( CommsCtxt* comms )
{
#ifdef BEYOND_IR
XP_LOGF( "relayDisconnect called" );
if ( comms->relayState != COMMS_RELAYSTATE_UNCONNECTED ) {
comms->relayState = COMMS_RELAYSTATE_UNCONNECTED;
send_via_relay( comms, XWRELAY_GAME_DISCONNECT, HOST_ID_NONE, NULL, 0 );
if ( comms->addr.conType == COMMS_CONN_RELAY ) {
if ( comms->relayState != COMMS_RELAYSTATE_UNCONNECTED ) {
comms->relayState = COMMS_RELAYSTATE_UNCONNECTED;
send_via_relay( comms, XWRELAY_GAME_DISCONNECT, HOST_ID_NONE, NULL, 0 );
}
}
#endif
} /* relayDisconnect */

View file

@ -69,7 +69,7 @@ typedef struct CommsAddrRec {
} u;
} CommsAddrRec;
typedef XP_S16 (*TransportSend)( XP_U8* buf, XP_U16 len,
typedef XP_S16 (*TransportSend)( const XP_U8* buf, XP_U16 len,
const CommsAddrRec* addr,
void* closure );

View file

@ -143,7 +143,7 @@ typedef struct UtilVtable {
XP_U16 turn, XP_Bool turnLost );
#ifdef BEYOND_IR
void (*m_util_addrChange)( XW_UtilCtxt* uc, const CommsAddrRec* oldAddr,
const CommsAddrRec* newAddr );
const CommsAddrRec* newAddr, XP_Bool isServer );
#endif
#ifdef XWFEATURE_SEARCHLIMIT
@ -221,8 +221,8 @@ struct XW_UtilCtxt {
(uc)->vtable->m_util_warnIllegalWord((uc),(w),(p),(b))
#ifdef BEYOND_IR
#define util_addrChange( uc, addro, addrn ) \
(uc)->vtable->m_util_addrChange((uc), (addro), (addrn))
#define util_addrChange( uc, addro, addrn, srvr ) \
(uc)->vtable->m_util_addrChange((uc), (addro), (addrn), (srvr))
#endif
#ifdef XWFEATURE_SEARCHLIMIT

View file

@ -42,7 +42,7 @@ typedef struct StreamCtxVTable {
XP_U32 (*m_stream_getBits)( XWStreamCtxt* dctx, XP_U16 nBits );
void (*m_stream_putU8)( XWStreamCtxt* dctx, XP_U8 byt );
void (*m_stream_putBytes)( XWStreamCtxt* dctx, void* whence,
void (*m_stream_putBytes)( XWStreamCtxt* dctx, const void* whence,
XP_U16 count );
void (*m_stream_putString)( XWStreamCtxt* dctx, const char* whence );
void (*m_stream_putU16)( XWStreamCtxt* dctx, XP_U16 data );

View file

@ -115,6 +115,9 @@ MYDEFS_COMMON += -DXWFEATURE_SEARCHLIMIT
# experimental at this point!
# MYDEFS_COMMON += -DBEYOND_IR
# turn on bluetooth comms option -- off by default until ready
# MYDEFS_COMMON += -DXWFEATURE_PALM_BLUETOOTH
# For Danish and perhaps other languages, custom-measure glyph height
# so that overtall letters have a chance of fitting.
MYDEFS_COMMON += -DTALL_FONTS
@ -147,7 +150,8 @@ BITMAP_RSRCS = \
$(BITMAPS)/showtray.pbitm \
$(BITMAPS)/xwords4.pbitm \
INCLUDES += -I/usr/local/share/palmdev/sdk-5r3/Extensions/ExpansionMgr
# INCLUDES += -I/usr/local/share/palmdev/sdk-5r3/Extensions/ExpansionMgr
INCLUDES += -I/usr/local/share/palmdev/sdk-5r3/include/Extensions/Bluetooth
# HS_DUO_SUPPORT = 1
@ -181,6 +185,7 @@ OBJS_68K = $(PLATFORM)/palmmain.o \
$(PLATFORM)/dictlist.o \
$(PLATFORM)/palmir.o \
$(PLATFORM)/palmip.o \
$(PLATFORM)/palmbt.o \
$(PLATFORM)/prefsdlg.o \
$(PLATFORM)/connsdlg.o \
$(COMMONOBJ)

View file

@ -28,6 +28,7 @@ INCLUDE += \
-I$(PALMDIR)/Core/System \
-I$(PALMDIR)/Core/System/Unix \
-I$(PALMDIR)/Core/Hardware \
-I$(PALMDIR)/Extensions/Bluetooth \
-I. -I../common -I../relay
# NOTE!!!! Added the -w flag to supress all warnings since arm-elf-gcc
@ -61,6 +62,7 @@ OBJS = $(PLATFORM)/pnolet.o \
$(PLATFORM)/dictlist.o \
$(PLATFORM)/palmir.o \
$(PLATFORM)/palmip.o \
$(PLATFORM)/palmbt.o \
$(PLATFORM)/prefsdlg.o \
$(PLATFORM)/connsdlg.o \
$(PLATFORM)/pace_gen.o \

View file

@ -55,24 +55,6 @@ strFromField( XP_U16 id, XP_UCHAR* buf, XP_U16 max )
buf[len] = '\0';
} /* strFromField */
#if 0
static void
stateFromGlobals( PalmAppGlobals* globals, ConnsDlgState* state )
{
comms_getAddr( globals->game.comms, &state->targetAddr,
&state->myPort );
state->isNewGame = globals->isNewGame;
} /* stateFromGlobals */
static void
globalsFromState( PalmAppGlobals* globals, ConnsDlgState* state )
{
comms_setAddr( globals->game.comms, &state->targetAddr,
state->myPort );
} /* globalsFromState */
#endif
static void
ctlsFromState( PalmAppGlobals* globals, FormPtr form, ConnsDlgState* state )
{
@ -134,6 +116,43 @@ cleanupExit( PalmAppGlobals* globals )
FrmReturnToForm( 0 );
} /* cleanupExit */
static XP_U16
conTypeToSel( CommsConnType conType )
{
XP_U16 result;
switch ( conType ) {
#ifdef XWFEATURE_PALM_BLUETOOTH
case COMMS_CONN_BT: result = 0; break;
case COMMS_CONN_IR: result = 1; break;
case COMMS_CONN_RELAY: result = 2; break;
#else
case COMMS_CONN_IR: result = 0; break;
case COMMS_CONN_RELAY: result = 1; break;
#endif
default:
XP_ASSERT(0);
}
return result;
} /* conTypeToSel */
static CommsConnType
selToConType( XP_U16 sel )
{
CommsConnType conType;
switch( sel ) {
#ifdef XWFEATURE_PALM_BLUETOOTH
case 0: conType = COMMS_CONN_BT; break;
case 1: conType = COMMS_CONN_IR; break;
case 2: conType = COMMS_CONN_RELAY; break;
#else
case 0: conType = COMMS_CONN_IR; break;
case 1: conType = COMMS_CONN_RELAY; break;
#endif
default: XP_ASSERT(0);
}
return conType;
}
Boolean
ConnsFormHandleEvent( EventPtr event )
{
@ -167,9 +186,10 @@ ConnsFormHandleEvent( EventPtr event )
/* setup connection popup */
state->connTypesList = getActiveObjectPtr( XW_CONNS_TYPE_LIST_ID );
XP_ASSERT( state->addr->conType == COMMS_CONN_IR
|| state->addr->conType == COMMS_CONN_RELAY );
|| state->addr->conType == COMMS_CONN_RELAY
|| state->addr->conType == COMMS_CONN_BT );
setSelectorFromList( XW_CONNS_TYPE_TRIGGER_ID, state->connTypesList,
state->addr->conType == COMMS_CONN_IR? 0:1 );
conTypeToSel(state->addr->conType) );
ctlsFromState( globals, form, state );
@ -190,8 +210,7 @@ ConnsFormHandleEvent( EventPtr event )
if ( chosen >= 0 ) {
setSelectorFromList( XW_CONNS_TYPE_TRIGGER_ID,
state->connTypesList, chosen );
state->addr->conType =
chosen == 0? COMMS_CONN_IR : COMMS_CONN_RELAY;
state->addr->conType = selToConType( chosen );
updateFormCtls( form, state );
}
}

View file

@ -239,9 +239,18 @@ BEGIN
POPUPTRIGGER "" ID XW_CONNS_TYPE_TRIGGER_ID
AT (PREVRIGHT+5 PREVTOP 72 12) LEFTANCHOR
LIST "IR/Bluetooth" "Internet/IP" ID XW_CONNS_TYPE_LIST_ID
PREVLEFT PREVTOP 72 12 VISIBLEITEMS 2 NONUSABLE
POPUPLIST XW_CONNS_TYPE_TRIGGER_ID XW_CONNS_TYPE_LIST_ID
LIST
#ifdef XWFEATURE_PALM_BLUETOOTH
"Bluetooth"
#endif
"IR" "Internet/IP" ID XW_CONNS_TYPE_LIST_ID
PREVLEFT PREVTOP 72 12 VISIBLEITEMS
#ifdef XWFEATURE_PALM_BLUETOOTH
3
#else
2
#endif
NONUSABLE POPUPLIST XW_CONNS_TYPE_TRIGGER_ID XW_CONNS_TYPE_LIST_ID
LABEL "Relay name:" XW_CONNS_RELAY_LABEL_ID
AT ( LEFTCOL+10 LOCALIP_TOP )

619
palm/palmbt.c Normal file
View file

@ -0,0 +1,619 @@
/* -*-mode: C; fill-column: 77; c-basic-offset: 4; compile-command: "make ARCH=68K_ONLY MEMDEBUG=TRUE"; -*- */
/*
* Copyright 2006 by Eric House (xwords@eehouse.org). All rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifdef XWFEATURE_PALM_BLUETOOTH
#include "xptypes.h"
#include "palmbt.h"
# include <BtLib.h>
# include <BtLibTypes.h>
#define L2CAPSOCKETMTU 500
#define SOCK_INVAL 0XFFFF
typedef struct PalmBTStuff {
DataCb cb;
PalmAppGlobals* globals;
XP_U16 btLibRefNum;
XP_U16 lenOut;
XP_UCHAR bufOut[L2CAPSOCKETMTU]; /* what's the mmu? */
BtLibSocketRef dataSocket;
XP_Bool sendInProgress;
XP_Bool sendPending;
XP_Bool amMaster;
union {
struct {
BtLibDeviceAddressType masterAddr;
BtLibSocketRef spdSocket;
} slave;
struct {
BtLibSocketRef listenSocket;
} master;
} u;
BtLibSdpRecordHandle sdpRecordH;
} PalmBTStuff;
#define LOG_ERR(f,e) palm_bt_log( #f, __FUNCTION__, e )
/* WHAT SHOULD THIS BE? Copied from Whiteboard.... PENDING */
static const BtLibSdpUuidType XWORDS_UUID = {
btLibUuidSize128,
{ 0x83, 0xe0, 0x87, 0xae, 0x4e, 0x18, 0x46, 0xbe,
0x83, 0xe0, 0x7b, 0x3d, 0xe6, 0xa1, 0xc3, 0x3b } };
static void initBTStuff( PalmAppGlobals* globals, DataCb cb, XP_Bool amMaster );
static void palm_bt_log( const char* btfunc, const char* func, Err err );
static void pbt_connect_slave( PalmBTStuff* btStuff, BtLibL2CapPsmType psm );
#ifdef DEBUG
static const char* btErrToStr( Err err );
static const char* btEvtToStr( BtLibSocketEventEnum evt );
static const char* mgmtEvtToStr( BtLibManagementEventEnum event );
#else
# define btErrToStr( err ) ""
# define btEvtToStr( evt ) ""
# define mgmtEvtToStr( evt ) ""
#endif
/* callbacks */
static void libMgmtCallback( BtLibManagementEventType* mEvent, UInt32 refCon );
static void spdSocketCallback( BtLibSocketEventType* sEvent, UInt32 refCon );
static void l2SocketCallback( BtLibSocketEventType* sEvent, UInt32 refCon );
void
palm_bt_init( PalmAppGlobals* globals, DataCb cb, XP_Bool amMaster )
{
XP_LOGF( "%s(amMaster=%d)", __FUNCTION__, (XP_U16)amMaster );
initBTStuff( globals, cb, amMaster );
}
void
palm_bt_close( PalmAppGlobals* globals )
{
PalmBTStuff* btStuff = globals->btStuff;
if ( !!btStuff ) {
/* Need to unregister callbacks */
(void)BtLibUnregisterManagementNotification( btStuff->btLibRefNum,
libMgmtCallback );
if ( btStuff->amMaster
&& btStuff->u.master.listenSocket != SOCK_INVAL ) {
(void)BtLibSocketClose( btStuff->btLibRefNum,
btStuff->u.master.listenSocket );
btStuff->u.master.listenSocket = SOCK_INVAL;
}
if ( btStuff->dataSocket != SOCK_INVAL ) {
(void)BtLibSocketClose( btStuff->btLibRefNum,
btStuff->u.master.listenSocket );
btStuff->dataSocket = SOCK_INVAL;
}
if ( btStuff->btLibRefNum != 0 ) {
Err err = BtLibClose( btStuff->btLibRefNum );
LOG_ERR( BtLibClose, err );
XP_ASSERT( errNone == err );
}
XP_FREE( globals->mpool, btStuff );
globals->btStuff = NULL;
}
} /* palm_bt_close */
XP_Bool
btSocketIsOpen( PalmAppGlobals* globals )
{
return (NULL != globals->btStuff)
&& (globals->btStuff->dataSocket != 0);
}
static void
pbt_send_pending( PalmBTStuff* btStuff )
{
LOG_FUNC();
if ( btStuff->sendPending && !btStuff->sendInProgress ) {
if ( !!btStuff->dataSocket ) {
Err err = BtLibSocketSend( btStuff->btLibRefNum, btStuff->dataSocket,
btStuff->bufOut, btStuff->lenOut );
LOG_ERR( BtLibSocketSend, err );
if ( err == errNone ) {
// clear on receipt of btLibSocketEventSendComplete
btStuff->sendInProgress = XP_TRUE;
}
}
}
}
XP_S16
palm_bt_send( const XP_U8* buf, XP_U16 len, PalmAppGlobals* globals )
{
PalmBTStuff* btStuff;
XP_LOGF( "%s(len=%d)", __FUNCTION__, len );
btStuff = globals->btStuff;
XP_ASSERT( !!btStuff );
if ( !!btStuff ) {
if ( !btStuff->sendInProgress ) {
if ( len > sizeof( btStuff->bufOut ) ) {
len = sizeof( btStuff->bufOut );
}
XP_MEMCPY( btStuff->bufOut, buf, len );
btStuff->lenOut = len;
btStuff->sendPending = XP_TRUE;
pbt_send_pending( btStuff );
}
}
return -1;
} /* palm_bt_send */
static void
pbt_find_psm( PalmBTStuff* btStuff )
{
Err err;
XP_ASSERT( !btStuff->amMaster );
err = BtLibSocketCreate( btStuff->btLibRefNum, &btStuff->u.slave.spdSocket,
spdSocketCallback,
(UInt32)btStuff, btLibSdpProtocol );
LOG_ERR( BtLibSocketCreate, err );
err = BtLibSdpGetPsmByUuid( btStuff->btLibRefNum,
btStuff->u.slave.spdSocket,
&btStuff->u.slave.masterAddr,
(BtLibSdpUuidType*)&XWORDS_UUID, 1 );
LOG_ERR( BtLibSdpGetPSMByUuid, err );
}
static void
pbt_connect_slave( PalmBTStuff* btStuff, BtLibL2CapPsmType psm )
{
Err err;
LOG_FUNC();
XP_ASSERT( !btStuff->amMaster );
err = BtLibSocketCreate( btStuff->btLibRefNum, &btStuff->dataSocket,
l2SocketCallback, (UInt32)btStuff,
btLibL2CapProtocol );
LOG_ERR( BtLibSocketCreate, err );
if ( btLibErrNoError == err ) {
BtLibSocketConnectInfoType connInfo;
connInfo.data.L2Cap.remotePsm = psm;
connInfo.data.L2Cap.localMtu = L2CAPSOCKETMTU;
connInfo.data.L2Cap.minRemoteMtu = L2CAPSOCKETMTU;
connInfo.remoteDeviceP = &btStuff->u.slave.masterAddr;
err = BtLibSocketConnect( btStuff->btLibRefNum,
btStuff->dataSocket, &connInfo );
LOG_ERR( BtLibSocketConnect, err );
}
}
static void
pbt_setup_master( PalmBTStuff* btStuff )
{
/* Will eventually want to create a piconet here for more than two
devices to play.... */
Err err;
BtLibSocketListenInfoType listenInfo;
btStuff->u.master.listenSocket = SOCK_INVAL;
/* 1. BtLibSocketCreate: create an L2CAP socket. */
err = BtLibSocketCreate( btStuff->btLibRefNum,
&btStuff->u.master.listenSocket, l2SocketCallback,
(UInt32)btStuff, btLibL2CapProtocol );
LOG_ERR( BtLibSocketCreate, err );
/* 2. BtLibSocketListen: set up an L2CAP socket as a listener. */
XP_MEMSET( &listenInfo, 0, sizeof(listenInfo) );
listenInfo.data.L2Cap.localPsm = BT_L2CAP_RANDOM_PSM;
listenInfo.data.L2Cap.localMtu = L2CAPSOCKETMTU;
listenInfo.data.L2Cap.minRemoteMtu = L2CAPSOCKETMTU;
err = BtLibSocketListen( btStuff->btLibRefNum,
btStuff->u.master.listenSocket, &listenInfo );
LOG_ERR( BtLibSocketListen, err );
/* 3. BtLibSdpServiceRecordCreate: allocate a memory chunk that
represents an SDP service record. */
err = BtLibSdpServiceRecordCreate(btStuff->btLibRefNum, &btStuff->sdpRecordH );
LOG_ERR( BtLibSdpServiceRecordCreate, err );
/* 4. BtLibSdpServiceRecordSetAttributesForSocket: initialize an SDP
memory record so it can represent the newly-created L2CAP listener
socket as a service */
err = BtLibSdpServiceRecordSetAttributesForSocket(
btStuff->btLibRefNum, btStuff->u.master.listenSocket,
(BtLibSdpUuidType*)&XWORDS_UUID, 1, APPNAME,
StrLen(APPNAME), btStuff->sdpRecordH );
LOG_ERR( BtLibSdpServiceRecordSetAttributesForSocket, err );
/* 5. BtLibSdpServiceRecordStartAdvertising: make an SDP memory record
representing a local SDP service record visible to remote
devices. */
err = BtLibSdpServiceRecordStartAdvertising( btStuff->btLibRefNum,
btStuff->sdpRecordH );
LOG_ERR( BtLibSdpServiceRecordStartAdvertising, err );
} /* pbt_setup_master */
static void
pbt_setup_slave( PalmBTStuff* btStuff )
{
Err err;
static const BtLibClassOfDeviceType deviceFilter
= btLibCOD_ServiceAny
| btLibCOD_Major_Any // btLibCOD_Major_Computer
| btLibCOD_Minor_Comp_Any; //btLibCOD_Minor_Comp_Palm;
XP_ASSERT( !btStuff->amMaster );
err = BtLibDiscoverSingleDevice( btStuff->btLibRefNum, "Crosswords host",
(BtLibClassOfDeviceType*)&deviceFilter, 1,
&btStuff->u.slave.masterAddr,
false, false );
LOG_ERR( BtLibDiscoverSingleDevice, err );
if ( errNone == err ) {
err = BtLibLinkConnect( btStuff->btLibRefNum,
&btStuff->u.slave.masterAddr );
LOG_ERR( BtLibLinkConnect, err );
XP_ASSERT( err == btLibErrPending );
}
} /* pbt_setup_slave */
static void
initBTStuff( PalmAppGlobals* globals, DataCb cb, XP_Bool amMaster )
{
PalmBTStuff* btStuff;
Err err;
XP_U16 btLibRefNum;
btStuff = globals->btStuff;
if ( btStuff != NULL ) {
if ( btStuff->amMaster == amMaster ) {
/* nothing to do */
} else {
/* role change. Adapt... */
XP_ASSERT( 0 );
}
} else {
btStuff = XP_MALLOC( globals->mpool, sizeof(*btStuff) );
XP_ASSERT( !!btStuff );
XP_MEMSET( btStuff, 0, sizeof(*btStuff) );
globals->btStuff = btStuff;
btStuff->globals = globals;
btStuff->cb = cb;
btStuff->amMaster = amMaster;
btStuff->dataSocket = SOCK_INVAL;
err = SysLibFind( btLibName, &btLibRefNum );
XP_LOGF( "%s: SysLibFind(%s) => %d\n", __FUNCTION__, btLibName, err );
XP_ASSERT( errNone == err );
btStuff->btLibRefNum = btLibRefNum;
err = BtLibOpen( btLibRefNum, false );
LOG_ERR( BtLibOpen, err );
XP_ASSERT( errNone == err );
err = BtLibRegisterManagementNotification( btLibRefNum, libMgmtCallback,
(UInt32)btStuff );
LOG_ERR( BtLibRegisterManagementNotification, err );
if ( btStuff->amMaster ) {
pbt_setup_master( btStuff );
} else {
pbt_setup_slave( btStuff );
}
}
} /* initBTStuff */
static void
l2SocketCallback( BtLibSocketEventType* sEvent, UInt32 refCon )
{
PalmBTStuff* btStuff = (PalmBTStuff*)refCon;
BtLibSocketEventEnum event = sEvent->event;
Err err;
XP_LOGF( "%s(%s)", __FUNCTION__, btEvtToStr(event) );
switch( event ) {
case btLibSocketEventConnectRequest:
err = BtLibSocketRespondToConnection( btStuff->btLibRefNum,
sEvent->socket, true );
LOG_ERR( BtLibSocketRespondToConnection, err );
break;
case btLibSocketEventConnectedInbound:
if ( sEvent->status == errNone ) {
btStuff->dataSocket = sEvent->eventData.newSocket;
XP_LOGF( "we have a data socket!!!" );
pbt_send_pending( btStuff );
} else {
XP_LOGF( "%s: status = %d(%s)", __FUNCTION__,
sEvent->status, btErrToStr(sEvent->status) );
}
break;
case btLibSocketEventConnectedOutbound:
pbt_send_pending( btStuff );
break;
case btLibSocketEventData:
(*btStuff->cb)( btStuff->globals, sEvent->eventData.data.data,
sEvent->eventData.data.dataLen );
break;
default:
break;
}
} /* l2SocketCallback */
/***********************************************************************
* Callbacks
***********************************************************************/
static void
spdSocketCallback( BtLibSocketEventType* sEvent, UInt32 refCon )
{
Err err;
PalmBTStuff* btStuff = (PalmBTStuff*)refCon;
BtLibSocketEventEnum event = sEvent->event;
XP_LOGF( "%s(%s)", __FUNCTION__, btEvtToStr(event) );
XP_ASSERT( sEvent->socket == btStuff->u.slave.spdSocket );
XP_ASSERT( !btStuff->amMaster );
switch( event ) {
case btLibSocketEventSdpGetPsmByUuid:
if ( btLibErrNoError == sEvent->status ) {
err = BtLibSocketClose( btStuff->btLibRefNum,
sEvent->socket );
LOG_ERR( BtLibSocketClose, err );
btStuff->u.slave.spdSocket = SOCK_INVAL;
pbt_connect_slave( btStuff, sEvent->eventData.sdpByUuid.param.psm );
}
break;
default: /* happy now, compiler? */
break;
}
} /* spdSocketCallback */
static void
libMgmtCallback( BtLibManagementEventType* mEvent, UInt32 refCon )
{
PalmBTStuff* btStuff = (PalmBTStuff*)refCon;
BtLibManagementEventEnum event = mEvent->event;
XP_LOGF( "%s(%s)", __FUNCTION__, mgmtEvtToStr(event) );
switch( event ) {
case btLibManagementEventACLConnectOutbound:
if ( btLibErrNoError == mEvent->status ) {
XP_LOGF( "successful ACL connection to master!" );
pbt_find_psm( btStuff );
}
break;
case btLibManagementEventACLConnectInbound:
if ( btLibErrNoError == mEvent->status ) {
XP_LOGF( "successful ACL connection!" );
}
break;
default:
break;
}
} /* libMgmtCallback */
/***********************************************************************
* Debug helpers for verbose logging
***********************************************************************/
#ifdef DEBUG
# define CASESTR(e) case(e): return #e
static const char*
btEvtToStr( BtLibSocketEventEnum evt )
{
switch( evt ) {
CASESTR(btLibSocketEventConnectRequest);
CASESTR(btLibSocketEventConnectedOutbound);
CASESTR(btLibSocketEventConnectedInbound);
CASESTR(btLibSocketEventDisconnected);
CASESTR(btLibSocketEventData);
CASESTR(btLibSocketEventSendComplete);
CASESTR(btLibSocketEventSdpServiceRecordHandle);
CASESTR(btLibSocketEventSdpGetAttribute);
CASESTR(btLibSocketEventSdpGetStringLen);
CASESTR(btLibSocketEventSdpGetNumListEntries);
CASESTR(btLibSocketEventSdpGetNumLists);
CASESTR(btLibSocketEventSdpGetRawAttribute);
CASESTR(btLibSocketEventSdpGetRawAttributeSize);
CASESTR(btLibSocketEventSdpGetServerChannelByUuid);
CASESTR(btLibSocketEventSdpGetPsmByUuid);
default:
XP_ASSERT(0);
return "";
}
} /* btEvtToStr */
static const char*
mgmtEvtToStr( BtLibManagementEventEnum event )
{
switch( event ) {
CASESTR(btLibManagementEventRadioState);
CASESTR(btLibManagementEventInquiryResult);
CASESTR(btLibManagementEventInquiryComplete);
CASESTR(btLibManagementEventInquiryCanceled);
CASESTR(btLibManagementEventACLDisconnect);
CASESTR(btLibManagementEventACLConnectInbound);
CASESTR(btLibManagementEventACLConnectOutbound);
CASESTR(btLibManagementEventPiconetCreated);
CASESTR(btLibManagementEventPiconetDestroyed);
CASESTR(btLibManagementEventModeChange);
CASESTR(btLibManagementEventAccessibilityChange);
CASESTR(btLibManagementEventEncryptionChange);
CASESTR(btLibManagementEventRoleChange);
CASESTR(btLibManagementEventNameResult);
CASESTR(btLibManagementEventLocalNameChange);
CASESTR(btLibManagementEventAuthenticationComplete);
CASESTR(btLibManagementEventPasskeyRequest);
CASESTR(btLibManagementEventPasskeyRequestComplete);
CASESTR(btLibManagementEventPairingComplete);
default:
XP_ASSERT(0);
return "unknown";
}
} /* mgmtEvtToStr */
static const char*
btErrToStr( Err err )
{
switch ( err ) {
CASESTR(btLibErrNoError);
CASESTR(btLibErrError);
CASESTR(btLibErrNotOpen);
CASESTR(btLibErrBluetoothOff);
CASESTR(btLibErrNoPrefs);
CASESTR(btLibErrAlreadyOpen);
CASESTR(btLibErrOutOfMemory);
CASESTR(btLibErrFailed);
CASESTR(btLibErrInProgress);
CASESTR(btLibErrParamError);
CASESTR(btLibErrTooMany);
CASESTR(btLibErrPending);
CASESTR(btLibErrNotInProgress);
CASESTR(btLibErrRadioInitFailed);
CASESTR(btLibErrRadioFatal);
CASESTR(btLibErrRadioInitialized);
CASESTR(btLibErrRadioSleepWake);
CASESTR(btLibErrNoConnection);
CASESTR(btLibErrAlreadyRegistered);
CASESTR(btLibErrNoAclLink);
CASESTR(btLibErrSdpRemoteRecord);
CASESTR(btLibErrSdpAdvertised);
CASESTR(btLibErrSdpFormat);
CASESTR(btLibErrSdpNotAdvertised);
CASESTR(btLibErrSdpQueryVersion);
CASESTR(btLibErrSdpQueryHandle);
CASESTR(btLibErrSdpQuerySyntax);
CASESTR(btLibErrSdpQueryPduSize);
CASESTR(btLibErrSdpQueryContinuation);
CASESTR(btLibErrSdpQueryResources);
CASESTR(btLibErrSdpQueryDisconnect);
CASESTR(btLibErrSdpInvalidResponse);
CASESTR(btLibErrSdpAttributeNotSet);
CASESTR(btLibErrSdpMapped);
CASESTR(btLibErrSocket);
CASESTR(btLibErrSocketProtocol);
CASESTR(btLibErrSocketRole);
CASESTR(btLibErrSocketPsmUnavailable);
CASESTR(btLibErrSocketChannelUnavailable);
CASESTR(btLibErrSocketUserDisconnect);
CASESTR(btLibErrCanceled);
CASESTR(btLibErrBusy);
CASESTR(btLibMeStatusUnknownHciCommand);
CASESTR(btLibMeStatusNoConnection);
CASESTR(btLibMeStatusHardwareFailure);
CASESTR(btLibMeStatusPageTimeout);
CASESTR(btLibMeStatusAuthenticateFailure);
CASESTR(btLibMeStatusMissingKey);
CASESTR(btLibMeStatusMemoryFull);
CASESTR(btLibMeStatusConnnectionTimeout);
CASESTR(btLibMeStatusMaxConnections);
CASESTR(btLibMeStatusMaxScoConnections);
CASESTR(btLibMeStatusMaxAclConnections);
CASESTR(btLibMeStatusCommandDisallowed);
CASESTR(btLibMeStatusLimitedResources);
CASESTR(btLibMeStatusSecurityError);
CASESTR(btLibMeStatusPersonalDevice);
CASESTR(btLibMeStatusHostTimeout);
CASESTR(btLibMeStatusUnsupportedFeature);
CASESTR(btLibMeStatusInvalidHciParam);
CASESTR(btLibMeStatusUserTerminated);
CASESTR(btLibMeStatusLowResources);
CASESTR(btLibMeStatusPowerOff);
CASESTR(btLibMeStatusLocalTerminated);
CASESTR(btLibMeStatusRepeatedAttempts);
CASESTR(btLibMeStatusPairingNotAllowed);
CASESTR(btLibMeStatusUnknownLmpPDU);
CASESTR(btLibMeStatusUnsupportedRemote);
CASESTR(btLibMeStatusScoOffsetRejected);
CASESTR(btLibMeStatusScoIntervalRejected);
CASESTR(btLibMeStatusScoAirModeRejected);
CASESTR(btLibMeStatusInvalidLmpParam);
CASESTR(btLibMeStatusUnspecifiedError);
CASESTR(btLibMeStatusUnsupportedLmpParam);
CASESTR(btLibMeStatusRoleChangeNotAllowed);
CASESTR(btLibMeStatusLmpResponseTimeout);
CASESTR(btLibMeStatusLmpTransdCollision);
CASESTR(btLibMeStatusLmpPduNotAllowed);
CASESTR(btLibL2DiscReasonUnknown);
CASESTR(btLibL2DiscUserRequest);
CASESTR(btLibL2DiscRequestTimeout);
CASESTR(btLibL2DiscLinkDisc);
CASESTR(btLibL2DiscQosViolation);
CASESTR(btLibL2DiscSecurityBlock);
CASESTR(btLibL2DiscConnPsmUnsupported);
CASESTR(btLibL2DiscConnSecurityBlock);
CASESTR(btLibL2DiscConnNoResources);
CASESTR(btLibL2DiscConfigUnacceptable);
CASESTR(btLibL2DiscConfigReject);
CASESTR(btLibL2DiscConfigOptions);
CASESTR(btLibServiceShutdownAppUse);
CASESTR(btLibServiceShutdownPowerCycled);
CASESTR(btLibServiceShutdownAclDrop);
CASESTR(btLibServiceShutdownTimeout);
CASESTR(btLibServiceShutdownDetached);
CASESTR(btLibErrInUseByService);
CASESTR(btLibErrNoPiconet);
CASESTR(btLibErrRoleChange);
CASESTR(btLibErrSdpNotMapped);
CASESTR(btLibErrAlreadyConnected);
CASESTR(btLibErrStackNotOpen);
CASESTR(btLibErrBatteryTooLow);
CASESTR(btLibErrNotFound);
CASESTR(btLibNotYetSupported);
default:
return "unknown err";
}
} /* btErrToStr */
static void
palm_bt_log( const char* btfunc, const char* func, Err err )
{
/* if ( errNone != err ) { */
XP_LOGF( "%s from %s called in %s", btErrToStr(err), btfunc, func );
/* } */
}
#endif /* DEBUG */
/*
use piconet? With that, HOST sets it up and clients join. That establishes
ACL links that can then be used to open sockets. I think. How to get from
piconet advertising to clients connecting?
See http://www.palmos.com/dev/support/docs/palmos/BTCompanion.html
NOTE: I've read conflicting reports on whether a listening socket is good for
accepting more than one inbound connection. Confirm. Or just do a piconet.
*/
#endif /* #ifdef XWFEATURE_PALM_BLUETOOTH */

37
palm/palmbt.h Normal file
View file

@ -0,0 +1,37 @@
/* -*-mode: C; fill-column: 77; c-basic-offset: 4; -*- */
/*
* Copyright 2006 by Eric House (xwords@eehouse.org). All rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef _PALMBT_H_
#define _PALMBT_H_
#ifdef XWFEATURE_PALM_BLUETOOTH
#include "comms.h"
#include "palmmain.h"
typedef void (*DataCb)( PalmAppGlobals* globals,
const XP_U8* data, XP_U16 len );
void palm_bt_init( PalmAppGlobals* globals, DataCb cb, XP_Bool amMaster );
void palm_bt_close( PalmAppGlobals* globals );
XP_S16 palm_bt_send( const XP_U8* buf, XP_U16 len, PalmAppGlobals* globals );
XP_Bool btSocketIsOpen( PalmAppGlobals* globals );
#endif
#endif

View file

@ -204,7 +204,7 @@ ip_addr_change( PalmAppGlobals* globals, const CommsAddrRec* oldAddr,
/* Deal with NetLibSend's willingness to send less than the full buffer */
static XP_Bool
sendLoop( PalmAppGlobals* globals, XP_U8* buf, XP_U16 len )
sendLoop( PalmAppGlobals* globals, const XP_U8* buf, XP_U16 len )
{
XP_U16 totalSent = 0;
@ -237,7 +237,7 @@ sendLoop( PalmAppGlobals* globals, XP_U8* buf, XP_U16 len )
} /* sendLoop */
XP_S16
palm_ip_send( XP_U8* buf, XP_U16 len, const CommsAddrRec* addrp,
palm_ip_send( const XP_U8* buf, XP_U16 len, const CommsAddrRec* addrp,
PalmAppGlobals* globals )
{
CommsAddrRec localRec;
@ -344,7 +344,7 @@ packetToStream( PalmAppGlobals* globals )
void
checkHandleNetEvents( PalmAppGlobals* globals )
{
if ( socketIsOpen( globals ) ) {
if ( ipSocketIsOpen( globals ) ) {
NetFDSetType readFDs;
NetFDSetType writeFDs;
NetFDSetType ignoreFDs;

View file

@ -24,7 +24,7 @@
void palm_ip_setup( PalmAppGlobals* globals );
void palm_ip_close( PalmAppGlobals* globals );
XP_S16 palm_ip_send( XP_U8* buf, XP_U16 len, const CommsAddrRec* addr,
XP_S16 palm_ip_send( const XP_U8* buf, XP_U16 len, const CommsAddrRec* addr,
PalmAppGlobals* globals );
void ip_addr_change( PalmAppGlobals* globals, const CommsAddrRec* oldAddr,
const CommsAddrRec* newAddr );

View file

@ -462,7 +462,7 @@ ir_cleanup( PalmAppGlobals* globals )
* outgoing.
*/
XP_S16
palm_ir_send( XP_U8* buf, XP_U16 len, PalmAppGlobals* globals )
palm_ir_send( const XP_U8* buf, XP_U16 len, PalmAppGlobals* globals )
{
#ifdef IR_EXCHMGR
UInt32 sent = 0;

View file

@ -87,7 +87,7 @@ XP_Bool loadReceivedMove( PalmAppGlobals* globals, MemHandle moveData );
void palm_ir_receiveMove( PalmAppGlobals* globals, ExgSocketPtr socket );
XP_S16 palm_ir_send( XP_U8* buf, XP_U16 len, PalmAppGlobals* globals );
XP_S16 palm_ir_send( const XP_U8* buf, XP_U16 len, PalmAppGlobals* globals );
#ifdef XWFEATURE_STANDALONE_ONLY
# define palm_ir_send (TransportSend)NULL

View file

@ -1,4 +1,4 @@
/* -*-mode: C; fill-column: 77; c-basic-offset: 4; -*- */
/* -*-mode: C; fill-column: 77; c-basic-offset: 4; compile-command: "make ARCH=68K_ONLY MEMDEBUG=TRUE"; -*- */
/*
* Copyright 1999 - 2004 by Eric House (xwords@eehouse.org). All rights reserved.
*
@ -33,7 +33,7 @@
#include <unix_stdarg.h>
#include <FileStream.h>
#ifdef FEATURE_SILK
#include <SonyCLIE.h>
# include <SonyCLIE.h>
#endif
#include "comtypes.h"
@ -51,6 +51,7 @@
#include "strutils.h"
#include "palmir.h"
#include "palmip.h"
#include "palmbt.h"
#include "xwcolors.h"
#include "prefsdlg.h"
#include "connsdlg.h"
@ -114,8 +115,8 @@ static UInt16 romVersion( void );
static Boolean handleHintRequest( PalmAppGlobals* globals );
static XP_Bool timeForTimer( PalmAppGlobals* globals, XWTimerReason* why,
XP_U32* when );
static XP_S16 palm_send( XP_U8* buf, XP_U16 len, const CommsAddrRec* addr,
void* closure );
static XP_S16 palm_send( const XP_U8* buf, XP_U16 len,
const CommsAddrRec* addr, void* closure );
static void palm_send_on_close( XWStreamCtxt* stream, void* closure );
/* callbacks */
@ -155,7 +156,7 @@ static XP_Bool palm_util_warnIllegalWord( XW_UtilCtxt* uc, BadWordInfo* bwi,
XP_U16 turn, XP_Bool turnLost );
#ifdef BEYOND_IR
static void palm_util_addrChange( XW_UtilCtxt* uc, const CommsAddrRec* oldAddr,
const CommsAddrRec* newAddr );
const CommsAddrRec* newAddr, XP_Bool isServer );
#endif
#ifdef XWFEATURE_SEARCHLIMIT
static XP_Bool palm_util_getTraySearchLimits( XW_UtilCtxt* uc, XP_U16* min,
@ -1301,6 +1302,9 @@ stopApplication( PalmAppGlobals* globals )
#ifdef BEYOND_IR
palm_ip_close( globals );
#endif
#endif
#ifdef XWFEATURE_PALM_BLUETOOTH
palm_bt_close( globals );
#endif
if ( !!globals->dictList ) {
@ -1349,9 +1353,15 @@ figureWaitTicks( PalmAppGlobals* globals )
if ( 0 ) {
#ifdef BEYOND_IR
} else if ( socketIsOpen(globals) ) {
} else if ( ipSocketIsOpen(globals) ) {
/* we'll do our sleeping in NetLibSelect */
result = 0;
# ifdef XWFEATURE_PALM_BLUETOOTH
} else if ( btSocketIsOpen(globals) ) {
/* From Whiteboard. But: what to use here? BTLib needs nil events
AFAIK. */
result = SysTicksPerSecond() / 10;
# endif
#endif
} else if ( globals->timeRequested || globals->hintPending ) {
result = 0;
@ -3365,7 +3375,7 @@ palm_util_engineProgressCallback( XW_UtilCtxt* uc )
static void
palm_util_setTimer( XW_UtilCtxt* uc, XWTimerReason why,
XP_U16 XP_UNUSED(secsFromNow),
XP_U16 XP_UNUSED_IR(secsFromNow),
TimerProc proc, void* closure )
{
PalmAppGlobals* globals = (PalmAppGlobals*)uc->closure;
@ -3439,8 +3449,8 @@ palm_send_on_close( XWStreamCtxt* stream, void* closure )
} /* palm_send_on_close */
static XP_S16
palm_send( XP_U8* buf, XP_U16 len,
const CommsAddrRec* XP_UNUSED(addr), /* !!!? */
palm_send( const XP_U8* buf, XP_U16 len,
const CommsAddrRec* XP_UNUSED_IR(addr), /* !!!? */
void* closure )
{
PalmAppGlobals* globals = (PalmAppGlobals*)closure;
@ -3454,6 +3464,11 @@ palm_send( XP_U8* buf, XP_U16 len,
case COMMS_CONN_RELAY:
result = palm_ip_send( buf, len, addr, globals );
break;
#ifdef XWFEATURE_PALM_BLUETOOTH
case COMMS_CONN_BT:
result = palm_bt_send( buf, len, globals );
break;
#endif
default:
XP_ASSERT(0);
}
@ -3521,12 +3536,31 @@ palm_util_warnIllegalWord( XW_UtilCtxt* uc, BadWordInfo* bwi,
} /* palm_util_warnIllegalWord */
#ifdef BEYOND_IR
#ifdef XWFEATURE_PALM_BLUETOOTH
static void
btDataHandler( PalmAppGlobals* globals, const XP_U8* data, XP_U16 len )
{
XWStreamCtxt* instream;
LOG_FUNC();
instream = makeSimpleStream( globals, NULL );
stream_putBytes( instream, data, len );
checkAndDeliver( globals, instream );
LOG_RETURN_VOID();
}
#endif
static void
palm_util_addrChange( XW_UtilCtxt* uc, const CommsAddrRec* oldAddr,
const CommsAddrRec* newAddr )
const CommsAddrRec* newAddr, XP_Bool isServer )
{
PalmAppGlobals* globals = (PalmAppGlobals*)uc->closure;
ip_addr_change( globals, oldAddr, newAddr );
if ( COMMS_CONN_RELAY == newAddr->conType ) {
ip_addr_change( globals, oldAddr, newAddr );
#ifdef XWFEATURE_PALM_BLUETOOTH
} else if ( COMMS_CONN_BT == newAddr->conType ) {
palm_bt_init( globals, btDataHandler, isServer );
#endif
}
}
#endif

View file

@ -215,7 +215,7 @@ typedef struct NetLibStuff {
NetSocketRef socket;
XP_Bool ipAddrInval;
} NetLibStuff;
#define socketIsOpen(g) ((g)->nlStuff.socket != -1)
#define ipSocketIsOpen(g) ((g)->nlStuff.socket != -1)
#endif
#define MAX_DLG_PARAMS 2
@ -304,6 +304,9 @@ struct PalmAppGlobals {
#ifdef BEYOND_IR
NetLibStuff nlStuff;
XP_U32 heartTimerFireAt;
# ifdef XWFEATURE_PALM_BLUETOOTH
struct PalmBTStuff* btStuff;
# endif
#endif
#ifdef DEBUG

View file

@ -132,5 +132,11 @@ XP_U8* palm_realloc(XP_U8* in, XP_U16 size);
# define XP_UNUSED_SILK(x) XP_UNUSED(x)
#endif
#ifdef BEYOND_IR
# define XP_UNUSED_IR(x) x
#else
# define XP_UNUSED_IR(x) XP_UNUSED(x)
#endif
#endif