How to make spidev.c work on samsung s5p6818/Android5.1 - android

I'am using a develop board of samsung s5p6818 soc. After choosing "user mode spi""SLSI SPI port0" on menuconfig, and adding these code in plat-s5p6818/drone/device.c,
/*------------------------------------------------------------------------------
* SSP/SPI
*/
#if defined(CONFIG_SPI_SPIDEV) || defined(CONFIG_SPI_SPIDEV_MODULE)
#include <linux/spi/spi.h>
#include <linux/gpio.h>
#include <mach/slsi-spi.h>
static struct s3c64xx_spi_csinfo spi0_csi[] = {
[0] = {
.line = CFG_SPI0_CS,
.set_level = gpio_set_value,
.fb_delay = 0x2,
},
};
static struct spi_board_info spi_plat_board[] __initdata = {
[0] = {
.modalias = "spidev", /* fixup */
.max_speed_hz = 3125000, /* max spi clock (SCK) speed in HZ */
.bus_num = 0, /* Note> set bus num, must be smaller than ARRAY_SIZE(spi_plat_device) */
.chip_select = 0, /* Note> set chip select num, must be smaller than spi cs_num */
.controller_data = &spi0_csi[0],//spi0_info,
.mode = SPI_MODE_3 | SPI_CPOL | SPI_CPHA,
},
};
#endif
spi_register_board_info(spi_plat_board,ARRAY_SIZE(spi_plat_board));
/*--------------------------------------------------------------------------*/
I can find "spidev0.0" in /dev when Android system is operating on my board. However, this device dosen't work when I use a testing program calling the function read/write, and cause my system to reboot (function "open","ioctl" can work properly). Here is my testing code
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <linux/ioctl.h>
#define SPI_IOC_MAGIC 'k'
#define SPI_CPHA 0x01
#define SPI_CPOL 0x02
#define SPI_MODE_0 (0|0)
#define SPI_MODE_1 (0|SPI_CPHA)
#define SPI_MODE_2 (SPI_CPOL|0)
#define SPI_MODE_3 (SPI_CPOL|SPI_CPHA)
typedef unsigned char __u8;
typedef unsigned int __u32;
/* Read / Write of SPI mode (SPI_MODE_0..SPI_MODE_3) */
#define SPI_IOC_RD_MODE _IOR(SPI_IOC_MAGIC, 1, __u8)
#define SPI_IOC_WR_MODE _IOW(SPI_IOC_MAGIC, 1, __u8)
/* Read / Write SPI bit justification */
#define SPI_IOC_RD_LSB_FIRST _IOR(SPI_IOC_MAGIC, 2, __u8)
#define SPI_IOC_WR_LSB_FIRST _IOW(SPI_IOC_MAGIC, 2, __u8)
/* Read / Write SPI device word length (1..N) */
#define SPI_IOC_RD_BITS_PER_WORD _IOR(SPI_IOC_MAGIC, 3, __u8)
#define SPI_IOC_WR_BITS_PER_WORD _IOW(SPI_IOC_MAGIC, 3, __u8)
/* Read / Write SPI device default max speed hz */
#define SPI_IOC_RD_MAX_SPEED_HZ _IOR(SPI_IOC_MAGIC, 4, __u32)
#define SPI_IOC_WR_MAX_SPEED_HZ _IOW(SPI_IOC_MAGIC, 4, __u32)
static int fd = 0;
int main(void)
{
// int fd = -1;
int buf[1000];
int i = 0;
fd = open("/dev/spidev0.0", O_RDWR);
if(fd < 0){
printf("open /dev/spidev0.0 error!!!\n");
}
printf("-------------===============------------fd=%d\n",fd);
spi_init();
for (i=0;i<1000;i++)
{
buf[i]=0x33333333;
}
for(i=0;i<20;i++)
{ write(fd,buf,1000*4);
}
return 0;
}
void spi_init(void){
int ret = 0;
int speed = 2*1000*1000;
int delay;
unsigned char bits = 32;
unsigned char mode = SPI_MODE_1;
ret = ioctl(fd, SPI_IOC_WR_MODE, &mode);
if(ret == -1){
printf("can't set spi mode\n");
}else{
printf("set spi mode %d\n",ret);
}
ret = ioctl(fd, SPI_IOC_RD_MODE, &mode);
if(ret == -1){
printf("can't get spi mode\n");
}else{
printf("get spi mode %d\n",ret);
}
ret = ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &bits);
if(ret == -1){
printf("can't set bits per word\n");
}else{
printf("set bits per word %d\n",ret);
}
ret = ioctl(fd, SPI_IOC_RD_BITS_PER_WORD, &bits);
if(ret == -1){
printf("can't get bits per word\n");
}else{
printf(" get bits per word %d\n",ret);
}
ret = ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed);
if(ret == -1){
printf("can't set max speed hz\n");
}else{
printf("set max speed hz %d\n",ret);
}
ret = ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ, &speed);
if(ret == -1){
printf("can't get max speed hz\n");
}else{
printf("get max speed hz %d\n",ret);
}
}
Here is my debug loglog
I think this is because I didn't config gpio correctly, but I don't know how and where to config gpio pins. I hope someone can teach me how to make this correct.

you can set gpio function in plat-s5p6818/drone/include/cfg_gpio.h for examples check how i2c bus interface is defined for your arch.

