Now faster. And with more Jenny Holzer.

This commit is contained in:
jaseg 2014-03-04 01:07:22 +01:00
parent bd5b1b6267
commit 7878aa1d45
10 changed files with 528 additions and 64 deletions

View file

@ -1,6 +1,12 @@
all: main.c font.c font.h color.c color.h all: libml libbdf
gcc -shared -fPIC -std=gnu11 -Wall -lm -o libbdf.so -g -O0 main.c font.c color.c
libml: usb.c color.c color.h
gcc -shared -fPIC -std=gnu11 -Wall -lm -lusb-1.0 -o libml.so -g usb.c color.c
libbdf: main.c font.c font.h color.c color.h
gcc -shared -fPIC -std=gnu11 -Wall -lm -o libbdf.so -g main.c font.c color.c
clean: clean:
rm libbdf.so rm libbdf.so libml.so

View file

@ -6,12 +6,13 @@
/* For easier memsetting we use an inverted alpha channel, i.e. 0 ≘ fully opaque; 255 ≘ fully transparent */ /* For easier memsetting we use an inverted alpha channel, i.e. 0 ≘ fully opaque; 255 ≘ fully transparent */
typedef struct { typedef struct {
uint8_t r; uint8_t r, g, b, a;
uint8_t g;
uint8_t b;
uint8_t a;
} color_t; } color_t;
typedef struct {
uint8_t r, g, b;
} rgb_t;
typedef struct { typedef struct {
color_t *data; color_t *data;
size_t w; size_t w;

259
host/default.lines Normal file
View file

@ -0,0 +1,259 @@
\x1B[38;5;214mabstraction is a type of decadence
\x1B[38;5;214mit's important to stay clean on all levels
\x1B[38;5;214mexpiring for love is beautiful but stupid
\x1B[38;5;214mlack of charisma can be fatal
\x1B[38;5;214mambition is just as dangerous as complacency
\x1B[38;5;214mslipping into madness is good for the sake of comparison
\x1B[38;5;214mplanning for the future is escapism
\x1B[38;5;214mtrue freedom is frightful
\x1B[92mMate Light\x1B[0m powered by \x1B[95mData Becker™ \x1B[96mLaufschriftstudio 2000® Platinum Edition
\x1B[38;5;214mreligion causes as many problems as it solves
\x1B[38;5;214mdisorganization is a kind of anesthesia
\x1B[38;5;214mpursuing pleasure for the sake of pleasure will ruin you
\x1B[38;5;214manger or hate can be a useful motivating force
\x1B[38;5;214mjust believing something can make it happen
\x1B[38;5;214mtrading a life for a life is fair enough
\x1B[38;5;214mlisten when your body talks
\x1B[38;5;214mfake or real indifference is a powerful personal weapon
\x1B[38;5;214mcalm is more conductive to creativity than is anxiety
\x1B[38;5;214mthere are too few immutable truths today
\x1B[38;5;214mbeing happy is more important than anything else
\x1B[38;5;214mit can be helpful to keep going no matter what
\x1B[38;5;214mbelieving in rebirth is the same as admitting defeat
\x1B[38;5;214mit's vital to live in harmony with nature
\x1B[38;5;214mdisgust is the appropriate response to most situations
\x1B[38;5;214mnothing upsets the balance of good and evil
\x1B[38;5;214mrandom mating is good for debunking sex myths
\x1B[38;5;214manimalism is perfectly healthy
\x1B[92mMate Light\x1B[0m powered by \x1B[95mSiemens™ \x1B[96mLaufschrift® v.0.1.2b fuer Intel™ Pentium®
\x1B[38;5;214msalvation can't be bought and sold
\x1B[38;5;214mextreme self-consciousness leads to perversion
\x1B[38;5;214mroutine small excesses are worse than then the occasional debauch
\x1B[38;5;214mwe must make sacrifices to maintain our quality of life
\x1B[38;5;214mmuch was decided before you were born
\x1B[38;5;214ma positive attitude means all the difference in the world
\x1B[38;5;214myou must have one grand passion
\x1B[38;5;214mit is heroic to try to stop time
\x1B[38;5;214moccasionally principles are more valuable than people
\x1B[38;5;214ma sense of timing is the mark of genius
\x1B[38;5;214mexpressing anger is necessary
\x1B[38;5;214mroutine is a link with the past
\x1B[38;5;214mtorture is barbaric
\x1B[38;5;214melaboration is a form of pollution
\x1B[38;5;214mpeople are responsible for what they do unless they are insane
\x1B[38;5;214mromantic love was invented to manipulate women
\x1B[38;5;214msex differences are here to stay
\x1B[38;5;214mthe unattainable is invariable attractive
\x1B[38;5;214ma man can't know what it is to be a mother
\x1B[38;5;214mthere's nothing except what you sense
\x1B[38;5;214msurvival of the fittest applies to men and animals
\x1B[38;5;214man elite is inevitable
\x1B[38;5;214mit is man's fate to outsmart himself
\x1B[38;5;214mpeople won't behave if they have nothing to lose
\x1B[38;5;214mpeople are nuts if they think they are important
\x1B[38;5;214many surplus is immoral
\x1B[38;5;214mremember you always have freedom of choice
\x1B[38;5;214ma lot of professionals are crackpots
\x1B[38;5;214msacrificing yourself for a bad cause is not a moral act
\x1B[38;5;214mit's better to be naive than jaded
\x1B[38;5;214mdependence can be a meal ticket
\x1B[38;5;214mkeep something in reserve for emergencies
\x1B[38;5;214mold friends are better left in the past
\x1B[38;5;214mmoney creates taste
\x1B[38;5;214mto disagree presupposes moral integrity
\x1B[38;5;214mbeing sure of yourself means you're a fool
\x1B[38;5;214myou must know where you stop and the world begins
\x1B[38;5;214mideals are replaced by conventional goals at a certain age
\x1B[38;5;214mmost people are not fit to rule themselves
\x1B[38;5;214mguilt and self-laceration are indulgences
\x1B[38;5;214mit's better to be lonely than to be with inferior people
\x1B[38;5;214mdying and coming back gives you considerable perspective
\x1B[38;5;214mabsolute submission can be a form of freedom
\x1B[38;5;214mfear is the greatest incapacitator
\x1B[38;5;214mholding back protects your vital energies
\x1B[38;5;214mwhen something terrible happens people wake up
\x1B[38;5;214mensure that your life stays in flux
\x1B[38;5;214mbeing judgmental is a sign of life
\x1B[38;5;214mfreedom is a luxury not a necessity
\x1B[38;5;214mdrama often obscures the real issues
\x1B[38;5;214mwith perseverance you can discover any truth
\x1B[38;5;214mhumanism is obsolete
\x1B[38;5;214myou must disagree with authority figures
\x1B[38;5;214mmyth can make reality more intelligible
\x1B[38;5;214mhabitual contempt doesn't reflect a finer sensibility
\x1B[38;5;214msterilization is a weapon of the rulers
\x1B[38;5;214myour oldest fears are the worst ones
\x1B[38;5;214moffer very little information about yourself
\x1B[38;5;214mthreatening someone sexually is a horrible act
\x1B[38;5;214mbeing alone with yourself is increasingly unpopular
\x1B[38;5;214myou are a victim of the rules you live by
\x1B[38;5;214mto volunteer is reactionary
\x1B[38;5;214myou have to hurt others to be extraordinary
\x1B[38;5;214mabuse of power comes as no surprise
\x1B[38;5;214mrecluses always get weak
\x1B[38;5;214mawful punishment awaits really bad people
\x1B[38;5;214mchildren are the most cruel of all
\x1B[38;5;214mthe cruelest disappointment is when you let yourself down
\x1B[38;5;214mgo all out in romance and let the chips fall where they may
\x1B[38;5;214mthe only way to be pure is to stay by yourself
\x1B[38;5;214mspending too much time on self-improvement is antisocial
\x1B[38;5;214mknowing yourself lets you understand others
\x1B[38;5;214mresolutions serve to ease our conscience
\x1B[38;5;214mwar is a purification rite
\x1B[38;5;214mgiving free rein to your emotions is an honest way to live
\x1B[38;5;214mpeople who go crazy are too sensitive
\x1B[38;5;214mit's better to study the living fact than to analyze history
\x1B[38;5;214mmen are not monogamous by nature
\x1B[38;5;214mclass action is a nice idea with no substance
\x1B[38;5;214mdreaming while awake is a frightening contradiction
\x1B[38;5;214millness is a state of mind
\x1B[38;5;214myou are responsible for constituting the meaning of things
\x1B[38;5;214mit's good to give extra money to charity
\x1B[38;5;214mit's better to be a good person than a famous person
\x1B[38;5;214moften you should act like you are sexless
\x1B[38;5;214mpeople who don't work with their hands are parasites
\x1B[38;5;214mmonomania is a prerequisite of success
\x1B[38;5;214mchasing the new is dangerous to society
\x1B[38;5;214mrevolution begins with changes in the individual
\x1B[38;5;214mselflessness is the highest achievement
\x1B[38;5;214msymbols are more meaningful than things themselves
\x1B[38;5;214ma strong sense of duty imprisons you
\x1B[38;5;214mautomation is deadly
\x1B[38;5;214mopacity is an irresistible challenge
\x1B[38;5;214mmurder has its sexual side
\x1B[38;5;214mat times inactivity is preferable to mindless functioning
\x1B[38;5;214mmostly you should mind your own business
\x1B[38;5;214mthe mundane is to be cherished
\x1B[38;5;214mselfishness is the most basic motivation
\x1B[38;5;214msloppy thinking gets worse over time
\x1B[38;5;214myou can't expect people to be something they're not
\x1B[38;5;214mambivalence can ruin your life
\x1B[38;5;214munquestioning love demonstrates largesse of spirit
\x1B[38;5;214mlabor is a life-destroying activity
\x1B[38;5;214mgovernment is a burden on the people
\x1B[38;5;214mdecency is a relative thing
\x1B[38;5;214myour actions ae pointless if no one notices
\x1B[38;5;214mdying should be as easy as falling off a log
\x1B[38;5;214martificial desires are despoiling the earth
\x1B[38;5;214mcategorizing fear is calming
\x1B[38;5;214mit's just an accident that your parents are your parents
\x1B[38;5;214meven your family can betray you
\x1B[38;5;214mbad intentions can yield good results
\x1B[38;5;214mif you have many desires your life will be interesting
\x1B[92mMate Light\x1B[93m@\x1B[92mPlay store or \x1B[94;101mtcp://ml.jaseg.net:1337\x1B[0;91m ♥
\x1B[38;5;214mit's not good to operate on credit
\x1B[38;5;214mdescription is more important than metaphor
\x1B[38;5;214mhiding your emotions is despicable
\x1B[38;5;214mthe desire to reproduce is a death wish
\x1B[38;5;214mpush yourself to the limit as often as possible
\x1B[38;5;214mextreme behavior has its basis in pathological psychology
\x1B[38;5;214mthere's nothing redeeming in toil
\x1B[38;5;214myou are guileless in your dreams
\x1B[38;5;214manything is a legitimate area of investigation
\x1B[38;5;214mdeviants are sacrificed to increase group solidarity
\x1B[38;5;214myou can't fool others if you're fooling yourself
\x1B[38;5;214myou can understand someone of your sex only
\x1B[38;5;214mraise boys and girls the same way
\x1B[38;5;214mit's not good to hold too many absolutes
\x1B[38;5;214mkilling is unavoidable but nothing to be proud of
\x1B[38;5;214myou should study as much as possible
\x1B[38;5;214malienation produces eccentrics or revolutionaries
\x1B[38;5;214mtimidity is laughable
\x1B[38;5;214mfathers often use too much force
\x1B[38;5;214mgrass roots agitation is the only hope
\x1B[38;5;214mstrong emotional attachment stems from basic insecurity
\x1B[38;5;214mrechanneling destructive impulses is a sign of maturity
\x1B[92mMate Light\x1B[0m powered by \x1B[95mApple™ \x1B[96miScroll®'
\x1B[38;5;214msometimes science advances faster than it should
\x1B[38;5;214ma sincere effort is all you can ask
\x1B[38;5;214myou owe the world not the other way around
\x1B[38;5;214mmothers shouldn't make too many sacrifices
\x1B[38;5;214mloving animals is a substitute activity
\x1B[38;5;214mchange is valuable when the oppressed become tyrants
\x1B[38;5;214msolitude is enriching
\x1B[38;5;214msometimes things seem to happen of their own accord
\x1B[38;5;214mviolence is permissible even desirable occasionally
\x1B[38;5;214mall things are delicately interconnected
\x1B[38;5;214mplaying it safe can cause a lot of damage in the long run
\x1B[38;5;214mdecadence can be an end in itself
\x1B[92mMate Light\x1B[0;91m ♥ \x1B[92mUnicode
\x1B[38;5;214meveryone's work is equally important
\x1B[38;5;214mtaking a strong stand publicizes the opposite position
\x1B[38;5;214mpain can be a very positive thing
\x1B[38;5;214mclass structure is as artificial as plastic
\x1B[38;5;214mthe world operates according to discoverable laws
\x1B[38;5;214mteasing people sexually can have ugly consequences
\x1B[38;5;214mredistributing wealth is imperative
\x1B[38;5;214maction causes more trouble than thought
\x1B[38;5;214mignoring enemies is the best way to fight
\x1B[38;5;214mnoise can be hostile
\x1B[38;5;214mwishing things away is not effective
\x1B[38;5;214mit is a gift to the world not to have babies
\x1B[38;5;214mthe sum of your actions determines what you are
\x1B[38;5;214ma name means a lot just by itself
\x1B[38;5;214mthinking too much can only cause problems
\x1B[38;5;214msin is a means of social control
\x1B[38;5;214mchildren are the hope of the future
\x1B[38;5;214min some instances it's better to die than to continue
\x1B[38;5;214mself-awareness can be crippling
\x1B[38;5;214mprivate property created crime
\x1B[38;5;214mlow expectations are good protection
\x1B[38;5;214meverything that's interesting is new
\x1B[38;5;214mdon't place to much trust in experts
\x1B[38;5;214mstupid people shouldn't breed
\x1B[38;5;214ma relaxed man is not necessarily a better man
\x1B[38;5;214mleisure time is a gigantic smoke screen
\x1B[38;5;214mexceptional people deserve special concessions
\x1B[38;5;214mstasis is a dream state
\x1B[38;5;214mgood deeds eventually are rewarded
\x1B[38;5;214menjoy yourself because you can't change anything anyway
\x1B[38;5;214mthe new is nothing but a restatement of the old
\x1B[38;5;214mit's crucial to have an active fantasy life
\x1B[38;5;214mworrying can help you prepare
\x1B[38;5;214minheritance must be abolished
\x1B[38;5;214mpeople are boring unless they are extremists
\x1B[38;5;214mconfusing yourself is a way to stay honest
\x1B[38;5;214mstarvation is nature's way
\x1B[38;5;214mhumor is a release
\x1B[38;5;214mcrime against property is relatively unimportant
\x1B[38;5;214mat times your unconsciousness is truer than your conscious mind
\x1B[38;5;214mself-contempt can do more harm than good
\x1B[38;5;214mtalking is used to hide one's inability to act
\x1B[38;5;214mthe idea of revolution is an adolescent fantasy
\x1B[38;5;214mif you live simply there is nothing to worry about
\x1B[38;5;214ma single event can have infinitely many interpretations
\x1B[38;5;214mgoing with the flow is soothing but risky
\x1B[38;5;214mmanual labor can be refreshing and wholesome
\x1B[38;5;214mpotential counts for nothing until it's realized
\x1B[38;5;214myou are the past present and future
\x1B[38;5;214mtechnology will make or break us
\x1B[38;5;214mevery achievement requires a sacrifice
\x1B[38;5;214mthe family is living on borrowed time
\x1B[38;5;214mphysical culture is second best
\x1B[38;5;214munique things must be the most valuable
\x1B[38;5;214ma solid home base builds a sense of self
\x1B[38;5;214mthe idiosyncratic has lost its authority
\x1B[38;5;214mlooking back is the first sign of aging and decay
\x1B[38;5;214mrepetition is the best way to learn
\x1B[38;5;214mknowledge should be advanced at all costs
\x1B[38;5;214mif you aren't political your personal life should be exemplary
\x1B[38;5;214mboredom makes you do crazy things
\x1B[38;5;214myou must be intimate with a token few
\x1B[38;5;214myou can live on through your descendants
\x1B[38;5;214mseparatism is the way to a new beginning
\x1B[38;5;214mthe idea of transcendence is used to obscure oppression
\x1B[38;5;214mpolitics is used for personal gain
\x1B[38;5;214meating too much is criminal
\x1B[38;5;214mimposing order is man's vocation for chaos is hell
\x1B[38;5;214myou don't know what's what until you support yourself
\x1B[38;5;214mif you can't leave your mark give up
\x1B[38;5;214ma little knowledge can go a long way
\x1B[38;5;214musing force to stop force is absurd
\x1B[38;5;214mmorals are for little people
\x1B[38;5;214mwords tend to be inadequate
\x1B[38;5;214memotional responses ar as valuable as intellectual responses
\x1B[92mMate Light\x1B[0m powered by \x1B[95mMicrosoft™ \x1B[96mMarquee Manager® Professional OEM
\x1B[38;5;214mthe most profound things are inexpressible
\x1B[38;5;214mfaithfulness is a social not a biological law
\x1B[38;5;214mrelativity is no boon to mankind
\x1B[38;5;214mmoderation kills the spirit

View file

@ -3,7 +3,6 @@
#include "main.h" #include "main.h"
#include "color.h" #include "color.h"
#include "font.h" #include "font.h"
#include "net.h"
#include <stdint.h> #include <stdint.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
@ -65,7 +64,7 @@ framebuffer_t *framebuffer_render_text(char *s, glyphtable_t *glyph_table){
p += inc; p += inc;
if(c > glyph_table->size){ if(c > glyph_table->size){
fprintf(stderr, "Error rendering string: Codepoint 0x%lx out of valid range (0-%ld).\n", (long int)c, glyph_table->size); fprintf(stderr, "Error rendering string: Codepoint 0x%lx out of valid range (0-%zd).\n", (long int)c, glyph_table->size);
goto error; goto error;
} }
@ -87,7 +86,7 @@ framebuffer_t *framebuffer_render_text(char *s, glyphtable_t *glyph_table){
size_t gbufsize = gbufwidth*gbufheight; size_t gbufsize = gbufwidth*gbufheight;
gbuf = calloc(gbufsize, sizeof(color_t)); gbuf = calloc(gbufsize, sizeof(color_t));
if(!gbuf){ if(!gbuf){
fprintf(stderr, "Cannot malloc() %lu bytes.\n", gbufsize*sizeof(color_t)); fprintf(stderr, "Cannot malloc() %zu bytes.\n", gbufsize*sizeof(color_t));
goto error; goto error;
} }
memset(gbuf, 0, gbufsize*sizeof(color_t)); memset(gbuf, 0, gbufsize*sizeof(color_t));
@ -296,7 +295,7 @@ framebuffer_t *framebuffer_render_text(char *s, glyphtable_t *glyph_table){
} }
framebuffer_t *fb = malloc(sizeof(framebuffer_t)); framebuffer_t *fb = malloc(sizeof(framebuffer_t));
if(!fb){ if(!fb){
fprintf(stderr, "Cannot malloc() %lu bytes.\n", sizeof(framebuffer_t)); fprintf(stderr, "Cannot malloc() %zu bytes.\n", sizeof(framebuffer_t));
goto error; goto error;
} }
fb->w = gbufwidth; fb->w = gbufwidth;
@ -311,7 +310,7 @@ error:
void console_render_buffer(color_t *data, size_t w, size_t h){ void console_render_buffer(color_t *data, size_t w, size_t h){
/* Render framebuffer to terminal, two pixels per character using Unicode box drawing stuff */ /* Render framebuffer to terminal, two pixels per character using Unicode box drawing stuff */
color_t lastfg = {0, 0, 0}, lastbg = {0, 0, 0}; color_t lastfg = {0, 0, 0}, lastbg = {0, 0, 0};
printf("\e[38;5;0;48;5;0m"); printf("\e[38;5;0;48;5;0m\e[K");
for(size_t y=0; y < h; y+=2){ for(size_t y=0; y < h; y+=2){
for(size_t x=0; x < w; x++){ for(size_t x=0; x < w; x++){
/* Da magicks: ▀█▄ */ /* Da magicks: ▀█▄ */
@ -350,7 +349,7 @@ void console_render_buffer(color_t *data, size_t w, size_t h){
} }
} }
} }
printf("\n"); printf("\n\e[K");
} }
printf("\033[0m"); printf("\033[0m");
} }

View file

@ -1,7 +1,8 @@
import usb
import colorsys import colorsys
import numpy as np import numpy as np
from itertools import product from itertools import product
from ctypes import c_size_t, c_uint8, c_void_p, c_float, CDLL, Structure, POINTER
import time
CRATE_WIDTH = 5 CRATE_WIDTH = 5
CRATE_HEIGHT = 4 CRATE_HEIGHT = 4
@ -19,7 +20,14 @@ GAMMA = 2.5
# Brightness of the LEDs in percent. 1.0 means 100%. # Brightness of the LEDs in percent. 1.0 means 100%.
BRIGHTNESS = 0.2 BRIGHTNESS = 0.2
dev = usb.core.find(idVendor=0x1cbe, idProduct=0x0003) ml = CDLL('./libml.so')
ml.matelight_open.restype = c_void_p
if ml.matelight_usb_init():
raise OSError('Cannot initialize USB library')
matelights = ml.matelight_open()
if matelights is None:
raise ImportError('Cannot open any Mate Light devices')
def sendframe(framedata): def sendframe(framedata):
""" Send a frame to the display """ Send a frame to the display
@ -27,15 +35,25 @@ def sendframe(framedata):
The argument contains a h * w array of 3-tuples of (r, g, b)-data or 4-tuples of (r, g, b, a)-data where the a The argument contains a h * w array of 3-tuples of (r, g, b)-data or 4-tuples of (r, g, b, a)-data where the a
channel is ignored. channel is ignored.
""" """
# Gamma correction # just use the first Mate Light available
framedata = (((framedata/255) ** GAMMA) * BRIGHTNESS * 255).astype(np.uint8) buf = framedata.ctypes.data_as(POINTER(c_uint8))
for cx, cy in product(range(CRATES_X), range(CRATES_Y)): ml.matelight_send_frame(matelights, buf, c_size_t(CRATES_X), c_size_t(CRATES_Y), c_float(BRIGHTNESS), True)
datar = framedata[cy*CRATE_HEIGHT:(cy+1)*CRATE_HEIGHT, cx*CRATE_WIDTH:(cx+1)*CRATE_WIDTH, :3]
data = datar.flat
if len(data) != CRATE_SIZE:
raise ValueError('Invalid frame data. Expected {} bytes, got {}.'.format(CRATE_SIZE, len(data)))
# Send framebuffer data
dev.write(0x01, bytes([0, cx, cy])+bytes(data))
# Send latch command
dev.write(0x01, b'\x01')
if __name__ == '__main__':
#foo = np.array([[(0, 0, 0, 0)]*DISPLAY_WIDTH]*DISPLAY_HEIGHT)
#bar = np.array([[(255, 0, 255, 0)]*DISPLAY_WIDTH]*DISPLAY_HEIGHT)
x,y = 0,0
while True:
x += 1
if x == DISPLAY_WIDTH:
x = 0
y += 1
if y == DISPLAY_HEIGHT:
y = 0
foo = np.array([[(64, 0, 0, 255)]*DISPLAY_WIDTH]*DISPLAY_HEIGHT, dtype=np.uint8)
foo[y,x,:] = (0,64,0,255)
#from terminal import printframe
sendframe(foo)
#printframe(foo)
#sendframe(bar)
time.sleep(0.1)

View file

@ -1,18 +0,0 @@
#ifndef __NET_H__
#define __NET_H__
#include "config.h"
typedef struct {
uint8_t r, g, b;
} rgb_t;
typedef struct {
uint32_t magic, seq;
uint16_t width, height;
rgb_t data[DISPLAY_WIDTH*DISPLAY_HEIGHT];
} ml_packet_t;
#define UDP_BUF_SIZE sizeof(ml_packet_t)
#endif//__NET_H__

View file

@ -3,7 +3,7 @@
from socketserver import * from socketserver import *
from time import time, strftime, sleep from time import time, strftime, sleep
from collections import namedtuple from collections import namedtuple
from itertools import product from itertools import product, cycle
import threading import threading
import random import random
@ -49,19 +49,21 @@ def printframe(fb):
print('\0337\033[H', end='') print('\0337\033[H', end='')
print('Rendering frame @{}'.format(time())) print('Rendering frame @{}'.format(time()))
bdf.console_render_buffer(fb.ctypes.data_as(POINTER(c_uint8)), w, h) bdf.console_render_buffer(fb.ctypes.data_as(POINTER(c_uint8)), w, h)
print('\033[0mCurrently rendering', current_entry.entrytype, 'from', current_entry.remote, ':', current_entry.text, '\0338', end='') print('\033[0m\033[KCurrently rendering', current_entry.entrytype, 'from', current_entry.remote, ':', current_entry.text, '\0338', end='')
printlock.release() printlock.release()
def scroll(text): def scroll(text):
""" Returns whether it could scroll all the text uninterrupted """ """ Returns whether it could scroll all the text uninterrupted """
log('Scrolling', text)
fb = render_text(text); fb = render_text(text);
h,w,_ = fb.shape h,w,_ = fb.shape
for i in range(-DISPLAY_WIDTH,w+1): for i in range(-DISPLAY_WIDTH,w+1):
if current_entry.entrytype == 'udp' or (current_entry in defaulttexts and textqueue): # if current_entry.entrytype == 'udp' or (textqueue and current_entry in defaulttexts):
return False # log('Aborting rendering due to new input')
leftpad = np.zeros((DISPLAY_HEIGHT, max(-i, 0), 4), dtype=np.uint8) # return False
framedata = fb[:, max(0, i):min(i+DISPLAY_WIDTH, w)] leftpad = np.zeros((DISPLAY_HEIGHT, max(-i, 0), 4), dtype=np.uint8)
rightpad = np.zeros((DISPLAY_HEIGHT, min(DISPLAY_WIDTH, max(0, i+DISPLAY_WIDTH-w)), 4), dtype=np.uint8) framedata = fb[:, max(0, i):min(i+DISPLAY_WIDTH, w)]
rightpad = np.zeros((DISPLAY_HEIGHT, min(DISPLAY_WIDTH, max(0, i+DISPLAY_WIDTH-w)), 4), dtype=np.uint8)
dice = np.concatenate((leftpad, framedata, rightpad), 1) dice = np.concatenate((leftpad, framedata, rightpad), 1)
sendframe(dice) sendframe(dice)
printframe(dice) printframe(dice)
@ -69,21 +71,16 @@ def scroll(text):
return True return True
QueueEntry = namedtuple('QueueEntry', ['entrytype', 'remote', 'timestamp', 'text']) QueueEntry = namedtuple('QueueEntry', ['entrytype', 'remote', 'timestamp', 'text'])
defaulttexts = [QueueEntry('text', '127.0.0.1', 0, t) for t in [ defaultlines = [ QueueEntry('text', '127.0.0.1', 0, l[:-1].replace('\\x1B', '\x1B')) for l in open('default.lines').readlines() ]
'\x1B[92mMate Light\x1B[93m@\x1B[92mPlay store or \x1B[94;101mtcp://ml.jaseg.net:1337\x1B[0;91m ♥', random.shuffle(defaultlines)
'\x1B[92mMate Light\x1B[0;91m ♥ \x1B[92mUnicode', defaulttexts = cycle(defaultlines)
'\x1B[92mMate Light\x1B[0m powered by \x1B[95mMicrosoft™ \x1B[96mMarquee Manager® Professional OEM', current_entry = next(defaulttexts)
'\x1B[92mMate Light\x1B[0m powered by \x1B[95mData Becker™ \x1B[96mLaufschriftstudio 2000® Platinum Edition',
'\x1B[92mMate Light\x1B[0m powered by \x1B[95mApple™ \x1B[96miScroll®',
'\x1B[92mMate Light\x1B[0m powered by \x1B[95mSiemens™ \x1B[96mLaufschrift® v.0.1.2b fuer Intel™ Pentium®',
]]
current_entry = random.choice(defaulttexts)
conns = {} conns = {}
textqueue = [] textqueue = []
def log(*args): def log(*args):
printlock.acquire() printlock.acquire()
print(strftime('[%m-%d %H:%M:%S]'), *args) print(strftime('[%m-%d %H:%M:%S]'), ' '.join(str(arg) for arg in args), '\x1B[0m')
printlock.release() printlock.release()
class MateLightUDPHandler(BaseRequestHandler): class MateLightUDPHandler(BaseRequestHandler):
@ -159,12 +156,12 @@ if __name__ == '__main__':
if conns: if conns:
current_entry = random.choice(list(conns.values())) current_entry = random.choice(list(conns.values()))
else: else:
current_entry = random.choice(defaulttexts) current_entry = next(defaulttexts)
if current_entry.entrytype != 'udp' and textqueue: if current_entry.entrytype != 'udp' and textqueue:
current_entry = textqueue[0] current_entry = textqueue[0]
if current_entry.entrytype == 'udp': if current_entry.entrytype == 'udp':
if time() - current_entry.timestamp > UDP_TIMEOUT: if time() - current_entry.timestamp > UDP_TIMEOUT:
current_entry = random.choice(defaulttexts) current_entry = next(defaulttexts)
else: else:
sleep(0.2) sleep(0.1)

19
host/terminal.py Normal file
View file

@ -0,0 +1,19 @@
from pixelterm.pixelterm import termify_pixels
class MockImage:
def __init__(self, nparray):
self.nparray = nparray
self.im = self
@property
def size(self):
h, w, _ = self.nparray.shape
return (w, h)
def getpixel(self, pos):
x, y = pos
return tuple(self.nparray[y][x])
def printframe(framedata):
print(termify_pixels(MockImage(framedata)))

156
host/usb.c Normal file
View file

@ -0,0 +1,156 @@
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <libusb-1.0/libusb.h>
#include "color.h"
#include "usb.h"
int matelight_usb_init(){
int rc = 0;
rc = libusb_init(NULL);
if(rc){
fprintf(stderr, "LIBML: Cannot initialize libusb\n");
return 1;
}
return 0;
}
void matelight_usb_destroy(){
libusb_exit(NULL);
}
static int matelight_cmp_str_desc(libusb_device_handle *dev, uint8_t index, char *value){
char data[256];
if(libusb_get_string_descriptor_ascii(dev, index, (unsigned char*)data, sizeof(data)) < 0){
fprintf(stderr, "LIBML: Cannot read device string descriptor\n");
return 0;
}
return strcmp(data, value) == 0;
}
matelight_handle *matelight_open(){
matelight_handle *out = NULL;
libusb_device** device_list;
struct libusb_device_descriptor desc;
ssize_t res = libusb_get_device_list(NULL, &device_list);
if(res == 0){
fprintf(stderr, "LIBML: Cannot find any connected matelight\n");
goto error;
}else if(res < 0){
fprintf(stderr, "LIBML: Error enumerating connected USB devices\n");
goto error;
}else{
out = calloc(res+1, sizeof(matelight_handle));
if(!out){
fprintf(stderr, "LIBML: Cannot allocate memory\n");
goto error;
}
memset(out, 0, (res+1)*sizeof(matelight_handle));
unsigned int found = 0;
for(ssize_t i=0; i<res; i++){
libusb_get_device_descriptor(device_list[i], &desc);
if(desc.idVendor == MATELIGHT_VID && desc.idProduct == MATELIGHT_PID){
libusb_device_handle *handle;
if(libusb_open(device_list[i], &(handle))){
fprintf(stderr, "LIBML: Cannot open Mate Light USB device\n");
goto error;
}
out[found].handle = handle;
if(matelight_cmp_str_desc(handle, desc.iManufacturer, "Gold & Apple"))
if(matelight_cmp_str_desc(handle, desc.iProduct, "Mate Light")){
#define BUF_SIZE 256
char *serial = malloc(BUF_SIZE);
if(!serial){
fprintf(stderr, "LIBML: Cannot allocate memory\n");
goto error;
}
if(libusb_get_string_descriptor_ascii(out[found].handle, desc.iSerialNumber, (unsigned char*)serial, BUF_SIZE) < 0){
fprintf(stderr, "LIBML: Cannot read device string descriptor\n");
goto error;
}
#undef BUF_SIZE
out[found].serial = serial;
found++;
}
}
}
out[found].handle = NULL;
out[found].serial = NULL;
}
libusb_free_device_list(device_list, 1);
return out;
error:
if(res>0 && out){
for(ssize_t i=0; i<res; i++){
if(out[i].handle)
libusb_close(out[i].handle);
free(out[i].serial);
}
}
free(out);
libusb_free_device_list(device_list, 1);
return 0;
}
typedef struct{
uint8_t opcode;
uint8_t x, y;
rgb_t buf[CRATE_WIDTH*CRATE_HEIGHT];
} crate_frame_t;
int matelight_send_frame(matelight_handle *ml, void *buf, size_t w, size_t h, float brightness, int alpha){
// fprintf(stderr, "\nFRAME START\n");
for(size_t cy=0; cy<h; cy++){
// fprintf(stderr, "##### NEXT ROW\n");
for(size_t cx=0; cx<w; cx++){
crate_frame_t frame;
frame.opcode = 0;
frame.x = cx;
frame.y = cy;
// fprintf(stderr, "CRATE %d %d\n", cx, cy);
for(size_t x=0; x<CRATE_WIDTH; x++){
for(size_t y=0; y<CRATE_HEIGHT; y++){
size_t dpos = y*CRATE_WIDTH + x;
size_t spos = w*CRATE_WIDTH*(cy*CRATE_HEIGHT+y) + cx*CRATE_WIDTH+x;
color_t *src = (((color_t*)buf)+spos);
rgb_t *dst = frame.buf+dpos;
/* Gamma correction */
#define GAMMA_APPLY(c) ((uint8_t)roundf(powf((c/255.0F), GAMMA) * brightness * 255))
dst->r = GAMMA_APPLY(src->r);
dst->g = GAMMA_APPLY(src->g);
dst->b = GAMMA_APPLY(src->b);
// fprintf(stderr, "%c", ((dst->r > 1) ? '#' : '.'));
#undef GAMMA_APPLY
}
// fprintf(stderr, "\n");
}
int transferred = 0;
int rc = libusb_bulk_transfer(ml->handle, MATELIGHT_FRAMEDATA_ENDPOINT, (unsigned char*)&frame, sizeof(frame), &transferred, MATELIGHT_TIMEOUT);
if(rc){
fprintf(stderr, "LIBML: Cannot write frame data\n");
return 1;
}
if(transferred != sizeof(frame)){
fprintf(stderr, "LIBML: Could not transfer all frame data. Only transferred %d out of %d bytes.\n", transferred, sizeof(frame));
return 1;
}
}
}
uint8_t payload = 0x01;
int transferred = 0;
int rc = libusb_bulk_transfer(ml->handle, MATELIGHT_FRAMEDATA_ENDPOINT, &payload, sizeof(uint8_t), &transferred, MATELIGHT_TIMEOUT);
if(rc){
fprintf(stderr, "LIBML: Cannot write frame data\n");
return 1;
}
if(transferred != sizeof(uint8_t)){
fprintf(stderr, "LIBML: Could not transfer all frame data. Only transferred %d out of %d bytes.\n", transferred, sizeof(uint8_t));
return 1;
}
return 0;
}

27
host/usb.h Normal file
View file

@ -0,0 +1,27 @@
#ifndef __USB_H__
#define __USB_H__
#include <libusb-1.0/libusb.h>
#define MATELIGHT_VID 0x1cbe
#define MATELIGHT_PID 0x0003
#define CRATE_WIDTH 5
#define CRATE_HEIGHT 4
#define MATELIGHT_FRAMEDATA_ENDPOINT 0x01
#define MATELIGHT_TIMEOUT 1000
#define GAMMA 2.5F
typedef struct {
libusb_device_handle *handle;
char *serial;
} matelight_handle;
int matelight_usb_init(void);
void matelight_usb_destroy(void);
matelight_handle *matelight_open(void);
int matelight_send_frame(matelight_handle *ml, void *buf, size_t w, size_t h, float brightness, int alpha);
#endif//__USB_H__