In order to integrate the BLE library, add dependency on app level build.gradle file.
implementation 'com.fretzealot:fz-android-sdk:1.0.0'
Under the <manifest>
tag in your manifest, add the permissions:
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
Register following service in manfest file inside <application>
tag:
<service
android:name="com.fz.blelib.BluetoothLeService"
android:enabled="true" />
While using the library for the first time in the app, a library instance should be created as follows:
To integrate this BLE library in android application minimum Android version 19 is required
In the activity where the library is used for the first time in the application lifecycle, DO NOT call finish();
since the library instance is created using its context throughout the app. See below example activity:
package com.fretzealot.led;
import android.Manifest;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGattService;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v4.app.ActivityCompat;
import android.support.v7.app.AppCompatActivity;
import android.widget.Toast;
import com.fz.blelib.LEDBLELib;
import com.fz.blelib.LEDBLELibCallback;
import java.util.List;
public class MainActivity extends AppCompatActivity {
private static final int REQUEST_ENABLE_BT = 101;
private static final int PERMISSION_CODE = 102;
LEDBLELib ledbleLib;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ledbleLib = LEDBLELib.getInstance(getApplicationContext());
if (ledbleLib.isSupported()) {
if (ledbleLib.isEnabled()) {
checkForPermissions();
} else {
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
}
} else {
Toast.makeText(this, "Bluetooth not supported", Toast.LENGTH_LONG).show();
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == REQUEST_ENABLE_BT && resultCode == RESULT_OK) {
checkForPermissions();
}
}
private void checkForPermissions() {
if (hasPermissions(Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION)) {
startScanner();
} else {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION}
, PERMISSION_CODE);
}
}
private boolean hasPermissions(String... permissions) {
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && permissions != null) {
for (String permission : permissions) {
if (ActivityCompat.checkSelfPermission(this, permission) != PackageManager.PERMISSION_GRANTED) {
return false;
}
}
}
return true;
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == PERMISSION_CODE) {
for (int grantResult : grantResults) {
if (grantResult != PackageManager.PERMISSION_GRANTED) {
Toast.makeText(this, "Location permission required to connect fretzealot", Toast.LENGTH_LONG).show();
return; }
}
startScanner();
}
}
private void startScanner() {
ledbleLib.startScan(new BluetoothAdapter.LeScanCallback() {
@Override
public void onLeScan(BluetoothDevice bluetoothDevice, int i, byte[] bytes) {
if (bluetoothDevice != null && bluetoothDevice.getName() != null && bluetoothDevice.getName().toLowerCase().equals("fret zealot")) {
ledbleLib.stopScan();
startConnectionService(bluetoothDevice.getAddress());
}
}
});
}
private void startConnectionService(String address) {
ledbleLib.startService(address, new LEDBLELibCallback() {
@Override
public void onConnected() {
Toast.makeText(MainActivity.this, "Fret zealot connected", Toast.LENGTH_LONG).show();
}
@Override
public void onDisconnected() {
Toast.makeText(MainActivity.this, "Fret zealot disconnected", Toast.LENGTH_LONG).show();
}
@Override
public void onServiceDiscovered(List<BluetoothGattService> serviceList) {
}
@Override
public void onDataReceived(byte[] rxBytes) {
}
@Override
public void onBatteryString(String value) {
}
@Override
public void onManufactureNameString(String value) {
}
@Override
public void onModelNumberString(String value) {
}
@Override
public void onSerialNumberString(String value) {
}
@Override
public void onHardwareRevisionString(String value) {
}
});
ledbleLib.onResume();
}
}
The next time the library is instantiated (ideally in a different class), it can be instantiated as follows:
mLib = LEDBLELib.getInstance();
And in order to connect to a device, the following method needs to be called:
mLib.connect(deviceAddress)
OR
mLib.startService() --> Below
where deviceAddress is a String
.
To start the service on Fret Zealot :
mLib.startService(mDeviceAddress, mLibCallback);
protected LEDBLELibCallback mLibCallback = new LEDBLELibCallback() {
@Override
public void onConnected() {
Toast.makeText(MainActivity.this, "Device connected", Toast.LENGTH_SHORT).show();
}
@Override
public void onDisconnected() {
try {
mLib.disconnect();
} catch (Exception e) {
e.printStackTrace();
}
Toast.makeText(MainActivity.this, "Device disconnected", Toast.LENGTH_SHORT).show();
}
@Override
public void onServiceDiscovered(List<BluetoothGattService> serviceList) {
try {
if (!mLib.isLED()) {
Toast.makeText(MainActivity.this, "Connected (Not LED)", Toast.LENGTH_SHORT).show();
}
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void onDataReceived(byte[] rxBytes) {
}
@Override
public void onBatteryString(String s) {
}
@Override
public void onManufactureNameString(String s) {
}
@Override
public void onModelNumberString(String s) {
}
@Override
public void onSerialNumberString(String s) {
}
@Override
public void onHardwareRevisionString(String s) {
}
};
Once the instance is ready, we can use the following methods of the library to send commands to Fret Zealot.
All the commands are held in a command buffer. This means that the commands are collected into a buffer prior to getting sent. A command buffer can hold a maximum of 5 commands. To insert a command into the buffer, various methods can be called as shown below.
All the values sent as arguments should be converted to byte
from int
Also, the parameters commonly used are:
fret and string - Fret is self explanatory, and the valid range is 0 (Open) to 14. The tuning is read from the 5th string to the 0th string: E-A-D-G-B-E. Hence, the string indices would be as follows: E=5, A=4, D=3, G=2, B=1, E=0
red, blue and green - These are the values for the LED color. Possible values for each can be between 0 and 15.
intensity - The intensity of the LED. Possible values are between 0 and 10. fadeMode - The fade effect with which to light up the LED. Possible values for fadeMode are between 0 and 4.
Fade effect reference chart:
Fade Mode Value Description
0 Fade not active //Set Pixel On **Most Common**
1 Fade in short //Fade in Pixel over 50ms
2 Fade in long //Fade out Pixel over 50ms
3 Fade out short //Fade in Pixel over 200ms
4 Fade out long //fade out Pixel over 200ms
There are several methods for controlling LED state on the fretboard
The set
method - This method lights up a single LED
mLib.set((byte)fret, (byte)string, (byte)red, (byte)blue, (byte)green, (byte)intensity, (byte)fadeMode);
The set_across
method - This method lights up all the frets in a string
mLib.set_across((byte)string, (byte)red, (byte)blue, (byte)green, (byte)intensity, (byte)fadeMode);
The set_all
method - This method lights up the whole fretboard with the LED color supplied as arguments.
mLib.set_all((byte)string, (byte)red, (byte)blue, (byte)green, (byte)intensity, (byte)fadeMode);
The set_subset
method - This method lights up a string from a given fret to the 14th fret. For example, if you need to turn on the LEDs from fret 8 to fret 14, this is the method for you. However, the upper limit (14) cannot be changed.
mLib.set_subset((byte)starting_fret, (byte)string, (byte)red, (byte)blue, (byte)green, (byte)intensity, (byte)fadeMode);
The clear
method - This method sets each LED on the fretboard to off. This counts as one command of the 5 allowed in the command buffer
mLib.clear();
There exist several utility methods for inteacting with the command buffer. The command buffer holds 5 (five) serialized commands, and mirrors the size of the Bluetooth MTU. This structure does not need to be initialized.
The sendCommandBufferClear
method - This method clears the buffer of any existing data, and should be invoked before each write to the fretboard.
mLib.sendCommandBufferClear();
The sendCommandFlush()
method - This method dumps the contents (up to 5 commands) of the command buffer to the BLE device. A minimum of 1 ms is required as the value of DELAY
. Please ensure that this method is always called in a Handler
's runnable with delay.
private static final int DELAY = 1;
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
mBLE.sendCommandFlush();
}
}, DELAY);
LED commands should be wrapped in these utility commands, to ensure delivery to the Fret Zealot. A typical command to set completely new pixels -- (C) major Triad in Standard Tuning looks as follows:
mLib.sendCommandBufferClear(); // Flush the buffer
mLib.clear(); //Clear all displayed Pixels
mLib.set((byte) 3, (byte) 4, (byte) 0, (byte) 15, (byte) 0, (byte) 9, (byte) 0); // Set 'C' to blue
mLib.set((byte) 2, (byte) 3, (byte) 0, (byte) 0, (byte) 15, (byte) 9, (byte) 0); // Set 'E' to green
mLib.set((byte) 0, (byte) 2, (byte) 15, (byte) 15, (byte) 15, (byte) 9, (byte) 0); // Set 'G' to blue
private static final int DELAY = 1;
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
mBLE.sendCommandFlush();
}
}, DELAY); // Send commands to the Fret Zealot
The onResume()
method - This method reconnects the bluetooth connection when an app activity is resumed. (For example moved to background/foreground) Please ensure to call mLib.onResume() each time the app is refocused.
@Override
protected void onResume() {
mLib.onResume();
super.onResume();
}
The onPause()
method - This method disconnect the bluetooth connection when an activity is paused.
phase.
@Override
protected void onPause() {
mLib.onPause();
super.onPause();
}
The isConnected()
method - This method returns boolean value true if fretboard is connected with application and false
if fretboard is not connected with application.
mLib.isConnected();
strand_start :
intensity : LED intensity on fretboard
fade_mode:
fade_mode Description
0 No lights
1 Sparkler
2 Bolt
3 Rainbow
mLib.sendCommandBufferClear();
mLib.set_display((byte) strand_start, (byte) intensity, (byte) fadValue);
private static final int DELAY = 1;
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
mBLE.sendCommandFlush();
}
}, DELAY);
Function | Color | FZ RGB |
---|---|---|
Index Finger | Blue | [0,0,15] |
Middle Finger | Green | [0,15,0] |
Ring Finger | Yellow | [12,15,0] |
Finger Finger | Purple | [12,0,15] |
Open String | White | [12,15,15] |
Muted String | Red | [4,0,0] |
use the ‘set_across’ command for muting