~foura/uxn900

88b17af754568c3639f641175894501d04fdae74 — james palmer 2 months ago c113ddf
controller: add wip controller device.

only the d-pad works at the moment.
for other things i need to have a keymap.
4 files changed, 229 insertions(+), 3 deletions(-)

M Makefile
A src/dev/controller.c
A src/inc/dev/controller.h
M src/main.c
M Makefile => Makefile +1 -0
@@ 13,6 13,7 @@ OFILES = \
	src/timer.o \
	src/uxn.o \
	src/dev/console.o \
	src/dev/controller.o \
	src/dev/nil.o \
	src/dev/screen.o \
	src/dev/system.o

A src/dev/controller.c => src/dev/controller.c +199 -0
@@ 0,0 1,199 @@
#include "uxn.h"
#include "dat.h"
#include "fns.h"

#include "dev/console.h"
#include "dev/controller.h"

enum {
	Ckp = 0x4a,

	Mshift = (1 << 2),
	Mfn    = (1 << 1),
	Mctrl  = (1 << 0),

	Rctrl = 0xd2,
		Rctrlon       = (1 << 6),
		Rctrlsoftmode = (1 << 1),
		Rctrlsoftnrst = (1 << 0),
	Rcode = 0xdb,
	Risr  = 0xe3,
	Rimr  = 0xe4,
	Redr  = 0xe8,
	Rsih  = 0xe9,
};

void
controller_init(Controller *ctrl)
{
	int i;
	Uint8 buf[2];

	/* read in ctrl register */
	buf[0] = Rctrl;
	buf[1] = 0;
	i2c_read(PHYSI2C1, Ckp, buf, 1, 1);

	/* turn on the keyboard */
	buf[0] = Rctrl;
	buf[1] |= Rctrlon;
	buf[1] |= Rctrlsoftmode;
	buf[1] |= Rctrlsoftnrst;
	i2c_write(PHYSI2C1, Ckp, buf, 1, 1);

	/* enable key event status */
	buf[0] = Rimr;
	buf[1] = 0xfe;
	i2c_write(PHYSI2C1, Ckp, buf, 1, 1);

	/* enable rising and falling interrupts (qemu workaround) */
	buf[0] = Redr;
	buf[1] = 0x57;
	i2c_write(PHYSI2C1, Ckp, buf, 1, 1);

	/* enable isr clear on read */
	buf[0] = Rsih;
	buf[1] = 0x05;
	i2c_write(PHYSI2C1, Ckp, buf, 1, 1);

	/* clear state */
	ctrl->raw.curmods = 0;
	ctrl->raw.prevmods = 0;
	for(i = 0; i < 8; i++) {
		ctrl->raw.cur[i] = 0;
		ctrl->raw.prev[i] = 0;
	}
}

static void
controller_button(Controller *ctrl, Uxn *u, Uint8 code)
{
	if(ctrl->raw.curmods & 2)
		return;

	switch(code) {
	case 0x12: ctrl->buttons |= 0x10; break; /* up */
	case 0x21: ctrl->buttons |= 0x20; break; /* down */
	case 0x1f: ctrl->buttons |= 0x40; break; /* left */
	case 0x22: ctrl->buttons |= 0x80; break; /* right */
	}
}

static void
controller_process_buttons(Controller *ctrl, Uxn *u)
{
	int col, row;
	Uint8 c;

	/* scan the keyboard matrix */
	ctrl->buttons = 0;
	for(col = 0; col < 8; col++) {
		c  = ctrl->raw.cur[col];

		for(row = 0; row < 8; row++) {
			if(c & 1)	
				controller_button(ctrl, u, col * 8 + row);

			c = c >> 1;
		}
	}

	uxn_eval(u, ctrl->vector);
}

static void
controller_key(Controller *ctrl, Uxn *u, Uint8 code)
{
}

static void
controller_process_keys(Controller *ctrl, Uxn *u)
{
	int col, row;
	Uint8 c;

	/* scan the keyboard matrix */
	for(col = 0; col < 8; col++) {
		/* newly pressed keys only */
		c  = ctrl->raw.cur[col];
		c ^= ctrl->raw.prev[col];
		c &= ctrl->raw.cur[col];

		for(row = 0; row < 8; row++) {
			if(c & 1)
				controller_key(ctrl, u, col * 8 + row);

			c = c >> 1;
		}
	}
}

