Skip to content

Commit e69f5a8

Browse files
committed
use history in packet to prevent lost events
1 parent 78a1c12 commit e69f5a8

File tree

3 files changed

+133
-57
lines changed

3 files changed

+133
-57
lines changed

main.cpp

+37-29
Original file line numberDiff line numberDiff line change
@@ -3,19 +3,20 @@ MicroBit uBit;
33
const int8_t CALIBRATED_POWERS[] = {-49, -37, -33, -28, -25, -20, -15, -10};
44
uint8_t advertising = 0;
55
uint8_t tx_power_level = 6;
6-
uint8_t AdvData [] = {0xff, 0xff,
7-
0x55, 0x97,
8-
'0', '0',
9-
'.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.'};
6+
uint8_t AdvData [26] = {0xff, 0xff,
7+
0x55, 0x98,
8+
0,
9+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
1010
uint8_t buttonsState = 0;
1111
uint8_t eventCounter = 0;
1212

1313
char digit(uint8_t n)
14-
{
14+
{
1515
return '0' + n;
16-
}
16+
}
1717

18-
void startAdvertising() {
18+
void startAdvertising()
19+
{
1920
int connectable = 0;
2021
int interval = 160;
2122
uBit.bleManager.setTransmitPower(tx_power_level);
@@ -25,34 +26,34 @@ void startAdvertising() {
2526
uBit.bleManager.ble->accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE);
2627
uBit.bleManager.ble->accumulateAdvertisingPayload(GapAdvertisingData::MANUFACTURER_SPECIFIC_DATA, AdvData, sizeof(AdvData));
2728
uBit.bleManager.ble->startAdvertising();
28-
uBit.display.printAsync("ULTIBO", 200);
29+
uBit.display.printAsync("ULTIBO 98", 200);
2930
advertising = 1;
30-
}
31+
}
3132

3233
void updatePayload ()
33-
{
34+
{
3435
uBit.bleManager.ble->clearAdvertisingPayload();
3536
uBit.bleManager.ble->accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE);
36-
AdvData [4] = digit (eventCounter / 10);
37-
AdvData [5] = digit (eventCounter % 10);
38-
for (int i = 19; i >= 1; i--)
39-
{
40-
AdvData [i + 6] = AdvData [i + 6 - 1];
41-
}
42-
AdvData [6] = buttonsState + '0';
37+
AdvData [4] = eventCounter;
38+
for (int i = 20; i >= 1; i--)
39+
{
40+
AdvData [i + 5] = AdvData [i + 5 - 1];
41+
}
42+
AdvData [5] = (buttonsState << 6);
4343
uBit.bleManager.ble->accumulateAdvertisingPayload(GapAdvertisingData::MANUFACTURER_SPECIFIC_DATA, AdvData, sizeof(AdvData));
44-
}
44+
}
4545

46-
void stopAdvertising() {
46+
void stopAdvertising()
47+
{
4748
uBit.bleManager.stopAdvertising();
4849
uBit.display.scroll("OFF");
4950
advertising = 0;
50-
}
51+
}
5152

5253
char text[] = "?";
5354

5455
void onButton(MicroBitEvent e)
55-
{
56+
{
5657
uint8_t mask;
5758
uint8_t prev = buttonsState;
5859
if (e.source == MICROBIT_ID_BUTTON_A)
@@ -80,10 +81,17 @@ void onButton(MicroBitEvent e)
8081
buttonsState &= ~mask;
8182

8283
if (buttonsState != prev)
83-
{
84-
eventCounter = (eventCounter + 1) % 100;
85-
switch (buttonsState)
8684
{
85+
if (eventCounter == 255)
86+
{
87+
eventCounter = 128;
88+
}
89+
else
90+
{
91+
eventCounter = eventCounter + 1;
92+
}
93+
switch (buttonsState)
94+
{
8795
case 0: text [0] = ' ';
8896
break;
8997
case 1: text [0] = 'A';
@@ -93,10 +101,10 @@ void onButton(MicroBitEvent e)
93101
case 3: text [0] = '2';
94102
break;
95103
default: text [0] = '?';
96-
}
104+
}
97105
uBit.display.printAsync (text);
98106
updatePayload ();
99-
}
107+
}
100108

101109
// if (e.value == MICROBIT_BUTTON_EVT_CLICK)
102110
// uBit.serial.printf("CLICK");
@@ -111,13 +119,13 @@ void onButton(MicroBitEvent e)
111119
// uBit.serial.printf("DOUBLE_CLICK");
112120
//
113121
// uBit.serial.printf("\r\n");
114-
}
122+
}
115123

116124
int main()
117-
{
125+
{
118126
uBit.init();
119127
uBit.messageBus.listen(MICROBIT_ID_BUTTON_A, MICROBIT_EVT_ANY, onButton);
120128
uBit.messageBus.listen(MICROBIT_ID_BUTTON_B, MICROBIT_EVT_ANY, onButton);
121129
startAdvertising();
122130
release_fiber();
123-
}
131+
}

