/***** GAPScanResponse検知メソッド(bgLibイベント呼び出し) *****/ private void bgLib_BLEEventGAPScanResponse(object sender, Bluegiga.BLE.Events.GAP.ScanResponseEventArgs e) { // データパケットの長さが25以上であれば、UUIDが乗っていないかチェックする if (e.data.Length > 25) { byte[] data_buf = new byte[16]; for (int i = 0; i < data_buf.Length; i++) data_buf[i] = e.data[i + 9]; // データパケットにUUIDが乗っていた場合 if (Object.ReferenceEquals(data_buf, PLEN2_TX_CHARACTERISTIC_UUID) && bleConnectState == BLEState.NotConnected) { bleConnectState = BLEState.Connecting; // PLEN2からのアドバタイズなので、接続を試みる bgLib.SendCommand(serialPort, bgLib.BLECommandGAPConnectDirect(e.sender, 0, 60, 76, 100, 0)); } } else { // 本来の接続手順を実装する。(具体的には以下の通りです。) // 1. ble_cmd_gap_connect_direct() // 2. ble_cmd_attclient_find_information() // 3. ble_evt_attclient_find_information_found()を処理し、UUIDを比較 // a. UUIDが一致する場合は、そのキャラクタリスティックハンドルを取得 → 接続完了 // b. 全てのキャラクタリスティックについてUUIDが一致しない場合は、4.以降の処理へ // 4. MACアドレスを除外リストに追加した後、ble_cmd_connection_disconnect() // 5. 再度ble_cmd_gap_discove() // 6. 1.へ戻る。ただし、除外リストとMACアドレスを比較し、該当するものには接続をしない。 // CAUTION!: 以下は横着した実装。本来は上記の手順を踏むべき。 // PLEN2からのアドバタイズなので、接続を試みる Int64 key = 0; // キー作成 for (int index = 0; index < 6; index++) key += (Int64)e.sender[index] << (index * 8); // 取得したキーに対してまだ接続していない場合,接続を試みる // ※connectedDictは他スレッドからの参照もありうるので排他制御 if (bleConnectState == BLEState.NotConnected) { lock(connectedDict) { // 取得したキーに対して,すでに接続を試みたならばスルー if (connectedDict.ContainsKey(key) == true && connectedDict[key] != BLEState.NotConnected) { return; } // 取得したキーをリストに追加,状態を接続要求中へ if (connectedDict.ContainsKey(key) == true) connectedDict.Add(key, BLEState.Connecting); else connectedDict[key] = BLEState.Connecting; // 自分の接続状態を更新 bleConnectState = BLEState.Connecting; // 取得したキーに対して接続を試みる(接続完了後イベント発生) bgLib.SendCommand(serialPort, bgLib.BLECommandGAPConnectDirect(e.sender, 0, 60, 76, 100, 0)); } } } }
public void ATTClientAttributeValueEvent(object sender, Bluegiga.BLE.Events.ATTClient.AttributeValueEventArgs e) { String log = String.Format("ble_evt_attclient_attribute_value: connection={0}, atthandle={1}, type={2}, value=[ {3}]" + Environment.NewLine, e.connection, e.atthandle, e.type, ByteArrayToHexString(e.value) ); Console.Write(log); ThreadSafeDelegate(delegate { txtLog.AppendText(log); }); // check for a new value from the connected peripheral's temperature measurement attribute if (e.connection == connection_handle && e.atthandle == att_handle_measurement) { Byte htm_flags = e.value[0]; int htm_exponent = e.value[4]; int htm_mantissa = (e.value[3] << 16) | (e.value[2] << 8) | e.value[1]; if (htm_exponent > 127) { // # convert to signed 8-bit int htm_exponent = htm_exponent - 256; } float htm_measurement = htm_mantissa * (float)Math.Pow(10, htm_exponent); char temp_type = 'C'; if ((htm_flags & 0x01) == 0x01) { // value sent is Fahrenheit, not Celsius temp_type = 'F'; } // display actual measurement ThreadSafeDelegate(delegate { txtLog.AppendText(String.Format("Temperature: {0}\u00B0 {1}", htm_measurement, temp_type) + Environment.NewLine); }); } }
public void ATTClientAttributeValueEvent(object sender, Bluegiga.BLE.Events.ATTClient.AttributeValueEventArgs e) { String log = String.Format("ble_evt_attclient_attribute_value: connection={0}, atthandle={1}, type={2}, value=[ {3}]" + Environment.NewLine, e.connection, e.atthandle, e.type, ByteArrayToHexString(e.value) ); Console.Write(log); ThreadSafeDelegate(delegate { txtLog.AppendText(log); }); // check for a new value from the connected peripheral's if (e.connection == adrTIUser) { switch ((TI_Sensor_Data)e.atthandle) { case TI_Sensor_Data.Temperature: double tempA = st.getTempAmbient(e.value); double tempIR = st.extractTargetTemperature(e.value, tempA); ThreadSafeDelegate(delegate { labTempAmbient.Text = tempA.ToString("f2") + " °C"; }); ThreadSafeDelegate(delegate { labTempIR.Text = tempIR.ToString("f2") + " °C"; }); break; case TI_Sensor_Data.Humidity: ThreadSafeDelegate(delegate { labHumidity.Text = st.convertHumidity(e.value).ToString("f2") + " rel. %"; }); break; case TI_Sensor_Data.Barometer: ThreadSafeDelegate(delegate { labBarometer.Text = st.convertBarometer(e.value).ToString("f2") + " mbar"; }); break; case TI_Sensor_Data.Movement: p3d_a = st.convertAccelerometer(e.value); p3d_g = st.convertGyroscope(e.value); p3d_m = st.convertMagnetometer(e.value); ThreadSafeDelegate(delegate { dataGridView1.Rows[0].Cells[1].Value = p3d_a.x.ToString("f3"); dataGridView1.Rows[0].Cells[2].Value = p3d_a.y.ToString("f3"); dataGridView1.Rows[0].Cells[3].Value = p3d_a.z.ToString("f3"); dataGridView1.Rows[1].Cells[1].Value = p3d_g.x.ToString("f3"); dataGridView1.Rows[1].Cells[2].Value = p3d_g.y.ToString("f3"); dataGridView1.Rows[1].Cells[3].Value = p3d_g.z.ToString("f3"); dataGridView1.Rows[2].Cells[1].Value = p3d_m.x.ToString("f3"); dataGridView1.Rows[2].Cells[2].Value = p3d_m.y.ToString("f3"); dataGridView1.Rows[2].Cells[3].Value = p3d_m.z.ToString("f3"); }); break; case TI_Sensor_Data.Luxometer: ThreadSafeDelegate(delegate { labLuxometer.Text = st.convertLuxometer(e.value).ToString("f2") + " lux"; }); break; default: break; } } }
public void GAPScanResponseEvent(object sender, Bluegiga.BLE.Events.GAP.ScanResponseEventArgs e) { String log = String.Format("ble_evt_gap_scan_response:" + Environment.NewLine + "\trssi={0}, packet_type={1}, bd_addr=[ {2}], address_type={3}, bond={4}, data=[ {5}]" + Environment.NewLine, (SByte)e.rssi, (SByte)e.packet_type, ByteArrayToHexString(e.sender), (SByte)e.address_type, (SByte)e.bond, ByteArrayToHexString(e.data) ); Console.Write(log); ThreadSafeDelegate(delegate { txtLog.AppendText(log); }); }
public void SystemBootEvent(object sender, Bluegiga.BLE.Events.System.BootEventArgs e) { String log = String.Format("ble_evt_system_boot:" + Environment.NewLine + "\tmajor={0}, minor={1}, patch={2}, build={3}, ll_version={4}, protocol_version={5}, hw={6}" + Environment.NewLine, e.major, e.minor, e.patch, e.build, e.ll_version, e.protocol_version, e.hw ); Console.Write(log); ThreadSafeDelegate(delegate { txtLog.AppendText(log); }); }
public void ATTClientAttributeValueEvent(object sender, Bluegiga.BLE.Events.ATTClient.AttributeValueEventArgs e) { String log = String.Format("ble_evt_attclient_attribute_value: connection={0}, atthandle={1}, type={2}, value=[ {3}]" + Environment.NewLine, e.connection, e.atthandle, e.type, ByteArrayToHexString(e.value) ); Console.Write(log); ThreadSafeDelegate(delegate { txtLog.AppendText(log); }); // check for a new value from the connected peripheral's heart rate measurement attribute if (e.connection == connection_handle && e.atthandle == att_handle_measurement) { Byte hr_flags = e.value[0]; int hr_measurement = e.value[1]; // display actual measurement ThreadSafeDelegate(delegate { txtLog.AppendText(String.Format("Heart rate: {0} bpm", hr_measurement) + Environment.NewLine); }); } }
public void ATTClientFindInformationFoundEvent(object sender, Bluegiga.BLE.Events.ATTClient.FindInformationFoundEventArgs e) { String log = String.Format("ble_evt_attclient_find_information_found: connection={0}, chrhandle={1}, uuid=[ {2}]" + Environment.NewLine, e.connection, e.chrhandle, ByteArrayToHexString(e.uuid) ); Console.Write(log); ThreadSafeDelegate(delegate { txtLog.AppendText(log); }); // check for thermometer measurement characteristic if (e.uuid.SequenceEqual(new Byte[] { 0x1C, 0x2A })) { ThreadSafeDelegate(delegate { txtLog.AppendText(String.Format("Found attribute w/UUID=0x2A1C: handle={0}", e.chrhandle) + Environment.NewLine); }); att_handle_measurement = e.chrhandle; } // check for subsequent client characteristic configuration else if (e.uuid.SequenceEqual(new Byte[] { 0x02, 0x29 }) && att_handle_measurement > 0) { ThreadSafeDelegate(delegate { txtLog.AppendText(String.Format("Found attribute w/UUID=0x2902: handle={0}", e.chrhandle) + Environment.NewLine); }); att_handle_measurement_ccc = e.chrhandle; } }
/// <summary> /// BLEクライアント接続完了メソッド(イベント呼び出し) /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void bgLib_BLEEventConnectionStatus(object sender, Bluegiga.BLE.Events.Connection.StatusEventArgs e) { // PLENと接続完了 if ((e.flags & 0x01) != 0) { // アドレスリストを更新(接続中→接続完了へ) // ※connectedDictは他スレッドからも操作されるので排他制御 lock (connectedDict) { // アドレス作成 Int64 key = 0; for (int index = 0; index < 6; index++) key += (Int64)e.address[index] << (index * 8); // 状態更新(接続完了) connectedDict[key] = BLEState.Connected; connectedBLEKey = key; } serialCommProcessMessage(this, "Connected"); bleConnectState = BLEState.Connected; } // 再度接続を試みる else bgLib.SendCommand(serialPort, bgLib.BLECommandGAPDiscover(1)); }
/// <summary> /// AtrributeWrite-データ送信完了メソッド(イベント呼び出し) /// </summary> /// <param name="sender">sender</param> /// <param name="e">Args</param> void bgLib_BLEEventATTClientProcedureCompleted(object sender, Bluegiga.BLE.Events.ATTClient.ProcedureCompletedEventArgs e) { //serialCommProcessMessage(this, "ProcedureCompleted Result : " + e.result); // e.result == 0 ⇒データ送信正常完了 if (e.result == 0) isAttributeWrited = true; }
// for master/scanner devices, the "gap_scan_response" event is a common entry-like point // this filters ad packets to find devices which advertise the Health Thermometer service public void GAPScanResponseEvent(object sender, Bluegiga.BLE.Events.GAP.ScanResponseEventArgs e) { String log = String.Format("ble_evt_gap_scan_response: rssi={0}, packet_type={1}, sender=[ {2}], address_type={3}, bond={4}, data=[ {5}]" + Environment.NewLine, (SByte)e.rssi, e.packet_type, ByteArrayToHexString(e.sender), e.address_type, e.bond, ByteArrayToHexString(e.data) ); Console.Write(log); ThreadSafeDelegate(delegate { txtLog.AppendText(log); }); // pull all advertised service info from ad packet List<Byte[]> ad_services = new List<Byte[]>(); Byte[] this_field = {}; int bytes_left = 0; int field_offset = 0; for (int i = 0; i < e.data.Length; i++) { if (bytes_left == 0) { bytes_left = e.data[i]; this_field = new Byte[e.data[i]]; field_offset = i + 1; } else { this_field[i - field_offset] = e.data[i]; bytes_left--; if (bytes_left == 0) { if (this_field[0] == 0x02 || this_field[0] == 0x03) { // partial or complete list of 16-bit UUIDs ad_services.Add(this_field.Skip(1).Take(2).Reverse().ToArray()); } else if (this_field[0] == 0x04 || this_field[0] == 0x05) { // partial or complete list of 32-bit UUIDs ad_services.Add(this_field.Skip(1).Take(4).Reverse().ToArray()); } else if (this_field[0] == 0x06 || this_field[0] == 0x07) { // partial or complete list of 128-bit UUIDs ad_services.Add(this_field.Skip(1).Take(16).Reverse().ToArray()); } } } } // check for 0x1809 (official health thermometer service UUID) if (ad_services.Any(a => a.SequenceEqual(new Byte[] { 0x18, 0x09 }))) { // connect to this device Byte[] cmd = bglib.BLECommandGAPConnectDirect(e.sender, e.address_type, 0x20, 0x30, 0x100, 0); // 125ms interval, 125ms window, active scanning // DEBUG: display bytes written ThreadSafeDelegate(delegate { txtLog.AppendText(String.Format("=> TX ({0}) [ {1}]", cmd.Length, ByteArrayToHexString(cmd)) + Environment.NewLine); }); bglib.SendCommand(serialAPI, cmd); //while (bglib.IsBusy()) ; // update state app_state = STATE_CONNECTING; } }
// the "connection_status" event occurs when a new connection is established public void ConnectionStatusEvent(object sender, Bluegiga.BLE.Events.Connection.StatusEventArgs e) { String log = String.Format("ble_evt_connection_status: connection={0}, flags={1}, address=[ {2}], address_type={3}, conn_interval={4}, timeout={5}, latency={6}, bonding={7}" + Environment.NewLine, e.connection, e.flags, ByteArrayToHexString(e.address), e.address_type, e.conn_interval, e.timeout, e.latency, e.bonding ); Console.Write(log); ThreadSafeDelegate(delegate { txtLog.AppendText(log); }); if ((e.flags & 0x05) == 0x05) { // connected, now perform service discovery connection_handle = e.connection; ThreadSafeDelegate(delegate { txtLog.AppendText(String.Format("Connected to {0}", ByteArrayToHexString(e.address)) + Environment.NewLine); }); Byte[] cmd = bglib.BLECommandATTClientReadByGroupType(e.connection, 0x0001, 0xFFFF, new Byte[] { 0x00, 0x28 }); // "service" UUID is 0x2800 (little-endian for UUID uint8array) // DEBUG: display bytes written ThreadSafeDelegate(delegate { txtLog.AppendText(String.Format("=> TX ({0}) [ {1}]", cmd.Length, ByteArrayToHexString(cmd)) + Environment.NewLine); }); bglib.SendCommand(serialAPI, cmd); //while (bglib.IsBusy()) ; // update state app_state = STATE_FINDING_SERVICES; } }
public void ATTClientProcedureCompletedEvent(object sender, Bluegiga.BLE.Events.ATTClient.ProcedureCompletedEventArgs e) { String log = String.Format("ble_evt_attclient_procedure_completed: connection={0}, result={1}, chrhandle={2}" + Environment.NewLine, e.connection, e.result, e.chrhandle ); Console.Write(log); ThreadSafeDelegate(delegate { txtLog.AppendText(log); }); // check if we just finished searching for services if (app_state == STATE_FINDING_SERVICES) { if (att_handlesearch_end > 0) { //print "Found 'Health Thermometer' service with UUID 0x1809" // found the Health Thermometer service, so now search for the attributes inside Byte[] cmd = bglib.BLECommandATTClientFindInformation(e.connection, att_handlesearch_start, att_handlesearch_end); // DEBUG: display bytes written ThreadSafeDelegate(delegate { txtLog.AppendText(String.Format("=> TX ({0}) [ {1}]", cmd.Length, ByteArrayToHexString(cmd)) + Environment.NewLine); }); bglib.SendCommand(serialAPI, cmd); //while (bglib.IsBusy()) ; // update state app_state = STATE_FINDING_ATTRIBUTES; } else { ThreadSafeDelegate(delegate { txtLog.AppendText("Could not find 'Health Thermometer' service with UUID 0x1809" + Environment.NewLine); }); } } // check if we just finished searching for attributes within the thermometer service else if (app_state == STATE_FINDING_ATTRIBUTES) { if (att_handle_measurement_ccc > 0) { //print "Found 'Health Thermometer' measurement attribute with UUID 0x2A1C" // found the measurement + client characteristic configuration, so enable indications // (this is done by writing 0x02 to the client characteristic configuration attribute) Byte[] cmd = bglib.BLECommandATTClientAttributeWrite(e.connection, att_handle_measurement_ccc, new Byte[] { 0x02 }); // DEBUG: display bytes written ThreadSafeDelegate(delegate { txtLog.AppendText(String.Format("=> TX ({0}) [ {1}]", cmd.Length, ByteArrayToHexString(cmd)) + Environment.NewLine); }); bglib.SendCommand(serialAPI, cmd); //while (bglib.IsBusy()) ; // update state app_state = STATE_LISTENING_MEASUREMENTS; } else { ThreadSafeDelegate(delegate { txtLog.AppendText("Could not find 'Health Thermometer' measurement attribute with UUID 0x2A1C" + Environment.NewLine); }); } } }
public void ATTClientGroupFoundEvent(object sender, Bluegiga.BLE.Events.ATTClient.GroupFoundEventArgs e) { String log = String.Format("ble_evt_attclient_group_found: connection={0}, start={1}, end={2}, uuid=[ {3}]" + Environment.NewLine, e.connection, e.start, e.end, ByteArrayToHexString(e.uuid) ); Console.Write(log); ThreadSafeDelegate(delegate { txtLog.AppendText(log); }); // found "service" attribute groups (UUID=0x2800), check for thermometer service if (e.uuid.SequenceEqual(new Byte[] { 0x09, 0x18 })) { ThreadSafeDelegate(delegate { txtLog.AppendText(String.Format("Found attribute group for service w/UUID=0x1809: start={0}, end=%d", e.start, e.end) + Environment.NewLine); }); att_handlesearch_start = e.start; att_handlesearch_end = e.end; } }
/// <summary> /// Event handler for when the connection status changes. /// </summary> private void BGLib_BLEEventConnectionStatus(object sender, Bluegiga.BLE.Events.Connection.StatusEventArgs e) { ConnectionStatusFlags flags = (ConnectionStatusFlags)e.flags; // Run in Dispatcher.Invoke Lambda as the event is in a different thread to the UI... this.Dispatcher.Invoke(() => { if (flags.HasFlag(ConnectionStatusFlags.Connected)) { //SendOutput("Device connected!"); connection = e.connection; IsConnected = true; IsAdvertising = false; } else if (flags.HasFlag(ConnectionStatusFlags.Encrypted)) { //SendOutput("Connection encrypted!"); IsEncrypted = true; } }); }
/// <summary> /// Called when the remote device disconnects. /// </summary> private void BGLib_BLEEventConnectionDisconnected(object sender, Bluegiga.BLE.Events.Connection.DisconnectedEventArgs e) { // Run in Dispatcher.Invoke Lambda as the event is in a different thread to the UI... this.Dispatcher.Invoke(() => { DisconnectedReason reason = (DisconnectedReason)e.reason; SendOutput("Device disconnected. Reason: " + reason.ToString()); StopTimer(); IsEncrypted = false; IsConnected = false; StartAdvertisingMode(); }); }