I am trying to write a program that makes a phone call via bluetooth
and return my balance (money). I am using the 32feet.net bluetooth api.
BluetoothAddress addr = device.DeviceAddress;
BluetoothEndPoint rep = new BluetoothEndPoint(addr, BluetoothService.Handsfree);
BluetoothClient cli = new BluetoothClient();
cli.Connect(rep);
Stream peerStream = cli.GetStream();
String dialCmd4 = "ATD*100#;\r";
Byte[] sRes = new Byte[200];
Byte[] dcB = System.Text.Encoding.ASCII.GetBytes(dialCmd4);
peerStream.Write(dcB, 0, dcB.Length);
peerStream.Read(sRes, 0, 199);
string t4 = "\n\r----------\n\r" + System.Text.Encoding.ASCII.GetString(sRes);
peerStream.Close();
cli.Close();
This code make a regular call but doesn't return a message containing my balance,
and in the phone I can see this message "number not assigned".
Using ATD to send SS (supplementary service) USSD (Unstructured Supplementary Service Data) commands will in the very, very, very best case only work for a small subset (or not at all. When you enter those number using the MMI they are parsed by a completely different entity than the one parsing AT commands).
What you really want to do is to use those AT commands that have specifically been written to support sending SS or USSD. For USSD you use
AT+CUSD=[<n>[,<str>[,<dcs>]]]
See the 3GPP 27.007 specification for details.
Related
I have a USB HID device that I would like to communicate with. I am successfully doing so on Windows using the HidSharp library (link: https://github.com/treehopper-electronics/HIDSharp). My Windows application is developed using the .NET Framework 4.5, C#, and Visual Studio.
I now want to communicate with this same USB HID device from an Android tablet instead of from the Windows desktop. I am encountering some problems doing so. When I have the device plugged in to my tablet, it reports a single interface with a single "read" endpoint. Here is what is reported to me:
Interface #0
Class: Human Interaction Device (0x3)
Endpoint: #0
Address : 0x81 (10000001)
Number : 1
Direction : Inbound (0x80)
Type : Intrrupt (0x3)
Poll Interval : 1
Max Packet Size: 64
Attributes : 000000011
As you can see, it only reports a single endpoint, which is an inbound endpoint. I need to be able to output simple commands to this device, which I was able to do so successfully on Windows using HidSharp.
HidSharp abstracted everything into a single "stream" object that you could read from and write to. Using the Android APIs, there isn't a single "stream" object, but rather there seem to be 3 different ways of reading/writing: bulk transfer, control transfer, and USB Request. I've tried sending out data using all 3, but with seemingly no success.
Any suggestions on what to do? Is there a reason why I could send out data to this device on Windows, but seemingly cannot do so from Android? Is there a way to use a single endpoint as both a read and a write endpoint? Is there something that I am just obviously missing and not understanding?
I am using Xamarin as my development environment (C#, Visual Studio 2017). Since code is always helpful, here is how I am connecting to the device:
int VendorID = 0x04d8;
int ProductID = 0x2742;
UsbManager USB_Manager = null;
UsbDevice USB_Device = null;
UsbDeviceConnection DeviceConnection = null;
UsbInterface DeviceInterface = null;
UsbEndpoint OutputEndpoint = null;
UsbEndpoint InputEndpoint = null;
//Grab the Android USB manager and get a list of connected devices
var USB_Manager = MyMainActivity.ApplicationContext.GetSystemService(Android.Content.Context.UsbService) as Android.Hardware.Usb.UsbManager;
var attached_devices = USB_Manager.DeviceList;
//Find the device in the list of connected devices
foreach (var d in attached_devices.Keys)
{
if (attached_devices[d].VendorId == VendorID && attached_devices[d].ProductId == ProductID)
{
USB_Device = attached_devices[d];
break;
}
}
//Assuming we found the correct device, let's set everything up
if (USB_Device != null)
{
for (int j = 0; j < USB_Device.InterfaceCount; j++)
{
DeviceInterface = USB_Device.GetInterface(j);
for (int i = 0; i < DeviceInterface.EndpointCount; i++)
{
var temp_ep = DeviceInterface.GetEndpoint(i);
if (temp_ep.Type == Android.Hardware.Usb.UsbAddressing.XferInterrupt)
{
if (temp_ep.Direction == Android.Hardware.Usb.UsbAddressing.In)
{
InputEndpoint = temp_ep;
}
if (temp_ep.Direction == Android.Hardware.Usb.UsbAddressing.Out)
{
OutputEndpoint = temp_ep;
}
}
}
}
//Request permission to communicate with this USB device
UsbReceiver receiver = new UsbReceiver();
PendingIntent pending_intent = PendingIntent.GetBroadcast(Game.Activity, 0, new Android.Content.Intent(UsbReceiver.ACTION_USB_PERMISSION), 0);
IntentFilter intent_filter = new IntentFilter(UsbReceiver.ACTION_USB_PERMISSION);
Game.Activity.RegisterReceiver(receiver, intent_filter);
USB_Manager.RequestPermission(USB_Device, pending_intent);
bool has_permission = USB_Manager.HasPermission(USB_Device);
var device_connection = USB_Manager.OpenDevice(USB_Device);
device_connection.ClaimInterface(DeviceInterface, true);
DeviceConnection = device_connection;
}
Next, here is how I attempt to read from the device:
//3 methods of attempting to read from the device
//Method 1:
byte[] inpt = new byte[64];
var request = new UsbRequest();
request.Initialize(DeviceConnection, InputEndpoint);
var byte_buffer = ByteBuffer.Allocate(64);
request.Queue(byte_buffer, 64);
DeviceConnection.RequestWait();
byte_buffer.Rewind();
for(int i = 0; i < 64; i++)
{
inpt[i] = (byte) byte_buffer.Get();
}
//Method 2:
byte[] inpt = new byte[64];
DeviceConnection.BulkTransfer(InputEndpoint, inpt, inpt.Length, 1000);
//Method 3:
byte[] inpt = new byte[64];
DeviceConnection.ControlTransfer(UsbAddressing.In, 0, 0, 0, inpt, 64, 1000);
And finally, here is how I attempt to write data to this device:
//Method 1:
byte[] output_msg; //This variable is assigned elsewhere in the code
DeviceConnection.BulkTransfer(OutputEndpoint, output_msg, output_msg.Length, 30);
//Method 2:
byte[] output_msg; //This variable is assigned elsewhere in the code
DeviceConnection.ControlTransfer(UsbAddressing.Out, 0, 0, 0, output_msg, output_msg.Length, 1000);
//Method 3:
byte[] output_msg; //This variable is assigned elsewhere in the code
var write_request = new UsbRequest();
write_request.Initialize(DeviceConnection, OutputEndpoint);
var byte_buffer_write = ByteBuffer.Wrap(output_msg);
request.Queue(byte_buffer_write, output_msg.Length);
DeviceConnection.RequestWait();
"OutputEndpoint" is typically null because there is no output endpoint, so I often replace "OutputEndpoint" with "InputEndpoint", but with no success.
Any help would be greatly appreciated! Thanks!!!
You are dealing with HID devices which means you should do Interrupt Transfers.
In Android, you should use UsbRequest to perform Interrupt Transfers (as it does Asynchronous NonBlocking IO).
The endpoints are unidirectional and can be used for both inbounds and outbound (but not at the same time)
If the endpoint is inbound then submit the Urb using UsbRequest and queue as you tried before but using empty buffer with expected bufferLength.
The RequestWait will return UsbRequest Object back upon completion.
If the usbRequest.getEndPoint().getDirection() is inbound then your buffer variable will be updated with read buffer from the device.
If the usbRequest.getEndpoint().getDirection() is outbound then you should pass your buffer to write data to the device
I am using Lapsnapper (a transponder timing system) running on Android.
Lapsnapper enables a TCP/IP server with which a connection can be made, to build a custom interface and get some other relevant data RE: the transponders etc from the system.
I do not understand the Lapsnapper tcp server specification.
I have done some tcp stuff before, but I am mostly a higher level programmer and to be honest I am a bit out of my depth with this raw TCP stuff.
The spec reads:
What I don't understand is how to "send" the tcp data?
I don't understand how 0x70, 0x17 equates to (6000) and 2 bytes...
The same goes for 0x13, 0x00, 0x00, 0x00 = 19 which the spec says should be 4 bytes, but a string of "19" is 2 bytes?
I am trying to understand what I am reading. Any help would be appreciated as I need to do quite a bit of comms to this server, and I want to understand what I am doing...
I have asked for help from lapsnapper support, but in the mean time I would like to learn something new as per the above.
What do I actually "send" on the TCP connection?
The spec says that I should expect a message back, but with my current implementation, a connection seems to be established, but I never receive anything back.
Response Message to expect:
My code:
(P.S This code block works if I do a simple connection to a SMTP server and I can do a basic connection with reply from said smtp server. I however never receive a reply when I try to talk to the Lapsnapper TCP server using the code below)
string lapSnapperIP = "10.0.0.131";
int lapsnapperPort = 9001;
string lapSnapperMessageID;
string lapsnapperLengthOfMessage;
string lapsnapperProductID;
string lapsnapperServerVersion;
string lapsnapperPasswordLength;
string lapsnapperPassword;
lapSnapperMessageID = "6000";
lapsnapperLengthOfMessage = "19"; //to implement
lapsnapperProductID = "50";
lapsnapperServerVersion = "100000";
lapsnapperPasswordLength = "4";
lapsnapperPassword = "1234";
string lapSnapperDataSend;
lapSnapperDataSend = lapSnapperMessageID + lapsnapperLengthOfMessage + lapsnapperProductID + lapsnapperServerVersion + lapsnapperPasswordLength + lapsnapperPassword;
s.Connect(lapSnapperIP, lapsnapperPort);
byte[] sendMessage = Encoding.UTF8.GetBytes(lapSnapperDataSend);
byte[] receiveBytes = new byte[256];
int i = 0;
string receivedMessage = "";
//send data
i = s.Send(sendMessage);
//receive data
i = s.Receive(receiveBytes); // (no reply here...)
receivedMessage = Encoding.UTF8.GetString(receiveBytes);
Thanks
I'm trying to send an array of bytes from android (client) to Linux (server), I can send around 17kB but then the socket send an client socket timeout exception. At the server side I'm using netcat with the next command:
nc -l -p 55000 > out.txt
This works ok because I'm capable of sending files from other computer, for this reason I think the problem is at the client side (Android).
I'm using Visual Studio 2015 with Xamarin to compile the project and I tried many methods to send thought socket with the same result, between 15~20kB sended. Of course the permissions on Android to send through internet and other rights are ok.
This is the first mode I tried:
byte[] data = new byte[200000];
TcpClient client = new TcpClient("192.168.0.245", 55000);
client.SendBufferSize = 8192;
NetworkStream ns = client.GetStream();
ns.ReadTimeout = 1000;
ns.WriteTimeout = 1000;
ns.Write(data, 0, data.Length);
ns.Flush();
ns.Close();
client.Close();
With this method only around 17kB are received and the socket is not closed, but the close methods are executed (I tested it with the debugger placing MessageBox to test in release).
Other method I've tested is this:
IPEndPoint remoteEP = new IPEndPoint(IPAddress.Parse("192.168.0.245"), 55000);
System.Net.Sockets.Socket sender = new System.Net.Sockets.Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
sender.ExclusiveAddressUse = true;
sender.LingerState = new LingerOption(true, 1);
sender.NoDelay = true;
sender.SendBufferSize = 8192;
sender.ReceiveBufferSize = 8192;
sender.SendTimeout = 1000;
sender.ReceiveTimeout = 1000;
sender.Ttl = 42;
try{
byte[] data = new byte[200000];
sender.Connect(remoteEP);
for (int a = 0; a < data.Length;)
{
int len = (data.Length - a) > 8192 ? 8192 : data.Length - a;
a += sender.Send(data, a, len, SocketFlags.None);
}
}
catch (Exception e)
{
string a = e.ToString();
}
The program send the first 8192 bytes and in the second round an socket timeout exception is trowed. If I try to send all the bytes is one time the program executes the send method the returned bytes are the total length of the array, this mean all bytes are sent to the socket but only received 17kB.
I've tested other methods to do the same thing with the same results in two phones. The android version for compiler I'm using is 4.2. For VS and Xamarin the latest.
Also I tried to download an app from the market to send files throught TCP to see if the problem is in Netcat, firewalls, SO or other and the files was sended ok.... I'm very frustated, I think I'm doing well all the things.
Thanks in advance
I have a bluetooth button from Radius networks. The builtin - "add a bluetooth device" finds it every time.
I need the api or a stack that I can use to do from my app. I am doing this in c#. the library 32 feet is not compatible
To enumerate RFCOMM Bluetooth devices attached to a device, do:
var DEVICE_ID = new Guid("{00000000-0000-0000-0000-000000000000}"); //Enter your device's RFCOMM service id (try to find it on manufactorer's website
var services = await Windows.Devices.Enumeration.DeviceInformation.FindAllAsync(
RfcommDeviceService.GetDeviceSelector(
RfcommServiceId.FromUuid(DEVICE_ID)));
To connect to a the first available device, do:
if (services.Count > 0)
{
var service = await RfcommDeviceService.FromIdAsync(services[0].Id);
//Open a socket to the bluetooth device for communication. Use the socket to communicate using the device's API
var socket = new StreamSocket();
await socket.ConnectAsync(service.ConnectionHostName, service.ConnectionServiceName, SocketProtectionLevel
.BluetoothEncryptionAllowNullAuthentication); //Substitue real BluetoothEncryption
}
To send data to the device and read data back, do:
var BYTE_NUM = 64 as UInt32; //Read this many bytes
IInputStream input = socket.InputStream;
IOutputStream output = socket.OutputStream;
var inputBuffer = new Buffer();
var operation = input.ReadAsync(inputBuffer, BYTE_NUM, InputStreamOptions.none);
while (!operation.Completed) Thread.Sleep(200);
inputBuffer = operation.GetResults();
var resultReader = DataReader.FromBuffer(inputBuffer);
byte[] result = new byte[BYTE_NUM];
resultReader.ReadBytes(result);
resultReader.Dispose();
//Do something with the bytes retrieved. If the Bluetooth device has an api, it will likely specify what bytes will be sent from the device
//Now time to give some data to the device
byte[] outputData = Encoding.ASCII.GetBytes("Hello, Bluetooth Device. Here's some data! LALALALALA");
IBuffer outputBuffer = outputData.AsBuffer(); //Neat method, remember to include System.Runtime.InteropServices.WindowsRuntime
operation = output.WriteAsync(outputBuffer);
while (!operation.Completed) Thread.Sleep(200);
await output.FlushAsync(); //Now the data has really been written
This will work for all RFCOMM (normal) bluetooth devices, if your device uses Bluetooth Low Energy please use the corresponding GATT classes.
I am trying to provide a "click to dial" solution for someone to a bluetooth device such as a mobile phone. I have been trying to do so using the 32feet.net bluetooth api.
I haven't really done anything with bluetooth (since the days of at commands via a bluetooth serial port) but I have paired the device in question, which supports the handsfree service with the pc. I have the following code to attempt to connect and send a dial command.
String deviceAddr = "11:11:11:11:11:11";
BluetoothAddress addr = BluetoothAddress.Parse(deviceAddr);
BluetoothEndPoint rep = new BluetoothEndPoint(addr, BluetoothService.Handsfree);
BluetoothClient cli = new BluetoothClient();
cli.Connect(rep);
Stream peerStream = cli.GetStream();
String dialCmd = "ATD 0000000000\r\n";
Byte[] dcB = System.Text.Encoding.ASCII.GetBytes(dialCmd);
peerStream.Write(dcB, 0, dcB.Length);
// Begin Edit ------------------------------------------------------------
Byte[] sResponse = new Byte[100];
peerStream.Read(sResponse, 0, 99);
TextBox1.Text = System.Text.Encoding.ASCII.GetString(sResponse);
// End Edit --------------------------------------------------------------
peerStream.Close();
cli.Close();
MessageBox.Show("Done");
Since it seems to run through these lines of code, taking an appropriate time to connect at the relevant spot or crashing out if the device address is wrong and it can't connect. Obviously the AT command is not the right thing to be sending it.
Can anyone enlighten me as to what I might need to send to a bluetooth device via the handsfree profile to get it to dial?
Begin Edit -------------------------------------------
I decided to read from the stream and see if there was a response of any sort after sending the AT command through. Since I am just testing to see if I can make it work I am just dumping the response into a textbox.
The response I read from the stream is :
ERROR
There doesn't seem to be an error codes or anything.
End Edit ---------------------------------------------
Edit --------------------------------------------------
Sent command : AT+CMER\r
Result : OK
then
Sent command : AT+CIND=?\r
Result :
+CIND: ("service",(0-1)),("call",(0-1)),("callsetup",(0-3)),("battchg",(0-5)),("signal",(0-5)),("roam",(0-1)),("callheld",(0-2))
then
Send command : ATD 0000000000\r
Result:
OK
D: ("service",(0-1)),("call",(0-1)),("callsetup",(0-3)),("battchg",(0-5)),("signal",(0-5)),("roam",(0-1)),("callheld",(0-2))
Still it doesn't actually dial :(
End Edit ----------------------------------------------
Solution ----------------------------------------------
The following code now works to dial via my iPhone. It's really rough at the moment, as I have just been testing to see if I could make it work. It's enough to get started for anyone else wanting to do a similar thing.
String deviceAddr = "00:00:00:00:00:00";
BluetoothAddress addr = BluetoothAddress.Parse(deviceAddr);
BluetoothEndPoint rep = new BluetoothEndPoint(addr, BluetoothService.Handsfree);
BluetoothClient cli = new BluetoothClient();
cli.Connect(rep);
Stream peerStream = cli.GetStream();
String dialCmd1 = "AT+CMER\r";
String dialCmd2 = "AT+CIND=?\r";
String dialCmd3 = "AT+BRSF=\r";
String dialCmd4 = "ATD 0000000000;\r";
Byte[] dcB = System.Text.Encoding.ASCII.GetBytes(dialCmd1);
peerStream.Write(dcB, 0, dcB.Length);
Byte[] sRes = new Byte[200];
peerStream.Read(sRes, 0, 199);
textBox1.Text = textBox1.Text + "\n\r----------\n\r" + System.Text.Encoding.ASCII.GetString(sRes);
dcB = System.Text.Encoding.ASCII.GetBytes(dialCmd2);
peerStream.Write(dcB, 0, dcB.Length);
peerStream.Read(sRes, 0, 199);
textBox1.Text = textBox1.Text + "\n\r----------\n\r" + System.Text.Encoding.ASCII.GetString(sRes);
dcB = System.Text.Encoding.ASCII.GetBytes(dialCmd3);
peerStream.Write(dcB, 0, dcB.Length);
peerStream.Read(sRes, 0, 199);
textBox1.Text = textBox1.Text + "\n\r----------\n\r" + System.Text.Encoding.ASCII.GetString(sRes);
dcB = System.Text.Encoding.ASCII.GetBytes(dialCmd4);
peerStream.Write(dcB, 0, dcB.Length);
peerStream.Read(sRes, 0, 199);
textBox1.Text = textBox1.Text + "\n\r----------\n\r" + System.Text.Encoding.ASCII.GetString(sRes);
peerStream.Close();
cli.Close();
Try to find what is the response for AT\r (or) ATH\r.
If the response is "OK\r\n", try your dial command with no space after ATD and number.
As maintainer of 32feet.NET I'd love to find the answer to this. Hopefully someone with knowledge of HSP/HFP will explain why this doesn't work. My only general guess is that since we're not accepting/creating the SCO channel for the audio channel the phone refuses the connection.
Once thing in your case however... AT commands are terminated by a CR (0Dh); or does the semicolon act the same??