mangOH Red
製品概要
mangOH™ Redは、低消費電力のモノのインターネット(IoT)プラットフォームであり、バッテリ電源で最大10年間動作します。mangoh.ioでは、次のように説明されています。
- クレジットカードサイズのフォームファクタで、概念実証の迅速な構築に理想的。
- スナップインソケットにより、任意のCF3™互換モジュールの追加が可能。ワイヤレスモジュール(2G~4GおよびLTE-M/NB-IoT)を使用すると最大10年間のバッテリ駆動が可能(この記事で使用したCF3モジュールは、WP8548_1103113(DigiKey品番1645-1022-1-ND)でした)。
- IoT拡張カードスロットには、IoT拡張カードのオープン標準に基づくあらゆるテクノロジのプラグインが可能。
- 内蔵のSierra WirelessスマートSIMに最大100MB(リージョンによる)のフリーデータを保持でき、市販のあらゆるSIMと併用が可能。
- AirVantage IoTプラットフォームと統合されており、クラウドでのソリューションの作成、展開、管理が可能。
- 内蔵のWi-Fi b/g/nとBluetooth 4.2 BLEおよびCortex-M4により、I/Oへのリアルタイムアクセスが可能。
- 加速度センサ/ジャイロスコープ、圧力および光センサを内蔵、26ピンRaspberry Pi対応コネクタ(このコネクタケーブルは、DigiKey品番1597-1065-NDです)。
(画像提供:Talon Communications Inc.)同梱されていたもの
箱の中には、以下のアイテムが入っていました。
- mangOH Red
- CF3モジュール(我々のは、WP8548_1103113)
- マイクロUSBケーブル
- アンテナ × 2(1本はメイン用、もう1本は全地球航法衛星システム(GNSS)用)
- 初期データの割り当て済みのSierra WirelessマイクロSIMカード
ハードウェアのセットアップ
セットアップ手順については、mangOH Redユーザーおよびセットアップガイドに従ってください。
mangOH Redには、2つのマイクロUSBポートがあります。
ハードウェアのセットアップは簡単です。マイクロUSBをmangOHに繋いでコンピュータに接続します。アンテナを接続し、SIMカードをmangOHの背面スロットに差し込みます。次の図は、mangOH Red開発者ガイドから抜粋したハードウェアアーキテクチャ図です。
(画像提供:Talon Communications Inc.)Raspberry Piコネクタ
リボンケーブルコネクタのDigiKey品番は1597-1065-NDです。下の画像は、Raspberry Pi(Raspberry Piのピン配置図では、MangOH Redが使用しないピンは網掛けされています)とMangOH Redのピン配置図を示しています。接続は、ピン1〜ピン1、ピン2〜ピン2、以下同様のようになります。
(画像提供:pinout.xyz)
(画像提供:Talon Communications Inc.)ソフトウェアのセットアップ
ソフトウェアのセットアップは少し面倒でした。このデバイスを使って作業を始めるときは、mangOHの最終製品には3つのエンティティが絡んでいることに十分注意してください。mangOH Redはボード本体です。Sierra Wirelessは、CF3モジュールのメーカーであると同時に、mangOHからのデータを格納するIoT CloudであるAirVantageの所有者でもあります。また、Legatoは、Linuxベースのコマンドラインインターフェース(CLI)ですが、mangOHとの接続に使用されます。これらそれぞれについてと、そのフォーラムへのアクセスの仕方をこれから順に説明します。
最初に閲覧するウェブサイトは、Getting Started with mangOH(mangOHのスタートアップ)のページです。ここでは、WindowsかLinuxのどちらかのオペレーティングシステムを選択できます(Mac OSも同様ですが、後述します)。どちらのOSを選んでも、Windows上の仮想マシン(Oracle VirtualBox)またはLinux上のLegato開発用アドオンのいずれかを使用して、Legato CLIを組み込む必要があります。Windows用セットアップマニュアルとLinux用セットアップマニュアルは、マシンのセットアップ時の重要な情報であり、ここではその内容は繰り返しません。
64ビットのLinuxマシンを使用している場合は、Linuxセットアップマニュアルの16ページの項目6に注意してください。
Windows、Linux、Mac OSで使用できるDeveloper Studioもダウンロードする必要があります。Sierra Wirelessのウェブサイトによると、「Developer Studioは、Legato Application Framework用のSierra Wireless IDE(統合開発環境)」ということです。つまり、自分でアプリを作成するには2つの選択肢があります。ベーシックなテキストベースのプログラムを使用するか、それともGUIベースのDeveloper Studioを使用して、ファイル/フォルダ作成の一部をオートで行うかです。私は各OS用のDeveloper Studioをダウンロードしてみましたが、唯一問題があったのはMac OS用のJava 8でした。Java 8の標準インストールでは、何らかの理由でDeveloper Studioが動作しなかったので、OracleのサイトからJava SE Development Kit 8u151をダウンロードし、これをインストールしました。
サンプルアプリとファイル構造
mangOHをセットアップしたら、手始めに行くべきは、Legato on Githubのサイトです。ここでLegatoフォルダをダウンロードするか、クローンを作成します。Githubでダウンロードしたサンプルについては、Legatoのサンプルアプリの説明を参照してください。Legatoサンプルアプリのウェブサイトは、素晴らしい「ノウハウ」の宝庫です。
ファイル構造にも注意を払ってください。各アプリケーションには、次のようなディレクトリ/ファイル構造があります。

