Diffstat (limited to 'noncore/settings/networksettings2/opietooth2/OTHCISocket.cpp') (more/less context) (show whitespace changes)
-rw-r--r-- | noncore/settings/networksettings2/opietooth2/OTHCISocket.cpp | 274 |
1 files changed, 274 insertions, 0 deletions
diff --git a/noncore/settings/networksettings2/opietooth2/OTHCISocket.cpp b/noncore/settings/networksettings2/opietooth2/OTHCISocket.cpp new file mode 100644 index 0000000..471c3bf --- a/dev/null +++ b/noncore/settings/networksettings2/opietooth2/OTHCISocket.cpp | |||
@@ -0,0 +1,274 @@ | |||
1 | //-*-c++-*- | ||
2 | /*************************************************************************** | ||
3 | * Copyright (C) 2003 by Fred Schaettgen * | ||
4 | * kdebluetooth@schaettgen.de * | ||
5 | * * | ||
6 | * This program is free software; you can redistribute it and/or modify * | ||
7 | * it under the terms of the GNU General Public License as published by * | ||
8 | * the Free Software Foundation; either version 2 of the License, or * | ||
9 | * (at your option) any later version. * | ||
10 | ***************************************************************************/ | ||
11 | |||
12 | #include <qbuffer.h> | ||
13 | #include <qtimer.h> | ||
14 | #include <qdatastream.h> | ||
15 | #include <opie2/odebug.h> | ||
16 | |||
17 | #include <bluezlib.h> | ||
18 | |||
19 | // #include "deviceaddress.h" | ||
20 | #include <OTHCISocket.h> | ||
21 | #include <OTDriver.h> | ||
22 | |||
23 | using namespace Opietooth2; | ||
24 | |||
25 | OTHCISocket::OTHCISocket( OTDriver * D ) : | ||
26 | QObject( D, D->devname() ) { | ||
27 | BStatusSet = false; | ||
28 | Driver = D; | ||
29 | HCIReadNotifier = 0; | ||
30 | } | ||
31 | |||
32 | OTHCISocket::~OTHCISocket() { | ||
33 | close(); | ||
34 | } | ||
35 | |||
36 | void OTHCISocket::close() { | ||
37 | owarn << "OTHCISocket::close()" << oendl; | ||
38 | if( HCIReadNotifier ) { | ||
39 | delete HCIReadNotifier; | ||
40 | } | ||
41 | |||
42 | if( HCISocket.isValid() ) { | ||
43 | HCISocket.close(); | ||
44 | } | ||
45 | } | ||
46 | |||
47 | bool OTHCISocket::open() { | ||
48 | |||
49 | owarn << "OTHCISocket::open()" << oendl; | ||
50 | int s; | ||
51 | |||
52 | s = ::socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI); | ||
53 | |||
54 | if (s < 0) { | ||
55 | emit error( tr( "Error creating socket on %1 : %2 %3"). | ||
56 | arg( Driver->devname() ). | ||
57 | arg( errno ). | ||
58 | arg( strerror(errno) ) | ||
59 | ); | ||
60 | return false; | ||
61 | } | ||
62 | |||
63 | /* Bind socket to the HCI device */ | ||
64 | struct sockaddr_hci sa; | ||
65 | sa.hci_family = AF_BLUETOOTH; | ||
66 | sa.hci_dev = Driver->devId(); | ||
67 | if (bind(s, (struct sockaddr *)&sa, sizeof(sa)) < 0) { | ||
68 | ::close(s); | ||
69 | emit error( tr( "Error binding to socket to %1 : %2 %3"). | ||
70 | arg( Driver->devname() ). | ||
71 | arg( errno ). | ||
72 | arg( strerror(errno) ) | ||
73 | ); | ||
74 | return false; | ||
75 | } | ||
76 | |||
77 | struct hci_filter flt; | ||
78 | hci_filter_clear(&flt); | ||
79 | hci_filter_set_ptype(HCI_EVENT_PKT, &flt); | ||
80 | hci_filter_all_events(&flt); | ||
81 | if( setsockopt(s, SOL_HCI, HCI_FILTER, &flt, sizeof(flt)) < 0 ) { | ||
82 | ::close(s); | ||
83 | emit error( tr( "HCI filter setup failed on %1 : %2 %3"). | ||
84 | arg( Driver->devname() ). | ||
85 | arg( errno ). | ||
86 | arg( strerror(errno) ) | ||
87 | ); | ||
88 | return false; | ||
89 | } | ||
90 | |||
91 | if( HCIReadNotifier ) { | ||
92 | delete HCIReadNotifier; | ||
93 | } | ||
94 | |||
95 | HCISocket.setSocket(s, QSocketDevice::Datagram); | ||
96 | HCIReadNotifier = new QSocketNotifier( | ||
97 | s, QSocketNotifier::Read, this); | ||
98 | |||
99 | connect( HCIReadNotifier, | ||
100 | SIGNAL(activated(int)), | ||
101 | this, | ||
102 | SLOT(slotSocketActivated()) | ||
103 | ); | ||
104 | |||
105 | //connect(hciSocket, SIGNAL(error(int)), | ||
106 | // this, SLOT(slotSocketError(int))); | ||
107 | //connect(hciSocket, SIGNAL(connectionClosed()), | ||
108 | // this, SLOT(slotConnectionClosed())); | ||
109 | //hciSocket->setSocket(s); | ||
110 | |||
111 | return true; | ||
112 | } | ||
113 | |||
114 | void OTHCISocket::slotSocketError(int e) { | ||
115 | close(); | ||
116 | emit error( tr( "HCI socket error 0x%1 on %1 : %2 %3"). | ||
117 | arg(e,2,16). | ||
118 | arg( Driver->devname() ). | ||
119 | arg( errno ). | ||
120 | arg( strerror(errno) ) | ||
121 | ); | ||
122 | } | ||
123 | |||
124 | void OTHCISocket::slotSocketActivated() { | ||
125 | |||
126 | QSocketDevice::Error err = HCISocket.error(); | ||
127 | |||
128 | if( (err == QSocketDevice::NoError ) && | ||
129 | ( HCISocket.isValid() ) ) { | ||
130 | //kdDebug() << "HCI socket ready read." << endl; | ||
131 | |||
132 | unsigned char buf[512]; | ||
133 | int psize = HCISocket.readBlock((char*)buf, 512); | ||
134 | |||
135 | if (psize <= 0) { | ||
136 | slotSocketError(HCISocket.error()); | ||
137 | HCISocket.close(); | ||
138 | return; | ||
139 | } | ||
140 | |||
141 | //unsigned char packetType = buf[0]; | ||
142 | unsigned char eventCode = buf[1]; | ||
143 | unsigned char len = buf[2]; | ||
144 | |||
145 | if (psize-3 == len) { | ||
146 | |||
147 | QByteArray databuf; | ||
148 | databuf.duplicate((char*)(buf+3), len); | ||
149 | emit event(eventCode, databuf); | ||
150 | if (eventCode == EVT_CMD_STATUS) { | ||
151 | updateStatus( databuf ); | ||
152 | } | ||
153 | } else { | ||
154 | owarn << "Error reading hci packet: packetSize(" | ||
155 | << psize | ||
156 | << ")-3 != dataSize(" | ||
157 | << len | ||
158 | << ")" | ||
159 | << oendl; | ||
160 | } | ||
161 | } else if (err == QSocketDevice::NoError) { | ||
162 | slotConnectionClosed(); | ||
163 | } else { | ||
164 | HCISocket.close(); | ||
165 | slotSocketError(err); | ||
166 | } | ||
167 | } | ||
168 | |||
169 | void OTHCISocket::updateStatus(const QByteArray& data) { | ||
170 | |||
171 | QDataStream stream(data, IO_ReadOnly); | ||
172 | stream.setByteOrder(QDataStream::LittleEndian); | ||
173 | Q_UINT8 status, dummy; | ||
174 | Q_UINT16 opcode; | ||
175 | |||
176 | BStatusSet = true; | ||
177 | |||
178 | stream >> status >> dummy >> opcode; | ||
179 | //kdDebug() << "updatestatus opcode=" << uint32_t(opcode) << endl; | ||
180 | LastStatus = status; | ||
181 | LastStatusOgf = cmd_opcode_ogf(opcode); | ||
182 | LastStatusOcf = cmd_opcode_ocf(opcode); | ||
183 | } | ||
184 | |||
185 | void OTHCISocket::slotConnectionClosed() { | ||
186 | owarn << "HCI connection closed." << oendl; | ||
187 | emit connectionClosed(); | ||
188 | } | ||
189 | |||
190 | void OTHCISocket::readEvent() { | ||
191 | |||
192 | if (HCIReadNotifier) { | ||
193 | slotSocketActivated(); | ||
194 | } | ||
195 | } | ||
196 | |||
197 | bool OTHCISocket::sendCommand( unsigned char ogf, | ||
198 | unsigned short ocf, | ||
199 | QByteArray buf | ||
200 | ) { | ||
201 | QBuffer packet; | ||
202 | QDataStream stream(&packet); | ||
203 | |||
204 | stream.setByteOrder(QDataStream::LittleEndian); | ||
205 | packet.open(IO_WriteOnly); | ||
206 | |||
207 | if (buf.size() > 255) return false; | ||
208 | |||
209 | //kdDebug() << "sendCommand. ogf=" << ogf << " ocf=" << ocf << endl; | ||
210 | Q_UINT16 opcode = cmd_opcode_pack(ogf, ocf); | ||
211 | Q_UINT8 pType = HCI_COMMAND_PKT; | ||
212 | Q_UINT8 buflen = buf.size(); | ||
213 | |||
214 | stream << pType << opcode << buflen; | ||
215 | stream.writeRawBytes(buf.data(), buflen); | ||
216 | packet.close(); | ||
217 | HCISocket.writeBlock((const char*)packet.buffer(), | ||
218 | packet.buffer().size()); | ||
219 | return true; | ||
220 | } | ||
221 | |||
222 | bool OTHCISocket::readStatus( unsigned char ogf, | ||
223 | unsigned short ocf, | ||
224 | int *status, | ||
225 | int timeout_ms) { | ||
226 | QTimer timer; | ||
227 | |||
228 | timer.start(timeout_ms, true); | ||
229 | BStatusSet = false; | ||
230 | |||
231 | while (timer.isActive() && HCISocket.isValid()) { | ||
232 | |||
233 | owarn << "OTHCISocket::readStatus()" << oendl; | ||
234 | bool timeout = false; | ||
235 | |||
236 | if( HCISocket.bytesAvailable() == 0) { | ||
237 | int rv = HCISocket.waitForMore(timeout_ms); | ||
238 | timeout = (rv == 0); | ||
239 | } | ||
240 | |||
241 | if (!timeout) { | ||
242 | slotSocketActivated(); | ||
243 | } | ||
244 | |||
245 | if( BStatusSet == true && | ||
246 | ogf == LastStatusOgf && | ||
247 | ocf == LastStatusOcf) { | ||
248 | *status = LastStatus; | ||
249 | owarn << "OTHCISocket::readStatus(ogf=" | ||
250 | << ogf | ||
251 | << ",ocf=" | ||
252 | << ocf | ||
253 | << ",timeout=" | ||
254 | << LastStatus | ||
255 | << ")" | ||
256 | << oendl; | ||
257 | return true; | ||
258 | } | ||
259 | } | ||
260 | |||
261 | owarn << "OTHCISocket::readStatus(ogf=" | ||
262 | << ogf | ||
263 | << ",ocf=" | ||
264 | << ocf | ||
265 | << ",timeout=" | ||
266 | << LastStatus | ||
267 | << ") : timeout " | ||
268 | << oendl; | ||
269 | return false; | ||
270 | } | ||
271 | |||
272 | int OTHCISocket::socket() { | ||
273 | return HCISocket.socket(); | ||
274 | } | ||