Related

Executing self generated machine code on mobile platforms

There are a couple of questions already on SO assessing the possibility of executing self generated code. The generic answer is that it's possible, it's being done in JIT compilers and with dynamic library loading.
The application is in optimisation of sparse convolutions where the sparse structure should be embedded in the code, since skipping multiplication by zeros conditionally is slower than multiplying by zeros. Neither it's feasible in terms of performance to encode the structure in data:
do { // actually: don't do this
auto offset = *encoded_offset++;
auto coeff = *encoded_coefficient++;
accum += data[offset] * coeff;
} while (end_of_data); // e.g. offset < 0, or offset == previous offset
Vs.
...
ldr q5, [x1], 16 ; load data
fmla v0.4s, v5.4s, v8.s[0]
fmla v1.4s, v5.4s, v8.s[1]
fmla v2.4s, v5.4s, v8.s[2]
// fmla v3.4s, v5.4s, v8.s[3] ; omitted, when |weight| < threshold
fmla v4.4s, v5.4s, v8.s[3] ; we reuse the v8.s[3] with a weight that matters
ldr q5, [x1], 16
// fmla v0.4s, v5.4s, v9.s[0] ; omitted, when |weight| < threshold
// fmla v1.4s, v5.4s, v9.s[0] ; omitted
fmla v2.4s, v5.4s, v9.s[0]
fmla v3.4s, v5.4s, v9.s[1]
fmla v4.4s, v5.4s, v9.s[2]
; + several kilobytes of instructions
It's possible to generate the code by templates, but it would be far more efficient (and marginally more secure reverse engineering in mind) if the code was generated on the fly.
Now the question is, how to exactly call the generated function in some of the most important mobile ecosystems: Ios, android and possibly webassembly (using off course WASM (SIMD) bytecode).
What exact system calls need to be issued to be able to execute the block of memory filled with the code -- legally?
The only problem you will stumble upon is that "normal" memory is usually protected against execution. You just need to set on that memory the execute permission.
After that you can set any sort of instructions you want. See for example the top fizzbuzz bandwidth winner, who uses a simple JIT machine.
https://codegolf.stackexchange.com/a/236630/108147
But the basic code is this:
#include <string>
#include <iostream>
#include <stdlib.h>
#include <unistd.h>
#include <sys/mman.h>
#include <string.h>
uint8_t code[] = { 0x89, 0xf8, // mov eax, edi
0x0f, 0xaf, 0xc6, // imul eax, esi
0xc3 }; // ret
int main() {
using multifn = int( int a, int b);
size_t pagesize = getpagesize();
size_t codesize = ((sizeof(code)-1)/pagesize+1)*pagesize;
uint64_t codeaddr = uint64_t(code);
codeaddr -= codeaddr % pagesize;
mprotect((void*)codeaddr, codesize, PROT_READ | PROT_WRITE |PROT_EXEC);
multifn* m = reinterpret_cast<multifn*>(code);
std::cout << "Result:" << m(2,3) << std::endl;
return 0;
}
I just ran it in my Linux box as a regular user and the result is:
Program stdout
Result:6
I assume that as Android is basically Linux, the result will be the same. As per IOS I have to speculate here.
Also Godbolt: https://godbolt.org/z/hsMKWsjM9
If you are really picky about not messing up with regular memory, you can create a separate page for your generated code
#include <string>
#include <iostream>
#include <stdlib.h>
#include <unistd.h>
#include <sys/mman.h>
#include <string.h>
void* createExecPage( size_t size ) {
size_t pagesize = getpagesize();
size = ((size-1)/pagesize+1)*pagesize;
std::cout << "Pagesize:" << pagesize << " size:" << size << std::endl;
void* temp = nullptr;
int res = posix_memalign(&temp, pagesize, size );
if ( res!=0 ) {
perror("posix_memalign");
}
res = mprotect(temp, size, PROT_READ | PROT_WRITE |PROT_EXEC);
if ( res!=0 ) {
perror( "mprotect" );
}
return temp;
}
uint8_t code[] = { 0x89, 0xf8, // mov eax, edi
0x0f, 0xaf, 0xc6, // imul eax, esi
0xc3 }; // ret
int main()
{
using multifn = int( int a, int b);
void* xpage = createExecPage(sizeof(code));
memcpy( xpage, code, sizeof(code));
multifn* m = reinterpret_cast<multifn*>(xpage);
std::cout << "Result:" << m(2,3) << std::endl;
return 0;
}
https://godbolt.org/z/ebW76o1KP

Writing to framebuffer directly on Android

