Android USB serial port used from shared library... How? - android

Am I developing an Android app (in Embarcadero Delphi 10.3) that will use the HamLib library for controlling radios, etc. I've compiled the library (libhamlib.so) with the NDK, and works. I can use the library from the application created with Delphi, but only if using the network connection. (the library connects to another maching, running a server to control the radio)
The goal, however, is to control the radio directly from the Android app with an USB to serial adapter connected to the Android device.
The problem is permissions. I've looked with an rooted phone that /dev/ttyUSB0 is created when the USB serial adapter is inserted. But the permissions on the device is crw------- and owned by root. So the application does not have permission to use the device.
I've tried setting permissions in AndroidManifest.xml and also added Intents (so my app gets called when inserting the USB adapter)
I have also played with the UsbManager and it says the app has permissions. The UsbManager reports the device as /dev/bus/usb/001/001 though, so something is not right. If i tell the library to use /dev/bus/usb/001/001 it fails aswell. And the /dev/bus/usb/001/001 is not the same major minor character device as /dev/ttyUSB0
Anyone out there with experience with Android and serial ports, and of course using the serial port from a shared library?

You could try using usb-serial-for-android library, compile it into a .jar file and add this to your Delphi project.

I use the Comport for Android USB Serial library from Winsoft, and as you can see from this page https://www.winsoft.sk/acpusbser.htm, it has build in functions to obtain permission from the user to use the comport. I'm pasting is some code from 1 of my projects to give you an idea of how Winsoft library requires this to be handled.
procedure TfrmLiveMain.RefreshDevices;
var
i: Integer;
IDString: String;
Device: JUsbDevice;
begin
UsbDevices := UsbSerial.UsbDevices;
if UsbDevices = nil then
EXIT;
if Length(UsbDevices) = 0 then
begin
Sound(50);
Vibrate(25);
FToast.MakeToast('No USB serial devices were found!');
EXIT;
end;
for i := 0 to 1 {Length(UsbDevices)} - 1 do
begin
Device := UsbDevices[i];
if TJBuild_VERSION.JavaClass.SDK_INT >= 21 then
IDString := JStringToString(Device.getManufacturerName) + ' ' +
JStringToString(Device.getProductName)
else
IDString := JStringToString(Device.getDeviceName);
end;
if not UsbSerial.IsSupported(Device) then
raise Exception.Create(IDString + ' is not a supported device!');
// give them 2 chances to grant permission
if not UsbSerial.HasPermission(Device) then
begin
UsbSerial.RequestPermission(Device);
if not UsbSerial.HasPermission(Device) then
begin
PermTimer.Enabled := True; // begin permission loop ->
EXIT;
end;
end;
procedure TfrmLiveMain.PermTimerTimer(Sender: TObject);
var
Device: JUsbDevice;
begin
PermTimer.Enabled := False;
Device := UsbDevices[0];
if UsbSerial.HasPermission(Device) then
RefreshDevices; // and try open ->
end;
Now of course, I can't say if this is what you need for the Hamlib library, so this is an extended comment, and not really an answer.

Related

Can't connect to server Resolve/ConnectTimeout error

I have a common problem on Android only that I don't know how to reproduce on demand. It happens on Android 7, 9 and 11. Internet permission is enable and accepted on the app.
When we open the application, a call to my server is done.
function TXXVersion.GetVersion : IXXVersion;
var
LVSPortType : VersionServicePortType; // generate from wsdl
LIdURI: TIdURI;
begin
Result := nil;
if Assigned(FWebServiceHelper.PrepareCall(VersionServicePortType, LVSPortType, false)) then
begin
LIdURI := TIdURI.Create('https://my-backend.test.com');
try
Result := ParseVersion(LVSPortType.GetVersion, LIdURI.Host);
finally
LIdURI.Free;
end;
end;
end;
I got the system error message :
An unexpected error (EIdResolveError) occurred with message:
Error resolving Address my-backend.test.com:
No address associated with hostname (7)
If I try
to ping my-backend.test.com or access with a webbrowser it's ok
try several times I'll end up with a EIdConnectTimeout
If I reboot my phone, it works until 2-3 days and then I will get this error again.
I never got this problem on other plateform, that's only on Android. I see nothing other with adb.