microbitdemo.lpr

+94-27
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,15 @@
5454

5555
type
5656
TArrayOfByte = Array of Byte;
57+
PMicroBitPeripheral = ^TMicroBitPeripheral;
58+
TMicroBitPeripheral = record
59+
AddressString:String;
60+
ButtonCounter:Integer;
61+
ButtonChordStarted:Boolean;
62+
end;
5763

5864
var
65+
MicroBitPeripherals:Array of TMicroBitPeripheral;
5966
ScanRxCount:Integer;
6067
BluetoothUartDeviceDescription:String;
6168
ScanCycleCounter:LongWord;
@@ -69,8 +76,6 @@
6976
UART0:PSerialDevice = Nil;
7077
KeyboardLoopHandle:TThreadHandle = INVALID_HANDLE_VALUE;
7178
ReadByteCounter:Integer;
72-
ButtonCounter:Integer;
73-
ButtonChordStarted:Boolean;
7479

7580
function ReadByte:Byte; forward;
7681

@@ -255,20 +260,6 @@ procedure HciCommand(OGF:byte; OCF:Word; Params:array of byte);
255260
HciCommand((OGF shl 10) or OCF,Params);
256261
end;
257262

258-
procedure SetLEScanResponseData(Data:array of byte);
259-
var
260-
Params:array of byte;
261-
Len:byte;
262-
i:integer;
263-
begin
264-
Len:=Min(Length(Data),31);
265-
SetLength(Params,Len + 1);
266-
Params[0]:=Len;
267-
for i:=0 to Len - 1 do
268-
Params[i + 1]:=Data[i];
269-
HciCommand(OGF_LE_CONTROL,$09,Params);
270-
end;
271-
272263
function EventReadFirstByte:Byte;
273264
var
274265
c:LongWord;
@@ -564,7 +555,7 @@ function KeyboardLoop(Parameter:Pointer):PtrInt;
564555
'Q' : SystemRestart(0);
565556
'R' :
566557
begin
567-
RestoreBootFile('bluetooth-dev-bluetoothtest','config.txt');
558+
RestoreBootFile('microbitdemo','config.txt');
568559
SystemRestart(0);
569560
end;
570561
end;
@@ -599,6 +590,29 @@ function AsWord(Hi,Lo:Integer):Word;
599590
Result:=(Hi shl 8) or Lo;
600591
end;
601592

