Files
2020-01-13 12:56:21 +00:00

5278 lines
213 KiB
C#

//
//-
#define RADIO_MODESSS
//
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using InTheHand.Net.Sockets;
using InTheHand.Net.Bluetooth;
using InTheHand.Net;
using System.Threading;
using System.Diagnostics;
using Console = System.ValueType; // Block the use of Console, must use "console".
using System.Reflection;
using InTheHand.Net.Bluetooth.AttributeIds;
using System.Runtime.InteropServices;
using Microsoft.Win32;
using System.Globalization;
using System.Net;
using System.ComponentModel;
#if !ANDROID
using System.IO.Ports;
#endif
using InTheHand.Net.Bluetooth.Factory;
namespace ConsoleMenuTesting
{
partial class BluetoothTesting
{
public MenuSystem console; //HACK public MenuSystem console;
Stream _peer;
public BluetoothTesting()
{
}
//----
WeakReferenceT<BluetoothClient> _cli;
class WeakReferenceT<T> : WeakReference
{
public WeakReferenceT(T target)
: base(target)
{
}
public new T Target
{
get { return (T)base.Target; }
set { base.Target = value; }
}
}
//--------
#if false && ANDROID
[MenuItem, SubMenu("PLAYING")]
public void CheckAndroidNetworkStream()
{
var tmp = new MemoryStream();
var ns = new InTheHand.Net.Bluetooth.Droid.AndroidBthClient.AndroidNetworkStream(tmp);
console.WriteLine("Done create AndroidNetworkStream.");
ns.WriteByte(11);
console.WriteLine("Done write to AndroidNetworkStream.");
ns.Position = 0;
var bi = ns.ReadByte();
console.WriteLine("Done read from AndroidNetworkStream.");
}
#endif
#if true || DEBUG
[MenuItem, SubMenu("TEST")]
public void TestPause()
{
console.WriteLine("1111");
console.WriteLine("2222");
console.WriteLine("3333");
console.WriteLine("4444");
console.WriteLine("55555");
console.WriteLine("Before Pause");
console.Pause("Message");
console.WriteLine("After Pause");
}
[MenuItem, SubMenu("TEST")]
public void TestReadLine()
{
var i = console.ReadLine("foo\r\nbar");
if (i == null) {
console.WriteLine("you input: <null>");
} else {
console.WriteLine("you input: [[{0}]], len: {1}", i, i.Length);
}
}
[MenuItem, SubMenu("TEST")]
public void TestReadBluetoothAddress()
{
var a = console.ReadBluetoothAddress("foo\r\nbar");
if (a == null) {
console.WriteLine("you input: <null>");
} else {
console.WriteLine("you input: [[{0}]]", a);
}
}
[MenuItem, SubMenu("TEST")]
public void TestReadOptionalBluetoothAddress()
{
var a = console.ReadOptionalBluetoothAddress("foo\r\nbar");
if (a == null) {
console.WriteLine("you input: <null>");
} else {
console.WriteLine("you input: [[{0}]]", a);
}
}
[MenuItem, SubMenu("TEST")]
public void TestReadOptionalInteger()
{
var i = console.ReadOptionalInteger("foobar");
if (i == null) {
console.WriteLine("you input: <null>");
} else {
console.WriteLine("you input: [[{0}]]", i.Value);
}
}
[MenuItem, SubMenu("TEST")]
public void TestReadYesNo()
{
bool i = console.ReadYesNo("foobarYN (default: true)", true);
console.WriteLine("you input: {0}", i);
i = console.ReadYesNo("foobarYN (default: false)", false);
console.WriteLine("you input: {0}", i);
}
[MenuItem, SubMenu("TEST")]
public void TestReadYesNoCancel()
{
bool? i = console.ReadYesNoCancel("foobarYNC (default: true)", true);
console.WriteLine("you input: {0}", i);
i = console.ReadYesNoCancel("foobarYNC (default: false)", false);
console.WriteLine("you input: {0}", i);
i = console.ReadYesNoCancel("foobarYNC (default: cancel)", null);
console.WriteLine("you input: {0}", i);
}
[MenuItem, SubMenu("TEST")]
public void TestGetFilename()
{
var a = console.GetFilename();
if (a == null) {
console.WriteLine("you input: <null>");
} else {
console.WriteLine("you input: [[{0}]]", a);
}
}
#endif
[MenuItem, SubMenu("Playing")]
public void DoBthReadRemoteVersion()
{
var addr = console.ReadBluetoothAddress("remote");
var ba = addr.ToByteArray();
//
byte lmpVersion;
ushort lmpSubVersion, manuf0;
byte[] lmpFeatures = new byte[20];
int ret = BthReadRemoteVersion(ba,
out lmpVersion, out lmpSubVersion, out manuf0, lmpFeatures);
console.WriteLine("ret: {0}=0x{0:X}", ret);
var manuf = (Manufacturer)manuf0;
console.WriteLine("lmpVersion: {0}, lmpSubVersion: {1},"
+ " manuf {2} {3}, lmpFeatures[0]: 0x{4:X}",
lmpVersion, lmpSubVersion, manuf, manuf, lmpFeatures[0]);
}
private const string btdrtDll = "btdrt.dll";
[DllImport(btdrtDll, SetLastError = true)]
public static extern int BthReadRemoteVersion(byte[] pba, out byte plmp_version,
out ushort plmp_subversion, out ushort pmanufacturer, byte[] plmp_features);
[MenuItem, SubMenu("BtLsnr")]
public void SomeCustomUuids()
{
var list = new Guid[] {
new Guid("{7630F141-6361-4e60-A8EE-237180DA9CE8}"),
new Guid("{C7CB927D-8DBE-44f2-B671-3DF8D50C4E2F}"),
new Guid("{59438E67-6094-4bbc-B500-511DE96BB535}"),
new Guid("{C50AFF29-3C38-4fb7-AB32-D541AD835C34}"),
};
foreach (var g in list) {
console.WriteLine(g);
}
}
//[MenuItem, SubMenu("TEST")]
//TODO public void ExceptionNative()
//{
// IntPtr p = new IntPtr(1);
// var o = Marshal.PtrToStructure(p, typeof(Int64));
//}
[MenuItem, SubMenu("TEST")]
public void ExceptionManaged()
{
if (!console.ReadYesNo("Throw exception", false)) return;
throw new RankException("test");
}
[MenuItem, SubMenu("TEST")]
public void ExceptionManagedOnDelegateAsyncInvoke()
{
Action<Version> dlgt = delegate(Version fake)
{
console.WriteLine("(Thread gonna throw...)");
throw new RankException("test");
};
if (!console.ReadYesNo("Throw exception", false)) return;
var ar = DelegateExtension.BeginInvoke(dlgt, null, null, null);
DelegateExtension.EndInvoke(dlgt, ar);
}
//----
[MenuItem, SubMenu("Playing")]
public void Base64Decode()
{
string s = console.ReadLine("Base64 string");
console.WriteLine("Input Base64 string: '{0}'", s);
byte[] arr = Convert.FromBase64String(s);
var asStr = GetEncoding_forHTC().GetString(arr, 0, Math.Min(20, arr.Length));
console.WriteLine("asStr: '{0}'", asStr);
}
private static Encoding GetEncoding_forHTC()
{
var enc = (Encoding)Encoding.ASCII.Clone();
#if !NETCF
enc.DecoderFallback = new System.Text.DecoderReplacementFallback(".");
enc.EncoderFallback = new System.Text.EncoderReplacementFallback(".");
#endif
return enc;
}
[MenuItem, SubMenu("Playing")]
public void Base64Encode()
{
string s = console.ReadLine("Input String");
console.WriteLine("Input string: '{0}'", s);
var arr = GetEncoding_forHTC().GetBytes(s);
var b64str = Convert.ToBase64String(arr);
console.WriteLine("b64str: '{0}'", b64str);
}
//----
[MenuItem, SubMenu("Device Discovery")]
public void Ebap_NotImplHandlers()
{
var bco2 = new BluetoothComponent();
bco2.DiscoverDevicesComplete += new EventHandler<DiscoverDevicesEventArgs>(bco2_DiscoverDevicesComplete);
bco2.DiscoverDevicesProgress += new EventHandler<DiscoverDevicesEventArgs>(bco2_DiscoverDevicesProgress);
bco2.DiscoverDevicesAsync(255, true, true, true, false, null);
}
void bco2_DiscoverDevicesProgress(object sender, DiscoverDevicesEventArgs e)
{
throw new NotImplementedException();
}
void bco2_DiscoverDevicesComplete(object sender, DiscoverDevicesEventArgs e)
{
throw new NotImplementedException();
}
[MenuItem, SubMenu("Device Discovery")]
public void _EbapAsyncDiscoDevices()
{
bool discoOnly, auth, rembd, unk;
GetDiscoveryFlags(console, out discoOnly, out auth, out rembd, out unk);
//
var cli = Create_BluetoothClient();
//cli.InquiryLength = TimeSpan.FromMinutes(1);
BluetoothComponent bco = new BluetoothComponent(cli);
#if NETCF
//bco.SetSynchronizeInvoke((System.Windows.Forms.Control)console.InvokeeControl);
#endif
bco.DiscoverDevicesProgress += _DiscoDevicesAsync_ProgressCallback;
bco.DiscoverDevicesComplete += _DiscoDevicesAsync_CompleteCallback;
EventHandler startAction = delegate
{
bco.DiscoverDevicesAsync(255, auth, rembd, unk, discoOnly, 99);
};
bool startOnUi = console.ReadYesNo("Start from UI thread", true);
if (startOnUi) {
console.UiInvoke(startAction);
} else {
startAction(null, EventArgs.Empty);
}
console.WriteLine("Started at {0} (UTC {1}).", GetTimeWallclockHR(), DateTime.UtcNow.ToLongTimeString());
console.Pause("After completion un-pause to continue");
}
void _DiscoDevicesAsync_CompleteCallback(object sender, DiscoverDevicesEventArgs e)
{
Debug.Assert((int)e.UserState == 99);
CheckSyncCtx();
console.WriteLine("At {0} {1}, ", GetTimeWallclockHR(), "Complete");
if (WriteAsyncCompletedState("DiscoDevicesAsync", e)) {
console.WriteLine("DiscoDevicesAsync found {0} devices.", e.Devices.Length);
_DiscoDevicesAsync_ShowDevices(e);
}
console.WriteLine("Complete.");
}
void _DiscoDevicesAsync_ProgressCallback(object sender, DiscoverDevicesEventArgs e)
{
var nowUtc = DateTime.UtcNow;
Debug.Assert((int)e.UserState == 99);
CheckSyncCtx();
console.WriteLine("At {0}, {1}, {2} devices:",
GetTimeWallclockHR(), "async progress",
e.Devices.Length);
_DiscoDevicesAsync_ShowDevices(e);
}
private void _DiscoDevicesAsync_ShowDevices(DiscoverDevicesEventArgs e)
{
foreach (var dev in e.Devices) {
console.WriteLine("* {0} {1}, last seen: {2}", dev.DeviceAddress, ToStringQuotedOrNull(dev.DeviceName),
dev.LastSeen == DateTime.MinValue ? "NEVER" : dev.LastSeen.ToString("o"));
}
}
private bool WriteAsyncCompletedState(string name,
AsyncCompletedEventArgs e)
{
if (e.Cancelled) {
console.WriteLine("Cancelled: " + name);
} else if (e.Error != null) {
console.WriteLine("Error in: " + name + ", error: {0}.", Exception_FirstLine(e.Error));
} else {
console.WriteLine("Successful Completion of: " + name);
return true;
}
return false;
}
private void CheckSyncCtx()
{
bool? bad = console.InvokeRequired;
if (bad == true) {
console.WriteLine("Event not called on the UI thread!!!!");
}
}
//--------
BluetoothRadio m_factoryRadio;
BluetoothPublicFactory m_factory;
// TODO Should BluetoothPublicFactory have a Primary/AllRadios property?
/// <summary>
/// --can return null--
/// </summary>
/// <returns></returns>
BluetoothRadio Get_BluetoothRadio()
{
if (m_factory == null)
return BluetoothRadio.GetPrimaryRadio();
BluetoothRadio radio = m_factoryRadio;
if (radio == null)
throw new InvalidOperationException("No active radios.");
//ClassOfDevice checkNonNull = radio.ClassOfDevice;
return radio;
}
BluetoothDeviceInfo Create_BluetoothDeviceInfo(BluetoothAddress addr)
{
if (m_factory == null)
return new BluetoothDeviceInfo(addr);
return m_factory.CreateBluetoothDeviceInfo(addr);
}
BluetoothClient Create_BluetoothClient()
{
if (m_factory == null)
return new BluetoothClient();
return m_factory.CreateBluetoothClient();
}
private BluetoothClient Create_BluetoothClient(BluetoothEndPoint localEndPoint)
{
if (m_factory == null)
return new BluetoothClient(localEndPoint);
return m_factory.CreateBluetoothClient(localEndPoint);
}
BluetoothListener Create_BluetoothListener(Guid svc)
{
if (m_factory == null)
return new BluetoothListener(svc);
return m_factory.CreateBluetoothListener(svc);
}
BluetoothListener Create_BluetoothListener(Guid svc, ServiceRecord record)
{
if (m_factory == null)
return new BluetoothListener(svc, record);
return m_factory.CreateBluetoothListener(svc, record);
}
BluetoothListener Create_BluetoothListener(BluetoothEndPoint ep)
{
if (m_factory == null)
return new BluetoothListener(ep);
return m_factory.CreateBluetoothListener(ep);
}
BluetoothListener Create_BluetoothListener(BluetoothEndPoint ep, ServiceRecord record)
{
if (m_factory == null)
return new BluetoothListener(ep, record);
return m_factory.CreateBluetoothListener(ep, record);
}
ObexWebRequest Create_ObexWebRequest(Uri requestUri)
{
if (m_factory == null)
return new ObexWebRequest(requestUri);
return m_factory.CreateObexWebRequest(requestUri);
}
ObexWebRequest Create_ObexWebRequest(string scheme, BluetoothAddress target, string path)
{
if (m_factory == null)
return new ObexWebRequest(target, path);
return m_factory.CreateObexWebRequest(scheme, target, path);
}
ObexListener Create_ObexListener_Bluetooth()
{
if (m_factory == null)
return new ObexListener(ObexTransport.Bluetooth);
return m_factory.CreateObexListener();
}
#if !ANDROID
L2CapListener Create_L2CapListener(Guid svc)
{
//if (m_factory == null)
return new L2CapListener(svc);
//return m_factory.CreateL2CapListener(svc);
}
private L2CapListener Create_L2CapListener(BluetoothEndPoint localEndPoint)
{
//if (m_factory == null)
return new L2CapListener(localEndPoint);
//return m_factory.CreateL2CapListener(localEndPoint);
}
#endif
[MenuItem]
public void SetStack_Factory()
{
BluetoothRadio[] list = BluetoothRadio_GetAllAndDump();
if (list.Length == 0) {
console.WriteLine("No radios found!");
m_factory = null;
m_factoryRadio = null;
}
int? choice;
do {
choice = console.ReadOptionalInteger(string.Format("Which stack for factory (1-{0}), 0 for \"new\"-direct", list.Length));
if (choice == null) choice = 0;
} while (choice < 0 || choice > list.Length);
if (choice == 0) {
m_factory = null;
m_factoryRadio = null;
console.WriteLine("Selected #{0} 'new-direct'.", choice);
} else {
m_factoryRadio = list[choice.Value - 1];
m_factory = m_factoryRadio.StackFactory;
console.WriteLine("Selected #{0}, stack: '{1}' address: {2}.", choice,
m_factoryRadio.SoftwareManufacturer, m_factoryRadio.LocalAddress);
}
}
//--------
private string GetTimeWallclockHR()
{
return DateTime.Now.TimeOfDay.ToString();
}
private string GetTime()
{
return Environment.TickCount.ToString();
}
void ErrorFromMiscCallback(IAsyncResult ar)
{
MiscCallback(ar);
throw new RankException();
}
void MiscCallback(IAsyncResult ar)
{
console.WriteLine("{1}: Callback called for \"{0}\"", ar.AsyncState, GetTime());
}
void EmptyCallback(IAsyncResult ar)
{
if (ar.CompletedSynchronously) {
} else {
}
}
bool VerifyConnectionWrite()
{
if (_peer == null) {
console.WriteLine("No connection!");
return false;
}
if (!_peer.CanWrite) {
if (!console.ReadYesNo("NOT CanWrite, do operation anyway", false))
return false;
}
return true;
}
bool VerifyConnectionRead()
{
if (_peer == null) {
console.WriteLine("No connection!");
return false;
}
if (!_peer.CanRead) {
if (!console.ReadYesNo("NOT CanRead, do operation anyway", false))
return false;
}
return true;
}
//--------
[MenuItem, SubMenu("Data")]
public void PrintStreamState()
{
if (_peer == null) {
console.WriteLine("Stream is null.");
} else {
console.WriteLine("Stream has CanRead: {0}, CanWrite: {1}.",
_peer.CanRead, _peer.CanWrite);
}
if (_cli == null) {
console.WriteLine("BtClient is null.");
} else {
var cli = _cli.Target;
if (cli == null) {
console.WriteLine("BtClient has been GC'd away.");
} else {
console.WriteLine("BtClient has Connected: {0}.",
cli.Connected);
}
}
}
[MenuItem, SubMenu("Data")]
public void CloseStream()
{
if (_peer != null) {
_peer.Close();
_peer = null;
}
}
[MenuItem, SubMenu("Data")]
public void CloseStream_ButDontNullIt()
{
if (_peer != null) {
_peer.Close();
}
}
[MenuItem, SubMenu("Data")]
public void NullStreamAndClient()
{
_peer = null;
_cli = null;
}
[MenuItem, SubMenu("Data")]
public void CloseClientIfExists()
{
if (_cli != null) {
BluetoothClient cli = _cli.Target;
if (cli != null) {
cli.Close();
_cli = null;
} else {
console.WriteLine("The reference has been GC'd.");
}
}
}
private BluetoothListener ListenInit()
{
Guid svcClass = BluetoothService.Wap;
console.WriteLine("Default UUID : {0}", svcClass);
Guid? inputGuid = console.ReadOptionalBluetoothUuid("UUID", svcClass);
if (inputGuid.HasValue)
svcClass = inputGuid.Value;
int? port = console.ReadOptionalInteger("Port number");
bool auth = console.ReadYesNo("Authenticate", false);
bool encpt = console.ReadYesNo("Encrypt", false);
bool setPin1, setPin2;
string passcode;
BluetoothAddress pinAddr;
PromptForSetPin(console, out setPin1, out setPin2, out passcode, out pinAddr);
string svcName = console.ReadLine("Service Name (optional)");
if (svcName != null && svcName.Length == 0)
svcName = null;
//
BluetoothEndPoint lep;
if (port == null)
lep = new BluetoothEndPoint(BluetoothAddress.None, svcClass);
else
lep = new BluetoothEndPoint(BluetoothAddress.None, svcClass, port.Value);
console.WriteLine("Going to listen on: {0}:{1}:{2}; auth: {3}, encrypt: {4}.",
lep.Address, lep.Service, lep.Port, auth, encpt);
//
ServiceRecord sr = null;
if (lep.Service == BluetoothService.DialupNetworking) {
var bldr = new ServiceRecordBuilder();
bldr.AddServiceClass(lep.Service);
bldr.AddServiceClass(BluetoothService.GenericNetworking);
bldr.AddBluetoothProfileDescriptor(lep.Service, 1, 0);
sr = bldr.ServiceRecord;
console.WriteLine("Adding custom record: "
+ ServiceRecordUtilities.Dump(sr));
}
BluetoothListener lsnr;
if (sr == null) {
lsnr = Create_BluetoothListener(lep);
} else {
lsnr = Create_BluetoothListener(lep, sr);
}
if (svcName != null)
lsnr.ServiceName = svcName;
// Assume false by default, so if NotImpl fails only if user says true.
if (auth)
lsnr.Authenticate = true;
if (encpt)
lsnr.Encrypt = true;
if (setPin1) {
Debug.Assert(pinAddr == null, "pinAddr == null");
//lsnr.SetPin(passcode);
console.WriteLine("Soooorrrrry we don't support SetPin(String) on listener!!!!");
throw new NotSupportedException("MenuTesting");
} else if (setPin2) {
Debug.Assert(pinAddr != null, "pinAddr != null");
lsnr.SetPin(pinAddr, passcode);
}
console.WriteLine("Starting Listener...");
lsnr.Start();
BluetoothEndPoint lepLsnr = (BluetoothEndPoint)lsnr.LocalEndPoint;
console.WriteLine("Listening on endpoint: {0}", lepLsnr);
return lsnr;
}
//[MenuItem, SubMenu("BtLsnr")]
//public void ListenStartStopStart()
//{
// Guid svcClass = BluetoothService.Wap;
// console.WriteLine("Default UUID : {0}", svcClass);
// Guid? inputGuid = console.ReadOptionalBluetoothUuid("UUID");
// if (inputGuid.HasValue)
// svcClass = inputGuid.Value;
// BluetoothListener lsnr = Create_BluetoothListener(svcClass);
// lsnr.Start();
// lsnr.Stop();
// lsnr.Start();
// //
// lsnr = null;
// GC.Collect();
// GC.Collect();
// GC.WaitForPendingFinalizers();
//}
[MenuItem, SubMenu("BtLsnr")]
public void Listen()
{
BluetoothListener lsnr = ListenInit();
BluetoothClient cli;
bool startStopStartEtc = console.ReadYesNo("Start-Stop-Start-Stop-Start-Finalize", false);
if (startStopStartEtc) {
lsnr.Stop();
lsnr.Start();
console.WriteLine("Stopped and restarted.");
}
bool @async = console.ReadYesNo("Async Accept", false);
if (!@async) {
bool callPending = console.ReadYesNo("Loop on Pending()", false);
if (callPending) {
int i = 0;
while (!lsnr.Pending()) {
console.WriteLine("Not Pending" + new string('.', (i + 3) % 3));
const int HalfSecond = 500;
Thread.Sleep(HalfSecond);
++i;
}
console.WriteLine("Is Pending...");
}
//bool closeNow = console.ReadYesNo("Hit return to proceed to EndConnect. Enter Y to call Close first.", false);
console.WriteLine("calling Accept...");
cli = lsnr.AcceptBluetoothClient();
} else {
console.WriteLine("Waiting for connection...");
IAsyncResult ar = lsnr.BeginAcceptBluetoothClient(MiscCallback, "BeginAcceptBluetoothClient");
console.WriteLine("(BeginAccept returned)");
bool startStopStartEtcAfter = console.ReadYesNo("Start-Stop-Start-Stop-Start-Finalize (will break *us*)", false);
if (startStopStartEtcAfter) {
lsnr.Stop();
lsnr.Start();
console.WriteLine("Stopped and restarted.");
}
#if !NETCF
ManualResetEvent quit = console.NewManualResetEvent(false);
int signalledIdx = WaitHandle.WaitAny(new WaitHandle[] { ar.AsyncWaitHandle, quit });
if (signalledIdx == 1) {
// ?Do we want to test disposal or Finalization here?
// lsnr.Stop()
_peer = null;
return;
}
#endif
cli = lsnr.EndAcceptBluetoothClient(ar);
}
//
_peer = cli.GetStream();
_cli = new WeakReferenceT<BluetoothClient>(cli);
console.WriteLine("Got connection from: '{0}' {1}", cli.RemoteMachineName, cli.RemoteEndPoint);
PrintLocalEndpointIfAvailable(cli);
console.Pause("Un-pause to continue; and close listener");
if (!startStopStartEtc) {
lsnr.Stop();
} else {
lsnr.Stop();
lsnr.Start();
//
bool x = console.ReadYesNo("Do Async Accept (before Finalization)", false);
IAsyncResult arLast = null;
if (x) {
arLast = lsnr.BeginAcceptBluetoothClient(MiscCallback, "BeginAcceptBluetoothClient");
console.WriteLine("(BeginAccept returned)");
}
lsnr = null;
GC.Collect();
GC.Collect();
GC.WaitForPendingFinalizers();
console.WriteLine("Stopped, restarted, and Finalized.");
if (arLast != null) {
console.WriteLine("arLastL: {0}", arLast.IsCompleted);
// Can't call EndAccept as no lsnr reference!
}
}
}
[MenuItem, SubMenu("BtLsnr")]
public void ListenAndImmediatelyClose()
{
ListenAndImmediatelySendAndClose_(null);
}
[MenuItem, SubMenu("BtLsnr")]
public void ListenAndImmediatelySendOneByteAndClose()
{
ListenAndImmediatelySendAndClose_(new byte[] { (byte)'a' });
}
void ListenAndImmediatelySendAndClose_(byte[] data)
{
BluetoothListener lsnr = ListenInit();
console.WriteLine("Waiting for connection...");
BluetoothClient cli = lsnr.AcceptBluetoothClient();
console.WriteLine("Got connection from: {0}!", cli.RemoteMachineName);
_peer = cli.GetStream();
if (data != null)
_peer.Write(data, 0, data.Length);
_peer.Close();
_peer = null;
console.WriteLine("Got connection from ({2}and closed it!): '{0}' {1}",
cli.RemoteMachineName, cli.RemoteEndPoint,
(data != null ? "sent " : string.Empty));
lsnr.Stop();
}
[MenuItem, SubMenu("Data")]
public void SendOneByteAndImmediatelyClose()
{
if (!VerifyConnectionWrite())
return;
byte[] data = { (byte)'a' };
_peer.Write(data, 0, data.Length);
_peer.Close();
}
[MenuItem, SubMenu("BtLsnr")]
public void ListenAcceptMultiple()
{
BluetoothListener lsnr = ListenInit();
ManualResetEvent quit = console.NewManualResetEvent(false);
ListenAcceptMultipleState state = new ListenAcceptMultipleState();
state.lsnr = lsnr;
state.quit = quit;
bool keepOpen = console.ReadYesNo("Keep reference to all connections?", false);
state.KeepAllConnections = keepOpen;
state.ReadToEnd = console.ReadYesNo("ReadToEnd of all connections?", false);
lsnr.BeginAcceptBluetoothClient(ListenAcceptMultiple_Callback, state);
console.Pause("Un-pause to stop accepting");
quit.Set();
lsnr.Stop();
}
struct ListenAcceptMultipleState
{
public BluetoothListener lsnr;
public ManualResetEvent quit;
public int num;
//
bool storeAllConnections;
public List<BluetoothClient> connList;
public bool ReadToEnd;
public bool KeepAllConnections
{
get { return storeAllConnections; }
set
{
storeAllConnections = value;
if (storeAllConnections && connList == null) {
connList = new List<BluetoothClient>();
}
}
}
}
struct ListenAcceptMultipleConnectionState
{
public BluetoothClient Cli;
public int Id;
}
void ListenAcceptMultiple_Callback(IAsyncResult arCb)
{
ListenAcceptMultipleState state = (ListenAcceptMultipleState)arCb.AsyncState;
BluetoothClient cli;
try {
cli = state.lsnr.EndAcceptBluetoothClient(arCb);
if (state.KeepAllConnections) {
state.connList.Add(cli);
}
} catch (ArgumentException ex) {
console.WriteLine("Accept failed, due to quit? Exiting. "
+ Exception_FirstLine(ex));
return;
} catch (ObjectDisposedException ex) {
console.WriteLine("Accept failed, due to quit? Exiting. "
+ Exception_FirstLine(ex));
return;
}
Stream peer = cli.GetStream();
console.WriteLine("At " + DateTime.Now.ToLongTimeString() + " got connection #" + (state.num + 1) + " from: '{0}' {1}", cli.RemoteMachineName, cli.RemoteEndPoint);
++state.num;
if (!IsSet(state.quit))
state.lsnr.BeginAcceptBluetoothClient(ListenAcceptMultiple_Callback, state);
if (state.ReadToEnd) {
ThreadPool.QueueUserWorkItem(ReadToEnd_Runner,
new ListenAcceptMultipleConnectionState { Cli = cli, Id = state.num });
}
if (_peer == null) {
_peer = peer;
console.WriteLine("Connection now active.");
}
}
void ReadToEnd_Runner(object state)
{
var state2 = (ListenAcceptMultipleConnectionState)state;
var conn = state2.Cli.GetStream();
var buf = new byte[1000];
while (true) {
try {
int readLen = conn.Read(buf, 0, buf.Length);
console.WriteLine("Conn#{0}: Read '{1}' bytes",
state2.Id, readLen);
if (readLen == 0)
break;
} catch (Exception ex) {
console.WriteLine("Conn#{0}: exception: {1}",
state2.Id, Exception_FirstLine(ex));
break;
}
}//while
console.WriteLine("Conn#{0}: Exit at {1}",
state2.Id, DateTime.Now.ToLongTimeString());
}
[MenuItem, SubMenu("SmokeTest")]
public void NewBt_Endpoint()
{
var ep = new BluetoothEndPoint(BluetoothAddress.None, Guid.Empty);
console.WriteLine("BluetoothEndPoint created successfully.");
}
[MenuItem, SubMenu("SmokeTest")]
public void NewBtEndpoint_fromSocketAddress()
{
var ep = new BluetoothEndPoint(BluetoothAddress.Parse("002233445566"), BluetoothService.AttProtocol);
console.WriteLine("BluetoothEndPoint created successfully.");
var sa = ep.Serialize();
console.WriteLine("SocketAddress created successfully.");
var ep2 = ep.Create(sa);
console.WriteLine("BluetoothEndPoint created successfully.");
}
[MenuItem, SubMenu("SmokeTest")]
public void NewBt_Cli()
{
using (BluetoothClient cli = Create_BluetoothClient()) {
console.WriteLine("BluetoothClient created successfully.");
console.ReadLine("BluetoothClient created. Continue to dispose");
}
}
[MenuItem, SubMenu("SmokeTest")]
public void NewBt_Lsnr()
{
BluetoothListener lsnr = Create_BluetoothListener(BluetoothService.Wap);
try {
console.WriteLine("BluetoothListener created, now calling Start.");
lsnr.Start();
console.ReadLine("Started. Continue to dispose");
} finally {
if (lsnr != null)
lsnr.Stop();
}
}
BluetoothAddress _simpleConnectAddress;
[MenuItem, SubMenu("BtClient")]
public void Connect_SimpleClosingFirst()
{
if (_peer != null && console.ReadYesNo("Close (possible) connection first", false)) {
CloseStream();
}
//
BluetoothAddress addr;
if (_simpleConnectAddress != null
&& console.ReadYesNo("Use server address: " + _simpleConnectAddress, true)) {
addr = _simpleConnectAddress;
} else {
addr = console.ReadBluetoothAddress("Server's BluetoothAddress");
}
ConnectSimpleClosingFirstPart2(addr);
}
void ConnectSimpleClosingFirstPart2(BluetoothAddress addr)
{
Guid svcClass = BluetoothService.Wap;
BluetoothEndPoint rep = new BluetoothEndPoint(addr, svcClass);
BluetoothClient cli = Create_BluetoothClient();
_simpleConnectAddress = addr;
//
console.WriteLine("Connecting to: {0}:{1}:{2} ...", rep.Address, rep.Service, rep.Port);
cli.Connect(rep);
console.WriteLine("Connected to : '{0}' {1}", cli.RemoteMachineName, cli.RemoteEndPoint);
PrintLocalEndpointIfAvailable(cli);
_peer = cli.GetStream();
_cli = new WeakReferenceT<BluetoothClient>(cli);
}
[MenuItem, SubMenu("BtClient")]
public void Connect()
{
BluetoothClient cli;
Connect_(out cli);
_peer = cli.GetStream();
_cli = new WeakReferenceT<BluetoothClient>(cli);
}
#if NETCF
[MenuItem, SubMenu("Playing")]
public void BtpsScoWith_Connect()
{
var p = new InTheHand.Net.Bluetooth.StonestreetOne.BluetopiaPlaying();
Action<BluetoothAddress> makeConnect = delegate(BluetoothAddress address) {
p.HciCreateConnection(address);
};
//
BluetoothClient cli;
Connect_(out cli, makeConnect);
_peer = cli.GetStream();
_cli = new WeakReferenceT<BluetoothClient>(cli);
ThreadPool.QueueUserWorkItem(state => Read_(40, false));
//
p.HciAddScoConnection();
//
var buf = Encoding.ASCII.GetBytes("ATD 07981152473\r");
_peer.Write(buf, 0, buf.Length);
}
[MenuItem, SubMenu("Playing")]
public void BtpsRawHci()
{
var p = new InTheHand.Net.Bluetooth.StonestreetOne.BluetopiaPlaying();
Byte ogf = 0x3f;
ushort ocf = 0;
const byte FirstFragment = 0x80;
const byte LastFragment = 0x40;
const byte BccmdChannelId = 2;
const byte PayloadDescriptor = BccmdChannelId | FirstFragment | LastFragment;
//
//const ushort xxBccmdGetReqxx = 0x0000;
//const ushort xxBuildIdxx = 0x28_19;
//const ushort xxBuildIdLoaderxx = 0x28_38;
//
int seqNum = Interlocked.Increment(ref csrSeqNum);
Byte[] command = { PayloadDescriptor,
//cmd
0x00, 0x00,
//len
16,0,
//SeqNum
(byte)seqNum,0,
// VarId
0x19,0x28,
// Status
0,0,
// Payload
0,0,0,0, 0,0,0,0,
};
Byte lenCommand = checked((byte)command.Length);
//
int ret = p.HciSendRawCommand(ogf, ocf, lenCommand, command);
console.WriteLine("HCI_Send_Raw_Command ret: {0}", ret);
/*
Frame 1: 23 bytes on wire (184 bits), 23 bytes captured (184 bits)
01:00:fc:13!c2:00:00:10: 00:01:00:19:28:00:00:00:
00:00:00:00:00:00:00
Frame 2: 36 bytes on wire (288 bits), 36 bytes captured (288 bits)
04:ff:21!c2:01:00:10:00: 01:00:19:28:00:00:7e:0d:
00:00:00:00:00:00:00:00: 00:00:00:00:00:00:00:00:
00:00:00:00
* Status = 0
* BuildID = 0x0d7e = 3454
* Which is the same as the value reported in Radio info. :-)
*/
}
static int csrSeqNum;
#endif
readonly TimeSpan ConnectDuringDiscoveryPreConnectDelayMs
= TimeSpan.FromSeconds(4);
[MenuItem, SubMenu("BtClient")]
public void Connect_WithInquiryRunning_APM()
{
TimeSpan delay = ConnectDuringDiscoveryPreConnectDelayMs;
var givenDelay = console.ReadTimeSecondsOptional(" (default " + delay + ")");
if (givenDelay != null) {
delay = givenDelay.Value;
}
BluetoothClient cliDD = Create_BluetoothClient();
IAsyncResult arDD = null;
Action<BluetoothAddress> startDisco = delegate
{
arDD = cliDD.BeginDiscoverDevices(255, false, false, false, true,
MiscCallback, "BeginDiscoverDevices");
Thread.Sleep(delay.Seconds);
};
BluetoothClient cli;
DateTime startT = DateTime.UtcNow;
try {
Connect_(out cli, startDisco);
_peer = cli.GetStream();
_cli = new WeakReferenceT<BluetoothClient>(cli);
} finally {
DateTime connectedT = DateTime.UtcNow;
console.WriteLine("Started at: {0}", startT);
console.WriteLine("Connect completed at: {0}, waiting for device discovery...", connectedT);
var devices = cliDD.EndDiscoverDevices(arDD);
DateTime endDdT = DateTime.UtcNow;
console.WriteLine("End of DD at: {0}, with {1} devices.", endDdT, devices.Length);
}
}
[MenuItem, SubMenu("BtClient")]
public void Connect_WithInquiryRunning_EBAP()
{
TimeSpan delay = ConnectDuringDiscoveryPreConnectDelayMs;
var givenDelay = console.ReadTimeSecondsOptional(" (default " + delay + ")");
if (givenDelay != null) {
delay = givenDelay.Value;
}
BluetoothClient cliDD = Create_BluetoothClient();
var ddComplete = new ManualResetEvent(false);
var btco = new BluetoothComponent(cliDD);
btco.DiscoverDevicesProgress += _DiscoDevicesAsync_ProgressCallback;
btco.DiscoverDevicesComplete += _DiscoDevicesAsync_CompleteCallback;
btco.DiscoverDevicesComplete += (s, e) => ddComplete.Set();
Action<BluetoothAddress> startDisco = delegate
{
btco.DiscoverDevicesAsync(255, false, false, false, true, 99);
Thread.Sleep(delay.Seconds);
};
BluetoothClient cli;
DateTime startT = DateTime.UtcNow;
try {
Connect_(out cli, startDisco);
_peer = cli.GetStream();
_cli = new WeakReferenceT<BluetoothClient>(cli);
} finally {
DateTime connectedT = DateTime.UtcNow;
console.WriteLine("Started at: {0}", startT);
console.WriteLine("Connect completed at: {0}, waiting for device discovery...", connectedT);
ddComplete.WaitOne();
DateTime endDdT = DateTime.UtcNow;
//console.WriteLine("End of DD at: {0}, with {1} devices.", endDdT, devices.Length);
console.WriteLine("End of DD at: {0}.", endDdT);
ddComplete.Close();
}
}
[MenuItem, SubMenu("BtClient")]
public void Connect_FromInquiryCallback()
{
BluetoothClient cliDd = Create_BluetoothClient();
cliDd.BeginDiscoverDevices(255, true, true, true, false,
Connect_FromInquiryCallback_DdCallback, cliDd);
console.WriteLine("Running async DiscoverDevices...");
}
void Connect_FromInquiryCallback_DdCallback(IAsyncResult ar)
{
console.WriteLine("DiscoverDevices completed...");
BluetoothClient cliDd = (BluetoothClient)ar.AsyncState;
cliDd.EndDiscoverDevices(ar);
//
try {
BluetoothClient cli;
Connect_(out cli);
_peer = cli.GetStream();
_cli = new WeakReferenceT<BluetoothClient>(cli);
} catch (Exception ex) {
console.WriteLine("Connect_FromInquiryCallback error: " + ex);
}
}
#if TEST_EARLY
[MenuItem, SubMenu("BtClient")]
public void Connect_GetStream2()
{
BluetoothClient cli;
Connect_(out cli);
peer = cli.GetStream2();
s_cli = new WeakReferenceT<BluetoothClient>(cli);
}
#endif
[MenuItem, SubMenu("BtClient")]
public void ConnectSuccessfullyAnd_ImmediatelyClose()
{
ConnectSuccessfullyAndImmediatelySendAndClose_(null);
}
[MenuItem, SubMenu("BtClient")]
public void ConnectSuccessfullyAndImmediatelySend_OneByteAndClose()
{
ConnectSuccessfullyAndImmediatelySendAndClose_(new byte[] { (byte)'b' });
}
void ConnectSuccessfullyAndImmediatelySendAndClose_(byte[] data)
{
BluetoothClient cli;
Connect_(out cli);
_peer = cli.GetStream();
if (data != null)
_peer.Write(data, 0, data.Length);
_peer.Close();
_peer = null;
_cli = null;
}
[MenuItem, SubMenu("BtClient")]
public void ConnectMultiple_Devices()
{
int num = console.ReadInteger("How many connects?");
bool oaat = console.ReadYesNo("Do one-at-a-time (e.g. Widcomm SDP sync)?", false);
BluetoothAddress[] addrList = new BluetoothAddress[num];
Guid[] svcClassList = new Guid[num];
int?[] portList = new int?[num];
BluetoothClient[] cliList = new BluetoothClient[num];
IAsyncResult[] arList = new IAsyncResult[num];
//
for (int i = 0; i < num; ++i) {
addrList[i] = console.ReadBluetoothAddress("Server #" + (i + 1) + "'s BluetoothAddress");
svcClassList[i] = BluetoothService.Wap;
Guid? inputGuid = console.ReadOptionalBluetoothUuid("UUID", svcClassList[i]);
if (inputGuid.HasValue)
svcClassList[i] = inputGuid.Value;
portList[i] = console.ReadOptionalInteger("Port number");
}
//
IAsyncResult waitForLast = null;
for (int i = 0; i < num; ++i) {
if (waitForLast != null) {
console.Write("Waiting previous. ");
bool signalled = waitForLast.AsyncWaitHandle.WaitOne(60 * 1000, false);
if (!signalled) {
throw new InvalidOperationException("Timed-out waiting for previous connect to complete.");
}
}
BluetoothEndPoint rep;
if (portList[i] == null)
rep = new BluetoothEndPoint(addrList[i], svcClassList[i]);
else
rep = new BluetoothEndPoint(addrList[i], svcClassList[i], portList[i].Value);
console.WriteLine("{4}: Connecting #{3} to: {0}:{1}:{2} ...", rep.Address, rep.Service, rep.Port,
(i + 1), GetTime());
//
cliList[i] = Create_BluetoothClient();
try {
arList[i] = cliList[i].BeginConnect(rep,
MiscCallback, "BeginConnect #" + (i + 1));
console.WriteLine("{0}: (BeginConnect returned)", GetTime());
if (oaat) {
waitForLast = arList[i];
}
} catch (System.Net.Sockets.SocketException ex) {
console.WriteLine("{0}: BeginConnect failed: {1}", GetTime(), Exception_FirstLine(ex));
}
}//for
//
WaitAll(arList);
console.WriteLine("All signalled");
//
for (int i = 0; i < cliList.Length; i++) {
try {
cliList[i].EndConnect(arList[i]);
} catch (Exception ex) {
console.WriteLine("Error for #{3}: ", (i + 1), Exception_FirstLine(ex));
}
}
console.WriteLine("All completed");
}
private void WaitAll(IList<IAsyncResult> arList)
{
WaitHandle[] whList = GetWaitHandles(arList);
#if !NETCF
bool signalled = WaitHandle.WaitAll(whList);
#else
bool signalled = WaitHandle_WaitAll_Hack(whList);
#endif
Debug.Assert(signalled, "Given infinite timeout, but returned NON-signalled!?!");
}
private WaitHandle[] GetWaitHandles(IList<IAsyncResult> arList)
{
Debug.Assert(arList != null, "ArgNullEx");
List<WaitHandle> output = new List<WaitHandle>(arList.Count);
for (int i = 0; i < arList.Count; ++i) {
if (arList[i] != null)
output.Add(arList[i].AsyncWaitHandle);
}
return output.ToArray();
}
#if NETCF
bool WaitHandle_WaitAll_Hack(WaitHandle[] list)
{
bool sum = true;
foreach (WaitHandle cur in list) {
bool signalled = cur.WaitOne();
Debug.Assert(signalled, "NOT signalled");
sum = sum && signalled;
}
Debug.Assert(sum, "NOT signalled->sum");
return sum;
}
#endif
void Connect_(out BluetoothClient cli)
{
Connect_(out cli, null);
}
void Connect_(out BluetoothClient cli, Action<BluetoothAddress> codeToRunJustBeforeConnect)
{
BluetoothAddress addr = console.ReadBluetoothAddress("Server's BluetoothAddress");
Guid svcClass = BluetoothService.Wap;
Guid? inputGuid = console.ReadOptionalBluetoothUuid("UUID", svcClass);
if (inputGuid.HasValue)
svcClass = inputGuid.Value;
int? port = console.ReadOptionalInteger("Port number");
bool auth = console.ReadYesNo("Authenticate", false);
bool encpt = console.ReadYesNo("Encrypt", false);
bool setPin1, setPin2;
string passcode;
BluetoothAddress pinAddr;
PromptForSetPin(console, out setPin1, out setPin2, out passcode, out pinAddr);
//
BluetoothEndPoint lep;
BluetoothAddress localAddrOptional = console.ReadOptionalBluetoothAddress("Local Bind() BluetoothAddress");
if (localAddrOptional != null) {
const int DefaultLocalPort = 0;
var localPort = console.ReadOptionalInteger("Local port (default: " + DefaultLocalPort + ")");
if (!localPort.HasValue) { localPort = DefaultLocalPort; }
lep = new BluetoothEndPoint(localAddrOptional, BluetoothService.Empty, localPort.Value);
} else {
lep = null;
}
//
#if FX4
bool taskAsync = console.ReadYesNo("Task-Async Connect?", false);
#else
bool taskAsync = false;
#endif
bool @async = taskAsync ? false : console.ReadYesNo("Async (APM) Connect?", false);
bool asyncCallback = true;//not used but init anyway
if (taskAsync || @async) {
asyncCallback = console.ReadYesNo("Async Callback?", true);
}
//
BluetoothEndPoint rep;
if (port == null)
rep = new BluetoothEndPoint(addr, svcClass);
else
rep = new BluetoothEndPoint(addr, svcClass, port.Value);
console.WriteLine("Connecting to: {0}:{1}:{2} ...", rep.Address, rep.Service, rep.Port);
//
if (lep != null) {
console.WriteLine("Binding to: {0}::{2} ...", lep.Address, lep.Service, lep.Port);
cli = Create_BluetoothClient(lep);
} else {
cli = Create_BluetoothClient();
}
//
// For Auth & Encrypt assume false by default, so if NotImpl fails only if user says true.
if (auth)
cli.Authenticate = true;
if (encpt)
cli.Encrypt = true;
if (setPin1) {
Debug.Assert(pinAddr == null, "pinAddr == null");
cli.SetPin(passcode);
} else if (setPin2) {
Debug.Assert(pinAddr != null, "pinAddr != null");
cli.SetPin(pinAddr, passcode);
}
if (codeToRunJustBeforeConnect != null) {
codeToRunJustBeforeConnect(addr);
console.WriteLine("(Have run the code before connect).");
}
if (taskAsync) {
#if FX4
var task = cli.ConnectAsync(rep, "ConnectAsync");
if (asyncCallback)
task.ContinueWith(MiscCallback);
console.WriteLine("(ConnectAsync returned)");
bool closeNow = console.ReadYesNo("Respond when we should proceed to Wait. Enter Y to call Close first.", false);
if (closeNow) {
cli.Close();
}
task.Wait();
#else
throw new NotSupportedException("Task is FX4");
#endif
} else if (@async) {
AsyncCallback cb = null;
if (asyncCallback)
cb = MiscCallback;
IAsyncResult ar = cli.BeginConnect(rep,
cb, "BeginConnect");
console.WriteLine("(BeginConnect returned)");
#if NETCF // ReadYesNo will block the screen. :-(
console.Pause("Paused after BeginConnect");
#endif
bool closeNow = console.ReadYesNo("Respond when we should proceed to EndConnect. Enter Y to call Close first.", false);
if (closeNow) {
cli.Close();
}
cli.EndConnect(ar);
} else {
cli.Connect(rep);
}
console.WriteLine("Connected to : '{0}' {1}", cli.RemoteMachineName, cli.RemoteEndPoint);
PrintLocalEndpointIfAvailable(cli);
}
private void PrintLocalEndpointIfAvailable(BluetoothClient cli)
{
System.Net.Sockets.Socket sock = null;
try {
sock = cli.Client;
} catch (NotSupportedException) {
} catch (NotImplementedException) {
}
if (sock != null) {
console.WriteLine("Local endpoint : {0}", sock.LocalEndPoint);
}
}
private void PromptForSetPin(MenuSystem console, out bool setPin1, out bool setPin2,
out string passcode, out BluetoothAddress pinAddr)
{
passcode = null;
pinAddr = null;
setPin1 = console.ReadYesNo("SetPin(string) [not for BtLsnr!]", false);
if (setPin1) {
setPin2 = false;
} else {
setPin2 = console.ReadYesNo("SetPin(address,string)", false);
}
if (setPin1 || setPin2) {
passcode = console.ReadLine("Passcode");
}
if (setPin2) {
pinAddr = console.ReadBluetoothAddress("PIN address");
}
}
[MenuItem, SubMenu("BtClient")]
public void ConnectMultiple_Times()
{
BluetoothAddress addr = console.ReadBluetoothAddress("Server's BluetoothAddress");
Guid svcClass = BluetoothService.Wap;
Guid? inputGuid = console.ReadOptionalBluetoothUuid("UUID", svcClass);
if (inputGuid.HasValue)
svcClass = inputGuid.Value;
int? port = console.ReadOptionalInteger("Port number");
//
BluetoothEndPoint rep;
if (port == null)
rep = new BluetoothEndPoint(addr, svcClass);
else
rep = new BluetoothEndPoint(addr, svcClass, port.Value);
console.WriteLine("Will connect to: {0}:{1}:{2} ...", rep.Address, rep.Service, rep.Port);
//
int count = console.ReadInteger("Connect how many times");
int? delay = console.ReadOptionalInteger("Delay between each (ms)");
//
BluetoothClient cli = null;
byte[] buf = { 0x61, 0x62, 0x63, 0x64 };
int countSuccess = 0;
int countFail = 0;
for (int i = 0; i < count; ++i) {
try {
if (delay.HasValue) {
Thread.Sleep(delay.Value);
}
console.Write("Connecting #" + (i + 1) + "...");
cli = Create_BluetoothClient();
cli.LingerState = new System.Net.Sockets.LingerOption(true, 10);
cli.Connect(rep);
++countSuccess;
console.WriteLine("Connected");
using (Stream peerA = cli.GetStream()) {
peerA.Write(buf, 0, buf.Length);
}
} catch (Exception ex) {
++countFail;
console.Write("Failed: " + Exception_FirstLine(ex));
Debug.WriteLine("ConnMulti: " + ex);
var exitOnError = false;
if (exitOnError) {
break;
}
} finally {
if (cli != null) {
cli.Close();
}
}
}//for
console.WriteLine("Count success: {0}, fail {1}",
countSuccess, countFail);
}
[MenuItem, SubMenu("Data")]
public void SendForever()
{
if (!VerifyConnectionWrite())
return;
int interSendPeriod = console.ReadInteger("Inter-send period in milliseconds");
byte[] buf = Encoding.ASCII.GetBytes("____abcdefghijklmnopqrstuvwxyz");
ManualResetEvent quit = console.NewManualResetEvent(false);
Action<Stream> send = delegate(Stream peer2)
{
int num = 0;
while (true) {
if (IsSet(quit))
break;
string numString = num.ToString("d4");
Debug.Assert(numString.Length == 4, "numString.Length: " + numString.Length);
unchecked {
buf[0] = (byte)numString[0];
buf[1] = (byte)numString[1];
buf[2] = (byte)numString[2];
buf[3] = (byte)numString[3];
}
peer2.Write(buf, 0, buf.Length);
console.Write(".");
if (IsSet(quit))
break;
Thread.Sleep(interSendPeriod);
++num;
}//while
};
IAsyncResult ar = DelegateExtension.BeginInvoke(send, _peer, null, null);
console.Pause("Un-pause to stop sending");
quit.Set();
DelegateExtension.EndInvoke(send, ar);
}
[MenuItem, SubMenu("Data")]
public void ZeroLengthSend()
{
if (_peer == null)
return;
byte[] buf = new byte[2];
_peer.Write(buf, 0, 0);
console.WriteLine("ZeroLengthSend");
}
[MenuItem, SubMenu("Data")]
public void ZeroLengthRead()
{
if (_peer == null)
return;
byte[] buf = new byte[2];
IAsyncResult ar = null;
bool doNormalReadFirst = console.ReadYesNo("Do normal async read first", false);
if (doNormalReadFirst)
ar = _peer.BeginRead(buf, 0, 1, null, null);
int readLen = _peer.Read(buf, 0, 0);
console.WriteLine("Did ZeroLengthRead, got length: {0}", readLen);
if (ar != null) {
int readLen0 = _peer.EndRead(ar);
console.WriteLine("The first read got {0} bytes.", readLen0);
}
}
[MenuItem, SubMenu("Data")]
public void Flush()
{
if (_peer == null)
return;
_peer.Flush();
}
[MenuItem, SubMenu("Data")]
public void SendOneAtATime()
{
if (!VerifyConnectionWrite())
return;
byte[] buf = Encoding.ASCII.GetBytes("____abcdefghijklmnopqrstuvwxyz");
Action<Stream> send = delegate(Stream peer2)
{
int num = 0;
while (true) {
string numString = num.ToString("d4");
Debug.Assert(numString.Length == 4, "numString.Length: " + numString.Length);
unchecked {
buf[0] = (byte)numString[0];
buf[1] = (byte)numString[1];
buf[2] = (byte)numString[2];
buf[3] = (byte)numString[3];
}
peer2.Write(buf, 0, buf.Length);
console.Write(".");
if (!console.ReadYesNo("Send another", true))
break;
}//while
};
send.Invoke(_peer);
}
private static bool IsSet(ManualResetEvent quit)
{
bool signalled = quit.WaitOne(0, false);
return signalled;
}
[MenuItem, SubMenu("Data")]
public void SendCrLf()
{
if (_peer == null || !_peer.CanWrite) {
console.WriteLine("No connection!");
return;
}
byte[] buf = Encoding.ASCII.GetBytes("\r\n");
_peer.Write(buf, 0, buf.Length);
}
[MenuItem, SubMenu("Playing")]
public void Write_HCI_ReadLocalName_toStream()
{
byte[] ReadLocalName = { 0x01, /*hci*/ 0x14, 0x0c, 0x00 };
if (_peer == null || !_peer.CanWrite) {
console.WriteLine("No connection!");
return;
}
byte[] buf = ReadLocalName;
_peer.Write(buf, 0, buf.Length);
}
[MenuItem, SubMenu("Data")]
public void SendAmountOneAtATime()
{
if (!VerifyConnectionWrite())
return;
byte[] srcBuf = Encoding.ASCII.GetBytes("____abcdefghijklmnopqrstuvwxyz");
Action<Stream> send = delegate(Stream peer2)
{
int num = 0;
int lastAmount = 4096;
byte[] buf = new byte[0];
while (true) {
int? amount = console.ReadOptionalInteger("How big send (default: " + lastAmount + ")");
amount = amount ?? lastAmount;
lastAmount = amount.Value;
//
if (buf.Length < amount) {
buf = new byte[amount.Value];
}
//
string numString = num.ToString("d4");
Debug.Assert(numString.Length == 4, "numString.Length: " + numString.Length);
unchecked {
buf[0] = (byte)numString[0];
buf[1] = (byte)numString[1];
buf[2] = (byte)numString[2];
buf[3] = (byte)numString[3];
}
peer2.Write(buf, 0, amount.Value);
console.Write(".");
if (!console.ReadYesNo("Send another", true))
break;
}//while
};
send.Invoke(_peer);
}
//--------
[MenuItem, SubMenu("Data")]
public void Read()
{
if (!VerifyConnectionRead())
return;
int? dumpTruncate = console.ReadOptionalInteger("Dump how much of receive (default None)");
bool binary = false;
if (dumpTruncate == null) {
dumpTruncate = 0;
}
if (dumpTruncate > 0) {
binary = console.ReadYesNo("Dump in hex", false);
}
Read_(dumpTruncate, binary);
}
void Read_(int? dumpTruncate, bool binary)
{
byte[] buf = new byte[100];
ManualResetEvent quit = console.NewManualResetEvent(false);
object lastReturn = "-never set-";
int totalRead = 0;
Action<Stream> dlgt = delegate(Stream peer2)
{
while (true) {
if (IsSet(quit))
break;
bool success = false;
try {
int readLen = peer2.Read(buf, 0, buf.Length);
console.Write(" len='{0}'", readLen);
success = true;
lastReturn = readLen;
totalRead += readLen;
if (readLen == 0) {
console.WriteLine(" EoS.");
break;
}
if (dumpTruncate > 0) {
string txt;
if (!binary) {
txt = Encoding.ASCII.GetString(buf, 0,
Math.Min(readLen, dumpTruncate.Value));
} else {
txt = BitConverter.ToString(buf, 0,
Math.Min(readLen, dumpTruncate.Value));
txt = txt.Substring(0,
Math.Min(txt.Length, dumpTruncate.Value));
}
console.WriteLine("\"{0}\"", txt);
}
} finally {
if (!success) {
lastReturn = "Error";
console.WriteLine("Completed by Error!!!");
}
}
}//while
};
IAsyncResult ar = DelegateExtension.BeginInvoke(dlgt, _peer, null, null);
console.Pause("Un-pause to stop after next Read");
quit.Set();
DelegateExtension.EndInvoke(dlgt, ar);
console.WriteLine("Last read returned: {0}", lastReturn);
console.WriteLine("Total read : {0}", totalRead);
}
[MenuItem, SubMenu("Data")]
public void ReadAndReflect()
{
if (!VerifyConnectionRead())
return;
byte[] buf = new byte[100];
byte[] rsp = new byte[100];
ManualResetEvent quit = console.NewManualResetEvent(false);
Action<Stream> dlgt = delegate(Stream peer2)
{
while (true) {
if (IsSet(quit))
break;
int readLen = peer2.Read(buf, 0, buf.Length);
console.Write(" len='{0}'", readLen);
if (readLen == 0) {
console.WriteLine(" EoS.");
break;
}
SwapCase(buf, rsp, readLen);
peer2.Write(rsp, 0, readLen);
}//while
};
IAsyncResult ar = DelegateExtension.BeginInvoke(dlgt, _peer, null, null);
console.Pause("Un-pause to stop after next Read");
quit.Set();
DelegateExtension.EndInvoke(dlgt, ar);
}
private static void SwapCase(byte[] src, byte[] dst, int len)
{
for (int i = 0; i < len; ++i) {
byte b = src[i];
char ch = (char)b;
char upper = char.ToUpper(ch, System.Globalization.CultureInfo.InvariantCulture);
char lower = char.ToLower(ch, System.Globalization.CultureInfo.InvariantCulture);
char upperBack = char.ToLower(ch, System.Globalization.CultureInfo.InvariantCulture);
char lowerBack = char.ToUpper(ch, System.Globalization.CultureInfo.InvariantCulture);
if (lowerBack != ch && upperBack != ch) {
// didn't round-trip, not a displayable(?) char, return as is.
dst[i] = (byte)ch;
} else if (lower == ch && upper == ch) {
// didn't change, not a alphabetical char, return as is.
dst[i] = (byte)ch;
} else if (lower == ch) { // Is lower case, so return as upper case
Debug.Assert(upper != ch, ((ushort)upper).ToString("X") + " != " + ((ushort)ch).ToString("X"));
dst[i] = (byte)upper;
} else {
Debug.Assert(upper == ch);
Debug.Assert(lower != ch, ((ushort)upper).ToString("X") + " != " + ((ushort)ch).ToString("X"));
dst[i] = (byte)lower;
}
}//for
}
[MenuItem, SubMenu("Data")]
public void SendObexPutInOnePacket()
{
if (!VerifyConnectionWrite())
return;
byte[] bufValid = {
/*PutFinal*/0x82, 0,41,
/*Name*/0x01, 0,19, 0,(byte)'a', 0,(byte)'a', 0,(byte)'a',
0,(byte)'.', 0,(byte)'t', 0,(byte)'x', 0,(byte)'t', 0,0,
/*EoB*/0x49, 0,19, 0,(byte)'a', 0,(byte)'a', 0,(byte)'a',
0,(byte)'.', 0,(byte)'t', 0,(byte)'x', 0,(byte)'t', 0,0
};
byte[] bufTruncatedInFront = {
/*PutFinal*/0x82, 0, // !!!!
};
byte[] bufTruncatedInRear = {
/*PutFinal*/0x82, 0,41,
/*Name*/0x01, 0,19, 0,(byte)'a', // !!!!!
};
byte[] bufTruncateBeforeFinal = {
/*Put-NON-Final*/0x02, 0,41,
/*Name*/0x01, 0,19, 0,(byte)'a', 0,(byte)'a', 0,(byte)'a',
0,(byte)'.', 0,(byte)'t', 0,(byte)'x', 0,(byte)'t', 0,0,
/*Body*/0x48, 0,19, 0,(byte)'a', 0,(byte)'a', 0,(byte)'a',
0,(byte)'.', 0,(byte)'t', 0,(byte)'x', 0,(byte)'t', 0,0
};
int? choice;
while (true) {
choice = console.ReadOptionalInteger(
"1. Complete (one packet), 2. Truncated in front, 3. Truncated in back, 4. Truncated before final packet");
if (!choice.HasValue || (choice.Value >= 1 && choice.Value <= 4))
break;
console.WriteLine("Invalid selection.");
}
byte[] buf;
switch (choice) {
case null:
case 1:
buf = bufValid;
break;
case 2:
buf = bufTruncatedInFront;
break;
case 3:
buf = bufTruncatedInRear;
break;
case 4:
buf = bufTruncateBeforeFinal;
break;
default:
throw new ArgumentException("Invalid selection: " + choice);
}
_peer.Write(buf, 0, buf.Length);
_peer.Flush(); // just in case
console.ReadLine("Waiting before closing the connection");
_peer.Close();
}
//----
[MenuItem, SubMenu("Device Discovery")]
public void AllDiscover()
{
BluetoothClient cli = Create_BluetoothClient();
DateTime startTime = DateTime.Now;
BluetoothDeviceInfo[] devices = cli.DiscoverDevices();
DateTime endTime = DateTime.Now;
DumpDeviceInfo(devices, startTime, endTime);
}
[MenuItem, SubMenu("Device Discovery")]
public void AllApmDiscover()
{
BluetoothClient cli = Create_BluetoothClient();
const int DefaultTimeout = 30;
TimeSpan? timeout = console.ReadTimeSecondsOptional("Set InquiryLength (default " + DefaultTimeout + "secs)");
if (timeout == null) {
timeout = TimeSpan.FromSeconds(DefaultTimeout);
}
cli.InquiryLength = timeout.Value;
EventHandler dlgt = delegate
{
DateTime startTime = DateTime.Now;
DiscoState1 state = new DiscoState1(cli, startTime);
IAsyncResult ar = cli.BeginDiscoverDevices(255,
true, true, true, false,
RestartDiscoCallback, state);
};
#if NETCF
bool fromUi = console.ReadYesNo("Start first discovery from UI thread?", false);
#else
bool fromUi = false;
#endif
if (fromUi) {
console.UiInvoke(dlgt);
} else {
dlgt(null, null);
}
//
console.Pause("Un-pause when discovery has completed");
}
class DiscoState1
{
public readonly BluetoothClient cli;
public readonly DateTime startTime;
public DiscoState1(BluetoothClient cli, DateTime startTime)
{
this.cli = cli;
this.startTime = startTime;
}
}
void SimpleDiscoCallback(IAsyncResult ar)
{
DiscoState1 state = (DiscoState1)ar.AsyncState;
try {
BluetoothDeviceInfo[] devices = state.cli.EndDiscoverDevices(ar);
DateTime endTime = DateTime.Now;
DumpDeviceInfoBrief(devices, state.startTime, endTime);
} catch (Exception ex) {
console.WriteLine("Discovery failed with: " + ex);
}
}
void RestartDiscoCallback(IAsyncResult ar)
{
SimpleDiscoCallback(ar);
bool startAgainInCallback = console.ReadYesNo("Start discovery again from callback", false);
if (startAgainInCallback) {
DiscoState1 state0 = (DiscoState1)ar.AsyncState;
DiscoState1 state = new DiscoState1(state0.cli, DateTime.Now);
IAsyncResult ar2 = state.cli.BeginDiscoverDevices(255,
true, true, true, false,
SimpleDiscoCallback, state);
}
}
[MenuItem, SubMenu("Device Discovery")]
public void ConcurrentlyTwoDiscoverApm()
{
var cli1 = Create_BluetoothClient();
var cli2 = Create_BluetoothClient();
IAsyncResult ar1 = cli1.BeginDiscoverDevices(255, true, true, true, false, null, null);
IAsyncResult ar2 = cli2.BeginDiscoverDevices(255, true, true, true, false, null, null);
console.WriteLine("Two started...");
bool signalled = _WaitAll(new WaitHandle[] { ar1.AsyncWaitHandle, ar2.AsyncWaitHandle }, 30 * 1000);
if (!signalled) {
console.WriteLine("Something horrible happened, at least one never/took too long to complete.");
} else {
var rslt1 = cli1.EndDiscoverDevices(ar1);
var rslt2 = cli2.EndDiscoverDevices(ar2);
console.WriteLine("They returned respectively: {0} and {1} devices.",
rslt1.Length, rslt2.Length);
}
}
[MenuItem, SubMenu("Device Discovery")]
public void _RememberedDiscover()
{
BluetoothClient cli = Create_BluetoothClient();
DateTime startTime = DateTime.Now;
BluetoothDeviceInfo[] devices = cli.DiscoverDevices(255, false, true, false);
DateTime endTime = DateTime.Now;
DumpDeviceInfo(devices, startTime, endTime);
}
[MenuItem, SubMenu("Device Discovery")]
public void _FlagsDiscover()
{
DiscoverFlags_(false);
}
[MenuItem, SubMenu("Device Discovery")]
void FlagsA_pmDiscover()
{
DiscoverFlags_(true);
}
private void GetDiscoveryFlags(MenuSystem console, out bool discoOnly, out bool auth, out bool rembd, out bool unk)
{
console.WriteLine("Discover which type of remote devices?");
discoOnly = console.ReadYesNo("discoverableOnly", false);
unk = console.ReadYesNo("Unknown", false);
rembd = console.ReadYesNo("Remembered", false);
auth = console.ReadYesNo("Authenticated", false);
}
public void DiscoverFlags_(bool @async)
{
BluetoothClient cli = Create_BluetoothClient();
bool discoOnly, auth, rembd, unk;
GetDiscoveryFlags(console, out discoOnly, out auth, out rembd, out unk);
BluetoothDeviceInfo[] devices;
//
TimeSpan? timeout = console.ReadTimeSecondsOptional("InquiryLength");
if (timeout != null) {
cli.InquiryLength = timeout.Value;
}
console.WriteLine("cli.InquiryLength is: {0}", cli.InquiryLength);
int? maxDevices = console.ReadOptionalInteger("maxDevices (default 255)");
if (maxDevices == null) maxDevices = 255;
console.WriteLine("maxDevices is: {0}", maxDevices);
//
DateTime startTime = DateTime.Now;
if (@async) {
bool doPause = console.ReadYesNo("Pause after BeginDD", false);
bool errorCallback = console.ReadYesNo("Throw an Error from the Callback", false);
AsyncCallback cb = errorCallback ? new AsyncCallback(ErrorFromMiscCallback) : MiscCallback;
IAsyncResult ar = cli.BeginDiscoverDevices(255, auth, rembd, unk, discoOnly,
cb, "BeginDiscoverDevices");
console.WriteLine("(BeginDiscoverDevices returned)");
if (doPause) console.Pause("Un-pause to continue to EndDD");
devices = cli.EndDiscoverDevices(ar);
} else {
devices = cli.DiscoverDevices(maxDevices.Value, auth, rembd, unk, discoOnly);
}
DateTime endTime = DateTime.Now;
DumpDeviceInfo(devices, startTime, endTime);
bool dispose = console.ReadYesNo("Dispose BtCli", true);
if (dispose && cli != null) {
cli.Dispose();
}
}
[MenuItem, SubMenu("Device Discovery")]
public void _RunAllFlagCombinations()
{
BluetoothClient cli = Create_BluetoothClient();
DateTime startTime = DateTime.Now;
bool discoOnly, authenticated, remembered, unknown;
int flagSource = 0;
while (true) {
authenticated = (flagSource & 1) != 0;
remembered = (flagSource & 2) != 0;
unknown = (flagSource & 4) != 0;
discoOnly = (flagSource & 8) != 0;
//
BluetoothDeviceInfo[] devices = cli.DiscoverDevices(255,
authenticated, remembered, unknown, discoOnly);
console.WriteLine("Got {0} results", devices.Length);
//
if (authenticated && remembered && unknown && discoOnly)
break; // Have tested all cases of the original four flags.
++flagSource;
Thread.Sleep(2000); // This sequence hangs on my W2k+Widcomm box -- does delaying help...?
}//while
//DateTime endTime = DateTime.Now;
//DumpDeviceInfo(devices, startTime, endTime);
console.WriteLine("All DiscoverDevices flag combinations run.");
}
const string vbCrLf = "\r\n";
void DumpDeviceInfo(BluetoothDeviceInfo[] devices,
DateTime startTime, DateTime endTime)
{
System.Text.StringBuilder sb = new System.Text.StringBuilder();
DateTime localTime = startTime.ToLocalTime();
sb.AppendFormat(System.Globalization.CultureInfo.InvariantCulture,
"Discovery process started at {0} UTC, {1} local, and ended at {2} UTC.",
startTime, localTime, endTime);
sb.Append(vbCrLf + vbCrLf);
console.WriteLine(sb.ToString());
foreach (BluetoothDeviceInfo curDevice in devices) {
sb.Length = 0;
DumpDeviceInfo(sb, curDevice);
console.WriteLine(sb.ToString());
}
}
void DumpDeviceInfoBrief(BluetoothDeviceInfo[] devices,
DateTime startTime, DateTime endTime)
{
System.Text.StringBuilder sb = new System.Text.StringBuilder();
DateTime localTime = startTime.ToLocalTime();
sb.AppendFormat(System.Globalization.CultureInfo.InvariantCulture,
"Discovery process started at {0} UTC, {1} local, and ended at {2} UTC.",
startTime, localTime, endTime);
console.WriteLine(sb.ToString());
foreach (BluetoothDeviceInfo curDevice in devices) {
sb.Length = 0;
DumpDeviceInfoBrief(sb, curDevice);
console.WriteLine(sb.ToString());
}
}
private static void DumpDeviceInfoBrief(StringBuilder sb, BluetoothDeviceInfo curDevice)
{
sb.AppendFormat(System.Globalization.CultureInfo.InvariantCulture,
"* {0}", ToStringQuotedOrNull(curDevice.DeviceName));
sb.AppendFormat(System.Globalization.CultureInfo.InvariantCulture,
", Address: {0}", curDevice.DeviceAddress);
}
private static string DumpDeviceInfoBrief(BluetoothDeviceInfo curDevice)
{
System.Text.StringBuilder sb = new StringBuilder();
DumpDeviceInfoBrief(sb, curDevice);
return sb.ToString();
}
private static void DumpDeviceInfo(System.Text.StringBuilder sb, BluetoothDeviceInfo curDevice)
{
sb.AppendFormat(System.Globalization.CultureInfo.InvariantCulture,
"* {0}", ToStringQuotedOrNull(curDevice.DeviceName));
sb.Append(vbCrLf);
sb.AppendFormat(System.Globalization.CultureInfo.InvariantCulture,
"Address: {0}", curDevice.DeviceAddress);
sb.Append(vbCrLf);
sb.AppendFormat(System.Globalization.CultureInfo.InvariantCulture,
"Remembered: {2}, Authenticated: {0}, Connected: {1}",
curDevice.Authenticated, curDevice.Connected, curDevice.Remembered);
sb.Append(vbCrLf);
sb.AppendFormat(System.Globalization.CultureInfo.InvariantCulture,
"LastSeen: {0} ({2}), LastUsed: {1} ({3})",
curDevice.LastSeen, curDevice.LastUsed,
curDevice.LastSeen.Kind, curDevice.LastUsed.Kind);
sb.Append(vbCrLf);
DumpCodInfo(curDevice.ClassOfDevice, sb);
Int32 rssi = curDevice.Rssi;
if (rssi != Int32.MinValue) {
sb.AppendFormat(System.Globalization.CultureInfo.InvariantCulture,
"Rssi: {0} (0x{0:X})", rssi);
} else {
sb.AppendFormat(System.Globalization.CultureInfo.InvariantCulture,
"Rssi: failed");
}
sb.Append(vbCrLf);
}
private static string DumpDeviceInfo(BluetoothDeviceInfo curDevice)
{
System.Text.StringBuilder sb = new StringBuilder();
DumpDeviceInfo(sb, curDevice);
return sb.ToString();
}
static void DumpCodInfo(ClassOfDevice cod, System.Text.StringBuilder sb)
{
sb.AppendFormat(System.Globalization.CultureInfo.InvariantCulture,
"CoD: (0x{0:X6})", cod.Value, cod);
sb.Append(vbCrLf);
sb.AppendFormat(System.Globalization.CultureInfo.InvariantCulture,
" Device: {0} (0x{1:X2}) / {2} (0x{3:X4})", cod.MajorDevice, (int)cod.MajorDevice, cod.Device, (int)cod.Device);
sb.Append(vbCrLf);
sb.AppendFormat(System.Globalization.CultureInfo.InvariantCulture,
" Service: {0} (0x{1:X2})", cod.Service, (int)cod.Service);
sb.Append(vbCrLf);
}
#if !NO_WINFORMS
[MenuItem, SubMenu("Device Discovery")]
public void UiDiscovery()
{
bool discoOnly, auth, rembd, unk;
GetDiscoveryFlags(console, out discoOnly, out auth, out rembd, out unk);
InTheHand.Windows.Forms.SelectBluetoothDeviceDialog dlg = new InTheHand.Windows.Forms.SelectBluetoothDeviceDialog();
dlg.ShowAuthenticated = auth;
dlg.ShowRemembered = rembd;
dlg.ShowUnknown = unk;
dlg.ShowDiscoverableOnly = discoOnly;
if (console.ReadYesNo("set filter (always returns true)", false)) {
dlg.DeviceFilter = FilterDevice;
if (console.ReadYesNo("set filter to null now(!)", false)) {
dlg.DeviceFilter = null;
}
}
System.Windows.Forms.DialogResult rslt = System.Windows.Forms.DialogResult.None;
EventHandler action = delegate
{
rslt = dlg.ShowDialog();
};
console.UiInvoke(action);
console.WriteLine("DialogResult: {0}, Selected: {1}", rslt,
dlg.SelectedDevice == null ? "(null)" : ("'" + dlg.SelectedDevice.DeviceName + "' " + dlg.SelectedDevice.DeviceAddress.ToString("C")));
}
void X()
{
var dlg = new InTheHand.Windows.Forms.SelectBluetoothDeviceDialog();
dlg.DeviceFilter = FilterDevice;
var rslt = dlg.ShowDialog();
//......
}
bool FilterDevice(BluetoothDeviceInfo dev)
{
var ret = true;
ret = console.ReadYesNo("Include this device " + dev.DeviceAddress + " " + dev.DeviceName, ret);
return ret;
}
#endif
//----
#if TEST_EARLY
[MenuItem, SubMenu("SDP")]
public void HackServiceDiscovery()
{
BluetoothAddress addr = console.ReadBluetoothAddress("SDP server BluetoothAddress");
try {
BluetoothClient cli0 = new BluetoothClient();
// Don't dispose this to check its Finalization.
InTheHand.Net.Bluetooth.Widcomm.ISdpDiscoveryRecordsBuffer recs
= cli0.WidcommHack__GetServiceRecordsUnparsed(addr, BluetoothService.L2CapProtocol);
console.WriteLine("recordCount: {0}", recs.RecordCount);
//
int[] ports = recs.Hack_GetPorts();
#if !NETCF
string[] txtArr = Array.ConvertAll<int, string>(ports,
delegate(int cur) { return cur.ToString(); });
#else
string[] txtArr = new string[ports.Length];
for (int i = 0; i < ports.Length; ++i)
txtArr[i] = ports[i].ToString();
#endif
string txt = string.Join(", ", txtArr);
console.WriteLine("Ports: {0}", txt);
//
ServiceRecord[] recordArr = recs.GetServiceRecords();
foreach (ServiceRecord cur in recordArr) {
console.WriteLine(
ServiceRecordUtilities.Dump(cur));
}
} catch (Exception ex) {
console.WriteLine(ex);
}
}
#endif
[MenuItem, SubMenu("SDP")]
public void Sdp_Query()
{
SdpQuery_();
}
void SdpQuery_()
{
BluetoothAddress addr = console.ReadBluetoothAddress("SDP server BluetoothAddress");
Guid? svcClass1 = console.ReadOptionalBluetoothUuid("Search UUID (default L2CAP->all)", null);
if (svcClass1 == null) {
svcClass1 = BluetoothService.L2CapProtocol;
}
#if FX4
bool taskAsync = console.ReadYesNo("Task-Async Get", false);
#else
bool taskAsync = false;
#endif
bool @async = taskAsync ? false : console.ReadYesNo("Async Get", false);
//
BluetoothDeviceInfo bdi = Create_BluetoothDeviceInfo(addr);
ServiceRecord[] recordArr;
var svcClassList = new List<Guid> { (Guid)svcClass1 };
var foo = false;
if (foo) {
var from = 0x1000;
var to = 0x1100;
svcClassList.Clear();
for (int cur = from; cur <= to; ++cur) {
svcClassList.Add(BluetoothService.CreateBluetoothUuid(cur));
}
}
foreach (var svcClass in svcClassList) {
string target = string.Format(CultureInfo.InvariantCulture,
"{0} on {1}", (Guid)svcClass, bdi.DeviceAddress);
if (taskAsync) {
#if FX4
var task = bdi.GetServiceRecordsAsync((Guid)svcClass, "GetServiceRecordsAsync");
task.ContinueWith(MiscCallback);
console.WriteLine("(GetServiceRecordsAsync returned)");
console.Pause("Un-pause when should continue to get Result");
recordArr = task.Result;
task.Wait();
#else
throw new NotSupportedException("Task is FX4");
#endif
} else if (@async) {
console.WriteLine("Calling BeginGetServiceRecords for " + target);
IAsyncResult ar = bdi.BeginGetServiceRecords((Guid)svcClass,
MiscCallback, "BeginGetServiceRecords");
console.WriteLine("BeginGetServiceRecords returned");
console.Pause("Un-pause when should continue to EndGetServiceRecords");
recordArr = bdi.EndGetServiceRecords(ar);
} else {
console.WriteLine("Calling GetServiceRecords for " + target);
recordArr = bdi.GetServiceRecords((Guid)svcClass);
}
//
SdpRecordDump(recordArr);
}
}
private void SdpRecordDump(ICollection<ServiceRecord> recordArr)
{
console.WriteLine("recordCount: {0}", recordArr.Count);
int i = 1;
foreach (ServiceRecord cur in recordArr) {
console.WriteLine("{0})", i);
try {
console.WriteLine(
ServiceRecordUtilities.Dump(cur));
} catch (Exception ex) {
console.WriteLine("Error in Dump, trying DumpRaw ({0})", ex);
console.WriteLine(
ServiceRecordUtilities.DumpRaw(cur));
}
console.WriteLine("----");
++i;
}
}
[MenuItem, SubMenu("SDP")]
public void SdpQuery_Repeatedly()
{
BluetoothAddress addr = console.ReadBluetoothAddress("SDP server BluetoothAddress");
Guid? svcClass = console.ReadOptionalBluetoothUuid("Search UUID (default L2CAP->all)", null);
if (svcClass == null) {
svcClass = BluetoothService.L2CapProtocol;
}
//
BluetoothDeviceInfo bdi = Create_BluetoothDeviceInfo(addr);
string target = string.Format(CultureInfo.InvariantCulture,
"{0} on {1}", (Guid)svcClass, bdi.DeviceAddress);
int InterDelay = 500;
//
MyAction startQuery = null;
bool stop = false;
AsyncCallback _Callback = delegate(IAsyncResult ar)
{
try {
bdi.EndGetServiceRecords(ar);
console.Write("|");
Thread.Sleep(InterDelay);
if (stop) {
console.WriteLine("]");
} else {
startQuery();
}
} catch (Exception ex) {
console.WriteLine(ex);
}
};
startQuery = delegate
{
bdi.BeginGetServiceRecords((Guid)svcClass,
_Callback, null);
console.Write("-");
};
//
console.WriteLine("Calling first BeginGetServiceRecords for " + target);
while (true) {
stop = false;
startQuery();
console.Pause("When to stop");
stop = true;
var startAgain = console.ReadYesNo("Start again?", false);
if (!startAgain) {
break;
}
}
}
[MenuItem, SubMenu("SDP")]
public void SdpQuery_Concurrent()
{
BluetoothAddress addrA = console.ReadBluetoothAddress("SDP server BluetoothAddress");
BluetoothAddress addrB;
var another = console.ReadYesNoCancel("Different device | dupl. DBI | same BDI", null);
BluetoothDeviceInfo bdiA = Create_BluetoothDeviceInfo(addrA);
BluetoothDeviceInfo bdiB;
if (another == true) {
console.Write("Another target. ");
addrB = console.ReadBluetoothAddress("SDP server BluetoothAddress");
bdiB = Create_BluetoothDeviceInfo(addrB);
} else if (another == false) {
console.Write("Dupl.BDI. ");
bdiB = Create_BluetoothDeviceInfo(addrA);
} else {
console.Write("Same BDI. ");
bdiB = bdiA;
}
//
Guid? svcClass = console.ReadOptionalBluetoothUuid("Search UUID (default L2CAP->all)", null);
if (svcClass == null) {
svcClass = BluetoothService.L2CapProtocol;
}
//
string target = string.Format(CultureInfo.InvariantCulture,
"{0} on {1} and {2}", (Guid)svcClass, bdiA.DeviceAddress, bdiB.DeviceAddress);
console.WriteLine(target);
//
bool repeat;
do {
console.Write("Starting...");
IAsyncResult arA, arB;
try {
arA = bdiA.BeginGetServiceRecords(svcClass.Value, MiscCallback, "A");
} catch (Exception ex) {
arA = null;
console.WriteLine("A @Begin " + " ex: " + ex);
}
try {
arB = bdiB.BeginGetServiceRecords(svcClass.Value, MiscCallback, "B");
} catch (Exception ex) {
arB = null;
console.WriteLine("B @Begin " + " ex: " + ex);
}
console.Pause("when complete");
MyFunc<IAsyncResult, string> doGetIsCompleted = delegate(IAsyncResult arX)
{
if (arX == null) return "NULL";
return arX.IsCompleted.ToString();
};
console.WriteLine("IsCompleted: A: {0}, B: {1}",
doGetIsCompleted(arA), doGetIsCompleted(arB));
//--
MyAction<string, BluetoothDeviceInfo, IAsyncResult> doComplete
= delegate(string name, BluetoothDeviceInfo devX, IAsyncResult arX)
{
ServiceRecord[] rs;
try {
rs = devX.EndGetServiceRecords(arX);
console.WriteLine(name + " #r: " + rs.Length);
} catch (Exception ex) {
console.WriteLine(name + " ex: " + ex);
}
};
// Complete if they started
if (arA != null) {
doComplete("A", bdiA, arA);
}
if (arB != null) {
doComplete("B", bdiB, arB);
}
//
repeat = console.ReadYesNo("Do again on same BDIs?", false);
} while (repeat);
}
delegate void MyAction();
delegate void MyAction<T0>(T0 p0);
delegate void MyAction<T0, T1>(T0 p0, T1 p1);
delegate void MyAction<T0, T1, T2>(T0 p0, T1 p1, T2 p2);
[MenuItem, SubMenu("SDP")]
public void SdpCreateCustom()
{
ServiceRecord record = CreateAVariousRecord();
BluetoothListener lsnr = Create_BluetoothListener(BluetoothService.HealthDeviceSink,
record);
lsnr.Start();
console.Pause("Un-pause to stop the server");
lsnr.Stop();
}
#if false
[MenuItem, SubMenu("SDP")]
public void SdpCreateCustomSimpleElements_Btps()
{
ServiceRecord record = CreateAVariousRecordWithSimpleElements();
//
var c = InTheHand.Net.Bluetooth.StonestreetOne
.BluetopiaSdpCreator.CreateTestable();
c.CreateServiceRecord(record);
console.Pause("Un-pause to stop the server");
c.DeleteServiceRecord();
}
[MenuItem, SubMenu("SDP")]
public void SdpCreateCustom_Btps()
{
ServiceRecord record = CreateAVariousRecord();
//
var c = InTheHand.Net.Bluetooth.StonestreetOne
.BluetopiaSdpCreator.CreateTestable();
c.CreateServiceRecord(record);
console.Pause("Un-pause to stop the server");
c.DeleteServiceRecord();
}
#endif
private static ServiceRecord CreateAVariousRecord()
{
MyFunc<ElementType, ServiceAttributeId> createId = delegate(ElementType etX)
{
return (ServiceAttributeId)0x4000 + checked((byte)etX);
};
ServiceRecordBuilder bldr = new ServiceRecordBuilder();
bldr.AddServiceClass(BluetoothService.HealthDevice);
var longquotes = false;
if (longquotes) {
bldr.ServiceName = new string('"', 40);
// cmd> sdptool search --bdaddr 00:0a:3a:68:65:bb --xml ftp
bldr.AddServiceClass(BluetoothService.ObexFileTransfer);
} else {
bldr.ServiceName = "alan";
}
IList<ServiceAttribute> attrList = new List<ServiceAttribute>();
ElementType et_;
CreateVariousSimpleElements(createId, attrList);
et_ = ElementType.Uuid16;
attrList.Add(new ServiceAttribute(createId(et_),
new ServiceElement(et_, (UInt16)et_)));
et_ = ElementType.Uuid32;
attrList.Add(new ServiceAttribute(createId(et_),
new ServiceElement(et_, (UInt32)et_)));
et_ = ElementType.Uuid128;
attrList.Add(new ServiceAttribute(createId(et_),
new ServiceElement(et_, BluetoothService.CreateBluetoothUuid((int)et_))));
bldr.AddCustomAttributes(attrList);
bldr.AddCustomAttributes(ElementsAndVariableAndFixedInDeepTree1());
ServiceRecord record = bldr.ServiceRecord;
return record;
}
private static ServiceRecord CreateAVariousRecordWithSimpleElements()
{
MyFunc<ElementType, ServiceAttributeId> createId = delegate(ElementType etX)
{
return (ServiceAttributeId)0x4000 + checked((byte)etX);
};
ServiceRecordBuilder bldr = new ServiceRecordBuilder();
bldr.AddServiceClass(BluetoothService.HealthDevice); // not optional :-(
IList<ServiceAttribute> attrList = new List<ServiceAttribute>();
CreateVariousSimpleElements(createId, attrList);
bldr.AddCustomAttributes(attrList);
ServiceRecord record = bldr.ServiceRecord;
return record;
}
private static void CreateVariousSimpleElements(MyFunc<ElementType, ServiceAttributeId> createId,
IList<ServiceAttribute> attrList)
{
ElementType et_;
#if SUPPORT_NIL
et_ = ElementType.Nil;
attrList.Add(new ServiceAttribute(createId(et_), new ServiceElement(et_, null)));
#endif
et_ = ElementType.Boolean;
attrList.Add(new ServiceAttribute(createId(et_), new ServiceElement(et_, true)));
ElementType[] weee = {
ElementType.UInt8, ElementType.UInt16, ElementType.UInt32, ElementType.UInt64, //UInt128,
ElementType.Int8, ElementType.Int16, ElementType.Int32, ElementType.Int64, //Int128,
};
foreach (ElementType et in weee) {
attrList.Add(new ServiceAttribute(
createId(et),
ServiceElement.CreateNumericalServiceElement(et, (uint)et)));
}
}
public const String RecordBytes_OneString_StringValue = "abcd\u00e9fgh\u012dj";
public static IList<ServiceAttribute> ElementsAndVariableAndFixedInDeepTree1()
{
IList<ServiceAttribute> attrs = new List<ServiceAttribute>();
//
String str = RecordBytes_OneString_StringValue;
ServiceElement itemStr1 = new ServiceElement(ElementType.TextString, str);
ServiceElement itemStr2 = new ServiceElement(ElementType.TextString, str);
//
Uri uri = new Uri("http://example.com/foo.txt");
ServiceElement itemUrl = new ServiceElement(ElementType.Url, uri);
//
ServiceElement itemF1 = new ServiceElement(ElementType.UInt16, (UInt16)0xfe12);
ServiceElement itemF2 = new ServiceElement(ElementType.UInt16, (UInt16)0x1234);
//
IList<ServiceElement> leaves2 = new List<ServiceElement>();
leaves2.Add(itemStr1);
leaves2.Add(itemUrl);
leaves2.Add(itemF1);
ServiceElement e2 = new ServiceElement(ElementType.ElementSequence, leaves2);
//
ServiceElement e1 = new ServiceElement(ElementType.ElementSequence, e2);
//
IList<ServiceElement> leaves0 = new List<ServiceElement>();
leaves0.Add(e1);
leaves0.Add(itemStr2);
leaves0.Add(itemF2);
attrs.Add(
new ServiceAttribute(0x0401, new ServiceElement(ElementType.ElementAlternative,
leaves0)));
return attrs;
}
[MenuItem, SubMenu("SDP")]
public void SdpCreateHidAndPnpRecords()
{
ServiceRecord record = CreateAHumanInputDeviceRecord();
BluetoothListener lsnr = Create_BluetoothListener(BluetoothService.HealthDeviceSink,
record);
ServiceRecord record2 = CreateAHumanInputDeviceRecordB();
BluetoothListener lsnr2 = Create_BluetoothListener(BluetoothService.HealthDeviceSink,
record2);
ServiceRecord record3 = CreateAPnpRecord();
BluetoothListener lsnr3 = Create_BluetoothListener(BluetoothService.HealthDeviceSink,
record3);
lsnr.Start();
lsnr2.Start();
lsnr3.Start();
console.Pause("Un-pause to stop the server");
lsnr.Stop();
lsnr2.Stop();
lsnr3.Stop();
}
[MenuItem, SubMenu("SDP")]
public void SdpCreatePnpRecord()
{
ServiceRecord record = CreateAPnpRecord();
BluetoothListener lsnr = Create_BluetoothListener(BluetoothService.HealthDeviceSink,
record);
lsnr.Start();
console.Pause("Un-pause to stop the server");
lsnr.Stop();
}
private ServiceRecord CreateAPnpRecord()
{
ServiceRecordBuilder bldr = new ServiceRecordBuilder();
// Listener needs this. :-(
bldr.ProtocolType = BluetoothProtocolDescriptorType.GeneralObex;
bldr.AddServiceClass(BluetoothService.PnPInformation);
bldr.AddCustomAttribute(new ServiceAttribute(DeviceIdProfileAttributeId.SpecificationId,
ServiceElement.CreateNumericalServiceElement(ElementType.UInt16, 1)));
bldr.AddCustomAttribute(new ServiceAttribute(DeviceIdProfileAttributeId.VendorId,
ServiceElement.CreateNumericalServiceElement(ElementType.UInt16, 2)));
bldr.AddCustomAttribute(new ServiceAttribute(DeviceIdProfileAttributeId.ProductId,
ServiceElement.CreateNumericalServiceElement(ElementType.UInt16, 3)));
bldr.AddCustomAttribute(new ServiceAttribute(DeviceIdProfileAttributeId.Version,
ServiceElement.CreateNumericalServiceElement(ElementType.UInt16, 4)));
bldr.AddCustomAttribute(new ServiceAttribute(DeviceIdProfileAttributeId.PrimaryRecord,
new ServiceElement(ElementType.Boolean, true)));
bldr.AddCustomAttribute(new ServiceAttribute(DeviceIdProfileAttributeId.VendorIdSource,
ServiceElement.CreateNumericalServiceElement(ElementType.UInt16, 6)));
return bldr.ServiceRecord;
}
[MenuItem, SubMenu("SDP")]
public void SdpCreateHumanInputDeviceRecord()
{
ServiceRecord record = CreateAHumanInputDeviceRecord();
BluetoothListener lsnr = Create_BluetoothListener(BluetoothService.HealthDeviceSink,
record);
ServiceRecord record2 = CreateAHumanInputDeviceRecordB();
BluetoothListener lsnr2 = Create_BluetoothListener(BluetoothService.HealthDeviceSink,
record2);
lsnr.Start();
lsnr2.Start();
console.Pause("Un-pause to stop the servers");
lsnr.Stop();
lsnr2.Stop();
}
private ServiceRecord CreateAHumanInputDeviceRecord()
{
ServiceRecordBuilder bldr = new ServiceRecordBuilder();
// Listener needs this. :-(
bldr.ProtocolType = BluetoothProtocolDescriptorType.GeneralObex;
bldr.AddServiceClass(BluetoothService.HumanInterfaceDevice);
bldr.AddCustomAttribute(new ServiceAttribute(HidProfileAttributeId.DeviceReleaseNumber,
ServiceElement.CreateNumericalServiceElement(ElementType.UInt16, 0x1000)));
bldr.AddCustomAttribute(new ServiceAttribute(HidProfileAttributeId.ParserVersion,
ServiceElement.CreateNumericalServiceElement(ElementType.UInt16, 1)));
bldr.AddCustomAttribute(new ServiceAttribute(HidProfileAttributeId.DeviceSubclass,
ServiceElement.CreateNumericalServiceElement(ElementType.UInt8, 2)));
bldr.AddCustomAttribute(new ServiceAttribute(HidProfileAttributeId.CountryCode,
ServiceElement.CreateNumericalServiceElement(ElementType.UInt8, 3)));
bldr.AddCustomAttribute(new ServiceAttribute(HidProfileAttributeId.VirtualCable,
ServiceElement.CreateNumericalServiceElement(ElementType.UInt8, 4)));
bldr.AddCustomAttribute(new ServiceAttribute(HidProfileAttributeId.ReconnectInitiate,
ServiceElement.CreateNumericalServiceElement(ElementType.UInt8, 5)));
//bldr.AddCustomAttribute(new ServiceAttribute(HidProfileAttributeId.DescriptorList,
// new ServiceElement(ElementType.ElementSequence,
// ServiceElement.CreateNumericalServiceElement(ElementType.UInt8, 6))));
//bldr.AddCustomAttribute(new ServiceAttribute(HidProfileAttributeId.LangIdBaseList,
// new ServiceElement(ElementType.ElementSequence,
// ServiceElement.CreateNumericalServiceElement(ElementType.UInt8, 7))));
bldr.AddCustomAttribute(new ServiceAttribute(HidProfileAttributeId.SdpDisable,
ServiceElement.CreateNumericalServiceElement(ElementType.UInt8, 8)));
bldr.AddCustomAttribute(new ServiceAttribute(HidProfileAttributeId.BatteryPower,
ServiceElement.CreateNumericalServiceElement(ElementType.UInt8, 9)));
bldr.AddCustomAttribute(new ServiceAttribute(HidProfileAttributeId.RemoteWake,
ServiceElement.CreateNumericalServiceElement(ElementType.UInt8, 10)));
bldr.AddCustomAttribute(new ServiceAttribute(HidProfileAttributeId.BootDevice,
ServiceElement.CreateNumericalServiceElement(ElementType.UInt8, 14)));
bldr.AddCustomAttribute(new ServiceAttribute(HidProfileAttributeId.SupervisionTimeout,
ServiceElement.CreateNumericalServiceElement(ElementType.UInt8, 12)));
bldr.AddCustomAttribute(new ServiceAttribute(HidProfileAttributeId.NormallyConnectable,
ServiceElement.CreateNumericalServiceElement(ElementType.UInt8, 13)));
bldr.AddCustomAttribute(new ServiceAttribute(HidProfileAttributeId.ProfileVersion,
ServiceElement.CreateNumericalServiceElement(ElementType.UInt8, 11)));
return bldr.ServiceRecord;
}
private ServiceRecord CreateAHumanInputDeviceRecordB()
{
ServiceRecordBuilder bldr = new ServiceRecordBuilder();
// Listener needs this. :-(
bldr.ProtocolType = BluetoothProtocolDescriptorType.GeneralObex;
bldr.AddServiceClass(BluetoothService.HumanInterfaceDevice);
bldr.AddCustomAttribute(new ServiceAttribute(HidProfileAttributeId.DeviceReleaseNumber,
ServiceElement.CreateNumericalServiceElement(ElementType.UInt16, 0x1FFF)));
bldr.AddCustomAttribute(new ServiceAttribute(HidProfileAttributeId.ParserVersion,
ServiceElement.CreateNumericalServiceElement(ElementType.UInt16, 0xFF1F)));
bldr.AddCustomAttribute(new ServiceAttribute(HidProfileAttributeId.DeviceSubclass,
ServiceElement.CreateNumericalServiceElement(ElementType.UInt8, 0x2F)));
bldr.AddCustomAttribute(new ServiceAttribute(HidProfileAttributeId.CountryCode,
ServiceElement.CreateNumericalServiceElement(ElementType.UInt8, 0x3F)));
bldr.AddCustomAttribute(new ServiceAttribute(HidProfileAttributeId.VirtualCable,
ServiceElement.CreateNumericalServiceElement(ElementType.UInt8, 0x4F)));
bldr.AddCustomAttribute(new ServiceAttribute(HidProfileAttributeId.ReconnectInitiate,
ServiceElement.CreateNumericalServiceElement(ElementType.UInt8, 0x5F)));
//bldr.AddCustomAttribute(new ServiceAttribute(HidProfileAttributeId.DescriptorList,
// new ServiceElement(ElementType.ElementSequence,
// ServiceElement.CreateNumericalServiceElement(ElementType.UInt8, 6))));
//bldr.AddCustomAttribute(new ServiceAttribute(HidProfileAttributeId.LangIdBaseList,
// new ServiceElement(ElementType.ElementSequence,
// ServiceElement.CreateNumericalServiceElement(ElementType.UInt8, 7))));
bldr.AddCustomAttribute(new ServiceAttribute(HidProfileAttributeId.SdpDisable,
ServiceElement.CreateNumericalServiceElement(ElementType.UInt8, 0x8F)));
bldr.AddCustomAttribute(new ServiceAttribute(HidProfileAttributeId.BatteryPower,
ServiceElement.CreateNumericalServiceElement(ElementType.UInt8, 0x9F)));
bldr.AddCustomAttribute(new ServiceAttribute(HidProfileAttributeId.RemoteWake,
ServiceElement.CreateNumericalServiceElement(ElementType.UInt8, 0x1F)));
bldr.AddCustomAttribute(new ServiceAttribute(HidProfileAttributeId.BootDevice,
ServiceElement.CreateNumericalServiceElement(ElementType.UInt8, 14)));
bldr.AddCustomAttribute(new ServiceAttribute(HidProfileAttributeId.SupervisionTimeout,
ServiceElement.CreateNumericalServiceElement(ElementType.UInt8, 12)));
bldr.AddCustomAttribute(new ServiceAttribute(HidProfileAttributeId.NormallyConnectable,
ServiceElement.CreateNumericalServiceElement(ElementType.UInt8, 13)));
bldr.AddCustomAttribute(new ServiceAttribute(HidProfileAttributeId.ProfileVersion,
ServiceElement.CreateNumericalServiceElement(ElementType.UInt8, 11)));
return bldr.ServiceRecord;
}
[MenuItem, SubMenu("SDP")]
private void SdpCreateAHumanInputDeviceRecordsAllTwoOfThree()
{
var create = new Converter<object, ServiceRecordBuilder>(delegate
{
ServiceRecordBuilder bldrF = new ServiceRecordBuilder();
// Listener needs this. :-(
bldrF.ProtocolType = BluetoothProtocolDescriptorType.GeneralObex;
bldrF.AddServiceClass(BluetoothService.HumanInterfaceDevice);
return bldrF;
});
var attrA = new Action<ServiceRecordBuilder>(delegate(ServiceRecordBuilder bldrF)
{
bldrF.AddCustomAttribute(new ServiceAttribute(HidProfileAttributeId.DeviceReleaseNumber,
ServiceElement.CreateNumericalServiceElement(ElementType.UInt16, 0x1FFF)));
});
var attrC = new Action<ServiceRecordBuilder>(delegate(ServiceRecordBuilder bldrF)
{
bldrF.AddCustomAttribute(new ServiceAttribute(HidProfileAttributeId.DeviceSubclass,
ServiceElement.CreateNumericalServiceElement(ElementType.UInt8, 0x2F)));
});
var attrB = new Action<ServiceRecordBuilder>(delegate(ServiceRecordBuilder bldrF)
{
bldrF.AddCustomAttribute(new ServiceAttribute(HidProfileAttributeId.CountryCode,
ServiceElement.CreateNumericalServiceElement(ElementType.UInt8, 0x3F)));
});
//
ServiceRecordBuilder bldr;
bldr = create(null);
attrA(bldr);
attrB(bldr);
BluetoothListener lsnr = Create_BluetoothListener(BluetoothService.HealthDeviceSink,
bldr.ServiceRecord);
bldr = create(null);
attrA(bldr);
attrC(bldr);
BluetoothListener lsnr2 = Create_BluetoothListener(BluetoothService.HealthDeviceSink,
bldr.ServiceRecord);
bldr = create(null);
attrB(bldr);
attrC(bldr);
BluetoothListener lsnr3 = Create_BluetoothListener(BluetoothService.HealthDeviceSink,
bldr.ServiceRecord);
//
lsnr.Start();
lsnr2.Start();
lsnr3.Start();
console.Pause("Un-pause to stop the server");
lsnr.Stop();
lsnr2.Stop();
lsnr3.Stop();
}
[MenuItem, SubMenu("SDP")]
public void SdpCreateTwoSppRecordsOneWithAvailAndBrowse()
{
var bldr = new ServiceRecordBuilder();
bldr.AddServiceClass(BluetoothService.WapClient);
bldr.AddCustomAttribute(new ServiceAttribute(
UniversalAttributeId.ServiceAvailability,
ServiceElement.CreateNumericalServiceElement(ElementType.UInt8, 255)));
bldr.AddCustomAttribute(new ServiceAttribute(
UniversalAttributeId.BrowseGroupList,
new ServiceElement(ElementType.ElementSequence,
new ServiceElement(ElementType.Uuid128, BluetoothService.PublicBrowseGroup))));
var sr = bldr.ServiceRecord;
//DEBUGconsole.Write(ServiceRecordUtilities.Dump(sr));
var lsnr = Create_BluetoothListener(
new BluetoothEndPoint(BluetoothAddress.None, BluetoothService.SerialPort, 22),
sr);
var lsnr2 = Create_BluetoothListener(
new Guid("{E665C159-4721-4e73-8E97-9A8BE42423D9}"));
//
lsnr.Start();
lsnr2.Start();
console.Pause("Un-pause to stop the server");
lsnr.Stop();
lsnr2.Stop();
}
[MenuItem, SubMenu("SDP")]
public void SdpCreateAndDumpAnAvcrpRecord()
{
ServiceRecord record = CreateAnAvcrpCtRecord();
//
string dump = ServiceRecordUtilities.Dump(record);
console.WriteLine(dump);
}
internal static ServiceRecord CreateAnAvcrpCtRecord()
{
//const UInt16 SvcClass16Avcrp = 0x110E;
const UInt16 SvcClass16AvcrpController_ = 0x110F;
Guid SvcClass128AvcrpController = BluetoothService.CreateBluetoothUuid(SvcClass16AvcrpController_);
//
const UInt16 SvcClass16ProtocolL2CAP = 0x0100;
Debug_Assert_CorrectShortUuid(SvcClass16ProtocolL2CAP, BluetoothService.L2CapProtocol);
const UInt16 SvcClass16ProtocolAvctp = 0x0017;
Debug_Assert_CorrectShortUuid(SvcClass16ProtocolAvctp, BluetoothService.AvctpProtocol);
//
const UInt16 PsmAvcrp = 0x0017;
const UInt16 PsmAvcrpBrowsing = 0x001B;
//
const UInt16 Version = 0x0103; // 1.3.......
//
var layer0 = new ServiceElement(ElementType.ElementSequence,
new ServiceElement(ElementType.Uuid16, SvcClass16ProtocolL2CAP),
new ServiceElement(ElementType.UInt16, PsmAvcrp));
var layer1 = new ServiceElement(ElementType.ElementSequence,
new ServiceElement(ElementType.Uuid16, SvcClass16ProtocolAvctp),
new ServiceElement(ElementType.UInt16, Version));
ServiceElement pdl = new ServiceElement(ElementType.ElementSequence,
layer0, layer1);
//
var apdlLayer0 = new ServiceElement(ElementType.ElementSequence,
new ServiceElement(ElementType.Uuid16, SvcClass16ProtocolL2CAP),
new ServiceElement(ElementType.UInt16, PsmAvcrpBrowsing));
var apdlLayer1 = new ServiceElement(ElementType.ElementSequence,
new ServiceElement(ElementType.Uuid16, SvcClass16ProtocolAvctp),
new ServiceElement(ElementType.UInt16, Version));
ServiceElement additionalPdlSubList0 = new ServiceElement(ElementType.ElementSequence,
apdlLayer0, apdlLayer1);
ServiceElement additionalPdl = new ServiceElement(ElementType.ElementSequence,
additionalPdlSubList0);
//
ServiceRecordBuilder bldr = new ServiceRecordBuilder();
bldr.AddServiceClass(BluetoothService.AVRemoteControl);
bldr.AddServiceClass(SvcClass128AvcrpController);
//
bldr.ProtocolType = BluetoothProtocolDescriptorType.None;
bldr.AddCustomAttributes(
new ServiceAttribute(UniversalAttributeId.ProtocolDescriptorList, pdl),
new ServiceAttribute(UniversalAttributeId.AdditionalProtocolDescriptorLists,
additionalPdl));
//
bldr.AddBluetoothProfileDescriptor(BluetoothService.AVRemoteControl, 1, 4);
//
bldr.AddCustomAttribute(new ServiceAttribute(HandsFreeProfileAttributeId.SupportedFeatures,
ServiceElement.CreateNumericalServiceElement(ElementType.UInt16,
(int)(AvcrpSupportedFeatures.Category1 | AvcrpSupportedFeatures.Category2)
)));
//
bldr.ProviderName = "alanjmcf!!!!!!";
bldr.ServiceName = "avcrp tc!!!!!!";
return bldr.ServiceRecord;
}
[Conditional("DEBUG")]
private static void Debug_Assert_CorrectShortUuid(UInt16 svcClass16, Guid svcClass)
{
Debug.Assert(svcClass.Equals(BluetoothService.CreateBluetoothUuid(svcClass16)),
"Wrong integer value 0x" + svcClass16.ToString("X4") + ", extracted from: " + svcClass);
}
[Conditional("DEBUG")]
private static void Debug_Assert_CorrectShortUuid(UInt32 svcClass32, Guid svcClass)
{
Debug.Assert(svcClass.Equals(BluetoothService.CreateBluetoothUuid(svcClass32)),
"Wrong integer value 0x" + svcClass32.ToString("X8") + ", extracted from: " + svcClass);
}
[Flags]
enum AvcrpSupportedFeatures : ushort
{
/// <summary>
/// Category 1
/// </summary>
Category1 = 0x01,
/// <summary>
/// Category 2
/// </summary>
Category2 = 0x02,
/// <summary>
/// Category 3
/// </summary>
Category3 = 0x04,
/// <summary>
/// Category 4
/// </summary>
Category4 = 0x08,
/// <summary>
/// Player Application Settings
/// </summary>
/// -
/// <remarks>"Bit 0 should be set for this bit to be set."
/// </remarks>
PlayerApplicationSettings = 0x10,
/// <summary>
/// Group Navigation
/// </summary>
/// -
/// <remarks>"Bit 0 should be set for this bit to be set."
/// </remarks>
GroupNavigation = 0x20,
/// <summary>
/// Supports Browsing
/// </summary>
SupportsBrowsing = 0x40,
/// <summary>
/// Supports multiple media player applications
/// </summary>
SupportsMultipleMediaPlayerApplications = 0x20,
// RFA
}
internal static ServiceRecord CreateAnAvcrpCtRecord_GuidForUuid16()
{
//Guid SvcClass128Avcrp = /*0x110E*/BluetoothService.AVRemoteControl;
const UInt16 _SvcClass16AvcrpController = 0x110F;
Guid SvcClass128AvcrpController = BluetoothService.CreateBluetoothUuid(_SvcClass16AvcrpController);
//
Guid SvcClass128ProtocolL2CAP = /*0x0100*/BluetoothService.L2CapProtocol;
Guid SvcClass128ProtocolAvctp = /*0x0017*/BluetoothService.AvctpProtocol;
//
const UInt16 PsmAvcrp = 0x0017;
const UInt16 PsmAvcrpBrowsing = 0x001B;
//
const UInt16 Version = 0x0103; // 1.3.......
//
var layer0 = new ServiceElement(ElementType.ElementSequence,
new ServiceElement(ElementType.Uuid16, GetBluetoothUuid16(SvcClass128ProtocolL2CAP)),
new ServiceElement(ElementType.UInt16, PsmAvcrp));
var layer1 = new ServiceElement(ElementType.ElementSequence,
new ServiceElement(ElementType.Uuid16, GetBluetoothUuid16(SvcClass128ProtocolAvctp)),
new ServiceElement(ElementType.UInt16, Version));
ServiceElement pdl = new ServiceElement(ElementType.ElementSequence,
layer0, layer1);
//
var apdlLayer0 = new ServiceElement(ElementType.ElementSequence,
new ServiceElement(ElementType.Uuid16, GetBluetoothUuid16(SvcClass128ProtocolL2CAP)),
new ServiceElement(ElementType.UInt16, PsmAvcrpBrowsing));
var apdlLayer1 = new ServiceElement(ElementType.ElementSequence,
new ServiceElement(ElementType.Uuid16, GetBluetoothUuid16(SvcClass128ProtocolAvctp)),
new ServiceElement(ElementType.UInt16, Version));
ServiceElement additionalPdlSubList0 = new ServiceElement(ElementType.ElementSequence,
apdlLayer0, apdlLayer1);
ServiceElement additionalPdl = new ServiceElement(ElementType.ElementSequence,
additionalPdlSubList0);
//
ServiceRecordBuilder bldr = new ServiceRecordBuilder();
bldr.AddServiceClass(BluetoothService.AVRemoteControl);
bldr.AddServiceClass(SvcClass128AvcrpController);
//
bldr.ProtocolType = BluetoothProtocolDescriptorType.None;
bldr.AddCustomAttributes(
new ServiceAttribute(UniversalAttributeId.ProtocolDescriptorList, pdl),
new ServiceAttribute(UniversalAttributeId.AdditionalProtocolDescriptorLists, additionalPdl));
//
bldr.AddBluetoothProfileDescriptor(BluetoothService.AVRemoteControl, 1, 4);
//
bldr.AddCustomAttribute(new ServiceAttribute(HandsFreeProfileAttributeId.SupportedFeatures,
ServiceElement.CreateNumericalServiceElement(ElementType.UInt16,
(int)(AvcrpSupportedFeatures.Category1 | AvcrpSupportedFeatures.Category2)
)));
//
bldr.ProviderName = "alanjmcf!!!!!!";
bldr.ServiceName = "avcrp tc!!!!!!";
return bldr.ServiceRecord;
}
static UInt16 GetBluetoothUuid16(Guid sigServiceClass)
{
Int64 uuid32 = GetBluetoothUuid32(sigServiceClass);
UInt16 uuid16;
try {
UInt32 uuid32Real = (UInt32)uuid32;
uuid16 = (UInt16)uuid32Real;
return uuid16;
} catch (OverflowException oex) {
throw new ArgumentException("The Service Class Guid does not have a UUID16 short form.", oex);
}
}
static UInt32 GetBluetoothUuid32(Guid sigServiceClass)
{
byte[] ba = sigServiceClass.ToByteArray();
UInt32 uuid32 = BitConverter.ToUInt32(ba, 0);
Guid recreated = BluetoothService.CreateBluetoothUuid(uuid32);
if (!recreated.Equals(sigServiceClass))
throw new ArgumentException("The Service Class Guid is not a Bluetooth standard class.");
return uuid32;
}
[MenuItem, SubMenu("SDP")]
public void SdpDumpGiven()
{
console.WriteLine("Enter the record bytes, e.g. 0x36, 0x00, 0x53, 0x09, 0x00, 0x00, 0x0a ...");
console.WriteLine("Enter an empty line to finish.");
var lineList = new List<string>();
while (true) {
//string line = "0x36, 0x00, 0x56, 0x36, 0x00, 0x53, 0x09, 0x00, 0x00, 0x0a, 0x00, 0x01, 0x00, 0x00, 0x09, 0x00, ";
string line = console.ReadLine(string.Empty);
if (string.IsNullOrEmpty(line)) {
break;
}
lineList.Add(line);
}
//
const int GuessMaxLineLen = 16;
var bytesList = new List<byte>(GuessMaxLineLen * lineList.Count);
foreach (var curLine in lineList) {
string[] arr = curLine.Split(',');
bool sawBlank = false;
foreach (var cur in arr) {
if (sawBlank) {
throw new FormatException("Found blank array entry in line.");
}
string v = cur.Trim();
byte b;
if (v.Length == 0) { // Empty, allow if after last comma...
sawBlank = true;
continue;
}
if (v.StartsWith("0x", StringComparison.Ordinal)) {
v = v.Substring(2);
b = byte.Parse(v, NumberStyles.AllowHexSpecifier);
} else {
b = byte.Parse(v);
}
bytesList.Add(b);
}
}
//
byte[] raw = bytesList.ToArray();
var p = new ServiceRecordParser();
ServiceRecord rcd;
try {
rcd = p.Parse(raw);
} catch (UriFormatException) {
console.WriteLine("Record parse failed with UriFormatException,"
+ " trying again with LazyUrlCreation=true.");
p.LazyUrlCreation = true;
rcd = p.Parse(raw);
}
SdpRecordDump(new ServiceRecord[] { rcd });
}
[MenuItem, SubMenu("SDP")]
public void FromJsr82ServerUri()
{
var line = console.ReadLine("JSR-82 uri");
var bldr = ServiceRecordBuilder.FromJsr82ServerUri(line);
console.WriteLine(ServiceRecordUtilities.Dump(bldr.ServiceRecord));
}
//--------
delegate TResult MyFunc<T0, TResult>(T0 p0);
delegate TResult MyFunc<T0, T1, TResult>(T0 p0, T1 p1);
//----
[MenuItem, SubMenu("Data")]
public void SendLots()
{
if (!VerifyConnectionWrite())
return;
byte[] data = MakeLotsData();
Lots_CheckTheTest(ref data);
bool @async = console.ReadYesNo("Async", true);
if (@async) {
IAsyncResult ar = _peer.BeginWrite(data, 0, data.Length, MiscCallback, "BeginWrite");
console.WriteLine("Started writing (async), len: {0}.", data.Length);
_peer.EndWrite(ar);
} else {
_peer.Write(data, 0, data.Length);
}
console.WriteLine("Finished writing.");
}
[MenuItem, SubMenu("Data")]
public void SendLots_InSizedChunks()
{
if (!VerifyConnectionWrite())
return;
byte[] data = MakeLotsData();
Lots_CheckTheTest(ref data);
IList<byte[]> dataList = SplitIntoChunks(data, 999);
bool @async = console.ReadYesNo("Async", true);
if (@async) {
List<IAsyncResult> arList = new List<IAsyncResult>(dataList.Count);
int total = 0;
foreach (byte[] cur in dataList) {
IAsyncResult ar = _peer.BeginWrite(cur, 0, cur.Length, EmptyCallback, "BeginWrite");
total += cur.Length;
console.Write(".");
arList.Add(ar);
}
console.WriteLine("Did BeginWrite all chunks ({2}, async), len: {0} is {1}.", total, data.Length, arList.Count);
foreach (IAsyncResult cur in arList) {
_peer.EndWrite(cur);
}
console.WriteLine("Did EndWrite all chunks.");
} else {
foreach (byte[] chunk in dataList) {
console.WriteLine("chunk={0}", chunk.Length);
_peer.Write(chunk, 0, chunk.Length);
}
}
console.WriteLine("Finished writing.");
}
private void Lots_CheckTheTest(ref byte[] data)
{
bool testChecking1 = console.ReadYesNo("check the TEST, set one byte wrong", false);
if (testChecking1) {
data[1030000] ^= 255;
}
int hackOffset = 1040000;
bool testChecking2 = console.ReadYesNo("check the TEST, add two bytes at " + hackOffset, false);
if (testChecking2) {
byte[] dataSlodged = new byte[data.Length + 2];
Array.Copy(data, 0, dataSlodged, 0, hackOffset);
Array.Copy(data, hackOffset, dataSlodged, 2 + hackOffset, data.Length - hackOffset);
data = dataSlodged;
}
}
private IList<byte[]> SplitIntoChunks(byte[] data, int chunkSize)
{
int offset = 0;
List<byte[]> chunkList = new List<byte[]>(data.Length / chunkSize + 1);
while (offset < data.Length) {
int curSize = Math.Min(chunkSize, data.Length - offset);
byte[] cur = new byte[curSize];
Array.Copy(data, offset, cur, 0, cur.Length);
offset += cur.Length;
chunkList.Add(cur);
}
if (offset != data.Length)
throw new InvalidOperationException("NOT offset==data.Length: " + offset + " vs " + data.Length);
return chunkList;
}
private byte[] MakeLotsData()
{
byte[] data = new byte[1 * 1024 * 1024];
bool useRandom = console.ReadYesNo("Random data", true);
if (useRandom) {
Random r = new Random(999);
r.NextBytes(data);
} else {
for (int i = 0; i < data.Length; ++i) {
data[i] = unchecked((byte)i);
if (data[i] == 0) // Don't allow zeros, to se if that bug occurs.
data[i] = 255;
}
}
return data;
}
[MenuItem, SubMenu("Data")]
public void ReadLots()
{
if (!VerifyConnectionRead())
return;
byte[] expectedData = MakeLotsData();
ReadLotsState state = new ReadLotsState(_peer, expectedData);
state.data = new byte[expectedData.Length + 20];
ReadLotsStartNextRead(state);
console.Pause("Un-pause to stop");
//lock (readLotsCurAr) {
// readLotsCurAr.
//}
}
IAsyncResult readLotsCurAr;
private void ReadLotsStartNextRead(ReadLotsState state)
{
if (state.numCompletedSynchronously > ReadLotsState.MaxCompletedSynchronously) {
// (There's lots of pending data and thus) We've CompletedSynchronously
// *many* times, so there's a danger of stack overflow
// (BeginRead->callback->BeginRead->callback->BeginRead->callback->...),
// so start the next operation on a new thread.
WaitCallback dlgt = delegate(object stateP)
{
ReadLotsState state0 = (ReadLotsState)stateP;
state.numCompletedSynchronously = 0;
ReadLotsStartNextRead(state);
};
ThreadPool.QueueUserWorkItem(dlgt);
return;
}
readLotsCurAr = state.peer.BeginRead(state.data, state.totalLen, state.data.Length - state.totalLen,
ReadLotsReadCallBack, state);
console.Write("-");
}
class ReadLotsState
{
public ReadLotsState(Stream peer, byte[] expectedData)
{
this.peer = peer;
this.expectedData = expectedData;
}
public Stream peer;
public byte[] data;
public int totalLen;
//
public byte[] expectedData;
//
public int numCompletedSynchronously;
public const int MaxCompletedSynchronously = 50;
}
void ReadLotsReadCallBack(IAsyncResult ar)
{
ReadLotsState state = (ReadLotsState)ar.AsyncState;
int readLen;
try {
readLen = state.peer.EndRead(ar);
} catch (ObjectDisposedException) {
console.WriteLine("Connection was closed during ReadLots.");
console.WriteLine("???, hit return to continue.");
return;
}
console.Write(">{1} ({0}) ", readLen, state.totalLen + readLen);
ArraysEqual(state.expectedData, state.data, state.totalLen, readLen);
state.totalLen += readLen;
if (ar.CompletedSynchronously)
++state.numCompletedSynchronously;
else
state.numCompletedSynchronously = 0;
if (state.totalLen == state.expectedData.Length) {
console.WriteLine("got all!");
return;
}
//
if (readLen == 0) {
console.WriteLine("EoF, hit return to continue.");
return;
}
ReadLotsStartNextRead(state);
}
private void ArraysEqual(byte[] expected, byte[] actual, int offset, int count)
{
for (int i = 0; i < count; ++i) {
if (offset + i >= expected.Length) {
console.WriteLine("!! ({0}+{1}=>) {2} >= {3}", offset, i, (offset + i), expected.Length);
}
if (offset + i >= actual.Length) {
console.WriteLine("!! ({0}+{1}=>) {2} >= {3}", offset, i, (offset + i), actual.Length);
}
if (expected[offset + i] != actual[offset + i]) {
console.WriteLine("wrong at {0}+{1}={2}", offset, i, offset + i);
break;
}
}
}
//----
[MenuItem, SubMenu("Local")]
public void GetAllRadios_OnUiThread()
{
EventHandler dlgt = delegate
{
#if ANDROID
InTheHand.Net.Bluetooth.Droid.AndroidBthInquiry
.MyActivity = (Android.App.Activity)console.InvokeeControl;
#endif
var rl = BluetoothRadio.GetAllRadios();
};
console.UiInvoke(dlgt);
}
[MenuItem, SubMenu("Local")]
public void GetAllRadios()
{
BluetoothRadio_GetAllAndDump();
}
[MenuItem, SubMenu("Local")]
public void GetAllRadiosWith_Features()
{
BluetoothRadio_GetAllAndDump(true);
}
[MenuItem, SubMenu("Local")]
public void Get_AllRadiosDumpRepeatedly()
{
BluetoothRadio[] list = BluetoothRadio.GetAllRadios();
do {
DumpBluetoothRadios(list, false);
} while (console.ReadYesNo("Dump again", false));
}
BluetoothRadio[] BluetoothRadio_GetAllAndDump()
{
return BluetoothRadio_GetAllAndDump(false);
}
BluetoothRadio[] BluetoothRadio_GetAllAndDump(bool dumpFeatureList)
{
BluetoothRadio[] list;
if (console.ReadYesNo("Get Method rather then Property", true)) {
list = BluetoothRadio.GetAllRadios();
} else {
list = BluetoothRadio.AllRadios;
}
DumpBluetoothRadios(list, dumpFeatureList);
return list;
}
void DumpBluetoothRadios(BluetoothRadio[] list, bool dumpFeatureList)
{
if (list == null)
console.WriteLine("AllRadios returned null!!!");
else if (list.Length == 0)
console.WriteLine("AllRadios returned empty list.");
int i = 1;
foreach (BluetoothRadio r in list) {
console.WriteLine("{0}) {1}", i, DumpBluetoothRadio(r, dumpFeatureList));
++i;
}
}
[MenuItem, SubMenu("Local")]
public void GetPrimaryRadio()
{
GetPrimaryRadio_(false);
}
[MenuItem, SubMenu("Local")]
public void Get_PrimaryRadioAndDumpRepeatedly()
{
GetPrimaryRadio_(true);
}
void GetPrimaryRadio_(bool offerRepeat)
{
BluetoothRadio r;
if (console.ReadYesNo("Get Method rather then Property", true)) {
r = BluetoothRadio.GetPrimaryRadio();
} else {
r = BluetoothRadio.PrimaryRadio;
}
do {
if (r == null)
console.WriteLine("PrimaryRadio returned null.");
else
console.WriteLine(DumpBluetoothRadio(r, false));
} while (offerRepeat
&& console.ReadYesNo("Dump again", false));
}
private static string DumpVersions(RadioVersions v)
{
if (v == null)
throw new ArgumentNullException("radio");
using (StringWriter wtr = new StringWriter()) {
wtr.WriteLine("LMP Version: " + v.LmpVersion
+ ", Subversion: " + v.LmpSubversion);
wtr.WriteLine("Manufacturer: {0}",
v.Manufacturer);
wtr.WriteLine("LMP Features: {0}",
v.LmpSupportedFeatures);
return wtr.ToString();
}
}
private static string DumpBluetoothRadio(BluetoothRadio radio, bool dumpFeatureList)
{
if (radio == null)
throw new ArgumentNullException("radio");
using (StringWriter wtr = new StringWriter()) {
RadioMode mode = radio.Mode;
// Warning: LocalAddress is null if the radio is powered-off.
wtr.WriteLine("Radio, address: {0:C}", radio.LocalAddress);
#if RADIO_MODESSS
wtr.Write("Mode: " + mode.ToString());
wtr.WriteLine("; Modes: { " + radio.Modes.ToString() + " }");
#else
wtr.WriteLine("Mode: " + mode.ToString());
#endif
wtr.WriteLine("Name: " + ToStringQuotedOrNull(radio.Name));
wtr.WriteLine("HCI Version: " + radio.HciVersion
+ ", Revision: " + radio.HciRevision);
wtr.WriteLine("LMP Version: " + radio.LmpVersion
+ ", Subversion: " + radio.LmpSubversion);
if (dumpFeatureList) { wtr.WriteLine("LMP Features: " + radio.LmpFeatures); }
wtr.WriteLine("ClassOfDevice: " + radio.ClassOfDevice.ToString()
+ ", device: " + radio.ClassOfDevice.Device.ToString()
+ " / service: " + radio.ClassOfDevice.Service.ToString());
wtr.WriteLine("Software: {0}, Hardware: {1}, status: {2}",
radio.SoftwareManufacturer, radio.Manufacturer, radio.HardwareStatus);
//try {
// wtr.WriteLine("Handle: 0x{0:X}", radio.Handle);
//} catch (Exception ex) {
// wtr.WriteLine("Handle: failed with: '{0}'", ex.GetType().Name);
//}
wtr.WriteLine("Remote: '{0}'", radio.Remote);
return wtr.ToString();
}
}
private static string DumpBluetoothRadioBrief(BluetoothRadio radio)
{
if (radio == null)
throw new ArgumentNullException("radio");
using (StringWriter wtr = new StringWriter()) {
RadioMode mode = radio.Mode;
// Warning: LocalAddress is null if the radio is powered-off.
//wtr.Write("Address: {0:C}, ", radio.LocalAddress);
wtr.Write("Mode: " + mode.ToString());
#if RADIO_MODESSS
wtr.Write("; Modes: { " + radio.Modes.ToString() + " }");
#endif
//wtr.Write(", Name: " + radio.Name);
return wtr.ToString();
}
}
[MenuItem, SubMenu("Local")]
public void RepeatedlyGetPrimaryRadio()
{
int? initialDelay = console.ReadOptionalInteger("Initial delay (ms)");
int? interDelay = 250;
int? userInterDelay = console.ReadOptionalInteger("Inter delay (ms) (default " + interDelay + ")");
if (userInterDelay.HasValue) interDelay = userInterDelay;
int count = 20;
int? userCount = console.ReadOptionalInteger("Optional count (default " + count + ")");
if (userCount.HasValue) count = userCount.Value;
//
if (initialDelay.HasValue) Thread.Sleep(initialDelay.Value);
for (int i = 0; i < count; ++i) {
console.WriteLine(Environment.TickCount.ToString() + ": ");
try {
BluetoothRadio r = BluetoothRadio.PrimaryRadio;
if (r == null) {
console.WriteLine("PrimaryRadio returned null.");
} else {
console.WriteLine(DumpBluetoothRadioBrief(r));
}
} catch (Exception ex) {
console.WriteLine("Error:" + Exception_FirstLine(ex));
Debug.WriteLine("RGPR: " + ex);
}
if (interDelay.HasValue) Thread.Sleep(interDelay.Value);
}//for
}
[MenuItem, SubMenu("Local")]
public void IsSupported()
{
bool? f = null;
EventHandler dlgt = (o, e) =>
f = BluetoothRadio.IsSupported;
bool ui = console.ReadYesNo("On UI thread?", false);
if (!ui)
dlgt(null, null);
else
console.UiInvoke(dlgt);
console.WriteLine("IsSupported: {0}", f.Value);
}
//----
#if TEST_EARLY
[MenuItem, SubMenu("BtLsnr")]
public void WidcommHackListen()
{
BluetoothAddress addr = BluetoothAddress.None;
//BluetoothAddress addr = console.ReadBluetoothAddress("Server's local BluetoothAddress");
Guid svcClass = BluetoothService.WapClient;
console.WriteLine("Default UUID : {0}", svcClass);
Guid? inputGuid = console.ReadOptionalBluetoothUuid("UUID");
if (inputGuid.HasValue)
svcClass = inputGuid.Value;
int? port = console.ReadOptionalInteger("Port number");
//
BluetoothEndPoint rep;
if (port == null)
rep = new BluetoothEndPoint(addr, svcClass);
else
rep = new BluetoothEndPoint(addr, svcClass, port.Value);
console.WriteLine("Connecting to: {0}:{1}:{2}", rep.Address, rep.Service, rep.Port);
//
InTheHand.Net.Bluetooth.Widcomm.WidcommBluetoothListener lsnr
= new InTheHand.Net.Bluetooth.Widcomm.WidcommBluetoothListener();
lsnr.Construct(rep);
lsnr.Start();
BluetoothClient conn = lsnr.AcceptBluetoothClient();
peer = conn.GetStream();
s_cli = new WeakReferenceT<BluetoothClient>(conn);
}
#endif
[MenuItem, SubMenu("GC")]
public void RunFinalizersAfterGc()
{
RunFinalizersAfterGc_();
}
internal static void RunFinalizersAfterGc_()
{
GC.Collect();
GC.WaitForPendingFinalizers();
}
[MenuItem, SubMenu("GC")]
public void RunGc()
{
RunGc_();
}
internal static void RunGc_()
{
GC.Collect();
}
#if !NETCF && !ANDROID
[MenuItem, SubMenu("GC")]
public void BeepOnFinalization()
{
JRichter.GCNotification.StartBeeper();
}
#endif
//----------
[MenuItem, SubMenu("OBEX")]
public void _ObexWebRequest()
{
string addr = console.ReadLine("Address (IrDA / TCP/IP; hit return for BT)");
bool useUriCtor = true;
BluetoothAddress addrBth;
if (addr.Length == 0) {
addrBth = console.ReadBluetoothAddress("Target Bluetooth device");
addr = addrBth.ToString();
useUriCtor = !console.ReadYesNo("Use BluetoothAddress+stringPath constructor", !useUriCtor);
} else {
// Often get a space after string on NETCF (remembered string)
addr = addr.Trim();
addrBth = null;
}
string pathO;
string fileSource;
int? contentLen;
if (console.ReadYesNo("Send dummy content", true)) {
pathO = "/obexpush1.txt";
contentLen = console.ReadOptionalInteger("How much content (default ~60 bytes)");
fileSource = null;
if (contentLen == null)
contentLen = 60;
} else {
contentLen = null;
fileSource = console.GetFilename();
pathO = Path.GetFileName(fileSource);
pathO = "/" + pathO;
}
//
int? timeout = console.ReadOptionalInteger("timeout (ms)");
//
const string scheme = "obex";
Debug.Assert(pathO.StartsWith("/"), "NOT path starts with /");
var s = string.Format(System.Globalization.CultureInfo.InvariantCulture,
"{0}://{1}{2}",
scheme, addr, pathO);
Uri uri = new Uri(s);
ObexWebRequest req;
if (useUriCtor) {
req = Create_ObexWebRequest(uri);
} else {
req = Create_ObexWebRequest(scheme, addrBth, pathO);
}
if (timeout != null) { req.Timeout = timeout.Value; }
//
if (contentLen != null) {
WriteDummyContent(contentLen.Value, req);
} else {
req.ReadFile(fileSource);
}
console.WriteLine("Calling GetResponse with " + req.ContentLength + " bytes of content...");
ObexWebResponse rsp = (ObexWebResponse)req.GetResponse();
console.WriteLine("Response Code: {0} (0x{0:X})", rsp.StatusCode);
}
private static void WriteDummyContent(int contentLen, ObexWebRequest req)
{
using (Stream content = req.GetRequestStream()) {
// Using a StreamWriter to write text to the stream...
using (TextWriter wtr = new StreamWriter(content)) {
int i = 0;
while (content.Length < contentLen) {
++i;
wtr.WriteLine("Hello World GetRequestStream {0}",
// Write the time to the first line
i == 1 ? DateTime.Now.ToString() : i.ToString());
wtr.Flush(); // push through to stream
}
// Set the Length header value
req.ContentLength = content.Length;
}
}
}
#if !NETCF
bool _touchedOwr;
[MenuItem, SubMenu("OBEX")]
public void WebClientPut()
{
if (!_touchedOwr) {
bool ret = console.ReadYesNo("Touch ObexWebRequest to install protocol handler.", true);
if (ret) {
var x = new ObexWebRequest(new Uri("obex://127.0.0.1/foo.txt"));
_touchedOwr = true;
}
}
string addr = console.ReadLine("Address (IrDA / TCP/IP; hit return for BT)");
if (addr.Length == 0) {
BluetoothAddress addrB = console.ReadBluetoothAddress("Target Bluetooth device");
addr = addrB.ToString();
}
int? contentLen = console.ReadOptionalInteger("How much content (default ~60 bytes)");
if (contentLen == null)
contentLen = 60;
//NOT on NETCF!
// UriBuilder bldr = new UriBuilder();
// bldr.Scheme = "obex";
// bldr.Path = "/obexpush1.txt";
// bldr.Host = addr.ToString();
Uri uri = new Uri(string.Format(System.Globalization.CultureInfo.InvariantCulture,
"{0}://{1}{2}",
"obex", addr, "/obexpush1.txt"));
//
var cli = new WebClient();
cli.UploadProgressChanged += delegate(object sender, UploadProgressChangedEventArgs e)
{
console.WriteLine("Progress: {0}%, {1} of {2}",
e.ProgressPercentage, e.BytesSent, e.TotalBytesToSend);
};
cli.UploadDataCompleted += delegate(object sender, UploadDataCompletedEventArgs e)
{
WriteAsyncCompletedState("UploadData", e);
};
byte[] data;
using (var content = new MemoryStream()) {
// Using a StreamWriter to write text to the stream...
using (TextWriter wtr = new StreamWriter(content)) {
int i = 0;
while (content.Length < contentLen) {
++i;
wtr.WriteLine("Hello World GetRequestStream {0}",
// Write the time to the first line
i == 1 ? DateTime.Now.ToString() : i.ToString());
wtr.Flush(); // push through to stream
}
//
data = content.ToArray();
}
}
// Need method set!
cli.UploadDataAsync(uri, "PUT", data);
console.Pause("Un-pause after completion");
//console.WriteLine("Calling GetResponse with " + req.ContentLength + " bytes of content...");
//ObexWebResponse rsp = (ObexWebResponse)req.GetResponse();
//console.WriteLine("Response Code: {0} (0x{0:X})", rsp.StatusCode);
}
#endif
[MenuItem, SubMenu("OBEX")]
public void ObexWebRequest_GET()
{
string addr = console.ReadLine("Address (IrDA / TCP/IP; hit return for BT)");
if (addr.Length == 0) {
BluetoothAddress addrB = console.ReadBluetoothAddress("Target Bluetooth device");
addr = addrB.ToString();
}
string path = console.ReadLine("Path");
Uri uri = new Uri(string.Format(System.Globalization.CultureInfo.InvariantCulture,
"{0}://{1}/{2}",
"obex-ftp", addr, path));
console.WriteLine("Using URL: '{0}'", uri);
ObexWebRequest req = new ObexWebRequest(uri);
req.Method = "GET";
ObexWebResponse rsp = (ObexWebResponse)req.GetResponse();
console.WriteLine("Response Code: {0} (0x{0:X})", rsp.StatusCode);
var strm = rsp.GetResponseStream();
console.WriteLine(" ContentLength: {0}, Stream.Length: {1}",
rsp.ContentLength, strm.Length);
using (Stream rspData = strm) {
StreamReader rdr = new StreamReader(rspData);
console.WriteLine("data, first line: '{0}'", rdr.ReadLine());
}
}
[MenuItem, SubMenu("OBEX")]
public void Obex_Listener()
{
m_lsnrStop = false;
Interlocked.Exchange(ref m_lsnrId, 0);
ObexListener lstnr = null;
ObexTransport? proto = null;
while (lstnr == null) {
int? i = console.ReadOptionalInteger("Which ObexListener transport: 1. Bluetooth, 2. IrDA, 3. TCP/IP");
if (!i.HasValue || i.Value == 1) {
proto = ObexTransport.Bluetooth;
lstnr = Create_ObexListener_Bluetooth();
} else {
while (!proto.HasValue) {
switch (i) {
case 2:
proto = ObexTransport.IrDA;
break;
case 3:
proto = ObexTransport.Tcp;
break;
default:
// (No Trace.Fail on NETCFv2)
Debug.Assert(false, "invalid input: " + i);
break;
}
}
lstnr = new ObexListener(proto.Value);
}
}
console.WriteLine("Created {0} ObexListener.", proto);
//
var auth = console.ReadYesNoCancel("Authenticate value (or don't set)", null);
if (auth.HasValue) { lstnr.Authenticate = auth.Value; }
console.WriteLine("get_Authenticate value: '{0}'", lstnr.Authenticate);
var encrypt = console.ReadYesNoCancel("Encrypt value (or don't set)", null);
if (encrypt.HasValue) { lstnr.Encrypt = encrypt.Value; }
console.WriteLine("get_Encrypt value: '{0}'", lstnr.Encrypt);
//
lstnr.Start();
console.WriteLine("OBEX listening");
console.WriteLine("get_Authenticate value: '{0}'", lstnr.Authenticate);
console.WriteLine("get_Encrypt value: '{0}'", lstnr.Encrypt);
int? count = console.ReadOptionalInteger("How many acceptors threads? (1 by default)");
if (count == null) {
count = 1;
}
console.WriteLine("Starting acceptor...");
for (int i = 0; i < count; ++i) {
ThreadPool.QueueUserWorkItem(ObexListener_Worker, lstnr);
}
try {
console.Pause("Un-pause to continue; and close listener");
} finally {
m_lsnrStop = true;
lstnr.Stop();
}
}
private volatile bool m_lsnrStop;
private int m_lsnrId;
void ObexListener_Worker(object state)
{
int id = Interlocked.Increment(ref m_lsnrId);
while (true) {
ObexListener lstnr = (ObexListener)state;
if (m_lsnrStop || !lstnr.IsListening) {
break;
}
ObexListenerContext ctx = null;
try {
ctx = lstnr.GetContext();
if (ctx == null) {
console.WriteLine("{0}: OBEX null context!", id);
continue;
}
console.WriteLine("{0}: OBEX accepted lContext", id);
ObexListenerRequest req = ctx.Request;
console.WriteLine("{0}: OBEX lRequest url: {1}, ContentLength64: {2}",
id, req.RawUrl, req.ContentLength64);
var ms = (MemoryStream)req.InputStream;
console.WriteLine("{0}: InputStream.Len: {1}",
id, ms.Length);
} catch (Exception ex) {
console.WriteLine("{0}: OBEX ctx/req fault: {1}", id, ex);
}
ctx = null;
}//while
}
//--------
#if TEST_EARLY
[MenuItem, SubMenu("Security etc")]
public void SetPain()
{
BluetoothAddress addr = console.ReadBluetoothAddress("Address");
string passphrase = console.ReadLine("Passphrase");
using (BluetoothClient cli = new BluetoothClient()) {
InTheHand.Net.Bluetooth.Widcomm.BOND_RETURN_CODE ret = cli.WidcommHack__SetPinX(addr, passphrase);
console.WriteLine("Bond returned: {0} = 0x{1:X}", ret, (int)ret);
}
}
#endif
private BluetoothPublicFactory GetStackFactory()
{
var r = Get_BluetoothRadio();
if (r == null) {
console.WriteLine("No radios.");
throw new InvalidOperationException("No radios.");
}
return r.StackFactory;
}
[MenuItem, SubMenu("Security etc")]
public void PairRequest()
{
BluetoothAddress addr = console.ReadBluetoothAddress("Address");
string passphrase = console.ReadLine("Passphrase");
if (string.IsNullOrEmpty(passphrase)) {
bool makeNull = console.ReadYesNo("Do you want to use a null/Nothing passphrase", true);
passphrase = makeNull ? null : string.Empty;
}
InTheHand.Net.Bluetooth.Factory.IBluetoothSecurity sec
= GetStackFactory().BluetoothSecurity;
bool ret = sec.PairRequest(addr, passphrase);
console.WriteLine("PairRequest returned: {0}", ret);
}
[MenuItem, SubMenu("Security etc")]
public void RemoveDevice()
{
BluetoothAddress addr = console.ReadBluetoothAddress("Address");
InTheHand.Net.Bluetooth.Factory.IBluetoothSecurity sec
= GetStackFactory().BluetoothSecurity;
bool ret = sec.RemoveDevice(addr);
console.WriteLine("RemoveDevice returned: {0}", ret);
}
[MenuItem, SubMenu("Security etc")]
public void SetPin()
{
string passphrase = console.ReadLine("Passphrase");
if (string.IsNullOrEmpty(passphrase)) {
bool makeNull = console.ReadYesNo("Do you want to use a null/Nothing passphrase", true);
passphrase = makeNull ? null : string.Empty;
}
BluetoothAddress addr = console.ReadBluetoothAddress("Address");
InTheHand.Net.Bluetooth.Factory.IBluetoothSecurity sec
= GetStackFactory().BluetoothSecurity;
bool ret = sec.SetPin(addr, passphrase);
console.WriteLine("SetPin returned: {0}", ret);
}
[MenuItem, SubMenu("Security etc")]
public void RevokePin()
{
BluetoothAddress addr = console.ReadBluetoothAddress("Address");
string passphrase = console.ReadLine("Passphrase");
if (string.IsNullOrEmpty(passphrase)) {
bool makeNull = console.ReadYesNo("Do you want to use a null/Nothing passphrase", true);
passphrase = makeNull ? null : string.Empty;
}
InTheHand.Net.Bluetooth.Factory.IBluetoothSecurity sec
= GetStackFactory().BluetoothSecurity;
bool ret = sec.RevokePin(addr);
console.WriteLine("RevokePin returned: {0}", ret);
}
//--------
[MenuItem, SubMenu("MultiStack")]
public void ListenerOnStack1ClientOnStack2()
{
BluetoothRadio[] radios = BluetoothRadio_GetAllAndDump();
Debug.Assert(radios != null, "Should't return null!");
if (radios.Length < 2) {
console.WriteLine("Fewer that two radios were found ({0}).", radios.Length);
return;
}
//
ListenerOnStackAClientOnStackB(radios[0], radios[1]);
}
[MenuItem, SubMenu("MultiStack")]
public void ListenerOnStack2ClientOnStack1()
{
BluetoothRadio[] radios = BluetoothRadio_GetAllAndDump();
Debug.Assert(radios != null, "Should't return null!");
if (radios.Length < 2) {
console.WriteLine("Fewer that two radios were found ({0}).", radios.Length);
return;
}
//
ListenerOnStackAClientOnStackB(radios[1], radios[0]);
}
public void ListenerOnStackAClientOnStackB(BluetoothRadio radioLsnr, BluetoothRadio radioCli)
{
BluetoothListener lsnr = radioLsnr.StackFactory.CreateBluetoothListener(BluetoothService.Wap);
BluetoothClient conn = null;
BluetoothClient cli = null;
try {
lsnr.Start();
#if APM_LSNR
IAsyncResult arLsnr = lsnr.BeginAcceptBluetoothClient(MiscCallback, "ListenerOnStack1ClientOnStack2");
#else
ManualResetEvent accepted = new ManualResetEvent(false);
WaitCallback dlgt = delegate(object state)
{
BluetoothListener lsnr_ = (BluetoothListener)state;
try {
conn = lsnr_.AcceptBluetoothClient();
console.WriteLine("Server got connection from : '{0}' {1}", conn.RemoteMachineName, conn.RemoteEndPoint);
PrintLocalEndpointIfAvailable(conn);
} catch (Exception ex) {
console.WriteLine("Accept failed with: " + ex);
} finally {
accepted.Set();
}
};
conn = null;
ThreadPool.QueueUserWorkItem(dlgt, lsnr);
#endif
BluetoothEndPoint lep = lsnr.LocalEndPoint;
console.WriteLine("Listener active on SCN: {0}", lep.Port);
//
cli = radioCli.StackFactory.CreateBluetoothClient();
BluetoothEndPoint rep = new BluetoothEndPoint(radioLsnr.LocalAddress, BluetoothService.Empty, lep.Port);
console.WriteLine("Gonna connect to: {0}", rep);
console.Pause("Un-pause to connect!");
cli.Connect(rep);
console.WriteLine("Client Connected to : '{0}' {1}", cli.RemoteMachineName, cli.RemoteEndPoint);
PrintLocalEndpointIfAvailable(cli);
//
#if APM_LSNR
console.WriteLine("Lsnr.Accept.IsCompleted: {0}", arLsnr.IsCompleted);
conn = lsnr.EndAcceptBluetoothClient(arLsnr);
#else
console.WriteLine("waiting for Lsnr.Accept completion event.");
accepted.WaitOne();
Debug.Assert(conn != null, "Should have veen set by thread!");
#endif
console.WriteLine("All success");
console.Pause("Un-pause to exit (and close both)");
} finally {
if (lsnr != null)
lsnr.Stop();
if (conn != null)
conn.Dispose();
if (cli != null)
cli.Dispose();
}
}
[MenuItem, SubMenu("MultiStack")]
public void ObexWebRequest_MultiAsync()
{
BluetoothRadio[] radios = BluetoothRadio_GetAllAndDump();
Debug.Assert(radios != null, "Should't return null!");
if (radios.Length < 1) {
console.WriteLine("No radios found.");
return;
}
//
List<BluetoothAddress> addrList = new List<BluetoothAddress>();
for (int i = 0; i < radios.Length; ++i) {
BluetoothAddress addr = console.ReadBluetoothAddress(
"Target device for radio #" + (i + 1));
addrList.Add(addr);
}//for
bool bigSend = console.ReadYesNo("Send big (1MB) or small?", false);
byte[] bigBuf = null;
if (bigSend) {
bigBuf = new byte[1024 * 1024];
#if !NETCF
Array.ForEach(bigBuf, delegate(byte cur) { cur = (byte)'a'; });
#endif
}
List<IAsyncResult> arList = new List<IAsyncResult>(addrList.Count);
for (int i = 0; i < radios.Length; ++i) {
BluetoothAddress addr = addrList[i];
Uri uri = new Uri(string.Format(System.Globalization.CultureInfo.InvariantCulture,
"{0}://{1}{2}",
"obex", addr, "/obexpush1.txt"));
BluetoothPublicFactory factory = radios[i].StackFactory;
ObexWebRequest req = factory.CreateObexWebRequest(uri);
using (Stream content = req.GetRequestStream()) {
// Using a StreamWriter to write text to the stream...
if (bigSend) {
content.Write(bigBuf, 0, bigBuf.Length);
} else {
using (TextWriter wtr = new StreamWriter(content)) {
wtr.WriteLine("Hello World GetRequestStream");
wtr.WriteLine("Hello World GetRequestStream 2");
wtr.Flush();
// Set the Length header value
req.ContentLength = content.Length;
}
}
}
IAsyncResult ar = req.BeginGetResponse(null, req);
arList.Add(ar);
}//for
//
console.WriteLine("Waiting for all requests to complete...");
WaitAll(arList);
console.WriteLine("All requests completed...");
//
for (int i = 0; i < radios.Length; ++i) {
IAsyncResult cur = arList[i];
ObexWebRequest req = (ObexWebRequest)cur.AsyncState;
console.WriteLine("- - - #{1} - - -", null, (i + 1));
try {
ObexWebResponse rsp = (ObexWebResponse)req.EndGetResponse(cur);
console.WriteLine("#{1}. Response Code: {0} (0x{0:X})", rsp.StatusCode, (i + 1));
} catch (Exception ex) {
console.WriteLine("#{1}. Failed: {0}", ex, (i + 1));
}
}//for
}
//----
[MenuItem, SubMenu("Data")]
public void SetReadTimeout()
{
if (_peer == null) {
console.WriteLine("no connection");
return;
}
console.WriteLine("ReadTimeout: {0}", _peer.ReadTimeout);
int? to = console.ReadOptionalInteger("New value");
if (to.HasValue)
_peer.ReadTimeout = to.Value;
}
[MenuItem, SubMenu("Data")]
public void SetWriteTimeout()
{
if (_peer == null) {
console.WriteLine("no connection");
return;
}
console.WriteLine("WriteTimeout: {0}", _peer.WriteTimeout);
int? v = console.ReadOptionalInteger("New value");
if (v.HasValue)
_peer.WriteTimeout = v.Value;
}
//----
Stream _tcpConn;
[MenuItem, SubMenu("SOCKETS")]
public void TcpConnect()
{
string hostname = console.ReadLine("hostname");
int port = console.ReadInteger("port");
System.Net.Sockets.TcpClient cli = new System.Net.Sockets.TcpClient(hostname, port);
_tcpConn = cli.GetStream();
}
[MenuItem, SubMenu("SOCKETS")]
public void TcpClose()
{
if (_tcpConn != null) {
_tcpConn.Close();
}
_tcpConn = null;
}
//----
[MenuItem, SubMenu("DeviceInfo")]
public void GetDeviceInfo()
{
BluetoothAddress addr = console.ReadBluetoothAddress("Device Address");
BluetoothDeviceInfo device = Create_BluetoothDeviceInfo(addr);
bool again;
do {
console.WriteLine(DumpDeviceInfo(device));
RadioVersions v;
try {
#if true
v = device.GetVersions();
#elif false
var w = device.GetImpl<InTheHand.Net.Bluetooth.Msft.WindowsBluetoothDeviceInfo>();
if (w != null) {
v = w.GetVersions();
}
#endif
} catch (Exception ex) {
console.WriteLine("GetVersions error: " + Exception_FirstLine(ex));
var w32ex = ex as Win32Exception;
if (w32ex != null) {
console.WriteLine(" NativeErrorCode: " + w32ex.NativeErrorCode);
}
goto afterDisplayVersion;
}
if (v == null) {
console.WriteLine("GetVersions returned null!!!!!!!!!!!!!");
} else {
console.WriteLine(DumpVersions(v));
}
afterDisplayVersion:
//
again = console.ReadYesNo("Display same one again", false);
if (again) {
var doSdp = console.ReadYesNo("Do SDP to", false);
if (doSdp) {
device.BeginGetServiceRecords(BluetoothService.L2CapProtocol, null, null);
}
}
} while (again);
}
[MenuItem, SubMenu("DeviceInfo")]
public void GetDeviceInfoAndConnect()
{
Action<BluetoothAddress> dlgtDevInfo = delegate(BluetoothAddress addrX)
{
BluetoothDeviceInfo device = Create_BluetoothDeviceInfo(addrX);
console.WriteLine("name0: " + ToStringQuotedOrNull(device.DeviceName));
console.WriteLine("name1: " + ToStringQuotedOrNull(device.DeviceName));
};
Action<BluetoothAddress> dlgtConn = delegate(BluetoothAddress addrX)
{
Thread.Sleep(1500);
console.WriteLine("Connecting...");
ConnectSimpleClosingFirstPart2(addrX);
};
//
BluetoothAddress addrDev0 = console.ReadBluetoothAddress("Device Address for DeviceInfo");
BluetoothAddress addrConn = console.ReadBluetoothAddress("Device Address for Connect");
long addrTmpl = addrDev0.ToInt64();
var arrArBdi = new IAsyncResult[4];
//
new BluetoothClient(); // Init the stack in case the user forgot to do so before.
var ar = DelegateExtension.BeginInvoke(dlgtConn, addrConn, null, null);
for (int i = 0; i < arrArBdi.Length; ++i) {
arrArBdi[i] = DelegateExtension.BeginInvoke(dlgtDevInfo, new BluetoothAddress(addrTmpl++), null, null);
}
try {
DelegateExtension.EndInvoke(dlgtConn, ar);
console.WriteLine("connect success");
} catch (System.Net.Sockets.SocketException) {
console.WriteLine("connect fail");
}
foreach (var curAr in arrArBdi) {
DelegateExtension.EndInvoke(dlgtDevInfo, curAr);
}
}
[MenuItem, SubMenu("DeviceInfo")]
public void SetServiceState()
{
BluetoothAddress addr = console.ReadBluetoothAddress("Device Address");
Guid? svcClass = console.ReadOptionalBluetoothUuid("Service Class (default SPP)", null);
if (svcClass == null) svcClass = BluetoothService.SerialPort;
console.WriteLine("Service: {0}", svcClass);
BluetoothDeviceInfo device = Create_BluetoothDeviceInfo(addr);
console.WriteLine(DumpDeviceInfoBrief(device));
bool state = console.ReadYesNo("Enable/Disable the service", true);
console.WriteLine("Will set the service to: " + state);
device.SetServiceState(svcClass.Value, state, true);
}
[MenuItem, SubMenu("DeviceInfo")]
public void GetInstalledServices()
{
BluetoothAddress addr = console.ReadBluetoothAddress("Device Address");
BluetoothDeviceInfo device = Create_BluetoothDeviceInfo(addr);
console.WriteLine(DumpDeviceInfoBrief(device));
var guidList = device.InstalledServices;
console.WriteLine("{0} of", guidList.Length);
foreach (var cur in guidList) {
var name = BluetoothService.GetName(cur);
//var shortI = BluetoothService.CreateBluetoothUuid(
console.WriteLine("* {0} aka {1}", cur, name);
}
}
#if !ANDROID
[MenuItem, SubMenu("WidcommPlaying")]
public void WidcommIsPresentConnected()
{
BluetoothAddress addr = console.ReadBluetoothAddress("Device Address");
InTheHand.Net.Bluetooth.Widcomm.RemoteDeviceState state
= new InTheHand.Net.Bluetooth.Widcomm.WidcommPlaying().FindIfPresentOrConnected(addr);
console.WriteLine("state: {0}", state);
}
[MenuItem, SubMenu("WidcommPlaying")]
public void DoPowerDownUpReset()
{
var p = new InTheHand.Net.Bluetooth.Widcomm.WidcommPlaying();
var prev = p.DoPowerDownUpReset;
var set = console.ReadYesNoCancel(string.Format(
"DoPowerDownUpReset current: {0}. Set to", prev), null);
if (set.HasValue) {
p.DoPowerDownUpReset = set.Value;
}
console.WriteLine("DoPowerDownUpReset set: {0}, was: {1}.",
set, prev);
}
#endif
//----
#if !ANDROID
[MenuItem, SubMenu("Serial")]
public void SerialPorts_List()
{
#if !NETCF
SerialPortsListWmi();
#else
SerialPortsListWmRegistry();
#endif
//----
console.WriteLine("SerialPort.GetPortNames...");
string[] nameList = System.IO.Ports.SerialPort.GetPortNames();
console.WriteLine("SerialPort.GetPortNames: {0}",
string.Join(", ", nameList));
}
#if NETCF
private void SerialPortsListWmRegistry()
{
//console.WriteLine("SerialPortsListWmRegistry");
using (var portsK = Registry.LocalMachine.OpenSubKey(@"Software\Microsoft\Bluetooth\Serial\Ports", false)) {
if (portsK == null) {
console.WriteLine("Bluetooth COM port configuration is missing.");
return;
}
foreach (var devKeyName in portsK.GetSubKeyNames()) {
BluetoothAddress addr;
try {
addr = BluetoothAddress.Parse(devKeyName);
} catch (FormatException) {
console.WriteLine("Error: key name is not a device address: '{0}'", devKeyName);
continue;
}
console.WriteLine("DeviceID: {0} ", addr);
using (var devKey = portsK.OpenSubKey(devKeyName)) {
var portN0 = devKey.GetValue("Port");
var portN1 = portN0 as string;
var portN = TruncateAtZeros(portN1);
console.WriteLine("PortName: '{0}'", portN);
}
}//for
}
}
string TruncateAtZeros(string value)
{
if (value == null) return null;
string result = value;
int idx = value.IndexOf((char)0);
if (idx != -1) {
result = value.Substring(0, idx);
}
#if DUMP_TRUNCATED_STRING_CONTENT
if (value.Length != result.Length) {
console.WriteLine("(Zero in string!! ({0}vs{1}))", value.Length, result.Length);
// (No Array.ForEach etc in NETCF)
StringBuilder bldr = new StringBuilder();
foreach (var ch in value.ToCharArray()) {
if (char.IsControl(ch))
bldr.AppendFormat(CultureInfo.InvariantCulture, "\\x{0:x4}", (ushort)ch);
else
bldr.Append(ch);
}
console.WriteLine("([{0}])", bldr.ToString());
}
#endif
return result;
}
#endif
#if !NETCF
private void SerialPortsListWmi()
{
const string Win32_SerialPort = "Win32_SerialPort";
#if false // Either work
console.WriteLine("Running query...");
System.Management.SelectQuery q = new System.Management.SelectQuery(Win32_SerialPort);
System.Management.ManagementObjectSearcher s = new System.Management.ManagementObjectSearcher(q);
#else
console.WriteLine("Running WMI query...");
System.Management.ManagementObjectSearcher s = new System.Management.ManagementObjectSearcher(
"SELECT DeviceID,PNPDeviceID FROM " + Win32_SerialPort);
#endif
console.WriteLine("Getting results...");
System.Management.ManagementObjectCollection list = s.Get();
console.WriteLine("Enumerating results...");
foreach (System.Management.ManagementBaseObject cur in list) {
object id = cur.GetPropertyValue("DeviceID");
object pnpId = cur.GetPropertyValue("PNPDeviceID");
console.WriteLine("DeviceID: {0} ", id);
console.WriteLine("PNPDeviceID: {0} ", pnpId);
console.WriteLine("");
}//for
}
#endif
SerialPort SerialPortCreate()
{
var nameNum = console.ReadOptionalInteger("Port -- if numerical 'COMx'");
string name;
if (nameNum != null) {
name = "COM" + nameNum.ToString();
} else {
name = console.ReadLine("Port name");
}
var bitrate = console.ReadOptionalInteger("Bit rate");
System.IO.Ports.SerialPort port;
if (bitrate == null) {
console.WriteLine("Connecting to port '{0}'.", name);
port = new System.IO.Ports.SerialPort(name);
} else {
console.WriteLine("Connecting to port '{0}' at bitrate '{1}'.", name, bitrate.Value);
port = new System.IO.Ports.SerialPort(name, bitrate.Value);
}
return port;
}
[MenuItem, SubMenu("Serial")]
public void SerialPort_GetDefaults()
{
string name = console.ReadLine("(Serial) Device Name");
console.WriteLine("(Serial) Device Name: {0}", name);
var cc = new Foo.COMMCONFIG(null);
uint size = checked((uint)cc.dwSize);
bool success = Foo.NativeMethods.GetDefaultCommConfig(name, ref cc, ref size);
var gle = Marshal.GetLastWin32Error();
if (!success) {
console.WriteLine("Failed: " + gle);
return;
}
console.WriteLine("dwProviderSubType: {0}, baud: {1}, size: {2} (provider offset: {3}, size: {4})",
cc.dwProviderSubType, cc.dcb.BaudRate,
cc.dwSize,
cc.dwProviderOffset, cc.dwProviderSize);
}
static class Foo
{
internal static class NativeMethods
{
[DllImport("kernel32.dll", SetLastError = true)]
internal static extern bool GetDefaultCommConfig(string lpszName, [In, Out] ref COMMCONFIG lpCC,
ref uint lpdwSize);
}
[StructLayout(LayoutKind.Sequential)]
internal struct DCB
{
public Int32 DCBLength;
public Int32 BaudRate;
public Int32 fBitField;
public Int16 wReserved;
public Int16 XonLim;
public Int16 XoffLim;
public Byte ByteSize;
public Byte Parity;
public Byte StopBits;
public Char XonChar;
public Char XoffChar;
public Char ErrorChar;
public Char EofChar;
public Char EvtChar;
public Int32 wReserved1;
}
[StructLayout(LayoutKind.Sequential)]
internal struct COMMCONFIG
{
public Int32 dwSize;
public Int16 wVersion;
public Int16 wReserved;
public DCB dcb;
public Int32 dwProviderSubType;
public Int32 dwProviderOffset;
public Int32 dwProviderSize;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 200/*e.g.*/)]
public byte[] ProviderData;
public COMMCONFIG(object fake)
: this()
{
this.dwSize = Marshal.SizeOf(this);
}
}
}
[MenuItem, SubMenu("Serial")]
public void SerialPortCo_nnect()
{
var port = SerialPortCreate();
port.Open();
_peer = port.BaseStream;
}
[MenuItem, SubMenu("Serial")]
public void SerialPort_ConnectAlsoUsePortEvents()
{
var port = SerialPortCreate();
port.DataReceived += new SerialDataReceivedEventHandler(port_DataReceived);
port.ErrorReceived += new SerialErrorReceivedEventHandler(port_ErrorReceived);
port.PinChanged += new SerialPinChangedEventHandler(port_PinChanged);
port.Open();
_peer = port.BaseStream;
}
void port_PinChanged(object sender, SerialPinChangedEventArgs e)
{
console.WriteLine("Port PinChanged: " + e.EventType);
}
void port_ErrorReceived(object sender, SerialErrorReceivedEventArgs e)
{
console.WriteLine("Port Error: " + e.EventType);
}
void port_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
console.WriteLine("Port Rcv: " + e.EventType);
}
#endif
[MenuItem, SubMenu("Serial")]
public void OpenFileStream()
{
string name = console.ReadLine("File/port name");
_peer = new FileStream(name, FileMode.Open);
}
//----
#if !ANDROID
#if NETCF
InTheHand.Net.Ports.BluetoothSerialPort _btSerialPort;
#endif
InTheHand.Net.Bluetooth.Widcomm.WidcommSerialPort _wcSerialPort;
[MenuItem, SubMenu("Serial")]
public void BtWcSerialPortCliClose()
{
#if NETCF
_btSerialPort.Close();
_btSerialPort = null;
#endif
_wcSerialPort.Close();
_wcSerialPort = null;
}
[MenuItem, SubMenu("Serial")]
public void BtWcSerialPortCliNullNoDispose()
{
#if NETCF
_btSerialPort = null;
#endif
_wcSerialPort = null;
}
#if NETCF
[MenuItem, SubMenu("Serial")]
public void BtSerialPortCliConnect()
{
var addr = console.ReadBluetoothAddress("target");
var addrWithSpp = new BluetoothEndPoint(addr, BluetoothService.SerialPort);
var spp = InTheHand.Net.Ports
.BluetoothSerialPort.CreateClient(addrWithSpp);
console.WriteLine("Success: {0}", spp.PortName);
_btSerialPort = spp;
}
#endif
[MenuItem, SubMenu("Serial")]
public void WcSerialPortCliConnect()
{
var addr = console.ReadBluetoothAddress("Target Device");
var count = console.ReadOptionalInteger("Repeat count");
console.WriteLine(null);
Converter<BluetoothAddress, InTheHand.Net.Bluetooth.Widcomm.WidcommSerialPort> open
= addrI =>
{
var spp = InTheHand.Net.Bluetooth.Widcomm
.WidcommSerialPort.CreateClient(addrI);
console.WriteLine("Success: {0}", spp.PortName);
return spp;
};
//
if (count == null) {
_wcSerialPort = open(addr);
} else {
for (int i = 0; i < count; ++i) {
using (var spp = open(addr)) {
}
}//for
}
}
#endif
//--------
[MenuItem, SubMenu("SOCKETS")]
public void TestsSocketsAndSockaddr()
{
Converter<bool, System.Net.Sockets.Socket> createSocket = delegate(bool unspecificProto)
{
System.Net.Sockets.Socket s0;
if (unspecificProto)
s0 = new System.Net.Sockets.Socket(
AddressFamily32.Bluetooth, System.Net.Sockets.SocketType.Stream,
System.Net.Sockets.ProtocolType.Unspecified);
else
s0 = new System.Net.Sockets.Socket(
AddressFamily32.Bluetooth, System.Net.Sockets.SocketType.Stream,
BluetoothProtocolType.RFComm);
return s0;
};
BluetoothEndPoint ep;
System.Net.Sockets.Socket s;
//
int step = 0;
console.WriteLine("#{0}, gonna createSocket(false)", ++step);
s = createSocket(false);
ep = new BluetoothEndPoint(
BluetoothAddress.None,
BluetoothService.ObexFileTransfer);
console.WriteLine("#{0}, gonna Bind", ++step);
// Bind None/FTP/None
try {
s.Bind(ep);
} catch (Exception ex) {
console.WriteLine(ex);
}
ep = new BluetoothEndPoint(
BluetoothAddress.Parse("12345679abcd"),
BluetoothService.ObexObjectPush);
console.WriteLine("#{0}, gonna Connect", ++step);
// Connect Foo/OPP/None
try {
s.Connect(ep);
} catch (Exception ex) {
console.WriteLine(ex);
}
//
console.WriteLine("#{0}, gonna createSocket(false)", ++step);
s = createSocket(false);
ep = new BluetoothEndPoint(
BluetoothAddress.None,
BluetoothService.ObexFileTransfer,
unchecked((Int32)0xF2345678));
console.WriteLine("#{0}, gonna Bind", ++step);
// Bind None/FTP/Bar
try {
s.Bind(ep);
} catch (Exception ex) {
console.WriteLine("Excepted failure");
console.WriteLine(ex);
}
//
ep = new BluetoothEndPoint(
BluetoothAddress.None,
BluetoothService.ObexFileTransfer,
0x45);
console.WriteLine("#{0}, gonna Bind", ++step);
// Bind None/FTP/Bar
try {
s.Bind(ep);
} catch (Exception ex) {
console.WriteLine(ex);
}
//
ep = new BluetoothEndPoint(
BluetoothAddress.Parse("12345679abcd"),
BluetoothService.Fax, 0x45);
console.WriteLine("#{0}, gonna Connect", ++step);
// Connect Foo/OPP/Bar
try {
s.Connect(ep);
} catch (Exception ex) {
console.WriteLine(ex);
}
//
console.WriteLine("#{0}, gonna createSocket(true)", ++step);
try {
s = createSocket(true);
} catch (System.Net.Sockets.SocketException ex) {
const int WSAEPROTOTYPE = 10041;
#if NETCF
if (ex.ErrorCode != WSAEPROTOTYPE)
throw;
#else
if (ex.SocketErrorCode != System.Net.Sockets.SocketError.ProtocolType)
throw;
#endif
Debug.Assert(ex.NativeErrorCode == WSAEPROTOTYPE);
console.WriteLine("(Somewhat) expected failure; how to get 'Unspecified' behaviour supported?");
console.WriteLine(ex);
}
}
[MenuItem, SubMenu("SOCKETS")]
public void TryAllMsftSocketOptions()
{
var wr = _cli;
BluetoothClient cli = null;
if (wr == null || (cli = wr.Target) == null) {
console.WriteLine("No BluetoothClient available, do a Connect/Accept.");
return;
}
var sock = cli.Client;
// Do one get option manually.
{
System.Net.Sockets.SocketOptionName option;
#if NETCF
option = BluetoothSocketOptionName.GetMtu;
#else
option = BluetoothSocketOptionName.XPMtu;
#endif
var v = sock.GetSocketOption(BluetoothSocketOptionLevel.RFComm, option);
var i = (int)v;
console.WriteLine("Option MTU value: {0}=0x{0:X}", i);
}
// Do all known options.
var nameFiList = typeof(BluetoothSocketOptionName).GetFields(
BindingFlags.Static | BindingFlags.Public);
foreach (var curField in nameFiList) {
var curOpt = (System.Net.Sockets.SocketOptionName)curField.GetValue(null);
var curName = curField.Name;
string txtOpt = (int)curOpt >= 0 ? ((int)curOpt).ToString()
: "0x" + ((int)curOpt).ToString("X8");
console.Write("Option: {0,24} {1,11} : ",
curName, txtOpt);
try {
var v = sock.GetSocketOption(BluetoothSocketOptionLevel.RFComm, curOpt);
var i = (int)v;
console.WriteLine("value: {0}=0x{0:X}", i);
} catch (System.Net.Sockets.SocketException soex) {
console.WriteLine("error: " + SocketException_Codes(soex));
}
}//for
}
//--------
[MenuItem, SubMenu("DeviceInfo")]
public void RssiRepeated()
{
console.WriteLine("Stack: {0}", Get_BluetoothRadio().SoftwareManufacturer);
BluetoothAddress addr = console.ReadBluetoothAddress("Address of device to read RSSI for");
bool doSdp = console.ReadYesNo("Do concurrent repeated SDP Query", true);
//
_quitRepeatRssiing.Reset();
try {
ThreadPool.QueueUserWorkItem(RepeatRssiing_ReadRssi, addr);
if (doSdp) { // Doing SDP queries to force forming a connection.
ThreadPool.QueueUserWorkItem(RepeatRssiing_DoSdp, addr);
}
console.WriteLine(null);
console.Pause("Un-pause to stop RSSI-ing");
} finally {
_quitRepeatRssiing.Set();
}
}
ManualResetEvent _quitRepeatRssiing = new ManualResetEvent(false);
void RepeatRssiing_ReadRssi(object state)
{
BluetoothAddress addr = (BluetoothAddress)state;
int delayMs = 1000;
BluetoothDeviceInfo info = Create_BluetoothDeviceInfo(addr);
int? lastRssi = null;
while (!_quitRepeatRssiing.WaitOne(delayMs, false)) {
int rssi = info.Rssi;
console.Write("r");
if (rssi != lastRssi) {
lastRssi = rssi;
console.WriteLine(null);
console.WriteLine("{0:T}: RSSI now: {1}", DateTime.Now, rssi);
}
}//while
}
void RepeatRssiing_DoSdp(object state)
{
Thread.Sleep(5000); // show rssi not available when not connected
//
BluetoothAddress addr = (BluetoothAddress)state;
int delayMs = 1000;
BluetoothDeviceInfo info = Create_BluetoothDeviceInfo(addr);
while (!_quitRepeatRssiing.WaitOne(delayMs, false)) {
ServiceRecord[] records = info.GetServiceRecords(BluetoothService.TcpProtocol);
console.Write("s");
}//while
}
//--------
#if RADIO_MODESSS
[MenuItem, SubMenu("Local")]
public void SetModesss()
{
BluetoothRadio r = Get_BluetoothRadio();
if (r == null) {
console.WriteLine("No radio(?)");
return;
}
console.WriteLine("Radio stack is: {0}", r.SoftwareManufacturer);
var conno = console.ReadYesNoCancel("Connectable (on/off/leave)", null);
var disco = console.ReadYesNoCancel("Discoverable (on/off/leave)", null);
bool doit = console.ReadYesNo("Set radio mode to: c=" + conno + " d=" + disco, true);
if (doit) {
console.WriteLine("Setting Modes({0},{1})", conno, disco);
r.SetMode(conno, disco);
}
}
#endif
[MenuItem, SubMenu("Local")]
public void SetMode()
{
BluetoothRadio r = Get_BluetoothRadio();
if (r == null) {
console.WriteLine("No radio(?)");
return;
}
console.WriteLine("Radio stack is: {0}", r.SoftwareManufacturer);
int choice = console.ReadInteger("0. PowerOff, 1. Connectable, 2. Discoverable");
RadioMode mode = (RadioMode)choice;
bool doit = console.ReadYesNo("Set radio mode to: " + mode, true);
if (doit) {
r.Mode = mode;
}
}
[MenuItem, SubMenu("Local")]
public void SetAllModes()
{
BluetoothRadio r_ = Get_BluetoothRadio();
if (r_ == null) {
console.WriteLine("No radio(?)");
return;
}
console.WriteLine("Radio stack is: {0}", r_.SoftwareManufacturer);
var doIt = console.ReadYesNo("Do Set All Modes", false);
if (!doIt) return;
//
// o->c, o->d; c->o, c->d; d->o, d->c.
var stateList = new RadioMode[] {
RadioMode.PowerOff, RadioMode.Connectable, RadioMode.Connectable, RadioMode.Discoverable,
RadioMode.PowerOff, RadioMode.Discoverable, RadioMode.Discoverable, RadioMode.Connectable,
RadioMode.PowerOff, RadioMode.PowerOff,
};
int i;
var originalMode = r_.Mode;
console.WriteLine("Running test, using same radio instance each time.");
i = 0;
var r0 = r_;
foreach (var cur in stateList) {
console.Write(" Set {0,12}, ", cur);
var ts = RunAndTime(delegate { r0.Mode = cur; });
RadioMode? got = null;
var tg = RunAndTime(delegate { got = r0.Mode; });
if (got != cur)
console.Write("error at {0} expected {1} was {2}, ",
i, cur, got);
console.WriteLine("set: {0,-16}, get: {1,-16}", ts, tg);
++i;
}//for
console.WriteLine("Done {0} tests.", i);
console.WriteLine("Do test again, using new radio instance each time.");
i = 0;
foreach (var cur in stateList) {
var rx = Get_BluetoothRadio();
if (rx == null) {
console.WriteLine("error at {0} radio is null!", i);
goto next;
}
console.Write(" Set {0,12}, ", cur);
var ts = RunAndTime(delegate { rx.Mode = cur; });
RadioMode? got = null;
var tg = RunAndTime(delegate { got = rx.Mode; });
if (got != cur)
console.Write("error at {0} expected {1} was {2}, ",
i, cur, got);
console.WriteLine("set: {0,-16}, get: {1,-16}", ts, tg);
next:
++i;
}//for
console.WriteLine("Done {0} tests.", i);
r_.Mode = originalMode;
}
[MenuItem, SubMenu("Local")]
public void SetName()
{
BluetoothRadio r = Get_BluetoothRadio();
if (r == null) {
console.WriteLine("No radio(?)");
return;
}
console.WriteLine("Radio stack is: {0}", r.SoftwareManufacturer);
var name = console.ReadLine("New Name");
bool doit = console.ReadYesNo("Set radio name to: " + name, true);
if (doit) {
r.Name = name;
}
}
//--------
[MenuItem, SubMenu("Data")]
public void CloseLinger()
{
if (!VerifyConnectionWrite())
return;
BluetoothClient cli = _cli.Target;
if (cli == null) {
console.WriteLine("No BtCli to set LingerState on!.");
return;
}
cli.LingerState = new System.Net.Sockets.LingerOption(true, 30);
// Write until buffers full
List<IAsyncResult> arList = new List<IAsyncResult>();
byte[] buf = new byte[16 * 1024];
bool exitAfterNext = false;
while (true) {
IAsyncResult ar = _peer.BeginWrite(buf, 0, buf.Length, MiscCallback, "BeginWrite");
arList.Add(ar);
console.Write(".");
if (exitAfterNext)
break;
if (!ar.IsCompleted) {
bool signalled = ar.AsyncWaitHandle.WaitOne(10000, false);
if (!signalled) {
exitAfterNext = true;
}
}
}//while
console.WriteLine("Did BeginWrite until full ({0} times).", arList.Count);
//
console.WriteLine("Now going to Close. Release receiver to not linger timeout.");
console.Pause("Un-pause to Close");
console.WriteLine("Closing at {0}", GetTime());
DateTime startT = DateTime.UtcNow;
try {
_peer.Close();
string end = GetTime();
console.WriteLine("Close exited cleanly at {0} after {1}.", end, DateTime.UtcNow - startT);
} catch (Exception ex) { // We throw Exception currently!
string end = GetTime();
console.WriteLine("Close failed at {0} after {1} with: {2}", end, DateTime.UtcNow - startT, ex);
}
//
int i = 0;
console.Write("Write statuses (. or x, where x=exception): ");
foreach (IAsyncResult cur in arList) {
if (!cur.IsCompleted) {
console.WriteLine("Write #{0} is not completed!", i + 1);
}
try {
_peer.EndWrite(cur);
console.Write(".");
} catch (IOException) {
console.Write("x");
}
++i;
}//for
console.WriteLine(null);
console.WriteLine("Finished.");
}
//--------
[MenuItem, SubMenu("Playing")]
public void HackShutdownAll()
{
InTheHand.Net.Bluetooth.Factory.BluetoothFactory.HackShutdownAll();
console.WriteLine("Done HackShutdownAll");
}
//--------
#if NETCF
[MenuItem, SubMenu("Playing")]
public void HidEnable_NotCompletedTesting()
{
IntPtr h = CreateFile("BHI0:", 0, 0, IntPtr.Zero, CreateFile__OPEN_EXISTING, 0, IntPtr.Zero);
if (h == IntPtr.Zero || h == (IntPtr)(-1)) {
int err = Marshal.GetLastWin32Error();
console.WriteLine("CreateFile(BHI0:) returned: {0}, gle: {1} = 0x{1:X}", h, err);
return;
}
console.WriteLine("CreateFile(BHI0:) SUCCESS");
//console.WriteLine("Skipping for now!!!!!!");
//return;
//----
int tmp;
BluetoothAddress addr = console.ReadBluetoothAddress("Device address");
byte[] addrBytes = addr.ToByteArray();
bool ret = DeviceIoControl(h, BTHHID_IOCTL_HIDConnect, addrBytes, addrBytes.Length,
IntPtr.Zero, 0, out tmp, IntPtr.Zero);
int err2 = Marshal.GetLastWin32Error();
console.WriteLine("DeviceIoControl(h, BTHHID_IOCTL_HIDConnect) ret: {0}", ret);
if (!ret) {
console.WriteLine("DeviceIoControl(h, BTHHID_IOCTL_HIDConnect) gle: {0} = 0x{0:X}", err2);
}
}
// http://read.pudn.com//downloads123/sourcecode/embed/523853/BLUETOOTH/PROFILES/HID/BASE/hidioctl.h__.htm
const int BTHHID_IOCTL_HIDConnect = 1;
const int BTHHID_IOCTL_HIDVerify = 2;
const int CreateFile__OPEN_EXISTING = 3;
[System.Runtime.InteropServices.DllImport("coredll.dll", SetLastError = true)]
static extern IntPtr CreateFile(string lpFileName, UInt32 dwDesiredAccess,
UInt32 dwShareMode, IntPtr lpSecurityAttributes, UInt32 dwCreationDisposition,
UInt32 dwFlagsAndAttributes, IntPtr hTemplateFile);
[System.Runtime.InteropServices.DllImport("coredll.dll", SetLastError = true)]
private static extern bool DeviceIoControl(IntPtr hDevice, int dwIoControlCode, byte[] lpInBuffer, int nInBufferSize, byte[] lpOutBuffer, int nOutBufferSize, out int lpBytesReturned, IntPtr lpOverlapped);
[System.Runtime.InteropServices.DllImport("coredll.dll", SetLastError = true)]
private static extern bool DeviceIoControl(IntPtr hDevice, int dwIoControlCode, byte[] lpInBuffer, int nInBufferSize, IntPtr lpOutBuffer, int nOutBufferSize, out int lpBytesReturned, IntPtr lpOverlapped);
[System.Runtime.InteropServices.DllImport("coredll.dll", SetLastError = true)]
private static extern bool DeviceIoControl(IntPtr hDevice, int dwIoControlCode, IntPtr lpInBuffer, int nInBufferSize, IntPtr lpOutBuffer, int nOutBufferSize, out int lpBytesReturned, IntPtr lpOverlapped);
#endif
#if NETCF
[System.Runtime.InteropServices.DllImport("coredll.dll", SetLastError = true, CharSet = CharSet.Unicode)]
private static extern int EnumDevices([Out]char[] devList, ref int bufLen);
[MenuItem, SubMenu("Playing")]
public void EnumDevices()
{
var buf = new char[4096];
int bufLen = buf.Length; // Docs don't say measured in bytes or wchars! Be conservative
//const int ERROR_MORE_DATA = 234;
var ret = EnumDevices(buf, ref bufLen);
if (ret != 0) {
console.WriteLine("!! EnumDevices failed: {0}", ret);
}
int dbgCharsUsed;
var list = ParseDoubleNullTerminatedStrings(buf, out dbgCharsUsed);
Debug.Assert(dbgCharsUsed * 2 == bufLen, "is measured in bytes");
var x = list.Count;
const string Sep = ", ";
var all = string.Join(Sep, list.ToArray());
console.WriteLine(all);
//
//
TestParseDoubleNullTerminatedStrings();
}
private static List<string> ParseDoubleNullTerminatedStrings(char[] buf, out int dbgCharsUsed)
{
int idx = 0;
var list = new List<string>();
while (true) {
if (buf[idx] == 0) {
break;
}
var idxEnd = Array.IndexOf(buf, (char)0, idx);
var len = idxEnd - idx;
var str = new string(buf, idx, len);
list.Add(str);
idx = idxEnd + 1;
}
dbgCharsUsed = idx + 1;
return list;
}
static void TestParseDoubleNullTerminatedStrings()
{
var buf = new char[30];
List<string> list;
const char NullChar = (char)0;
//
list = DoTestParse(new char[]{
'a','b','c',NullChar,
'e','f',NullChar,
'm','n','o','p',NullChar,
NullChar });
Assert_AreEqual(3, list.Count, "A Count");
Assert_AreEqual(3, list[0].Length, "A0 Len");
Assert_AreEqual("abc", list[0], "A0 Count");
Assert_AreEqual(2, list[1].Length, "A1 Len");
Assert_AreEqual("ef", list[1], "A1");
Assert_AreEqual(4, list[2].Length, "A2 Len");
Assert_AreEqual("mnop", list[2], "A2");
//
// Null at start -- (like first is empty)
list = DoTestParse(new char[]{
NullChar,
NullChar });
Assert_AreEqual(0, list.Count, "00 B list.Count");
//
// None -- NOT double null, is valid
list = DoTestParse(new char[]{
NullChar,'*','*'});
Assert_AreEqual(0, list.Count, "C Count");
//
// First is empty -- same as all empty
list = DoTestParse(new char[]{
NullChar,
'e','f',NullChar,
NullChar });
Assert_AreEqual(0, list.Count, "D Count");
//
// Second is empty -- same as termination
list = DoTestParse(new char[]{
'a','b','c',NullChar,
NullChar,
'm','n','o','p',NullChar,
NullChar });
Assert_AreEqual(1, list.Count, "E Count");
Assert_AreEqual(3, list[0].Length, "E0 Len");
Assert_AreEqual("abc", list[0], "E0 Count");
}
private static void FillWithRubbish(char[] buf)
{
for (int i = 0; i < buf.Length; ++i) buf[i] = 'z';
}
private static void Assert_AreEqual(int expected, int actual, string name)
{
if (expected != actual) throw new RankException(name);
}
private static void Assert_AreEqual(string expected, string actual, string name)
{
if (expected != actual) throw new RankException(name);
}
private static List<string> DoTestParse(char[] content)
{
char[] buf;
//
buf = new char[content.Length * 2];
FillWithRubbish(buf);
content.CopyTo(buf, 0);
int dbgUsed;
var list = ParseDoubleNullTerminatedStrings(buf, out dbgUsed);
//TODO assert on dbgUsed
return list;
#if false
//
buf = new char[content.Length];
FillWithRubbish(buf);
content.CopyTo(buf, 0);
list = ParseDoubleNullTerminatedStrings(buf, buf.Length);
#endif
}
#endif
//--------
#if !NETCF
[MenuItem]
public void Win32EventsNew()
{
var r = Get_BluetoothRadio();
// Better be MSFT+Win32 radio!!!
using (var x = new BluetoothWin32Events(r)) {
x.InRange += HandleWin32InRange;
x.OutOfRange += HandleWin32OutOfRange;
console.Pause("Continue to stop getting events");
}
}
[MenuItem]
public void Win32EventsShared()
{
var r = Get_BluetoothRadio();
// Better be MSFT+Win32 radio!!!
var x = BluetoothWin32Events.GetInstance();
try {
x.InRange += HandleWin32InRange;
x.OutOfRange += HandleWin32OutOfRange;
console.Pause("Continue to stop getting events");
} finally {
x.InRange -= HandleWin32InRange;
x.OutOfRange -= HandleWin32OutOfRange;
}
}
void HandleWin32InRange(object sender, BluetoothWin32RadioInRangeEventArgs e)
{
console.WriteLine("{0}: InRange {1} '{2}', now '{3}' was '{4}'.",
GetTimeWallclockHR(), e.Device.DeviceAddress, e.Device.DeviceName,
e.CurrentState, e.PreviousState);
}
void HandleWin32OutOfRange(object sender, BluetoothWin32RadioOutOfRangeEventArgs e)
{
console.WriteLine("{0}: OutOfRange {1} '{2}'.",
GetTimeWallclockHR(), e.Device.DeviceAddress, e.Device.DeviceName);
}
#endif
#if !NETCF && false
[MenuItem, SubMenu("Playing")]
public void AllIoctls()
{
console.WriteLine("Output is on Debug.Write...");
InTheHand.Net.Bluetooth.Msft.MsftPlaying.AllIoctls();
}
[MenuItem, SubMenu("Playing")]
public void AuthDeviceExFakeOob()
{
var device = console.ReadBluetoothAddress("target");
byte[] oobData;
int ret;
//
oobData = new byte[16];
new Random().NextBytes(oobData);
ret = InTheHand.Net.Bluetooth.Msft.MsftPlaying.AuthDeviceExFakeOob(
device, oobData);
console.WriteLine("ret: {0} = 0x{0:X}", ret);
}
[MenuItem, SubMenu("Playing")]
public void AuthDeviceExFakeOob_ThreeWays()
{
var device = console.ReadBluetoothAddress("target");
byte[] oobData;
int ret;
//
oobData = new byte[16];
new Random().NextBytes(oobData);
ret = InTheHand.Net.Bluetooth.Msft.MsftPlaying.AuthDeviceExFakeOob(
device, oobData);
console.WriteLine("ret: {0} = 0x{0:X}", ret);
//
oobData = new byte[32];
ret = InTheHand.Net.Bluetooth.Msft.MsftPlaying.AuthDeviceExFakeOob(
device, oobData);
console.WriteLine("ret: {0} = 0x{0:X}", ret);
//
oobData = null;
ret = InTheHand.Net.Bluetooth.Msft.MsftPlaying.AuthDeviceExFakeOob(
device, oobData);
console.WriteLine("ret: {0} = 0x{0:X}", ret);
}
#endif
#if false
[MenuItem, SubMenu("Playing")]
public void BlueZSdpDumpSdpBlueZDbus()
{
var b = new ServiceRecordBuilder();
b.AddServiceClass(0x1105);
b.AddServiceClass(BluetoothService.SerialPort);
b.AddServiceClass(0x12345);
//
b.AddCustomAttribute(0x500, ElementType.Boolean, false);
b.AddCustomAttribute(0x501, ElementType.Boolean, true);
b.AddCustomAttribute(0x511, ElementType.Nil, null);
//
// UUID128 (AddServiceClass shortens automatically)
b.AddCustomAttribute(0x1000, ElementType.Uuid128, BluetoothService.SerialPort);
var g128 = new Guid("{54D39E6A-2AF2-47dd-BB14-59C476CF2848}");
b.AddCustomAttribute(0x1001, ElementType.Uuid128, g128);
//
b.AddCustomAttribute(0x6000 + (ushort)ElementType.UInt8, ElementType.UInt8, (int)ElementType.UInt8);
b.AddCustomAttribute(0x6000 + (ushort)ElementType.UInt16, ElementType.UInt16, 0xfe00 + (int)ElementType.UInt16);
b.AddCustomAttribute(0x6000 + (ushort)ElementType.UInt32, ElementType.UInt32, 0xfe00 + (int)ElementType.UInt32);
b.AddCustomAttribute(0x6000 + (ushort)ElementType.UInt64, ElementType.UInt64, 0xfe00 + (int)ElementType.UInt64);
var arr128 = new byte[16];
arr128[0] = 0xfe;
arr128[15] = (byte)ElementType.UInt64;
//b.AddCustomAttribute(0x6000 + (ushort)ElementType.UInt128, ElementType.UInt128, arr128);
//b.AddCustomAttribute(new ServiceAttribute(0x6000 + (ushort)ElementType.UInt128,
// new ServiceElement(ElementType.UInt128, arr128)));
//
b.AddCustomAttribute(0x7000 + (ushort)ElementType.Int8, ElementType.Int8, (int)ElementType.Int8);
b.AddCustomAttribute(0x7000 + (ushort)ElementType.Int16, ElementType.Int16, 0x7e00 + (int)ElementType.Int16);
b.AddCustomAttribute(0x7000 + (ushort)ElementType.Int32, ElementType.Int32, 0x7e00 + (int)ElementType.Int32);
b.AddCustomAttribute(0x7000 + (ushort)ElementType.Int64, ElementType.Int64, 0x7e00 + (int)ElementType.Int64);
//
b.AddCustomAttribute(new ServiceAttribute(0x7000,
new ServiceElement(ElementType.ElementAlternative,
ServiceElement.CreateNumericalServiceElement(ElementType.UInt8, 1),
ServiceElement.CreateNumericalServiceElement(ElementType.UInt8, 2))));
var foo = true;
if (foo) {
b.ServiceName = "foo";
}
//----
var s = new BluezSdpXmlWriter().Write(b.ServiceRecord);
console.WriteLine(s);
//----
var rOut = new BluezSdpXmlReader().Read(s);
console.WriteLine(ServiceRecordUtilities.Dump(rOut));
//================
//
new BluezSdpReaderTests().One();
new BluezSdpReaderTests().Two_UnterminatedEntity();
}
#endif
//--------
public static string ToStringQuotedOrNull<T>(T obj)
{
if (obj == null)
return "(null)";
else
return obj.ToString();
}
static string Exception_FirstLine(Exception ex)
{
string line;
using (StringReader rdr = new StringReader(ex.ToString())) {
line = rdr.ReadLine();
}
var soex = ex as System.Net.Sockets.SocketException;
if (soex != null) {
line += SocketException_Codes(soex);
}
return line;
}
static string SocketException_Codes(System.Net.Sockets.SocketException soex)
{
string line = null;// string.Empty;
line += " (" + soex.ErrorCode; // int
#if !NETCF
line += " " + soex.SocketErrorCode; // Enum name
#endif
line += ")";
return line;
}
static bool _WaitAll(WaitHandle[] events, int timeout)
{
#if false && !NETCF
return WaitHandle.WaitAll(events, timeout);
#else
var final = DateTime.UtcNow.AddMilliseconds(timeout);
foreach (var curE in events) {
TimeSpan curTo = final.Subtract(DateTime.UtcNow);
if (curTo.CompareTo(TimeSpan.Zero) <= 0) {
Debug.Fail("Should we expect to get here? Normally exit at !signalled below...");
return false;
}
bool signalled = curE.WaitOne((int)curTo.TotalMilliseconds, false);
if (!signalled) {
return false;
}
}//for
return true;
#endif
}
static TimeSpan RunAndTime(ThreadStart method)
{
var start = DateTime.UtcNow;
method();
var time = DateTime.UtcNow - start;
return time;
}
}//class
}