Raw midi values and bytes c++ - android

I use superpowered, I need send midi note to a controller midi.
The problem is that I saw a function send(int deviceID, unsigned char *data, int bytes);
Where in their source code say:
deviceID: Device identifier.
data: Raw MIDI data.
bytes: Number of
bytes.
I don't know the values that I need put exactly on data and bytes to work.
The raw midi could be 0x80 - 0x48 - 0x00(start of C4 note, pitch= 72, See values)
And the bytes 1001nnnn0kkkkkkk0kkkkkkk(note on event See values) for example?
Something like that:
SuperpoweredUSBMIDI::send(deviceID, reinterpret_cast(0x80 - 0x48 - 0x00), 1001nnnn0kkkkkkk0kkkkkkk);
The problem that always crash, and I can't debug or get the error for the reason that I use the mobile with otg to replicate the error.
When I find a solution, I will put it as soon as I can.
I'm newbie with markdown, sorry for any mistakes and my English grammar.
Edit: I'm using the example project that they have on GitHub for testing purposes, specifically the simpleusb project. (source)
I make a small modifications and work, but with this specifically I try with many ways and nothing. I think this simple macrochange at least could work if I insert well the values
class simpleusb.cpp:
#include <jni.h>
#include <math.h>
#include <SuperpoweredCPU.h>
#include <AndroidIO/SuperpoweredUSBAudio.h>
#include <malloc.h>
#include <pthread.h>
// Called when the application is initialized. You can initialize SuperpoweredUSBSystem
// at any time btw. Although this function is marked __unused, it's due Android Studio's
// annoying warning only. It's definitely used.
__unused jint JNI_OnLoad (
JavaVM * __unused vm,
void * __unused reserved
) {
SuperpoweredUSBSystem::initialize(NULL, NULL, NULL, NULL, NULL);
return JNI_VERSION_1_6;
}
// Called when the application is closed. You can destroy SuperpoweredUSBSystem at any time btw.
// Although this function is marked __unused, it's due Android Studio's annoying warning only.
// It's definitely used.
__unused void JNI_OnUnload (
JavaVM * __unused vm,
void * __unused reserved
) {
SuperpoweredUSBSystem::destroy();
}
// A helper structure for sine wave output.
typedef struct sineWaveOutput {
float mul;
unsigned int step;
} sineWaveOutput;
// This is called periodically for audio I/O. Audio is always 32-bit floating point,
// regardless of the bit depth preference. (SuperpoweredUSBAudioProcessingCallback)
static bool audioProcessing (
void *clientdata,
int __unused deviceID,
float *audioIO,
int numberOfSamples,
int samplerate,
int __unused numInputChannels,
int numOutputChannels
) {
// If audioIO is NULL, then it's the very last call, IO is closing.
if (!audioIO) {
// Free memory for sine wave struct.
free(clientdata);
return true;
}
sineWaveOutput *swo = (sineWaveOutput *)clientdata;
if (swo->mul == 0.0f) swo->mul = (2.0f * float(M_PI) * 300.0f) / float(samplerate);
// Output sine wave on all output channels.
for (int n = 0; n < numberOfSamples; n++) {
float v = sinf(swo->step++ * swo->mul) * 0.5f;
for (int c = 0; c < numOutputChannels; c++) *audioIO++ = v;
}
return true; // Return false for silence, true if we put audio output into audioIO.
}
static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
static int latestMidiCommand = -1;
static int latestMidiChannel = 0;
static int latestMidiNumber = 0;
static int latestMidiValue = 0;
// This is called when some MIDI data is coming in.
// We are doing some primitive MIDI data processing here.
static void onMidiReceived (
void * __unused clientdata,
int __unused deviceID,
unsigned char *data,
int bytes
) {
while (bytes > 0) {
if (*data > 127) {
int command = *data >> 4;
switch (command) {
case 8: // note off
case 9: // note on
case 11: // control change
pthread_mutex_lock(&mutex);
// store incoming MIDI data
latestMidiCommand = command;
latestMidiChannel = *data++ & 15;
latestMidiNumber = *data++;
latestMidiValue = *data++;
pthread_mutex_unlock(&mutex);
bytes -= 3;
break;
default:
data++;
bytes--;
}
} else {
data++;
bytes--;
}
}
}
// Beautifying the ugly Java-C++ bridge (JNI) with these macros.
#define PID com_superpowered_simpleusb_SuperpoweredUSBAudio // Java package name and class name. Don't forget to update when you copy this code.
#define MAKE_JNI_FUNCTION(r, n, p) extern "C" JNIEXPORT r JNICALL Java_ ## p ## _ ## n
#define JNI(r, n, p) MAKE_JNI_FUNCTION(r, n, p)
// This is called by the SuperpoweredUSBAudio Java object when a USB device is connected.
JNI(jint, onConnect, PID) (
JNIEnv *env,
jobject __unused obj,
jint deviceID,
jint fd,
jbyteArray rawDescriptor
) {
jbyte *rd = env->GetByteArrayElements(rawDescriptor, NULL);
int dataBytes = env->GetArrayLength(rawDescriptor);
int r = SuperpoweredUSBSystem::onConnect(deviceID, fd, (unsigned char *)rd, dataBytes);
env->ReleaseByteArrayElements(rawDescriptor, rd, JNI_ABORT);
// r is 0 if SuperpoweredUSBSystem can't do anything with the connected device.
// r & 2 is true if the device has MIDI. Start receiving events.
if (r & 2) {
SuperpoweredUSBMIDI::startIO(deviceID, NULL, onMidiReceived);
//TODO HERE IT'S THE PROBLEM: error: integer literal is too large to be represented in any integer type
SuperpoweredUSBMIDI::send(deviceID, reinterpret_cast<unsigned char *>(0x80 - 0x48 - 0x00), 100100010011100000000011);
//FINISH PROBLEM
}
// r & 1 is true if the device has audio. Start output.
if (r & 1) {
// allocate struct for sine wave oscillator
sineWaveOutput *swo = (sineWaveOutput *)malloc(sizeof(sineWaveOutput));
if (swo) {
swo->mul = 0.0f;
swo->step = 0;
SuperpoweredCPU::setSustainedPerformanceMode(true);
// Our preferred settings: 44100 Hz, 16 bits, 0 input channels, 256 output channels,
// low latency. Superpowered will set up the audio device as close as it can to these.
SuperpoweredUSBAudio::easyIO (
deviceID, // deviceID
44100, // sampling rate
16, // bits per sample
0, // numInputChannels
256, // numOutputChannels
SuperpoweredUSBLatency_Low, // latency
swo, // clientData
audioProcessing // SuperpoweredUSBAudioProcessingCallback
);
}
}
return r;
}
// This is called by the SuperpoweredUSBAudio Java object when a USB device is disconnected.
JNI(void, onDisconnect, PID) (
JNIEnv * __unused env,
jobject __unused obj,
jint deviceID
) {
SuperpoweredUSBSystem::onDisconnect(deviceID);
SuperpoweredCPU::setSustainedPerformanceMode(false);
}
#undef PID
#define PID com_superpowered_simpleusb_MainActivity
// This is called by the MainActivity Java object periodically.
JNI(jintArray, getLatestMidiMessage, PID) (
JNIEnv *env,
jobject __unused obj
) {
jintArray ints = env->NewIntArray(4);
jint *i = env->GetIntArrayElements(ints, 0);
pthread_mutex_lock(&mutex);
i[0] = latestMidiCommand;
i[1] = latestMidiChannel;
i[2] = latestMidiNumber;
i[3] = latestMidiValue;
pthread_mutex_unlock(&mutex);
env->ReleaseIntArrayElements(ints, i, 0);
return ints;
}
The other important class but I don't change on this problem, MainActivity:
#RequiresApi(api = Build.VERSION_CODES.M)
public class MainActivity extends AppCompatActivity implements SuperpoweredUSBAudioHandler {
private Handler handler;
private TextView textView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = findViewById(R.id.text);
SuperpoweredUSBAudio usbAudio = new SuperpoweredUSBAudio(getApplicationContext(), this);
usbAudio.check();
// Update UI every 40 ms.
Runnable runnable = new Runnable() {
#Override
public void run() {
int[] midi = getLatestMidiMessage();
switch (midi[0]) {
case 8: textView.setText(String.format(Locale.ENGLISH, "Note Off, CH %d, %d, %d",
midi[1] + 1, midi[2], midi[3]));
break;
case 9: textView.setText(String.format(Locale.ENGLISH, "Note On, CH %d, %d, %d",
midi[1] + 1, midi[2], midi[3]));
break;
case 11: textView.setText(String.format(Locale.ENGLISH, "Control Change, CH %d, %d, %d",
midi[1] + 1, midi[2], midi[3]));
break;
}
handler.postDelayed(this, 40);
}
};
handler = new Handler();
handler.postDelayed(runnable, 40);
/*Not look, only for testing purposes and for remember what use.
byte[] buffer = new byte[32];
int numBytes = 0;
int channel = 6; // MIDI channels 1-16 are encoded as 0-15.
buffer[numBytes++] = (byte)(0x90 + (channel - 1)); // note on
buffer[numBytes++] = (byte)60; // pitch is middle C
buffer[numBytes++] = (byte)127; // max velocity
int offset = 0;*/
}
public void onUSBAudioDeviceAttached(int deviceIdentifier) {
}
public void onUSBMIDIDeviceAttached(int deviceIdentifier) {
}
public void onUSBDeviceDetached(int deviceIdentifier) {
}
// Function implemented in the native library.
private native int[] getLatestMidiMessage();
static {
System.loadLibrary("SuperpoweredExample");
}
}
Error that I can't build app finally:
Build command failed.
Error while executing process D:\Users\ramoc\AppData\Local\Android\sdk\cmake\3.6.4111459\bin\cmake.exe with arguments {--build F:\PROYECTOFIN\SuperpoweredUSBExample\simpleusb\.externalNativeBuild\cmake\debug\arm64-v8a --target SuperpoweredExample}
[1/2] Building CXX object CMakeFiles/SuperpoweredExample.dir/simpleusb.cpp.o
FAILED: D:\Users\ramoc\AppData\Local\Android\sdk\ndk-bundle\toolchains\llvm\prebuilt\windows-x86_64\bin\clang++.exe --target=aarch64-none-linux-android --gcc-toolchain=D:/Users/ramoc/AppData/Local/Android/sdk/ndk-bundle/toolchains/aarch64-linux-android-4.9/prebuilt/windows-x86_64 --sysroot=D:/Users/ramoc/AppData/Local/Android/sdk/ndk-bundle/sysroot -DSuperpoweredExample_EXPORTS -IF:/PROYECTOFIN/SuperpoweredUSBExample/simpleusb/src/main/jni/src/main/jni -IF:/PROYECTOFIN/SuperpoweredUSBExample/simpleusb/../../../Superpowered -isystem D:/Users/ramoc/AppData/Local/Android/sdk/ndk-bundle/sources/cxx-stl/gnu-libstdc++/4.9/include -isystem D:/Users/ramoc/AppData/Local/Android/sdk/ndk-bundle/sources/cxx-stl/gnu-libstdc++/4.9/libs/arm64-v8a/include -isystem D:/Users/ramoc/AppData/Local/Android/sdk/ndk-bundle/sources/cxx-stl/gnu-libstdc++/4.9/include/backward -isystem D:/Users/ramoc/AppData/Local/Android/sdk/ndk-bundle/sysroot/usr/include/aarch64-linux-android -D__ANDROID_API__=21 -g -DANDROID -ffunction-sections -funwind-tables -fstack-protector-strong -no-canonical-prefixes -Wa,--noexecstack -Wformat -Werror=format-security -fsigned-char -IF:\PROYECTOFIN\SuperpoweredUSBExample\simpleusb\..\..\..\Superpowered -O0 -fno-limit-debug-info -fPIC -MD -MT CMakeFiles/SuperpoweredExample.dir/simpleusb.cpp.o -MF CMakeFiles\SuperpoweredExample.dir\simpleusb.cpp.o.d -o CMakeFiles/SuperpoweredExample.dir/simpleusb.cpp.o -c F:\PROYECTOFIN\SuperpoweredUSBExample\simpleusb\src\main\jni\simpleusb.cpp
F:\PROYECTOFIN\SuperpoweredUSBExample\simpleusb\src\main\jni\simpleusb.cpp:129:100: error: integer literal is too large to be represented in any integer type
SuperpoweredUSBMIDI::send(deviceID, reinterpret_cast<unsigned char *>(0x80 - 0x48 - 0x00), 100100010011100000000011);
^
F:\PROYECTOFIN\SuperpoweredUSBExample\simpleusb\src\main\jni\simpleusb.cpp:129:100: warning: implicit conversion from 'unsigned long long' to 'int' changes value from 7976667151972931595 to 887068683 [-Wconstant-conversion]
SuperpoweredUSBMIDI::send(deviceID, reinterpret_cast<unsigned char *>(0x80 - 0x48 - 0x00), 100100010011100000000011);
~~~~~~~~~~~~~~~~~~~ ^~~~~~~~~~~~~~~~~~~~~~~~
1 warning and 1 error generated.
ninja: build stopped: subcommand failed.
Maybe it's for the documentation, very newbie with jni or too complex to me for now to understand 100%.