I've a rooted phone with Android 4.2.2. I'd like to use minui API used (source here) in bootloader code to draw stuff on the screen. minui is much simpler than native OpenGL and I don't need any complex functionality exposed by OpenGL.
The problem is that I can't write stuff directly to fb0 device. FBIOPUT_VSCREENINFO fails for unknown reason.
How can I draw directly to fb0 on Android, or how can I use minui outside the bootloader mode?
device node:/dev/graphics/fb0
you can build in Android tree or use arm-linux-gcc.
arm-linux-gcc -D__ANDROID__ fb-test.c -static
likes a normal embeded linux, there is a sample:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <linux/fb.h>
#include <sys/mman.h>
struct fb_fix_screeninfo FixedInfo;
struct fb_var_screeninfo OrigVarInfo;
static int FrameBufferFD = -1;
void *FrameBuffer = (void *) -1;
#ifndef __ANDROID__
#define FRAMEBUFFER "/dev/fb0"
#else
#define FRAMEBUFFER "/dev/graphics/fb0"
#endif //__ANDROID__
void openFBDEV(void)
{
/* open the framebuffer device */
FrameBufferFD = open(FRAMEBUFFER, O_RDWR);
if (FrameBufferFD < 0)
{
fprintf(stderr, "Error opening %s\n", FRAMEBUFFER);
exit(1);
}
/* Get the fixed screen info */
if (ioctl(FrameBufferFD, FBIOGET_FSCREENINFO, &FixedInfo))
{
fprintf(stderr, "error: ioctl(FBIOGET_FSCREENINFO) failed\n");
exit(1);
}
/* get the variable screen info */
if (ioctl(FrameBufferFD, FBIOGET_VSCREENINFO, &OrigVarInfo))
{
fprintf(stderr, "error: ioctl(FBIOGET_VSCREENINFO) failed\n");
exit(1);
}
if (FixedInfo.visual != FB_VISUAL_TRUECOLOR
&& FixedInfo.visual != FB_VISUAL_DIRECTCOLOR)
{
fprintf(stderr,
"non-TRUE/DIRECT-COLOR visuals (0x%x) not supported by this demo.\n",
FixedInfo.visual);
exit(1);
}
/*
* fbdev says the frame buffer is at offset zero, and the mmio region
* is immediately after.
*/
/* mmap the framebuffer into our address space */
FrameBuffer = (void *) mmap(0, /* start */
FixedInfo.smem_len, /* bytes */
PROT_READ | PROT_WRITE, /* prot */
MAP_SHARED, /* flags */
FrameBufferFD, /* fd */
0 /* offset */);
if (FrameBuffer == (void *) -1)
{
fprintf(stderr, "error: unable to mmap framebuffer\n");
exit(1);
}
}
void closeFBDEV(void)
{
munmap(FrameBuffer, FixedInfo.smem_len);
close(FrameBufferFD);
}
int main()
{
openFBDEV();
fprintf(stderr, "openFBDEV finish\n");
memset(FrameBuffer, 128, FixedInfo.smem_len);
sleep(5);
closeFBDEV();
fprintf(stderr, "closeFBDEV finish\n");
return 0;
}
Source code,test it works in Qualcomm platform MSM89xx:
panel_test.c
#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>
#include <linux/fb.h>
#include <sys/mman.h>
#include <stdlib.h>
#include "yellow_face.zif"
int main()
{
int fbfd = 0;
struct fb_var_screeninfo vinfo;
struct fb_fix_screeninfo finfo;
struct fb_cmap cmapinfo;
long int screensize = 0;
char *fbp = 0;
int x = 0, y = 0;
long int location = 0;
int b,g,r;
// Open the file for reading and writing
fbfd = open("/dev/graphics/fb0", O_RDWR,0); // 打开Frame Buffer设备
if (fbfd < 0) {
printf("Error: cannot open framebuffer device.%x\n",fbfd);
exit(1);
}
printf("The framebuffer device was opened successfully.\n");
// Get fixed screen information
if (ioctl(fbfd, FBIOGET_FSCREENINFO, &finfo)) { // 获取设备固有信息
printf("Error reading fixed information.\n");
exit(2);
}
printf("\ntype:0x%x\n", finfo.type ); // FrameBuffer 类型,如0为象素
printf("visual:%d\n", finfo.visual ); // 视觉类型:如真彩2,伪彩3
printf("line_length:%d\n", finfo.line_length ); // 每行长度
printf("\nsmem_start:0x%lx,smem_len:%u\n", finfo.smem_start, finfo.smem_len ); // 映象RAM的参数
printf("mmio_start:0x%lx ,mmio_len:%u\n", finfo.mmio_start, finfo.mmio_len );
// Get variable screen information
if (ioctl(fbfd, FBIOGET_VSCREENINFO, &vinfo)) { // 获取设备可变信息
printf("Error reading variable information.\n");
exit(3);
}
printf("%dx%d, %dbpp,xres_virtual=%d,yres_virtual=%dvinfo.xoffset=%d,vinfo.yoffset=%d\n", vinfo.xres, vinfo.yres, vinfo.bits_per_pixel,vinfo.xres_virtual,vinfo.yres_virtual,vinfo.xoffset,vinfo.yoffset);
screensize = finfo.line_length * vinfo.yres_virtual;
// Map the device to memory 通过mmap系统调用将framebuffer内存映射到用户空间,并返回映射后的起始地址
fbp = (char *)mmap(0, screensize, PROT_READ | PROT_WRITE, MAP_SHARED,fbfd, 0);
if ((int)fbp == -1) {
printf("Error: failed to map framebuffer device to memory.\n");
exit(4);
}
printf("The framebuffer device was mapped to memory successfully.\n");
/***************exampel 1**********************/
b = 10;
g = 100;
r = 100;
for ( y = 0; y < 340; y++ )
for ( x = 0; x < 420; x++ ) {
location = (x+100) * (vinfo.bits_per_pixel/8) +
(y+100) * finfo.line_length;
if ( vinfo.bits_per_pixel == 32 ) { //
*(fbp + location) = b; // Some blue
*(fbp + location + 1) = g; // A little green
*(fbp + location + 2) = r; // A lot of red
*(fbp + location + 3) = 0; // No transparency
}
}
/*****************exampel 1********************/
/*****************exampel 2********************/
unsigned char *pTemp = (unsigned char *)fbp;
int i, j;
//起始坐标(x,y),终点坐标(right,bottom)
x = 400;
y = 400;
int right = 700;//vinfo.xres;
int bottom = 1000;//vinfo.yres;
for(i=y; i< bottom; i++)
{
for(j=x; j<right; j++)
{
unsigned short data = yellow_face_data[(((i-y) % 128) * 128) + ((j-x) %128)];
pTemp[i*finfo.line_length + (j*4) + 2] = (unsigned char)((data & 0xF800) >> 11 << 3);
pTemp[i*finfo.line_length + (j*4) + 1] = (unsigned char)((data & 0x7E0) >> 5 << 2);
pTemp[i*finfo.line_length + (j*4) + 0] = (unsigned char)((data & 0x1F) << 3);
}
}
/*****************exampel 2********************/
//note:vinfo.xoffset =0 vinfo.yoffset =0 否则FBIOPAN_DISPLAY不成功
if (ioctl(fbfd, FBIOPAN_DISPLAY, &vinfo)) {
printf("Error FBIOPAN_DISPLAY information.\n");
exit(5);
}
sleep(10);
munmap(fbp,finfo.smem_len);//finfo.smem_len == screensize == finfo.line_length * vinfo.yres_virtual
close(fbfd);
return 0;
}
Android.mk
# Copyright 2006-2014 The Android Open Source Project
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= panel_test.c
LOCAL_SHARED_LIBRARIES := $(common_libs) libqdutils libdl liblog libbase libcutils
LOCAL_C_INCLUDES := $(common_includes) $(kernel_includes)
LOCAL_ADDITIONAL_DEPENDENCIES := $(common_deps) $(kernel_deps)
LOCAL_MODULE := panel_test
LOCAL_CFLAGS := -Werror
include $(BUILD_EXECUTABLE)
include $(call first-makefiles-under,$(LOCAL_PATH))
yellow_face.zif
yellow_face.zif

How to capture screenshot from FrameBuffer?

I want to capture screenshot from FrameBuffer in Android, I use the code below, but just got a fuzzy image.I contains 3 main steps. first, read data and info from FrameBuffer, second, convert the raw data to 24 bits, third, construct the BITMAP structs and write to bmp file. But I got fuzzy images, does anyone could help?I will appreciate it.
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <linux/fb.h>
#include <sys/ioctl.h>
typedef unsigned char BYTE;
typedef unsigned short WORD;
typedef unsigned int DWORD;
typedef long LONG;
typedef struct tagBITMAPFILEHEADER {
WORD bfType;
DWORD bfSize;
WORD bfReserved1;
WORD bfReserved2;
DWORD bfOffBits;
}__attribute__((packed)) BITMAPFILEHEADER, *PBITMAPFILEHEADER;
typedef struct tagBITMAPINFOHEADER {
DWORD biSize;
LONG biWidth;
LONG biHeight;
WORD biPlanes;
WORD biBitCount;
DWORD biCompression;
DWORD biSizeImage;
LONG biXPelsPerMeter;
LONG biYPelsPerMeter;
DWORD biClrUsed;
DWORD biClrImportant;
}__attribute__((packed)) BITMAPINFOHEADER, *PBITMAPINFOHEADER;
typedef struct tagRGBQUAD {
BYTE rgbBlue;
BYTE rgbGreen;
BYTE rgbRed;
BYTE rgbReserved;
}__attribute__((packed)) RGBQUAD;
#define FRAME_BUFFER_PATH "/dev/graphics/fb0"
int take_screenshot(char *path)
{
int i;
int img_fd, fb_fd;
int data_size;
char *img_buf;
struct fb_var_screeninfo var_info;
struct fb_fix_screeninfo fix_info;
BITMAPFILEHEADER file_head;
BITMAPINFOHEADER info_head;
//RGBQUAD rgb_quad;
/*open files*/
fb_fd = open(FRAME_BUFFER_PATH, O_RDWR);
if (img_fd < 0) {
perror("open framebuff");
return -1;
}
if (ioctl(fb_fd, FBIOGET_VSCREENINFO, &var_info) < 0) {
perror("ioctl FBIOGET_VSCREENINFO");
close(img_fd);
return 0;
}
printf("xres %d, yres %d\n", var_info.xres, var_info.yres);
if (ioctl(fb_fd, FBIOGET_FSCREENINFO, &fix_info)){
debug("Error reading fixed information\n");
close(img_fd);
return 0;
}
img_fd = open(path, O_RDWR | O_CREAT, 0644);
if (img_fd < 0)
{
perror("open image");
close(img_fd);
return -1;
}
data_size = var_info.xres*var_info.yres*(var_info.bits_per_pixel/8);
/*initialize bmp structs*/
file_head.bfType = 0x4d42;
file_head.bfSize = sizeof(file_head) + sizeof(info_head) + data_size;
file_head.bfReserved1 = 0;
file_head.bfReserved2 = 0;
file_head.bfOffBits = sizeof(file_head) + sizeof(info_head);
info_head.biSize = sizeof(info_head);
info_head.biWidth = var_info.xres;
info_head.biHeight = -var_info.yres;
info_head.biPlanes = 0;
info_head.biBitCount = 24;
info_head.biCompression = 0;
info_head.biSizeImage = data_size;
info_head.biXPelsPerMeter = 3780;
info_head.biYPelsPerMeter = 3780;
info_head.biClrUsed = 0;
info_head.biClrImportant = 0;
img_buf = (char *)malloc(data_size);
if (img_buf == NULL)
{
printf("malloc failed!\n");
close(fb_fd);
close(img_fd);
return -1;
}
/*read img data and */
read(fb_fd, img_buf, data_size);
write(img_fd, &file_head, sizeof(file_head));
write(img_fd, &info_head, sizeof(info_head));
/*********************/
int w, h;
int depth;
unsigned short *bits;
w = var_info.xres;
h = var_info.yres;
depth = var_info.bits_per_pixel;
uint8_t *rgb24;
if (depth == 16) {
rgb24 = (uint8_t *)malloc(w * h * 3);
int i = 0;
for ( ; i < w*h; i++) {
uint16_t pixel16 = ((uint16_t *)img_buf)[i];
// RRRRRGGGGGGBBBBBB -> RRRRRRRRGGGGGGGGBBBBBBBB
// in rgb24 color max is 2^8 per channel (*255/32 *255/64 *255/32)
rgb24[3*i+0] = (255*(pixel16 & 0x001F))/ 32; //Blue
rgb24[3*i+1] = (255*((pixel16 & 0x07E0) >> 5))/64; //Green
rgb24[3*i+2] = (255*((pixel16 & 0xF800) >> 11))/32; //Red
}
} else if (depth == 24) {
rgb24 = (uint8_t *)img_buf;
} else if (depth == 32) {
//skip transparency channel
rgb24 = (uint8_t *) malloc(w * h * 3);
int i=0;
for ( ; i <w*h; i++) {
uint32_t pixel32 = ((uint32_t *)img_buf)[i];
// in rgb24 color max is 2^8 per channel
rgb24[3*i+2] = pixel32 & 0x000000FF; //Blue
rgb24[3*i+1] = (pixel32 & 0x0000FF00) >> 8; //Green
rgb24[3*i+0] = (pixel32 & 0x00FF0000) >> 16; //Red
}
} else {
};
write(img_fd, rgb24, w*h*3);
close(fb_fd);
close(img_fd);
return 0;
}
Sometime the framebuffer's row size will be larger than the resolution. So you shouldn't use the xres to determine where the next line begins. There is a total memory size attribute saved in the fixed info, so you could divide it with the yres. There is also a row-stride attribute but I'm not sure whether it works. Maybe you could try it.

