Examples: Hello World!¶
Overview¶
The “Hello World” example (sometimes lovingly referred to as “Blinky”) is an end-to-end example that shows basic Moto Mods functionality (by controlling the LED on the Reference Moto Mod). It includes open source firmware and is driven by the MDK Utility app (see the MDK Utility Example page for more details, including Flashing & Developer support).
The purpose of this example is to:
- Provide a “Hello World” example (aka “Blinky”)
- Demonstrate end-to-end implementation of Moto Mods functionality
- Provide control to LED located in Reference Moto Mod
Before you begin...¶
Required Hardware¶
This app and example requires a Moto Z and Reference Moto Mod. To get started, you'll need to buy the required hardware.
Software and Tools¶
See the Build > Tools section to set up your development environment and learn about building from source, flashing firmware, and how to debug & log.
Download Example Source Code¶
- Open source application code for the MDK Utility App is available at https://github.com/jksim/mdkutility.
- Open source firmware code for this example is located at https://github.com/jksim/nuttx - specifically:
- Build Target: https://github.com/jksim/nuttx/tree/master/nuttx/configs/hdk/muc/blinky
- Source Directory: https://github.com/jksim/nuttx/tree/master/nuttx/configs/hdk/muc/src
‘MDK Utility’ App¶
MDK Utility is a simple app that provides an end-to-end ‘Hello World’ example that shows how to control the LED on the Reference Moto Mod.
The MDK Utility App will only work on Moto Z devices.
- MDK Utility app (rebuilt from source; was on Google Play Store)
- MDK Utility app (rebuilt from source; was on Lenovo App Store)
For more details, see the Moto Mods Android Application section further down this page.
Community and Support¶
Ask questions, engage with the developer community, and get support for this example in the Moto Mods group at element14.com. Also check out our Support page.
Firmware Development¶
Firmware¶
Follow these instructions to setup your firmware development environment and download source code if it has not been done already. The base source code has a target for blinky. The information below details the steps to create the firmware for blinky, if it did not exist before.
New Build Target¶
Create a new build target for blinky using hdk/muc/base_powered target as the base.
Switch to using the new build target.
The following features in nuttx are to be enabled to support blinky functionality.
- Greybus RAW protocol
- Timer 6
menuconfig support¶
To integrate into menuconfig and the build system, two files must be updated.
nuttx/nuttx/configs/hdk/muc/Kconfig
config MODS_RAW_BLINKY
bool "Blinky LED Mods Raw support"
default n
depends on GREYBUS_RAW
select DEVICE_CORE
select STM32_TIM6
---help---
Enable Blinky LED Raw support
nuttx/nuttx/configs/hdk/muc/src/Makefile
Raw Protocol¶
Files¶
nuttx/drivers/greybus/raw.c- Raw protocol
Configuration Changes¶
Set the configuration options to enable Raw Protocol.
Timer6¶
Set the configuration options to enable timer6.
Blinking LED (Blinky) Device Driver¶
The driver implements blinking LED control with ON/OFF data exchange over raw protocol between Moto Z and the reference mod.
In addition the driver also toggles a control GPIO(to control optional external circuitry) based on the same blinky ON/OFF commands.
Files¶
nuttx/configs/hdk/muc/src/stm32_modsraw_blinky.c- raw protocol device driver for blinking LED control.
Blinky Raw Protocol¶
Message format: (Table coming soon...)
Message Commands: data sent from apk to HDK 0 or ‘0’ for OFF command. Non-zero value for ON command.
Driver Details¶
stm32_modsraw_blinky.c
This driver is based on nuttx/nuttx/configs/hdk/muc/src/stm32_modsraw.c
static struct device_raw_type_ops blinky_type_ops = {
.recv = blinky_recv,
.register_callback = blinky_register_callback,
.unregister_callback = blinky_unregister_callback,
};
static struct device_driver_ops blinky_driver_ops = {
.probe = blinky_probe,
.type_ops = &blinky_type_ops,
};
struct device_driver mods_raw_blinky_driver = {
.type = DEVICE_TYPE_RAW_HW,
.name = "mods_raw_blinky",
.desc = "Blinky LED Raw Interface",
.ops = &blinky_driver_ops,
};
Setup the GPIO and initialize the pin in the driver.
In stm32_boot.c
{ GPIO_MODS_LED_DRV_3, (GPIO_OPENDRAIN) },
In stm32_modsraw_blinky.c
static int blinky_probe(struct device *dev)
{
gpio_direction_out(GPIO_MODS_LED_DRV_3, LED_OFF);
gpio_direction_out(GPIO_MODS_DEMO_ENABLE, 0);
return 0;
}
Implement raw message handling in blinky_recv().
Turn ON LED blinking with any non-zero value.
static int blinky_recv(struct device *dev, uint32_t len, uint8_t data[])
{
if (len == 0)
return -EINVAL;
if (data[1] == 0 || data[1] == '0')
blinky_timer_stop();
else
blinky_timer_start();
return 0;
}
Initialize and setup timer functionality for the timer handler be triggered every 1000 milliseconds
#define BLINKY_ACTIVITY 10
#define BLINKY_TIM 6
#define BLINKY_TIM_FREQ 1000
#define BLINKY_PERIOD 1000
----
static void blinky_timer_start(void)
{
gpio_set_value(GPIO_MODS_DEMO_ENABLE, 1);
----
tim_dev = stm32_tim_init(BLINKY_TIM);
DEBUGASSERT(tim_dev);
STM32_TIM_SETPERIOD(tim_dev, BLINKY_PERIOD);
STM32_TIM_SETCLOCK(tim_dev, BLINKY_TIM_FREQ);
STM32_TIM_SETMODE(tim_dev, STM32_TIM_MODE_PULSE);
STM32_TIM_SETISR(tim_dev, blinky_timer_handler, 0);
STM32_TIM_ENABLEINT(tim_dev, 0);
In timer handler function, toggle the GPIO level.
static int blinky_timer_handler(int irq, FAR void *context)
{
----
new_val = gpio_get_value(GPIO_MODS_LED_DRV_3) ^ 1;
gpio_set_value(GPIO_MODS_LED_DRV_3, new_val);
---
Disable the timer and assert the GPIO to stop the LED blinking
static void blinky_timer_stop(void)
{
gpio_set_value(GPIO_MODS_DEMO_ENABLE, 0);
----
STM32_TIM_DISABLEINT(tim_dev, 0);
stm32_tim_deinit(tim_dev);
tim_dev = NULL;
gpio_set_value(GPIO_MODS_LED_DRV_3, LED_OFF);
-----
Driver and Device Initialization¶
MDK has LED connected over GPIO pin PE8
Define the GPIO for LED control at $BUILD_TOP/nuttx/nuttx/configs/hdk/muc/include/mods.h
Control GPIO to enable/signal any external circuitry
Define the control GPIO at $BUILD_TOP/nuttx/nuttx/configs/hdk/muc/include/mods.h
The device driver is initialized in $BUILD_TOP/nuttx/nuttx/configs/hdk/muc/src/stm32_boot.c.
Entry in the devices[] array.
#ifdef CONFIG_MODS_RAW_BLINKY
{
.type = DEVICE_TYPE_RAW_HW,
.name = "mods_raw_blinky",
.desc = "Blinky LED Raw Interface",
.id = 0,
},
#endif
Part of the board_initialize() function.
#ifdef CONFIG_MODS_RAW_BLINKY
extern struct device_driver mods_raw_blinky_driver;
device_register_driver(&mods_raw_blinky_driver);
#endif
Configuration Changes¶
Set the configuration options to enable the raw protocol device driver for Blinky.
Hardware Manifest¶
New Manifest¶
Create hardware manifest for the example using apps/greybus-utils/manifests/hdk-powered.mnfs as the base.
Edit the hdk-blinky.mnfs file to change the interface string and add Raw Interfaces and Bundle.
; RAW interface on CPort 4
[cport-descriptor 4]
bundle = 3
protocol = 0xfe
; RAW Bundle 3
[bundle-descriptor 3]
class = 0xfe
Setting the Manifest¶
Set the configuration options to use the newly created manifest.
Application Configuration --->
-*- Greybus utility --->
Select a predefined Manifest (Custom manifest)
(hdk-termapp) manifest name
Building and Flashing Firmware¶
The new target supports all required functionality now. The firmware can be built and flashed into the Reference Moto Mod. Make sure that the Moto Mod is running in development mode as per these instructions or build and flash the development bootloader yourself as documented here.
Moto Mods Android Application¶
MDK Utility sample APK¶
The MDK Utility sample APK is an open source project, works as an downloadable Android app, to show the capability to toggle the MDK LED.
Install APK¶
Download and install the MDK Utility sample APK - see MDK Utility app (rebuilt from source; was on Google Play Store)
Source code¶
The source code of the MDK Utility sample APK is published at https://github.com/jksim/mdkutility.
To build the sample APK from source code, please download and install Android Studio from Android Developer Site, then import the mdkutility project into Android Studio. See Developer Tools: Setup Your Development Environment for more info.
Sequence Diagram¶
(Diagram coming soon…)
Reference¶
Reference for ModManager interface:¶
Intent service = new Intent(ModManager.ACTION_BIND_MANAGER);
service.setComponent(ModManager.MOD_SERVICE_NAME);
bindService(service, mConnection, Context.BIND_AUTO_CREATE);
private ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className,
IBinder binder) {
IModManager mMgrSrvc = IModManager.Stub.asInterface(binder);
modManager = new ModManager(context, mMgrSrvc);
onModAttached(true);
}
public void onServiceDisconnected(ComponentName className) {
modDevice = null;
modManager = null;
onModAttached(false);
}
};
Reference for ModService events:¶
/** Register Mod intents receiver */
modReceiver = new MyBroadcastReceiver();
IntentFilter filter = new IntentFilter(ModManager.ACTION_MOD_ATTACH);
filter.addAction(ModManager.ACTION_MOD_DETACH);
/**
* Request the broadcaster who send these intents must hold permission PERMISSION_MOD_INTERNAL,
* to avoid the intent from fake senders. For future details, refer to:
* https://developer.android.com/reference/android/content/Context.html#registerReceiver
*/
context.registerReceiver(modReceiver, filter, ModManager.PERMISSION_MOD_INTERNAL, null);
Query Mod status:¶
List<ModDevice> l = modManager.getModList(true);
if (l == null || l.size() == 0) {
Log.d(Constants.TAG, "Mod device invalid”);
return;
}
for (ModDevice d : l) {
Log.d(Constants.TAG, "Mod device Info: " + d);
}
Reference for ModManager RAW protocol:¶
List<ModInterfaceDelegation> devices =
modManager.getModInterfaceDelegationsByProtocol(modDevice,
ModProtocol.Protocol.RAW);
if (devices != null && !devices.isEmpty()) {
// TODO: go through the whole devices list for multi connected devices.
// Here simply operate the first device for this example.
ModInterfaceDelegation device = devices.get(0);
/**
* Be care to strict follow Android policy, you need visibly asking for
* grant permission.
*/
if (context.checkSelfPermission(ModManager.PERMISSION_USE_RAW_PROTOCOL)
!= PackageManager.PERMISSION_GRANTED) {
onRequestRawPermission();
} else {
/** The RAW_PROTOCOL permission already granted, open RAW I/O */
getRawPfd(device);
return true;
}
}
Execute RAW command:¶
public static byte[] RAW_CMD_LED_ON = {0x01};
public static byte[] RAW_CMD_LED_OFF = {0x00};
// Turn ON LED
byte[] cmd = RAW_CMD_LED_ON;
outputStream.write(cmd);
// Turn OFF LED
byte[] cmd = RAW_CMD_LED_OFF;
outputStream.write(cmd);
Verify¶
1) Attach MDK to phone, then install and launch MDK Utility sample apk: (Screenshot coming soon...)
2) Check the Mod / Personality card status and information, then turn on/off LED switcher UI to enable LED to blink: (Screenshot coming soon...)
3) The LED light on board should blink.