I'm having a problem communicating protobufs through tcp sockets where the client is working in Android emulator (running eclipse + ADP + SDK android-15) and the server in C++ (Visual Studio 2010), both on Windows 7. Protobuf version: 2.4.1
.proto
package pck;
option java_package = "my.messages.package";
option java_outer_classname = "ClassName";
option optimize_for = LITE_RUNTIME;
message msg_name {
optional int32 VARIABLE = 6;
//moro...
}
client: android side
msg_name outMsg = to_send.build();
ByteArrayOutputStream output = new ByteArrayOutputStream();
outMsg.writeTo(output);
//now output.toString() is sent via tcp socket...
What I get, and the reason I'm asking here is: communication works, messages reach server endpoint, but values for the int32 variable are as following:
(values sent on android ->> values read on visual-c++ side)
android: [0, 127] ->> visual-c++: [0, 127] Works fine, ok.
android: [128, 255] -->> visual-c++: 3104751
android: [256, 383] -->> visual-c++: 5201903
...
So, is it a problem of encoding? Is my problem with protobufs on client-android side? (I must say it's my first day on android, opss!)
Related
I'am trying to make a android tablet communicate with a USB device (STM32 Nucleo).
I developped a sketch available on github :
the mobile application is developped with Xamarin and VS Studio. It acts as usb host
the STM32 Nucleo application is developped with STMCube and uses it's USB stack to act as a CDC device.
I developped a small master/slave protocol to echange "register" id/value. The device is the slave.
I managed to make it work using the Android.hardware.usb API.
But I must use a native C shared object library for communication as it used on other platform, and that's where I am having trouble now.
I embbeded the library using swig and build it with VS Studio.
I tried two ways to make the library communicate with the device :
From the Android side get permission and fd and pass it to the library that does standard read/write opérations.
From the Android do the same as above, but also pass with fd the endpoints numbers that uses the linux usbdevice_fs API to call bulk transfers; more o less like presented at that question.
Both methods fail and returns an error about the fd that does not exist. I checked the fd and and enpoints values, they're same as the Android.
I launched the android usb device monitor, I can't find the created fd. I can't use any android shell like termux to list the process /proc tree.
But still I can use tehm in the Android side.
From the community I checked that passing fd to the native library is the right method.
I don't know what to do now, is there some more permission to ask ?
Below is how I retrieve the fd :
_devHandle.usbdev = _devHandle.usbManager.DeviceList[name];
// Ask for permission to access the created device
if (!_devHandle.usbManager.HasPermission(_devHandle.usbdev))
{
PendingIntent pi = PendingIntent.GetBroadcast((ContextWrapper)_context, 0, new Intent(ACTION_USB_PERMISSION), 0);
_devHandle.usbManager.RequestPermission(_devHandle.usbdev, pi);
/* We check the permission was given
*/
if (!_devHandle.usbManager.HasPermission(_devHandle.usbdev))
{
// Loose !
Log.Debug("pandavcom", "FAILED : did not have persmission to open device" + _devHandle.usbdev.DeviceName);
return;
}
}
// Now open the port, with the USB Manager : we get the fd/enpoints and pass it to library, no more
_devHandle.connection = _devHandle.usbManager.OpenDevice(_devHandle.usbdev);
if (_devHandle.connection != null)
{
if (OpenInterface(_devHandle.usbdev, _devHandle.connection, ref _devHandle.usbIface, ref _devHandle.ep_in, ref _devHandle.ep_out) == 0)
{
_devHandle.fd = _devHandle.connection.FileDescriptor;
Log.Debug("pandavcom", "opened device endpoint" + _devHandle.usbdev.DeviceName + "with descriptor: " + _devHandle.fd);
}
else
{
Log.Debug("pandavcom", "FAILED : open device endpoint" + _devHandle.usbdev.DeviceName);
}
}
So I made it working, thanks tho the guys of the libusb mailing list.
Actually the mad resistor libusb could only send data to device.
Now with the officiel libusb there's a way to do it, that is still recent.
So the process is :
get with android the device permission and the file descriptor
pass the file descriptor to your native code and execute this step to
initliaze libusb on the fd :
libusb_context *ctx;
enum libusb_error rc;
rc = libusb_set_option(&ctx, LIBUSB_OPTION_WEAK_AUTHORITY, NULL);
if (rc != LIBUSB_SUCCESS) {
__android_log_print(ANDROID_LOG_ERROR, TAG,"libusb_init failed: %d\n", ret);
return -1;
}
ret = libusb_init(&ctx);
if (ret < 0) {
__android_log_print(ANDROID_LOG_INFO, TAG,
"libusb_init failed: %d\n", ret);
return 1;
}
libusb_device_handle *devh = NULL;
ret = libusb_wrap_sys_device(NULL, (intptr_t)FD, &devh);
if (ret < 0) {
__android_log_print(ANDROID_LOG_INFO, TAG,
"libusb_wrap_sys_device failed: %d\n", ret);
return 2;
}
else if (devh == NULL) {
__android_log_print(ANDROID_LOG_INFO, TAG,
"libusb_wrap_sys_device returned invalid handle\n");
return 3;
}
(FD = FileDescriptor from Android.USBManager)
The code above was sent over the mailing.
An example of integration is available on my github project.
I'm still validating this solution on more Android tablet.
Android grpc client is receiving GOAWAY from server with "too many pings" error. Now I realise that this is probably a server side issue, but I think the issue is that the client channel settings do not match that of the servers.
I have a C# gRPC server with the following settings:
List<ChannelOption> channelOptions = new List<ChannelOption>();
channelOptions.Add(new
ChannelOption("GRPC_ARG_HTTP2_MIN_RECV_PING_INTERVAL_WITHOUT_DATA_MS",
1000));
channelOptions.Add(new
ChannelOption("GRPC_ARG_HTTP2_MAX_PINGS_WITHOUT_DATA", 0));
channelOptions.Add(new
ChannelOption("GRPC_ARG_KEEPALIVE_PERMIT_WITHOUT_CALLS", 1));
this.server = new Server(channelOptions) {
Services = { TerminalService.BindService(this) },
Ports = {new ServerPort("0.0.0.0", 5000,
ServerCredentials.Insecure)}
};
On Android I have the following channel setup:
private val channel = ManagedChannelBuilder.forAddress(name, port)
.usePlaintext()
.keepAliveTime(10, TimeUnit.SECONDS)
.keepAliveWithoutCalls(true)
.build()
After a few min (however seems to be a random time). I get the goaway error. I noticed that if I stream data on the call then the error never happens. It is only when there is no data on the stream. This leads me to believe the issue is that the GRPC_ARG_HTTP2_MAX_PINGS_WITHOUT_DATA needs to be set on the Android client aswell. Problem is for the life of me I cannot find where to set these channel settings on gRPC java. Can someone point out to me where I can set these channel settings? There are no examples where these have been set.
The channel options being specified are using the wrong names. Names like GRPC_ARG_HTTP2_MAX_PINGS_WITHOUT_DATA are the C-defines for things like "grpc.http2.max_pings_without_data".
You can map from the C name to the key string by looking at grpc_types.h. You should prefer using one of the C# constants in ChannelOptions when it is available, but that doesn't seem to be an option in this case.
These options are not visible in the Java ManagedChannelBuilder API because they are server-specific settings. So instead they are visible on the ServerBuilder. See A8 client-side keepalive for reference to the Java keepalive API.
I'm building an app with the Entity Framework on Xamarin that lets me compare some data. But when I start my "fetchdata" function, I receive the Error:
System.Data.SqlClient.SqlException (0x80131904): Snix_Connect (provider: SNI_PN7, error: 35 - SNI_ERROR_35)Snix_Connect (provider: SNI_PN7, error: 35 - SNI_ERROR_35)
I see many posts about Xamarin / Android & that it is not possible to get a connection to a SQL Server. Is there any way to fetch data from a SQL Server with .NET Core on Xamarin?
This is the string I put into SQL_Class folder with Sql_Common.cs
Fill up the brace brackets with actual parameters (removing the brace brakets too).
public static string SQL_connection_string = #"data source={server_address};initial catalog={database_name};user id={user_id};password={password};Connect Timeout={seconds}";
Then I access whenever I need it from any xamarin code just like we use in our asp.net c#
This works for me on my app without any issues.
using (SqlConnection Sql_Connection = new SqlConnection(Sql_Common.saralEHR_connection_string))
But as #Jason mentioned in his first reply, I too would get once again check the security part. I fexperienced before publishing Package to Google Play, they encrypt the App files with Hash Key Code and then only it gets upload to server
Yes it is possible (HuurrAYY!):
Im new in .net core, c# and so on and for me it was a hell of a work to get it working..
So here for the other noobs who are seeking for Help:
Guide´s i used:
Building Android Apps with Entity Framework
https://medium.com/#yostane/data-persistence-in-xamarin-using-entity-framework-core-e3a58bdee9d1
https://blog.xamarin.com/building-android-apps-entity-framework/
Scaffolding
https://cmatskas.com/scaffolding-dbcontext-and-models-with-entityframework-core-2-0-and-the-cli/
How i did it:
Build your normal Xamarin app.
create new .net solution like in the tutorials (DONT WRITE YOUR Entity Framework CLASSES)
create a third solution what has to be a .net core console application
Scaffold your DB in your CONSOLE application move all created classes & folders in your "xamarin .net" solution & change the namespaces
Ready to Go!
Side Node: NuGets you need in every solution:
Microsoft.EntityFrameworkCore
Microsoft.EntityFrameworkCore.SqlServer
[EDIT: NuGets you need in every solution]
I am doing this way (working snippet):
string connectionString = #"data source={server};initial catalog={database};user id={user};password={password};Connect Timeout=10";
string databaseTable = "{table name}";
string selectQuery = String.Format("SELECT count(*) as Orders FROM {0}", databaseTable);
try
{
using (SqlConnection connection = new SqlConnection(connectionString))
{
//open connection
connection.Open();
SqlCommand command = new SqlCommand(selectQuery, connection);
command.Connection = connection;
command.CommandText = selectQuery;
var result = command.ExecuteScalar().ToString();
//check if there is result
if(result != null)
{
OrdersLabel.Text = result;
}
}
}
catch (Exception ex)
{
OrdersLabel.Text = ex.Message;
}
It is working fine, but API call more elegant.
I hope it helps.
I am writing an open source framework to use BLE Mini module with Android and iOS mobile devices using Unity engine.
This framework should allow to establish a connection between the mobile device and the BLE Mini module, and to send/receive data using it. The framework can be theoretically adapted to work with any BLE module.
The idea is to make the existing BLE Mini frameworks (available for iOS and Android) work in Unity engine, hence I am writing native plugins for iOS and Android that will allow Unity apps use the native frameworks.
The iOS plugin is working as expected, while I am having problems writing the Android plugin.
Everything works as expected except the fact that I cannot send data to my characteristic. If I send the data the BLE Mini module does not receive it.
The code controlling the BLE Mini data reception is correct because it works when iOS sends the data. So I am pretty sure the problem is in the Android plugin.
The Android plugin is composed by Android native code that can be found here:
https://github.com/giomurru/ble-framework/tree/master/AndroidPlugin/src/com/gmurru/bleframework
and by Unity c# code that can call the public java methods: https://github.com/giomurru/ble-framework/blob/master/Unity/Assets/BLE/BLEController.cs
The code contained in RBLGattAttributes.java and RBLService.java is correct because it is the framework provided by RedBearLab and I tested it and it works correctly with native Android apps.
The code in which I need help and that probably contains the bug is the one in BleFramework.java
The BleFramework class contains a series of functions that can be called by the Unity engine. The functions are called following this order:
Call the get static method BleFramework.getInstance() to get a singleton instance of the class BleFramework. This method returns one and only one instance of the BleFramework class.
After I have the instance of the class I can call the BleFramework methods using this instance (which is always the same instance).
The methods are called following this order:
1) Call the function _InitBLEFramework from Unity. The function should initialize the BLE framework. When the initialization is finished the Android plugin answer to Unity with a OnBleDidInitialize "Success" message.
2) If Unity receives the OnBleDidInitialize "Success" message, I can call the function _ScanForPeripherals from Unity. The function scans for available BLE modules peripherals. When the available peripherals are found the plugin answer to Unity with a OnBleDidCompletePeripheralScan "Success" message.
3) If Unity receives the OnBleDidCompletePeripheralScan "Success" message, I can call the function _GetListOfDevices to get the list of found devices.
4) Once I have the list of BLE module devices I found, I can try to connect to one of them using the function _ConnectPeripheralAtIndex(int peripheralIndex). When the _mGattUpdateReceiver receives RBLService.ACTION_GATT_SERVICES_DISCOVERED I can say the connection is established and I can let Unity know I am ready to send/receive data by sending a OnBleDidConnect "Success" message.
Up to here the plugin works as expected, and the connection is established.
The problem is when I try to send data in step 5.
5) When Unity receives the OnBleDidConnect "Success" message it is ready to send data through the established connection. Hence I try to send the data by using _SendData function in the plugin. Unfortunately it does not work.
This is the code:
public void _SendData(byte[] data)
{
Log.d(TAG,"_SendData: ");
BluetoothGattCharacteristic characteristic = _map.get(RBLService.UUID_BLE_SHIELD_TX);
Log.d(TAG, "Set data in the _characteristicTx");
byte[] tx = hexStringToByteArray("fefefe");
characteristic.setValue(tx);
Log.d(TAG, "Write _characteristicTx in the _mBluetoothLeService: " + tx[0] + " " + tx[1] + " " + tx[2]);
if (_mBluetoothLeService==null)
{
Log.d(TAG, "_mBluetoothLeService is null");
}
_mBluetoothLeService.writeCharacteristic(characteristic);
}
public static byte[] hexStringToByteArray(String s) {
int len = s.length();
byte[] data = new byte[len / 2];
for (int i = 0; i < len; i += 2) {
data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
+ Character.digit(s.charAt(i+1), 16));
}
return data;
}
Just for the purpose of testing I ignored byte[] data parameter and I try to send byte[] tx data that I create inside the _SendData function using hexStringToByteArray function (that I found in this StackOverflow post: Convert a string representation of a hex dump to a byte array using Java?)
I also tried to create the tx data as:
byte tx[] = new byte[] { (byte) 0xfe, (byte) 0xfe, (byte) 0xfe };
or to send the data directly like this:
public void _SendData(byte[] data)
{
Log.d(TAG,"_SendData: ");
BluetoothGattCharacteristic characteristic = _map.get(RBLService.UUID_BLE_SHIELD_TX);
Log.d(TAG, "Set data in the _characteristicTx");
characteristic.setValue(data);
Log.d(TAG, "Write _characteristicTx in the _mBluetoothLeService: " + data[0] + " " + data[1] + " " + data[2]);
if (_mBluetoothLeService==null)
{
Log.d(TAG, "_mBluetoothLeService is null");
}
_mBluetoothLeService.writeCharacteristic(characteristic);
}
In all the cases I failed to send the data.
I really can't understand why this is happening. The code I am using to search ble devices, establish connection, send receive data is very similar to the Android native samples available in ReadBearLab github page: https://github.com/RedBearLab/Android/tree/master/Examples
The only difference is that I am not extending Activity.
I tried to make BleFramework class an extension of Activity but it didn't work. The problem I had was that while BleFramework activity was running I was not able to send messages back to Unity using the UnityPlayer.UnitySendMessage function.
I answer my own question just for reference if anybody is interested in the solution I found.
I fixed the bug by updating the code to the latest Android APIs. Please check out the commits from June 15th 2019 to June 22nd 2019 in the repository if you are interested in the modifications. In particular the commit named "Android tx/rx works"
https://github.com/giomurru/ble-framework
I am programming an authentication service in Android and this one includes a server part written in java.
I do the same operations in both parts executing these two pieces of codes in Android and Server:
ANDROID:
String genChallengeResponse(String challenge, String message) {
String Hmac_ALG = "HmacSHA256";
SecretKey key = new SecretKeySpec(challenge.getBytes(), Hmac_ALG);
Mac m = Mac.getInstance(Hmac_ALG);
m.init(key);
m.update(password.getBytes());
byte[] mac = m.doFinal();
return new String(Base64.encode(mac, Base64.DEFAULT));
}
SERVER:
String genChallengeResponse(String challenge, String message) {
String Hmac_ALG = "HmacSHA256";
SecretKey key = new SecretKeySpec(challenge.getBytes(), Hmac_ALG);
Mac m = Mac.getInstance(Hmac_ALG);
m.init(key);
m.update(password.getBytes());
byte[] mac = m.doFinal();
return new String(Base64.encodeBase64(mac));
}
Starting from the same challenge and message these are the results:
Android: n2EaLpQr0uKgkZKhCQzwuIFeeLjzZKerZcETVNcfla4=
Server: n2EaLpQr0uKgkZKhCQzwuD9eeLjzZKerZcETVNcfla4=
^^
These are different just for TWO CHARACTERS.
The problem is that this strange behaviour does not appear in every pair of String passed to the functions...
I tried to use the UTF-8 in each system, but nothing changes...
Do someone knows what is the problem? If this is a known problem...
(is important to say that the problem is the same using Android 2.2 or also 4.0, then the problem is not the operating system, I think).
Can't comment yet therefore as answer:
I found out a few weeks ago that Android's Base64 uses different settings for the Linefeeds (check here: http://developer.android.com/reference/android/util/Base64.html )
I think in my case it was NO_WRAP missing.Perhaps one of the other options (NO_PADDING or URL-Safe, does the tested password contain + or - ?) could change your results...