Why doesn't the demokit program for the ADK compile in Arduino?

I have a pretty good understanding of Arduino and Java, and I decided to take a stab at trying to control my Arduino ATMega with my Samsung Galaxy 10.1 tab. I have installed API 12 with SDK manager, the ADT plugin for Eclipse, and now I am following the instructions from Installing the Arduino software and necessary libraries (at Android Open Accessory Development Kit) to install the firmware for the ADK board. When I hit compile it gives me two errors:
demokit:146: error: 'acc' was not declared in this scope
demokit:249: error: 'touch_robot' was not declared in this scope
and says
'AndroidAccessory' does not name a type.
The code looks like this:
#include <Wire.h>
#include <Servo.h>
#include <Max3421e.h>
#include <Usb.h>
#include <AndroidAccessory.h>
#include <CapSense.h>
#define LED3_RED 2
#define LED3_GREEN 4
#define LED3_BLUE 3
#define LED2_RED 5
#define LED2_GREEN 7
#define LED2_BLUE 6
#define LED1_RED 8
#define LED1_GREEN 10
#define LED1_BLUE 9
#define SERVO1 11
#define SERVO2 12
#define SERVO3 13
#define TOUCH_RECV 14
#define TOUCH_SEND 15
#define RELAY1 A0
#define RELAY2 A1
#define LIGHT_SENSOR A2
#define TEMP_SENSOR A3
#define BUTTON1 A6
#define BUTTON2 A7
#define BUTTON3 A8
#define JOY_SWITCH A9 // pulls line down when pressed
#define JOY_nINT A10 // active low interrupt input
#define JOY_nRESET A11 // active low reset output
AndroidAccessory acc("Google, Inc.",
"DemoKit",
"DemoKit Arduino Board",
"1.0",
"http://www.android.com",
"0000000012345678");
Servo servos[3];
// 10 Mohm resistor on demo shield
CapSense touch_robot = CapSense(TOUCH_SEND, TOUCH_RECV);
void setup();
void loop();
void init_buttons()
{
pinMode(BUTTON1, INPUT);
pinMode(BUTTON2, INPUT);
pinMode(BUTTON3, INPUT);
pinMode(JOY_SWITCH, INPUT);
// enable the internal pullups
digitalWrite(BUTTON1, HIGH);
digitalWrite(BUTTON2, HIGH);
digitalWrite(BUTTON3, HIGH);
digitalWrite(JOY_SWITCH, HIGH);
}
void init_relays()
{
pinMode(RELAY1, OUTPUT);
pinMode(RELAY2, OUTPUT);
}
void init_LEDs()
{
digitalWrite(LED1_RED, 1);
digitalWrite(LED1_GREEN, 1);
digitalWrite(LED1_BLUE, 1);
pinMode(LED1_RED, OUTPUT);
pinMode(LED1_GREEN, OUTPUT);
pinMode(LED1_BLUE, OUTPUT);
digitalWrite(LED2_RED, 1);
digitalWrite(LED2_GREEN, 1);
digitalWrite(LED2_BLUE, 1);
pinMode(LED2_RED, OUTPUT);
pinMode(LED2_GREEN, OUTPUT);
pinMode(LED2_BLUE, OUTPUT);
digitalWrite(LED3_RED, 1);
digitalWrite(LED3_GREEN, 1);
digitalWrite(LED3_BLUE, 1);
pinMode(LED3_RED, OUTPUT);
pinMode(LED3_GREEN, OUTPUT);
pinMode(LED3_BLUE, OUTPUT);
}
void init_joystick(int threshold);
byte b1, b2, b3, b4, c;
void setup()
{
Serial.begin(115200);
Serial.print("\r\nStart");
init_LEDs();
init_relays();
init_buttons();
init_joystick( 5 );
// autocalibrate OFF
touch_robot.set_CS_AutocaL_Millis(0xFFFFFFFF);
servos[0].attach(SERVO1);
servos[0].write(90);
servos[1].attach(SERVO2);
servos[1].write(90);
servos[2].attach(SERVO3);
servos[2].write(90);
b1 = digitalRead(BUTTON1);
b2 = digitalRead(BUTTON2);
b3 = digitalRead(BUTTON3);
b4 = digitalRead(JOY_SWITCH);
c = 0;
acc.powerOn();
}
void loop()
{
byte err;
byte idle;
static byte count = 0;
byte msg[3];
long touchcount;
if (acc.isConnected()) {
int len = acc.read(msg, sizeof(msg), 1);
int i;
byte b;
uint16_t val;
int x, y;
char c0;
if (len > 0) {
// assumes only one command per packet
if (msg[0] == 0x2) {
if (msg[1] == 0x0)
analogWrite(LED1_RED, 255 - msg[2]);
else if (msg[1] == 0x1)
analogWrite(LED1_GREEN, 255 - msg[2]);
else if (msg[1] == 0x2)
analogWrite(LED1_BLUE, 255 - msg[2]);
else if (msg[1] == 0x3)
analogWrite(LED2_RED, 255 - msg[2]);
else if (msg[1] == 0x4)
analogWrite(LED2_GREEN, 255 - msg[2]);
else if (msg[1] == 0x5)
analogWrite(LED2_BLUE, 255 - msg[2]);
else if (msg[1] == 0x6)
analogWrite(LED3_RED, 255 - msg[2]);
else if (msg[1] == 0x7)
analogWrite(LED3_GREEN, 255 - msg[2]);
else if (msg[1] == 0x8)
analogWrite(LED3_BLUE, 255 - msg[2]);
else if (msg[1] == 0x10)
servos[0].write(map(msg[2], 0, 255, 0, 180));
else if (msg[1] == 0x11)
servos[1].write(map(msg[2], 0, 255, 0, 180));
else if (msg[1] == 0x12)
servos[2].write(map(msg[2], 0, 255, 0, 180));
} else if (msg[0] == 0x3) {
if (msg[1] == 0x0)
digitalWrite(RELAY1, msg[2] ? HIGH : LOW);
else if (msg[1] == 0x1)
digitalWrite(RELAY2, msg[2] ? HIGH : LOW);
}
}
msg[0] = 0x1;
b = digitalRead(BUTTON1);
if (b != b1) {
msg[1] = 0;
msg[2] = b ? 0 : 1;
acc.write(msg, 3);
b1 = b;
}
b = digitalRead(BUTTON2);
if (b != b2) {
msg[1] = 1;
msg[2] = b ? 0 : 1;
acc.write(msg, 3);
b2 = b;
}
b = digitalRead(BUTTON3);
if (b != b3) {
msg[1] = 2;
msg[2] = b ? 0 : 1;
acc.write(msg, 3);
b3 = b;
}
b = digitalRead(JOY_SWITCH);
if (b != b4) {
msg[1] = 4;
msg[2] = b ? 0 : 1;
acc.write(msg, 3);
b4 = b;
}
switch (count++ % 0x10) {
case 0:
val = analogRead(TEMP_SENSOR);
msg[0] = 0x4;
msg[1] = val >> 8;
msg[2] = val & 0xff;
acc.write(msg, 3);
break;
case 0x4:
val = analogRead(LIGHT_SENSOR);
msg[0] = 0x5;
msg[1] = val >> 8;
msg[2] = val & 0xff;
acc.write(msg, 3);
break;
case 0x8:
read_joystick(&x, &y);
msg[0] = 0x6;
msg[1] = constrain(x, -128, 127);
msg[2] = constrain(y, -128, 127);
acc.write(msg, 3);
break;
case 0xc:
touchcount = touch_robot.capSense(5);
c0 = touchcount > 750;
if (c0 != c) {
msg[0] = 0x1;
msg[1] = 3;
msg[2] = c0;
acc.write(msg, 3);
c = c0;
}
break;
}
}
else {
// reset outputs to default values on disconnect
analogWrite(LED1_RED, 255);
analogWrite(LED1_GREEN, 255);
analogWrite(LED1_BLUE, 255);
analogWrite(LED2_RED, 255);
analogWrite(LED2_GREEN, 255);
analogWrite(LED2_BLUE, 255);
analogWrite(LED3_RED, 255);
analogWrite(LED3_GREEN, 255);
analogWrite(LED3_BLUE, 255);
servos[0].write(90);
servos[0].write(90);
servos[0].write(90);
digitalWrite(RELAY1, LOW);
digitalWrite(RELAY2, LOW);
}
delay(10);
}
// ==============================================================================
// Austria Microsystems i2c Joystick
void init_joystick(int threshold)
{
byte status = 0;
pinMode(JOY_SWITCH, INPUT);
digitalWrite(JOY_SWITCH, HIGH);
pinMode(JOY_nINT, INPUT);
digitalWrite(JOY_nINT, HIGH);
pinMode(JOY_nRESET, OUTPUT);
digitalWrite(JOY_nRESET, 1);
delay(1);
digitalWrite(JOY_nRESET, 0);
delay(1);
digitalWrite(JOY_nRESET, 1);
Wire.begin();
do {
status = read_joy_reg(0x0f);
} while ((status & 0xf0) != 0xf0);
// invert magnet polarity setting, per datasheet
write_joy_reg(0x2e, 0x86);
calibrate_joystick(threshold);
}
int offset_X, offset_Y;
void calibrate_joystick(int dz)
{
char iii;
int x_cal = 0;
int y_cal = 0;
// Low Power Mode, 20ms auto wakeup
// INTn output enabled
// INTn active after each measurement
// Normal (non-Reset) mode
write_joy_reg(0x0f, 0x00);
delay(1);
// dummy read of Y_reg to reset interrupt
read_joy_reg(0x11);
for(iii = 0; iii != 16; iii++) {
while(!joystick_interrupt()) {}
x_cal += read_joy_reg(0x10);
y_cal += read_joy_reg(0x11);
}
// Divide by 16 to get average
offset_X = -(x_cal>>4);
offset_Y = -(y_cal>>4);
write_joy_reg(0x12, dz - offset_X); // Xp, LEFT threshold for INTn
write_joy_reg(0x13, -dz - offset_X); // Xn, RIGHT threshold for INTn
write_joy_reg(0x14, dz - offset_Y); // Yp, UP threshold for INTn
write_joy_reg(0x15, -dz - offset_Y); // Yn, DOWN threshold for INTn
// Dead zone threshold detect requested?
if (dz)
write_joy_reg(0x0f, 0x04);
}
void read_joystick(int *x, int *y)
{
*x = read_joy_reg(0x10) + offset_X;
*y = read_joy_reg(0x11) + offset_Y; // reading Y clears the interrupt
}
char joystick_interrupt()
{
return digitalRead(JOY_nINT) == 0;
}
#define JOY_I2C_ADDR 0x40
char read_joy_reg(char reg_addr)
{
char c;
Wire.beginTransmission(JOY_I2C_ADDR);
Wire.send(reg_addr);
Wire.endTransmission();
Wire.requestFrom(JOY_I2C_ADDR, 1);
while(Wire.available())
c = Wire.receive();
return c;
}
void write_joy_reg(char reg_addr, char val)
{
Wire.beginTransmission(JOY_I2C_ADDR);
Wire.send(reg_addr);
Wire.send(val);
Wire.endTransmission();
}
By the way, I even tried to copy the ADK_relsease_0512 folder in my arduino directory at that still didn't work. Thanks in advance!
Now I reached sucess with Arduino 1.0 , and I want to share the solution:
I used the CapSense04.zip library:
I changed the type from void to size_t in following files from arduino_bundle_ADK.zip:
AndroidAccessory.cpp line 280: size_t AndroidAccessory::write(uint8_t b)
AndroidAccessory.h line 71: size_t write(uint8_t b);
Max_LCD.cpp line 257: inline size_t Max_LCD::write(uint8_t value)
Max_LCD.h line 101: virtual size_t write(uint8_t);
I also changed send to write and receive to read, in the demokit.pde (you will find it in adk_release_0512.zip)
Demokit.pde line 377: Wire.write(reg_addr);
line 383: c = Wire.read();
line 391: Wire.write(reg_addr);
line 392: Wire.write(val);
Perhaps try using an earlier version of Arduino (i.e. not arduino 1.0) - a recent update has changed some class names as far as I can see.
I was experiencing the errors detailed here and so this fixed it for me: http://www.jjoe64.com/2011/12/adk-arduino-wprogramh-not-found.html
There is no WProgram.h in Arduino 1.0 IDE. The include statement should be:
#if ARDUINO >= 100
#include "Arduino.h"
#else
#include "WProgram.h"
#endif
This will fix the header not found problem under Arduino 1.0.
Later version of the code (arduino_bundle_ADK_02) doesn't need to be patched.
Disclaimer: I still can't make this zoo work with Nexus S beyond ADK app popping up (dreaded "Setup packet error: D" after a few seconds after initial connection), but I think the reason for that is elsewhere.
I've changed in the lines with errors "CapSense" to "CapacitiveSensor"
considering that the class is now named (CapacitiveSensor) at CapSense library v.04
and the library is now called CapacitiveSensor as well
then after pressing verify I had to change a property "touch_robot.capSense" to "touch_robot.capacitiveSensor"
Just to share info, if you use arduino uno (Mega328), check this site. The firmware for the uno is here. Note it uses arduino IDE v0.22 and need to add libraries.
Happy microcontroller programming...
Best regards,
pak
The ADK software was just recently updated to be compatible with Arduino 1.0.
Check the ADK page on developer.android.com:
http://developer.android.com/guide/topics/usb/adk.html
New download link is:
https://dl-ssl.google.com/android/adk/adk_release_20120606.zip

