Skip to content

Commit

Permalink
LRemote Update (#97)
Browse files Browse the repository at this point in the history
- New `LRemoteJoystick` control
- New example `JoyStick` to demonstrate the usage of `LRemoteJoystick`
- Add a queue for `rcEvent` BLE characteristic to handle multiple incoming events. The queue implementation comes from https://github.com/sdesalas/Arduino-Queue.h by Steven de Salas.
  • Loading branch information
pablosun authored Apr 17, 2018
1 parent 951f3af commit 7ef9b19
Show file tree
Hide file tree
Showing 5 changed files with 329 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -323,7 +323,7 @@ class LBLECharacteristicBuffer : public LBLECharacteristicBase
virtual int notify(bt_handle_t connection);
virtual int indicate(bt_handle_t connection);

private:
protected:
LBLEValueBuffer m_data;
LBLECharacteristicWrittenInfo m_writtenInfo;
};
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
/*
This example configures LinkIt 7697 to a reciver of the iOS LinkIt Remote App
created Aug 2017
*/
#include <LRemote.h>

LRemoteJoyStick stickLeft;
LRemoteJoyStick stickRight;
LRemoteLabel labelLeft;
LRemoteLabel labelRight;

void setup() {
//Initialize serial and wait for port to open:
Serial.begin(9600);

Serial.println("Start configuring remote");

// Initialize GPIO
pinMode(LED_BUILTIN, OUTPUT);
digitalWrite(LED_BUILTIN, 0);

// Setup the Remote Control's UI canvas
LRemote.setName("LinkIt 7697");

// We use a landscape since it is easir to contorl joysticks
LRemote.setOrientation(RC_LANDSCAPE);
LRemote.setGrid(4, 2);

// Add left stick
stickLeft.setPos(0, 1);
stickLeft.setSize(1, 1);
stickLeft.setColor(RC_ORANGE);
LRemote.addControl(stickLeft);

// Add Right stick
stickRight.setPos(3, 1);
stickRight.setSize(1, 1);
stickRight.setColor(RC_BLUE);
LRemote.addControl(stickRight);

// Add a simple text label
labelLeft.setText("(0, 0)");
labelLeft.setPos(0, 0);
labelLeft.setSize(1, 1);
labelLeft.setColor(RC_GREY);
LRemote.addControl(labelLeft);

labelRight.setText("(0, 0)");
labelRight.setPos(3, 0);
labelRight.setSize(1, 1);
labelRight.setColor(RC_GREY);
LRemote.addControl(labelRight);


// Start broadcasting our remote contoller
// This method implicitly initialized underlying BLE subsystem
// to create a BLE peripheral, and then
// start advertisement on it.
LRemote.begin();
Serial.println("begin() returned");
}

void checkAndUpdateLabel(LRemoteLabel& label, LRemoteJoyStick& stick) {
if(stick.isValueChanged()){
LRemoteDirection d = stick.getValue();
// d.x and d.y are the value from the Joystick component:
// d.x : -100 ~ 100, where 0 is center, -100 is leftmost, and 100 is rightmost.
// d.y : -100 ~ 100, where 0 is center, -100 is bottommost, and 100 is topmost.

// you can print d directly.
Serial.println(d);

// in this example, we simply pass the value of d.x/d.y
// back to the LinkIt Remote app.
label.updateText(d.toString());
}
}

void loop() {
// check if we are connect by some
// BLE central device, e.g. an mobile app
if(!LRemote.connected()) {
Serial.println("waiting for connection");
delay(1000);
} else {
// The interval between button down/up
// can be very short - e.g. a quick tap
// on the screen.
// We could lose some event if we
// delay something like 100ms.
delay(15);
}

// Process the incoming BLE write request
// and translate them to control events
LRemote.process();

// refer to this function to know how to parse the values from joystick.
checkAndUpdateLabel(labelLeft, stickLeft);
checkAndUpdateLabel(labelRight, stickRight);

}
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,59 @@
#include <LBLEPeriphral.h>
#include "LRemote.h"
#include <vector>
#include "SalasQueue.h"

LRemoteClass LRemote;