Ok, so here's what send is saying:
send(int deviceID, unsigned char *data, int bytes);
Send to deviceId a pointer to a buffer called data that has a certain number of bytes.
So when you say:
SuperpoweredUSBMIDI::send(deviceID, reinterpret_cast(0x80 - 0x48 - 0x00), 100100010011100000000011);
What you are essentially saying is "subtract these 3 numbers: 0x80 - 0x48 - 0x00", then re-interpret that number as a pointer to a buffer somewhere in memory. That buffer in memory contains 100100010011100000000011 bytes of data that I want you to read.
To fix this, we would send the data like this:
unsigned char* send_buffer[32] = {0}; // zero out buffer to use as scratch
send_buffer[0] = 0x90;
send_buffer[1] = 0x48;
send_buffer[2] = 0x00;
SuperpoweredUSBMIDI::send(deviceID, send_buffer, 3);

i thought midi had a check sum value (byte) appended to the sequence - is that done in your code or in the library code?
the message should be an array of unsigned char and pass the address of the array (name)
well that's what id have done in C when I was programming midi.

Related

In android how to find what /dev/input/event* is used for touchscreen using c function

I am trying to read touchscreen event, in my device /dev/input/event4 is used for touchscreen, while in some other phone, event7 is used for touchscreen.
I am looking for a c function that can help me
to find that touchscreen event.
Each input event device has a corresponding entry in the /sys/class/input/ pseudo-file hierarchy. (See Linux Input Subsystem userspace API in the Linux kernel documentation for further details.) For example, the name of the device corresponding to event7 is in /sys/class/input/event7/device/name.
When you open the event character device (/dev/input/event7), you can use the EVIOCGBIT(type, bits) ioctl to check which kind of events the device can produce. Touchpads will produce EV_ABS events ABS_X and ABS_Y, and EV_KEY event BTN_TOUCH.
Therefore, if you glob /dev/input/event*, open each device in turn, and check if they report the abovementioned three events, you are likely to find the device you look for. For example:
#define _POSIX_C_SOURCE 200809L
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <linux/input.h>
#include <fcntl.h>
#include <limits.h>
#include <string.h>
#include <glob.h>
#include <errno.h>
#include <stdio.h>
#ifndef ULONG_BITS
#define ULONG_BITS (CHAR_BIT * sizeof (unsigned long))
#endif
static inline int has_bit(const unsigned long data[], const size_t bit)
{
return !!(data[bit / ULONG_BITS] & (1uL << (bit % ULONG_BITS)));
}
char *touchscreen_event_device(size_t skip)
{
glob_t files;
int result;
result = glob("/dev/input/event*", 0, NULL, &files);
if (result) {
if (result == GLOB_NOSPACE) {
errno = ENOMEM;
return NULL;
} else
if (result == GLOB_NOMATCH) {
errno = ENOENT;
return NULL;
} else {
errno = EACCES;
return NULL;
}
}
for (size_t i = 0; i < files.gl_pathc; i++) {
int fd = open(files.gl_pathv[i], O_RDONLY);
if (fd != -1) {
unsigned long absbits[1 + ABS_MAX / ULONG_BITS] = { 0 };
unsigned long keybits[1 + KEY_MAX / ULONG_BITS] = { 0 };
if (ioctl(fd, EVIOCGBIT(EV_ABS, ABS_MAX+1), &absbits) != -1 &&
ioctl(fd, EVIOCGBIT(EV_KEY, KEY_MAX+1), &keybits) != -1) {
if (has_bit(absbits, ABS_X) &&
has_bit(absbits, ABS_Y) &&
has_bit(keybits, BTN_TOUCH)) {
/* Device reports ABS_X, ABS_Y and BTN_TOUCH,
and therefore is a touchpad device. */
if (!skip) {
char *devpath = strdup(files.gl_pathv[i]);
close(fd);
globfree(&files);
if (!devpath)
errno = ENOMEM;
return devpath;
} else {
skip--;
}
}
}
close(fd);
}
}
globfree(&files);
errno = ENOENT;
return NULL;
}
int main(void)
{
size_t i = 0;
while (1) {
char *devpath = touchscreen_event_device(i);
if (!devpath) {
if (i)
break;
fprintf(stderr, "No touchscreen input event devices found: %s.\n", strerror(errno));
return EXIT_FAILURE;
}
printf("Found touchscreen input event device '%s'\n", devpath);
free(devpath);
i++;
}
return EXIT_SUCCESS;
}
Compile using e.g. gcc -Wall -Wextra -O2 example.c -o example, and run with root privileges, and it will list the paths to the input event devices it believes are touch screens.
An answer for a complete code could be difficult because it's a long/heavy work.
I'll point you in right directions:
read "Input Event Codes": https://www.kernel.org/doc/html/v4.14/input/event-codes.html
then you have to list all /dev/input/* files
open each of them using "fd = open("/dev/input/xxxxx", O_RDONLY);"
call "ioctl(fd, EVIOCGBIT(EV_REL, sizeof(maskbit)), maskbit)" (calling this changing "EV_REL" with others "Input Event Codes"
analize "maskbit" by searching for some specific Values that only Touchscreen has
A possibile example could find here: https://android.googlesource.com/device/generic/brillo/+/d1917142dc905d808519023d80a664c066104600/examples/keyboard/keyboard_example.cpp in which the author looking for an Input that supports "KEY_B" Event Code.
Touchscreens should have:
for EV_ABS:
ABS_X
ABS_Y
ABS_MT_SLOT
ABS_MT_POSITION_X
ABS_MT_POSITION_Y
ABS_MT_TRACKING_ID
If the Input has all these Bit it is a Touchscreen (reference: https://www.kernel.org/doc/Documentation/input/multi-touch-protocol.txt)
adb shell dumpsys input - this will show the list of all event nodes with the details that you are looking for

Writing a driver i2c for MPC6050

I'm new in C, and I try to write a driver for MPC6050 accelerometer. (Kernel 3.4 for Android 4.2.2). This is the following of this question.
This page and this one helped me, but I can't use the driver yet:
arch/arm/mach-sun7i/core.c:77:44: warning: ‘sun7i_i2c_platform_data’ defined but not used [-Wunused-variable]
arch/arm/mach-sun7i/core.c:136:41: warning: ‘sun7i_i2c_platform_device’ defined but not used [-Wunused-variable]
I'm working on /ANDROID/lichee/linux-3.4/arch/arm/mach-sun7i/core.c file. (the equivalent of board-machine.c)
I have pasted the struct of each structure base.
The init functions are, I hope ok, like this:
/* ACCELEROMETER*/
#include <linux/i2c-gpio.h>
#include <linux/mpu.h>
#include <linux/i2c.h>
#include <mach/i2c.h>
#include <mach/gpio.h>
#define I2C_SDA TWI_LCR_SDA_EN
#define I2C_SCL TWI_LCR_SCL_EN
/*
* /////////// from linux/i2c-gpio.h //////////
*
struct i2c_gpio_platform_data {
unsigned int sda_pin;
unsigned int scl_pin;
int udelay;
int timeout;
unsigned int sda_is_open_drain:1;
unsigned int scl_is_open_drain:1;
unsigned int scl_is_output_only:1;
}; */
static struct i2c_gpio_platform_data sun7i_i2c_platform_data = {
.sda_pin = I2C_SDA, // gpio number
.scl_pin = I2C_SCL,
.udelay = 5, // 100KHz
.sda_is_open_drain = 0,
.scl_is_open_drain = 0,
.scl_is_output_only = 0
};
/*
* /////////// from linux/mpu.h //////////
*
struct mpu_platform_data {
__u8 int_config;
__u8 level_shifter;
__s8 orientation[9];
enum secondary_slave_type sec_slave_type;
enum ext_slave_id sec_slave_id;
__u16 secondary_i2c_addr;
__s8 secondary_orientation[9];
__u8 key[16];
enum secondary_slave_type aux_slave_type;
enum ext_slave_id aux_slave_id;
__u16 aux_i2c_addr;
int (*power_on)(struct mpu_platform_data *);
int (*power_off)(struct mpu_platform_data *);
struct regulator *vdd_ana;
struct regulator *vdd_i2c;
};
*/
static struct mpu_platform_data gyro_platform_data = {
.int_config = 0x00,
.level_shifter = 0,
.orientation = { -1, 0, 0,
0, 1, 0,
0, 0, -1 },
.sec_slave_type = SECONDARY_SLAVE_TYPE_COMPASS,
.sec_slave_id = COMPASS_ID_AK8972,
.secondary_i2c_addr = 0x0E
};
/*
* /////////// from i2c.h //////////
*
* struct i2c_board_info {
char type[I2C_NAME_SIZE];
unsigned short flags;
unsigned short addr;
void *platform_data;
struct dev_archdata *archdata;
struct device_node *of_node;
int irq;
};*/
//for MPU6050
#define IRQ_GPIO SUN7I_IRQ_TWI0
#define TWI_STAT_REG (0x10) /* 28 interrupt types + 0xF8 normal type = 29 */
static struct i2c_board_info __initdata sun7i_i2c_platform_device[] = {
{
I2C_BOARD_INFO("mpu6050", 0x68),
.irq = (IRQ_GPIO + TWI_STAT_REG),
.platform_data = &gyro_platform_data,
},
};
/*
// ORIGINAL FROM THE README PAGE //
static struct i2c_board_info __initdata single_chip_board_info[] = {
{
I2C_BOARD_INFO("mpu6050", 0x68), // can be 0x34
.irq = (IH_GPIO_BASE + MPUIRQ_GPIO),
.platform_data = &gyro_platform_data,
},
}; */
Now, my problem is to use and make active theses functions. I don't understand what means this:
static int __init omap4_panda_i2c_init(void)
{
omap_register_i2c_bus(4, 400,
single_chip_board_info,
ARRAY_SIZE(single_chip_board_info));
}
I can't find the register_i2c_bus equivalent in my folders.
And at the end of the file, I will call it like this:
static void __init sun7i_init(void)
{
pr_info("%s: enter\n", __func__);
sw_pdev_init();
/* Register platform devices here!! */
+ &sun7i_i2c_init();
+ pr_info("sun7i_i2c_init\n");
}
So, my question is: How to make active my init functions, because omap is a very different system comparate to sun7i ?
Any help should be very appeciate! Thanks a lot.
Edit: With this documentation the compilation don't fail.
The new dmesg is:
<3>[ 11.963914] inv-mpu-iio 1-0068: Unable to read axis_map_x
<3>[ 11.969998] i2c i2c-1: inv_mpu_probe failed -38
<4>[ 11.975080] inv-mpu-iio: probe of 1-0068 failed with error -5
<7>[ 11.975436] i2c-core: driver [inv-mpu-iio] registered