How can I get rendered frames statistics (drawn/dropped) from StageFright Media Framework?

I'm very newbie in Android world and I have to write an streaming video quality checker application on Android. I have to use the native StageFright media framework to play videos. As far as I understand there is an native API of render statistics, but I need advice how I can get it. Thank you.
There is an ADB command to print playback framerate.
Procedure
Open console on windows (or linux) on the host. Make sure that required drivers have been installed for USB connectivity with the device (android phone or board)
Run the following commands
$> adb kill-server
$> adb shell setprop debug.video.showfps 1
Run the video playback. If the video is being run using Android Media player stack, then you will see prints reporting frame rate achieved.
You're welcome to use this as well, call it at the beginning and end of each frame rendered. It's a slightly altered version of some sample code from the NDK:
stats.c:
#include <sys/time.h>
#include <string.h>
#include <android/log.h>
#include <stdio.h>
#include "stats.h"
#define LOG_TAG "[STATS]"
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__)
#define LOGW(...) __android_log_print(ANDROID_LOG_WARN,LOG_TAG,__VA_ARGS__)
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)
#define STATS_DUMP(...) __android_
double now_ms()
{
struct timeval tv;
gettimeofday(&tv, NULL);
return tv.tv_sec*1000. + tv.tv_usec/1000.;
}
void stats_init(Stats* s)
{
s->lastTime = now_ms();
s->firstTime = 0.;
s->firstFrame = 0;
s->numFrames = 0;
s->dump = malloc(128);
memset(s->dump,0,128);
}
void stats_startFrame(Stats* s)
{
s->frameTime = now_ms();
}
void stats_endFrame(Stats* s)
{
double now = now_ms();
double renderTime = now - s->frameTime;
double frameTime = now - s->lastTime;
int nn;
if (now - s->firstTime >= MAX_PERIOD_MS) {
if (s->numFrames > 0) {
double renderTime = now - s->frameTime;
double frameTime = now - s->lastTime;
int nn;
double minRender, maxRender, avgRender;
double minFrame, maxFrame, avgFrame;
int count;
nn = s->firstFrame;
minRender = maxRender = avgRender = s->frames[nn].renderTime;
minFrame = maxFrame = avgFrame = s->frames[nn].frameTime;
for (count = s->numFrames; count > 0; count-- ) {
nn += 1;
if (nn >= MAX_FRAME_STATS)
nn -= MAX_FRAME_STATS;
double render = s->frames[nn].renderTime;
if (render < minRender) minRender = render;
if (render > maxRender) maxRender = render;
double frame = s->frames[nn].frameTime;
if (frame < minFrame) minFrame = frame;
if (frame > maxFrame) maxFrame = frame;
avgRender += render;
avgFrame += frame;
}
avgRender /= s->numFrames;
avgFrame /= s->numFrames;
sprintf(s->dump,"Frames per second - [AVG:%.1f] [MIN:%.1f] [MAX:%.1f]Rendering time ms - [AVG:%.1f] [MIN:%.1f] [MAX:%.1f]", 1000./avgFrame, 1000./maxFrame, 1000./minFrame, avgRender, minRender, maxRender);
//LOGI("Frames per second - [AVG:%.1f] [MIN:%.1f] [MAX:%.1f]Rendering time ms - [AVG:%.1f] [MIN:%.1f] [MAX:%.1f]", 1000./avgFrame, 1000./maxFrame, 1000./minFrame, avgRender, minRender, maxRender);
}
s->numFrames = 0;
s->firstFrame = 0;
s->firstTime = now;
}
nn = s->firstFrame + s->numFrames;
if (nn >= MAX_FRAME_STATS)
nn -= MAX_FRAME_STATS;
s->frames[nn].renderTime = renderTime;
s->frames[nn].frameTime = frameTime;
if (s->numFrames < MAX_FRAME_STATS) {
s->numFrames += 1;
} else {
s->firstFrame += 1;
if (s->firstFrame >= MAX_FRAME_STATS)
s->firstFrame -= MAX_FRAME_STATS;
}
s->lastTime = now;
}
stats.h:
#include <jni.h>
#define MAX_FRAME_STATS 120
#define MAX_PERIOD_MS 5000
typedef struct{
double renderTime;
double frameTime;
} FrameStats;
typedef struct{
double firstTime;
double lastTime;
double frameTime;
int firstFrame;
int numFrames;
FrameStats frames[ MAX_FRAME_STATS ];
char* dump;
} Stats;
extern double now_ms();
extern void stats_init(Stats *);
extern int stats_dump(Stats *);
extern void stats_startFrame(Stats *);
extern void stats_endFrame(Stats *);

Categories

Resources