Skip to content

Instantly share code, notes, and snippets.

@kjunichi
Last active January 7, 2025 13:54
Show Gist options
  • Save kjunichi/a6143859f906830bf6bb47eaecdfbdc9 to your computer and use it in GitHub Desktop.
Save kjunichi/a6143859f906830bf6bb47eaecdfbdc9 to your computer and use it in GitHub Desktop.
webサーバーから日本語フォントのレンダリング情報をJSONでもらってArduino UNO R4 LEDに表示する
const { createCanvas, Image, registerFont } = require('canvas')
const { serve } = require(`@hono/node-server`)
const { Hono } = require('hono')
const app = new Hono()
app.get('/', (c) => {
return c.text('Hello Hono!')
})
const getJson = (data) => {
}
const genFontData = async (cs, moji, callback) => {
const target = moji
const fsize = 8
cs.width = fsize
cs.height = fsize //+ 2
const ctx = cs.getContext("2d")
//ctx.font = `${fsize}px "UD Digi Kyokasho N-R"`
ctx.font = `${fsize}px "Misaki"`
//ctx.font = `${fsize}px "MS Pゴシック"`
ctx.textBaseline = "bottom"
ctx.fillText(target, 0, fsize + 1);
const arraySize = cs.width * cs.height * 4
//console.log(`w = ${cs.width}, h = ${cs.height}`)
const simg = ctx.getImageData(0, 0, cs.width, cs.height)
const img = new Image()
const cs2 = createCanvas(400, 400)
cs2.width = cs.width * 4
cs2.height = cs.height * 4
const ctx2 = cs2.getContext("2d")
const out = { "value": "" }
await new Promise((resolve) => {
img.onload = async () => {
//console.dir(`img = ${img}`)
ctx2.drawImage(img, 0, 0, cs2.width, cs2.height)
const limage = ctx.getImageData(0, 0, cs.width, cs.height)
let pidx = 0
//console.log(`${cs.width},${cs.height}`)
let buf = []
for (let y = 0; y < cs.height; y++) {
let line = ""
for (let x = 0; x < cs.width; x++) {
if (limage.data[pidx + 3] > 100) {
line += "1"
} else {
line += "0"
}
pidx += 4
}
console.log(`${line}`)
buf.push(line + "0000")
}
out.value = buf.length + "\n"
out.line = buf.join("")
resolve(out.line);
}
img.src = cs.toDataURL("image/png");
})
return out.line
}
app.get('/moji', async (c) => {
const mojiRetsu = c.req.query('m')
console.log(`mojiRetsu = ${mojiRetsu}`)
const len = mojiRetsu.length
let counter = 0
let matData = []
const cb = (data) => {
console.log(`cb start data = ${data}`)
counter = counter + 1
matData.push(data)
console.log(`counter = ${counter}, len = ${len}`)
}
for (const moji of mojiRetsu) {
// dataに0,1で96ビット分が帰ってくる
const data = await genFontData(cs, moji, null)
//console.log(data.split(''))
let frame = []
for(let i= 0; i< 3; i++) {
let tmpline=[]
for(let j= 0; j< 32; j++) {
tmpline.push(data[i*32+j])
}
tmpline = tmpline.join("")
tmphex = parseInt(tmpline,2).toString(16)
console.log(`tmpline = 0x${tmphex}`)
frame.push(parseInt(tmpline,2))
}
// dataから32ビット区切りで16進数にする
matData.push({"frame": frame})
}
return c.json(matData)
})
const port = 3000
console.log(`Server is running on http://localhost:${port}`)
registerFont('misaki_gothic.ttf', { family: 'Misaki' })
const cs = createCanvas(400, 400)
serve({
fetch: app.fetch,
port
})
//kjunichi
#include <WiFiS3.h>
#include <Arduino_LED_Matrix.h>
#include <UrlEncode.h>
#include <ArduinoJson.h>
#include "arduino_secrets.h"
#include "anim.h"
///////please enter your sensitive data in the Secret tab/arduino_secrets.h
char ssid[] = SECRET_SSID; // your network SSID (name)
char pass[] = SECRET_PASS; // your network password (use for WPA, or use as key for WEP)
// grid dimensions. should not be larger than 8x8
#define MAX_Y 8
#define MAX_X 12
#include <LiquidCrystal.h>
unsigned long blankFrame[] = { 0, 0, 0 };
unsigned long gFrames[100][3];
unsigned long line[8];
int gNumFrames = 0;
int numFrames = 0;
int idxInFrame = 0;
ArduinoLEDMatrix matrix;
int tempPin = 0;
int status = WL_IDLE_STATUS;
WiFiServer wifiServer(80);
WiFiClient client;
//char server[] = "DESKTOP-F4B6ASC.local";
char server[] = "192.168.0.15";
int port = 3030;
// BS E D4 D5 D6 D7
LiquidCrystal lcd(7, 8, 9, 10, 11, 12);
// display the current grid to the LED matrix
void displayGrid() {
// 現在のフレームを1ドット左にずらす
// 96/32 => 12x8
line[0] = (blankFrame[0] & 0b11111111111100000000000000000000) >> 20;
line[1] = (blankFrame[0] & 0b00000000000011111111111100000000) >> 8;
line[2] = ((blankFrame[0] & 0b00000000000000000000000011111111) << 4) | ((blankFrame[1] & 0b11110000000000000000000000000000) >> 28);
line[3] = (blankFrame[1] & 0b00001111111111110000000000000000) >> 16;
line[4] = (blankFrame[1] & 0b00000000000000001111111111110000) >> 4;
line[5] = ((blankFrame[1] & 0b00000000000000000000000000001111) << 8) | ((blankFrame[2] & 0b11111111000000000000000000000000) >> 24);
line[6] = (blankFrame[2] & 0b00000000111111111111000000000000) >> 12;
line[7] = (blankFrame[2] & 0b00000000000000000000111111111111);
for (int i = 0; i < 8; i++) {
line[i] = line[i] << 1;
}
//Serial.println(gFrames[numFrames][0], BIN);
line[0] = line[0] | (((gFrames[numFrames][0] >> 20) & 0b111111111111) >> (8 - idxInFrame) & 0b1);
line[1] = line[1] | (((gFrames[numFrames][0] >> 8) & 0b111111111111) >> (8 - idxInFrame) & 0b01);
line[2] = line[2] | ((((gFrames[numFrames][0] << 4) & 0b111111110000) | ((gFrames[numFrames][1] >> 28) & 0b000000001111)) >> (8 - idxInFrame) & 0b01);
line[3] = line[3] | (((gFrames[numFrames][1] >> 16) & 0b111111111111) >> (8 - idxInFrame) & 0b1);
line[4] = line[4] | (((gFrames[numFrames][1] >> 4) & 0b111111111111) >> (8 - idxInFrame) & 0b1);
line[5] = line[5] | (((gFrames[numFrames][1] << 8) & 0b111100000000) | ((gFrames[numFrames][2] >> 24) & 0b000011111111) >> (8 - idxInFrame) & 0b1);
line[6] = line[6] | (((gFrames[numFrames][2] >> 12) & 0b111111111111) >> (8 - idxInFrame) & 0b1);
line[7] = line[7] | ((gFrames[numFrames][2] & 0b111111111111) >> (8 - idxInFrame) & 0b1);
blankFrame[0] = ((line[0] << 20) & 0b11111111111100000000000000000000) | ((line[1] << 8) & 0b00000000000011111111111100000000) | (line[2] >> 4) & 0b00000000000000000000000011111111;
blankFrame[1] = ((line[2] << 28) & 0b11110000000000000000000000000000) | ((line[3] << 16) & 0b00001111111111110000000000000000) | ((line[4] << 4) & 0b00000000000000001111111111110000) | ((line[5] >> 8) & 0b00000000000000000000000000001111);
blankFrame[2] = (((line[5] << 24) & 0b11111111000000000000000000000000) | ((line[6] << 12) & 0b00000000111111111111000000000000) | (line[7] & 0b00000000000000000000111111111111));
if (idxInFrame < 8) {
idxInFrame++;
} else {
idxInFrame = 0;
numFrames++;
}
//matrix.loadFrame(gFrames[numFrames]);
matrix.loadFrame(blankFrame);
if (numFrames >= gNumFrames) {
numFrames = 0;
}
}
void getMatData() {
if (client.connect(server, port)) {
char sbuf[1024];
String query;
query = urlEncode("日本語文字列のテスト!(aplphabet)");
//Serial.println(query);
sprintf(sbuf, "GET /moji?m=%s HTTP/1.1\r\nHost: %s\r\nConnection: close\r\n\r\n", query.c_str(), server);
Serial.print(sbuf);
client.print(sbuf);
memset(sbuf, 0x00, sizeof(sbuf));
delay(1000);
while (true) {
read_response(sbuf);
break;
}
} else {
Serial.println("Oops! server");
}
}
void read_response(char *buf) {
while (client.available()) {
char c = client.read();
strncat(buf, &c, 1);
}
Serial.print(buf);
// Check HTTP status
char *p = strtok(buf, "\r\n");
Serial.println(p);
if (strncmp(p, "HTTP/1.1 200 OK", 15) != 0) {
Serial.print(F("Unexpected response: "));
Serial.println(p);
client.stop();
return;
}
Serial.println("HTTP Status check is OK.");
// Skip HTTP headers
while ((p = strtok(NULL, "\r")) != NULL) {
Serial.print(p);
if (strcmp(p, "\n") == 0) {
Serial.println("End of Http Headers");
break;
}
}
p = strtok(NULL, "\r\n");
DynamicJsonDocument doc(4096);
// Parse JSON object
DeserializationError error = deserializeJson(doc, p);
if (error) {
Serial.print(F("deserializeJson() failed: "));
Serial.println(error.f_str());
client.stop();
return;
}
JsonArray array = doc.as<JsonArray>();
for (JsonVariant v : array) {
JsonObject jsonObj = v.as<JsonObject>();
unsigned long frame[3];
JsonArray frameArray = jsonObj["frame"].as<JsonArray>();
int idx = 0;
for (JsonVariant v2 : frameArray) {
Serial.println(v2.as<unsigned long>());
gFrames[gNumFrames][idx] = v2.as<unsigned long>();
frame[idx++] = v2.as<unsigned long>();
}
gNumFrames++;
matrix.loadFrame(frame);
delay(400);
}
}
void setup() {
Serial.begin(115200);
lcd.begin(16, 2);
matrix.begin();
// check for the WiFi module:
if (WiFi.status() == WL_NO_MODULE) {
Serial.println("Communication with WiFi module failed!");
// don't continue
while (true)
;
}
String fv = WiFi.firmwareVersion();
if (fv < WIFI_FIRMWARE_LATEST_VERSION) {
Serial.println("Please upgrade the firmware");
}
// attempt to connect to WiFi network:
while (status != WL_CONNECTED) {
Serial.print("Attempting to connect to SSID: ");
Serial.println(ssid);
// Connect to WPA/WPA2 network. Change this line if using open or WEP network:
status = WiFi.begin(ssid, pass);
// wait 10 seconds for connection:
delay(10000);
}
wifiServer.begin();
// you're connected now, so print out the status:
printWifiStatus();
getMatData();
}
void proc_webserver() {
}
int cnt = 0;
void loop() {
//read_response();
int tempReading = analogRead(tempPin);
// This is OK
double tempK = log(10000.0 * ((1024.0 / tempReading - 1)));
tempK = 1 / (0.001129148 + (0.000234125 + (0.0000000876741 * tempK * tempK)) * tempK); // Temp Kelvin
float tempC = tempK - 273.15; // Convert Kelvin to Celcius
float tempF = (tempC * 9.0) / 5.0 + 32.0; // Convert Celcius to Fahrenheit
/* replaced
float tempVolts = tempReading * 5.0 / 1024.0;
float tempC = (tempVolts - 0.5) * 10.0;
float tempF = tempC * 9.0 / 5.0 + 32.0;
*/
// Display Temperature in C
lcd.setCursor(0, 0);
lcd.print("Temp C ");
// Display Temperature in F
//lcd.print("Temp F ");
lcd.setCursor(6, 0);
// Display Temperature in C
lcd.print(tempC);
lcd.setCursor(0, 1);
lcd.print("@kjunichi");
lcd.setCursor(11, 1);
lcd.print(tempReading);
// Display Temperature in F
//lcd.print(tempF);
//Serial.println(tempC);
//matrix.loadFrame(animation[(cnt+tempReading)%5]);
cnt++;
displayGrid();
delay(100);
}
void printWifiStatus() {
// print the SSID of the network you're attached to:
Serial.print("SSID: ");
Serial.println(WiFi.SSID());
// print your board's IP address:
IPAddress ip = WiFi.localIP();
Serial.print("IP Address: ");
Serial.println(ip);
// print the received signal strength:
long rssi = WiFi.RSSI();
Serial.print("signal strength (RSSI):");
Serial.print(rssi);
Serial.println(" dBm");
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment