shithub: drawterm-fdroid

ref: 0818148b0432a1b11d2feb72cca47156a603e884
dir: /gui-android/cpp/devandroid.c/

View raw version
#include	"u.h"
#include	"lib.h"
#include	"dat.h"
#include	"fns.h"
#include	"error.h"

//#include <android/log.h>
#include <android/sensor.h>

void show_notification(char *buf);
void take_picture(int id);
int num_cameras();
long getlocation(char *a, long n);

int Ncameras = 0;

uchar *cambuf = nil;
int camlen = 0;
static char camopen = 0;

ASensorManager *sensorManager = NULL;

enum
{
	Qdir		= 0,
	Qaccel,
	Qcompass,
	Qnotify,
	Qlocation,
	Ntab,
	Qcam		= 8,
};

Dirtab
androiddir[] =
{
	".",		{Qdir, 0, QTDIR},	0,	DMDIR|0555,
	"accel",	{Qaccel},		0,	0444,
	"compass",	{Qcompass},		0,	0444,
	"notify",	{Qnotify},		0,	0222,
	"location",	{Qlocation},		0,	0444,
	"camNNNN",	{Qcam},			0,	0444,
};

static void androidinit(void);

static void
androidinit(void)
{
	sensorManager = ASensorManager_getInstance();

	Ncameras = num_cameras();
}

static Chan*
androidattach(char *param)
{
	return devattach('N', param);
}

int
androidgen(Chan *c, char *name, Dirtab *tab, int ntab, int i, Dir *dp)
{
	Qid q;

	if(tab == 0)
		return -1;
	if(i == DEVDOTDOT){
		/* nothing */
	}else if(name){
//		__android_log_print(ANDROID_LOG_WARN, "drawterm", "androidgen name %s", name);
		for(i=1; i<Ntab; i++)
			if(strcmp(tab[i].name, name) == 0)
				break;
		if (i == Ntab) {
			if (strncmp("cam", name, 3) == 0 &&
			    name[3] >= '0' && name[3] <= '9' &&
			    strspn(&name[3], "0123456789") == (strlen(name) - 3) &&
			    (i = atoi(&name[3])) < Ncameras)
				i += Ntab;
			else
				return -1;
		}
		if(i > Ntab)
			tab += Ntab;
		else
			tab += i;
	}else{
//		__android_log_print(ANDROID_LOG_WARN, "drawterm", "androidgen i %d", i);
		/* skip over the first element, that for . itself */
		i++;
		if(i >= ntab)
			return -1;
		if(i >= Ntab)
			tab += Ntab;
		else
			tab += i;
	}
	if (i >= Ntab) {
		q = tab->qid;
		q.path |= ((i - Ntab) << 16);
		sprintf(up->genbuf, "cam%d", i - Ntab);
		devdir(c, q, up->genbuf, tab->length, eve, tab->perm, dp);
		return 1;
	}
	devdir(c, tab->qid, tab->name, tab->length, eve, tab->perm, dp);
	return 1;
}

static Walkqid*
androidwalk(Chan *c, Chan *nc, char **name, int nname)
{
	return devwalk(c, nc, name, nname, androiddir, nelem(androiddir) + Ncameras - 1, androidgen);
}

static int
androidstat(Chan *c, uchar *db, int n)
{
	return devstat(c, db, n, androiddir, nelem(androiddir) + Ncameras - 1, androidgen);
}

static Chan*
androidopen(Chan *c, int omode)
{
	int i;

	if (c->qid.path & Qcam) {
		if (camopen != 0) {
			error(Einuse);
		} else {
			camopen = 1;
			i = c->qid.path >> 16;
			take_picture(i);
		}
	}
	c = devopen(c, omode, androiddir, nelem(androiddir) + Ncameras - 1, androidgen);

	return c;
}

static void
androidclose(Chan *c)
{
	if (c->qid.path & Qcam && camopen != 0) {
		free(cambuf);
		cambuf = nil;
		camlen = 0;
		camopen = 0;
	}
}

long
readsensor(char *a, long n, int type) {
	long l;
	const ASensor *sensor;
	ASensorEventQueue *queue = NULL;
	ASensorEvent data;

	queue = ASensorManager_createEventQueue(sensorManager, ALooper_prepare(ALOOPER_PREPARE_ALLOW_NON_CALLBACKS), 1, NULL, NULL);
	if (queue == NULL)
		return 0;
	sensor = ASensorManager_getDefaultSensor(sensorManager, type);
	if (sensor == NULL) {
		ASensorManager_destroyEventQueue(sensorManager, queue);
		return 0;
	}
	if (ASensorEventQueue_enableSensor(queue, sensor)) {
		ASensorEventQueue_disableSensor(queue, sensor);
		ASensorManager_destroyEventQueue(sensorManager, queue);
		return 0;
	}
	l = 0;
	if (ALooper_pollAll(1000, NULL, NULL, NULL) == 1) {
		if (ASensorEventQueue_getEvents(queue, &data, 1)) {
			l = snprint(a, n, "%11f %11f %11f\n", data.vector.x, data.vector.y, data.vector.z);
		}
	}
	ASensorEventQueue_disableSensor(queue, sensor);
	ASensorManager_destroyEventQueue(sensorManager, queue);

	return l;
}

static long
androidread(Chan *c, void *v, long n, vlong off)
{
	char *a = v;
	long l;

	switch((ulong)c->qid.path & 0xF) {
		default:
			error(Eperm);
			return -1;

		case Qcam:
			while(camlen == 0)
				usleep(10 * 1000);

			if(camlen < 0) {
				error(Eio);
				return -1;
			}

			l = camlen - off;
			if (l > n)
				l = n;

			if (l > 0)
				memcpy(a, cambuf + off, l);

			return l;
		case Qaccel:
			return readsensor(a, n, ASENSOR_TYPE_ACCELEROMETER);
		case Qcompass:
			return readsensor(a, n, ASENSOR_TYPE_MAGNETIC_FIELD);
		case Qlocation:
			return getlocation(a, n);
		case Qdir:
			return devdirread(c, a, n, androiddir, nelem(androiddir) + Ncameras - 1, androidgen);
	}
}

static long
androidwrite(Chan *c, void *vp, long n, vlong off)
{
	char *a = vp;
	char *str;

	switch((ulong)c->qid.path) {
		case Qnotify:
			str = malloc(n+1);
			memcpy(str, a, n);
			str[n] = '\0';
			show_notification(str);
			free(str);
			return n;
		default:
			error(Eperm);
			break;
	}
	return -1;
}

Dev androiddevtab = {
	'N',
	"android",

	devreset,
	androidinit,
	devshutdown,
	androidattach,
	androidwalk,
	androidstat,
	androidopen,
	devcreate,
	androidclose,
	androidread,
	devbread,
	androidwrite,
	devbwrite,
	devremove,
	devwstat,
};