Getting a ANativeWindowBuffer from ANativeWindow_Buffer

To get fast OpenGL ES 2.0 texture pixel access on Android NDK, I want to use the eglCreateImageKHR() extension.
According to the EGL_NATIVE_BUFFER_ANDROID docs:
This extension enables using an Android window buffer (struct
ANativeWindowBuffer) as an EGLImage source.
ANativeWindowBuffer is an internal struct used by the native framework classes like GraphicBuffer.
Unfortunately, since I am on NDK I do not have direct access to these classes.
The NDK native_window interface allows me to pass a Java Surface object through to the NDK. I can then use ANativeWindow_fromSurface() to get an opaque ANativeWindow* handle. With this pointer I can call ANativeWindow_lock() to fill a struct of type ANativeWindow_Buffer (Note the _).
If I try to use this &ANativeWindow_Buffer object with eglCreateImageKHR() it fails with EGL_BAD_NATIVE_WINDOW.
My question is: How can I use ANativeWindow_Buffer with eglCreateImageKHR() or alternatively how to get an ANativeWindowBuffer from ANativeWindow_Buffer or from ANativeWindow*.
From what I figured out while going down this road, ANativeWindow_Buffer and ANativeWindowBuffer are entirely different types. Well, they are somewhat similar, but definitely so different that they can't be used interchangeably.
If you want to compare, here are the definitions:
ANativeWindow_Buffer: http://androidxref.com/4.4.4_r1/xref/prebuilts/ndk/current/platforms/android-18/arch-arm/usr/include/android/native_window.h
ANativeWindowBuffer: http://androidxref.com/4.4.4_r1/xref/system/core/include/system/window.h
You will notice that they have a few fields in common (width, height, stride, format). The big difference is that ANativeWindow_Buffer contains a pointer to the actual data, while ANativeWindowBuffer contains an opaque handle of type buffer_handle_t.
So if you found out how to get a ANativeWindow_Buffer, and were hoping that you were well on your way to a ANativeWindowBuffer, you're... probably not. At least that was my conclusion. I think the very similar names are just a tease.
I did not find a way to create an ANativeWindowBuffer from NDK code. At least with using only supported APIs, I believe it's not possible. My research was with KitKat.
I found this question and I though it might be useful to answer it with newer information and developments, since I had to look up again on how to do it and this was one of the first answers on google for ImageKHR.
This is how you get a native buffer to use with ImageKHR. You have to "politely" ask for one from the gralloc, for that you just open the linux_kernel file that represents the IPC between the binder and gralloc, its way deeper inside the internals.
The technique demonstrated bellow will use dlopen to get the pointers to one of the ".so" that does that, but as it is internal to the system, and uses JNI reflection, there's a chance that the app verifier won't like it if you try to publish it.
You can circunvent it by going one level deeper and implementing what the gralloc itself does, it just writes and reads a file block device, the app verifier wouldn't stand a chance if its just a fopen call, it can't possibly check in runtime the difference between calls from the actual libui.so or you code, it just do a simple static analysis.
For doing this you can just copy the source code of the GrAlloc or link the libui.so with a different name as said in the github project.
Just for completeness, although I use this technique, I have a fallback using PBOs for transferring data from the GPU to the CPU in case of failures, but in most cases PBOs have acceptable performance.
the bare minimum needed
the complete library for doing this I used as reference
FramebufferNativeWindow.cpp
GraphicBuffer.h
#pragma once
#include <exception>
#include <cstdint>
#include <cerrno>
class DynamicLibrary
{
public:
DynamicLibrary(const char *fileName);
~DynamicLibrary();
void *getFunctionPtr(const char *name) const;
DynamicLibrary(const DynamicLibrary &) = delete;
DynamicLibrary & operator = (const DynamicLibrary &other) = delete;
private:
void *libHandle;
};
struct ANativeWindowBuffer;
namespace android
{
class GraphicBuffer;
// include/system/window.h
struct android_native_base_t
{
uint32_t magic;
uint32_t version;
void* reserved[4];
void (*incRef)(struct android_native_base_t* base);
void (*decRef)(struct android_native_base_t* base);
};
// include/ui/android_native_buffer.h
struct android_native_buffer_t
{
struct android_native_base_t common;
int32_t width;
int32_t height;
int32_t stride;
int32_t format;
int32_t usage;
// ...
};
}
// utils/Errors.h
enum status_t
{ /*ommited, look at the gist */ };
// ui/PixelFormat.h, system/graphics.h
enum PixelFormat
{ /*ommited, look at the gist */ };
// ui/GraphicBuffer.h
{ /*ommited, look at the gist */ };
class GraphicBuffer
{
public:
// ui/GraphicBuffer.h, hardware/gralloc.h
GraphicBuffer(uint32_t width, uint32_t height, PixelFormat format, uint32_t usage);
~GraphicBuffer();
status_t lock(uint32_t usage, void** vaddr);
status_t unlock();
ANativeWindowBuffer *getNativeBuffer() const;
uint32_t getStride() const;
private:
DynamicLibrary library;
GraphicBufferFunctions functions;
android::GraphicBuffer *impl = nullptr;
};
#include "GraphicBuffer.h"
And the implementation:
GraphicBuffer.cpp
#include <string>
#include <cstdlib>
#include <iostream>
#include <iostream>
#include <dlfcn.h>
const int GRAPHICBUFFER_SIZE = 1024;
using std::string;
DynamicLibrary::DynamicLibrary(const char *fileName)
{
libHandle = dlopen(fileName, RTLD_LAZY);
if (!libHandle) throw OpenLibFailedException();
}
DynamicLibrary::~DynamicLibrary()
{
if (libHandle) dlclose(libHandle);
}
void *DynamicLibrary::getFunctionPtr(const char *name) const
{
auto ret = (void *)dlsym(libHandle, name);
if (ret == nullptr) {
std::cerr << "Failed to get function " << name << std::endl;
}
return ret;
}
template<typename Func>
void setFuncPtr(Func *&funcPtr, const DynamicLibrary &lib, const string &symname) {
funcPtr = reinterpret_cast<Func *>(lib.getFunctionPtr(symname.c_str()));
}
#if defined(__aarch64__)
# define CPU_ARM_64
#elif defined(__arm__) || defined(__ARM__) || defined(__ARM_NEON__) || defined(ARM_BUILD)
# define CPU_ARM
#elif defined(_M_X64) || defined(__x86_64__) || defined(__amd64__)
# define CPU_X86_64
#elif defined(__i386__) || defined(_M_X86) || defined(_M_IX86) || defined(X86_BUILD)
# define CPU_X86
#else
# warning "target CPU does not support ABI"
#endif
template<typename RT, typename T1, typename T2, typename T3, typename T4>
RT *callConstructor4(void (*fptr)(), void *memory, T1 param1, T2 param2, T3 param3, T4 param4) {
#if defined(CPU_ARM)
// C1 constructors return pointer
typedef RT* (*ABIFptr)(void*, T1, T2, T3, T4);
(void)((ABIFptr)fptr)(memory, param1, param2, param3, param4);
return reinterpret_cast<RT*>(memory);
#elif defined(CPU_ARM_64)
// C1 constructors return void
typedef void (*ABIFptr)(void*, T1, T2, T3, T4);
((ABIFptr)fptr)(memory, param1, param2, param3, param4);
return reinterpret_cast<RT*>(memory);
#elif defined(CPU_X86) || defined(CPU_X86_64)
// ctor returns void
typedef void (*ABIFptr)(void *, T1, T2, T3, T4);
((ABIFptr) fptr)(memory, param1, param2, param3, param4);
return reinterpret_cast<RT *>(memory);
#else
return nullptr;
#endif
}
template<typename T>
void callDestructor(void (*fptr)(), T *obj) {
#if defined(CPU_ARM)
// D1 destructor returns ptr
typedef void* (*ABIFptr)(T* obj);
(void)((ABIFptr)fptr)(obj);
#elif defined(CPU_ARM_64)
// D1 destructor returns void
typedef void (*ABIFptr)(T* obj);
((ABIFptr)fptr)(obj);
#elif defined(CPU_X86) || defined(CPU_X86_64)
// dtor returns void
typedef void (*ABIFptr)(T *obj);
((ABIFptr) fptr)(obj);
#endif
}
template<typename T1, typename T2>
T1 *pointerToOffset(T2 *ptr, size_t bytes) {
return reinterpret_cast<T1 *>((uint8_t *) ptr + bytes);
}
static android::android_native_base_t *getAndroidNativeBase(android::GraphicBuffer *gb) {
return pointerToOffset<android::android_native_base_t>(gb, 2 * sizeof(void *));
}
GraphicBuffer::GraphicBuffer(uint32_t width, uint32_t height, PixelFormat format, uint32_t usage) :
library("libui.so") {
setFuncPtr(functions.constructor, library, "_ZN7android13GraphicBufferC1Ejjij");
setFuncPtr(functions.destructor, library, "_ZN7android13GraphicBufferD1Ev");
setFuncPtr(functions.getNativeBuffer, library,
"_ZNK7android13GraphicBuffer15getNativeBufferEv");
setFuncPtr(functions.lock, library, "_ZN7android13GraphicBuffer4lockEjPPv");
setFuncPtr(functions.unlock, library, "_ZN7android13GraphicBuffer6unlockEv");
setFuncPtr(functions.initCheck, library, "_ZNK7android13GraphicBuffer9initCheckEv");
// allocate memory for GraphicBuffer object
void *const memory = malloc(GRAPHICBUFFER_SIZE);
if (memory == nullptr) {
std::cerr << "Could not alloc for GraphicBuffer" << std::endl;
return;
}
try {
android::GraphicBuffer *const gb =
callConstructor4<android::GraphicBuffer, uint32_t, uint32_t, PixelFormat, uint32_t>(
functions.constructor,
memory,
width,
height,
format,
usage
);
android::android_native_base_t *const base = getAndroidNativeBase(gb);
status_t ctorStatus = functions.initCheck(gb);
if (ctorStatus) {
// ctor failed
callDestructor<android::GraphicBuffer>(functions.destructor, gb);
std::cerr << "GraphicBuffer ctor failed, initCheck returned " << ctorStatus <<
std::endl;
}
// check object layout
if (base->magic != 0x5f626672u) // "_bfr"
std::cerr << "GraphicBuffer layout unexpected" << std::endl;
// check object version
const uint32_t expectedVersion = sizeof(void *) == 4 ? 96 : 168;
if (base->version != expectedVersion)
std::cerr << "GraphicBuffer version unexpected" << std::endl;
base->incRef(base);
impl = gb;
} catch (...) {
free(memory);
throw;
}
}
GraphicBuffer::~GraphicBuffer() {
if (impl) {
android::android_native_base_t *const base = getAndroidNativeBase(impl);
base->decRef(base);
//no need to call it, decRef will do
//callDestructor<android::GraphicBuffer>(functions.destructor, impl);
}
}
status_t GraphicBuffer::lock(uint32_t usage, void **vaddr) {
return functions.lock(impl, usage, vaddr);
}
status_t GraphicBuffer::unlock() {
return functions.unlock(impl);
}
/// Here it is, the windowbuffer !!!
ANativeWindowBuffer *GraphicBuffer::getNativeBuffer() const {
return functions.getNativeBuffer(impl);
}
uint32_t GraphicBuffer::getStride() const {
return ((android::android_native_buffer_t *) getNativeBuffer())->stride;
}
References:

