Skip to content
Snippets Groups Projects
mensactrl.c 5.6 KiB
Newer Older
daniel's avatar
daniel committed
/*
daniel's avatar
daniel committed
 * Control Mensadisplay connected to the LCDIF
daniel's avatar
daniel committed
 *
daniel's avatar
daniel committed
 * (C) 2014 Daniel Willmann <daniel@totalueberwachung.de>
daniel's avatar
daniel committed

 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.

 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.

 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <linux/fb.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <math.h>

#include <zmq.h>

daniel's avatar
daniel committed
#include "common.h"
daniel's avatar
daniel committed
#define ROWS_PER_LINE 7
#define LINES_PER_MODULE 2
#define COLS_PER_MODULE 40

daniel's avatar
daniel committed
struct mensa_fb {
daniel's avatar
daniel committed
	int x_res, y_res;
daniel's avatar
daniel committed
	int hmodules, vmodules;
daniel's avatar
daniel committed
	int fd;
	uint8_t *inputfb;
	uint16_t *fbmem;
daniel's avatar
daniel committed
	ssize_t size;
daniel's avatar
daniel committed
static void blit_area(struct mensa_fb *mensafb, const int col, const int row,
		const int width, const int height)
{
    int r, c;
    int vmpos, vpos, hmpos, hpos, pos;

    if (row < 0 || height < 0 || row + height > mensafb->y_res ||
		    col < 0 || width < 0 || col + width > mensafb->x_res)
	    return;

    for (r = row; r < row + height; r++) {
Drahflow's avatar
Drahflow committed
	for (c = col; c < col + width; c++) {
	    /* Calculate module and position inside the module */
	    vmpos = r/(LINES_PER_MODULE*ROWS_PER_LINE);
	    vpos = r%(LINES_PER_MODULE*ROWS_PER_LINE);
	    hmpos = c/(COLS_PER_MODULE);
	    hpos = c%(COLS_PER_MODULE);
daniel's avatar
daniel committed

Drahflow's avatar
Drahflow committed
	    pos = hpos + hmpos*COLS_PER_MODULE*LINES_PER_MODULE;
daniel's avatar
daniel committed

Drahflow's avatar
Drahflow committed
	    if (vpos >= ROWS_PER_LINE) {
		vpos -= ROWS_PER_LINE;
		pos += COLS_PER_MODULE;
	    }
daniel's avatar
daniel committed

daniel's avatar
daniel committed
	    /* Invert order */
Drahflow's avatar
Drahflow committed
	    pos = (LINES_PER_MODULE * COLS_PER_MODULE * mensafb->hmodules - 1) - pos;
daniel's avatar
daniel committed

	    /* Add in row offset */
Drahflow's avatar
Drahflow committed
	    pos = pos + vpos*(mensafb->hmodules*COLS_PER_MODULE*LINES_PER_MODULE);
daniel's avatar
daniel committed

daniel's avatar
daniel committed

	    if (mensafb->inputfb[c + r * mensafb->x_res] == 0) {
Drahflow's avatar
Drahflow committed
		/* clear bit */
		mensafb->fbmem[pos] &= ~(1<<(mensafb->vmodules - 1 - vmpos));
	    } else {
		/* set bit */
		mensafb->fbmem[pos] |= (1<<(mensafb->vmodules - 1 - vmpos));
	    }
	}
daniel's avatar
daniel committed
    }
}


void encodeToFb(struct mensa_fb *mensafb)
{
	blit_area(mensafb, 0, 0, mensafb->x_res, mensafb->y_res);
daniel's avatar
daniel committed
}
Drahflow's avatar
Drahflow committed

