shithub: drawterm

ref: 8d1d00cf25eb46f29948bc021f153e4cc4c5c598
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();

int Ncameras = 0;

uchar *cambuf = nil;
int camlen;

ASensorManager *sensorManager = NULL;

enum
{
	Qdir		= 0,
	Qcam		= 1,
	Qaccel		= 2,
	Qcompass	= 4,
	Qnotify		= 6,
};

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

static void androidinit(void);

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

	Ncameras = num_cameras();
}

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

static int
androidgen(Chan *c, char *n, Dirtab *d, int nd, int s, Dir *dp)
{
	Qid q;

	if (s == DEVDOTDOT) {
		devdir(c, d->qid, "#N", 0, eve, 0555, dp);
		return 1;
	}
	if (s < Ncameras) {
		d += 1;
		q = d->qid;
		q.path |= (s << 16);
		sprintf(up->genbuf, "cam%d.jpg", s);
		devdir(c, q, up->genbuf, 0, eve, 0444, dp);
		return 1;
	}
	if (s == Ncameras) {
		d += 2;
		sprintf(up->genbuf, "accel");
		devdir(c, d->qid, up->genbuf, 0, eve, 0444, dp);
		return 1;
	}
	if (s == (Ncameras+1)) {
		d += 3;
		sprintf(up->genbuf, "compass");
		devdir(c, d->qid, up->genbuf, 0, eve, 0444, dp);
		return 1;
	}
	if (s == (Ncameras+2)) {
		d += 4;
		sprintf(up->genbuf, "notify");
		devdir(c, d->qid, up->genbuf, 0, eve, 0222, dp);
		return 1;
	}
	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)
{
	p9_uvlong s;

	c = devopen(c, omode, androiddir, nelem(androiddir) + Ncameras - 1, androidgen);

	if (c->qid.path & Qcam) {
		s = c->qid.path >> 16;
		take_picture(s);
	}
	c->mode = openmode(omode);
	c->flag |= COPEN;
	c->offset = 0;

	return c;
}

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

static long
androidread(Chan *c, void *v, long n, vlong off)
{
	char *a = v;
	long l;
	const ASensor *sensor;
	ASensorEventQueue *queue = NULL;
	ASensorEvent data;

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

		case Qcam:
			while(cambuf == nil)
				usleep(10 * 1000);

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

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

			return l;
		case Qaccel:
			queue = ASensorManager_createEventQueue(sensorManager, ALooper_prepare(ALOOPER_PREPARE_ALLOW_NON_CALLBACKS), 1, NULL, NULL);
			if (queue == NULL)
				return 0;
			sensor = ASensorManager_getDefaultSensor(sensorManager, ASENSOR_TYPE_ACCELEROMETER);
			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;
		case Qcompass:
			queue = ASensorManager_createEventQueue(sensorManager, ALooper_prepare(ALOOPER_PREPARE_ALLOW_NON_CALLBACKS), 1, NULL, NULL);
			if (queue == NULL)
				return 0;
			sensor = ASensorManager_getDefaultSensor(sensorManager, ASENSOR_TYPE_MAGNETIC_FIELD);
			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;
		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,
};