diff --git a/xwords4/common/comms.c b/xwords4/common/comms.c index ce62b135b..73e940e30 100644 --- a/xwords4/common/comms.c +++ b/xwords4/common/comms.c @@ -132,6 +132,9 @@ static XP_Bool send_via_relay( CommsCtxt* comms, XWRELAY_Cmd cmd, XWHostID destID, void* data, int dlen ); static XWHostID getDestID( CommsCtxt* comms, XP_PlayerAddr channelNo ); static void setHeartbeatTimer( CommsCtxt* comms ); +# ifdef XWFEATURE_BLUETOOTH +static void btConnect( CommsCtxt* comms ); +# endif #endif /**************************************************************************** @@ -354,6 +357,10 @@ comms_start( CommsCtxt* comms ) if ( comms->addr.conType == COMMS_CONN_RELAY ) { comms->relayState = COMMS_RELAYSTATE_UNCONNECTED; relayConnect( comms ); +#ifdef XWFEATURE_BLUETOOTH + } else if ( comms->addr.conType == COMMS_CONN_BT ) { + btConnect( comms ); +#endif } #endif } @@ -476,14 +483,17 @@ void comms_getInitialAddr( CommsAddrRec* addr ) { /* default values; default is still IR where there's a choice */ - addr->conType = COMMS_CONN_RELAY; - addr->u.ip_relay.ipAddr = 0L; /* force 'em to set it */ - addr->u.ip_relay.port = 10999; - { - char* name = "eehouse.org"; - XP_MEMCPY( addr->u.ip_relay.hostName, name, XP_STRLEN(name)+1 ); - } - addr->u.ip_relay.cookie[0] = '\0'; +#ifdef XWFEATURE_BLUETOOTH + addr->conType = COMMS_CONN_BT; /* for temporary ease in debugging */ +#else + addr->u.ip_relay.ipAddr = 0L; /* force 'em to set it */ + addr->u.ip_relay.port = 10999; + { + char* name = "eehouse.org"; + XP_MEMCPY( addr->u.ip_relay.hostName, name, XP_STRLEN(name)+1 ); + } + addr->u.ip_relay.cookie[0] = '\0'; +#endif } /* comms_getInitialAddr */ #endif @@ -812,10 +822,12 @@ comms_checkIncomingStream( CommsCtxt* comms, XWStreamCtxt* stream, XP_ASSERT( addr == NULL || comms->addr.conType == addr->conType ); #ifdef BEYOND_IR + /* relayPreProcess returns true if consumes the message. May just eat the + header and leave a regular message to be processed below. */ if ( relayPreProcess( comms, stream, &senderID ) ) { return XP_FALSE; } - usingRelay = XP_TRUE; + usingRelay = comms->addr.conType == COMMS_CONN_RELAY; #endif connID = stream_getU32( stream ); @@ -977,6 +989,7 @@ rememberChannelAddress( CommsCtxt* comms, XP_PlayerAddr channelNo, XP_ASSERT( recs->hostID == hostID ); } else { XP_MEMSET( &recs->addr, 0, sizeof(recs->addr) ); + recs->addr.conType = comms->addr.conType; } } return recs; @@ -1145,6 +1158,17 @@ relayConnect( CommsCtxt* comms ) } } /* relayConnect */ +#ifdef XWFEATURE_BLUETOOTH +static void +btConnect( CommsCtxt* comms ) +{ + /* Ping the bt layer so it'll get sockets set up. PENDING: if I'm server + need to do this once per guest record with non-null address. */ + (void)(*comms->sendproc)( (const void*)comms, /* any valid ptr will do */ + 0, NULL, comms->sendClosure ); +} /* btConnect */ +#endif + static void relayDisconnect( CommsCtxt* comms ) { @@ -1153,7 +1177,8 @@ relayDisconnect( CommsCtxt* comms ) 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 ); + send_via_relay( comms, XWRELAY_GAME_DISCONNECT, HOST_ID_NONE, + NULL, 0 ); } } #endif diff --git a/xwords4/common/comms.h b/xwords4/common/comms.h index 2173c3ada..a9fd6091d 100644 --- a/xwords4/common/comms.h +++ b/xwords4/common/comms.h @@ -42,6 +42,10 @@ typedef enum { LAST_____FOO } CommsConnType; +/* on Palm BtLibDeviceAddressType is a 48-bit quantity. Linux's typeis the + same size. Goal is something all platforms support */ +typedef XP_U8 XP_BtAddr[6]; + #define MAX_HOSTNAME_LEN 63 typedef struct CommsAddrRec { CommsConnType conType; @@ -63,8 +67,9 @@ typedef struct CommsAddrRec { XP_UCHAR foo; /* wince doesn't like nothing here */ } ir; struct { - /* nothing? */ - XP_UCHAR foo; /* wince doesn't like nothing here */ + /* guests can browse for the host to connect to */ + XP_UCHAR hostName[MAX_HOSTNAME_LEN + 1]; + XP_BtAddr btAddr; } bt; } u; } CommsAddrRec; diff --git a/xwords4/common/comtypes.h b/xwords4/common/comtypes.h index 0132af948..4b46d2a7e 100644 --- a/xwords4/common/comtypes.h +++ b/xwords4/common/comtypes.h @@ -100,6 +100,11 @@ typedef struct CommonPrefs { XP_Bool reserved2; } CommonPrefs; +#ifdef XWFEATURE_BLUETOOTH +/* temporary debugging hack */ +# define XW_PSM 0x3131 +#endif + /* used for all vtables */ #define SET_VTABLE_ENTRY( vt, name, prefix ) \ (vt)->m_##name = prefix##_##name diff --git a/xwords4/common/memstream.c b/xwords4/common/memstream.c index c4648c725..5a30f723c 100644 --- a/xwords4/common/memstream.c +++ b/xwords4/common/memstream.c @@ -171,7 +171,8 @@ mem_stream_getBits( XWStreamCtxt* p_sctx, XP_U16 nBits ) } /* stream_getBits */ static void -mem_stream_putBytes( XWStreamCtxt* p_sctx, void* whence, XP_U16 count ) +mem_stream_putBytes( XWStreamCtxt* p_sctx, const void* whence, + XP_U16 count ) { MemStreamCtxt* stream = (MemStreamCtxt*)p_sctx; XP_U32 newSize; diff --git a/xwords4/palm/Makefile b/xwords4/palm/Makefile index c90989387..262dbf6b5 100644 --- a/xwords4/palm/Makefile +++ b/xwords4/palm/Makefile @@ -115,8 +115,11 @@ 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 +# turn on bluetooth comms option for 68K and ARM -- which won't work yet +# MYDEFS_COMMON += -DXWFEATURE_BLUETOOTH + +# Add menu allowing to choose to run 68K or ARM +# MYDEFS_COMMON += -DFEATURE_DUALCHOOSE # For Danish and perhaps other languages, custom-measure glyph height # so that overtall letters have a chance of fitting. @@ -138,7 +141,10 @@ MYDEFS_COMMON += -DIR_SUPPORT -DIR_EXCHMGR endif MYDEFS_ARM = -D__LITTLE_ENDIAN -DXW_TARGET_PNO $(MYDEFS_COMMON) -MYDEFS_68K = -DPLATFORM_PALM -D__BIG_ENDIAN $(MYDEFS_COMMON) -DAPPNAME=\"$(APPNAME)\" +MYDEFS_68K = -DPLATFORM_PALM -D__BIG_ENDIAN $(MYDEFS_COMMON) \ + -DAPPNAME=\"$(APPNAME)\" \ + +# -DXWFEATURE_BLUETOOTH BITMAP_RSRCS = \ $(BITMAPS)/rightarrow.pbitm \ diff --git a/xwords4/palm/connsdlg.c b/xwords4/palm/connsdlg.c index 5f67a522e..e58f5b599 100644 --- a/xwords4/palm/connsdlg.c +++ b/xwords4/palm/connsdlg.c @@ -24,9 +24,11 @@ #include "callback.h" #include "connsdlg.h" +#include "strutils.h" #include "palmmain.h" #include "palmutil.h" #include "palmir.h" +#include "palmbt.h" /* When user pops up via Host gadget, we want to get the port to listen on. * When pops up via the Guest gadget, we want to get the port and IP address @@ -40,6 +42,7 @@ typedef struct ConnsDlgState { XP_U16 serverRole; XP_Bool isNewGame; CommsAddrRec* addr; + XP_BtAddr btAddr; /* since there's no field, save it here */ } ConnsDlgState; static void @@ -56,38 +59,58 @@ strFromField( XP_U16 id, XP_UCHAR* buf, XP_U16 max ) } /* strFromField */ static void -ctlsFromState( PalmAppGlobals* globals, FormPtr form, ConnsDlgState* state ) +ctlsFromState( ConnsDlgState* state ) { XP_Bool isNewGame = state->isNewGame; XP_UCHAR buf[16]; CommsAddrRec* addr = state->addr; - setFieldStr( XW_CONNS_RELAY_FIELD_ID, addr->u.ip_relay.hostName ); - setFieldEditable( XW_CONNS_RELAY_FIELD_ID, isNewGame ); + if ( addr->conType == COMMS_CONN_RELAY ) { + setFieldStr( XW_CONNS_RELAY_FIELD_ID, addr->u.ip_relay.hostName ); + setFieldEditable( XW_CONNS_RELAY_FIELD_ID, isNewGame ); - StrPrintF( buf, "%d", addr->u.ip_relay.port ); - setFieldStr( XW_CONNS_PORT_FIELD_ID, buf ); - setFieldEditable( XW_CONNS_PORT_FIELD_ID, isNewGame ); + StrPrintF( buf, "%d", addr->u.ip_relay.port ); + setFieldStr( XW_CONNS_PORT_FIELD_ID, buf ); + setFieldEditable( XW_CONNS_PORT_FIELD_ID, isNewGame ); - setFieldStr( XW_CONNS_COOKIE_FIELD_ID, addr->u.ip_relay.cookie ); - setFieldEditable( XW_CONNS_COOKIE_FIELD_ID, isNewGame ); + setFieldStr( XW_CONNS_COOKIE_FIELD_ID, addr->u.ip_relay.cookie ); + setFieldEditable( XW_CONNS_COOKIE_FIELD_ID, isNewGame ); +#ifdef XWFEATURE_BLUETOOTH + } else if ( addr->conType == COMMS_CONN_BT + && state->serverRole == SERVER_ISCLIENT ) { + setFieldStr( XW_CONNS_BT_HOSTFIELD_ID, addr->u.bt.hostName ); +#endif + } } /* ctlsFromState */ static XP_Bool -stateFromCtls( PalmAppGlobals* globals, ConnsDlgState* state ) +stateFromCtls( ConnsDlgState* state ) { XP_Bool ok = XP_TRUE; XP_UCHAR buf[16]; CommsAddrRec* addr = state->addr; - strFromField( XW_CONNS_RELAY_FIELD_ID, addr->u.ip_relay.hostName, - sizeof(addr->u.ip_relay.hostName) ); + if ( addr->conType == COMMS_CONN_RELAY ) { + strFromField( XW_CONNS_RELAY_FIELD_ID, addr->u.ip_relay.hostName, + sizeof(addr->u.ip_relay.hostName) ); - strFromField( XW_CONNS_PORT_FIELD_ID, buf, sizeof(buf) ); - addr->u.ip_relay.port = StrAToI( buf ); + strFromField( XW_CONNS_PORT_FIELD_ID, buf, sizeof(buf) ); + addr->u.ip_relay.port = StrAToI( buf ); + + strFromField( XW_CONNS_COOKIE_FIELD_ID, addr->u.ip_relay.cookie, + sizeof(addr->u.ip_relay.cookie) ); +#ifdef XWFEATURE_BLUETOOTH + } else if ( addr->conType == COMMS_CONN_BT + && state->serverRole == SERVER_ISCLIENT ) { + strFromField( XW_CONNS_BT_HOSTFIELD_ID, addr->u.bt.hostName, + sizeof(addr->u.bt.hostName) ); + /* Not exactly from a control... */ + XP_MEMCPY( &addr->u.bt.btAddr, state->btAddr, + sizeof(addr->u.bt.btAddr) ); + LOG_HEX( addr->u.bt.btAddr, sizeof(addr->u.bt.btAddr), __FUNCTION__ ); +#endif + } - strFromField( XW_CONNS_COOKIE_FIELD_ID, addr->u.ip_relay.cookie, - sizeof(addr->u.ip_relay.cookie) ); return ok; } /* stateFromCtls */ @@ -103,9 +126,41 @@ updateFormCtls( FormPtr form, ConnsDlgState* state ) XW_CONNS_COOKIE_FIELD_ID, 0 }; - - disOrEnableSet( form, relayCtls, - state->addr->conType == COMMS_CONN_RELAY ); + const XP_U16 btGuestCtls[] = { +#ifdef XWFEATURE_BLUETOOTH + XW_CONNS_BT_HOSTNAME_LABEL_ID, + XW_CONNS_BT_HOSTFIELD_ID, + XW_CONNS_BT_BROWSEBUTTON_ID, +#endif + 0 + }; + const XP_U16* allCtls[] = { + relayCtls, btGuestCtls + }; + const XP_U16* on; + XP_U16 i; + + if ( state->addr->conType == COMMS_CONN_RELAY ) { + on = relayCtls; +#ifdef XWFEATURE_BLUETOOTH + } else if ( state->addr->conType == COMMS_CONN_BT + && state->serverRole == SERVER_ISCLIENT ) { + on = btGuestCtls; +#endif + } else { + on = NULL; + } + + for ( i = 0; i < sizeof(allCtls)/sizeof(allCtls[0]); ++i ) { + const XP_U16* cur = allCtls[i]; + if ( cur != on ) { + disOrEnableSet( form, cur, XP_FALSE ); + } + } + if ( on != NULL ) { + disOrEnableSet( form, on, XP_TRUE ); + } + } /* updateFormCtls */ static void @@ -119,14 +174,14 @@ cleanupExit( PalmAppGlobals* globals ) static XP_U16 conTypeToSel( CommsConnType conType ) { - XP_U16 result; + XP_U16 result = 0; switch ( conType ) { -#ifdef XWFEATURE_PALM_BLUETOOTH - case COMMS_CONN_BT: result = 0; break; +#ifdef XWFEATURE_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_IR: /* result = 0; */break; case COMMS_CONN_RELAY: result = 1; break; #endif default: @@ -140,7 +195,7 @@ selToConType( XP_U16 sel ) { CommsConnType conType; switch( sel ) { -#ifdef XWFEATURE_PALM_BLUETOOTH +#ifdef XWFEATURE_BLUETOOTH case 0: conType = COMMS_CONN_BT; break; case 1: conType = COMMS_CONN_IR; break; case 2: conType = COMMS_CONN_RELAY; break; @@ -153,6 +208,20 @@ selToConType( XP_U16 sel ) return conType; } +#ifdef XWFEATURE_BLUETOOTH +static void +browseForDeviceName( PalmAppGlobals* globals, ConnsDlgState* state ) +{ + char buf[32]; + XP_BtAddr btAddr; + if ( palm_bt_browse_device( globals, &btAddr, buf, sizeof( buf ) ) ) { + setFieldStr( XW_CONNS_BT_HOSTFIELD_ID, buf ); + XP_MEMCPY( state->btAddr, &btAddr, sizeof(state->btAddr) ); + LOG_HEX( state->btAddr, sizeof(state->btAddr), __FUNCTION__ ); + } +} /* browseForDeviceName */ +#endif + Boolean ConnsFormHandleEvent( EventPtr event ) { @@ -176,12 +245,13 @@ ConnsFormHandleEvent( EventPtr event ) switch ( event->eType ) { case frmOpenEvent: - state->serverRole = (Connectedness)globals->dlgParams[CONNS_PARAM_ROLE_INDEX]; state->addr = (CommsAddrRec*)globals->dlgParams[CONNS_PARAM_ADDR_INDEX]; state->isNewGame = globals->isNewGame; + XP_MEMCPY( state->btAddr, &state->addr->u.bt.btAddr, + sizeof(state->btAddr) ); /* setup connection popup */ state->connTypesList = getActiveObjectPtr( XW_CONNS_TYPE_LIST_ID ); @@ -191,7 +261,7 @@ ConnsFormHandleEvent( EventPtr event ) setSelectorFromList( XW_CONNS_TYPE_TRIGGER_ID, state->connTypesList, conTypeToSel(state->addr->conType) ); - ctlsFromState( globals, form, state ); + ctlsFromState( state ); updateFormCtls( form, state ); @@ -204,6 +274,12 @@ ConnsFormHandleEvent( EventPtr event ) result = true; switch ( event->data.ctlSelect.controlID ) { +#ifdef XWFEATURE_BLUETOOTH + case XW_CONNS_BT_BROWSEBUTTON_ID: + browseForDeviceName( globals, state ); + break; +#endif + case XW_CONNS_TYPE_TRIGGER_ID: if ( state->isNewGame ) { chosen = LstPopupList( state->connTypesList ); @@ -219,7 +295,7 @@ ConnsFormHandleEvent( EventPtr event ) case XW_CONNS_OK_BUTTON_ID: if ( !state->isNewGame ) { /* do nothing; same as cancel */ - } else if ( !stateFromCtls( globals, state ) ) { + } else if ( !stateFromCtls( state ) ) { beep(); break; } else { diff --git a/xwords4/palm/l10n/xwords4_en_US.rcp.pre b/xwords4/palm/l10n/xwords4_en_US.rcp.pre index caff75fc4..764e34ffe 100644 --- a/xwords4/palm/l10n/xwords4_en_US.rcp.pre +++ b/xwords4/palm/l10n/xwords4_en_US.rcp.pre @@ -240,18 +240,27 @@ BEGIN POPUPTRIGGER "" ID XW_CONNS_TYPE_TRIGGER_ID AT (PREVRIGHT+5 PREVTOP 72 12) LEFTANCHOR LIST -#ifdef XWFEATURE_PALM_BLUETOOTH +#ifdef XWFEATURE_BLUETOOTH "Bluetooth" #endif "IR" "Internet/IP" ID XW_CONNS_TYPE_LIST_ID PREVLEFT PREVTOP 72 12 VISIBLEITEMS -#ifdef XWFEATURE_PALM_BLUETOOTH +#ifdef XWFEATURE_BLUETOOTH 3 #else 2 #endif NONUSABLE POPUPLIST XW_CONNS_TYPE_TRIGGER_ID XW_CONNS_TYPE_LIST_ID +#ifdef XWFEATURE_BLUETOOTH + LABEL "host name:" XW_CONNS_BT_HOSTNAME_LABEL_ID + AT ( LEFTCOL+10 LOCALIP_TOP ) + FIELD XW_CONNS_BT_HOSTFIELD_ID CONNS_FIELD_LEFT PREVTOP 70 AUTO \ + SINGLELINE EDITABLE UNDERLINED MAXCHARS 32 + BUTTON "Browse" XW_CONNS_BT_BROWSEBUTTON_ID LEFTCOL+10 PREVBOTTOM+5 + AUTO AUTO +#endif + LABEL "Relay name:" XW_CONNS_RELAY_LABEL_ID AT ( LEFTCOL+10 LOCALIP_TOP ) FIELD XW_CONNS_RELAY_FIELD_ID CONNS_FIELD_LEFT PREVTOP 70 AUTO \ diff --git a/xwords4/palm/palmbt.c b/xwords4/palm/palmbt.c index 0d3c396fa..9569fc6f4 100644 --- a/xwords4/palm/palmbt.c +++ b/xwords4/palm/palmbt.c @@ -17,10 +17,11 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -#ifdef XWFEATURE_PALM_BLUETOOTH +#ifdef XWFEATURE_BLUETOOTH #include "xptypes.h" #include "palmbt.h" +#include "strutils.h" # include # include @@ -44,6 +45,7 @@ typedef struct PalmBTStuff { struct { BtLibDeviceAddressType masterAddr; BtLibSocketRef spdSocket; + XP_Bool addrSet; } slave; struct { BtLibSocketRef listenSocket; @@ -55,6 +57,9 @@ typedef struct PalmBTStuff { } PalmBTStuff; #define LOG_ERR(f,e) palm_bt_log( #f, __FUNCTION__, e ) +#define CALL_ERR(e,f,...) \ + e = f(__VA_ARGS__); \ + LOG_ERR(f,e) /* WHAT SHOULD THIS BE? Copied from Whiteboard.... PENDING */ static const BtLibSdpUuidType XWORDS_UUID = { @@ -62,9 +67,11 @@ static const BtLibSdpUuidType XWORDS_UUID = { { 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 Err 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 ); +static Err bpd_discover( PalmBTStuff* btStuff, BtLibDeviceAddressType* addr ); +static void pbt_setup_slave( PalmBTStuff* btStuff, const CommsAddrRec* addr ); #ifdef DEBUG static const char* btErrToStr( Err err ); @@ -81,38 +88,45 @@ static void libMgmtCallback( BtLibManagementEventType* mEvent, UInt32 refCon ); static void spdSocketCallback( BtLibSocketEventType* sEvent, UInt32 refCon ); static void l2SocketCallback( BtLibSocketEventType* sEvent, UInt32 refCon ); -void +Err palm_bt_init( PalmAppGlobals* globals, DataCb cb, XP_Bool amMaster ) { XP_LOGF( "%s(amMaster=%d)", __FUNCTION__, (XP_U16)amMaster ); - initBTStuff( globals, cb, amMaster ); + return 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 ); + if ( !!btStuff ) { + XP_U16 btLibRefNum = btStuff->btLibRefNum; + if ( btLibRefNum != 0 ) { + Err err; + + /* Need to unregister callbacks */ + (void)BtLibUnregisterManagementNotification( btLibRefNum, + libMgmtCallback ); + if ( btStuff->amMaster + && btStuff->u.master.listenSocket != SOCK_INVAL ) { + CALL_ERR( err, BtLibSocketClose, btLibRefNum, + btStuff->u.master.listenSocket ); +/* btStuff->u.master.listenSocket = SOCK_INVAL; */ + } + if ( btStuff->dataSocket != SOCK_INVAL ) { + CALL_ERR( err, BtLibSocketClose, btLibRefNum, + btStuff->u.master.listenSocket ); +/* btStuff->dataSocket = SOCK_INVAL; */ + } + + if ( !!btStuff->sdpRecordH ) { + CALL_ERR( err, BtLibSdpServiceRecordDestroy, btLibRefNum, + btStuff->sdpRecordH ); + } + + CALL_ERR( err, BtLibClose, btLibRefNum ); XP_ASSERT( errNone == err ); } XP_FREE( globals->mpool, btStuff ); @@ -120,6 +134,42 @@ palm_bt_close( PalmAppGlobals* globals ) } } /* palm_bt_close */ +XP_Bool +palm_bt_browse_device( PalmAppGlobals* globals, XP_BtAddr* btAddr, + XP_UCHAR* out, XP_U16 len ) +{ + Err err; + PalmBTStuff* btStuff; + + err = initBTStuff( globals, NULL, XP_FALSE ); + if ( errNone == err ) { + UInt16 index; + BtLibDeviceAddressType addr; + btStuff = globals->btStuff; + + err = bpd_discover( btStuff, &addr ); + CALL_ERR( err, BtLibSecurityFindTrustedDeviceRecord, + btStuff->btLibRefNum, &addr, &index ); + CALL_ERR( err, BtLibSecurityGetTrustedDeviceRecordInfo, + btStuff->btLibRefNum, index, NULL, out, len, + NULL, NULL, NULL ); + XP_ASSERT( sizeof(*btAddr) >= sizeof(addr) ); + XP_MEMCPY( btAddr, &addr, sizeof(addr) ); + + LOG_HEX( &addr, sizeof(addr), __FUNCTION__ ); + +/* err = BtLibGetRemoteDeviceName( btStuff->btLibRefNum, */ +/* BtLibDeviceAddressTypePtr remoteDeviceP, */ +/* BtLibFriendlyNameType* nameP, */ +/* BtLibGetNameEnum retrievalMethod ); */ +/* err = BtLibAddrBtdToA( btStuff->btLibRefNum, &btStuff->u.slave.masterAddr, */ +/* out, len ); */ + } else { + XP_WARNF( "%s: err = %s", __FUNCTION__, btErrToStr(err) ); + } + return errNone == err; +} /* palm_bt_browse_device */ + XP_Bool btSocketIsOpen( PalmAppGlobals* globals ) { @@ -128,74 +178,118 @@ btSocketIsOpen( PalmAppGlobals* globals ) } static void -pbt_send_pending( PalmBTStuff* btStuff ) +pbt_send_pending( PalmBTStuff* btStuff, const CommsAddrRec* addr ) { + Err err; 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; + if ( btStuff->dataSocket != SOCK_INVAL ) { + if ( btStuff->lenOut > 0 ) { /* hack: zero-len send to cause connect */ + CALL_ERR( err, BtLibSocketSend, btStuff->btLibRefNum, + btStuff->dataSocket, + btStuff->bufOut, btStuff->lenOut ); + if ( err == errNone ) { + // clear on receipt of btLibSocketEventSendComplete + btStuff->sendInProgress = XP_TRUE; + } + } else { + btStuff->sendPending = XP_FALSE; } + } else { + /* No data socket? */ + if ( !btStuff->amMaster ) { + pbt_setup_slave( btStuff, addr ); + } + } + } +} /* pbt_send_pending */ + +static void +pbt_check_socket( PalmBTStuff* btStuff, const CommsAddrRec* addr ) +{ + LOG_FUNC(); + if ( btStuff->dataSocket == SOCK_INVAL ) { + if ( btStuff->amMaster ) { + XP_ASSERT(0); +/* pbt_setup_master( btStuff ); */ + } else { + pbt_setup_slave( btStuff, addr ); } } } XP_S16 -palm_bt_send( const XP_U8* buf, XP_U16 len, PalmAppGlobals* globals ) +palm_bt_send( const XP_U8* buf, XP_U16 len, const CommsAddrRec* addr, + PalmAppGlobals* globals ) { + XP_S16 nSent = -1; PalmBTStuff* btStuff; + CommsAddrRec remoteAddr; 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 ); - } + if ( !addr ) { + comms_getAddr( globals->game.comms, &remoteAddr ); + addr = &remoteAddr; } - return -1; + XP_ASSERT( !!addr ); + + btStuff = globals->btStuff; + if ( !!btStuff ) { + pbt_check_socket( btStuff, addr ); + + 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, addr ); + nSent = len; + } else { + XP_LOGF( "%s: send ALREADY in progress", __FUNCTION__ ); + } + } + } else { + XP_LOGF( "%s: btStuff null", __FUNCTION__ ); + } + LOG_RETURNF( "%d", nSent ); + return nSent; } /* 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 ); + LOG_FUNC(); - err = BtLibSdpGetPsmByUuid( btStuff->btLibRefNum, - btStuff->u.slave.spdSocket, - &btStuff->u.slave.masterAddr, - (BtLibSdpUuidType*)&XWORDS_UUID, 1 ); - LOG_ERR( BtLibSdpGetPSMByUuid, err ); + XP_ASSERT( !btStuff->amMaster ); + + CALL_ERR( err, BtLibSocketCreate, btStuff->btLibRefNum, + &btStuff->u.slave.spdSocket, + spdSocketCallback, (UInt32)btStuff, btLibSdpProtocol ); + + /* sends btLibSocketEventSdpGetPsmByUuid */ + CALL_ERR( err, BtLibSdpGetPsmByUuid, btStuff->btLibRefNum, + btStuff->u.slave.spdSocket, + &btStuff->u.slave.masterAddr, + (BtLibSdpUuidType*)&XWORDS_UUID, 1 ); } 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 ); + XP_LOGF( "%s(psm=%x)", __FUNCTION__, psm ); + + CALL_ERR( err, BtLibSocketCreate, btStuff->btLibRefNum, + &btStuff->dataSocket, + l2SocketCallback, (UInt32)btStuff, + btLibL2CapProtocol ); if ( btLibErrNoError == err ) { BtLibSocketConnectInfoType connInfo; @@ -204,9 +298,9 @@ pbt_connect_slave( PalmBTStuff* btStuff, BtLibL2CapPsmType psm ) connInfo.data.L2Cap.minRemoteMtu = L2CAPSOCKETMTU; connInfo.remoteDeviceP = &btStuff->u.slave.masterAddr; - err = BtLibSocketConnect( btStuff->btLibRefNum, - btStuff->dataSocket, &connInfo ); - LOG_ERR( BtLibSocketConnect, err ); + /* sends btLibManagementEventACLConnectOutbound */ + CALL_ERR( err, BtLibSocketConnect, btStuff->btLibRefNum, + btStuff->dataSocket, &connInfo ); } } @@ -218,48 +312,43 @@ pbt_setup_master( PalmBTStuff* btStuff ) 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 ); + CALL_ERR( err, BtLibSocketCreate, btStuff->btLibRefNum, + &btStuff->u.master.listenSocket, l2SocketCallback, + (UInt32)btStuff, btLibL2CapProtocol ); /* 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.localPsm = XW_PSM; // 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 ); + CALL_ERR( err, BtLibSocketListen, btStuff->btLibRefNum, + btStuff->u.master.listenSocket, &listenInfo ); /* 3. BtLibSdpServiceRecordCreate: allocate a memory chunk that represents an SDP service record. */ - err = BtLibSdpServiceRecordCreate(btStuff->btLibRefNum, &btStuff->sdpRecordH ); - LOG_ERR( BtLibSdpServiceRecordCreate, err ); + CALL_ERR( err, BtLibSdpServiceRecordCreate, + btStuff->btLibRefNum, &btStuff->sdpRecordH ); /* 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 ); + CALL_ERR( err, BtLibSdpServiceRecordSetAttributesForSocket, + btStuff->btLibRefNum, btStuff->u.master.listenSocket, + (BtLibSdpUuidType*)&XWORDS_UUID, 1, APPNAME, + StrLen(APPNAME), btStuff->sdpRecordH ); /* 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 ); + CALL_ERR( err, BtLibSdpServiceRecordStartAdvertising, btStuff->btLibRefNum, + btStuff->sdpRecordH ); } /* pbt_setup_master */ -static void -pbt_setup_slave( PalmBTStuff* btStuff ) +static Err +bpd_discover( PalmBTStuff* btStuff, BtLibDeviceAddressType* addr ) { Err err; static const BtLibClassOfDeviceType deviceFilter @@ -267,68 +356,103 @@ pbt_setup_slave( PalmBTStuff* btStuff ) | btLibCOD_Major_Any // btLibCOD_Major_Computer | btLibCOD_Minor_Comp_Any; //btLibCOD_Minor_Comp_Palm; + CALL_ERR( err, BtLibDiscoverSingleDevice, btStuff->btLibRefNum, "Crosswords host", + (BtLibClassOfDeviceType*)&deviceFilter, 1, + addr, false, false ); + LOG_RETURNF( "%s", btErrToStr(err) ); + return err; +} /* bpd_discover */ + +static void +pbt_setup_slave( PalmBTStuff* btStuff, const CommsAddrRec* addr ) +{ + LOG_FUNC(); XP_ASSERT( !btStuff->amMaster ); - err = BtLibDiscoverSingleDevice( btStuff->btLibRefNum, "Crosswords host", - (BtLibClassOfDeviceType*)&deviceFilter, 1, - &btStuff->u.slave.masterAddr, - false, false ); - LOG_ERR( BtLibDiscoverSingleDevice, err ); + if ( !!addr ) { + char buf[64]; + if ( errNone == BtLibAddrBtdToA( btStuff->btLibRefNum, + (BtLibDeviceAddressType*)&addr->u.bt.btAddr, + buf, sizeof(buf) ) ) { + XP_LOGF( "%s(%s)", __FUNCTION__, buf ); + } + } else { + XP_LOGF( "null addr" ); + } - if ( errNone == err ) { - err = BtLibLinkConnect( btStuff->btLibRefNum, - &btStuff->u.slave.masterAddr ); - LOG_ERR( BtLibLinkConnect, err ); + if ( !btStuff->u.slave.addrSet && !!addr ) { + Err err; + + /* Our xp type better be big enough */ + XP_ASSERT( sizeof(addr->u.bt.btAddr) + >= sizeof(btStuff->u.slave.masterAddr) ); + XP_MEMCPY( &btStuff->u.slave.masterAddr, addr->u.bt.btAddr, + sizeof(btStuff->u.slave.masterAddr) ); + + btStuff->u.slave.addrSet = XP_TRUE; + + CALL_ERR( err, BtLibLinkConnect, btStuff->btLibRefNum, + &btStuff->u.slave.masterAddr ); XP_ASSERT( err == btLibErrPending ); + } else { + XP_LOGF( "%s: doing nothing", __FUNCTION__ ); } } /* pbt_setup_slave */ -static void +static Err initBTStuff( PalmAppGlobals* globals, DataCb cb, XP_Bool amMaster ) { PalmBTStuff* btStuff; Err err; - XP_U16 btLibRefNum; + + LOG_FUNC(); btStuff = globals->btStuff; if ( btStuff != NULL ) { + if ( NULL != cb ) { + btStuff->cb = cb; + } if ( btStuff->amMaster == amMaster ) { /* nothing to do */ } else { /* role change. Adapt... */ XP_ASSERT( 0 ); } + err = errNone; } else { + XP_U16 btLibRefNum; - btStuff = XP_MALLOC( globals->mpool, sizeof(*btStuff) ); - XP_ASSERT( !!btStuff ); - XP_MEMSET( btStuff, 0, sizeof(*btStuff) ); - globals->btStuff = btStuff; + CALL_ERR( err, SysLibFind, btLibName, &btLibRefNum ); + if ( errNone == err ) { - btStuff->globals = globals; - btStuff->cb = cb; - btStuff->amMaster = amMaster; - btStuff->dataSocket = SOCK_INVAL; + btStuff = XP_MALLOC( globals->mpool, sizeof(*btStuff) ); + XP_ASSERT( !!btStuff ); + XP_MEMSET( btStuff, 0, sizeof(*btStuff) ); + globals->btStuff = btStuff; - err = SysLibFind( btLibName, &btLibRefNum ); - XP_LOGF( "%s: SysLibFind(%s) => %d\n", __FUNCTION__, btLibName, err ); - XP_ASSERT( errNone == err ); - btStuff->btLibRefNum = btLibRefNum; + btStuff->globals = globals; + btStuff->cb = cb; + btStuff->amMaster = amMaster; + btStuff->dataSocket = SOCK_INVAL; - err = BtLibOpen( btLibRefNum, false ); - LOG_ERR( BtLibOpen, err ); - XP_ASSERT( errNone == err ); + btStuff->btLibRefNum = btLibRefNum; - err = BtLibRegisterManagementNotification( btLibRefNum, libMgmtCallback, - (UInt32)btStuff ); - LOG_ERR( BtLibRegisterManagementNotification, err ); + CALL_ERR( err, BtLibOpen, btLibRefNum, false ); + XP_ASSERT( errNone == err ); - if ( btStuff->amMaster ) { - pbt_setup_master( btStuff ); - } else { - pbt_setup_slave( btStuff ); + CALL_ERR( err, BtLibRegisterManagementNotification, btLibRefNum, + libMgmtCallback, (UInt32)btStuff ); + + if ( btStuff->amMaster ) { + pbt_setup_master( btStuff ); + } else { + /* Can't set up b/c don't have address yet. */ + /* pbt_setup_slave( btStuff, addr ); */ + } } } + LOG_RETURNF( "%s", btErrToStr(err) ); + return err; } /* initBTStuff */ static void @@ -342,24 +466,24 @@ l2SocketCallback( BtLibSocketEventType* sEvent, UInt32 refCon ) switch( event ) { case btLibSocketEventConnectRequest: - err = BtLibSocketRespondToConnection( btStuff->btLibRefNum, - sEvent->socket, true ); - LOG_ERR( BtLibSocketRespondToConnection, err ); + CALL_ERR( err, BtLibSocketRespondToConnection, btStuff->btLibRefNum, + sEvent->socket, true ); break; case btLibSocketEventConnectedInbound: if ( sEvent->status == errNone ) { btStuff->dataSocket = sEvent->eventData.newSocket; XP_LOGF( "we have a data socket!!!" ); - pbt_send_pending( btStuff ); + pbt_send_pending( btStuff, NULL ); } else { XP_LOGF( "%s: status = %d(%s)", __FUNCTION__, sEvent->status, btErrToStr(sEvent->status) ); } break; case btLibSocketEventConnectedOutbound: - pbt_send_pending( btStuff ); + pbt_send_pending( btStuff, NULL ); break; case btLibSocketEventData: + XP_ASSERT( !!btStuff->cb ); (*btStuff->cb)( btStuff->globals, sEvent->eventData.data.data, sEvent->eventData.data.dataLen ); break; @@ -385,11 +509,11 @@ spdSocketCallback( BtLibSocketEventType* sEvent, UInt32 refCon ) switch( event ) { case btLibSocketEventSdpGetPsmByUuid: if ( btLibErrNoError == sEvent->status ) { - err = BtLibSocketClose( btStuff->btLibRefNum, - sEvent->socket ); - LOG_ERR( BtLibSocketClose, err ); + CALL_ERR( err, BtLibSocketClose, btStuff->btLibRefNum, + sEvent->socket ); btStuff->u.slave.spdSocket = SOCK_INVAL; - pbt_connect_slave( btStuff, sEvent->eventData.sdpByUuid.param.psm ); + pbt_connect_slave( btStuff, + sEvent->eventData.sdpByUuid.param.psm ); } break; default: /* happy now, compiler? */ @@ -616,4 +740,4 @@ 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 */ +#endif /* #ifdef XWFEATURE_BLUETOOTH */ diff --git a/xwords4/palm/palmbt.h b/xwords4/palm/palmbt.h index 408021c75..d97c206f0 100644 --- a/xwords4/palm/palmbt.h +++ b/xwords4/palm/palmbt.h @@ -20,7 +20,7 @@ #ifndef _PALMBT_H_ #define _PALMBT_H_ -#ifdef XWFEATURE_PALM_BLUETOOTH +#ifdef XWFEATURE_BLUETOOTH #include "comms.h" #include "palmmain.h" @@ -28,10 +28,15 @@ typedef void (*DataCb)( PalmAppGlobals* globals, const XP_U8* data, XP_U16 len ); -void palm_bt_init( PalmAppGlobals* globals, DataCb cb, XP_Bool amMaster ); +Err 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_S16 palm_bt_send( const XP_U8* buf, XP_U16 len, const CommsAddrRec* addr, + PalmAppGlobals* globals ); XP_Bool btSocketIsOpen( PalmAppGlobals* globals ); -#endif + +XP_Bool palm_bt_browse_device( PalmAppGlobals* globals, XP_BtAddr* btAddr, + XP_UCHAR* out,XP_U16 len ); + +#endif /* XWFEATURE_BLUETOOTH */ #endif diff --git a/xwords4/palm/palmmain.c b/xwords4/palm/palmmain.c index dd4bf6260..fb7b69a6e 100644 --- a/xwords4/palm/palmmain.c +++ b/xwords4/palm/palmmain.c @@ -1303,7 +1303,7 @@ stopApplication( PalmAppGlobals* globals ) palm_ip_close( globals ); #endif #endif -#ifdef XWFEATURE_PALM_BLUETOOTH +#ifdef XWFEATURE_BLUETOOTH palm_bt_close( globals ); #endif @@ -1356,7 +1356,7 @@ figureWaitTicks( PalmAppGlobals* globals ) } else if ( ipSocketIsOpen(globals) ) { /* we'll do our sleeping in NetLibSelect */ result = 0; -# ifdef XWFEATURE_PALM_BLUETOOTH +# ifdef XWFEATURE_BLUETOOTH } else if ( btSocketIsOpen(globals) ) { /* From Whiteboard. But: what to use here? BTLib needs nil events AFAIK. */ @@ -1888,6 +1888,8 @@ initAndStartBoard( PalmAppGlobals* globals, XP_Bool newGame ) if ( !!globals->game.comms ) { comms_setAddr( globals->game.comms, &globals->newGameState.addr ); + } else { + XP_ASSERT(0); } #endif } @@ -3450,8 +3452,7 @@ palm_send_on_close( XWStreamCtxt* stream, void* closure ) static XP_S16 palm_send( const XP_U8* buf, XP_U16 len, - const CommsAddrRec* XP_UNUSED_IR(addr), /* !!!? */ - void* closure ) + const CommsAddrRec* addr, void* closure ) { PalmAppGlobals* globals = (PalmAppGlobals*)closure; @@ -3464,9 +3465,9 @@ palm_send( const XP_U8* buf, XP_U16 len, case COMMS_CONN_RELAY: result = palm_ip_send( buf, len, addr, globals ); break; -#ifdef XWFEATURE_PALM_BLUETOOTH +#ifdef XWFEATURE_BLUETOOTH case COMMS_CONN_BT: - result = palm_bt_send( buf, len, globals ); + result = palm_bt_send( buf, len, addr, globals ); break; #endif default: @@ -3536,7 +3537,7 @@ palm_util_warnIllegalWord( XW_UtilCtxt* uc, BadWordInfo* bwi, } /* palm_util_warnIllegalWord */ #ifdef BEYOND_IR -#ifdef XWFEATURE_PALM_BLUETOOTH +#ifdef XWFEATURE_BLUETOOTH static void btDataHandler( PalmAppGlobals* globals, const XP_U8* data, XP_U16 len ) { @@ -3554,10 +3555,18 @@ palm_util_addrChange( XW_UtilCtxt* uc, const CommsAddrRec* oldAddr, const CommsAddrRec* newAddr, XP_Bool isServer ) { PalmAppGlobals* globals = (PalmAppGlobals*)uc->closure; + +#ifdef XWFEATURE_BLUETOOTH + XP_Bool isBT = COMMS_CONN_BT == newAddr->conType; + if ( !isBT ) { + palm_bt_close( globals ); + } +#endif + if ( COMMS_CONN_RELAY == newAddr->conType ) { ip_addr_change( globals, oldAddr, newAddr ); -#ifdef XWFEATURE_PALM_BLUETOOTH - } else if ( COMMS_CONN_BT == newAddr->conType ) { +#ifdef XWFEATURE_BLUETOOTH + } else if ( isBT ) { palm_bt_init( globals, btDataHandler, isServer ); #endif } diff --git a/xwords4/palm/palmmain.h b/xwords4/palm/palmmain.h index 7c8de93e0..b023edcb2 100644 --- a/xwords4/palm/palmmain.h +++ b/xwords4/palm/palmmain.h @@ -304,7 +304,7 @@ struct PalmAppGlobals { #ifdef BEYOND_IR NetLibStuff nlStuff; XP_U32 heartTimerFireAt; -# ifdef XWFEATURE_PALM_BLUETOOTH +# ifdef XWFEATURE_BLUETOOTH struct PalmBTStuff* btStuff; # endif #endif diff --git a/xwords4/palm/xwords4defines.h b/xwords4/palm/xwords4defines.h index 895caf08f..d4ca9a211 100644 --- a/xwords4/palm/xwords4defines.h +++ b/xwords4/palm/xwords4defines.h @@ -334,6 +334,11 @@ #define XW_CONNS_PORT_FIELD_ID 2907 #define XW_CONNS_RELAY_LABEL_ID 2908 #define XW_CONNS_RELAY_FIELD_ID 2909 +#ifdef XWFEATURE_BLUETOOTH +# define XW_CONNS_BT_HOSTNAME_LABEL_ID 2910 +# define XW_CONNS_BT_HOSTFIELD_ID 2911 +# define XW_CONNS_BT_BROWSEBUTTON_ID 2912 +#endif /* * selector for number of tiles during hint