/*
* Protocoder
* A prototyping platform for Android devices
*
* Victor Diaz Barrales victormdb@gmail.com
*
* Copyright (C) 2014 Victor Diaz
* Copyright (C) 2013 Motorola Mobility LLC
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the Software
* is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package org.protocoderrunner.apprunner.api.boards;
import android.content.Context;
import com.physicaloid.lib.Boards;
import com.physicaloid.lib.Physicaloid;
import com.physicaloid.lib.Physicaloid.UploadCallBack;
import com.physicaloid.lib.programmer.avr.UploadErrors;
import com.physicaloid.lib.usb.driver.uart.ReadLisener;
import com.physicaloid.lib.usb.driver.uart.UartConfig;
import org.protocoderrunner.apidoc.annotation.APIMethod;
import org.protocoderrunner.apidoc.annotation.APIParam;
import org.protocoderrunner.apprunner.AppRunnerSettings;
import org.protocoderrunner.apprunner.PInterface;
import org.protocoderrunner.apprunner.ProtocoderScript;
import org.protocoderrunner.sensors.WhatIsRunning;
import org.protocoderrunner.utils.MLog;
import java.io.File;
import java.io.UnsupportedEncodingException;
public class PArduino extends PInterface {
private final String TAG = "PArduino";
private Physicaloid mPhysicaloid;
private boolean started = false;
private String msg = "";
public static final Boards ARDUINO_UNO = Boards.ARDUINO_UNO;
public static final Boards ARDUINO_DUEMILANOVE_328 = Boards.ARDUINO_DUEMILANOVE_328;
public static final Boards ARDUINO_DUEMILANOVE_168 = Boards.ARDUINO_DUEMILANOVE_168;
public static final Boards ARDUINO_NANO_328 = Boards.ARDUINO_NANO_328;
public static final Boards ARDUINO_NANO_168 = Boards.ARDUINO_NANO_168;
public static final Boards ARDUINO_MEGA_2560_ADK = Boards.ARDUINO_MEGA_2560_ADK;
public static final Boards ARDUINO_MEGA_1280 = Boards.ARDUINO_MEGA_1280;
public static final Boards ARDUINO_MINI_328 = Boards.ARDUINO_MINI_328;
public static final Boards ARDUINO_MINI_168 = Boards.ARDUINO_MINI_168;
public static final Boards ARDUINO_ETHERNET = Boards.ARDUINO_ETHERNET;
public static final Boards ARDUINO_FIO = Boards.ARDUINO_FIO;
public static final Boards ARDUINO_BT_328 = Boards.ARDUINO_BT_328;
public static final Boards ARDUINO_BT_168 = Boards.ARDUINO_BT_168;
public static final Boards ARDUINO_LILYPAD_328 = Boards.ARDUINO_LILYPAD_328;
public static final Boards ARDUINO_LILYPAD_168 = Boards.ARDUINO_LILYPAD_168;
public static final Boards ARDUINO_PRO_5V_328 = Boards.ARDUINO_PRO_5V_328;
public static final Boards ARDUINO_PRO_5V_168 = Boards.ARDUINO_PRO_5V_168;
public static final Boards ARDUINO_PRO_33V_328 = Boards.ARDUINO_PRO_33V_328;
public static final Boards ARDUINO_PRO_33V_168 = Boards.ARDUINO_PRO_33V_168;
public static final Boards ARDUINO_NG_168 = Boards.ARDUINO_NG_168;
public static final Boards ARDUINO_NG_8 = Boards.ARDUINO_NG_8;
public static final Boards BALANDUINO = Boards.BALANDUINO;
public static final Boards POCKETDUINO = Boards.POCKETDUINO;
public static final Boards PERIDOT = Boards.PERIDOT;
public static final Boards FREADUINO = Boards.ARDUINO_UNO;
public static final Boards BQ_ZUM = Boards.ARDUINO_BT_328;
public static final Boards NONE = Boards.NONE;
public PArduino(Context a) {
super(a);
}
public void start() {
WhatIsRunning.getInstance().add(this);
mPhysicaloid = new Physicaloid(a.get());
open();
}
// Initializes arduino board
public void start(int bauds, onReadCB callbackfn) {
WhatIsRunning.getInstance().add(this);
if (!started) {
started = true;
MLog.d("PArduino", "start ");
mPhysicaloid = new Physicaloid(a.get());
open();
mPhysicaloid.setBaudrate(bauds);
onRead(callbackfn);
}
}
// Opens a device and communicate USB UART by default settings
public void open() {
if (mPhysicaloid.isOpened()) {
MLog.d(TAG, "The device is opened");
return;
}
if (mPhysicaloid.open()) {
MLog.d(TAG, "Device opened");
} else {
MLog.d(TAG, "Cannot open the device");
}
}
// Closes a device
public void close() {
if (mPhysicaloid.close()) {
// clear read callback
mPhysicaloid.clearReadListener();
MLog.d(TAG, "Device closed");
} else {
MLog.d(TAG, "Cannot close the device");
}
}
@ProtocoderScript
@APIMethod(description = "sends commands to arduino board", example = "arduino.write(\"LEDON\");")
public void write(String cmd) {
if (mPhysicaloid.isOpened()) {
byte[] buf = cmd.getBytes();
mPhysicaloid.write(buf, buf.length);
MLog.d(TAG, "Command sent to the device");
} else {
MLog.d(TAG, "Cannot write to the device. The device is not opened");
}
}
// --------- onReadCB ---------//
public interface onReadCB {
void event(String responseString);
}
@ProtocoderScript
@APIMethod(description = "reads from the arduino board", example = "arduino.read()")
public String read() {
String str = "";
if (mPhysicaloid.isOpened()) {
byte[] buf = new byte[256];
int readSize = mPhysicaloid.read(buf);
if(readSize>0) {
try {
str = new String(buf, "UTF-8");
} catch (UnsupportedEncodingException e) {
MLog.d(TAG, e.toString());
}
}
} else {
MLog.d(TAG, "Cannot read from the device. The device is not opened");
}
return str;
}
@ProtocoderScript
@APIMethod(description = "adds a read callback that is called when one or more bytes are read", example = "")
@APIParam(params = { "function(data)" })
public void onRead(final onReadCB callbackfn) {
if (mPhysicaloid.isOpened()) {
mPhysicaloid.addReadListener(new ReadLisener() {
String readStr;
// callback when reading one or more size buffer
@Override
public void onRead(int size) {
byte[] buf = new byte[size];
mPhysicaloid.read(buf, size);
try {
readStr = new String(buf, "UTF-8");
} catch (UnsupportedEncodingException e) {
MLog.d(TAG, e.toString());
return;
}
msg = msg + readStr;
//MLog.network(a.get(), TAG, "msg " + msg);
//MLog.network(a.get(), TAG, "readStr " + readStr);
int newLineIndex = msg.indexOf('\n');
//MLog.network(a.get(), TAG, "index " + newLineIndex);
String msgReturn = "";
if (newLineIndex != -1) {
msgReturn = msg.substring(0, newLineIndex);
msg = msg.substring(newLineIndex + 1, msg.length());
//MLog.network(a.get(), TAG, "msgReturn " + msgReturn);
}
if (msgReturn.trim().equals("") == false) {
final String finalMsgReturn = msgReturn;
mHandler.post(new Runnable() {
@Override
public void run() {
callbackfn.event(finalMsgReturn);
}
});
}
}
});
}
}
// --------- uploadCallback ---------//
public interface uploadCB {
void event(int progress);
}
// Uploads a binary file to a device on background process. No need to open().
// * @param board board profile e.g. Packages.com.physicaloid.lib.Boards.ARDUINO_UNO
// * @param fileName a binary file name e.g. Blink.hex
// * @param callbackfn callback when the upload has been completed (success, fail or error)
//
@ProtocoderScript
@APIMethod(description = "uploads a binary file to a device on background process", example = "")
@APIParam(params = { "board", "fileName", "function(error)" })
public void upload(Boards board, String fileName, final uploadCB callbackfn) {
if (mPhysicaloid.isOpened()) {
// Build the absolute path
String filePath = AppRunnerSettings.get().project.getStoragePath() + File.separator + fileName;
callbackfn.event(0);
// Check if the fileName includes the .hex extension
if (!filePath.toLowerCase().endsWith(".hex")) {
MLog.d(TAG, "Cannot upload the sketch. The file must have a .hex extension");
return;
}
try {
mPhysicaloid.upload(board, filePath, new UploadCallBack() {
String responseStr;
@Override
public void onPreUpload() {
MLog.d(TAG, "Upload : Start");
}
@Override
public void onUploading(int value) {
uploadCallbackEvent(value, callbackfn);
}
@Override
public void onPostUpload(boolean success) {
//MLog.network(a.get(), TAG, "5");
if(success) {
// uploadCallbackEvent(100, callbackfn);
} else {
uploadCallbackEvent(-1, callbackfn);
}
}
@Override
public void onCancel() {
uploadCallbackEvent(-1, callbackfn);
}
@Override
public void onError(UploadErrors err) {
MLog.d(TAG, "Error : " + err.toString());
uploadCallbackEvent(-1, callbackfn);
}
});
} catch (RuntimeException e) {
MLog.d(TAG, e.toString());
}
} else {
MLog.d(TAG, "Cannot upload the sketch. The device is not opened");
}
}
private void uploadCallbackEvent(final int value, final uploadCB callbackfn) {
mHandler.post(new Runnable() {
@Override
public void run() {
callbackfn.event(value);
}
});
}
@ProtocoderScript
@APIMethod(description = "uploads a binary file to a device on background process", example = "")
@APIParam(params = { "board", "fileName" })
public void upload(Boards board, String fileName) {
upload(board, fileName, new uploadCB() {
@Override
public void event(int progress) {
}
});
}
@ProtocoderScript
@APIMethod(description = "sets baud rate", example = "arduino.setBaudrate(9600)")
@APIParam(params = { "baudrate" })
public boolean setBaudrate(int baudrate) {
try {
return mPhysicaloid.setBaudrate(baudrate);
} catch (RuntimeException e) {
return false;
}
}
@ProtocoderScript
@APIMethod(description = "returns a list of the supported devices that you can use with the \"upload\" function", example = "arduino.getSupportedDevices()")
public Boards[] getSupportedDevices() {
MLog.d(TAG, Boards.ARDUINO_BT_328.toString());
return com.physicaloid.lib.Boards.values();
/*
Boards[] boards = new Boards[]{
Boards.ARDUINO_UNO,
Boards.ARDUINO_DUEMILANOVE_328,
Boards.ARDUINO_DUEMILANOVE_168,
Boards.ARDUINO_NANO_328,
Boards.ARDUINO_NANO_168,
Boards.ARDUINO_MEGA_2560_ADK,
Boards.ARDUINO_MEGA_1280,
Boards.ARDUINO_MINI_328,
Boards.ARDUINO_MINI_168,
Boards.ARDUINO_ETHERNET,
Boards.ARDUINO_FIO,
Boards.ARDUINO_BT_328,
Boards.ARDUINO_BT_168,
Boards.ARDUINO_LILYPAD_328,
Boards.ARDUINO_LILYPAD_168,
Boards.ARDUINO_PRO_5V_328,
Boards.ARDUINO_PRO_5V_168,
Boards.ARDUINO_PRO_33V_328,
Boards.ARDUINO_PRO_33V_168,
Boards.ARDUINO_NG_168,
Boards.ARDUINO_NG_8,
Boards.BALANDUINO,
Boards.POCKETDUINO,
Boards.PERIDOT,
Boards.NONE};
return boards;
*/
}
@ProtocoderScript
@APIMethod(description = "sets serial configuration", example = "")
@APIParam(params = { "settings" })
public void setConfig(UartConfig settings) {
try {
mPhysicaloid.setConfig(settings);
} catch (RuntimeException e) {
MLog.d(TAG, e.toString());
}
}
@ProtocoderScript
@APIMethod(description = "sets data bits", example = "")
@APIParam(params = { "dataBits" })
public boolean setDataBits(int dataBits) {
try {
return mPhysicaloid.setDataBits(dataBits);
} catch (RuntimeException e) {
MLog.d(TAG, e.toString());
return false;
}
}
@ProtocoderScript
@APIMethod(description = "sets parity bits", example = "")
@APIParam(params = { "parity" })
public boolean setParity(int parity) {
try {
return mPhysicaloid.setParity(parity);
} catch (RuntimeException e) {
MLog.d(TAG, e.toString());
return false;
}
}
@ProtocoderScript
@APIMethod(description = "sets stop bits", example = "")
@APIParam(params = { "stopBits" })
public boolean setStopBits(int stopBits) {
try {
return mPhysicaloid.setStopBits(stopBits);
} catch (RuntimeException e) {
MLog.d(TAG, e.toString());
return false;
}
}
@ProtocoderScript
@APIMethod(description = "sets flow control DTR/RTS", example = "")
@APIParam(params = { "stopBits" })
public boolean setDtrRts(boolean dtrOn, boolean rtsOn) {
try {
return mPhysicaloid.setDtrRts(dtrOn, rtsOn);
} catch (RuntimeException e) {
MLog.d(TAG, e.toString());
return false;
}
}
public void stop() {
close();
}
}