京都府舞鶴市、東舞鶴の商店街の大門通り沿い、元舞鶴高専の先生で、PCN舞鶴代表の町田さんによる、プログラミングもできる電子工作&模型屋さん「舞鶴電脳工作室」オープン!(アクセス


こどもから大人まで、ワクワクするお店!店頭の模型や、電子工作見ていると、ちょっと覗いてみたくなりますね。


福井県大野市、元福井高専の先生、前川さんによるPCN大野研究所で採れたイチゴを直送!


電波の先生、前川さん。電波を見るツール「Nano VNA」が良い感じとのこと。 オープンソースな高周波解析機。日本語ユーザーガイドもオープンソースで作成されていました。 コロナ禍、飛行機に電波を当てて反射させての通信実験、旅客機は減っても、貨物は比較的飛んでいるとのこと。人には見えないものが見える力、広めましょう!


真っ赤になった、甘いイチゴ!いつの日かしたい、イチゴ収穫ロボコン。


舞鶴電脳工作室で仕入れた電子部品と大野さんイチゴのコラボ!IchigoJamでMAX7219マトリクスLEDチェーンの制御できました!


風通しの良い店内、ミニ四駆コースがこどもに人気とのこと!IchigoJamを使った計測システムも計画中とのこと!


抵抗、コンデンサ、LED、基本パーツが揃っていてうれしい、電子パーツコーナー。


15 マイコン、と書かれた電子工作用部品コーナーにはIchigoJamも。右下に見慣れない部品を発見!


8x8の赤色マトリクスLEDx4、全部に制御用のIC、MAX7219搭載でデイジーチェーン対応。これで400円は安い!

MAX7219制御のマトリクスLEDx4のIchigoJam制御チャレンジ!

MAX7219/MAX7221データシートをチェック、日本語ドキュメントがありますね。7セグLEDを8コまとめて制御するチップの様子。 4bitで数を指定すると7セグLED用にデコードするモードと、そのままストレートに8bit分出すモードがあります。8桁以上に対応するためにWS2812Bの用にデータを後ろにパスする仕組みがあります。 転送方式は16bitのSPI、FM音源チップYMF825などでやりました。

VCC 5V
GND GND
DIN シリアルデータ入力 - IchigoJamのOUT3
CS チップセレクト - IchigoJamのOUT1
CLK クロック - IchigoJamのOUT2

とIchigoJamと接続して、ひとまずBASICで実験!

500 @SPIW:OUT1,0:FORI=15TO0STEP-1:OUT2,0:OUT3,N>>I&1:OUT2,1:NEXT:OUT1,1:RTN N=12<<8|1:GSB@SPIW

付きました!(SHUTDOWNアドレス12のbit0に1で表示)

SPIはBASICのままだとゆっくりなので、マシン語化して高速化。ライブラリとして整えて、サンプルプログラムと合わせてできあがり!

10 GSB@INIT 20 N=5:GSB@INTENSITY 30 S="0528":GSB@SHOW:WAIT30 40 S=" jig.jg ":FORK=0TO10:GSB@SHOW:WAIT10:S=S+1:NEXT 60 S="17th":GSB@SHOW 70 FORJ=0TO7:N=J&1*9+5:GSB@INTENSITY:WAIT10:NEXT:WAIT30 80 GOTO 20 200 @INIT 210 POKE#700,80,35,27,2,91,28,27,4,1,33,201,3,0,34,8,66,0,208,4,50,154,97,2,50,154,97,73,8,246,209,112,71 220 N=7:GSB@SCANLIMIT:N=1:GSB@DISPLAY:RTN 300 @SHOW:FORJ=0TO7:OUT1,0:A=(J+1)<<8:FORI=0TO3:C=ASC(S+I):N=PEEK(C*8+J):U=USR(#700,A|N):NEXT:OUT1,1:NEXT:RTN 400 @INTENSITY:N=10<<8|N&#F:GSB@CMD:RTN 410 @DISPLAY:N=12<<8|N&1:GSB@CMD:RTN 420 @SCANLIMIT:N=11<<8|N:GSB@CMD:RTN 500 @CMD:OUT1,0:FORI=0TO3:U=USR(#700,N):NEXT:OUT1,1:RTN

300 @SHOW S:display chars 4桁表示 (I,J,A,C,N,Uが破壊される)
400 @INTENSITY N=0-15 輝度設定 (I,Uが破壊される)
410 @DISPLAY N=0/1 表示のON/OFF制御、最初にONにする (I,Uが破壊される)
420 @SCANLIMIT N=0-7 使用する最後の行、今回は7まで8行全部使う (I,Uが破壊される)
500 @CMD cmd send x4 - 16bitのコマンドを4つ分送信 (I,Uが破壊される)


後ろにどんどんつなげることができるので、もっと長くしたり、縦16ドットにしてみたり、高速化するためにループをマシン語化してみるなど、必要に応じて改造しましょう!

今回のプログラムの見どころ、4文字表示する処理300行@SHOWを丁寧に書くと、下記のような2重ループになっています。

300 @SHOW 310 FORJ=0TO7 320 OUT1,0:A=(J+1)<<8 330 FORI=0TO3 340 C=ASC(S+I):N=PEEK(C*8+J) 350 U=USR(#700,A|N) 360 NEXT 370 OUT1,1 380 NEXT 390 RTN

OUT1でCSを0に、4つ分のデータをSPI転送して、CSを1にすることでバケツリレー!

@SPIWのマシン語バージョンはこちら。asm15でアセンブルしてみましょう。

' @SPIW:FORI=15TO0STEP-1:OUT2,0:OUT3,N>>I&1:OUT2,1:NEXT:RTN @SPIW R3=#50 ' R3=#50010000 R3=R3<<8 R3=R3+1 R3=R3<<16 R1=1 R1=R1<<15 @LOOP R2=0 R0&R1 'F=N>>(15-I)&1 IF 0 GOTO @SKIP R2+=4 ' for OUT3 @SKIP [R3+`110]L=R2 ' OUT2,0:OUT3,F R2+=2 ' for OUT2 [R3+`110]L=R2 ' OUT2,1 R1=R1>>1 IF !0 GOTO @LOOP @END RET

OUTポートを変更する場合は、適宜プログラム内の数を変更しましょう(マシン語入門


小学生の頃、敷居の高さにあきらめたプラモデルの塗装。


塗装コーナー、人気とのこと!


美しい、塗装された模型!VRで塗装体験できるもの作ってみるのも入門にいいかも!?

新しい世界への入口「舞鶴電脳工作室&PCN舞鶴」でした!

links
- 舞鶴電脳工作室に子供パソコンIchigoJamの開発者の福野さんがご来店 | Cyber Workshop in Maizuru

JavaScriptの可能性を大きく広げるDeno、現在公式サイトは Next.js フレームワークを使って構築されたオープンソース。

このように、誰でもGitHubからダウンロードやクローンして、自分の環境で動かしてみることができる。

npm i npm run dev

しばらく待って「event - compiled successfully」と出たら、「http://localhost:3000」を開く。そう、DenoのwebサイトはまだNodeで動いている。 Deno x React や、何か新しいフレームワークが誕生するでしょう。


denoland/deno_website2: deno.land website
モダンなwebサイトづくり、Denoのように熱くて若いプロジェクトの公式サイトを参考にするのは生きた学習教材としてオススメです!


Denoのトップページのサンプルコード。インデントが間違っていることが気になって、Issueを書き、プルリクを送ってみたところ、コードは不採用ながら修正は完了。 こうして世界中、みんなで協力して作っていくのがオープンソースのステキなところ。


さばえマスクポスト」(src on GitHub)
日本政府から届くマスク、不要な人の分を回収して寄付するプロジェクトが鯖江でスタート。

こちら Code for Sabae のオープンソース。シンプルなHTMLとCSSのみ。日本語でOK、失敗歓迎、礼儀作法気にしなくてOK。気軽に参加して、世界を動かすビッグプロジェクトへの予行練習にお使いください。

IchigoJamは24KBのOS、ソフトウェアとしての提供。いろんな方がいろんなIchigoJamを作っています。(IchigoJam公式サイトでオープンデータ提供開始!

PCN三重から限定発売されたIchigoJam互換機、KeyIchigoを入手したので、さっそくはんだづけして、起動、LED1!

下記、組み立てレポートです。

KeyIchigo パーツセット!


はんだづけ開始!どうするとミスなくできるか?楽か?速いか?手探りでのスタートが楽しい。
指で押さえつつ、右上1ピンを軽くはんだづけ、そのあと右下をはんだづけして、右上を再度はんだづけ、1列終わったら反対側をまとめてはんだづけして、1列完成!


後半は慣れてサクサク進みます。ひとりタイムアタックするとより楽しい。焦ってミスするとタイムロス! 65コも!?と思うかもしれませんが、65面あるゲームと同じです。しかも、ルールは自分で自由に決められます。


ボタンを指の腹で押す時に痛い、尖ってしまったはんをハンダ吸い取り線で吸い取って、仕上げ。 何を持って完成とするかは自分次第。とことん完成度にこだわるもよし、ひとまず動けばよしとするもよし。


残りのパーツもはんだづけ!


低い部品からぎ基本、ひとまず抵抗のはんだづけ


小型液晶は低いピンソケットとピンヘッダーで接続!


起動しました!
SWITCHコマンドの切り替えなしに、小型液晶に表示される!
謎の答えはキーボード制御用に使っているコンピューターのプログラムにありました。
まあくの工作の部屋: Key-Ichigo


電源に縦一列単4電池ボックスを使用。1.9V〜5VのDCDCコンバーターが入っているとのことなので、単5電池x2本を表に置くとか、CR2032でちょっと動くようにするとか、ソーラーパネルをつけて青空(時のみ)プログラミングとかの改造も良さそうです。

長ピンソケットをつけて下にIchigoJamを合体させようかとも思うので、ピンソケットやビデオ端子は未実装。 自分の使いたいようにいじれるのが、キットのいいところですね!

ハードもソフトも、自分で作ってみるのがおすすめです!

ハード初心者にオススメ、IchigoJam!
IchigoJam はんだづけ、はじめのいっぽ - まちをよくするプログランミング in 品川区 Day2!

先日収録した「ラジオ日本「bravesoft presents 目指せ!ハッカーRADIO」放映日時:2020年5月19日(火)25:00〜」の前半が公開!

COVID-19 JAPAN 新型コロナウイルス対策ダッシュボード」の話。患者数0県が増加中。緊急事態宣言終了後の活動後の動向に注目です。

links
- まあくの工作の部屋: Key-Ichigo
- まあくの工作の部屋: Key Ichigo 2

以前紹介した、5コ950円で買える、安価でIchigoJam BASICだけでも使える超音波センサー「HC-SR04」。 他デバイスとの関係で、どうしてもBTNを使いたいとご要望あり。


できました!IchigoSodaにつないでIoT化していますが、IchigoJam、IchigoDakeでもOKです!

BTNはIchigoJam付属のボタンとSLEEPからの復帰のため外部でプルアップ抵抗をつなげていて、ANA(0)としてアナログ入力としても使えます。 つまり、CPU内部の設定としてはアナログになっているので前回紹介したマシン語で読み出そうとしてもうまくいきません。


BTNを割り当てているPIO1_4、LPC1114のデータシートの IOCON_PIO1_4 (アドレス#40044094) を見ると設定方法が書いてあります。 一度、マシン語を使ってどういう設定になっているか読み出してみましょう。

R0=[@IOCON_PIO1_4]L R0=[R0]L RET @IOCON_PIO1_4 DATA L #40044094

asm15でアセンブルして、読みだした値を8桁の2進法で表示

POKE#700,1,72,0,104,112,71,0,0,148,64,4,64 OK ?BIN$(USR(#700,0),8) 01000001

2:0 つまり最下位の0bit目から2bit目の3bitを使ったFUNCは1、次の2bitのMODEは0(プルアップなどなし)、次の1bitのHYSは0(無効)、6bit目はReservedとして予約されていて1を設定することになっていて、7bit目ADMODEが0でアナログ入力モードとなっています。

これをADMODE:デジタル入力+FUNC:PIO1_4と、`11000000 に一時的に変更する作戦でいきます。前回のカウントプログラムの前後にこの設定を足します。

PIO1のベースアドレスは #50010000、BTNは、PIO1_4の場所なので
?"#5001";HEX$(1<<(4+2),4) → #50010040 を@INに設定します。

'BTN(PIO1_4) <- digital R1=`11000000 R3=[@IOCON_PIO1_4]L [R3]L=R1 'count check R0=0 R1=[@IN]L @LOOP R2=[R1]L R0=R0+1 R2-0 IF !0 GOTO @LOOP R0=R0>>9 'BTN(PIO1_4) <- analog R1=`01000001 [R3]L=R1 RET @IOCON_PIO1_4 DATA L #40044094 @IN DATA L #50010040 'BTN=PIO1_4

アセンブルして、BASICのプログラムと組み合わせて、できあがり!

10 POKE#700,192,33,6,75,25,96,0,32,5,73,10,104,64,28,0,42,251,209,64,10,65,33,25,96,112,71,0,0,148,64,4,64,64,0,1,80 20 OUT1,1:OUT1,0:?USR(#700,0) 30 WAIT 5:GOTO 20

マシン語でカウントした値、R0をBASICに返す前に9ビット右シフト、つまり512分の1にしています。マシン語のカウントだと速すぎて大きな値になってしまうからですが、ここをいじると精度アップが見込めます。 ただ、IchigoJamでは1秒間に1.5万回くらい画面表示用の割り込みが発生するので、高い精度で計測するには割り込みを一時的に止める必要があります。

CPSID R0=0 R1=[@IN]L @LOOP R2=[R1]L R0=R0+1 R2-0 IF !0 GOTO @LOOP R0=R0>>5 CPSIE RET @IN DATA L #50001000 'IN1=PIO0_10

割り込みの一時停止は CPSID、最下位は CPSIE です。戻し忘れると何も操作できなくなってしまいます。下記、CPSIDした後リターンする危険なプログラム、SAVEした後、お試しください。

LET[0],#B672,#4770:?USR(#800,0)

完成した、超音波センサー、TrigをIN1に接続し、精度16倍バージョンがこちら!

10 POKE#700,114,182,0,32,3,73,10,104,64,28,0,42,251,209,64,9,98,182,112,71,0,16,0,80 20 OUT1,1:OUT1,0:A=USR(#700,0):?A 25 LED A<300 30 WAIT 5:GOTO 20

一定距離から近づくとLEDがついてお知らせ、リレー経由でスゴイ照明と組み合わせると防犯ライトにもなりますね!

5 B=0 26 IF B=0 AND A<300 B=1:N=N+1:IOT.OUT N:?"IOT!";N:WAIT30 27 IF B=1 AND A>=300 B=0

IchigoSodaを使って通ったらIOT.OUTでカウントを送るように改造も簡単です!
福井県で始まった「混雑状況オープンデータ」との連携も便利そう。


Let's IoT with IchigoJam x various sensors!

links
- 200円 超音波距離センサー HC-SR04 を IchigoJam で使う方法 - Armマシン語で時間を測ろう
- 今週末は越前がにロボコン! IchigoJamで超音波センサーをIN1とは違うポートで使う方法 BASIC編 マシン語編

お気に入りのDeno(ディーノ)、WebSocketを使ったチャットづくりなど、いい感じですが、Nodeで作った既存プロジェクトとの並行はしばらく続きます。 そこで、DenoとNodeに両対応する方法を整理するのを兼ねて、世界で2番目に古いというプログラミング言語、LISPのS式っぽいものを作ってみました。

const n = S.eval([ S.PLUS, 1, [ S.MUL, 2, 3 ] ])

LISPの特徴はツリー構造(LISPでは、S式という)をそのままプログラムとして使うところ。上記、JavaScriptの配列で表現したS式を評価をするサンプルです。


minimum S, src on GitHub
プログラムはとってもシンプル。四則演算とIF文しかありません。興味があれば,forkして、いろいろ機能を追加するなどして遊んでみてください。 (import.metaとglobalThis.processを使い、Deno/Nodeでの直接起動時に説明表示)

ブラウザ上や、Denoでは、import文を使って、簡単に組み込めます(Nodeの場合ダウンロードしてファイルとして使用)

import S from 'https://taisukef.github.io/minimum_S/S.mjs' console.log('S.eval([S.PLUS, 1, 2]) is ' + S.eval([S.PLUS, 1, 2]))

deno test で簡単テストな S_test.ts が走ります。TypeScriptが基本のDenoはテストコードの拡張子はtsとします。 TypeScriptはJavaScriptの上位互換のプログラミング言語なので、拡張子を変えるだけでOKです。

Denoに刺激されてか、Node.jsも試験的実装ながら関数外でも await が使えるように!

const sleep = msec => new Promise(resolve => setTimeout(resolve, msec)) await sleep(3000)

指定された数分ミリ秒待つ関数 sleep を定義して、3000 = 3秒待つ。Nodeで普通に動かそうとすると「SyntaxError: Unexpected reserved word」とエラーになりますが、Node v14.3.0 で下記のように指定すれば、deno同様、動きます。 ただし、deno/node共に対話型アプリ上や、ブラウザ上では引き続き使えないので注意!(src on GitHub)

node --experimental-top-level-await sleep_test.mjs

Denoでの場合

deno run test.mjs

JavaScriptなど、最近のプログラミング言語には便利表記方法がいろいろ増えているので、少しずつ使える幅を増やすと楽できます。 例えば、=> は、関数定義のちょっと変わった書き方、reduceは配列の中身全部に対して処理して一つの値をだすものです。

sleepは、下記のようにも書けます。お好みでどうぞ!(thisを使う時は => と function で挙動が違うので注意)

async function sleep (msec) { return new Promise(function (resolve, reject) { setTimeout(resolve, msec) }) }

Deno情報を調べると気になる、汁なし担々麺「DENO」(こちらの読みは、での)

ファミマで販売中とのことで、こちらも試食!もっちりした麺が良い感じでした!札幌発、行くことがあればぜひ実店舗も巡礼したいところ。(東京、新潟、福島にもあった!)

links
- DenoとWebScoketで作る匿名チャットサーバー&webアプリ

Javaで作ったサーバーサイドのプログラム、少しずつリファインしつつDenoへ移行していきます。 まずはジェネラルにチャットサーバー。WebSocketベースで軽量実装!

AnonymousChat in deno」(src on GitHub)
部屋を作ってリアルタイムにやりとりできるだけのシンプルな匿名チャット。SSL化に別途調査が必要なので、テスト的に立ち上げています。

部屋があって、ユーザー管理する、オーソドックスなサーバー設計にしつつ、シンプルに匿名チャットとして作ったもの。「thecodeholic/deno-websocket-chat: Realtime Chat App with Deno and WebSockets」が参考になりました。Node.js風fsを使ったwebサーバーを除いて200行ほど。(server.mjs for Deno)

import { listenAndServe } from 'https://deno.land/std/http/server.ts' import { acceptWebSocket, acceptable, isWebSocketCloseEvent } from 'https://deno.land/std/ws/mod.ts' import { v4 } from 'https://deno.land/std/uuid/mod.ts' import { serveWeb } from 'https://taisukef.github.io/denolib/webserver.mjs' import dotenv from 'https://taisukef.github.io/denolib/dotenv.mjs' dotenv.config() const PORT = parseInt(Deno.env.get('PORT')) || 3000 class House { constructor () { this.rooms = new Map() this.users = new Map() } async serve (port) { listenAndServe({ port }, async req => { if (req.method === 'GET' && req.url === '/ws') { if (acceptable(req)) { const wsreq = { conn: req.conn, bufReader: req.r, bufWriter: req.w, headers: req.headers } const wsock = await acceptWebSocket(wsreq) await this.accept(wsock) } } else { serveWeb(req) } }) console.log(`started on port ${PORT}`) } async accept (ws) { let user = null for await (const data of ws) { if (isWebSocketCloseEvent(data)) { // code: 1001 break } const event = JSON.parse(data) const e = event.event if (e === 'login') { user = this.users.get(event.id) if (user) { if (user.passcode !== event.passcode) { await ws.send(JSON.stringify({ event: 'error', data: 'please login' })) } else { user.attachWebSocket(ws) } } if (!user) { user = new User(ws, this.getValidName(event.name)) this.users.set(user.id, user) } user.sendOne(ws, user.getData()) } else if (user === null) { await ws.send(JSON.stringify({ event: 'error', data: 'please login' })) } else if (e === 'create') { let room = this.rooms.get(event.room) if (room) { await user.sendOne(ws, { event: 'error', data: 'already exists' }) continue } room = new Room(event.room, user) this.rooms.set(event.room, room) user.send(room.getData()) } else if (e === 'enter') { const room = await this.getRoom(user, event.room) if (!room) { continue } if (room.users.indexOf(user) < 0) { room.users.push(user) const rep = { event: 'enter', data: { id: user.id, name: user.name } } room.users.forEach(u => u.send(rep)) } user.sendOne(ws, room.getData()) } else if (e === 'leave') { const room = await this.getRoom(user, event.room) if (!room) { continue } const n = room.users.indexOf(user) if (n < 0) { await user.sendOne(ws, { event: 'error', data: 'not member' }) continue } const rep = { event: 'leave', data: { id: user.id, name: user.name } } room.users.forEach(u => u.send(rep)) room.users.splice(n, 1) } else if (e === 'message') { const room = await this.getRoom(user, event.room) if (!room) { continue } if (room.users.indexOf(user) < 0) { await user.sendOne(ws, { event: 'error', data: 'not member' }) continue } // special command if (event.data.text === '/clearall') { room.messages = [] return } const message = { fromid: user.id, name: user.name, data: event.data } // console.log(room, room.messages) room.messages.push(message) const e = { event: 'message', data: { room: room.name, message } } room.users.forEach(u => u.send(e)) } else { await user.sendOne(ws, { event: 'error', data: 'unknown event' }) } } } async getRoom (user, rname) { const room = this.rooms.get(rname) if (!room) { await user.send({ event: 'error', data: 'not found ' + rname }) return null } return room } getValidName (name) { if (name == null) { name = '' } name = name.toString().trim() if (name.length === 0) { name = 'no name' } for (;;) { let flg = false this.users.forEach(v => { flg = flg || v.name === name }) if (!flg) { break } name += '\'' } return name } } class Room { constructor (name, owner) { this.id = v4.generate() this.name = name this.owner = owner this.users = [owner] this.messages = [] } getData () { return { event: 'room', data: { id: this.id, room: this.name, users: this.users.map(u => { return { id: u.id, name: u.name } }), messages: this.messages } } } } class User { constructor (ws, name) { this.ws = [ws] this.name = name this.id = v4.generate() this.passcode = v4.generate() this.rooms = [] } async sendOne (ws, json) { try { ws.send(JSON.stringify(json)) } catch (e) { } } async send (json) { let remflg = false for (let i = 0; i < this.ws.length; i++) { try { this.ws[i].send(JSON.stringify(json)) } catch (e) { this.ws[i] = null remflg = true // console.log('send', e) } } if (remflg) { this.ws = this.ws.filter(w => w) } } attachWebSocket (ws) { this.ws.push(ws) } getData () { return { event: 'user', data: { id: this.id, passcode: this.passcode, name: this.name, rooms: this.rooms.map(r => r.name) } } } } const house = new House() house.serve(PORT)

コミュニケーションツールも、ネットワークゲームもベースは一緒!

dotenv, fs, webserver など、Denoに使うちょっとしたライブラリは「taisukef/denolib」こちらでまとめて管理していきます。

さくらインターネットの田中さんによるDX化を3ステップに向ける「アナログからデジタル論」。 そもそもアナログとデジタルの切り分けも意外と難しい。アナログ時計、秒針はスムーズに動いてほしい派ですか?1秒置きに刻んでほしい派ですか?

小学生にとって最初の難関、アナログ時計。ややこしい理由は丸いアナログ表現から、デジタル量を要求されること。 時針と分針はアナログなのに、秒針はデジタルだったりする統一感のなさも気持ち悪い。

水晶と歯車という制約がないアプリなので、いっそ、デジタルに統一して読みやすくしたのがこちら「読みやすい時計 - JIGAKU」(自学サポートアプリ JIGAKUシリーズ

読みやすい時計 - JIGAKU
8時55分、普通のアナログ時計の場合、時針はほぼ9時を指しているのに、8時と読み取ることを要求される。読みやすい時計では、時針もデジタルなので、正確に8を指す。


読みやすい時計 - JIGAKU
タップすると普通のアナログ時計との切り替えできる。切り替えるとスケールを10倍細かくし、ミリ秒表示もいれて、時間の連続性を表現。

もうひとつネタ元、Twitterで見かけた、おもしろ時計。

一生付き合う、時間と時計。自分だけの時計づくりもオススメしたい。
スマートウォッチで動かしたい、秒針が主役の時計「ズームクロック」
ひさびさに見てみたら、動きがどうも悪いので、現代風への作り直しが必要そう。合わせて、現代のスマートウォッチ事情も調べてみたい。

links
- 自学サポートアプリ JIGAKUシリーズ

JavaScriptでサーバーサイドもサクサク書けて便利な Node.js。 jsからmjsへ移行したもののブラウザ上のコードとの互換性が無いことにと、プロジェクトごとに増える node_modules が気になっていたところ、Node.jsの作者 Ryan Dahl 氏自身による Deno を発見。 いい感じだったので「PUSHかんたんオープンデータ」を移行してみました。


福井県施設 オープンデータ - PUSHかんたんオープンデータ」(src on GitHub)
バックエンドのエンジン変更なので、見た目は変わりません。 それでは寂しいので、複数の施設をひとまとめにする「集約オープンデータ」に対応! 複数の施設や店舗をひとまとめにしたオープンデータリンクを自由に作成できます。追加、削除、順番変更も思いのまま!


福井県、県有施設等の混雑状況をオープンデータとして公開:民間有志が同データを利用して混雑状況の一覧をスマートフォン等からも閲覧可能なダッシュボードを作成し公開 | カレントアウェアネス・ポータル
国立国会図書館さん、中日新聞さんにご紹介いただきました!オープンデータで切り拓く、ライトな官民連携の仕組み。ぜひ他の地域でもどうぞ!
県有施設の混雑状況をオープンデータに 出発前に確認、スマホでOK:福井:中日新聞(CHUNICHI Web)


Deno
恐竜アイコンがかわいい、Deno(ディーノ)は、Node.js作者が反省を踏まえて開発した、webフレンドリーなもうひとつのJavaScriptバックエンドエンジンです。ブラウザとの互換性の高さと、package.json不要で、URLでimportし、適宜キャッシュしてくれるパッケージ管理システムが特徴です。 (Denoの登場でNode.jsの時代は終わるのか? - Qiita

Node.js 用プログラムからの移行、ファイルアクセスの標準モジュール fs を必要なものだけ独自に用意。(node_fs.mjs on GitHub)

const fs = {} fs.readFileSync = function (fn) { const data = Deno.readFileSync(fn) const decoder = new TextDecoder('utf-8') const s = decoder.decode(data) return s } fs.writeFileSync = function (fn, s) { const d = new TextEncoder('utf-8').encode(s) Deno.writeFileSync(fn, d) } fs.appendFileSync = function (fn, s) { const d = new TextEncoder('utf-8').encode(s) Deno.writeFileSync(fn, d, { append: true }) } fs.readdirSync = function (dirn) { return Deno.readDirSync(dirn) } fs.mkdirSync = function (dirn) { return Deno.mkdirSync(dirn) } export default fs

あとは、expressからDenoのhttpに移植して、完了!(push_deno.mjs on GitHub)

セットアップに npm install はもういりません!下記の起動コマンドで即実行!(ファイルアクセスやネットワークアクセスを許可する -A オプションが必要です)

deno run -A push_deno.mjs

mjs x Deno の組み合わせで作ってみることにします!

初心者にはオススメできないC言語ですが、多くの高専の授業で登場するC言語

#include <stdio.h> int main() { printf("Hello World!\n"); return 0; }

このC言語のプログラムを実行すると

Hello World!

と出ます。これで感激できるのはC言語を作った人と、環境構築に苦労した人くらい。大抵の人は「で?」と思うだけでしょう。 なぜ # で始まる? <stdio.h> はHTMLのタグとは違う? studio のつづり違い?など1行目から分からないことだらけです。

こちら、その謎に本質から迫るため開発した、x64版の超シンプルマシン語標準入出力ライブラリ stdio.asm を Windows 10で動かした様子。Mac/Linux/FreeBSDでも同様に動きます。

今日の記事はC言語を少しやったけど、なんだかスッキリしない人、現代PCの主力CPU、Intel/AMDのx86系x64マシン語を使ったOSの深い話が気になる人向けです。 まずは楽しくプログラミングでゲームを作ってみたい人や、マシン語の基本は、シンプル&コンパクトなパソコン、IchigoJamからスタートするのがオススメです。(IchigoJam入門動画はじめてのマシン語

C言語プログラミング、本当のはじめのいっぽはこちらです。

int main() { return 1 + 1; }

これを test1.c と保存し、コンパイルし、実行し、実行結果を表示すると(for macOS/Linux)

gcc test1.c ./a.out echo $? 2

1 + 1 という人間らしい言葉で、コンピューターに計算させることに成功!

細かく解説すると・・・。 こちら、整数(int)を返すmainと名付けた関数(数学の関数と似たもの)を作り、中身に「1 + 1」を返して(return)と記述したC言語のプログラムです。 mainという名前は特別で、プログラム起動時に最初に呼び出されます。 「1 + 1 」という人にわかりやすい言葉を、コンピューターが分かる言葉、マシン語へ変換してくれるのがC言語のコンパイラというツールです。 gccというコンパイラは、特に何も指定しないと a.out という実行ファイルができます。それを、実行。 プログラムが実行した結果をみるコマンド(echo $?)を使って、コンピューターが計算した結果「2」を得ることができた。というわけです。

ゲームのキャラクターを表示したい、コントローラー入力を使いたい、音を慣らしたい、いろいろ欲が出てきます。 そこで登場するのがライブラリ。コンピューターの仕様を隅から隅まで調べなくても、誰かが作ってくれた便利な部品を使うことで楽できます!

そんなライブラリの代表格が stdio.h(スタンダードI/Oの略) で定義されている標準ライブラリというものです。 基本的な文字の表示(output)と入力(input)のための関数が揃っています。 冒頭に登場した、printfという関数もそのひとつ。

int main() { printf("hello!\n"); return 0; }

上記のようにプログラムを変更してコンパイルすると、printfって何?とエラーになります。

printfを事前に定義する必要があります。stdio.h というファイルに定義があります。#include は指定したファイルを埋め込んでくれます。 ファイル stdio.h はどこにあるのでしょう?コンパイラが含めるために使うディレクトリが決まっていてその中のを使ってというのが、「<」と「>」で囲う意味でした。 その場にある自分で作ったファイルを含めるときは、ダブルクォートで囲みます。 HTML,CSS,BASIC,C,JavaScript,Pythonなど、コンピューター言語毎に、記号の意味は変わります。

文字の表示やサウンド出力などの手順は、Windows/macOS/LinuxなどのOS毎に違います。 C言語のコンパイラはCPUの違いを吸収してマシン語を生成してくれますが、手順の違いを吸収するのはライブラリの役目。

例えば、Macで文字を出力するには、レジスタrsiに出力したい文字列の先頭アドレスを、レジスタrdxに長さを、rdiに1を、raxに0x2000004をそれぞれ設定して、システムコール(syscall)を呼ぶことで、OSが文字を表示してくれます。(stdio_mac64.asm src on GitHub、cmd: nasm -f macho64 hello.asm -DMAC64; ld -lSystem hello.o -o hello )

mov rdi, 1 ; fd = stdout mov rax, 0x2000004 ; syscall write syscall

CentOS, Ubuntu, Debian, OpenSuSE, Arch Lniux, Fedoraなど、多くのLinuxではレジスタraxに設定するシステムコール番号を変えるだけでOKです。(stdio_linux64.asm src on GitHub、cmd: nasm -f elf64 hello.asm -DLINUX64; ld -e _main hello.o -o hello )

mov rdi, 1 ; fd = stdout mov rax, 1 ; syscall write syscall

FreeBSDでは他のLinuxと異なります。macOSはBSD系の子孫、この値に 0x2000000 数を足したものです。(stdio_bsd64.asm src on GitHub、cmd: nasm -f elf64 hello.asm -DBSD64; ld -m elf_x86_64_fbsd -e _main hello.o -o hello )

mov rdi, 1 ; fd = stdout mov rax, 4 ; syscall write syscall

Windowsでは直接システムコールを呼んではいけないことになっていて、dll(ダイナミックリンクライブラリ)を経由しての呼び出しとなります。stdio_stdout の初期化が必要で、レジスタの使い方や、スタックの使い方も違います。(stdio_win64.asm src on GitHub、cmd: nasm.exe -fwin64 hello.asm -DWIN64& link.exe /entry:_main /subsystem:console hello.obj kernel32.lib )

mov r8, rdx ; len mov rdx, rsi ; buffer mov rcx, [rel stdio_stdout] mov r9, stdio_bytesWritten push qword 0 call WriteFile

このようにOSによってそれぞれ使い方は異なりますが、名前と使い方に揃えれば、以後気にしなくてよくなります。stdio.asm で、環境によって使うライブラリを切り替えるようにしておきます。

%ifdef WIN64 %include "stdio_win64.asm" %elifdef MAC64 %include "stdio_mac64.asm" %elifdef LINUX64 %include "stdio_linux64.asm" %elifdef BSD64 %include "stdio_bsd64.asm" %endif

こうして準備をしておき、stdio.asm を include すれば、どのOSでも動くマシン語でプログラム「Hello World!」が、このようにシンプルに書けます。NASMでのファイルへの埋め込みのincludeは#ではなく%。 いろんな環境での動作確認はConoHaのVPSを使うと1環境1時間1円〜と、とても手軽です。

%include "stdio.asm" global _main section .rodata MESSAGE db "Hello World!", 0x0d, 0x0a LEN_MESSAGE equ $-MESSAGE section .text _main: call stdio_init mov rsi, MESSAGE mov rdx, LEN_MESSAGE call stdio_write mov rdi, 0 call stdio_exit ret

開発効率、速度、汎用性の向上や、特殊な用途への特化するためなど、さまざまなプログラミング言語が誕生し、使われたり、廃れたりしていますが、結局動いているのはこれらマシン語です。 基本を抑えておけば、余計な手間をかけることなく、楽しく楽に開発できてますますプログラミングが楽しくなります。

理解を深めるには、実際にやってみるのが一番です!Windows/Mac/Linux/FreeBSD、それぞれ環境に合わせた c-*.sh/bat、c-*-test.sh/bat を使って、実際に動かしてみましょう。(src on GitHub

開発に必要なツールを設定しましょう。Windowsでは「Visual Studio C++ 2019 コミュニティ」、Macでは「Xcode」がそれぞれ無料で提供されています。 アセンブリ言語をマシン語化してくれるツール、アセンブラ「NASM」もオープンソース、無料です。

Visual Studio C++ 2019 コミュニティ、右側赤枠で囲んだ2つ、ビルドツールとSDKがあれば、ひとまず今回の開発は可能です。セットアップ後、コマンドプロンプトで hello-x64asm のディレクトへ移動し init-win.bat を動かし、開発ツールとNASMにPATHを通して、レッツトライ!

stdio.asm は、stdio.h が持つ機能の極一部。自分なりのライブラリや、プログラミング言語づくりにチャレンジするのもおもしろいですよ!

links
- taisukef/hello-x64asm: the first step of x64 64bit assembly programming on Windows/macOS/Linux
- C言語開発者「C言語は初心者にはお勧めできない」 エントリーにオススメBASICは、世界初のクラウド対応言語だった! IoTで起業家甲子園目指す、長岡高専チームメンタリング
- プログラミング言語は何から学ぶべきか? ロボットプログラミングゲームをIchigoJamでプログラミング! C言語の教科書「Springs of C」より
- 高専でなぜC言語を学ぶのか? IchigoJamマシン語生成プログラム c4ij で作る、C言語版かわくだり
- IchigoJamからのステップアップ - IchigoJam BASIC / Python3 / JavaScript / Java / C言語 対照表
- ハンドアセンブルで高速計算! RISC-V、RV32ICエミュレーターのC言語実装
- マシン語対応 IchigoJam web、気軽にハンドアセンブルして遊べます!
- OpenCL/C言語 GPUプログラミングはじめのいっぽ on Mac
- わずか16KB! WebAssemblyで動くミニC言語オフラインコンパイラ&インタプリタ webci0
- 深いプログラミング言語学習に最適! 512行のC言語コンパイラ ci0 を使ってみました
- 地味なC言語がなぜ楽しいのか?

混雑を避ける、コロナ禍では平時以上に重要です。福井県統計情報課とCode for Fukui / Sabae 連携で、福井県施設ダッシュボードに混雑状況表示が加わり、運用開始

福井県施設ダッシュボード」(src on GitHub)
定休日や、臨時休館日などを反映して、開いているかどうか、空いているかどうかがひと目で分かります。CSV/JSONオープンデータを使った応用例です。 デザインや、使い勝手、データを収集しての解析など、自由に二次利用が可能です。もちろんこのアプリもオープンソース、改造提案、改造版立ち上げも大歓迎!


福井県施設状況オープンデータ
CSVやJSONでダウンロードし、自由に活用可能です。


PUSH かんたんオープンデータ」(src on GitHub)
Code for Fukui / Sabae で開発した、データを更新する仕組みはこちら。Googleスプレッドシートによる更新をもっとシンプルにしたイメージです。スマホで簡単に、混雑状況を伝えられます。 急な休業日、営業時間変更も簡単!


教育博物館 オープンデータ
個別のページも自動的にでき、CSV/JSONオープンデータへのリンクがあって、人にも機械にも優しい。


教育博物館 オープンデータ
プログラマー大好き、JSON形式!


エイトセンス オープンデータ
ランチなどでお世話になっている鯖江のカフェ、EIGHT SENSE(エイトンセンス)さんにも使ってみてもらいました。行政施設のみならず、幅広く使っていきたいところ。


県有施設等の混雑情報をオープンデータ化します | 福井県ホームページ
行政と民間、オープンデータでどんどんつないでいきましょう!


日本政府による民間とすすめるコロナ対策「指標をCSVオープンデータに! by 福野泰介さん | 新型コロナウイルスと戦う意見募集サイト VS COVID-19アイディアボックス」が、人気です!

Tweet
クリエイティブ・コモンズ・ライセンス
この作品は「Creative Commons — CC BY 4.0」の下に提供されています。
CC BY / @taisukef / アイコン画像 / プロフィール画像 / RSS