593+
function FindOrMakeMicroBitPeripheral(NewAddressString:String):PMicroBitPeripheral;
594+
var
595+
I:Integer;
596+
begin
597+
Result:=Nil;
598+
for I:= 0 to High(MicroBitPeripherals) do
599+
if MicroBitPeripherals[I].AddressString = NewAddressString then
600+
Result:=@MicroBitPeripherals[I];
601+
if Result = nil then
602+
begin
603+
SetLength(MicroBitPeripherals,Length(MicroBitPeripherals) + 1);
604+
Result:=@MicroBitPeripherals[High(MicroBitPeripherals)];
605+
with Result^ do
606+
begin
607+
AddressString:=NewAddressString;
608+
ButtonCounter:=0;
609+
ButtonChordStarted:=False;
610+
end;
611+
Log('');
612+
Log(Format('detected new micro:bit peripheral %s',[NewAddressString]));
613+
end;
614+
end;
615+
602616
procedure ParseEvent;
603617
var
604618
I:Integer;
@@ -613,6 +627,10 @@ procedure ParseEvent;
613627
LeEventType:Byte;
614628
NewButtonCounter:Integer;
615629
ButtonMessage:String;
630+
CounterByte:Byte;
631+
MicroEventIndex:Integer;
632+
MicroEvent:Byte;
633+
MicroBitPeripheral:PMicroBitPeripheral;
616634
function GetByte:Byte;
617635
begin
618636
Result:=Event[GetByteIndex];
@@ -675,8 +693,9 @@ function GetByte:Byte;
675693
MfrHi:=GetByte;
676694
SignatureLo:=GetByte;
677695
SignatureHi:=GetByte;
678-
if (MainType = $ff) and (AsWord(MfrHi,MfrLo) = Word(ManufacturerTesting)) and (SignatureLo = $55) and (SignatureHi = $97) then
696+
if (MainType = $ff) and (AsWord(MfrHi,MfrLo) = Word(ManufacturerTesting)) and (AsWord(SignatureHi,Signaturelo) = $9755) then
679697
begin
698+
MicroBitPeripheral:=FindOrMakeMicroBitPeripheral(AddressString);
680699
GetByteIndex:=20;
681700
NewButtonCounter:=(GetByte - Ord('0'))*10;
682701
NewButtonCounter:=NewButtonCounter + (GetByte - Ord('0'));
@@ -685,28 +704,77 @@ function GetByte:Byte;
685704
begin
686705
S:=S + Char(GetByte);
687706
end;
688-
if NewButtonCounter <> ButtonCounter then
707+
if NewButtonCounter <> MicroBitPeripheral^.ButtonCounter then
689708
begin
690-
ButtonCounter:=NewButtonCounter;
691-
if not ButtonChordStarted then
709+
MicroBitPeripheral^.ButtonCounter:=NewButtonCounter;
710+
if not MicroBitPeripheral^.ButtonChordStarted then
692711
begin
693712
LoggingOutput('');
694-
ButtonChordStarted:=True;
713+
MicroBitPeripheral^.ButtonChordStarted:=True;
695714
end;
696715
case S[1] of
697716
'0':
698717
begin
699718
ButtonMessage:='Released ';
700-
ButtonChordStarted:=False;
719+
MicroBitPeripheral^.ButtonChordStarted:=False;
701720
end;
702721
'1': ButtonMessage:='A down ';
703722
'2': ButtonMessage:='B down ';
704723
'3': ButtonMessage:='A and B down';
705724
else ButtonMessage:='????????????';
706725
end;
707-
LoggingOutput(Format('micro:bit addr %s %s - %02.2d events, history: %s',[AddressString,ButtonMessage,ButtonCounter,S]));
726+
LoggingOutput(Format('micro:bit addr %s %s - %02.2d events, history: %s',[AddressString,ButtonMessage,MicroBitPeripheral^.ButtonCounter,S]));
708727
end;
709-
end;
728+
end
729+
else if (MainType = $ff) and (AsWord(MfrHi,MfrLo) = Word(ManufacturerTesting)) and (AsWord(SignatureHi,SignatureLo) = $9855) then
730+
begin
731+
MicroBitPeripheral:=FindOrMakeMicroBitPeripheral(AddressString);
732+
GetByteIndex:=20;
733+
CounterByte:=GetByte;
734+
NewbuttonCounter:=CounterByte and $7f;
735+
S:='';
736+
while GetByteIndex <= High(Event) do
737+
S:=S + Char(Ord('0') + (GetByte shr 6));
738+
while (MicroBitPeripheral^.ButtonCounter mod 128) <> NewButtonCounter do
739+
begin
740+
Inc(MicroBitPeripheral^.ButtonCounter);
741+
MicroEventIndex:=NewButtonCounter - (MicroBitPeripheral^.ButtonCounter mod 128);
742+
// Log(Format('counter %d new %d index %d %s',[MicroBitPeripheral^.ButtonCounter,NewButtonCounter,MicroEventIndex,S]));
743+
if MicroEventIndex < 0 then
744+
Inc(MicroEventIndex,128);
745+
if MicroEventIndex >= 21 then
746+
begin
747+
Log(Format('unable to reconstruct event %d index %d from %d %s',[MicroBitPeripheral^.ButtonCounter,MicroEventIndex,NewButtonCounter,S]));
748+
if (CounterByte and $80) = 0 then
749+
begin
750+
MicroBitPeripheral^.ButtonCounter:=NewButtonCounter;
751+
Log('the micro:bit seems to have restarted');
752+
end;
753+
end
754+
else
755+
begin
756+
GetByteIndex:=21 + MicroEventIndex;
757+
if not MicroBitPeripheral^.ButtonChordStarted then
758+
begin
759+
LoggingOutput('');
760+
MicroBitPeripheral^.ButtonChordStarted:=True;
761+
end;
762+
MicroEvent:=GetByte shr 6;
763+
case MicroEvent of
764+
0:
765+
begin
766+
ButtonMessage:='Released ';
767+
MicroBitPeripheral^.ButtonChordStarted:=False;
768+
end;
769+
1: ButtonMessage:='A down ';
770+
2: ButtonMessage:='B down ';
771+
3: ButtonMessage:='A and B down';
772+
else ButtonMessage:='????????????';
773+
end;
774+
LoggingOutput(Format('micro:bit addr %s event number %03.3d %s - history: %s',[AddressString,MicroBitPeripheral^.ButtonCounter,ButtonMessage,S]));
775+
end;
776+
end;
777+
end;
710778
end;
711779

712780
begin
@@ -734,8 +802,7 @@ function GetByte:Byte;
734802
Log('Init complete');
735803
ScanCycleCounter:=0;
736804
ReadByteCounter:=0;
737-
ButtonCounter:=0;
738-
ButtonChordStarted:=False;
805+
SetLength(MicroBitPeripherals,0);
739806
while True do
740807
begin
741808
ReadBackLog:=0;

release-message.md

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Ultibo prototype-microbit-as-ultibo-peripheral repository
1+
# prototype-microbit-as-ultibo-peripheral
22

33
# Requires:
44
* a micro:bit computer and a usb cable
@@ -20,6 +20,7 @@
2020
* attach the microbit to the computer with the usb cable
2121
* the microbit should appear as a usb folder
2222
* copy microbit-as-ultibo-peripheral.hex from the sd card to the microbit usb folder
23+
* safely eject the sd card
2324
* insert the sd card into the pi
2425
* connect the pi to the tv using the hdmi cable
2526
* connect the pi to the optional usb keyboard

0 commit comments

Comments
 (0)