Setup and Tools

What you need:

  • Moto Z
  • Computer running Linux (including as a virtual machine)
  • Moto Mods Development Kit
  • USB Type-C cable

Tools Setup

http://developer.motorola.com/build/tools/setup-environment

Clone and Build

http://developer.motorola.com/build/tools/build-from-source

Flash Bootloader and Firmware

http://developer.motorola.com/build/tools/flashing-firmware

 

Example and Developer Modes

Example Mode simplifies switching between Personality Cards

  • VID = 0x312
  • Custom bootloader that reads the PID from an EEPROM in the Personality Card.
  • The Moto Z will download and update the firmware
  • Example firmwares monitor switches at the 80pin header to detect insertion/removal.  The MuC resets on transition.

Always detach the Reference Moto Mod from the Moto Z before inserting/removing a Personality Card.

 

Developer Mode lets you hack without system interference

  • VID = 0x42
  • Bypass Moto Z’s firmware update check
  • Flash firmware using the MDK Utility
  • “developer” config in the muc-loader repository

The MDK Utility requires Personality Cards removed from the Reference Moto Mod before allowing the switch to Developer mode.

Screenshot_20160720-200721.png

Blinky

Blinky is the “Hello, World!” of Moto Mods.

  • Raw protocol used for simple on/off switch
  • Uses hdk_powered as the base project with battery and charging support

 

Firmware Reference Paths

 

Manifest

nuttx/apps/greybus-utils/manifests/hdk-blinky.mnfs

Project Definition

nuttx/nuttx/config/hdk/muc/blinky

Kconfig

nuttx/nuttx/config/hdk/muc/Kconfig

Makefile

nuttx/nuttx/config/hdk/muc/src/Makefile

Source Files

nuttx/nuttx/config/hdk/muc/src

 

nuttx/apps/greybus-utils/manifests/hdk-blinky.mnfs

 

[manifest-header]

version-major = 0

version-minor = 1

Version of the Manifest file

[interface-descriptor]

vendor-string-id = 1

product-string-id = 2

; Interface vendor string (id can't be 0)

[string-descriptor 1]

string = Motorola Mobility, LLC

; Interface product string (id can't be 0)

[string-descriptor 2]

string = MDK-BLINKY

Vendor and Product String definitions

; Control protocol on CPort 0

[cport-descriptor 0]

bundle = 0

protocol = 0x00

; Control protocol Bundle 0

[bundle-descriptor 0]

class = 0

; Motorola specific on CPort 1

[cport-descriptor 1]

bundle = 1

protocol = 0xff

; Debug related Bundle 1

[bundle-descriptor 1]

class = 0xff

Greybus and Moto Mod interfaces for enumeration, communication, and control.

; Battery on CPort 2

[cport-descriptor 2]

bundle = 2

protocol = 0x08

 

; PTP on CPort 3

[cport-descriptor 3]

bundle = 2

protocol = 0xef

 

; Battery related Bundle 2

[bundle-descriptor 2]

class = 0x08

Battery and Power Transfer Protocols for metering and charging.

 

These are grouped together into a single Bundle, meaning both must enumerate properly for either to be accessible.

; RAW interface on CPort 4

[cport-descriptor 4]

bundle = 3

protocol = 0xfe

 

; RAW Bundle 3

[bundle-descriptor 3]

class = 0xfe

Raw Protocol, used for basic on/off switch.

 

 

Blinky is based off hdk-powered.mnfs.  hdk.mnfs should be used if your project does not require a battery.

 

nuttx/nuttx/config/hdk/muc/blinky Project Files

 

Make.defs

Makefile definitions

setenv.sh

Script to configure environment to build

defconfig

Moto Mod interfaces for enumeration, communication, and control.


Modified via “make menuconfig”

 

After creating your project, make it the active one:

cd $BUILD_TOP/nuttx/nuttx

make distclean

cd $BUILD_TOP/nuttx/nuttx/tools

./configure hdk/muc/blinky

cd $BUILD_TOP/nuttx/nuttx

make

 

Blinky is based off of base-powered.  base_unpowered should be used if your project does not require a battery.

 

nuttx/nuttx/config/hdk/muc/Kconfig

 

Update Kconfig to add your new project’s support:

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

 

This integrates Blinky with the ‘make menuconfig’ and defines any build dependencies needed to support the ‘Board Selection’ step later.   A primer on the NuttX menuconfig is available here:

http://www.programering.com/a/MjN1gjMwATE.html

 

Additional information on configuring NuttX can be found here:

http://nuttx.org/doku.php?id=documentation:configvars

http://nuttx.org/doku.php?id=documentation:menuconfig

 

Update the VID/PID

Go to the nuttx top and run use menuconfig

cd $BUILD_TOP/nuttx/nuttx

make menuconfig

Select “System Type” from the top level menu

 

Update the Board VID and PID

For Developer Mode:

VID = 0x42

PID = 0x1

 

Select <Save>, then <Exit> to the top level

Board Selection

Select “Board Selection” from the top level menu

Scroll to “Blinky LED Mods Raw Support” and press the space bar to toggle On

 

Select <Save>, then <Exit> to the top level

Setting the Manifest

1. Select “Application Configuration” from the top level menu

2. Select “Greybus Utility”

3. Select “manifest name”.  Type “hdk-blinky” in the dialog box and press Enter. 

Select <Save>, then <Exit> to the top level

Setup Raw Support

1. Select “Device Drivers” from the top level menu

2. Select “Greybus Support”

3. Scroll to “Vendor Raw Support” and press the space bar to toggle On

 

Select <Save>, then <Exit> to the top level

Enable Timer6 for LED Toggle Interrupts

1. Select “System Type” from the top level menu

 

2. Select “STM32 Peripheral Support”

3. Scroll to “TIM6” and press the space bar to toggle On

 

Select <Save>, then <Exit> to the top level

Update the Makefile

Add the new files to nuttx/nuttx/config/hdk/muc/src/Makefile

ifeq ($(CONFIG_MODS_RAW_BLINKY),y)

CSRCS += stm32_modsraw_blinky.c

endif

 

To ensure the changes made with “make menuconfig” are permanent, the nuttx/nuttx/.config should be copied over top the nuttx/nuttx/config/hdk/muc/{project}/defconfig

Setup Raw Device Driver

Copy stm32_modsraw.c to stm32_modsraw_blinky.c to use as a starting point.

Customize the device_driver and associated structures:

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,

};

Implement Driver Functions

From the ops structures, there are 4 functions to be implemented for Raw:

  • blinky_probe()
    • Called by kernel after device registration
  • blinky_recv()
    • Called by greybus when data has arrived on the Raw channel
  • blinky_register_callback()
    • Called by kernel to provide a pointer to the raw_send_callback.  The driver should save this pointer and use when sending data to the Moto Z
  • blinky_unregister_callback()
    • Called by the kernel when the device is no longer registered

 

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;

}

