Gammu internals  1.38.0
blue_osx.c
Go to the documentation of this file.
1 /*
2 
3  Based over gnokii code, addapation to Gammu by Michal Čihař
4 
5  Gnokii is free software; you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation; either version 2 of the License, or
8  (at your option) any later version.
9 
10  Gnokii is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  GNU General Public License for more details.
14 
15  You should have received a copy of the GNU General Public License
16  along with gnokii; if not, write to the Free Software
17  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 
19  Copyright (C) 1999-2000 Hugh Blemings & Pavel Janík ml.
20  Copyright (C) 2003 Siegfried Schloissnig
21 
22 */
23 
24 #include "../../gsmstate.h"
25 
26 #ifdef GSM_ENABLE_BLUETOOTHDEVICE
27 #ifdef OSX_BLUE_FOUND
28 
29 #include <CoreFoundation/CoreFoundation.h>
30 #include <IOBluetooth/Bluetooth.h>
31 #include <IOBluetooth/IOBluetoothUtilities.h>
32 #include <IOBluetooth/IOBluetoothUserLib.h>
33 #include <pthread.h>
34 
35 typedef struct {
36  IOBluetoothRFCOMMChannelRef rfcommChannel;
37  IOReturn ioReturnValue;
38  pthread_t threadID;
39 
40  BluetoothDeviceAddress deviceAddress;
41  uint8_t nChannel;
42 
43  pthread_mutex_t mutexWait;
44 
45  CFMutableArrayRef arrDataReceived;
46 } threadContext;
47 
48 typedef struct {
49  void *pData;
50  unsigned int nSize;
51 } dataBlock;
52 
53 static void thread_rfcommDataListener(IOBluetoothRFCOMMChannelRef rfcommChannel,
54  void* data, UInt16 length, void* refCon)
55 {
56  threadContext *pContext = (threadContext *)refCon;
57  void *pBuffer = malloc(length);
58  dataBlock *pDataBlock = (dataBlock *)malloc(sizeof(dataBlock));
59 
60  memcpy(pBuffer, data, length);
61 
62  pDataBlock->pData = pBuffer;
63  pDataBlock->nSize = length;
64 
65  pthread_mutex_lock(&(pContext->mutexWait));
66  CFArrayAppendValue(pContext->arrDataReceived, pDataBlock);
67  pthread_mutex_unlock(&(pContext->mutexWait));
68 }
69 
70 #ifdef OSX_BLUE_2_0
71 void thread_rfcommEventListener (IOBluetoothRFCOMMChannelRef rfcommChannel,
72  void *refCon, IOBluetoothRFCOMMChannelEvent *event)
73 {
74  if (event->eventType == kIOBluetoothRFCOMMNewDataEvent) {
75  thread_rfcommDataListener(rfcommChannel, event->u.newData.dataPtr, event->u.newData.dataSize , refCon);
76  }
77 }
78 #endif
79 
80 
81 
82 static void *thread_main(void *pArg)
83 {
84  threadContext* pContext = (threadContext *)pArg;
85  IOBluetoothDeviceRef device = IOBluetoothDeviceCreateWithAddress(&(pContext->deviceAddress));
86  IOBluetoothRFCOMMChannelRef rfcommChannel;
87 
88 #ifdef OSX_BLUE_2_0
89  if (IOBluetoothDeviceOpenRFCOMMChannelSync(device, &rfcommChannel, pContext->nChannel,
90  thread_rfcommEventListener, pArg) != kIOReturnSuccess) {
91  rfcommChannel = 0;
92  }
93 #else
94  if (IOBluetoothDeviceOpenRFCOMMChannel(device, pContext->nChannel,
95  &rfcommChannel) != kIOReturnSuccess) {
96  rfcommChannel = 0;
97  } else {
98  /* register an incoming data listener */
99  if (IOBluetoothRFCOMMChannelRegisterIncomingDataListener(rfcommChannel,
100  thread_rfcommDataListener, pArg) != kIOReturnSuccess) {
101  rfcommChannel = 0;
102  }
103  }
104 #endif
105 
106  pContext->rfcommChannel = rfcommChannel;
107 
108  pthread_mutex_unlock(&(pContext->mutexWait));
109 
110  /* start the runloop */
111  CFRunLoopRun();
112 
113  return NULL;
114 }
115 
116 /* ---- bluetooth io thread ---- */
117 
118 GSM_Error bluetooth_connect(GSM_StateMachine *s, int port, char *device)
119 {
120  GSM_Device_BlueToothData *d = &s->Device.Data.BlueTooth;
121  /* create the thread context and start the thread */
122  CFStringRef strDevice;
123  threadContext *pContext = (threadContext *)malloc(sizeof(threadContext));
124  if (pContext == NULL) return ERR_MOREMEMORY;
125 
126  strDevice = CFStringCreateWithCString(kCFAllocatorDefault, device, kCFStringEncodingMacRomanLatin1);
127  IOBluetoothCFStringToDeviceAddress(strDevice, &pContext->deviceAddress);
128  CFRelease(strDevice);
129 
130  pContext->arrDataReceived = CFArrayCreateMutable(kCFAllocatorDefault, 0, NULL);
131  pContext->rfcommChannel = 0;
132  pContext->nChannel = port;
133 
134  pthread_mutex_init(&(pContext->mutexWait), NULL);
135  pthread_mutex_lock(&(pContext->mutexWait)); /* lock */
136 
137  pthread_create(&(pContext->threadID), NULL, thread_main, pContext);
138 
139  /* wait until main finishes its initialization */
140  pthread_mutex_lock(&(pContext->mutexWait));
141  /* unblock the mutex */
142  pthread_mutex_unlock(&(pContext->mutexWait));
143 
144  if (pContext->rfcommChannel == 0) {
145  return ERR_DEVICEOPENERROR;
146  } else {
147  /* return the thread context as the file descriptor */
148  d->Data = pContext;
149  return ERR_NONE;
150  }
151 }
152 
154 {
155  GSM_Device_BlueToothData *d = &s->Device.Data.BlueTooth;
156  threadContext *pContext = (threadContext *)d->Data;
157  IOBluetoothDeviceRef device;
158 
159  sleep(2);
160 
161  if (pContext != NULL && pContext->rfcommChannel > 0) {
162 #ifndef OSX_BLUE_2_0
163  /* de-register the callback */
164  IOBluetoothRFCOMMChannelRegisterIncomingDataListener(pContext->rfcommChannel, NULL, NULL);
165 #endif
166 
167  /* close channel and device connection */
168  IOBluetoothRFCOMMChannelCloseChannel(pContext->rfcommChannel);
169  device = IOBluetoothRFCOMMChannelGetDevice(pContext->rfcommChannel);
170  IOBluetoothDeviceCloseConnection(device);
171  IOBluetoothObjectRelease(pContext->rfcommChannel);
172  IOBluetoothObjectRelease(device);
173  }
174 
175  return ERR_NONE;
176 }
177 
178 int bluetooth_write(GSM_StateMachine *s, const void *buf, size_t nbytes)
179 {
180  GSM_Device_BlueToothData *d = &s->Device.Data.BlueTooth;
181  threadContext *pContext = (threadContext *)d->Data;
182 
183 #ifdef OSX_BLUE_2_0
184  if (IOBluetoothRFCOMMChannelWriteSync(pContext->rfcommChannel, (void *)buf, nbytes) != kIOReturnSuccess)
185  return -1;
186 #else
187  if (IOBluetoothRFCOMMChannelWrite(pContext->rfcommChannel, (void *)buf, nbytes, TRUE) != kIOReturnSuccess)
188  return -1;
189 #endif
190 
191  return nbytes;
192 }
193 
194 int bluetooth_read(GSM_StateMachine *s, void *buffer, size_t size)
195 {
196  GSM_Device_BlueToothData *d = &s->Device.Data.BlueTooth;
197  threadContext *pContext = (threadContext *)d->Data;
198  int nOffset = 0;
199  int nBytes = 0;
200  dataBlock* pDataBlock;
201 
202  /* no data received so far */
203  if (CFArrayGetCount(pContext->arrDataReceived) == 0)
204  return 0;
205 
206  while (CFArrayGetCount(pContext->arrDataReceived) != 0) {
207  pthread_mutex_lock(&(pContext->mutexWait));
208  pDataBlock = (dataBlock*)CFArrayGetValueAtIndex(pContext->arrDataReceived, 0);
209  pthread_mutex_unlock(&(pContext->mutexWait));
210 
211  if (pDataBlock->nSize == size) {
212  /* copy data and remove block */
213  memcpy(((char *)buffer) + nOffset, pDataBlock->pData, size);
214 
215  pthread_mutex_lock(&(pContext->mutexWait));
216  CFArrayRemoveValueAtIndex(pContext->arrDataReceived, 0);
217  pthread_mutex_unlock(&(pContext->mutexWait));
218 
219  free(pDataBlock->pData);
220  pDataBlock->pData=NULL;
221  free(pDataBlock);
222  pDataBlock=NULL;
223 
224  return nBytes + size;
225  } else if (pDataBlock->nSize > size) {
226  /* copy data and update block contents */
227  memcpy(((char *)buffer) + nOffset, pDataBlock->pData, size);
228  memmove(pDataBlock->pData, ((char *)pDataBlock->pData) + size, pDataBlock->nSize - size);
229  pDataBlock->nSize -= size;
230  return nBytes + size;
231  } else { /* pDataBlock->nSize < size */
232  /* copy data and remove block */
233  memcpy(((char *)buffer) + nOffset, pDataBlock->pData, pDataBlock->nSize);
234 
235  size -= pDataBlock->nSize;
236  nOffset += pDataBlock->nSize;
237  nBytes += pDataBlock->nSize;
238 
239  pthread_mutex_lock(&(pContext->mutexWait));
240  CFArrayRemoveValueAtIndex(pContext->arrDataReceived, 0);
241  pthread_mutex_unlock(&(pContext->mutexWait));
242 
243  free(pDataBlock->pData);
244  pDataBlock->pData=NULL;
245  free(pDataBlock);
246  pDataBlock=NULL;
247  }
248  }
249 
250  return nBytes;
251 }
252 
253 
254 #endif
255 #endif
256 
257 /* How should editor hadle tabs in this file? Add editor commands here.
258  * vim: noexpandtab sw=8 ts=8 sts=8:
259  */
union GSM_Device::@0 Data
int bluetooth_write(GSM_StateMachine *s, const void *buf, size_t nbytes)
GSM_Error
Definition: gammu-error.h:23
GSM_Error bluetooth_connect(GSM_StateMachine *s, int port, char *device)
GSM_Error bluetooth_close(GSM_StateMachine *s)
#define TRUE
Definition: gammu-types.h:28
GSM_Device Device
Definition: gsmstate.h:1429
int bluetooth_read(GSM_StateMachine *s, void *buf, size_t nbytes)