Bad type conversion in android ndk

I want my Android application to create a fake virtual device, to achieve this the device needs to be rooted and uinput module is needed.
I am using the following code to create the device, calling
static{ System.loadLibrary("myModule"); }
CreateVirtualDevice("Devname",0x123,0x123);
inside my java code.
Here the native code:
#include <string.h>
#include <jni.h>
#include <fcntl.h>
#include <linux/input.h>
#include <linux/uinput.h>
static int fd;
static struct uinput_user_dev dev;
short int analog_axis_list[] = { ABS_X,ABS_Y,ABS_RX,ABS_RY, -1};
jint Java_com_example_app_MyClass_CreateVirtualDevice(
JNIEnv* env, jobject thiz, jstring param, jint param2, jint param3) {
int i;
memset(&dev, 0, sizeof(dev));
fd = open("/dev/uinput", O_WRONLY | O_NONBLOCK);
if (fd < 0)
return -1;
if(ioctl(fd, UI_SET_EVBIT, EV_ABS)<0) return -4;
for(i=0;analog_axis_list[i]>=0;i++){
if(ioctl(fd,UI_SET_ABSBIT,analog_axis_list[i])<0) return -5;
dev.absmax[analog_axis_list[i]]=32767;
dev.absmin[analog_axis_list[i]]=-32768;
}
const char *cparam = (*env)->GetStringUTFChars(env, param, 0);
snprintf(dev.name, UINPUT_MAX_NAME_SIZE, cparam);
(*env)->ReleaseStringUTFChars(env, param, cparam);
dev.id.bustype = BUS_VIRTUAL;
dev.id.vendor = param2;
dev.id.product = param3;
dev.id.version = 1;
if (write(fd, &dev, sizeof(dev)) < 0)
return -7;
if (ioctl(fd, UI_DEV_CREATE) < 0)
return -8;
return 0;
}
The device is successfully created, and the return value is 0.
Inside input.h the ABS values are so defined:
#define ABS_X 0x00
#define ABS_Y 0x01
#define ABS_RX 0x03
#define ABS_RY 0x04
But when checking the axis on android, I get proper values for AXIS_X and AXIS_Y, but ABS_RX and ABS_RY have wrong values. I used this code to check the axis values:
InputDevice device = InputDevice.getDevice(ids[position]);
List<InputDevice.MotionRange> ranges = device.getMotionRanges();
StringBuilder sb = new StringBuilder("");
if(ranges.size()==0){
sb.append("NO_MOTION_RANGES");
}
else{
int i = 0;
for(InputDevice.MotionRange range:ranges) {
if(i>0) {
sb.append(",");
}
sb.append(MotionEvent.axisToString(range.getAxis()));
sb.append("(").append(range.getAxis()).append(")");
i++;
}
}
return sb.toString();
And the result is:
AXIS_X(0),AXIS_Y(1),AXIS_Z(11),AXIS_RZ(14)
I am using the latest NDK release (r10d) without any particular settings enabled. What can cause these errors?
I want to point out that it's my code to have something wrong, because with an actual controller the axis numbers are correct.
Edit 1:
I tried to return analog_axis_list[2], which is ABS_RX, at the end of my function instead of 0 and it returns 3, so I think I'm passing a wrong type to the ioctl call.
Which type should I choose?
Android uses AXIS_Z and AXIS_RZ for the right stick; this is consistent with USB HID.