アプリケーションによっては、ファイル構造には.APIファイルや.hファイルも含まれています。プログラミングに関しては、コアは.cファイルで、他のファイルはアプリケーション作成のためのコンパイル手順です。
例:GNSS位置テキストアプリ
mangOH Redに何ができるかをよく示しているサンプルアプリケーションは、mangOH Redの連動機能をユーザーにテキストで表示するアプリです。ファイル構造は上記のとおりです。
textLoc.cファイルのコードは以下のとおりです。Randall Restle氏の新製品発見をチェックするには、ここをクリックしてください。ここでは、同氏が初めてmangOH Redを紹介しています。
コピー
textLoc.c //-------------------------------------------------------------------------------------------------- /** @file textLoc.c * * This app illustrates a sample usage of ultra low power mode API. This app reads the current gps * location and then sends it as a text message to a destination cell phone number. Once the text * message has been sent, the device enters ultra low power mode. The device will wake up from * ultra low power mode after a configurable delay. * * @note This app expects destination cell number to be specified in environment variable section * of adef file. If nothing specified in environment variable, it will send message to a default * non-existent phone number. * * Copyright (C) Sierra Wireless Inc. */ //-------------------------------------------------------------------------------------------------- #include "legato.h" /* IPC APIs */ #include "interfaces.h" //-------------------------------------------------------------------------------------------------- /** * GPS timeout interval in minutes * * @note Please change this timeout value as needed. */ //-------------------------------------------------------------------------------------------------- #define GPSTIMEOUT 15 //-------------------------------------------------------------------------------------------------- /** * Default phone number to send location information. * * @note This is a non-existent phone number (ref: * https://en.wikipedia.org/wiki/Fictitious_telephone_number). */ //-------------------------------------------------------------------------------------------------- #define DEFAULT_PHONE_NO "8005550101" //-------------------------------------------------------------------------------------------------- /** * Timer interval(in seconds) to exit from shutdown/ultralow-power state. * * @note Please change this interval as needed. */ //-------------------------------------------------------------------------------------------------- #define ULPM_EXIT_INTERVAL 30 //-------------------------------------------------------------------------------------------------- /** * Gpio used to exit from shutdown/ultralow-power state. * * @note Please change gpio number as needed. */ //-------------------------------------------------------------------------------------------------- #define WAKEUP_GPIO_NUM 38 //-------------------------------------------------------------------------------------------------- /** * Pointer to the null terminated string containing the destination phone number. */ //-------------------------------------------------------------------------------------------------- static const char *DestPhoneNumberPtr; //-------------------------------------------------------------------------------------------------- /** * Attempts to use the GPS to find the current latitude, longitude and horizontal accuracy within * the given timeout constraints. * * @return * - LE_OK on success * - LE_UNAVAILABLE if positioning services are unavailable * - LE_TIMEOUT if the timeout expires before successfully acquiring the location * * @note * Blocks until the location has been identified or the timeout has occurred. */ //-------------------------------------------------------------------------------------------------- static le_result_t GetCurrentLocation( int32_t *latitudePtr, ///< [OUT] latitude of device - set to NULL if not needed int32_t *longitudePtr, ///< [OUT] longitude of device - set to NULL if not needed int32_t *horizontalAccuracyPtr, ///< [OUT] horizontal accuracy of device - set to NULL if not ///< needed uint32_t timeoutInSeconds ///< [IN] duration to attempt to acquire location data before ///< giving up. A value of 0 means there is no timeout. ) { le_posCtrl_ActivationRef_t posCtrlRef = le_posCtrl_Request(); if (!posCtrlRef) { LE_ERROR("Can't activate the Positioning service"); return LE_UNAVAILABLE; } le_result_t result; const time_t startTime = time(NULL); LE_INFO("Checking GPS position"); while (true) { result = le_pos_Get2DLocation(latitudePtr, longitudePtr, horizontalAccuracyPtr); if (result == LE_OK) { break; } else if ( (timeoutInSeconds != 0) && (difftime(time(NULL), startTime) > (double)timeoutInSeconds)) { result = LE_TIMEOUT; break; } else { // Sleep for one second before requesting the location again. sleep(1); } } le_posCtrl_Release(posCtrlRef); return result; } //-------------------------------------------------------------------------------------------------- /** * Sends an SMS text message to the given destination with the given message content. * * @return * - LE_OK on success * - LE_FAULT on failure */ //-------------------------------------------------------------------------------------------------- static le_result_t SendTextMessage( const char *destinationNumberPtr, ///< [IN] Phone number to send the text message to as ASCII ///< values const char *messageBodyPtr ///< [IN] Text message body content ) { le_result_t result = LE_OK; LE_INFO("Sending SMS"); le_sms_MsgRef_t sms = le_sms_Create(); if (le_sms_SetDestination(sms, destinationNumberPtr) != LE_OK) { result = LE_FAULT; LE_ERROR("Could not set destination phone number"); goto sms_done; } if (le_sms_SetText(sms, messageBodyPtr) != LE_OK) { result = LE_FAULT; LE_ERROR("Could not set text message body"); goto sms_done; } if (le_sms_Send(sms) != LE_OK) { result = LE_FAULT; LE_ERROR("Could not send SMS message"); goto sms_done; } LE_INFO("SMS Message sent"); sms_done: le_sms_Delete(sms); return result; } //-------------------------------------------------------------------------------------------------- /** * Send the device location as a text message * * Attempts to send an SMS text message containing the current device location to the destination * phone number. * * @note * No failure notification is provided if location services or SMS send are unsuccessful. */ //-------------------------------------------------------------------------------------------------- static void SendSmsCurrentLocation( void ) { char smsBody[LE_SMS_TEXT_MAX_LEN]; int32_t latitude; int32_t longitude; int32_t horizontalAccuracy; const le_result_t result = GetCurrentLocation(&latitude, &longitude, &horizontalAccuracy, GPSTIMEOUT * 60); if (result == LE_OK) { snprintf(smsBody, sizeof(smsBody), "Loc:%d,%d", latitude, longitude); } else { strncpy(smsBody, "Loc:unknown", sizeof(smsBody)); } SendTextMessage(DestPhoneNumberPtr, smsBody); } //-------------------------------------------------------------------------------------------------- /** * Configure the boot source and shutdown MDM. */ //-------------------------------------------------------------------------------------------------- static void CfgShutDown ( void ) { // Boot after specified interval. if (le_ulpm_BootOnTimer(ULPM_EXIT_INTERVAL) != LE_OK) { LE_ERROR("Can't set timer as boot source"); return; } // Boot on gpio. Please note this is platform dependent, change it when needed. if (le_ulpm_BootOnGpio(WAKEUP_GPIO_NUM, LE_ULPM_GPIO_LOW) != LE_OK) { LE_ERROR("Can't set gpio: %d as boot source", WAKEUP_GPIO_NUM); return; } // Initiate shutdown. if (le_ulpm_ShutDown() != LE_OK) { LE_ERROR("Can't initiate shutdown."); } } //-------------------------------------------------------------------------------------------------- /** * Callback function to handle change of network registration state. */ //-------------------------------------------------------------------------------------------------- static void RegistrationStateHandler ( le_mrc_NetRegState_t state, ///< [IN] Network registration state. void *contextPtr ///< [IN] Context pointer. ) { switch(state) { case LE_MRC_REG_HOME: case LE_MRC_REG_ROAMING: LE_INFO("Registered"); SendSmsCurrentLocation(); LE_INFO("Now configure boot source and shutdown MDM"); CfgShutDown(); break; case LE_MRC_REG_SEARCHING: LE_INFO("Searching..."); break; case LE_MRC_REG_NONE: LE_INFO("Not registered"); break; case LE_MRC_REG_DENIED: LE_ERROR("Registration denied"); break; case LE_MRC_REG_UNKNOWN: LE_ERROR("Unknown registration state"); break; } } //-------------------------------------------------------------------------------------------------- /** * Simulate entry into the current NetReg state by calling RegistrationStateHandler * * RegistrationStateHandler will only be notified of state change events. This function exists to * simulate the change into the current state. */ //-------------------------------------------------------------------------------------------------- static void SimulateNetRegStateChangeToCurrentState( void *ignoredParam1, ///< Only exists to allow this function to conform to the ///< le_event_DeferredFunc_t declaration void *ignoredParam2 ///< Only exists to allow this function to conform to the ///< le_event_DeferredFunc_t declaration ) { le_mrc_NetRegState_t currentNetRegState; LE_FATAL_IF(le_mrc_GetNetRegState(¤tNetRegState) != LE_OK, "Couldn't get NetRegState"); RegistrationStateHandler(currentNetRegState, NULL); } //-------------------------------------------------------------------------------------------------- /** * Get the destination phone number. **/ //-------------------------------------------------------------------------------------------------- static void GetDestinationCellNo ( void ) { DestPhoneNumberPtr = getenv("DEST_CELL_NO"); if (!DestPhoneNumberPtr) { LE_WARN( "No destination cell number is specified. Using a default non-existent number"); DestPhoneNumberPtr = DEFAULT_PHONE_NO; } LE_INFO("Destination phone number = %s", DestPhoneNumberPtr); } COMPONENT_INIT { char version[LE_ULPM_MAX_VERS_LEN + 1]; LE_INFO("TextLoc started"); // Get ultra low power manager firmware version LE_FATAL_IF( le_ulpm_GetFirmwareVersion(version, sizeof(version)) != LE_OK, "Failed to get ultra low power firmware version"); LE_INFO("Ultra Low Power Manager Firmware version: %s", version); // Now check whether boot was due to timer expiry. if (le_bootReason_WasTimer()) { LE_INFO("Booted from timer, not sending another text message."); } else if (le_bootReason_WasGpio(WAKEUP_GPIO_NUM)) { LE_INFO("Booted from GPIO, not sending another text message."); } else { // Get the destination phone number GetDestinationCellNo(); // Register a callback handler for network registration state. le_mrc_AddNetRegStateEventHandler( (le_mrc_NetRegStateHandlerFunc_t)RegistrationStateHandler, NULL); le_event_QueueFunction(&SimulateNetRegStateChangeToCurrentState, NULL, NULL); } } The textLoc.adef file is: textLoc.adef sandboxed: false version: 1.0.0 maxFileSystemBytes: 512K executables: { textloc = ( textLocComponent ) } processes: { envVars: { LE_LOG_LEVEL = DEBUG // This is a non-existent fictitious phone number. Change it to a valid phone number. DEST_CELL_NO = 8005550101 } run: { ( textloc ) } maxCoreDumpFileBytes: 512K maxFileBytes: 512K } bindings: { textloc.textLocComponent.le_mrc -> modemService.le_mrc textloc.textLocComponent.le_posCtrl -> positioningService.le_posCtrl textloc.textLocComponent.le_pos -> positioningService.le_pos textloc.textLocComponent.le_sms -> modemService.le_sms textloc.textLocComponent.le_ulpm -> powerMgr.le_ulpm textloc.textLocComponent.le_bootReason -> powerMgr.le_bootReason } The Component.cdef: Component.cdef requires: { api: { modemServices/le_mrc.api modemServices/le_sms.api positioning/le_posCtrl.api positioning/le_pos.api le_ulpm.api le_bootReason.api } } sources: { textLoc.c } Makefile: Makefile TARGETS := $(MAKECMDGOALS) .PHONY: all $(TARGETS) all: $(TARGETS) $(TARGETS): mkapp -v -t $@ \ textLoc.adef clean: rm -rf _build_* *.update
Have questions or comments? Continue the conversation on TechForum, Digi-Key's online community and technical resource.
Visit TechForum
