MangOH Red
제품 설명
mangOH™ Red는 배터리 전력으로 최대 10년 동안 실행되는 저전력 사물 인터넷(IoT) 플랫폼입니다. mangoh.io에 따르면 mangOH™ Red는 다음과 같이 정의됩니다.
- 개념 증명을 신속하게 구축할 수 있는 신용카드 크기의 폼 팩터
- 무선 모듈(2G~4G 및 LTE-M/NB-IoT)을 포함한 모든 CF3™ 호환 모듈을 추가할 수 있고 최대 10년의 배터리 수명을 자랑하는 스냅인 소켓(이 기사에 사용된 CF3 모듈은 WP8548_1103113임(DigiKey 부품 번호1645-1022-1-ND))
- IoT 확장 카드 공개 표준을 기반으로 하는 모든 기술에 연결할 수 있는 IoT 확장 카드 슬롯
- 지역에 따라 최대 100MB의 무료 데이터가 제공되며 시판되는 모든 SIM에 사용할 수 있는 통합 Sierra Wireless 스마트 SIM
- AirVantage IoT 플랫폼과 통합되어 클라우드에서 솔루션을 제작, 배포, 관리함
- Cortex-M4를 탑재한 내장형 Wi-Fi b/g/n 및 Bluetooth 4.2 BLE로 실시간 I/O 액세스 제공
- 내장형 가속도계/자이로스코프, 압력 및 조명 센서, 26핀 Raspberry Pi 호환 가능 커넥터(커넥터 케이블의 DigiKey 부품 번호: 1597-1065-ND).
(이미지 출처: Talon Communications Inc.)
구성품
상자를 개봉하면 다음과 같은 부품이 포함되어 있습니다.
- mangOH Red
- CF3 모듈(이 경우 WP8548_1103113)
- 마이크로 USB 케이블
- 안테나 2개(주 안테나 1개, GNSS(Global Navigation Satellite System) 1개)
- 초기 데이터가 할당된 Sierra Wireless 마이크로 SIM 카드
하드웨어 설정
mangOH Red 사용 및 설정 안내서에 나오는 설정 지침을 따르세요.
mangOH Red에는 마이크로 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의 최종 제품에 세 개의 개체가 포함되어 있다는 것에 유의하세요. MangOH Red는 그 자체로 기판이고, Sierra Wireless는 CF3 모듈 제조업체이자 AirVantage(mangOH의 데이터를 저장하는 IoT 클라우드) 및 Legato(mangOH와 연결하는 데 사용되는 Linux 기반 명령줄 인터페이스(CLI))의 소유업체입니다. 각 항목에 대해 소개하고 과정을 진행하면서 포럼에 연결하는 방법을 살펴보겠습니다.
방문할 첫 번째 웹 사이트는 mangOH 시작하기 웹 사이트입니다. Windows 또는 Linux 운영 체제를 선택할 수 있습니다. Mac OS도 호환되지만 나중에 살펴보겠습니다. 어떤 OS를 선택하든 상관없이 Windows의 가상 머신(Oracle VirtualBox) 또는 Linux의 Legato 개발용 추가 기능을 통해 Legato CLI를 통합해야 합니다. Windows 설정 설명서 및 Linux 설정 설명서는 머신을 설정할 때 사용할 수 있는 유용한 리소스입니다. 여기서는 해당 내용을 반복해서 설명하지 않겠습니다.
64비트 Linux 기기를 사용 중인 경우 Linux 설정 설명서 16페이지의 항목 6번에 유의하세요.
또한 Developer Studio(Windows, Linux 및 Mac 운영 체제용으로 제공됨)를 다운로드해야 합니다. Sierra Wireless 웹 사이트에 따르면 'Developer Studio는 Legato 애플리케이션 프레임워크를 위한 Sierra Wireless IDE(Integrated Development Environment)입니다'. 이는 두 가지 옵션을 사용하여 앱을 생성할 수 있다는 것을 의미합니다. 즉, 기본 텍스트 프로그램을 사용하거나, 파일/폴더 생성을 자동화하는 그래픽 기반의 Developer Studio를 사용할 수 있습니다. 제 경우에는 각 운영 체제에 대한 Developer Studio를 다운로드했으므로 Mac OS에 대한 Java 8 요구 사항만 해결하면 되었습니다. Java 8 일반 설치로는 Developer Studio를 실행하는 데 충분하지 않아서 결국 Oracle에서 Java SE Development Kit 8u151을 다운로드하여 설치했습니다.
샘플 앱 및 파일 구조
mangOH를 설정한 후 Github의 Legato로 시작하는 것이 좋습니다. Legato 폴더를 다운로드하거나 복제하십시오. 또한 Github에서 다운로드한 몇 가지 샘플에 대한 Legato 샘플 앱 설명을 참조할 수 있습니다. Legato 샘플 앱 웹 사이트에서도 '유용한 방법'과 관련된 자료를 확인할 수 있습니다.
파일 구조에도 주의해야 합니다. 각 애플리케이션의 디렉터리/파일 구조는 다음과 같습니다.
애플리케이션에 따라 .API 및 .h 파일 형식이 파일 구조에 포함될 수도 있습니다. 프로그래밍의 핵심은 .c 파일에 있으며, 다른 파일은 애플리케이션을 만들기 위한 컴파일러 지침입니다.
예: GNSS Location Text App
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