daniel's avatar
daniel committed
//	int pix, row, cols, idx, fbidx, i, ledrow;
//	uint16_t pattern;
//
//	for (fbidx = 0; fbidx < mensafb->x_res * mensafb->y_res / mensafb->modules; fbidx++) {
//		cols = mensafb->x_res * 2;
//
//		row = fbidx / cols;
//		ledrow = row;
//		pix = fbidx % cols;
//
//		if (pix / 40 % 2 == 0) {
//			pix = pix + (pix / 40 * 40);
//		} else {
//			pix = pix + (pix / 40 * 40) + 40;
//			row = row + 7;
//		}
//
//
//		pattern = 0;
//		for (i = 0; i < mensafb->modules; i++) {
//			idx = row * mensafb->x_res + pix + i * mensafb->x_res * 14;
//			if (mensafb->inputfb[idx] > 0)
//				pattern |= 1 << i;
//		}
//			/* During update of the next line we want to display the
//			 * content of the last one */
//			pattern |= (ledrow-1 % 7) << 5;
//
//			mensafb->fbmem[fbidx] = pattern;
//	}
//}
daniel's avatar
daniel committed
void setPixel(struct mensa_fb *mensafb, int col, int row, uint8_t bright)
{
	int idx = row * mensafb->x_res + col;

	if (col < 0 || col >= mensafb->x_res)
		return;
	if (row < 0 || row >= mensafb->y_res)
		return;

	mensafb->inputfb[idx] = bright;
daniel's avatar
daniel committed
static struct mensa_fb *setup_fb(const char *devname, int hmodules, int vmodules)
daniel's avatar
daniel committed
{
daniel's avatar
daniel committed
	struct mensa_fb *mensafb = malloc(sizeof(struct mensa_fb));
daniel's avatar
daniel committed
	int i;

daniel's avatar
daniel committed
	mensafb->x_res = COLS_PER_MODULE * hmodules;
	mensafb->y_res = ROWS_PER_LINE * LINES_PER_MODULE * vmodules;
	mensafb->size = mensafb->x_res * ROWS_PER_LINE * LINES_PER_MODULE;
daniel's avatar
daniel committed
	mensafb->fd = open(devname, O_RDWR);
	if (mensafb->fd < 0) {
daniel's avatar
daniel committed
		perror("opening fb");
daniel's avatar
daniel committed
		free(mensafb);
daniel's avatar
daniel committed
		exit(1);
	}
daniel's avatar
daniel committed
	mensafb->inputfb = malloc(mensafb->x_res * mensafb->y_res);
daniel's avatar
daniel committed
	if (!mensafb->inputfb) {
		free(mensafb);
daniel's avatar
daniel committed
		exit(1);
	}
daniel's avatar
daniel committed
	memset(mensafb->inputfb, 0, mensafb->x_res * mensafb->y_res);
daniel's avatar
daniel committed
	mensafb->fbmem=mmap(NULL, mensafb->size * 2,
			PROT_READ|PROT_WRITE, MAP_SHARED, mensafb->fd, 0);
daniel's avatar
daniel committed
	if (mensafb->fbmem==NULL) {
daniel's avatar
daniel committed
		perror("mmap'ing fb");
daniel's avatar
daniel committed
		free(mensafb->inputfb);
		free(mensafb);
daniel's avatar
daniel committed
		exit(1);
	}
daniel's avatar
daniel committed
	for (i = 0; i < mensafb->size ; i++)
daniel's avatar
daniel committed
		mensafb->fbmem[i] = ((6 + i / (mensafb->x_res * LINES_PER_MODULE)) % 7)<<5;
daniel's avatar
daniel committed
	mensafb->hmodules = hmodules;
	mensafb->vmodules = vmodules;
daniel's avatar
daniel committed
	return mensafb;
Drahflow's avatar
Drahflow committed
void handlePixel(struct mensa_fb *mensafb, struct pixel *pix) {
	setPixel(mensafb, pix->x, pix->y, pix->bright);
	blit_area(mensafb, pix->x, pix->y, 1, 1);
}

void handleCommand(struct mensa_fb *mensafb, struct packet *p) {
	switch(p->cmd) {
		case CMD_PIXEL: handlePixel(mensafb, &p->pixel); break;
	}
}

daniel's avatar
daniel committed
int main(int argc, char *argv[]) {
daniel's avatar
daniel committed
	struct mensa_fb *mensafb;
daniel's avatar
daniel committed
	void *context = zmq_ctx_new ();
daniel's avatar
daniel committed
	void *responder = zmq_socket (context, ZMQ_REP);
daniel's avatar
daniel committed
	int rc;

	if (argc != 2)
		exit(1);

daniel's avatar
daniel committed
	rc = zmq_bind (responder, "tcp://*:5556");
daniel's avatar
daniel committed
	if (rc < 0)
daniel's avatar
daniel committed
		perror("zmq_bind");
daniel's avatar
daniel committed
	mensafb = setup_fb(argv[1], 12, 5);
daniel's avatar
daniel committed

	while (1) {
Drahflow's avatar
Drahflow committed
		int64_t more;
		size_t more_size = sizeof(more);

                do {
			zmq_msg_t message;
			zmq_msg_init (&message);
			zmq_msg_recv (&message, responder, 0);

			if(zmq_msg_size(&message)) {
				handleCommand(mensafb, (struct packet *)zmq_msg_data(&message));
			}

			zmq_getsockopt (responder, ZMQ_RCVMORE, &more, &more_size);

			zmq_msg_close (&message);
		} while(more);

		zmq_send(responder, NULL, 0, 0);
daniel's avatar
daniel committed
	}

	return 0;
}