Child pages
  • MangOH Red
Skip to end of metadata
Go to start of metadata


Product Description

The mangOH™ Red is a low-power Internet of Things (IoT) platform that will run on battery power for up to 10 years.  According to mangoh.io it is:

  • A credit card size form-factor ideal for rapidly building proof-of-concepts;
  • A snap-in socket to add any CF3™ compatible modules, including wireless modules (2G to 4G & LTE-M/NB-Iot) to achieve up to 10 years of battery life (The CF3 module used for this article was the WP8548_1103113 (Digi-Key part number 1645-1022-1-ND)).;
  • An IoT Expansion Card slot to plug in any technology based on the IoT Expansion Card open standard;
  • An integrated Sierra Wireless Smart SIM with up to 100 MB fee data, depending on region, and can also be used with any commercially available SIM;
  • Integrated with AirVantage IoT platform to create, deploy and manage solutions in the cloud;
  • Built-in Wi-Fi b/g/n and Bluetooth 4.2 BLE with a Cortex M4 to provide real-time access to I/O; and
  • Built-in Accelerometer/Gyroscope, Pressure and Light sensors along with a 26-pin Raspberry Pi-compatible connector (the connector cable is Digi-Key Electronics part number 1597-1065-ND).

What's in the Box

The box we opened included the following:

  • mangOH Red
  • CF3 Module (in our case WP8548_1103113)
  • Micro-USB cable
  • 2 Antennae (1 main and 1 Global Navigation Satellite System (GNSS))
  • Sierra Wireless micro-SIM card with initial data allocation

Hardware Setup

Follow the setup instructions found in the mangOH Red User and Setup Guide.

There are two micro-USB ports on the mangOH Red.

Hardware setup was straight forward: plug micro-usb into mangOH and into a computer, connect antennae, and put SIM card in slot on the back of the mangOH.  I have attached a hardware architecture illustration from mangOH Red Developers Guide :

 

Raspberry Pi Connector

The Digi-Key part number for the ribbon cable connector is 1597-1065-ND. I have inserted the pinout diagram for both the Raspberry Pi (the Raspberry Pi pinout diagram will lead you to an interactive diagram) and the Mangoh Red:  The connections are pin 1 to pin 1, pin 2 to pin 2, etc.

 

Software Setup

Software setup was a little more involved.  When starting on the journey to work with this device, it is well worth noting that there are three entities involved in the final product of the mangOH.  MangOH Red is the board itself, Sierra Wireless is the maker of the CF3 module as well as the owner of AirVantage, which is the IoT Cloud that stores the data from the mangOH, and Legato, the Linux based Command Line Interface (CLI) used to connect with the mangOH. I will discuss each of these and how to connect to their forums as we go along on our journey.

The first website to visit is the Getting Started with mangOH website.  You can choose either Windows or Linux operating system (Mac OS is compatible as well but I will discuss that later). Whichever OS you choose, you will still need to incorporate Legato CLI either through a virtual machine (Oracle VirtualBox) on Windows or an add-on for Legato development on Linux. The Windows setup manual  and the Linux setup manual are excellent resources to use when setting up your machine so I won't regurgitate that information here.

If you are using a 64-bit Linux machine, pay attention to item #6 on page 16 of the Linux setup manual.

You should also download Developer Studio, which is available for Windows, Linux and Mac operating systems. According to the Sierra Wireless website, "Developer Studio is the Sierra Wireless IDE (Integrated Development Environment) for Legato Application Framework".  What this means is you have two options for creating your own apps; you can use a basic text program or you can use Developer Studio, which is graphically based and will automate some of the file/folder creation.  I downloaded the Developer Studio for each operating system and the only hiccup I had was the Java 8 requirement for Mac OS, the regular install of Java 8 wasn't enough for Developer Studio to run for some reason so I ended up downloading and installing the Java SE Development Kit 8u151 from Oracle.

For Linux installation of Developer Studio

 

Sample Apps and File Structure

The best place to begin, after you have the mangOH setup, is Legato on Github. Download or clone the Legato folder   You will also want to visit Legato sample apps explanations for some of the samples you downloaded on Github.  The Legato sample apps website is also a great resource for "How To's".

The file structure is something to pay attention to as well. Each application has the following directory/file structure:

The file structure may also include .API and .h file types, depending on the application.  The meat of the programming is in the .c file while the other files are instructions to the compiler for creating the application.

Example: GNSS Location Text App

The sample application that illustrates a lot of what the mangOH Red can do is the app that will text the coordinates of the mangOH Red to the user.  The file structure is above. 

The code for the textLoc.c file is included below: 

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(&currentNetRegState) != 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

 

Legato Links

Legato Forum

mangOH Forum

Sierra Wireless Forum

Legato Github Page

mangOH Github Page

mangOH Red User and Setup Guide

Little Slice of mangOH

 

 

  • No labels