static int blinky_recv(struct device *dev, uint32_t len, uint8_t data[])

{

    if (len == 0)

        return -EINVAL;

    if (data[0] == 0 || data[0] == '0')

        blinky_timer_stop();

    else

        blinky_timer_start();

 

   return 0;

}

Implement Behavior

For Blinky, 3 other functions are implemented to provide the actual behavior:

  • blinky_timer_start()
    • Called when a Raw message arrives with the ON command
    • Creates and starts the timer used to blink the LED on the Reference Moto Mod on and off
  • blinky_timer_stop()
    • Called when a Raw message arrives with the OFF command
    • Cancels the running timer and ensures the LED is off
  • blinky_timer_handler()
    • Handles interrupts from the timer and toggles the GPIO state

 

These functions also reside in stm32_modsraw_blinky.c

Register the Device Driver

  • Open nuttx/nuttx/configs/hdk/muc/src/stm32_boot.c
  • In the devices[] array, add the following:

 

#ifdef CONFIG_MODS_RAW_BLINKY

    {

        .type = DEVICE_TYPE_RAW_HW,

        .name = "mods_raw_blinky",

        .desc = "Blinky LED Raw Interface",

        .id   = 0,

    },

#endif

 

  • In the board_initialize() function, add the following:

 

#ifdef CONFIG_MODS_RAW_BLINKY

  extern struct device_driver mods_raw_blinky_driver;

  device_register_driver(&mods_raw_blinky_driver);

#endif

 

Blinky Support Application (MDK Utility)

Your Moto Mod project may require an Android application to unlock its full capabilities.  To this end, Moto has released the modlib.  This library enables your app to query and receive Moto Mods status, as well as controls specific to the different Protocols.

 

Blinky uses two main components from the modlib:

  1. ModManager
    1. Provides Moto Mod Connect/Disconnect status
    2. Provides details about currently attached Moto Mod
    3. Allows access to Moto Mod protocols and handles permissions
  2. Raw access
    1. Retrieve File Descriptor to talk to the Moto Mod’s Raw protocol

 

The MDK Utility provides other developer functionality as well.  See http://developer.motorola.com/build/examples/mdk-utility for more detail.

Blinky Application Setup