IdIcmpclient.ping() under Android returns Socket error #1 - Delphi Rio 10.3

Thanks to the help of many Stackoverflow contributors, I have successfully completed my Windows VCL project to, ping a number of IP Addresses, add them to an SQLtable, sort them by ping time and automatically set the IpV4 DNS settings to the fastest 2 addresses. This works perfectly under Windows.
I am now trying to create a similar application running under Android. I am using idIcmpclient to ping the addreses and pick up the IdICMPClient1.ReplyStatus.MsRoundTripTime. The code compiles and installs on my Android test device(s). However when run under Android, I receive a Socket #1 error. The testing code is below.
procedure TForm1.Button1Click(Sender: TObject);
var
ipAddr: string;
begin
ipAddr := '188.132.234.170';
IdIcmpClient1.ReceiveTimeout := 200;
IdIcmpClient1.Host := ipAddr;
IdIcmpClient1.ping();
if IdIcmpClient1.ReplyStatus.ReplyStatusType = rsEcho then
begin
Memo1.Lines.Add(IntToStr(IdIcmpClient1.ReplyStatus.MsRoundTripTime));
Memo1.Lines.Add(IdIcmpClient1.ReplyStatus.Msg)
end
else if IdIcmpClient1.ReplyStatus.ReplyStatusType = rsTimeout then
begin
// have a timeout, link is down
end
else
begin
// do something else
end;
end;
I have looked to see if there are peculiarities with IdIcmpclient and other OS's and have found out that it does not work with iOS , something to do with Raw Sockets.
I am assuming that maybe the same case applies to Android, which leaves me with a bit of a problem and possibly an untimely end to my new Android project.
If IdIcmpClient.Ping does not work under Android, is there an alternative method to Ping addresses and get the return times.
Any help much appreciated

How can I connect to a Bluetooth module using Delphi XE8?

I have with my delphi code found the device I want to connect to and display services available. When I do the DiscoverServices for the device I found the method returns false meaning it didn't started. I suspect that this is because the device is not connected.
Following the example in https://developer.android.com/guide/topics/connectivity/bluetooth-le.html#read I do the whole discover part but I have found no equal thing in delphi that does
device.connectGatt(this, false, mGattCallback)
How do I go about to connect the device to my android phone in Delphi?
Am currently doing like the following
FBLEDevice := FBluetoothManagerLE.LastDiscoveredDevices.First;
FBLEDevice.OnServicesDiscovered := GetServicesAndCharacteristics;
if FBLEDevice.DiscoverServices = False then
Memo1.Lines.Add('DiscServ could not start')
else
Memo1.Lines.Add('Discover Services started');
SOLUTION:
You apparently don't need to connect in some special way as I though, the problem that my method won't start was because there are currently no services to discover on the module I am using.

How can I do connection with Bluetooth Printer with Android?

I want to connect with Android to a bluetooth printer with Delphi, using the technique described in the Bluetooth Paired Devices Browser example by David I.
My printer is the Panda BIXOLON SPP-R200II:
I get the Error:
"java.io.IOException: read failed, socket might closed or timeout, read ret: -1"
by sock.connect;
Here is my Code:
procedure TForm1.ListView1ItemClick(const Sender: TObject;
const AItem: TListViewItem);
begin
ShowMessage('You selected: '+Aitem.Text);
// depending on the bluetooth device selected - do something with it
targetMACAddress:=Aitem.Detail;
if trim(targetMACAddress)='' then exit;
Adapter:=TJBluetoothAdapter.JavaClass.getDefaultAdapter;
remoteDevice:=Adapter.getRemoteDevice(stringtojstring(targetMACAddress));
sock:=remoteDevice.createRfcommSocketToServiceRecord(UID);
try
sock.connect;
except
on E : Exception do
ShowMessage(E.Message);
end;
if not sock.isConnected then
begin
ShowMessage('Failed to connect to Try again...');
exit;
end;
listview1.Visible:=false; // hide the chooser
label1.Visible:=false; // hide the chooser
reload.Visible:=false; // hide the chooser
end;
All communication made with the Bluetooth device must be carried out through Threads.
I transcribed a project in Android Studio for Delphi, using threads, and everything worked.
Do not use Timer, use the TThread object.