Thread affinity in Android with C program

I have strange problems with thread affinity. I have created a program in C:
#define _GNU_SOURCE
#include<stdio.h>
#include <sys/syscall.h>
#include<string.h>
#include<pthread.h>
#include<stdlib.h>
#include<unistd.h>
#include <time.h>
#include <errno.h>
#define handle_error_en(en, msg) \
do { errno = en; perror(msg); exit(EXIT_FAILURE); } while (0)
#define NANOS 1000000000LL
#define SIZE 1000
void* mesaureTime(void *cpu)
{
unsigned long i = 0;
int s;
cpu_set_t cpuset;
struct timespec start, end;
long elapsed;
pthread_t id = pthread_self();
CPU_ZERO(&cpuset);
CPU_SET(*(int *) cpu, &cpuset);
s = pthread_setaffinity_np(id, sizeof(cpu_set_t), &cpuset);
if (s != 0)
handle_error_en(s, "pthread_setaffinity_np");
if(pthread_equal(id,tid[0]))
printf("Realizando test...\n");
while(i<SIZE){
clock_gettime(CLOCK_MONOTONIC, &start);
// Do some calculation.
factorial(150000);
clock_gettime(CLOCK_MONOTONIC, &end);
arrayTimes[i] = elapsed;
elapsed = end.tv_nsec - start.tv_nsec + (end.tv_sec - start.tv_sec)*NANOS;
i++;
}
printf("Finished\n");
return 0;
}
int factorial(int a){
if (a==1){
return 1;
}else{
a=a*factorial(a-1);
}
return a;
}
int main(int argc, char *argv[])
{
int i = 0;
int err, result;
int *cpu_pointer;
int cpu = atoi(argv[1]);
cpu_pointer = &cpu;
err = pthread_create(&tid[i], NULL, mesaureTime, (void *) cpu_pointer);
if (err != 0)
printf("can't create thread :[%s]", strerror(err));
else
printf("Hilo de test creado satisfactoriamente\n");
pthread_join(tid[0], NULL);
printf("\n Finalizado el test\n");
return 0;
}
This code works well in a Dual Core Intel CPU with Ubuntu, but when I have compiled it with arm-linux-gnueabi-gcc and I have executed in my Android devices (Nexus 4, Nexus 5 and S4), the program can't assign the thread in CPU 2, CPU 3 or CPU 4, it has only worked in CPU 1. The pthread_setaffinity_np function always returns an error (invalid argument) with CPU 2, 3 or 4.
I have read some questions here Is it possible to set affinity with sched_setaffinity in Android? and Android set thread affinity. I have tried it but I have obtain the same result.
The following description from the manual about this error:
EINVAL (pthread_setaffinity_np()) cpuset specified a CPU that was
outside the set supported by the kernel. (The kernel
configuration option CONFIG_NR_CPUS defines the range of the
set supported by the kernel data type used to represent CPU
sets.)
So it looks like your current kernel has been configured/built with CONFIG_NR_CPUS = 1. This seems to be reason your program is not able to set affinity to your threads to run on other core of your machine.
You may have recompile your kernel to achieve this.

Categories

Resources