Upload
paul-blundell
View
203
Download
0
Embed Size (px)
Citation preview
solid foundationsPaul BlundellXavi Rigau
CamerasGatewaysHVAC ControlSmart Meters
Point of SaleInventory ControlInteractive AdsVending Machines
Security SystemsSmart DoorbellsRoutersEnergy Monitors
Asset TrackingFleet ManagementDriver AssistPredictive Service
Ideal for powerful, intelligent devices on the edge that need to be secure.
IoT Developer Console
Automatic Security Updates
Signed Images Verified Boot
SoMArchitecture
Google Managed BSP
Displays are Optional
Consider Alternate UI
Supported protocols
Peripheral I/O
Communicate your Android Things device with external hardware components (usually called peripherals)
Various protocols can be used (depends on hardware)
General-Purpose Input/Output
GPIOPulse Width Modulation
PWM
Inter-Integrated Circuit
I2C
Universal Asynchronous
Receiver-Transmitter
UART
Serial Peripheral Interface
SPI
Peripheral I/O
Communicate your Android Things device with external hardware components (usually called peripherals)
Various protocols can be used (depends on hardware)
General-Purpose Input/Output
GPIOPulse Width Modulation
PWM
Inter-Integrated Circuit
I2C
Universal Asynchronous
Receiver-Transmitter
UART
Serial Peripheral Interface
SPI
Native Peripheral Input/Output
NPIO
General-Purpose Input/Output
GPIO
Pulse Width ModulationPWM
Serial Peripheral Interface
SPI
Inter-Integrated Circuit
I2C
Universal Asynchronous
Receiver-Transmitter
UART
Code example: use SPI for an LED strip
public class MainActivity extends Activity {
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); }
}
public class MainActivity extends Activity {
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState);
PeripheralManagerService service = new PeripheralManagerService(); }
}
public class MainActivity extends Activity {
private static final String SPI_PORT = "SPI1"; private SpiDevice device;
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState);
PeripheralManagerService service = new PeripheralManagerService();
try { device = service.openSpiDevice(SPI_PORT); } catch (IOException e) { throw new IllegalStateException(SPI_PORT + " bus cannot be opened.", e); } }
}
public class MainActivity extends Activity { ... @Override protected void onDestroy() { super.onDestroy(); try { device.close(); } catch (IOException e) { Log.e("TUT", SPI_PORT + " bus cannot be closed, you may experience errors on next launch.", e); } }
}
public class MainActivity extends Activity { ... @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState);
...
try { device.setMode(SpiDevice.MODE0); device.setFrequency(1_000_000); device.setBitsPerWord(8); } catch (IOException e) { throw new IllegalStateException(SPI_PORT + " bus cannot be configured.", e); } }
}
public class MainActivity extends Activity { ... private Handler ledToggleHandler;
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState);
...
ledToggleHandler = new Handler(Looper.getMainLooper()); }
}
public class MainActivity extends Activity { ... private Handler ledToggleHandler;
@Override protected void onStart() { super.onStart(); ledToggleHandler.post(toggleLed); }
@Override protected void onStop() { ledToggleHandler.removeCallbacks(toggleLed); super.onStop(); }
}
public class MainActivity extends Activity { ... private int colourValue; ... private final Runnable toggleLed = new Runnable() { @Override public void run() { try { colourValue = (colourValue == 0 ? 123 : 0); device.write(new byte[]{colourValue, colourValue, colourValue}, 3); } catch (IOException e) { throw new IllegalStateException(LED_PIN + " cannot be read/written.", e); } ledToggleHandler.postDelayed(this, TimeUnit.SECONDS.toMillis(1)); } };
}
Drivers
Driver Libraries Input Drivers
User Drivers
Read or write
from/to a peripheral
Reusable components
Abstract protocol details
Driver Libraries
Ws2801 ledstrip = Ws2801.create("SPI1", Ws2801.Mode.RGB);
ledstrip.write(new int[]{Color.rgb(123, 123, 123)});
Input Drivers
Framework redirects events to
theAndroid
event queue
Register an input driver
Use Services instead of Activities
BarActivityFooService
InputDriver inputDriver = InputDriver.builder(InputDevice.SOURCE_CLASS_BUTTON)
.setName("HelloInputDriver")
.setVersion(1)
.setKeys(new int[]{
KeyEvent.KEYCODE_T, KeyEvent.KEYCODE_H, KeyEvent.KEYCODE_I,
KeyEvent.KEYCODE_N, KeyEvent.KEYCODE_G, KeyEvent.KEYCODE_S
}).build();
UserDriverManager driverManager = UserDriverManager.getManager();
driverManager.registerInputDriver(inputDriver);
KeyEvent[] events = new KeyEvent[]{new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_T)};
inputDriver.emit(events);
Peripherals naming convention
Active peripherals
Passive peripherals
Output peripherals
Input peripherals
Input peripherals / Sensors
“A sensor detects or measures a physical property and responds to it.”
Output peripherals / Actuators
“An actuator is responsible for moving or controlling
a mechanism or system, or presenting data to the outside world.”
/*** HC-SR501*/class PirMotionSensor implements MotionSensor { …
/*** PS-1240*/class PiezoSoundActuator implements SoundActuator { ...
Clarity when searching classes
Clarity when reading code
Better team
discussions
Package structure convention
Grouping by
type
- activities- MainActivity- BasketActivity- CheckoutActivity
- services- LoginService- MoneyService
- utils- LoginUtils- HttpUtils
- peripherals- BarcodeScanningSensor- PriceInputSensor- HelpAlertSensor- FingerprintSensor- PriceDisplayActuator- MoneyDrawActuator
- models- Money- Username- Basket- Receipt- Barcode- Price
Grouping by
protocol
- activities- MainActivity- BasketActivity- CheckoutActivity
- services- LoginService- MoneyService
- utils- LoginUtils- HttpUtils
- gpio- BarcodeScanningSensor- PriceInputSensor- HelpAlertSensor
- i2c- FingerprintSensor
- pwm- PriceDisplayActuator- MoneyDrawActuator
- models- Money- Username- Basket- Receipt- Barcode- Price
Increased package
tackle index
Tidy, everything in its place and a place
for everything
Don’t always
remember the protocol
Context switching between packages
Grouping by domain
concepts
- login- MainActivity- LoginUtils- FingerprintSensor- LoginService- Username
- shopping- basket
- BasketActivity- PriceInputSensor- Basket
- checkout- CheckoutActivity- MoneyService- BarcodeScanningSensor- HelpAlertSensor- MoneyDrawActuator- Barcode
- receipt- PriceDisplayActuator- Receipt
- Money- Price- HttpUtils
Needs to be taught (DDD)
Easier to remember where to
look
All code in the same
place
Less chance of
conflicting changes
Peripherals MVP convention
Model
business logic
Presenter
co-ordination
View
user interface
Sensor
“A sensor detects or measures a physical property and responds to
it.”Model
business logic
Actuator
“An actuator is responsible for moving or controlling a mechanism or system,
or presenting data to the outside world.”
View
user interface
Faster debugging
and problem analysis
Clean code, more
maintainable
A clear separation of
concerns
Faster development
through agreed
standards
Clarity in discussions around class responsibiliti
es
Driver testing
Mock framework
classesTest driver behaviour
Extract collaborator
classes
Test driver behaviour
public class LightStripActuatorTest { @Mock Ws2801 driver;
private LightStripActuator actuator;
@Test
public void driverGoesRedWhenError() throws Exception { actuator.showError();
verify(driver).write({Color.RED});
}
}
Rely on mockspublic class Ws2801Test { @Mock SpiDevice device;
private Ws2801 driver; @Test
public void configures1MHzClockFrequencyWhenCreated() throws Exception {
driver = new Ws2801(device, Direction.NORMAL); verify(device).setFrequency(1_000_000);
}
@Test
public void writesToSpiDeviceWhenWriting() throws Exception { int[] anyColors = {Color.RED, Color.DKGRAY, Color.GREEN, Color.WHITE, Color.YELLOW};
driver.write(anyColors);
verify(device).write(any(byte[].class), anyInt()); }
}
Test collaborators easilypublic class ColorUnpackerTest { @Test public void orderedBytesWhenModeIsRBG() { Ws2801.Mode mode = Ws2801.Mode.RBG;
byte[] result = ColorUnpacker.getOrderedRgbBytes(mode, R, G, B);
assertBytesOrder(result, R, B, G); }
@Test public void orderedBytesWhenModeIsBGR() { Ws2801.Mode mode = Ws2801.Mode.BGR;
byte[] result = ColorUnpacker.getOrderedRgbBytes(mode, R, G, B);
assertBytesOrder(result, B, G, R); }}
Tips & Tricks
Always match .openSomething()
with .close()
Set a static IP addressor
use Android.local
On app crash need to redeploy
or adb shell am start
Only 1 app active at a time https://goo.gl/kLtvM7
Each board has different pin/bus address names
Threading, 3 choices
Thanks!Paul Blundell
Xavi Rigau@blundell_apps@xrigau
Questions?user drivers PWM
UARTGPIO
I2C
SPIinput
output
sensorsactuators
MVP
DDDPaul Blundell
Xavi Rigau@blundell_apps@xrigau