Accessが複数開かれている時にGetObject()する方法
はじめに
- 具体的には,CreateObject()やGetObject()といった関数で,各ソフトのApplicationオブジェクトに相当する参照を取得でき,例えば,ExcelからAccessにクエリを投げて,得られた結果をワークシートに転送する,といったマクロを作成可能である.
- いや,MSDN*2は最初の引数に使いたいファイルパスを指定すれば選択できそうな雰囲気ではあるが,試してみたところ,新しいインスタンスが開かれ,取得された参照が破棄されると同時にインスタンスも閉じられた.うまくやる方法があるのかもしれないが,ここでは操作するインスタンスを指定できないとしよう.
- そこで,ウィンドウタイトルから開いているファイルを推測し,そのウィンドウのハンドルを基にしてAccessibleObjectFromWindow()関数を呼び出し,目的のインスタンスの参照をつかむ方法が,首尾良く行きそうなので報告する.
AccessibleObjectFromWindow()関数
こいつでウィンドウハンドルから,インスタンスの参照を得られる.VBAでは引数の扱いに注意が必要な点がある.
- 第2引数は取得したいオブジェクトのIDを渡す.Office系の参照が欲しい場合はOBJID_NATIVEOMを指定する.
- 第3引数の REFIID riid はGUID渡すべきであるが,VBAのGUIDを指定すると怒られる.Declareな関数では使えないらしい?ので,同等の構造体をユーザー定義する.Office系の参照を得るためには,IDispatchに相当するGUIDを渡す.
Accessが複数開かれている場合に参照を取得する例
- Accessが複数開かれている場合を例にした実装を張る.
- Main()からEnumWindows()を呼び出し,目的のインスタンス("tesuto.accdb"なるファイルを開いたAccessインスタンス)が存在したら,フォーム"hoge"を開く.
- EnumWindows()のコールバック関数では,ウィンドウタイトルを調べ,目的のファイルを開いていそうだったら,Accessインスタンスの参照の取得を試みる.
Option Explicit Public AccessWndHandle As Long Public AccessApplication As Object Private Const OBJID_NATIVEOM = &HFFFFFFF0 Private Declare Function GetWindowText Lib "User32" _ Alias "GetWindowTextA" _ (ByVal Hwnd As Long, ByVal lpString As String, ByVal cch As Long) As Long Private Declare Function AccessibleObjectFromWindow Lib "oleacc" _ (ByVal Hwnd As Long, ByVal dwId As Long, _ ByRef riid As UUID, ByRef ppvObject As Object) As Long Private Declare Function EnumWindows Lib "User32" (ByVal lpEnumFunc As Long, ByVal lParam As Long) As Long Private Type UUID Data1 As Long Data2 As Integer Data3 As Integer Data4(7) As Byte End Type Public Function EnumWindowsCallBackFunc(ByVal Hwnd As Long, ByVal lParam As Long) As Boolean Dim title As String * 256 If False = GetWindowText(Hwnd, title, Len(title)) Then GoTo Continue End If If InStr(title, "tesuto") > 0 And InStr(title, "Access") > 0 Then Dim IID_IDispatch As UUID With IID_IDispatch .Data1 = &H20400 .Data4(0) = &HC0 .Data4(7) = &H46 End With If 0 <> AccessibleObjectFromWindow(Hwnd, OBJID_NATIVEOM, IID_IDispatch, AccessApplication) Then GoTo Continue End If AccessWndHandle = Hwnd EnumWindowsCallBackFunc = False Exit Function End If Continue: EnumWindowsCallBackFunc = True Exit Function End Function Public Sub Main() AccessWndHandle = 0 Call EnumWindows(AddressOf EnumWindowsCallBackFunc, 0) If AccessWndHandle = 0 Then Exit Sub End If AccessApplication.DoCmd.OpenForm "hoge" End Sub
参考
http://www.lw-tech.com/q1/base.htm
GDIplusCODE
Excel VBA - Get an Excel instance from the window handle
Twitterのロリコン人工無能Bot @jsfavo について
@jsfavoとは
JSこれくたー,Twitterを監視する淫らなbot君です.
くんかくんかしながら演技して金をつぎ込みました✌(๑╹◡╹๑)
— JS・これくたー (@jsfavo) 2016, 1月 31
・@sosoruと@jsfavoのHomeTLを見て,指定されたキーワードが入ってるとふぁぼる
・30分おき(朝7時~9時は10分おき)に何かをツイート.深夜帯はお休み
・リプライを送ると何か返してくる
ふぁぼ機能
- @sosoruと@jsfavoのHomeタイムラインを常に監視しています.指定されたキーワード,もしくは,キーワードの類似語が含まれていたらふぁぼります.
- UserStreamを使って監視していて,見つけたらすぐにふぁぼる仕様でしたが,何処からか圧力が掛かったので,いくらかの遅延を持たせてふぁぼらせています.
🔺こんな感じ.(TriggeredFilterが反応した単語)
🔺類似語の場合はこんな感じ
ツイート機能
- 予め登録されたキーワードを元に何か文章を作成します.文章の素は@sosoruの過去のHomeTLを使っています.
ロリに中出し"のレシピ
— JS・これくたー (@jsfavo) 2016, 1月 31
- 4語のマルコフ連鎖で幾つか文章を作成していますが,そのままだと「パクツイ」になりやすいので,名詞などを類似語にランダムで置き換えています.
- リプライを送ると,そのツイートを基に何か文章を作成して返してきます.
@sosoru テンプレパターンだよねよく考えるとコミケ勢が爆死してるちのちゃんとティッピー
— JS・これくたー (@jsfavo) 2016, 1月 31
🔺テンプレに反応して返してくれる
- 深夜帯の1時30分~6時前まではツイートしません.裏でデータベースのメンテナンスをしています.リプライ機能は生きているので,何かしら返してくれるかもしれませんが,メンテナンスの都合で返せない場合があります.
— JS・これくたー (@jsfavo) 2016, 1月 31
🔺返してくれないときもある,「わかんないよぉ」って言うときもある
リプライについて
- 空リプを送ると何のツイートに反応したか返してくれます.
@sosoru 最後に反応したツイートはこれだよっ!おにぃちゃん☆ (trigger : **Analogy: ココア from リゼ) https://t.co/XWhC4g0C9H
— JS・これくたー (@jsfavo) 2016, 1月 31
- 何か文章を送ると,反応する単語が含まれているか教えてくれます.同時に何か喋りかけてきます.
@jshiace へ,へんたいっ!! (trigger words: 変態)
— JS・これくたー (@jsfavo) 2016, 1月 31
- 文章に「詳細」が含まれていると,さらに詳しい情報を教えてくれます.triggered filterは内部で使っている正規表現です.
@sosoru へ,へんたいっ!! (trigger words: ゆのっち) (trigger filters: (^|[^ぁ-ん])ゆの(っち|さん|ちゃん|たん|たそ|くん|きゅん|[^ぁ-ん]|$)
— JS・これくたー (@jsfavo) 2016, 1月 31
- この他にも,リプライに対して定型文を返すような設定が幾つか入っています.探してみてください.
しくみ
- bot自体はC#で書かれていて,辞書学習等々のファイル操作でRubyをちょっと使っています.
- C#のCoreTweetでTwiterAPIを弄りつつ,SQLServerに得たツイートを垂れ流しています.文章の形態素解析にはMeCabを使っていて,辞書には「はてなキーワード」を主に使っています.(C#側のライブラリはLibNMeCab)
- 類似語の列挙にはword2vecを使っています.@sosoruのHomeTLをMeCabでわかち書きしたものを学習させています.(C#側のライブラリはWord2Vec.Net)
類似語について
- word2vecを使えば単語の意味ベクトルが得られるので,2つの単語ベクトルの内積を取れば,どれだけ類似しているかが数値化できます.(これをコサイン類似度と呼ぶ?)
- 類似語とは文脈で使われやすい単語を指しているようで,同義語と反義語の区別はないようです.
🔺類似度の高い単語を列挙した場合,それっぽい単語がサジェストされる
🔺類似語に同義語と反義語の区別はない?
🔺ペアだと高い類似度を持つ?
文章生成について
- @sosoruのHomeTLを基に4語のマルコフ連鎖で文章を作っています.2016年1月の時点で,過去1年程度のTL,300~400万ツイートがデータベースに溜まっています.
- リプライ等々で文章生成のリクエストを受け取ると30文程度の文章を生成します.生成された文章の中から,比較的短文で,基となった単語や文章と類似したものをランダムで選び出します.基の単語と文章の類似度を測るときにも,word2vecで出した単語の意味のベクトルを利用しています.
- 単語の意味ベクトルはword2vecが吐きだした数値を用いれば良いですが,文章の場合には,使われている名詞・形容詞などを抜き出し,その単語の意味ベクトルを足し合わせて正規化したものを,文章の意味ベクトルとして扱っています.
- 意味ベクトルとして考慮する単語が多くなるほど,基の単語・文章との類似度が低下するので,単語数を考慮してランダムで選び出します.
- 生成された文章と基になった文章の類似度が高い場合,幾つかの単語を類似語で置き換えています.botにたまによくある奇想天外な文章の類似度は,感覚的にあまり高くないようなので,わざと落とすことにしています.
🔺考慮する品詞,代名詞や接尾語は見ない
🔺「ゆのっち」を与えたときに生成された文.表示されているのは名詞や形容詞の数が2~10程度の文章.名詞・形容詞などの単語数,基の単語との類似度,生成された文章の順に表示.
Nゲージ鉄道模型のATS・ATC案③-LEDモジュール
この記事は過去に作ったNゲージ鉄道模型のATCシステムについて記述しています.
システム全体については下の過去記事を参照してください.
LEDモジュール
LEDの制御もユーザーの端末で出来るようにしていました.ATCの動作に直接の関係はありません.当時は駅ホームの照明に使っていました.(本当は信号に使うべきかもしれない)
ハードウェアについて
Dフリップフロップ(D-FF)とバッファを組み合わせた(恐らく)ポピュラーな回路構成です.D-FFはクロック入力CLKが立ち上がった時,入力Dの状態が出力Qに保存され,次にCLKに変化あるまで,出力Qは状態を保持し続けます.幾つかのD-FFを組み合わせ,それぞれの入力を共有しておき,各D-FFことにCLKを制御することで,マイコンが扱えるIOピンが増えます.このモジュールでは8入出力D-FFを4つ使っています.
DフリップフロップICの出力ピンに流せる電流が心許ないので,バッファを入れて大電流に備えています.
ちらつかない程度な低周波の128段階PWM波形を生成し,一つのモジュール当たり,32個のLEDを駆動することが出来ます.実際には出力を30個に切っています.これは,出力コネクタにパラレルATAケーブルを流用している都合です.
マイコン | ATmega1284P |
D-FF | TC74VHC574F |
バッファ | TD62783APG |
ソフトウェアについて
マイコンは20MHzで駆動しており,通信基板とSPIで会話しつつ,ソフトPWMをこなします.下にコードを貼ります.(いま見ると命名がひどいなぁ)
#include "avr_base.hpp" #include <avr/io.h> #include <avr/delay.h> #include <avr/interrupt.h> #include <Timer.h> #include <string.h> #include <tus.h> #include <led_packet.h> using namespace AVRCpp::Timer; #define PORT_DATA PORTA #define PORT_CLK PORTD #define PORT_ENABLE PORTC #define PORT_ENABLE_NUM 0 #define LED_COUNT 30 LedState g_States[LED_COUNT]; DeviceID g_myDevID; uint8_t led_count_remains[LED_COUNT]; uint8_t led_count_init[LED_COUNT]; #define APPLY_TO_LED(clk,ind) \ if(led_count_remains[(clk+1)*8-ind-1] >0){ \ sbi(led_signal_buffer, ind); \ led_count_remains[(clk+1)*8-ind-1]--; \ }else{ \ cbi(led_signal_buffer, ind);} ISR(TIMER1_COMPA_vect) { tus_spi_process_packets(); } void device_init() { DDRA = 0xFF; DDRD = 0xFF; DDRC = 0xFF; cbi(PORT_ENABLE, PORT_ENABLE_NUM); // enable D-flipflops memset(led_count_init, 0, sizeof(led_count_init)); memset(led_count_remains, 0x00, sizeof(led_count_remains)); } void init_led_status() { uint8_t cache = SREG; cli(); memcpy(led_count_remains, led_count_init, sizeof(led_count_init)); SREG = cache; } void apply_led_status() { uint8_t led_signal_buffer; APPLY_TO_LED(0,0); APPLY_TO_LED(0,1); APPLY_TO_LED(0,2); APPLY_TO_LED(0,3); APPLY_TO_LED(0,4); APPLY_TO_LED(0,5); APPLY_TO_LED(0,6); APPLY_TO_LED(0,7); PORT_DATA = led_signal_buffer; PORT_CLK = 1<<0; APPLY_TO_LED(1,0); APPLY_TO_LED(1,1); APPLY_TO_LED(1,2); APPLY_TO_LED(1,3); APPLY_TO_LED(1,4); APPLY_TO_LED(1,5); APPLY_TO_LED(1,6); APPLY_TO_LED(1,7); PORT_DATA = led_signal_buffer; PORT_CLK = 1<<1; APPLY_TO_LED(2,0); APPLY_TO_LED(2,1); APPLY_TO_LED(2,2); APPLY_TO_LED(2,3); APPLY_TO_LED(2,4); APPLY_TO_LED(2,5); APPLY_TO_LED(2,6); APPLY_TO_LED(2,7); PORT_DATA = led_signal_buffer; PORT_CLK = 1<<2; //APPLY_TO_LED(3,0); //APPLY_TO_LED(3,1); APPLY_TO_LED(3,2); APPLY_TO_LED(3,3); APPLY_TO_LED(3,4); APPLY_TO_LED(3,5); APPLY_TO_LED(3,6); APPLY_TO_LED(3,7); PORT_DATA = led_signal_buffer; PORT_CLK = 1<<3; PORT_CLK = 0; } bool ProcessLedPacket(LedState *pstate) { if(pstate->Base.ModuleType != MODULETYPE_LED && pstate->Base.InternalAddr > LED_COUNT && pstate->Base.InternalAddr == 0) return false; led_count_init[pstate->Base.InternalAddr-1] = pstate->DutyValue; return true; } void spi_received(args_received *e) { g_myDevID.raw = e->pdstId->raw; ProcessLedPacket((LedState*)e->ppack); } int main(void) { uint8_t i; MCUCR = 0b01100000; //todo: turn off bods MCUSR = 0; // Do not omit to clear this resistor, otherwise suffer a terrible reseting cause. tus_spi_init(); tus_spi_set_handler(spi_received); device_init(); TimerCounter1::SetUp(NoPrescaleB, Normal16, NormalPortOperationA, NormalPortOperationB, Off, Fall); TimerCounter1::CompareMatchAInterrupt::Enable(); while(1) { init_led_status(); for(i=0; i<128; ++i) { apply_led_status(); _delay_us(100); } } }
通信基板との会話
別ファイルにSPI割り込みの関数が定義されていて,データの送受信を行っています.
タイマ割り込みでtus_spi_process_packets()が呼び出されており,定期的に受信したデータの処理を行っています.この関数は,事前にtus_spi_handler()で指定された関数を間接的に呼び出し,具体的な処理を委ねています.このモジュールではspi_received()が設定されています.spi_received()は受信したデータを実際に反映していて,LEDのDuty比設定を更新しています.
ソフトPWM
led_count_initに設定するDuty比を書いておいて,周期の最初,led_count_remainsにled_count_initをコピーします.
ループ毎にled_count_remainsをデクリメントし,0になるまでオンにしておきます.この処理に相当するのがapply_led_status()です.
これが最も時間的な制約を受けそうですが,コンパイル時に-O3で最適化を書けた場合で,最悪でも大体200クロックで抜けるようです.これは,クロック周波数が20MHzだとすると,10usec程度で処理か終わる見込みです.
直後の100usecのdelayを考えると,1周期は約14msecぐらいで回り,PWM周波数は71Hz程度と予測できます.SPIの割り込み等を考えると,もう少し遅くなっているでしょう.
おわり
あとで写真を撮って貼っておきたい
本当はポイントモジュールが先だったけど,設計がちょっと疑問なので実測してから載せる予定
Nゲージ鉄道模型のATS・ATC案②-閉塞・モータモジュール
モータモジュールについて説明します.
モータモジュール
↑ブロック図
↑基板
主要な部品:
マイコン | ATmega1284P |
モータードライバ | TB6559FG |
リレー | 941H-2C-12D |
モータモジュールで担当している閉塞のレール電圧・電流を管理します.
マイコンのADCはモータードライバを貫く電流を見ています.シャント抵抗の電圧を25倍のアンプで増幅した電圧から判断しています.
リレーは,担当する閉塞のレールと,モータドライバの出力を繋ぐか,隣接する閉塞のレールを繋ぐかを制御しています.開放時には隣接する閉塞,短絡時にはモータドライバを接続しています.
モータモジュールの動作モード
このモータモジュールには,大きく分けて4つのモードが存在します.
モータドライバのHブリッジの様子です.
- スタンバイモード
リレーを開放し,隣接する閉塞と担当する閉塞が接続されている状態です.この時,このモジュールのモータードライバは仕事をしません.
- 正方向ONモード
リレーが短絡され,モータドライバと担当する閉塞が接続されています.モータードライバはレールと接続され,列車に電流が供給されます.
- 逆方向ONモード
正方向ONモードと逆方向に電流が供給されます.
- ブレーキモード
正方向・逆方向ONモードと同様にリレーが短絡されていますが,モータードライバは電流を供給せず,どちらのレールもグランドと接続されます.この時,レールはどちらともグランドに短絡した状態です.
この4つの動作モードを使い分けて閉塞動作を実現します.
閉塞遷移について
列車の進む向きで若干挙動が変わるので,正方向時と逆方向時を分けて説明します.
正方向時
閉塞遷移前
左モータモジュールが担当する閉塞上の列車を駆動しています.次の閉塞を担当している右モータモジュールはブレーキモードで待機しています.矢印は電流を表しています.
閉塞遷移中
列車の「車輪」が次の閉塞をまたごうとする瞬間,次の閉塞のモータモジュールには前の閉塞と短絡します.この時に流れる電流をモータモジュールは検知します.
閉塞遷移後
電流を検知したモータモジュールはスタンバイ状態に移行します.列車は前の閉塞のモータモジュールから電流が供給され,移動し続けます.
逆方向時
閉塞遷移前
正方向時とは逆に,右モータモジュールが担当する閉塞上の列車を駆動しています.同様に,左モータモジュールはブレーキモードで待機しています.
閉塞遷移中
同様に,車輪で前の閉塞と短絡したときに流れる電流を検知します.左モータモジュールはブレーキモードから逆方向ONモードに移行します.この時,左右どちらのモジュールも逆方向ONになります.
同一のマイコンであれば問題ありませんが,異なるマイコンだと,クロック源が異なるのでPWM波形の位相がズレます.この波形のズレは「うねり」となって現れ,走行に問題を引き起こします.この問題は通電カプラーを用いている編成には顕著に表れ,閉塞をまたぐときだけ速度が上昇し,室内灯の明るさに「うねり」が現れます.
この問題を防止するため,左のモータモジュールは逆方向ONモードになった後,速やかに右の閉塞に「スタンバイモード」へ移行するよう命令します.
閉塞遷移後
右のモータモジュールがスタンバイに移行した後,列車は運行を継続します.
閉塞遷移後の処理について
正方向・逆方向ともに,閉塞遷移した後,今までいた閉塞の開放処理をしません.閉塞の開放処理は「制御・Webサーバー」が担います.制御・Webサーバーは列車が抑えている閉塞数を監視し,一定数以上,閉塞を抑えたとき,末尾の閉塞を開放します.
この方法であれば,フィーダだけで閉塞を形成できますが,各列車は最低2閉塞占有することが問題です.これは閉塞数を増やすことでカバーしています.
閉塞の継ぎ目を列車がまたぎ終えたことを光センサ等で監視すれば,この問題を解決できますが,レイアウト形状に任意性を持たせるために導入しませんでした.
Nゲージ鉄道模型のATS・ATC案①-概要
数年前に作ったNゲージ鉄道模型の閉塞システムについて,あまり資料をまとめていなかったので,ここにまとめます.
動機
2010年頃,私はある大学のサークルの鉄道模型展示に関わることになりました.そこでは当時,8mX6mぐらいの規模で4線エンドレスのレイアウトを作成していました.
このレベルの規模だと,どれだけ長い編成でも中々列車が巡ってきてくれず,見ていて少し寂しい印象を受ける欠点がありました.
これを解決するために,私は1線で2編成以上の運行を行うため,閉塞システムを作ることになりました.
2編成以上動かすのであれば,DCCを導入すれば負担が軽減出来そうですが,走らせる車両は部の所有の車両ではなく,部員が持ち寄った車両ということで,車両への加工が必要なDCCは導入できませんでした.
そこで,リレー式の閉塞システムを作ることにしました.
全体図
レールやポイントを操作するハードウェアは「モジュール」にまとめられています.これらのモジュールは「通信基板」とルーターを通してそれぞれが通信できるようになっています.
「制御+Webサーバー」は閉塞制御行うようにモジュールに指示を飛ばし,ユーザーの入力を処理します.
「ユーザー」はタブレットやラップトップといった,Webブラウザが動く端末であればどれでも,列車の制御を行えます.
目次
- モータモジュール
- ポイントモジュール
- LEDモジュール
- Web・制御サーバー
- WebUI
- 在線表示ページ
- 電車でGOコントローラの利用
ElecrowからPanelizing(面付け)した基板が届いた
作成した基板について
この基板パターンを100x94mmに5つ面付けする.
Panelizingについて
Elecrowの基板作成サービスにはPanelizingなる項目がある
一つの基板に幾つかの基板パターンを入れて,Vカットの細い溝で区切ってくれるらしい.小さい基板を大量に欲しいときには割りと使えそう.
面付けに関する詳しいことは下記ページにある.基板サイズの制約や注意事項等々がある.
BLOG | PCB Panelize is Available now
その入れ方については公式wikiが説明してくれている.
How to panelize PCBs with CAM350 - Elecrow
- 面付けを行うためには8cm*8cm以上でなければならないとある.今回は5つ縦に置いても70x90mmなので条件を満たさない.8cm*8cmを下回る場合にはTechnology Edgeなる余白を3mm以上入れなければならない.
- Vカットを入れる切り取り線はシルクスクリーンに書き込む.基板パターンの間隔は1.6mmの基板厚さだと,0.8mmぐらい空ける必要がある.今回は1mmの間隔を置いている.
- 注文フォームのPanelizingには幾つか種類があって,面付けする基板パターンの種類や個数によって追加料金が異なるらしい.とりあえず「Single PCB with milling」で注文したら,あとで$8払ってくれメールが届いた.$8は「2-5 copies」に相当する.
基板到着までの流れ
Elecrow
2015/08/30に注文.とりあえず,追加情報に「ボトムシルクに切り取り線入れたからV-cutしてね」と書き込む
2015/08/31に追加料金の旨に関するメールのやりとり.その日のうちに「In Production」に進む
2015/09/07に「Traceable」に変更.製造に5~6営業日かかったのかな?(面付けでちょっと多く掛かるとは書いてある)
DHL
DHLの配達記録.日本語だと空欄になってるところがあったので,英語版を載せる.1~20番までは1日ちょっとで来てるからとても早い.
「Forwarded for delivery」は悪名高き「配達業者への荷物引渡し準備完了」,佐川急便に投げるってやつ.運が良いとDHLが直接届けてくれて,Traceableから1日で来るんだけど残念.
Friday, September 11, 2015 | Location | Time | ||||
---|---|---|---|---|---|---|
21 | Delivery attempted; recipient not home | TOKYO - JAPAN | 17:38 | |||
Tuesday, September 08, 2015 | Location | Time | ||||
20 | Forwarded for delivery | TOKYO - JAPAN | 14:20 | |||
19 | Arrived at Delivery Facility in TOKYO - JAPAN | TOKYO - JAPAN | 12:37 | |||
18 | Departed Facility in TOKYO - JAPAN | TOKYO - JAPAN | 11:36 | |||
17 | Processed at TOKYO - JAPAN | TOKYO - JAPAN | 11:28 | |||
16 | Clearance processing complete at TOKYO - JAPAN | TOKYO - JAPAN | 10:48 | |||
15 | Arrived at Sort Facility TOKYO - JAPAN | TOKYO - JAPAN | 9:55 | |||
14 | Customs status updated | TOKYO - JAPAN | 9:07 | |||
13 | Transferred through TOKYO - JAPAN | TOKYO - JAPAN | 8:50 | |||
12 | Departed Facility in HONG KONG - HONG KONG | HONG KONG - HONG KONG | 3:35 | |||
11 | Processed at HONG KONG - HONG KONG | HONG KONG - HONG KONG | 3:33 | |||
10 | Clearance processing complete at HONG KONG - HONG KONG | HONG KONG - HONG KONG | 0:44 | |||
9 | Arrived at Sort Facility HONG KONG - HONG KONG | HONG KONG - HONG KONG | 0:36 | |||
Monday, September 07, 2015 | Location | Time | ||||
8 | Shipment on hold | HONG KONG - HONG KONG | 23:35 | |||
7 | Clearance processing complete at SHENZHEN - CHINA, PEOPLES REPUBLIC | SHENZHEN - CHINA, PEOPLES REPUBLIC | 22:00 | |||
6 | Customs status updated | HONG KONG - HONG KONG | 18:23 | |||
5 | Clearance event | SHENZHEN - CHINA, PEOPLES REPUBLIC | 18:00 | |||
4 | Departed Facility in SHENZHEN - CHINA, PEOPLES REPUBLIC | SHENZHEN - CHINA, PEOPLES REPUBLIC | 17:22 | |||
3 | Processed at SHENZHEN - CHINA, PEOPLES REPUBLIC | SHENZHEN - CHINA, PEOPLES REPUBLIC | 17:16 | |||
2 | Arrived at Sort Facility SHENZHEN - CHINA, PEOPLES REPUBLIC | SHENZHEN - CHINA, PEOPLES REPUBLIC | 15:58 | |||
1 | Shipment picked up | SHENZHEN - CHINA, PEOPLES REPUBLIC | 12:08 |
佐川急便
配達記録.DHLの荷物番号とは紐付けされていないので,荷物が届かないと記録は見られない.
⇒ 2015年09月11日 17:47 配達は終了致しました。
↑ 2015年09月11日 17:38 ご不在でしたので、お預かりしております。
↑ 2015年09月11日 八王子営業所から配達に出発致しました。
↑ 八王子営業所でお預かりしております。
↑ 2015年09月08日 19:31 府中営業所を出発致しました。
↑ お荷物をお預かり致しました。
日本とシンセンよりも府中と八王子の方が遠いらしい.台風だったからね,仕方ないね.
届いた基板
切れてる基板が10枚届いた.隣のは同時に頼んだ普通の基板.Technology Edgeなるエリアには3つの穴とハンダで埋まったスルーホールがある.
Vカットされると思ったけど,ドリルで切ってくれたっぽい.シルク線を別々に書いたからかな?これなら基板外形線で書いても良かったかも.
Vカットのところを横から見るとこんな感じ.場合によっては,端面をヤスリでちょっと削らないといけないかもしれない.
- 5つ面付けした基板10枚セット(10x10cm)で$23.9だったので,一枚当たり$0.478.日本円で50円ちょっとかな.面付け無し10x5cmで頼むよりは安いですね.
- Elecrowの基板色はBlackの他にMatte Blackなるオプションがある($20).確かに今回の基板はちょっとくすんでる(縦のスジが目立つ感じ).Matte Black + ENIGなら相当映えるパターンの基板が出来そうだなぁ.
納涼?「すぐにけせ」を再現するUEFIバイナリを作ってみた
「すぐにけせ」?
オカルト都市伝説の一つ,SFCで発売された「真・女神転生(II?)」を起動すると1/65536の確率で表示されるメッセージのことです.
これは広く「ガセネタ」として認識されています.私自身も,SFCは疑似的に乱数を発生させて(る気がし)ますので,起動時にランダムで表示するのは厳しいと思ってます.(セーブデータが消えたら,とか,別のトリガーで出てきたら面白いですけどね)
UEFIとは?
マザーボードに乗っかってるファームウェアのインタフェースです.最近のマザーボードはUEFIを実装していて,UEFIのSDKも公開されているので,OS起動前の処理を比較的簡単に書けたりします.
今回はこれを使って,起動前にメッセージを表示させています.
ポイント
とりあえず,周知の事実から「すぐにけせ」は「起動時」に「1/65536で再現」することが出来れば良さそうです.
「起動時」
起動時に再現するためには,UEFIに関わらず,MBRブートした小さなLinuxに表示させれば良いんじゃないかなぁとも思いました.表示する判定の場合は表示して,表示しない判定の場合には,次回ブートするデバイスをBIOSに伝えればいいわけです.ただ,メッセージを表示しない確率が非常に高いはずなので,毎回起動時に2回ブートさせるのはちょっと微妙だなぁと思いました.
僕のマザーのブートマネージャだけかもしれませんが,UEFIブートであれば,起動に失敗した場合,すぐに次の起動プログラムを試してくれるようです.これを悪用しない手はありません.最初に「すぐにけせ」バイナリを起動させて,2段目に使用するOSを起動するように設定すれば,違和感なく起動時に「すぐにけせ」判定をさせることが出来ます.
「1/65536」
起動時に確率で発生させることはSFCでは出来ないはずです.しかし,我々の使っているモダンなコンピュータはRTCが内蔵されているので,起動時でも問題なく乱数を発生できそうです.
UEFIで日付を手に入れようとするには,RuntimeServicesのGetTime()を使えば良いのですが,渡されるのはEFI_TIME構造体で,○○年元旦からの積算秒で表しているわけではなく,年月日等々が直感的に分かる仕様*1でした.
時分秒とミリ秒が分かるようなので,ミリ秒ベースに変換して65536で割っています.お手軽実装です.ミリ秒だけは電源投入時から計測しているような気がして不安ですが.
画像について
複雑なファイルシステムを扱えるのがUEFIの売りな気がしますが,表示させる画像はリテラルなconst unsigned char [] に直してソースコードに埋め込んでいます.
GraphicsOutputで表示させるために,BMP画像を変換してくれる関数がEDK2内のBdsConsole.cで定義されているので利用します.
変換した画像で画面を埋め尽くします.横端・縦端を描画する場合にはスクリーンをはみ出すので,書き込む範囲を予め計算しておきますが,横端を描画するために,描画するwidthを元画像より小さくしようとすると,何というか,水平同期の周期がズレる感じになって,うまく描画されません.1ピクセルずつ書けば良さそうですが,今回は諦めています.
ビルド
VS2012でビルドしました.下の記事を見てやってましたが,IntelliSense効かないっぽいのが悲しいです.
http://uefi.blogspot.jp/2012/06/how-to-set-up-edk2s-windows-hosted-uefi.html
実機で動かすバイナリをビルドするには,Conf/target.txtのACTIVE_PLATFORMをAppPkg/AppPkg.dscのように適切に変更しておきます.Nt32Pkg.dscでは動かなかったです.
また,実機がX64アーキテクチャしかサポートしていない場合には,VS2012の「VS2012 x64 Cross Tools コマンド プロンプト」からedk2setup.bat→buildでクロスコンパイルします.
動作
実機動作.(ASRock Z87 Extreme 3)
1/2で出てくる高確率版を作って動作を確認しました.失敗した場合には,Windowsのブートに移ってくれるようです.
今日から1/65536版を入れてブートしますので,運悪く出てきたら追記します.
コード
EDK2のAppPkg/Mainを改変して作りました.
https://github.com/sosoru/sugunikese-on-uefi