// custom BLE characteristic
class LBLECharacteristicEvent : public LBLECharacteristicBuffer {
public:
static const size_t EVENT_QUEUE_SIZE = 8;

LBLECharacteristicEvent(LBLEUuid uuid, uint32_t permission) :
LBLECharacteristicBuffer(uuid, permission),
m_eventQueue(EVENT_QUEUE_SIZE)
{}

LBLECharacteristicEvent(LBLEUuid uuid) :
LBLECharacteristicBuffer(uuid),
m_eventQueue(EVENT_QUEUE_SIZE)
{}

virtual uint32_t onWrite(void *data, uint16_t size, uint16_t offset) {
// process the event
const auto ret = LBLECharacteristicBuffer::onWrite(data, size, offset);

// check if we're reaching a "complete" RCEventInfo
// if so, pusht the event into event queue
const size_t totalWritten = size + offset;
if(totalWritten >= m_data.size()) {
LOG_I(common, "ARD:LRemote:RCEventInfo done, push into Q");
m_eventQueue.push(*(RCEventInfo*)&m_data[0]);
}

return ret;
}

// get "unprocessed" events
size_t eventCount() {
return m_eventQueue.count();
}

RCEventInfo popEvent() {
return m_eventQueue.pop();
}

public:
Queue<RCEventInfo> m_eventQueue;

protected:
// User should use popEvent() instead of getValue.
void getValue(uint8_t* buffer, uint16_t size, uint16_t offset) {
return LBLECharacteristicBuffer::getValue(buffer, size, offset);
}
};

// UUID definition
static LBLEUuid rcServiceUUID("3f60ab39-1710-4456-930c-7e9c9539917e");
static LBLEService rcService(rcServiceUUID);
Expand All @@ -27,7 +77,7 @@ static LBLECharacteristicString
rcNames("3f60ab39-1717-4456-930c-7e9c9539917e"); // String of control names,
// separated by the \n
// ASCII character
static LBLECharacteristicBuffer
static LBLECharacteristicEvent
rcEvent("b5d2ff7b-6eff-4fb5-9b72-6b9cff5181e7"); // Array of UINT8[4],
// (sequence, event,
// event data_byte1,
Expand Down Expand Up @@ -191,13 +241,8 @@ bool LRemoteClass::connected() { return LBLEPeripheral.connected(); }

void LRemoteClass::process() {
// check if new event coming in
if (rcEvent.isWritten()) {
const LBLECharacteristicWrittenInfo &written = rcEvent.getLastWrittenInfo();

RCEventInfo event = {0};

// retrieve the control's event info
rcEvent.getValue((uint8_t *)&event, sizeof(event), 0);
while (rcEvent.eventCount()) {
const RCEventInfo event = rcEvent.popEvent();

// scan and update event info
// make sure that the "sequence number" is incremented
Expand All @@ -208,8 +253,7 @@ void LRemoteClass::process() {
control.m_lastEvent = event;
control.m_lastEvent.seq = oldSeq + 1;

event.processedSeq = event.seq;
rcEvent.setValueBuffer((uint8_t *)&event, sizeof(event));
LOG_I(common, "ARD:LRemote:process() ctrl:%d seq:%d", i, oldSeq);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@
#include <LBLE.h>
#include <LBLEPeriphral.h>
#include <vector>
#include "Printable.h"

#define PROTOCOL_VERSION (3)
#define PROTOCOL_VERSION (4)

// Background / primary color of the UI control
enum RCColorType {
Expand Down Expand Up @@ -33,6 +34,7 @@ enum RCControlType {
RC_CIRCLEBUTTON = 3,
RC_SWITCHBUTTON = 4,
RC_SLIDER = 5,
RC_ANALOG = 6,
};

// Internal data structure for BLE events
Expand Down Expand Up @@ -225,6 +227,50 @@ class LRemoteSlider : public LRemoteUIControl {
int16_t m_initValue;
};

// This class encapsulate the return value of a Joystick
struct LRemoteDirection : public Printable{
int8_t x; // 0: neutral, -100: left-most, 100: right-most
int8_t y; // 0: newtral, -100: bottom-most, 100: top-most

LRemoteDirection(uint16_t data) {
x = static_cast<int8_t>(data >> 8);
y = static_cast<int8_t>(data & 0xFF);
}

virtual size_t printTo(Print& p) const {
return p.print(toString());
}

virtual String toString() const {
String t = "(x:";
t += x;
t += " y:";
t += y;
t += ")";
return t;
}
};

class LRemoteJoyStick : public LRemoteUIControl {
public:
LRemoteJoyStick()
: LRemoteUIControl(){
setType(RC_ANALOG);
}

bool isValueChanged() { return hasEvent(); }

// returns value according to remote slider value
LRemoteDirection getValue() {
consumeEvent();
LRemoteDirection c(m_lastEvent.data);
return c;
}

protected:

};

class LRemoteClass {
public:
LRemoteClass()
Expand Down
Loading

0 comments on commit 7ef9b19

Please sign in to comment.