Flush MTP connection with Android tablet?

I connect a Samsung Galaxy Android tablet with a USB cable to computer running Windows 7. It connects using MTP.
Step 1. Copy my SQLite database from Windows 7 to tablet via Windows Explorer.
Step 2. Open it on the tablet (which adds the android_metadata table) and then close it.
Step 3. Copy the SQLite database back to Windows.
Step 4. Check it using sqlite3.exe. It's corrupt.
Now another test.
Step 1. Copy my SQLite database from Windows 7 to tablet via Windows Explorer
Step 2. Disconnect then reconnect the USB cable.
Step 3. Open it on the tablet (which adds the android_metadata table) and then close it.
Step 3. Copy the SQLite database back to Windows.
Step 4. Check it using sqlite3.exe. It's NOT corrupt.
Interestingly, if I switch steps 2 and 3, it also works.
Since it works when I disconnect and reconnect the USB cable, I'm guessing that I need to flush the MTP cache somehow. How can this be accomplished, or is there an API I can use to quickly disconnect and reconnect the device?
My actual Windows application uses the WPD (Windows Portable Devices) API, I'm just testing using Windows Explorer to prove it's not a problem in my Windows code. I don't see anything in WPD to do a flush.
The error seems to occur when the SQLite database on Android grows by a page (or more). The page size in SQLite is 512 bytes. Looking at the SQLite database's binary data , I can see what's happening. I make the database one page bigger on the device, copy the database off the device, unplug the usb, plug it in, then copy it off again. Comparing the two files, the file I get after I copy the usb data off is the same except it has a lot more data at the end. It's like MTP doesn't understand the file is bigger until you unplug the usb and plug it in again. If you leave USB plugged in it only copies over the number of bytes that were there the last time it copied the file.
Use this function of windows
as shown by this DELPHI example.
procedure shCopyFile(hWndOwner: HWND; const SourceFile, TargetFile: string);
var Info : TSHFileOpStruct;
Aborted : Bool;
begin
Aborted := False;
with Info do
begin
Wnd := hWndOwner;
wFunc := FO_COPY;
// From Microsoft's Help:
// wFunc = Operation to perform. This member can be one of the following values:
// FO_COPY Copies the files specified by pFrom to the location specified by pTo.
// FO_DELETE Deletes the files specified by pFrom (pTo is ignored).
// FO_MOVE Moves the files specified by pFrom to the location specified by pTo.
// FO_RENAME Renames the files specified by pFrom.
pFrom := pChar(SourceFile);
pTo := pChar(TargetFile);
fFlags := 0;
fFlags := FOF_SILENT or FOF_NOCONFIRMATION or FOF_NOERRORUI;
fAnyOperationsAborted := Aborted;
end;
try
SHFileOperation(Info);
finally
if Aborted then; enact upon any user cancellations
end;
end;
I'm copying file from Desktop to Android MTP device PATH
Stefano
www.data-ware.it
I have found exact the same problem on the Samsung Galaxy Tab 2 7.0.
But in my oppinion it is a problem on the android side.
If I force the application which opens the db to stop (System Settings->app manager->my app->force stopp) then it works.
Only "open connection" and "close connection" isn't enough.
The complete process on the android-side has to be closed.
This explains why it works after restarting the device.
Further investigation:
It works perfectly with Galaxy Tab and 4.1.2 (if App-process is closed).
It works with MTP but not PTP (Picture Transfer Protocol).
Both protocols are connecting with WPD-function but PTP is quite inconsistent when writing and reading (so never ever use PTP).

Categories

Resources