Show HN: 20ドルの4Gワイヤレスホットスポットをテキストメッセージデバイスに改造する
Show HN: Hacking a $20 4G wireless hotspot into a texting device (bkovac.github.io)
要約
この記事は、安価な4Gワイヤレスホットスポット(MF800)を、AdafruitのSHARPメモリディスプレイとClicks Keyboard for iPhoneを組み合わせて、テキストメッセージ専用デバイスに改造するプロジェクトを紹介しています。オープンソースプロジェクトであるOpenStickを活用し、LinuxをインストールしてカスタムPCBを作成することで、このユニークなガジェットが実現されました。
全文翻訳
20ドルの4Gワイヤレスホットスポットをテキストメッセージデバイスに改造する
[画像: The thing]
動機。
私は物を整理するのが得意ではありません。試してはいますが、しばしば机の上にたくさんの物がある状態になってしまいます。様々なAliExpressからの注文や、私が取り組んでいるプロジェクト、さらには贈り物や、片付ける時間がなかったものまで様々です。
このプロジェクトが生まれたのはまさにそんな状況からです。ある時、私の机の上には以下のようなものが転がっていました。
- 様々な、おそらくOpenStick互換のモデルたち - 特に:
- MF800 - 最終的に使用したもの
- UZ801 - サイズは良いが、バッテリーや十分なGPIOが見当たらない
- USBメモリ型のもの。他の問題で破棄した。
- Clicks Keyboard for iPhone 16 Pro Max(いとこからの贈り物 - 残念ながら適切なiPhoneを持っていない🥲)
- Adafruit SHARP Memory Display ボード
そしてもちろん、私の原始的な脳がこれら3つを組み合わせました。
まあ、正直に言うと、私はおそらくこれらを知っていたことで少し影響を受けていたのでしょう。
モデム。
需要と供給の神秘的な法則、そしてサプライチェーンの魔法のおかげで、Wi-Fi、Bluetooth、ディスプレイ、バッテリー駆動で完全にアンロックされた4Gモデムを、送料込みで20ドル未満で入手できるのです。これはもちろん、私たちのプロジェクトの礎石です。
ディスプレイ付きとディスプレイなしのバージョンがあります。ディスプレイなしのものは、ディスプレイをLEDに置き換えただけですが、PCBは同じです。ディスプレイはGC9107搭載のものですが、見た目がひどいので取り外しました。
OpenStickプロジェクトのおかげで、Linuxを簡単にインストールできます。標準のデバイスはAndroidで動作しますが、ADBは最初からアクセス可能です。そしてADBから直接EDLモードに入り、デバイスを再フラッシュできます。重要なパーティションはすべて保存するようにしてください。PCB上にはEDLモードに直接入るためにショートさせるピンもあります。
動作中のデバイスから実行中のデバイスツリーを抽出することは、情報の宝庫だったので、必ず実行してください。
参考になったガイドやリンクをいくつか紹介します。
- OpenStick github
- openstick.de
- wvthoog.nl blog - 最初はこれのカーネルを使ったと思います。
- extowerk.com blog
- このプロジェクトのGitHubリポジトリも役立つかもしれません。
OpenStickで本当に苦労するのは、ドライバーとデバイスツリーの段階からですが、それは後で話しましょう。
キーボード。
Clicks Keyboardについてはあまり言うことはありません。使うのはとても快適ですが、唯一の問題はかなりの金額を支払う必要があることです。さらに、それを切断する必要があるため、さらに悪化します😱。
プロトコルに関しては、MFiデバイスでの過去の経験から予想していた通りです。通常のUSBキーボードに、iPhoneが認証してからキーボードを通過させることを許可する、Apple独自の追加エンドポイントが付いています。
したがって、私たちのデバイスにとっては、これは単なる通常のキーボードであることを意味します。
ちなみに、Clicksには設定/アップデートなどに使用されるモバイルアプリがあります。キーボード自体はCH32V203または類似のもので駆動されています。カスタムコードをフラッシュすることも可能ですが、現時点ではその必要性は感じていません。将来的には設定ユーティリティが欲しいと思っています。
ディスプレイ。
シャープディスプレイは、高コントラストで素晴らしく見えると思います(そして、メッセージング専用のダムデバイスという私のユースケースにも合っています)。それ以外は、キーボードについてあまり言うことがなかったなら、ここではさらに何も言うことはありません。
それはディスプレイです。
コマンドを送ります。
表示します。
アダプターPCB。
すぐに明らかになったことが一つあります。カスタムPCBを追加する必要があるということです。MF800がオンボードで何を持っているのか正確には分かりませんでしたし、シールド缶を開けることもありませんでしたが、オンボードに5Vブースターがないことはほぼ確信しています。
物理的なサイズのため、後で詳しく説明しますが、USBコネクタは切り取られることになるので、それも処理する方法が必要です。
最終的なPCBは、USBホストモード電源、USBホスト/デバイスモード切り替え、ディスプレイ電源、およびディスプレイ信号レベル変換を処理することになりました。
[画像: PCB from the component side]
PCBはアセンブリと一緒に注文しました。そして、両面アセンブリは高価なので、すべてのコンポーネントを片面に収めるためにいくつかの妥協をしました。非コンポーネント側は、PCB-to-PCB接続用のハンダ付けポイントに使用されます。
すべてのファイルはGitHubで見つけることができますが、要約するとPCBは以下の通りです。
- TUSB320 - USBモード切り替え用
- SN74LVC8T245 - レベルシフト用
- MCP1640 - 5Vブースター
- TPS22917 (ハイとローの1つずつ) - VBUS/VBATの切り替え用
- USBコネクタとディスプレイ用FPCコネクタ
- MF800とアダプターPCBを接続するためのテストパッド
エンクロージャー 1。
MF800は、バッテリーを含むため、またその緩い性質のため、他のOpenStickよりもかなり大きいです。
[画像: MF800 without the back cover and with the (unnecessary) cut-out for the bootloader pins]
Clicksケースに収めるためには、垂直に配置して巨大な醜いものにするか、水平に収まるようにPCBをトリミングする必要があります。
[画像: Top, with a the blue lines showing the USB data lines going from the connector and pads to the SOC]
[画像: Bottom, red lines mark where I was planning to cut and the blue circle marks the via for USB data test pads]
私の右側のカット(下の写真)はバッテリー接続ラインを切断してしまうので、後でパッチを当てる必要があります。
カット。
PCBのカットは予想以上にうまくいきました。デバイスはすぐに起動し、すべてが機能しているように見えました。これらの領域を通る重要なラインは実際にはなかったようです。
[画像: The cut PCB inside a test enclosure with the battery below and the patch VBAT wire]
テストしなかったのはUSB接続と4Gモデムだけでした。モデムについては、これらの領域の下にルーティングされるものはないため、問題にならないと99%確信していましたが、USBについては、ビアを傷つけていないか心配でした。
[画像: 2D scan of the PCB, trimmed to the cut lines and extruded to match the measured thickness - a tight fit within the iPhone’s width]
配線 1。
元のディスプレイのパッドを再利用することにしました。なぜかはもうよく覚えていませんが、おそらく最初のアイデアはリジッドフレキシブルPCBを使用して、元のディスプレイと同じようにハンダ付けすることだったからです(価格を見てすぐに却下しました)。
今見ると、非常に愚かに思えます。マイクロSDコネクタの隣にあるラベル付きパッドを使うべきでした。これらのパッドがSIMカードと共有されているかどうかは一度も確認していません。
デバイスを起動でき、元のAndroidデバイスツリーを持っていたので、ディスプレイに使用されているピンを抽出しました。その後、gpiosetでそれらをテストして、正しかったことを確認しました。電源(デバイスツリーで無効にして再起動してテストしました)とグランドについても同様です。
[画像: Checking and mapping the pins with a multimeter]
最初に配線してチェックしたのは電源で、次にUSBでした。これは、独立したユニットとしてテストできたからです。また、これには私の側の回路と、あの怪しいビアが含まれていたため、より懐疑的でした。
[画像: Wiring the USB and the power supplies]
もちろん、最初はうまくいきませんでした。パッドの周りをプローブして、すべての電圧がOKであることを確認した後、ラップトップのdmesgで列挙を試みていることが分かりました。つまり、何かが起こっていました。
「ハイスピード」と表示されていることにも気づきました。これは少し驚きました。ハイスピードUSBを使うとは思っていませんでした。最初に考えたのは、ワイヤーが長すぎることでした。しかし、短くする前に、簡単な修正を試みました。よりきつく撚り合わせると、うまくいきました😲!
[画像: Device’s USB Gadget enumerating]
この成功に続いて、すぐに反対方向も機能させようとしました。これには時間がかかりました。どうやら、すべてのAliExpressアダプターがCCラインを正しく配線しているわけではないようです。キーボードはすぐに機能しましたが、問題は、何かが間違って配線されているのではないかと恐れて、最初にテストするのをためらったことです。
[画像: Events from the keyboard]
配線 2。
SPIラインをディスプレイに配線する前に、デバイスツリーを正しく再設定できたか確認したかったのです。以前のテストでパッドが正しいことは分かっていましたが、ここで間違える可能性はたくさんあります。
spi@78b9000 {
compatible = "qcom,spi-qup-v2.2.1";
reg = <0x78b9000 0x500>;
interrupts = <0x00 0x63 0x04>;
clocks = <0x13 0x41 0x13 0x36>;
clock-names = "core", "iface";
dmas = <0x6d 0x0c 0x6d 0x0d>;
dma-names = "tx", "rx";
pinctrl-names = "default", "sleep";
pinctrl-0 = <0x84>;
pinctrl-1 = <0x85>;
#address-cells = <0x01>;
#size-cells = <0x00>;
status = "okay";
spidev@0 {
//compatible = "linux,spidev";
compatible = "rohm,dh2228fv";
reg = <0>;
spi-max-frequency = <16000000>;
spi-cs-high;
};
};
例えば、Qualcommのドライバーは怪しく、コメントアウトされた互換性は実際にはspidevをエクスポートしないため、dh2228fv互換性でごまかします。
ループで実行されるspi-pipeユーティリティを使用して、MOSIとCLKラインの電圧変化を測定できました。これは、何かが起こっていると結論付けるには十分でした。もちろん、オシロスコープやロジックアナライザーがあればもっと良かったのですが、手元にはありませんでした。
電源とUSBの大成功に勇気づけられ、不注意にもデバイスがオンの状態でディスプレイをPCBに接続しました(🤦)。
すぐにディスプレイに何かが起こり、壊してしまったと確信しました。幸いなことに何も起こらず、ディスプレイは無事でした。(実際、デバイスの電源を入れるたびにこれは起こります。まだ心配すべきかどうかは分かりません😬。)
何も悪いことが起こっていないこと、そして何も燃えたり過熱したりしていないことを確認した後、ディスプレイを機能させることを試みました。
AI Pythonコードで1時間ほどこれをいじくり回しましたが、全く進展がありませんでした。失敗の可能性は複数ありました。レベルコンバーター、配線の間違い、接触不良など…
どうやら、よくあることですが(なぜかは不明)、QualcommドライバーはCSをうまく扱えていないようです(あるいは正しくない、あるいは他の用途では正しいのかもしれません)。いずれにせよ、同じテストスクリプトを再度試しましたが、今回はCSピンを手動で(libgpiod経由で)トグルしました。すると実際に動作しました。
[画像: Display showing a checkerboard test pattern]
再配線。
電源を接続するために使用した「電気的」なワイヤーから、信号用に採用した怪しい細いマグネットワイヤー、そしてMOSIとCLKの周りに巻き付けた(効果がないように見えた)撚り線まで、すべてにすぐに失望しました。そこで、すべてをもう一度配線することにしました。
今回は信号線と電源線の両方にマグネットワイヤーを使用しましたが、こちらはかなり太く、曲げた後も位置を保ちました。メインボードのパッドが非常に怪しいため、USBデータ線は再配線しませんでした。
[画像: Much better, though still lacking solder mask/resin and tape]
ディスプレイカーネルドライバー。
これまでのすべてのテストは、単なるPythonスクリプトで行われましたが、真の進歩はカーネルドライバーで行われます。利用可能なドライバーはいくつかありますが、私が選んだのはardangeloのsharp-drm-driverです。私がDRMドライバーを望む理由は以下の通りです。
- 例えば動画再生のために直接出力を使用できます(
mpvなど)。- フレームバッファでも機能しますが、2026年では怪しいです。
- X/Waylandを簡単に実行できます。
- ジョークのためにデスクトップ環境を試すかもしれません。
- ドライバーを拡張して部分的な更新を行えるようにする。
- フレームバッファインターフェースも引き続き利用できる。
これはほぼすぐに機能しました。CSとデフォルトのハイアクティブ値については調整が必要でした。
おそらく人生で初めて、カーネルモジュールのコンパイルと実行に問題はありませんでした。実行していた謎のカーネルは、モジュールが有効化された6.12.1-msm8916でした。.configファイルが存在したので、それを使用しました。
次に、メインラインのLinux 6.12.1カーネルをダウンロードし、変更がないか(または重大な変更がないこと)を期待しました。これは十分であり、ドライバーにいくつかの小さなパッチを当てた後、それは動作しました。
以下は、最終的なデバイスツリーの外観です。CSロジックがディスプレイドライバーによって処理されていることに注意してください。
spi@78b9000 {
compatible = "qcom,spi-qup-v2.2.1";
reg = <0x78b9000 0x500>;
interrupts = <0x00 0x63 0x04>;
clocks = <0x13 0x41 0x13 0x36>;
clock-names = "core", "iface";
dmas = <0x6d 0x0c 0x6d 0x0d>;
dma-names = "tx", "rx";
pinctrl-names = "default", "sleep";
pinctrl-0 = <0x84>;
pinctrl-1 = <0x85>;
#address-cells = <0x01>;
#size-cells = <0x00>;
status = "okay";
sharp_drm@0 {
compatible = "sharp-drm";
reg = <0>;
spi-max-frequency = <4000000>;
cs-gpios = <0x49 18 1>;
};
};
[画像: Standard linux console login prompt showed up]
現在の問題は、ドライバーが特定の値を黒に丸め、それ以上の値を白に丸める(またはパラメータによっては反転する)ことです。テキスト(またはアプリで自分でビジュアルを作成する場合)にはこれはうまく機能しますが、動画や画像を表示したい汎用的なソリューションでは、見た目がひどいです。この修正は、ドライバーにディザリングを追加することです。
[画像: A video looking bad with just color rounding]
ユーザーがディザリングを有効にできるようにするカスタムsys値を追加しました。また、使用するアルゴリズムを選択できるようにしました。
- 動画用:Atkinson
- 静止画用:Floyd-Steinberg
すべての初期機能はそのまま残されています。
[画像: Big buck bunny looking great (played by stock MPV with DRM output)]
これに関する詳細情報、またはDRMドライバーパッチは、プロジェクトのGitHubリポジトリで見つけることができます。
エンクロージャー 2。
すべてがテーブル上にあり、機能していること、主に寸法が設定され測定できることを確認した後、キーボードケースに何も壊す心配なく入れられるであろう、ほぼ最終的なケースのモデリングに飛び込みました。
AppleがUSB-CコネクタがiPhoneのどのくらい奥にあるかの寸法を提供していないため、これは少し怪しいものでしたが、Apple標準のUSB-Cケーブル(デバイスまでしっかりとフィットする)を測定し、そこから補間することで回避しました。
[画像: Linux login, working out-of-the-box after setting USB to host]
このプリントはまだ特に役立つものではありませんでしたが、USBコネクタの寸法(その他)が正しく測定されたことを確認するという目的は果たしました。
また、2つの側壁が正しく印刷されず、モデリング時(写真に見えるものを受け取る前)にはディスプレイ(開発キットPCBに接続されているもの以外)がなかったので、カバーが欠けています。
[画像: Cover fits but no display slot, case still not trimmed]
最終エンクロージャー(現時点)。
これが最終的なエンクロージャーになったものです。ほとんどすべてが正しく収まりました。まず、カプトンテープで固定された簡単なテストを作成しました。
[画像: Final encloure, in the still-not-trimmed case held with kapton tape]
この時点で、進行中の個人的な事情により、私のツールの大部分(主に3Dプリンターですが、他のものも)へのアクセスを一時的に失いました。
手が塞がったため、クリップで留まる「最終的な最終」のものを印刷する代わりに、ホットグルーでケースを接着することにしました。
電源ボタンについても忘れていました。PCB上にあり機能していましたが、ケースの切り欠きとプランジャーがありませんでした。これは小さな穴とピンで解決しました。非常に醜いですが、機能します。
[画像: Hot glued enclosure]
さて、大仕事です。工具なしでキーボードケースを切り詰めることです。予想通りの結果になりました。ただし、後でやすりで削ってきれいにできるように、必要最低限よりも少なめにカットしました。
実際にはそれほど悪く見えませんが、エッジはもう少しきれいにできます。ケースのホットグルーの突起の方が大きな問題です。
トップダウンの写真の魔法で、ほとんどをあなたから隠しました。
[画像: End result]
組み立て中の写真を撮り忘れました。以前と同じですが、4GフレキシブルPCBアンテナがPCBにハンダ付けされ、エンクロージャーの上半分のディスプレイの下に接着されています。ミニSIMもスロットに入っています。
バッテリー設定。
デバイスからコピーしたAndroidデバイスツリーには、バッテリーと充電器の設定があらかじめ定義されています。これらは、私が実行しているメインラインLinuxが提供するものよりも高度です。
それでも、実用的なものが機能するようになるのはかなり簡単だと予想していました。ここで大きな疑問は、バッテリー情報と私のアダプターPCBの消費電力でした。
しかし、ドライバーがユーザーレベルで提供したのは、uV単位のバッテリー電圧と、充電中かどうかを示すフラグだけでした。そのため、バッテリーパーセント値のためにドライバーを改造するつもりはないので、実際のバッテリーロジックは私のアプリに任されることになります。
充電は正常に機能しているようです。キーボードのUSBパススルーポート経由でも機能しますが、残念ながらデバイスが起動しているときだけです。
不足しているもの。
スリープ機能は、現時点で最大の未解決の問題です。主な理由は、デバイスの日常的なテスト、特にモデムをオンにした状態でのテスト、そして便利な電源ボタンの欠如です。
メッセージングのためにデバイスを使い始めるにあたり、近い将来これに取り組む予定です。少なくとも、高速な起動/シャットダウンを実現したいと考えています。
追加の入力方法、例えばタッチスクリーンやスクロールホイールは、おそらく最も良い追加機能になるでしょう。特にタッチは、非常に少ないスペースで実現できます。
次に、サウンドやバイブレーションが続きます。8kHz程度の小さなスピーカーでも良いでしょう。アンプ用の十分なPCBスペースと、エンクロージャー内のスピーカー用のスペースがあります。
醜い点。
主にグルーの問題と電源ボタンの欠如。どちらも新しいプリントが必要で、キーボードケースのギザギザのエッジをやすりで削る必要があります。
バッテリーは、ケースに入っていないと外れてしまうため、テープで固定されています。現時点では優先順位は高くありません。
エンクロージャーの高さを決定する大きな下部ベゼルも短縮できますが、それには他のものの中でも同じ3ピンコネクタを持つ別のバッテリーを入手する必要があります。
ヘルパーPCBは、ディスプレイFPCケーブルがわずかに引っ張るため、スロット内で上にスライドします。エンクロージャーカバーに固定するためのタブを追加するのを忘れました。理想的ではありませんが、エンクロージャーをケースにスライドさせるときにのみ問題になります。
最後に、ディスプレイの小さな部分がケースで覆われています。すべてのエッジに1〜2ピクセル程度です。これも次のプリントで修正されます。
全体として、デバイスには非常に満足していますが、もう少し作業をすれば、見た目が劇的に向上するでしょう。写真では大丈夫に見えますが、実物は少し物足りないです。
これを再現したり、似たようなことをしたい場合は、ほとんどのものをプロジェクトのGitHubリポジトリで見つけることができます。
将来。
ソフトウェアについては、使用によってのみ洗練されるため、意図的にこの投稿から除外しました。完成していないが、放棄していないプロジェクトをリリースするのはあまり好きではありません。
[画像: Quick preview of the software]
この記事を書いている時点で、元のディスプレイドライバーにメモリリークを発見しました。それを修正するパッチも提供しました。このようなことは、実際のハンズオンテストなしでは簡単に見つけることはできません。
このテキストは、人間である私が完全に書きました。
veggie_privacy_8y at icloud dot comまで連絡できます。