Ensure that Android Studio 2.0 and the Android SDK API 23 is installed.

Download the modlib from http://developer.motorola.com/build/tools/setup-environment

Open Android Studio and create a New Project

 

Then add the modlib.jar and version.xml files to your Project

cp modlib-{version}.jar $APP_TOP/app/libs

cp res/version.xml $APP_TOP/app/src/main/res/values

 

AndroidManifest.xml for all Moto Mods

To be a Moto Mods aware application, features and permissions must be added:

 

<uses-feature android:name="com.motorola.hardware.mods"/>

This defines your application as using the Moto Mods feature for Play Store filtering

 

<meta-data

   android:name="com.motorola.mod.version"

   android:value="@integer/moto_mod_services_version" />

This uses the value from the version.xml file as the Moto Mods Services version.  This is used for future compatibility checks as Moto Mods capabilities expand.

 

<uses-permission android:name="com.motorola.mod.permission.MOD_ACCESS_INFO" />

This permission allows access to the ModManager for access to Moto Mods information

 

 

Blinky access to the Raw Protocol

Blinky makes use of the Raw protocol as a custom data path to turn the LED on and off.  Since the Raw protocol provides direct access to communicate with the Moto Mod, it is protected by a unique permission in the AndroidManifest.xml.

<uses-permission android:name="com.motorola.mod.permission.RAW_PROTOCOL" />

This permission (when granted by the user) allows this Application to access the Raw protocol.

 

Before opening Raw, you should always check the VID/PID to ensure this is the Moto Mod you wish to communicate with.  And, of course, check with the user:

requestPermissions(new String[]{ModManager.PERMISSION_USE_RAW_PROTOCOL},

                   REQUEST_RAW_PERMISSION);

 

Implement onRequestPermissionsResult() to handle the result of the Permission request.  Only request the Raw file descriptor after receiving Permission or an exception will be thrown.

Handling Moto Mods State

Obtaining the basic of Moto Mods is done through the ModManager.  First and foremost, your application should determine whether the current device supports Moto Mods.

if(ModManager.isModServicesAvailable(context) == ModManager.SUCCESS) {
  // This device supports Moto Mods

}

 

The Moto Mods state can either be monitored through Intents, or via direct callbacks from the ModManager.  Blinky makes use of a BroadcastReceiver and Intents.

modReceiver = new MyBroadcastReceiver();

IntentFilter filter = new IntentFilter(ModManager.ACTION_MOD_ATTACH);

filter.addAction(ModManager.ACTION_MOD_DETACH);

context.registerReceiver(modReceiver, filter, ModManager.PERMISSION_MOD_INTERNAL, null);

 

For additional information on the ModManager, refer to http://developer.motorola.com/explore/software/mod-management

Check what was attached

As mentioned earlier, when using the Raw protocol you should always verify the VID/PID.  Never open the Raw protocol simply because it is available, since the actual data will be custom to that product.

String action = intent.getAction();

if(action != null ){

if(action.equals(ModManager.ACTION_MOD_ATTACH)){

int vid = intent.getIntExtra(ModManager.EXTRA_VENDOR_ID,
           INVALID_ID);

int pid = intent.getIntExtra(ModManager.EXTRA_PRODUCT_ID,
           INVALID_ID);

if ((vid == MY_BLINKY_VID) && (pid == MY_BLINKY_PID)) {

startRawService();

}

}

}



When using Raw, reads and writes should be done separate from the UI thread.  The MDK Utility handles this via the RawPersonalityService class.

Opening the Raw Interface

The Raw protocol is exposed to Android applications via a ParcelFileDescriptor provided by the ModManager:

 

List<ModInterfaceDelegation> devices =

       modManager.getModInterfaceDelegationsByProtocol(modDevice,

               ModProtocol.Protocol.RAW);

if (devices != null && !devices.isEmpty()) {

   ModInterfaceDelegation device = devices.get(0);

   Log.d(Constants.TAG, "openRawDeviceifAvailable checking " + device);

 

   parcelFD = modManager.openModInterface(device,

           ParcelFileDescriptor.MODE_READ_WRITE);

 

This code block obtains the Raw interface and retrieves a file descriptor that is used for direct read/write access.

Sending Data over Raw

FileDescriptor fd = parcelFD.getFileDescriptor();

outputStream = new FileOutputStream(fd);

outputStream.write((byte[]) cmd);

 

Although sending data over Raw appears simple, this should always be performed on a separate Thread from the UI or via an AsyncTask.  Otherwise, you will may receive ANR while your application is attempting to communicate with the Moto Mod.