diff --git a/README.md b/README.md index fff54e7..e95374e 100644 --- a/README.md +++ b/README.md @@ -35,8 +35,8 @@ dependencies { Driver | Type | Usage (add to your gradle dependencies) | Note :---:|:---:| --- | --- -[driver-ds3231](driver-ds3231) | real-time clock (RTC) | `implementation 'com.leinardi.android.things:driver-ds3231:0.1'` | [![Maven metadata URI](https://img.shields.io/maven-metadata/v/http/jcenter.bintray.com/com/leinardi/android/things/driver-ds3231/maven-metadata.xml.svg)](https://jcenter.bintray.com/com/leinardi/android/things/driver-ds3231/maven-metadata.xml) [changelog](driver-ds3231/CHANGELOG.md) [sample](sample-ds3231) -[driver-ds3231-receiver](driver-ds3231-receiver) | automatic persist on reboot/poweroff the system wall clock time | `implementation 'com.leinardi.android.things:driver-ds3231-receiver:0.1'` | [![Maven metadata URI](https://img.shields.io/maven-metadata/v/http/jcenter.bintray.com/com/leinardi/android/things/driver-ds3231-receiver/maven-metadata.xml.svg)](https://jcenter.bintray.com/com/leinardi/android/things/driver-ds3231-receiver/maven-metadata.xml) [changelog](driver-ds3231-receiver/CHANGELOG.md) +[driver-ds3231](driver-ds3231) | real-time clock (RTC) | `implementation 'com.leinardi.android.things:driver-ds3231:0.1'` | [![Maven metadata URI](https://img.shields.io/maven-metadata/v/http/jcenter.bintray.com/com/leinardi/android/things/driver-ds3231/maven-metadata.xml.svg)](https://jcenter.bintray.com/com/leinardi/android/things/driver-ds3231/maven-metadata.xml) [changelog](driver-ds3231/CHANGELOG.md) [sample](sample-ds3231) [driver-ds3231-receiver](driver-ds3231-receiver) +[driver-epaperdriverhat](driver-epaperdriverhat) | E-Paper Driver HAT | `implementation 'com.leinardi.android.things:driver-epaperdriverhat:0.1'` | [![Maven metadata URI](https://img.shields.io/maven-metadata/v/http/jcenter.bintray.com/com/leinardi/android/things/driver-epaperdriverhat/maven-metadata.xml.svg)](https://jcenter.bintray.com/com/leinardi/android/things/driver-epaperdriverhat/maven-metadata.xml) [changelog](driver-epaperdriverhat/CHANGELOG.md) [sample](sample-epaperdriverhat) [driver-hcsr04](driver-hcsr04) | ultrasonic ranging module | `implementation 'com.leinardi.android.things:driver-hcsr04:0.1'` | [![Maven metadata URI](https://img.shields.io/maven-metadata/v/http/jcenter.bintray.com/com/leinardi/android/things/driver-hcsr04/maven-metadata.xml.svg)](https://jcenter.bintray.com/com/leinardi/android/things/driver-hcsr04/maven-metadata.xml) [changelog](driver-hcsr04/CHANGELOG.md) [sample](sample-hcsr04) [driver-hd44780](driver-hd44780) | alphanumeric dot matrix LCD | `implementation 'com.leinardi.android.things:driver-hd44780:0.2'` | [![Maven metadata URI](https://img.shields.io/maven-metadata/v/http/jcenter.bintray.com/com/leinardi/android/things/driver-hd44780/maven-metadata.xml.svg)](https://jcenter.bintray.com/com/leinardi/android/things/driver-hd44780/maven-metadata.xml) [changelog](driver-hd44780/CHANGELOG.md) [sample](sample-hd44780) [driver-lsm9ds1](driver-lsm9ds1) | 3D accelerometer, 3D gyroscope, 3D magnetometer and temperature sensor | `implementation 'com.leinardi.android.things:driver-lsm9ds1:0.3'` | [![Maven metadata URI](https://img.shields.io/maven-metadata/v/http/jcenter.bintray.com/com/leinardi/android/things/driver-lsm9ds1/maven-metadata.xml.svg)](https://jcenter.bintray.com/com/leinardi/android/things/driver-lsm9ds1/maven-metadata.xml) [changelog](driver-lsm9ds1/CHANGELOG.md) [sample](sample-lsm9ds1) diff --git a/bintray.gradle b/bintray.gradle index 138d39e..0e9bd86 100644 --- a/bintray.gradle +++ b/bintray.gradle @@ -36,6 +36,8 @@ bintray { licenses = mvn_config.licenses.split(',') websiteUrl = mvn_config.website issueTrackerUrl = mvn_config.issue_tracker_url + githubRepo = mvn_config.githubRepo +// githubReleaseNotesFile = mvn_config.githubReleaseNotesFile vcsUrl = mvn_config.vcs_url labels = mvn_config.tags.split(',') version { diff --git a/driver-ds3231-receiver/mavenConfig.gradle b/driver-ds3231-receiver/mavenConfig.gradle index 1e00aee..f3f3865 100644 --- a/driver-ds3231-receiver/mavenConfig.gradle +++ b/driver-ds3231-receiver/mavenConfig.gradle @@ -25,6 +25,7 @@ mvn_config.issue_tracker_url = 'https://github.com/leinardi/androidthings-driver mvn_config.vcs_url = 'https://github.com/leinardi/androidthings-drivers.git' mvn_config.description = 'DS3231 boot completed and time set receiver for Android Things' mvn_config.tags = 'ds3231,android-things,android,raspberry-pi' // Comma separated +mvn_config.githubRepo = 'leinardi/androidthings-drivers' mvn_config.inception_year = '2018' mvn_config.dryRun = false mvn_config.publish = false diff --git a/driver-ds3231/mavenConfig.gradle b/driver-ds3231/mavenConfig.gradle index a73f244..9ca4eb5 100644 --- a/driver-ds3231/mavenConfig.gradle +++ b/driver-ds3231/mavenConfig.gradle @@ -25,6 +25,7 @@ mvn_config.issue_tracker_url = 'https://github.com/leinardi/androidthings-driver mvn_config.vcs_url = 'https://github.com/leinardi/androidthings-drivers.git' mvn_config.description = 'DS3231 driver for Android Things' mvn_config.tags = 'ds3231,android-things,android,raspberry-pi' // Comma separated +mvn_config.githubRepo = 'leinardi/androidthings-drivers' mvn_config.inception_year = '2018' mvn_config.dryRun = false mvn_config.publish = false diff --git a/driver-epaperdriverhat/.gitignore b/driver-epaperdriverhat/.gitignore new file mode 100644 index 0000000..796b96d --- /dev/null +++ b/driver-epaperdriverhat/.gitignore @@ -0,0 +1 @@ +/build diff --git a/driver-epaperdriverhat/CHANGELOG.md b/driver-epaperdriverhat/CHANGELOG.md new file mode 100644 index 0000000..6648d1c --- /dev/null +++ b/driver-epaperdriverhat/CHANGELOG.md @@ -0,0 +1,5 @@ +# Change Log + +## [0.1] - 2018-01-19 +- initial version + diff --git a/driver-epaperdriverhat/README.md b/driver-epaperdriverhat/README.md new file mode 100644 index 0000000..e5a65eb --- /dev/null +++ b/driver-epaperdriverhat/README.md @@ -0,0 +1,95 @@ +# E-Paper Driver HAT display driver for Android Things + +[![Maven metadata URI](https://img.shields.io/maven-metadata/v/http/jcenter.bintray.com/com/leinardi/android/things/driver-epaperdriverhat/maven-metadata.xml.svg?style=plastic)](https://jcenter.bintray.com/com/leinardi/android/things/driver-epaperdriverhat/maven-metadata.xml) +[![Build Status](https://img.shields.io/travis/leinardi/androidthings-drivers/master.svg?style=plastic)](https://travis-ci.org/leinardi/androidthings-drivers) +[![GitHub license](https://img.shields.io/github/license/leinardi/androidthings-drivers.svg?style=plastic)](https://github.com/leinardi/androidthings-drivers/blob/master/LICENSE) + +This driver supports E-Paper screen peripherals connected with an E-Paper Driver HAT. + +## Supported displays + + +Part Number | Class | Size | Color | Resolution | Interface +:---:|:---:| --- | --- | --- | --- +[GDEW075T8](https://www.waveshare.com/wiki/7.5inch_e-Paper_HAT) | `Gdew075t8Epd` | 7.5" | Black, White | 640x384 | SPI + + +NOTE: these drivers are not production-ready. They are offered as sample +implementations of Android Things user space drivers for common peripherals +as part of the Developer Preview release. There is no guarantee +of correctness, completeness or robustness. + +This driver is based on the [GxEPD driver from ZinggJM](https://github.com/ZinggJM/GxEPD) + +## How to use the driver + +### Gradle dependency + +To use the `epaperdriverhat` driver, simply add the line below to your project's `build.gradle`, +where `` matches the last version of the driver available on [jcenter][jcenter]. + +``` +dependencies { + implementation 'com.leinardi.android.things:driver-epaperdriverhat:' +} +``` + +### Sample usage + +```java +public class EpdScreenActivity extends Activity { + private static final String TAG = EpdScreenActivity.class.getSimpleName(); + Gdew075t8Epd mEpd; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + try { + mEpd = new Gdew075t8Epd(); + // Show checkerboard + for (int i = 0; i < mEpd.getDisplayWidth(); i++) { + for (int j = 0; j < mEpd.getDisplayHeight(); j++) { + mEpd.setPixel(i, j, (i % 2) == (j % 2)); + } + } + mEpd.show(); + } catch (IOException e) { + Log.e(TAG, "Error initializing EPD", e); + } + } + + @Override + public void onDestroy() { + super.onDestroy(); + try { + mEpd.close(); + } catch (IOException e) { + Log.e(TAG, "Exception closing EPD", e); + } finally { + mEpd = null; + } + } +} + +``` + +## License + +Copyright 2018 Roberto Leinardi + +Licensed to the Apache Software Foundation (ASF) under one or more contributor +license agreements. See the NOTICE file distributed with this work for +additional information regarding copyright ownership. The ASF licenses this +file to you under the Apache License, Version 2.0 (the "License"); you may not +use this file except in compliance with the License. You may obtain a copy of +the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +License for the specific language governing permissions and limitations under +the License. + +[jcenter]: https://bintray.com/leinardi/androidthings/driver-epaperdriverhat/_latestVersion diff --git a/driver-epaperdriverhat/build.gradle b/driver-epaperdriverhat/build.gradle new file mode 100644 index 0000000..81088a6 --- /dev/null +++ b/driver-epaperdriverhat/build.gradle @@ -0,0 +1,51 @@ +/* + * Copyright 2018 Roberto Leinardi. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +apply plugin: 'com.android.library' +apply from: rootProject.file('checkstyle.gradle') + +android { + compileSdkVersion build_versions.target_sdk + buildToolsVersion build_versions.build_tools + + apply from: 'mavenConfig.gradle' + + defaultConfig { + minSdkVersion build_versions.min_sdk + targetSdkVersion build_versions.target_sdk + versionCode build_versions.version_code + versionName mvn_config.version as String + testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" + } + + compileOptions { + sourceCompatibility build_versions.java_version + targetCompatibility build_versions.java_version + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + } + +} + +dependencies { + compileOnly deps.androidthings + implementation deps.support.annotations +} diff --git a/driver-epaperdriverhat/docs/GDEW075T8.pdf b/driver-epaperdriverhat/docs/GDEW075T8.pdf new file mode 100644 index 0000000..df1b9ba Binary files /dev/null and b/driver-epaperdriverhat/docs/GDEW075T8.pdf differ diff --git a/driver-epaperdriverhat/mavenConfig.gradle b/driver-epaperdriverhat/mavenConfig.gradle new file mode 100644 index 0000000..1449a92 --- /dev/null +++ b/driver-epaperdriverhat/mavenConfig.gradle @@ -0,0 +1,37 @@ +/* + * Copyright 2018 Roberto Leinardi. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +def mvn_config = [:] +mvn_config.repository = 'androidthings' +mvn_config.group_id = 'com.leinardi.android.things' +mvn_config.artifact_id = 'driver-epaperdriverhat' +mvn_config.version = '0.1' +mvn_config.licenses = 'Apache-2.0' // Comma separated +mvn_config.website = 'https://github.com/leinardi/androidthings-drivers' +mvn_config.issue_tracker_url = 'https://github.com/leinardi/androidthings-drivers/issues' +mvn_config.vcs_url = 'https://github.com/leinardi/androidthings-drivers.git' +mvn_config.description = 'E-Paper Driver HAT driver for Android Things' +mvn_config.tags = 'epaperdriverhat,gdew075t8,android-things,android,raspberry-pi' // Comma separated +mvn_config.githubRepo = 'leinardi/androidthings-drivers' +mvn_config.inception_year = '2018' +mvn_config.dryRun = false +mvn_config.publish = false +mvn_config.override = true + +ext.mvn_config = mvn_config + +apply from: rootProject.file('maven.gradle') +apply from: rootProject.file('bintray.gradle') diff --git a/driver-epaperdriverhat/proguard-rules.pro b/driver-epaperdriverhat/proguard-rules.pro new file mode 100644 index 0000000..f1b4245 --- /dev/null +++ b/driver-epaperdriverhat/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile diff --git a/driver-epaperdriverhat/src/main/AndroidManifest.xml b/driver-epaperdriverhat/src/main/AndroidManifest.xml new file mode 100644 index 0000000..aa5f5bf --- /dev/null +++ b/driver-epaperdriverhat/src/main/AndroidManifest.xml @@ -0,0 +1,25 @@ + + + + + + + + diff --git a/driver-epaperdriverhat/src/main/java/com/leinardi/android/things/driver/epaperdriverhat/BitmapHelper.java b/driver-epaperdriverhat/src/main/java/com/leinardi/android/things/driver/epaperdriverhat/BitmapHelper.java new file mode 100644 index 0000000..6c4abdc --- /dev/null +++ b/driver-epaperdriverhat/src/main/java/com/leinardi/android/things/driver/epaperdriverhat/BitmapHelper.java @@ -0,0 +1,61 @@ +/* + * Copyright 2018 Roberto Leinardi. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.leinardi.android.things.driver.epaperdriverhat; + +import android.graphics.Bitmap; + +public class BitmapHelper { + private static final int GRADIENT_CUTOFF = 85; // Tune for gradient picker on grayscale images. + + private BitmapHelper() { + } + + /** + * Converts a bitmap image to LCD screen data and sets it on the given screen at the specified + * offset. + * + * @param mScreen The e-paper screen to write the bitmap data to. + * @param xOffset The horizontal offset to draw the image at. + * @param yOffset The vertical offset to draw the image at. + * @param bmp The bitmap image that you want to convert to screen data. + * @param drawWhite true for drawing only white pixels, false for drawing grayscale pixel + * based on {@link #GRADIENT_CUTOFF}. + */ + public static void setBmpData(Epd mScreen, int xOffset, int yOffset, Bitmap bmp, boolean drawWhite) { + int width = bmp.getWidth(); + int height = bmp.getHeight(); + + for (int y = 0; y < height; y++) { + for (int x = 0; x < width; x++) { + int pixel = bmp.getPixel(x, y); + if (!drawWhite) { // Look at Alpha channel instead + if ((pixel & 0xFF) <= GRADIENT_CUTOFF) { + mScreen.setPixel(x + xOffset, y + yOffset, true); + } else { + mScreen.setPixel(x + xOffset, y + yOffset, false); + } + } else { + if (pixel == -1) { // Only draw white pixels + mScreen.setPixel(x + xOffset, y + yOffset, true); + } else { + mScreen.setPixel(x + xOffset, y + yOffset, false); + } + } + } + } + } +} diff --git a/driver-epaperdriverhat/src/main/java/com/leinardi/android/things/driver/epaperdriverhat/Epd.java b/driver-epaperdriverhat/src/main/java/com/leinardi/android/things/driver/epaperdriverhat/Epd.java new file mode 100644 index 0000000..6f7223b --- /dev/null +++ b/driver-epaperdriverhat/src/main/java/com/leinardi/android/things/driver/epaperdriverhat/Epd.java @@ -0,0 +1,237 @@ +/* + * Copyright 2018 Roberto Leinardi. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.leinardi.android.things.driver.epaperdriverhat; + +import android.graphics.Color; + +import com.google.android.things.pio.Gpio; +import com.google.android.things.pio.PeripheralManagerService; +import com.google.android.things.pio.SpiDevice; + +import java.io.Closeable; +import java.io.IOException; +import java.util.Arrays; + +/** + * Driver for controlling the EPAPERDRIVERHAT OLED display. + */ +@SuppressWarnings("WeakerAccess") +public abstract class Epd implements Closeable { + private static final String TAG = Epd.class.getSimpleName(); + private static final String EPD_RESET_PIN_RPI = "BCM17"; + private static final String EPD_DATA_COMMAND_PIN_RPI = "BCM25"; + // private static final String EPD_CS_PIN_RPI = "BCM8"; + private static final String EPD_BUSY_PIN_RPI = "BCM24"; + private static final String EPD_SPI_DEVICE_RPI = "SPI0.0"; + + // Device SPI Configuration constants + private static final int SPI_BPW = 8; // Bits per word + private static final int SPI_FREQUENCY = 2000000; + // Clock idle low, data is clocked in on rising edge, output data (change) on falling edge + private static final int SPI_MODE = SpiDevice.MODE0; + private static final int MAX_WRITE_BUFFER_LENGTH = 1024; + private SpiDevice mSpiDevice; + /** + * Reset signal input. The Reset is active Low. + */ + private Gpio mResetPin; + /** + * Data/Command control pin connecting to the MCU. When the pin is pulled High, the data will be interpreted as + * data. When the pin is pulled Low, the data will be interpreted as command. + */ + private Gpio mDataCommandPin; + /** + * Busy state output pin. When Busy the operation of chip should not be interrupted and any commands + * should not be issued to the module. + */ + private Gpio mBusyPin; + + public Epd() throws IOException { + this(EPD_SPI_DEVICE_RPI, EPD_RESET_PIN_RPI, EPD_DATA_COMMAND_PIN_RPI, EPD_BUSY_PIN_RPI); + } + + public Epd(String spiBusPort, String resetPin, String dataCommandPin, String busyPin) throws IOException { + PeripheralManagerService pioService = new PeripheralManagerService(); + mSpiDevice = pioService.openSpiDevice(spiBusPort); + mResetPin = pioService.openGpio(resetPin); + mDataCommandPin = pioService.openGpio(dataCommandPin); + mBusyPin = pioService.openGpio(busyPin); + try { + configure(); + } catch (IOException | RuntimeException e) { + try { + close(); + } catch (IOException | RuntimeException ignored) { + } + throw e; + } + } + + protected void configure() throws IOException { + // Note: You may need to set bit justification for your board. + // mSpiDevice.setBitJustification(SPI_BITJUST); + mSpiDevice.setFrequency(SPI_FREQUENCY); + mSpiDevice.setMode(SPI_MODE); + mSpiDevice.setBitsPerWord(SPI_BPW); + mResetPin.setDirection(Gpio.DIRECTION_OUT_INITIALLY_LOW); + mDataCommandPin.setDirection(Gpio.DIRECTION_OUT_INITIALLY_LOW); + mBusyPin.setDirection(Gpio.DIRECTION_IN); + } + + protected void sendCommand(int command) throws IOException { + if (mSpiDevice == null) { + throw new IllegalStateException("SPI device not open"); + } + mDataCommandPin.setValue(false); + byte[] buffer = new byte[]{(byte) (command & 0xFF)}; + mSpiDevice.write(buffer, buffer.length); + } + + protected void sendData(byte data) throws IOException { + byte[] buffer = new byte[]{data}; + sendData(buffer); + } + + protected void sendData(byte[] data) throws IOException { + if (mSpiDevice == null) { + throw new IllegalStateException("SPI device not open"); + } + mDataCommandPin.setValue(true); + if (data.length > MAX_WRITE_BUFFER_LENGTH) { + for (int i = 0; i < data.length - MAX_WRITE_BUFFER_LENGTH + 1; i += MAX_WRITE_BUFFER_LENGTH) { + mSpiDevice.write(Arrays.copyOfRange(data, i, i + MAX_WRITE_BUFFER_LENGTH), MAX_WRITE_BUFFER_LENGTH); + } + + if (data.length % MAX_WRITE_BUFFER_LENGTH != 0) { + mSpiDevice.write( + Arrays.copyOfRange(data, data.length - data.length % MAX_WRITE_BUFFER_LENGTH, data.length), + data.length % MAX_WRITE_BUFFER_LENGTH); + } + } else { + mSpiDevice.write(data, data.length); + } + } + + public void reset() throws IOException { + mResetPin.setValue(false); + delay(50); + mResetPin.setValue(true); + delay(50); + } + + /** + * @return the width of the display + */ + public abstract int getDisplayWidth(); + + /** + * @return the height of the display + */ + public abstract int getDisplayHeight(); + + /** + * Clears all pixel data in the display buffer. This will be rendered the next time + * {@link #show()} is called. + */ + public abstract void clearPixels(); + + /** + * Sets a specific pixel in the display buffer to on or off. This will be rendered the next time + * {@link #show()} is called. + * + * @param x The horizontal coordinate. + * @param y The vertical coordinate. + * @param on Set to true to enable the pixel; false to disable the pixel. + */ + public abstract void setPixel(int x, int y, boolean on) throws IllegalArgumentException; + + /** + * Invert the display color without rewriting the contents of the display data RAM.. + * + * @param invert Set to true to invert the display color; set to false to set the display back to normal. + * @throws IOException + * @throws IllegalStateException + */ + public abstract void setInvertDisplay(boolean invert) throws IOException, IllegalStateException; + + /** + * Renders the current pixel data to the screen. + * + * @throws IOException + * @throws IllegalStateException + */ + public abstract void show() throws IOException; + + protected abstract void wakeUp() throws IOException; + + protected abstract void sleep() throws IOException; + + protected abstract boolean isBusy() throws IOException; + + protected boolean getBusyPinValue() throws IOException { + return mBusyPin.getValue(); + } + + protected void waitUntilIdle() throws IOException { + while (isBusy()) { + delay(100); + } + } + + protected void delay(int millis) { + try { + Thread.sleep(millis); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + } + + /** + * Releases the SPI interface and related resources. + */ + @Override + public void close() throws IOException { + if (mSpiDevice != null) { + try { + mSpiDevice.close(); + } finally { + mSpiDevice = null; + } + } + if (mResetPin != null) { + try { + mResetPin.close(); + } finally { + mResetPin = null; + } + } + if (mDataCommandPin != null) { + try { + mDataCommandPin.close(); + } finally { + mDataCommandPin = null; + } + } + if (mBusyPin != null) { + try { + mBusyPin.close(); + } finally { + mBusyPin = null; + } + } + } +} diff --git a/driver-epaperdriverhat/src/main/java/com/leinardi/android/things/driver/epaperdriverhat/Gdew075t8Epd.java b/driver-epaperdriverhat/src/main/java/com/leinardi/android/things/driver/epaperdriverhat/Gdew075t8Epd.java new file mode 100644 index 0000000..7b3fbdf --- /dev/null +++ b/driver-epaperdriverhat/src/main/java/com/leinardi/android/things/driver/epaperdriverhat/Gdew075t8Epd.java @@ -0,0 +1,317 @@ +/* + * Copyright 2018 Roberto Leinardi. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.leinardi.android.things.driver.epaperdriverhat; + +import java.io.IOException; +import java.util.Arrays; + +public class Gdew075t8Epd extends Epd { + + // Display resolution + private static final int EPD_WIDTH = 640; + private static final int EPD_HEIGHT = 384; + // EPD7IN5 commands + private static final int PANEL_SETTING = 0x00; + private static final int POWER_SETTING = 0x01; + private static final int POWER_OFF = 0x02; + private static final int POWER_OFF_SEQUENCE_SETTING = 0x03; + private static final int POWER_ON = 0x04; + private static final int POWER_ON_MEASURE = 0x05; + private static final int BOOSTER_SOFT_START = 0x06; + private static final int DEEP_SLEEP = 0x07; + private static final int DATA_START_TRANSMISSION_1 = 0x10; + private static final int DATA_STOP = 0x11; + private static final int DISPLAY_REFRESH = 0x12; + private static final int IMAGE_PROCESS = 0x13; + private static final int LUT_FOR_VCOM = 0x20; + private static final int LUT_BLUE = 0x21; + private static final int LUT_WHITE = 0x22; + private static final int LUT_GRAY_1 = 0x23; + private static final int LUT_GRAY_2 = 0x24; + private static final int LUT_RED_0 = 0x25; + private static final int LUT_RED_1 = 0x26; + private static final int LUT_RED_2 = 0x27; + private static final int LUT_RED_3 = 0x28; + private static final int LUT_XON = 0x29; + private static final int PLL_CONTROL = 0x30; + private static final int TEMPERATURE_SENSOR_COMMAND = 0x40; + private static final int TEMPERATURE_CALIBRATION = 0x41; + private static final int TEMPERATURE_SENSOR_WRITE = 0x42; + private static final int TEMPERATURE_SENSOR_READ = 0x43; + private static final int VCOM_AND_DATA_INTERVAL_SETTING = 0x50; + private static final int LOW_POWER_DETECTION = 0x51; + private static final int TCON_SETTING = 0x60; + private static final int TCON_RESOLUTION = 0x61; + private static final int SPI_FLASH_CONTROL = 0x65; + private static final int REVISION = 0x70; + private static final int GET_STATUS = 0x71; + private static final int AUTO_MEASUREMENT_VCOM = 0x80; + private static final int READ_VCOM_VALUE = 0x81; + private static final int VCM_DC_SETTING = 0x82; + private static final int PARTIAL_WINDOW = 0x90; // Undocumented + private static final int PARTIAL_IN = 0x91; // Undocumented + private static final int PARTIAL_OUT = 0x92; // Undocumented + private static final int FLASH_MODE = 0xE5; // Undocumented + + private static final int PANEL_SETTING_RES_640X480 = 0b0000_0000; + private static final int PANEL_SETTING_RES_640X450 = 0b0100_0000; + private static final int PANEL_SETTING_RES_640X448 = 0b1000_0000; + private static final int PANEL_SETTING_RES_600X448 = 0b1100_0000; + + private static final int PANEL_SETTING_LUT_FROM_REGISTER = 0b0010_0000; + // Source = width, gate = height + /** + * First line to last: G1→ ......→Gn + */ + private static final int PANEL_SETTING_GATE_SCAN_UP = 0b0000_1000; + /** + * First data to last data: S1→......→Sn + */ + private static final int PANEL_SETTING_SOURCE_SHIFT_RIGHT = 0b0000_0100; + private static final int PANEL_SETTING_DC_DC_CONVERTER_ON = 0b0000_0010; + private static final int PANEL_SETTING_NORMAL_OPERATION = 0b0000_0001; + + private static final int POWER_SETTING_VDNS_L = 0b0011_0000; + private static final int POWER_SETTING_VSOURCE_LV_EN_INTERNAL_DC_DC = 0b0000_0100; + private static final int POWER_SETTING_VSOURCE_INTERNAL_DC_DC = 0b0000_0010; + private static final int POWER_SETTING_VGATE_INTERNAL_DC_DC = 0b0000_0001; + private static final int POWER_SETTING_VGHL_PLUS_MINUS_20V = 0b0000_0000; + + private static final int BOOSTER_SOFT_START_PHASE_PERIOD_10MS = 0b0000_0000; + private static final int BOOSTER_SOFT_START_PHASE_PERIOD_20MS = 0b0100_0000; + private static final int BOOSTER_SOFT_START_PHASE_PERIOD_30MS = 0b1000_0000; + private static final int BOOSTER_SOFT_START_PHASE_PERIOD_40MS = 0b1100_0000; + private static final int BOOSTER_SOFT_START_DRIVING_STRENGTH_1 = 0b0000_0000; + private static final int BOOSTER_SOFT_START_DRIVING_STRENGTH_2 = 0b0000_1000; + private static final int BOOSTER_SOFT_START_DRIVING_STRENGTH_3 = 0b0001_0000; + private static final int BOOSTER_SOFT_START_DRIVING_STRENGTH_4 = 0b0001_1000; + private static final int BOOSTER_SOFT_START_DRIVING_STRENGTH_5 = 0b0010_0000; + private static final int BOOSTER_SOFT_START_DRIVING_STRENGTH_6 = 0b0010_1000; + private static final int BOOSTER_SOFT_START_DRIVING_STRENGTH_7 = 0b0011_0000; + private static final int BOOSTER_SOFT_START_DRIVING_STRENGTH_8 = 0b0011_1000; + private static final int BOOSTER_SOFT_START_MIN_OFF_TIME_0_26 = 0b0000_0000; + private static final int BOOSTER_SOFT_START_MIN_OFF_TIME_0_31 = 0b0000_0001; + private static final int BOOSTER_SOFT_START_MIN_OFF_TIME_0_36 = 0b0000_0010; + private static final int BOOSTER_SOFT_START_MIN_OFF_TIME_0_52 = 0b0000_0011; + private static final int BOOSTER_SOFT_START_MIN_OFF_TIME_0_77 = 0b0000_0100; + private static final int BOOSTER_SOFT_START_MIN_OFF_TIME_1_61 = 0b0000_0101; + private static final int BOOSTER_SOFT_START_MIN_OFF_TIME_3_43 = 0b0000_0110; + private static final int BOOSTER_SOFT_START_MIN_OFF_TIME_6_77 = 0b0000_0111; + private static final int TEMPERATURE_CALIBRATION_INTERNAL = 0b0000_0000; + private static final int TEMPERATURE_CALIBRATION_EXTERNAL = 0b1000_0000; + + private static final int PLL_CONTROL_50HZ = 0b0011_1100; // See datasheet page 17 + + private static final int VCOM_AND_DATA_INTERVAL_SETTING_DEFAULT_WHITE_BALCK = 0b0110_0111; // See datasheet page 19 + private static final int VCOM_AND_DATA_INTERVAL_SETTING_INVERT_COLORS = 0b0001_0000; // See datasheet page 19 + + private static final int TCON_SETTING_DEFAULT_S2G_G2S = 0b0010_0010; // See datasheet page 20 + + private static final int DEEP_SLEEP_CHECK_CODE = 0b1010_0101; + + private static final int SPI_FLASH_CONTROL_ENABLED = 0b0000_00001; + private static final int SPI_FLASH_CONTROL_DISABLED = 0b0000_00000; + + private static final int PIXEL_ON = 0b011; + private static final int PARTIAL_UPDATE_DELAY = 500; + + private byte[] mBuffer; + private boolean mInvertColor; + + public Gdew075t8Epd() throws IOException { + } + + public Gdew075t8Epd(String spiBusPort, String resetPin, String dataCommandPin, String busyPin) throws IOException { + super(spiBusPort, resetPin, dataCommandPin, busyPin); + } + + @Override + protected void configure() throws IOException { + super.configure(); + mBuffer = new byte[((getDisplayWidth() * getDisplayHeight()) / 2)]; + } + + @Override + public void clearPixels() { + Arrays.fill(mBuffer, 0, mBuffer.length, (byte) 0); + } + + @Override + public void setPixel(int x, int y, boolean on) throws IllegalArgumentException { + if (x < 0 || y < 0 || x >= getDisplayWidth() || y >= getDisplayHeight()) { + throw new IllegalArgumentException("pixel out of bound:" + x + "," + y); + } + if (on) { + mBuffer[x / 2 + (y * getDisplayWidth() / 2)] |= (x % 2 == 0 ? (PIXEL_ON << 4) : PIXEL_ON); + } else { + mBuffer[x / 2 + (y * getDisplayWidth() / 2)] &= ~(x % 2 == 0 ? (PIXEL_ON << 4) : PIXEL_ON); + } + } + + @Override + public void setInvertDisplay(boolean invert) throws IOException, IllegalStateException { + mInvertColor = invert; + } + + @Override + public int getDisplayWidth() { + return EPD_WIDTH; + } + + @Override + public int getDisplayHeight() { + return EPD_HEIGHT; + } + + @Override + public void show() throws IOException { + wakeUp(); + sendCommand(DATA_START_TRANSMISSION_1); + sendData(mBuffer); + sendCommand(DISPLAY_REFRESH); + waitUntilIdle(); + sleep(); + } + + /** + * On this display, partial update to display RAM works, but refresh is full screen + */ + private void show(int left, int top, int right, int bottom) throws IOException { + int width = right - left; + int height = bottom - top; + + byte[] buffer = new byte[((width * height) + 1) / 2]; + for (int y = top; y < bottom; y++) { + for (int x = left; x < right; x++) { + byte b = mBuffer[x / 2 + (y * getDisplayWidth() / 2)]; + if (left == right - 1 && left % 2 == 0) { + b &= ~(0xF); + } + buffer[((x - left) / 2 + (((y - top) * width) + 1) / 2)] |= (x % 2 == 0 ? (b << 4) : b); + } + } + + left &= ~(0b0000_0111); // byte boundary + right = (right - 1) | 0b0000_0111; // byte boundary - 1 + sendCommand(PARTIAL_IN); + sendCommand(PARTIAL_WINDOW); + sendData((byte) (left / 256)); + sendData((byte) (left % 256)); + sendData((byte) (right / 256)); + sendData((byte) (right % 256)); + sendData((byte) (top / 256)); + sendData((byte) (top % 256)); + sendData((byte) (bottom / 256)); + sendData((byte) (bottom % 256)); + //sendData(0x01); // Gates scan both inside and outside of the partial window. (default) + sendData((byte) 0x00); // Gates scan only inside of the partial window + + sendCommand(DATA_START_TRANSMISSION_1); + sendData(buffer); + sendCommand(DISPLAY_REFRESH); + sendCommand(PARTIAL_OUT); + } + + @Override + protected void wakeUp() throws IOException { + reset(); + + sendCommand(SPI_FLASH_CONTROL); + sendData((byte) SPI_FLASH_CONTROL_ENABLED); + + sendCommand(0xAB); + + sendCommand(SPI_FLASH_CONTROL); + sendData((byte) SPI_FLASH_CONTROL_DISABLED); + + sendCommand(POWER_SETTING); + sendData((byte) (POWER_SETTING_VDNS_L + | POWER_SETTING_VSOURCE_LV_EN_INTERNAL_DC_DC + | POWER_SETTING_VSOURCE_INTERNAL_DC_DC + | POWER_SETTING_VGATE_INTERNAL_DC_DC)); //0b0011_0111 + sendData((byte) POWER_SETTING_VGHL_PLUS_MINUS_20V); + + sendCommand(PANEL_SETTING); + sendData((byte) (PANEL_SETTING_RES_600X448 + | PANEL_SETTING_GATE_SCAN_UP + | PANEL_SETTING_SOURCE_SHIFT_RIGHT + | PANEL_SETTING_DC_DC_CONVERTER_ON + | PANEL_SETTING_NORMAL_OPERATION)); // 0b1100_1111 + sendData((byte) 0b0000_1000); // What's the purpose of this? + + sendCommand(BOOSTER_SOFT_START); + sendData((byte) (BOOSTER_SOFT_START_PHASE_PERIOD_40MS + | BOOSTER_SOFT_START_DRIVING_STRENGTH_1 + | BOOSTER_SOFT_START_MIN_OFF_TIME_6_77)); // 0b1100_0111 + sendData((byte) (BOOSTER_SOFT_START_PHASE_PERIOD_40MS + | BOOSTER_SOFT_START_DRIVING_STRENGTH_2 + | BOOSTER_SOFT_START_MIN_OFF_TIME_0_77)); // 0b1100_1100 + sendData((byte) (BOOSTER_SOFT_START_DRIVING_STRENGTH_6 + | BOOSTER_SOFT_START_MIN_OFF_TIME_0_26)); // 0b0010_1000 + + sendData((byte) PLL_CONTROL_50HZ); + + sendCommand(TEMPERATURE_CALIBRATION); + sendData((byte) TEMPERATURE_CALIBRATION_INTERNAL); + + sendCommand(VCOM_AND_DATA_INTERVAL_SETTING); + int vcomAndDataIntervalSetting = VCOM_AND_DATA_INTERVAL_SETTING_DEFAULT_WHITE_BALCK; + if (mInvertColor) { + vcomAndDataIntervalSetting |= VCOM_AND_DATA_INTERVAL_SETTING_INVERT_COLORS; + } + sendData((byte) vcomAndDataIntervalSetting); + + sendCommand(TCON_SETTING); + sendData((byte) TCON_SETTING_DEFAULT_S2G_G2S); + + sendCommand(TCON_RESOLUTION); + sendData((byte) ((EPD_WIDTH >> 8) & 0xFF)); // 0b0000_0010 + sendData((byte) (EPD_WIDTH & 0xFF)); // 0b1000_0000 + sendData((byte) ((EPD_HEIGHT >> 8) & 0xFF)); // 0b0000_0001; + sendData((byte) (EPD_HEIGHT & 0xFF)); // 0b1000_0000; + + sendCommand(VCM_DC_SETTING); + sendData((byte) 0b0001_1110); // decide by LUT file; + + sendCommand(FLASH_MODE); + sendData((byte) 0x03); + + sendCommand(POWER_ON); + waitUntilIdle(); + } + + @Override + protected void sleep() throws IOException { + sendCommand(SPI_FLASH_CONTROL); + sendData((byte) SPI_FLASH_CONTROL_ENABLED); + + sendCommand(0xB9); + + sendCommand(SPI_FLASH_CONTROL); + sendData((byte) SPI_FLASH_CONTROL_DISABLED); + + sendCommand(POWER_OFF); + waitUntilIdle(); + sendCommand(DEEP_SLEEP); + sendData((byte) DEEP_SLEEP_CHECK_CODE); + } + + @Override + protected boolean isBusy() throws IOException { + return !getBusyPinValue(); + } +} diff --git a/driver-hcsr04/mavenConfig.gradle b/driver-hcsr04/mavenConfig.gradle index 43dac43..7f5c21b 100644 --- a/driver-hcsr04/mavenConfig.gradle +++ b/driver-hcsr04/mavenConfig.gradle @@ -25,6 +25,7 @@ mvn_config.issue_tracker_url = 'https://github.com/leinardi/androidthings-driver mvn_config.vcs_url = 'https://github.com/leinardi/androidthings-drivers.git' mvn_config.description = 'HC-SR04 driver for Android Things' mvn_config.tags = 'hcsr04,android-things,android,raspberry-pi' // Comma separated +mvn_config.githubRepo = 'leinardi/androidthings-drivers' mvn_config.inception_year = '2017' mvn_config.dryRun = false mvn_config.publish = false diff --git a/driver-hd44780/mavenConfig.gradle b/driver-hd44780/mavenConfig.gradle index f2e712b..bc0878b 100644 --- a/driver-hd44780/mavenConfig.gradle +++ b/driver-hd44780/mavenConfig.gradle @@ -25,6 +25,7 @@ mvn_config.issue_tracker_url = 'https://github.com/leinardi/androidthings-driver mvn_config.vcs_url = 'https://github.com/leinardi/androidthings-drivers.git' mvn_config.description = 'HD44780 LCD driver for Android Things' mvn_config.tags = 'pcf8574,hd44780,android-things,android,raspberry-pi' // Comma separated +mvn_config.githubRepo = 'leinardi/androidthings-drivers' mvn_config.inception_year = '2017' mvn_config.dryRun = false mvn_config.publish = false diff --git a/driver-lsm9ds1/mavenConfig.gradle b/driver-lsm9ds1/mavenConfig.gradle index 6fe519a..0418a99 100644 --- a/driver-lsm9ds1/mavenConfig.gradle +++ b/driver-lsm9ds1/mavenConfig.gradle @@ -25,6 +25,7 @@ mvn_config.issue_tracker_url = 'https://github.com/leinardi/androidthings-driver mvn_config.vcs_url = 'https://github.com/leinardi/androidthings-drivers.git' mvn_config.description = 'LSM9DS1 driver for Android Things' mvn_config.tags = 'lsm9ds1,android-things,android,raspberry-pi' // Comma separated +mvn_config.githubRepo = 'leinardi/androidthings-drivers' mvn_config.inception_year = '2017' mvn_config.dryRun = false mvn_config.publish = false diff --git a/driver-sh1106/mavenConfig.gradle b/driver-sh1106/mavenConfig.gradle index d055e0b..d56cc59 100644 --- a/driver-sh1106/mavenConfig.gradle +++ b/driver-sh1106/mavenConfig.gradle @@ -25,6 +25,7 @@ mvn_config.issue_tracker_url = 'https://github.com/leinardi/androidthings-driver mvn_config.vcs_url = 'https://github.com/leinardi/androidthings-drivers.git' mvn_config.description = 'SH1106 display driver for Android Things' mvn_config.tags = 'sh1106,android-things,android,raspberry-pi' // Comma separated +mvn_config.githubRepo = 'leinardi/androidthings-drivers' mvn_config.inception_year = '2017' mvn_config.dryRun = false mvn_config.publish = false diff --git a/sample-epaperdriverhat/.gitignore b/sample-epaperdriverhat/.gitignore new file mode 100644 index 0000000..796b96d --- /dev/null +++ b/sample-epaperdriverhat/.gitignore @@ -0,0 +1 @@ +/build diff --git a/sample-epaperdriverhat/README.md b/sample-epaperdriverhat/README.md new file mode 100644 index 0000000..49534ad --- /dev/null +++ b/sample-epaperdriverhat/README.md @@ -0,0 +1,44 @@ +## E-Paper Driver HAT sample for Android Things + +This sample demonstrates how to control the GDEW075T8 E-Paper display using E-Paper Driver HAT with +Android Things. + +## Pre-requisites + +- Android Things compatible board +- Android Studio 2.2+ +- 1 [GDEW075T8 + E-Paper Driver HAT](https://www.waveshare.com/wiki/7.5inch_e-Paper_HAT) + + +# Build and install + +On Android Studio, click on the "Run" button. + +If you prefer to run on the command line, from this repository's root directory, type + +```bash +./gradlew sample-epaperdriverhat:installDebug +adb shell am start com.leinardi.android.things.sample.epaperdriverhat/.EpdScreenActivity +``` + +If you have everything set up correctly, you will see an image on the screen. + + +## License + +Copyright 2018 Roberto Leinardi. + +Licensed to the Apache Software Foundation (ASF) under one or more contributor +license agreements. See the NOTICE file distributed with this work for +additional information regarding copyright ownership. The ASF licenses this +file to you under the Apache License, Version 2.0 (the "License"); you may not +use this file except in compliance with the License. You may obtain a copy of +the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +License for the specific language governing permissions and limitations under +the License. diff --git a/sample-epaperdriverhat/build.gradle b/sample-epaperdriverhat/build.gradle new file mode 100644 index 0000000..827946f --- /dev/null +++ b/sample-epaperdriverhat/build.gradle @@ -0,0 +1,54 @@ +/* + * Copyright 2018 Roberto Leinardi. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +apply plugin: 'com.android.application' +apply from: rootProject.file('checkstyle.gradle') + +android { + compileSdkVersion build_versions.target_sdk + buildToolsVersion build_versions.build_tools + + defaultConfig { + applicationId "com.leinardi.android.things.sample.epaperdriverhat" + minSdkVersion build_versions.min_sdk + targetSdkVersion build_versions.target_sdk + versionCode build_versions.version_code + versionName "1.0" + testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" + + } + + compileOptions { + sourceCompatibility build_versions.java_version + targetCompatibility build_versions.java_version + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + } + +} + +dependencies { + implementation fileTree(dir: 'libs', include: ['*.jar']) + compileOnly deps.androidthings + implementation deps.support.annotations + implementation project(':driver-epaperdriverhat') + +} diff --git a/sample-epaperdriverhat/proguard-rules.pro b/sample-epaperdriverhat/proguard-rules.pro new file mode 100644 index 0000000..f1b4245 --- /dev/null +++ b/sample-epaperdriverhat/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile diff --git a/sample-epaperdriverhat/src/main/AndroidManifest.xml b/sample-epaperdriverhat/src/main/AndroidManifest.xml new file mode 100644 index 0000000..89d657a --- /dev/null +++ b/sample-epaperdriverhat/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sample-epaperdriverhat/src/main/java/com/leinardi/android/things/sample/epaperdriverhat/BoardDefaults.java b/sample-epaperdriverhat/src/main/java/com/leinardi/android/things/sample/epaperdriverhat/BoardDefaults.java new file mode 100644 index 0000000..5fbc92c --- /dev/null +++ b/sample-epaperdriverhat/src/main/java/com/leinardi/android/things/sample/epaperdriverhat/BoardDefaults.java @@ -0,0 +1,45 @@ +/* + * Copyright 2018 Roberto Leinardi. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.leinardi.android.things.sample.epaperdriverhat; + +import android.os.Build; + +@SuppressWarnings("WeakerAccess") +public class BoardDefaults { + private static final String DEVICE_RPI3 = "rpi3"; + private static final String DEVICE_IMX6UL_PICO = "imx6ul_pico"; + private static final String DEVICE_IMX7D_PICO = "imx7d_pico"; + + private BoardDefaults() { + } + + /** + * Return the preferred I2C port for each board. + */ + public static String getSPIPort() { + switch (Build.DEVICE) { + case DEVICE_RPI3: + return "SPI0.0"; + case DEVICE_IMX6UL_PICO: + return "SPI3.0"; + case DEVICE_IMX7D_PICO: + return "SPI3.1"; + default: + throw new IllegalStateException("Unknown Build.DEVICE " + Build.DEVICE); + } + } +} diff --git a/sample-epaperdriverhat/src/main/java/com/leinardi/android/things/sample/epaperdriverhat/EpdScreenActivity.java b/sample-epaperdriverhat/src/main/java/com/leinardi/android/things/sample/epaperdriverhat/EpdScreenActivity.java new file mode 100644 index 0000000..ef9c853 --- /dev/null +++ b/sample-epaperdriverhat/src/main/java/com/leinardi/android/things/sample/epaperdriverhat/EpdScreenActivity.java @@ -0,0 +1,64 @@ +/* + * Copyright 2018 Roberto Leinardi. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.leinardi.android.things.sample.epaperdriverhat; + +import android.app.Activity; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.os.Bundle; +import android.util.Log; + +import com.leinardi.android.things.driver.epaperdriverhat.BitmapHelper; +import com.leinardi.android.things.driver.epaperdriverhat.Gdew075t8Epd; +import com.leinardi.android.things.sample.epd.R; + +import java.io.IOException; + +/** + * Activity that tests the EPD. + */ +public class EpdScreenActivity extends Activity { + private static final String TAG = EpdScreenActivity.class.getSimpleName(); + Gdew075t8Epd mEpd; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + Log.d(TAG, "EPD screen activity created"); + try { + mEpd = new Gdew075t8Epd(); + Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.monocolor_640x384); + BitmapHelper.setBmpData(mEpd, 0, 0, bitmap, false); + mEpd.show(); // render the pixel data + } catch (IOException e) { + Log.e(TAG, "Error initializing EPD", e); + } + } + + @Override + public void onDestroy() { + super.onDestroy(); + Log.d(TAG, "Closing EPD"); + try { + mEpd.close(); + } catch (IOException e) { + Log.e(TAG, "Exception closing EPD", e); + } finally { + mEpd = null; + } + } +} diff --git a/sample-epaperdriverhat/src/main/res/drawable-nodpi/monocolor_640x384.png b/sample-epaperdriverhat/src/main/res/drawable-nodpi/monocolor_640x384.png new file mode 100644 index 0000000..09490ef Binary files /dev/null and b/sample-epaperdriverhat/src/main/res/drawable-nodpi/monocolor_640x384.png differ diff --git a/sample-epaperdriverhat/src/main/res/values/strings.xml b/sample-epaperdriverhat/src/main/res/values/strings.xml new file mode 100644 index 0000000..579e54e --- /dev/null +++ b/sample-epaperdriverhat/src/main/res/values/strings.xml @@ -0,0 +1,19 @@ + + + + Sample E-Paper Driver HAT + diff --git a/sample-epaperdriverhat/src/main/res/values/styles.xml b/sample-epaperdriverhat/src/main/res/values/styles.xml new file mode 100644 index 0000000..51e3dac --- /dev/null +++ b/sample-epaperdriverhat/src/main/res/values/styles.xml @@ -0,0 +1,22 @@ + + + + + +