How do I convert a Linux C USB read to Android? - android

I have Tire Pressure Management System (TPMS) adapter that plugs into USB (http://store.mp3car.com/USB_TPMS_Version_2_20_4_Sensor_Kit_p/com-090.htm). I have it working with the original Windows software, as well as Linux C code to read the tire pressures and temperature. I'm now trying to use this adapter on Android and am having some difficulty. I can detect the device fine, but my reads are all returning -1 bytes read, whatever I try. Here's the C code I'm trying to convert:
int TpmsPlugin::readUsbSensor(int sid, unsigned char *buf)
{
int r, transferred;
buf[0] = 0x20 + sid;
r = libusb_interrupt_transfer(mDeviceHandle, ENDPOINT_OUT, buf, 1, &transferred, INTR_TIMEOUT);
if (r < 0) {
DebugOut() << "TPMS: USB write interrupt failed, code " << r << endl;
}
r = libusb_interrupt_transfer(mDeviceHandle, ENDPOINT_IN, buf, 4, &transferred, INTR_TIMEOUT);
if (r < 0) {
DebugOut() << "TPMS: USB read interrupt failed, code " << r << endl;
}
return r;
The value of sid is 1, 2, 3 or 4 depending on the wheel. The values are then extracted with:
lfPressure = ((float)buf[0]-40) * PRESSURE_SCALE * KPA_MULTIPLIER;
lfTemperature = (float)buf[1]-40;
You can see full implementation of this driver here as well: https://github.com/otcshare/automotive-message-broker/blob/master/plugins/tpms/tpmsplugin.cpp
My Android version is able to find the USB device, get permission to use it, connect to it, get the UsbEndpoints (it lists two), but whether bulkTransfer() or controlTransfer() I try, I've failed. In particular, I've tried a lot of different controlTransfer values based on all the docs I could find. Here is some code that I've tried:
UsbInterface intf = TpmsSectionFragment.device.getInterface(0);
UsbEndpoint endpoint_in = null, endpoint_out = null;
for (int i = 0; i < intf.getEndpointCount(); i++) {
UsbEndpoint ep = intf.getEndpoint(i);
if (ep.getDirection() == UsbConstants.USB_DIR_IN)
endpoint_in = ep;
else if (ep.getDirection() == UsbConstants.USB_DIR_OUT)
endpoint_out = ep;
}
UsbDeviceConnection connection = gUsbManager.openDevice(TpmsSectionFragment.device);
connection.claimInterface(intf, false);
int timeout = 1000;
int length = 4;
while (true) {
for (int sensorId = 1; sensorId <= 4 && mReadThreadActive; sensorId++) {
byte[] tpmsRaw = new byte[length];
tpmsRaw[0] = (byte) (0x20 + sensorId);
int out_len = connection.bulkTransfer(endpoint_out, tpmsRaw, 1, timeout);
int in_len = connection.bulkTransfer(endpoint_in, tpmsRaw, 4, timeout);
//int out_len = connection.controlTransfer(0x42, 0x0, 0x100, 0, tpmsRaw, tpmsRaw.length, timeout);
//int in_len = connection.controlTransfer(0x41, 0x0, 0x100, 0, tpmsRaw, tpmsRaw.length, timeout);
Any thoughts on what I could be doing wrong are greatly appreciated. I'm happy to try a few different things to debug further if you have any suggestions.
Thanks!

Here's the solution based on the help from Chris. I converted the calls to queue / requestWait:
ByteBuffer buf = ByteBuffer.allocate(4);
buf.put(0, (byte) (0x20 + sensorId));
UsbRequest send = new UsbRequest();
send.initialize(connection, endpoint_out);
Boolean sent = send.queue(buf, 1);
UsbRequest r1 = connection.requestWait();
send.initialize(connection, endpoint_in);
send.queue(buf, 4);
UsbRequest r2 = connection.requestWait();
The other thing I needed to tweak was this call and set the second parameter to true:
connection.claimInterface(intf, true);
That's it. Done. Thanks for the help!

Related

hid_get_feature_report analog in Android USB Library

What would be analog to hid_get_feature_report in Android USB Library?
I need to get relays state from usb relays device on Android.
I found example on C (for Linux/Windows): https://github.com/darrylb123/usbrelay/blob/master/libusbrelay.c
static int get_board_features(relay_board *board, hid_device *handle)
{
unsigned char buf[9];
//Get the features of the device
buf[0] = 0x01;
int ret = hid_get_feature_report(handle, buf, sizeof(buf));
if (ret == -1)
{
perror("hid_get_feature_report\n");
}
//Set the serial number (0x0 for termination)
memset(board->serial, 0x0, sizeof(board->serial));
memcpy(board->serial, buf, Serial_Length);
//Byte 7 in the response contains the target_state of the relays
board->state = buf[7];
return ret;
}
On Android it returns only one end point Log.i(TAG, "endpointCount ${usbInterface.endpointCount}

Android Socket Stuck every 20 seconds

I am using a TCP socket connection in an action game, we use lockstep synchronization, client will receive 20 - 40 packets per second. It works fine when the game is running on a PC but when running on Android devices, the socket will get stuck every 20 seconds
Server sends 5 packets per second
I have tried to use Unity3D's C# socket, Android Java socket and Android native C socket and blocking/non-blocking mode, small/large (1byte/100byte) data per packet, less/more (5/50) packets per second, use single thread/main thread, on multiple Android devices, all of them have the same issue.
PS: It seems the 20 second duration is based on devices, not my app or connection; that means if last stuck happens at 1:00:00, the next stuck will happen at 1:00:20, even if we reconnect or restart the app.
Android native C code:
extern "C" JNIEXPORT int JNICALL
Java_com_example_ymoon_sockettest_MainActivity_connect(JNIEnv *env, jobject /* this */)
{
__android_log_print(ANDROID_LOG_INFO, "CSocket", "Connecting...");
int sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock < 0) return -1;
struct sockaddr_in server;
memset(&server, 0, sizeof(server));
server.sin_family = AF_INET;
server.sin_port = htons(12350);
server.sin_addr.s_addr = inet_addr("192.168.3.66");
if (connect(sock, (struct sockaddr*)&server, sizeof(server)) < 0)
{
close(sock);
return -2;
}
__android_log_print(ANDROID_LOG_INFO, "CSocket", "Connected");
char buf[100];
int t = -1;
int received = 0;
while (true)
{
int count = recv(sock, &buf, 100, 0);
if (count < 1) break;
received += count;
struct timeval tv;
gettimeofday(&tv, NULL);
int m = tv.tv_sec * 1000 + tv.tv_usec / 1000;
int diff = m - t;
t = m;
std::string p = t < 0 ? "" : diff < 50 ? "-" : diff < 100 ? "-|" : diff < 150 ? "--|" :
diff < 250 ? "---|" : diff < 500 ? "----|" : diff < 1000 ? "-----|" : "------|";
__android_log_print(diff > 500 ? ANDROID_LOG_ERROR : ANDROID_LOG_INFO,
"CSocket", "%i | %s %i", received, p.c_str(), diff);
}
close(sock);
return 0;
}
Am I doing something wrong ?
It is my first time to ask a question on stackoverflow, sorry for my bad English, any help or suggestion is appreciated, thanks.
Edit: add server code, i rewrite a simple tcp server to test (Window platform)
int main()
{
addrinfo conf, *add = nullptr;
memset(&conf, 0, sizeof(conf));
conf.ai_flags = AI_PASSIVE;
conf.ai_socktype = SOCK_STREAM;
conf.ai_family = AF_INET;
if (getaddrinfo(nullptr, "12350", &conf, &add)) return 0;
SOCKET serverSock = socket(AF_INET, SOCK_STREAM, 0);
char opt = 1;
if (setsockopt(serverSock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1 ||
setsockopt(serverSock, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt)) == -1 ||
bind(serverSock, add->ai_addr, add->ai_addrlen) == -1 ||
listen(serverSock, 0) == -1)
{
close(serverSock);
return 0;
}
printf("Listening....\n");
sockaddr_storage incoming_addr;
int size = sizeof(incoming_addr);
SOCKET clientSock = accept(serverSock, (sockaddr*)&incoming_addr, &size);
printf("Client connected\n");
char buf[1] = { 0 };
int sendCount = 0;
while (true)
{
time_t t = time(nullptr);
tm *lt = localtime(&t);
printf("%02d:%02d:%02d Send to client %i\n", lt->tm_hour, lt->tm_min, lt->tm_sec, ++sendCount);
if (send(clientSock, buf, 1, 0) < 1) break;
Sleep(200);
}
close(serverSock);
return 0;
}
Edit: Add WireShark capture image:
Wireshark shot when stuck happen
I have test it (code posted here) in my home, and another WIFI environment, it worked fine. The only difference is the WIFI environment, so I think maybe our company WIFI network settings cause this issue.

how to use Tango3DR_updateTexture?

I am trying to make 3DR texturing but it always use only vertex colors in texture.
On every frame I store frame as PNG:
RGBImage frame(t3dr_image, 4);
std::ostringstream ss;
ss << dataset_.c_str();
ss << "/";
ss << poses_.size();
ss << ".png";
frame.Write(ss.str().c_str());
poses_.push_back(t3dr_image_pose);
timestamps_.push_back(t3dr_image.timestamp);
In the method Save I am trying to process texturing:
1) I extract full mesh from context
Tango3DR_Mesh* mesh = 0;
Tango3DR_Status ret;
ret = Tango3DR_extractFullMesh(t3dr_context_, &mesh);
if (ret != TANGO_3DR_SUCCESS)
std::exit(EXIT_SUCCESS);
2) Create texturing context using extracted mesh
Tango3DR_ConfigH textureConfig;
textureConfig = Tango3DR_Config_create(TANGO_3DR_CONFIG_TEXTURING);
ret = Tango3DR_Config_setDouble(textureConfig, "min_resolution", 0.01);
if (ret != TANGO_3DR_SUCCESS)
std::exit(EXIT_SUCCESS);
Tango3DR_TexturingContext context;
context = Tango3DR_createTexturingContext(textureConfig, dataset.c_str(), mesh);
if (context == nullptr)
std::exit(EXIT_SUCCESS);
Tango3DR_Config_destroy(textureConfig);
3) Call Tango3DR_updateTexture with data I stored before (this does not work)
for (unsigned int i = 0; i < poses_.size(); i++) {
std::ostringstream ss;
ss << dataset_.c_str();
ss << "/";
ss << i;
ss << ".png";
RGBImage frame(ss.str());
Tango3DR_ImageBuffer image;
image.width = frame.GetWidth();
image.height = frame.GetHeight();
image.stride = frame.GetWidth() * 3;
image.timestamp = timestamps_[i];
//data are for sure in this format
image.format = TANGO_3DR_HAL_PIXEL_FORMAT_RGB_888;
image.data = frame.GetData();
ret = Tango3DR_updateTexture(context, &image, &poses_[i]);
if (ret != TANGO_3DR_SUCCESS)
std::exit(EXIT_SUCCESS);
}
4) Texturize mesh
ret = Tango3DR_Mesh_destroy(mesh);
if (ret != TANGO_3DR_SUCCESS)
std::exit(EXIT_SUCCESS);
mesh = 0;
ret = Tango3DR_getTexturedMesh(context, &mesh);
if (ret != TANGO_3DR_SUCCESS)
std::exit(EXIT_SUCCESS);
5) Save it as OBJ (in the result texture are only data from vertex colors, why?)
ret = Tango3DR_Mesh_saveToObj(mesh, filename.c_str());
if (ret != TANGO_3DR_SUCCESS)
std::exit(EXIT_SUCCESS);
ret = Tango3DR_destroyTexturingContext(context);
if (ret != TANGO_3DR_SUCCESS)
std::exit(EXIT_SUCCESS);
ret = Tango3DR_Mesh_destroy(mesh);
if (ret != TANGO_3DR_SUCCESS)
std::exit(EXIT_SUCCESS);
All methods returned TANGO_3DR_SUCCESS.
Full code here: https://github.com/lvonasek/tango
Thanks for reaching out and providing the detailed code breakdown.
The error is on our end - the library currently doesn't support RGB texture inputs. It assumes YUV for all input images. I've opened a ticket to track this bug and we'll fix it for the next release, by allowing RGB input and providing better return values for invalid image formats.
Edit: Found another bug on our end. The API states image_pose should be the pose of the image, but our implementation actually expects the pose of the device. I've opened a bug, and this will be fixed in next release (release-H).
You can try working around this for now by passing in the device pose without multiplying the device-to-camera extrinsic calibration, although of course that's just a temp bandaid.

