LEDControl/src/main/java/de/zuim/ledcontrol/LEDControl.java
2021-03-14 12:18:00 +01:00

141 lines
4 KiB
Java

package de.zuim.ledcontrol;
import com.fazecast.jSerialComm.SerialPort;
import com.fazecast.jSerialComm.SerialPortDataListener;
import com.fazecast.jSerialComm.SerialPortEvent;
import java.awt.*;
import java.awt.geom.AffineTransform;
import java.awt.image.AffineTransformOp;
import java.awt.image.BufferedImage;
import java.nio.charset.StandardCharsets;
public class LEDControl {
public static final int WIDTH = 32;
public static final int HEIGHT = 16;
public static final int LED_NUM = WIDTH * HEIGHT;
public static final int BAUD = 1000000;
private static final int FRAME_MS = 40;
private SerialPort port;
private final byte[][][] leds = new byte[WIDTH][HEIGHT][3];
private final EffectManager eff;
private BufferedImage scaledImage;
public LEDControl() {
eff = new EffectManager();
Runtime.getRuntime().addShutdownHook(new Thread(() -> port.closePort()));
connect();
sendLoop();
}
private void sendLoop() {
long time = System.nanoTime();
long iteration = 0;
long minTimeDelta = Long.MAX_VALUE,
maxTimeDelta = 0,
avgTimeDelta = 0;
while (true) {
if (port == null || !port.isOpen()) {
if (!connect()) {
sleep(1000);
continue;
}
}
long timeDelta = System.nanoTime() - time;
if (timeDelta > maxTimeDelta)
maxTimeDelta = timeDelta;
if (timeDelta < minTimeDelta)
minTimeDelta = timeDelta;
avgTimeDelta += timeDelta;
time = System.nanoTime();
renderFrame(timeDelta);
port.writeBytes(new byte[]{(byte) 255}, 1); //start of new frame
for (int x = 0; x < WIDTH; x++) {
for (int y = 0; y < HEIGHT; y++) {
int col = scaledImage.getRGB(x, (x % 2 == 1) ? leds[0].length - y - 1 : y);
leds[x][y][0] = (byte) Math.min(((col >> 16) & 0xff), 254);
leds[x][y][1] = (byte) Math.min((col >> 8) & 0xff, 254);
leds[x][y][2] = (byte) Math.min(((col) & 0xff), 254);
port.writeBytes(leds[x][y], 3);
}
}
sleep(FRAME_MS);//(int) (FRAME_MS) - ((System.nanoTime()-time)/1000000)));
if (iteration % 1000 == 0 && iteration > 0) {
System.out.println("Frametime: " + (Math.round(avgTimeDelta / 1000.0) / 100000) / 10.0 + "ms (" + (Math.round(minTimeDelta) / 100000) / 10.0 + "ms - " + (Math.round(maxTimeDelta) / 100000) / 10.0 + "ms) " + iteration + " Frames");
minTimeDelta = Long.MAX_VALUE;
maxTimeDelta = 0;
avgTimeDelta = 0;
}
iteration++;
}
}
private boolean connect() {
SerialPort[] ports = SerialPort.getCommPorts();
if (ports.length > 0) {
port = SerialPort.getCommPorts()[0];
System.out.println("Connect to " + port.getDescriptivePortName() + " " + port.getSystemPortName() + " ");
port.setComPortParameters(BAUD, 8, 1, 0);
if (port.openPort()) {
port.addDataListener(new SerialPortDataListener() {
@Override
public int getListeningEvents() {
return SerialPort.LISTENING_EVENT_DATA_RECEIVED;
}
@Override
public void serialEvent(SerialPortEvent event) {
System.err.println("Received: " + new String(event.getReceivedData(), StandardCharsets.US_ASCII));
}
});
return true;
}
}
return false;
}
private void sleep(int ms) {
try {
Thread.sleep(ms);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
private void renderFrame(long timeDelta) {
BufferedImage image = new BufferedImage(WIDTH * eff.getActiveEffect().getScale(), HEIGHT * eff.getActiveEffect().getScale(), BufferedImage.TYPE_INT_ARGB);
Graphics g = image.getGraphics();
eff.getActiveEffect().render(timeDelta, g);
g.dispose();
if (eff.getActiveEffect().getScale() == 1) {
scaledImage = image;
} else {
scaledImage = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_ARGB);
AffineTransform at = new AffineTransform();
at.scale(1.0 / eff.getActiveEffect().getScale(), 1.0 / eff.getActiveEffect().getScale());
AffineTransformOp scaleOp =
new AffineTransformOp(at, AffineTransformOp.TYPE_BILINEAR);
scaledImage = scaleOp.filter(image, scaledImage);
}
}
public static void main(String[] args) {
new LEDControl();
}
}