void
controller_poll(Controller *ctrl, Uxn *u)
{
	Uint8 buf[2];
	int i, j;

	/* twl4030 remembers the last 2 events */
	for(i = 0; i < 2; i++) {
		/* check status register */
		buf[0] = Risr + 2*i;
		i2c_read(PHYSI2C1, Ckp, buf, 1, 1);
		if(!(buf[1] & 1))
			continue;

		/* read the key state */
		buf[0] = Rcode;
		for(j = 0; j < 8; j++) {
			i2c_read(PHYSI2C1, Ckp, buf, 1, 1);

			/* extract modifiers */
			if(j == 5) {
				ctrl->raw.prevmods = ctrl->raw.curmods;
				ctrl->raw.curmods  = buf[1] >> 4;
				buf[1] &= 0x0f;
			}

			ctrl->raw.prev[j] = ctrl->raw.cur[j];
			ctrl->raw.cur[j] = buf[1];

			buf[0]++;
		}

		controller_process_buttons(ctrl, u);
		controller_process_keys(ctrl, u);
	}
}

Uint8
controller_dei(Device *d, Uint8 port)
{
	switch(port) {
	case 0x0: return uxn_controller.vector >> 8;
	case 0x1: return uxn_controller.vector;
	case 0x2: return uxn_controller.buttons;
	case 0x3: return uxn_controller.key;
	}

	return 0;
}

void
controller_deo(Device *d, Uint8 port)
{
	Uint16 tmp;

	switch(port) {
	case 0x0:
		tmp = d->dat[port] << 8;
		tmp |= uxn_controller.vector & 0x00ff;

		uxn_controller.vector = tmp;
		break;
	case 0x1:
		tmp = d->dat[port];
		tmp |= uxn_controller.vector & 0xff00;

		uxn_controller.vector = tmp;
	}
}

A src/inc/dev/controller.h => src/inc/dev/controller.h +21 -0
@@ 0,0 1,21 @@
typedef struct Controller Controller;
struct Controller {
	Uint16 vector;
	Uint8 buttons;
	Uint8 key;

	struct {
		Uint8 cur[8];
		Uint8 curmods;

		Uint8 prev[8];
		Uint8 prevmods;
	} raw;
};

extern Controller uxn_controller;

void  controller_init(Controller *ctrl);
void  controller_poll(Controller *ctrl, Uxn *u);
Uint8 controller_dei(Device *d, Uint8 port);
void  controller_deo(Device *d, Uint8 port);

M src/main.c => src/main.c +8 -3
@@ 3,12 3,14 @@
#include "fns.h"

#include "dev/console.h"
#include "dev/controller.h"
#include "dev/nil.h"
#include "dev/screen.h"
#include "dev/system.h"

Uint8  uxn_ram[64*1024];
Screen uxn_screen;
Uint8      uxn_ram[64*1024];
Controller uxn_controller;
Screen     uxn_screen;

void
uxn_init(void)


@@ 66,6 68,7 @@ main(void)

	watchdog_init();
	screen_init(&uxn_screen);
	controller_init(&uxn_controller);

	uxn_init();
	uxn_boot(&u, &uxn_ram[0]);


@@ 73,13 76,13 @@ main(void)
	uxn_port(&u, 0x0, system_dei, system_deo);
	uxn_port(&u, 0x1, nil_dei,    console_deo);
	uxn_port(&u, 0x2, screen_dei, screen_deo);
	uxn_port(&u, 0x8, controller_dei, controller_deo);

	uxn_port(&u, 0x3, nil_dei, nil_deo);
	uxn_port(&u, 0x4, nil_dei, nil_deo);
	uxn_port(&u, 0x5, nil_dei, nil_deo);
	uxn_port(&u, 0x6, nil_dei, nil_deo);
	uxn_port(&u, 0x7, nil_dei, nil_deo);
	uxn_port(&u, 0x8, nil_dei, nil_deo);
	uxn_port(&u, 0x9, nil_dei, nil_deo);
	uxn_port(&u, 0xa, nil_dei, nil_deo);
	uxn_port(&u, 0xb, nil_dei, nil_deo);


@@ 92,6 95,8 @@ main(void)
		return;

	for(;;) {
		controller_poll(&uxn_controller, &u);

		uxn_eval(&u, GETVECTOR(&u.dev[2]));
		if(uxn_screen.fg.changed || uxn_screen.bg.changed)
			screen_redraw(&uxn_screen);