Android Bluetooth SPP Loss/Corrupted Data

I'm attempting to transfer a large file (2.7MB) from a server device to an android device via bluetooth using SPP. Upon connection, the android device reads the bytes available and store into a buffer of 2.7MB. I am using the variable "counter" (counting from 0 to 127) to verify the data.
To experiment, all data is correct if the server device outputs the file byte by byte. However, if the device outputs in packets of n bytes (e.g. 128 in this case), the data received on android was corrupted without any consistent pattern - it would incorrectly read values as 0s or 1s, but it always fixed itself at the start of the packet.
Any suggestions on how to prevent loss/corruption of data is greatly appreciated.
Receiving on Android device:
int imageSize = 2718720;
int counter = 0;
int totalByte = 0;
byte[] buffer = new byte[imageSize];
while (totalByte < imageSize) {
int bytesAvailable = mInStream.available();
int numOfBytesRead = mInStream.read(buffer, totalByte, bytesAvailable);
for (int i = totalByte; i < totalByte + numOfBytesRead; i++) {
if (buffer[i] != counter) {
Log.d("BTDevice", Integer.toString(i) + ". read byte = " + Integer.toString(buffer[i] & 0xff) + " - Failed");
} else {
Log.d("BTDevice", Integer.toString(i) + ". read byte = " + Integer.toString(buffer[i] & 0xff));
}
counter++;
if (counter == 128) {
counter = 0;
}
}
totalByte += actualBytesRead;
}
Output:

Is it possible to use write c code access rild socket in Android

like the Title. I write the code like this:
printf("create socket\r\n");
fd = socket_local_client(SOCKET_NAME_RIL,
ANDROID_SOCKET_NAMESPACE_RESERVED,
SOCK_STREAM);
if (fd < 0) {
perror ("opening radio socket error");
exit(-1);
}
printf("fd = %d\r\n",fd);
int length = 12;
char datalength[5]={0};
datalength[0] = 0;
datalength[1] = 0;
datalength[2] = (length >>8) & 0xff;
datalength[3] = (length & 0xff);
int ret = send(fd, datalength, 4, 0);
if(ret != sizeof(int)) {
perror ("Socket write error when sending length");
close(fd);
exit(-1);
}
i can get fd value successfully, and send data successfully.
but from "logcat -b radio" there is nothing information can be displayed.
it seems that rild has prevent socket connection.
is there any resolutions? Thanks
The rild socket is "owned" by the Phone app, so you won't be able to connect to it as long as that is running. You might try connecting to the rild-debug socket.

Categories

Resources