docs: add next-gen profile (#71)
This commit is contained in:
committed by
GitHub
parent
4e556ab11f
commit
68148af209
173
BadgeBLE.md
173
BadgeBLE.md
@@ -2,14 +2,33 @@
|
|||||||
|
|
||||||
### Connection Information
|
### Connection Information
|
||||||
|
|
||||||
The pixel data is transferred to the badge via BLE. The badge advertizes the name "LSLED" and uses a vendor specific service/characteristic:
|
#### OEM Firmware
|
||||||
|
|
||||||
- Service-UUID: 0000fee0-0000-1000-8000-00805f9b34fb
|
The pixel data is transferred to the badge via BLE. The OEM firmware advertises
|
||||||
- Characteristic: 0000fee1-0000-1000-8000-00805f9b34fb
|
the name 'LSLED' and a 16-bit vendor-specific service/characteristic pair:
|
||||||
|
|
||||||
The characteristic accepts 16 byte long data packets.
|
- Service-UUID: 0xFEE0 (128-bit equivalent:
|
||||||
|
0000fee0-0000-1000-8000-00805f9b34fb)
|
||||||
|
- Characteristic: 0xFEE1 (128-bit equivalent:
|
||||||
|
0000fee1-0000-1000-8000-00805f9b34fb)
|
||||||
|
|
||||||
### Data Format
|
The characteristic of the OEM firmware has Read/Write/Notify properties. It
|
||||||
|
accepts 16 byte long data packets on writing. Its Read/Notify behavior is
|
||||||
|
currently unknown and needs to be investigated.
|
||||||
|
|
||||||
|
#### Open Firmware
|
||||||
|
|
||||||
|
This open firmware advertises the service/characteristic pair 0xFEE0/0xFEE1 in
|
||||||
|
the same way as the OEM firmware and uses the name "LED Badge Magic" which can
|
||||||
|
be renamed via the [next-gen profile](#next-gen-profile). The characteristic
|
||||||
|
0xFEE1, marked as the legacy profile, is write-only. Read/Notify functionality
|
||||||
|
will be supported once its behavior is fully understood.
|
||||||
|
|
||||||
|
An additional custom profile has been implemented, enabling more remote features
|
||||||
|
and configuration over the BLE connection, see the [next-gen
|
||||||
|
profile](#next-gen-profile) for details.
|
||||||
|
|
||||||
|
### Data Format (Legacy)
|
||||||
|
|
||||||
The badge supports up to 8 bitmaps which can have various features enabled.
|
The badge supports up to 8 bitmaps which can have various features enabled.
|
||||||
|
|
||||||
@@ -50,3 +69,147 @@ The "mode" bytes are a combination of two 4 bit values. The high nibble describe
|
|||||||
| 0x07 | "picture" |
|
| 0x07 | "picture" |
|
||||||
| 0x08 | "laser" |
|
| 0x08 | "laser" |
|
||||||
|
|
||||||
|
### Next-Gen profile
|
||||||
|
|
||||||
|
16-bit Service/characteristic:
|
||||||
|
|
||||||
|
- Service-UUID: 0xF055 (128-bit equivalent:
|
||||||
|
0000f055-0000-1000-8000-00805f9b34fb)
|
||||||
|
- Characteristic: 0xF056 (128-bit equivalent:
|
||||||
|
0000f056-0000-1000-8000-00805f9b34fb)
|
||||||
|
- Write property: to receive controls and configs
|
||||||
|
- Notify property: to return error codes
|
||||||
|
- Read property: to be implemented
|
||||||
|
|
||||||
|
#### Protocol
|
||||||
|
|
||||||
|
The next-gen characteristic accepts messages of varying lengths (0 to 512
|
||||||
|
bytes). The first byte represents the function/command code, while the remaining
|
||||||
|
bytes contain parameters for the corresponding function/command.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
Supported functions/commands:
|
||||||
|
|
||||||
|
- power_setting
|
||||||
|
- streaming_setting
|
||||||
|
- stream_bitmap
|
||||||
|
- ble_setting
|
||||||
|
- flash_splash_screen
|
||||||
|
- save_cfg
|
||||||
|
- load_fallback_cfg
|
||||||
|
|
||||||
|
The client app should enable notifications for the characteristic to receive the
|
||||||
|
returned error code (e.g., by using setCharacteristicNotification() on Android).
|
||||||
|
|
||||||
|
##### power_setting
|
||||||
|
|
||||||
|
Function/Command code: `0x01`.
|
||||||
|
|
||||||
|
Parameters:
|
||||||
|
|
||||||
|
- Power off: `0x00`.
|
||||||
|
- Enable resetting after uploading is done: `[0x01, 0x00]`. Note: call
|
||||||
|
the [save_cfg](#save_cfg) command to save this config.
|
||||||
|
- Disable resetting after uploading is done: `[0x01, 0x01]`. Note: call
|
||||||
|
the [save_cfg](#save_cfg) command to save this config.
|
||||||
|
- Power off: `0x02`.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
|
||||||
|
- Parameters out of range: `0xff`.
|
||||||
|
- Success: `0x00`.
|
||||||
|
|
||||||
|
##### streaming_setting
|
||||||
|
|
||||||
|
Function/Command code: `0x02`.
|
||||||
|
|
||||||
|
Parameters:
|
||||||
|
|
||||||
|
- Enter streaming mode `0x00`. This command stops all animations, clears the
|
||||||
|
screen, and switches the device to streaming mode.
|
||||||
|
- Leave streaming mode `0x01`. This command resumes all normal operations.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
|
||||||
|
- Parameters out of range: `0xff`.
|
||||||
|
- Success: `0x00`.
|
||||||
|
|
||||||
|
##### stream_bitmap
|
||||||
|
|
||||||
|
Function/Command code: `0x03`.
|
||||||
|
|
||||||
|
Parameters:
|
||||||
|
|
||||||
|
- Array of bitmap in word (16-bit). Each word represents a column. The
|
||||||
|
least-significant bit of each word represents the top pixel of each column.
|
||||||
|
The length of the word array must be less than the number of columns on the
|
||||||
|
screen; otherwise, any overflow pixels will be ignored.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
|
||||||
|
- Parameters out of range or streaming not enabled: `0xff`.
|
||||||
|
- Success: `0x00`.
|
||||||
|
|
||||||
|
##### ble_setting
|
||||||
|
|
||||||
|
Function/Command code: `0x04`.
|
||||||
|
|
||||||
|
Parameters:
|
||||||
|
|
||||||
|
- Disable always-on BLE: `[0x00, 0x00]`. Note: Call the save_cfg command to save
|
||||||
|
this configuration.
|
||||||
|
- Enable always-on BLE: `[0x00, 0x01]`. Note: Call the save_cfg command to save
|
||||||
|
this configuration.
|
||||||
|
- Change BLE device name: `[0x01, "This is name"]`. The name must be less than
|
||||||
|
or equal to 20 characters. Note: Call the save_cfg command to save this
|
||||||
|
configuration.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
|
||||||
|
- Parameters out of range: `0xff`.
|
||||||
|
- Success: `0x00`.
|
||||||
|
|
||||||
|
##### flash_splash_screen
|
||||||
|
|
||||||
|
Function/Command code: `0x05`.
|
||||||
|
|
||||||
|
Parameters:
|
||||||
|
|
||||||
|
- The first byte describes the width of the image.
|
||||||
|
- The second byte describes the height of the image.
|
||||||
|
- The third byte describes the frame height that will be displayed on the
|
||||||
|
screen.
|
||||||
|
- The rest are pixel content in `xbm` format.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
|
||||||
|
- Parameters out of range: `0xff`.
|
||||||
|
- The width is larger than the maximum allowed (currently 48 pixels): `0xff`.
|
||||||
|
- The height is larger than the maximum allowed (currently 44 pixels): `0xfe`.
|
||||||
|
- Message length is not matched (currently 44 pixels): `0xfd`.
|
||||||
|
- Missing pixel contents: `0xfc`.
|
||||||
|
- Success: `0x00`.
|
||||||
|
|
||||||
|
##### save_cfg
|
||||||
|
|
||||||
|
Save configs to flash.
|
||||||
|
|
||||||
|
Command code: `0x06`.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
|
||||||
|
- Parameters out of range: `0xff`.
|
||||||
|
- Flash writing error: `0x01`.
|
||||||
|
- Success: `0x00`.
|
||||||
|
|
||||||
|
##### load_fallback_cfg
|
||||||
|
|
||||||
|
Load firmware default configuration. Note: call the [save_cfg](#save_cfg)
|
||||||
|
command to save this config.
|
||||||
|
|
||||||
|
Function/Command code: `0x07`.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
|
||||||
|
- Success: `0x00`.
|
||||||
|
|||||||
223
assets/ng-protocol.svg
Normal file
223
assets/ng-protocol.svg
Normal file
@@ -0,0 +1,223 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
width="93.96756mm"
|
||||||
|
height="37.041668mm"
|
||||||
|
viewBox="0 0 93.967559 37.041667"
|
||||||
|
version="1.1"
|
||||||
|
id="svg1"
|
||||||
|
inkscape:version="1.4 (e7c3feb100, 2024-10-09)"
|
||||||
|
sodipodi:docname="ng-protocol.svg"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg">
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="namedview1"
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#000000"
|
||||||
|
borderopacity="0.25"
|
||||||
|
inkscape:showpageshadow="2"
|
||||||
|
inkscape:pageopacity="0.0"
|
||||||
|
inkscape:pagecheckerboard="0"
|
||||||
|
inkscape:deskcolor="#d1d1d1"
|
||||||
|
inkscape:document-units="mm"
|
||||||
|
inkscape:zoom="1.9276399"
|
||||||
|
inkscape:cx="197.91041"
|
||||||
|
inkscape:cy="18.675688"
|
||||||
|
inkscape:window-width="1920"
|
||||||
|
inkscape:window-height="1060"
|
||||||
|
inkscape:window-x="0"
|
||||||
|
inkscape:window-y="0"
|
||||||
|
inkscape:window-maximized="1"
|
||||||
|
inkscape:current-layer="layer1" />
|
||||||
|
<defs
|
||||||
|
id="defs1">
|
||||||
|
<marker
|
||||||
|
style="overflow:visible"
|
||||||
|
id="marker12"
|
||||||
|
refX="0"
|
||||||
|
refY="0"
|
||||||
|
orient="auto-start-reverse"
|
||||||
|
inkscape:stockid="Wide arrow"
|
||||||
|
markerWidth="1"
|
||||||
|
markerHeight="1"
|
||||||
|
viewBox="0 0 1 1"
|
||||||
|
inkscape:isstock="true"
|
||||||
|
inkscape:collect="always"
|
||||||
|
preserveAspectRatio="xMidYMid">
|
||||||
|
<path
|
||||||
|
style="fill:none;stroke:context-stroke;stroke-width:1;stroke-linecap:butt"
|
||||||
|
d="M 3,-3 0,0 3,3"
|
||||||
|
transform="rotate(180,0.125,0)"
|
||||||
|
sodipodi:nodetypes="ccc"
|
||||||
|
id="path12" />
|
||||||
|
</marker>
|
||||||
|
<marker
|
||||||
|
style="overflow:visible"
|
||||||
|
id="ArrowWide"
|
||||||
|
refX="0"
|
||||||
|
refY="0"
|
||||||
|
orient="auto-start-reverse"
|
||||||
|
inkscape:stockid="Wide arrow"
|
||||||
|
markerWidth="1"
|
||||||
|
markerHeight="1"
|
||||||
|
viewBox="0 0 1 1"
|
||||||
|
inkscape:isstock="true"
|
||||||
|
inkscape:collect="always"
|
||||||
|
preserveAspectRatio="xMidYMid">
|
||||||
|
<path
|
||||||
|
style="fill:none;stroke:context-stroke;stroke-width:1;stroke-linecap:butt"
|
||||||
|
d="M 3,-3 0,0 3,3"
|
||||||
|
transform="rotate(180,0.125,0)"
|
||||||
|
sodipodi:nodetypes="ccc"
|
||||||
|
id="path1" />
|
||||||
|
</marker>
|
||||||
|
</defs>
|
||||||
|
<g
|
||||||
|
inkscape:label="Layer 1"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer1"
|
||||||
|
transform="translate(-4.0441577,-4.1136454)">
|
||||||
|
<rect
|
||||||
|
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.264582;stroke-opacity:1"
|
||||||
|
id="rect1"
|
||||||
|
width="18.955954"
|
||||||
|
height="18.955954"
|
||||||
|
x="6.7991281"
|
||||||
|
y="4.2459364" />
|
||||||
|
<text
|
||||||
|
xml:space="preserve"
|
||||||
|
style="font-size:4.80828px;line-height:1;font-family:'Noto Sans';-inkscape-font-specification:'Noto Sans';text-align:start;text-decoration-color:#000000;writing-mode:lr-tb;direction:ltr;text-anchor:start;fill:#0000ff;fill-opacity:1;stroke:none;stroke-width:0.1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:5;stroke-opacity:1;paint-order:stroke markers fill"
|
||||||
|
x="9.8561001"
|
||||||
|
y="13.041375"
|
||||||
|
id="text1"><tspan
|
||||||
|
sodipodi:role="line"
|
||||||
|
id="tspan1"
|
||||||
|
style="font-size:4.80828px;fill:#0000ff;fill-opacity:1;stroke:none;stroke-width:0.1"
|
||||||
|
x="9.8561001"
|
||||||
|
y="13.041375" /></text>
|
||||||
|
<text
|
||||||
|
xml:space="preserve"
|
||||||
|
style="font-size:4.80828px;line-height:1;font-family:'Noto Sans';-inkscape-font-specification:'Noto Sans';text-align:start;text-decoration-color:#000000;writing-mode:lr-tb;direction:ltr;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:5;stroke-opacity:1;paint-order:stroke markers fill"
|
||||||
|
x="8.3145914"
|
||||||
|
y="15.152661"
|
||||||
|
id="text2"><tspan
|
||||||
|
sodipodi:role="line"
|
||||||
|
id="tspan2"
|
||||||
|
style="font-size:4.80828px;fill:#000000;fill-opacity:1;stroke-width:0.1"
|
||||||
|
x="8.3145914"
|
||||||
|
y="15.152661">byte 0</tspan></text>
|
||||||
|
<rect
|
||||||
|
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.264582;stroke-opacity:1"
|
||||||
|
id="rect2"
|
||||||
|
width="18.955954"
|
||||||
|
height="18.955954"
|
||||||
|
x="26.375713"
|
||||||
|
y="4.2459364" />
|
||||||
|
<rect
|
||||||
|
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.264582;stroke-opacity:1"
|
||||||
|
id="rect3"
|
||||||
|
width="18.955954"
|
||||||
|
height="18.955954"
|
||||||
|
x="59.346848"
|
||||||
|
y="4.2459364" />
|
||||||
|
<rect
|
||||||
|
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.264582;stroke-opacity:1"
|
||||||
|
id="rect4"
|
||||||
|
width="18.955954"
|
||||||
|
height="18.955954"
|
||||||
|
x="78.92347"
|
||||||
|
y="4.2459364" />
|
||||||
|
<text
|
||||||
|
xml:space="preserve"
|
||||||
|
style="font-size:4.80828px;line-height:1;font-family:'Noto Sans';-inkscape-font-specification:'Noto Sans';text-align:start;text-decoration-color:#000000;writing-mode:lr-tb;direction:ltr;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:5;stroke-opacity:1;paint-order:stroke markers fill"
|
||||||
|
x="50.130188"
|
||||||
|
y="14.017906"
|
||||||
|
id="text4"><tspan
|
||||||
|
sodipodi:role="line"
|
||||||
|
id="tspan4"
|
||||||
|
style="font-size:4.80828px;stroke-width:0.1"
|
||||||
|
x="50.130188"
|
||||||
|
y="14.017906">...</tspan></text>
|
||||||
|
<text
|
||||||
|
xml:space="preserve"
|
||||||
|
style="font-size:4.80828px;line-height:1;font-family:'Noto Sans';-inkscape-font-specification:'Noto Sans';text-align:start;text-decoration-color:#000000;writing-mode:lr-tb;direction:ltr;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:5;stroke-opacity:1;paint-order:stroke markers fill"
|
||||||
|
x="27.891172"
|
||||||
|
y="15.152661"
|
||||||
|
id="text5"><tspan
|
||||||
|
sodipodi:role="line"
|
||||||
|
id="tspan5"
|
||||||
|
style="font-size:4.80828px;fill:#000000;fill-opacity:1;stroke-width:0.1"
|
||||||
|
x="27.891172"
|
||||||
|
y="15.152661">byte 1</tspan></text>
|
||||||
|
<text
|
||||||
|
xml:space="preserve"
|
||||||
|
style="font-size:4.80828px;line-height:1;font-family:'Noto Sans';-inkscape-font-specification:'Noto Sans';text-align:start;text-decoration-color:#000000;writing-mode:lr-tb;direction:ltr;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:5;stroke-opacity:1;paint-order:stroke markers fill"
|
||||||
|
x="69.297417"
|
||||||
|
y="13.091969"
|
||||||
|
id="text6"><tspan
|
||||||
|
sodipodi:role="line"
|
||||||
|
id="tspan6"
|
||||||
|
style="font-size:4.80828px;text-align:center;text-anchor:middle;fill:#000000;fill-opacity:1;stroke-width:0.1"
|
||||||
|
x="69.297417"
|
||||||
|
y="13.091969">byte </tspan><tspan
|
||||||
|
sodipodi:role="line"
|
||||||
|
style="font-size:4.80828px;text-align:center;text-anchor:middle;fill:#000000;fill-opacity:1;stroke-width:0.1"
|
||||||
|
x="69.297417"
|
||||||
|
y="17.900249"
|
||||||
|
id="tspan7">n-2</tspan></text>
|
||||||
|
<text
|
||||||
|
xml:space="preserve"
|
||||||
|
style="font-size:4.80828px;line-height:1;font-family:'Noto Sans';-inkscape-font-specification:'Noto Sans';text-align:start;text-decoration-color:#000000;writing-mode:lr-tb;direction:ltr;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:5;stroke-opacity:1;paint-order:stroke markers fill"
|
||||||
|
x="89.904373"
|
||||||
|
y="13.091969"
|
||||||
|
id="text9"><tspan
|
||||||
|
sodipodi:role="line"
|
||||||
|
id="tspan8"
|
||||||
|
style="font-size:4.80828px;text-align:center;text-anchor:middle;fill:#000000;fill-opacity:1;stroke-width:0.1"
|
||||||
|
x="89.904373"
|
||||||
|
y="13.091969">byte </tspan><tspan
|
||||||
|
sodipodi:role="line"
|
||||||
|
style="font-size:4.80828px;text-align:center;text-anchor:middle;fill:#000000;fill-opacity:1;stroke-width:0.1"
|
||||||
|
x="89.904373"
|
||||||
|
y="17.900249"
|
||||||
|
id="tspan9">n-1</tspan></text>
|
||||||
|
<text
|
||||||
|
xml:space="preserve"
|
||||||
|
style="font-size:4.80828px;line-height:1;font-family:'Noto Sans';-inkscape-font-specification:'Noto Sans';text-align:center;text-decoration-color:#000000;writing-mode:lr-tb;direction:ltr;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:5;stroke-opacity:1;paint-order:stroke markers fill"
|
||||||
|
x="16.348543"
|
||||||
|
y="36.29895"
|
||||||
|
id="text10"><tspan
|
||||||
|
sodipodi:role="line"
|
||||||
|
style="font-size:4.80828px;stroke-width:0.1"
|
||||||
|
x="16.348543"
|
||||||
|
y="36.29895"
|
||||||
|
id="tspan13">functions/</tspan><tspan
|
||||||
|
sodipodi:role="line"
|
||||||
|
style="font-size:4.80828px;stroke-width:0.1"
|
||||||
|
x="16.348543"
|
||||||
|
y="41.107231"
|
||||||
|
id="tspan14">commands</tspan></text>
|
||||||
|
<text
|
||||||
|
xml:space="preserve"
|
||||||
|
style="font-size:4.80828px;line-height:1;font-family:'Noto Sans';-inkscape-font-specification:'Noto Sans';text-align:center;text-decoration-color:#000000;writing-mode:lr-tb;direction:ltr;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:5;stroke-opacity:1;paint-order:stroke markers fill"
|
||||||
|
x="62.139526"
|
||||||
|
y="36.29895"
|
||||||
|
id="text11"><tspan
|
||||||
|
sodipodi:role="line"
|
||||||
|
id="tspan11"
|
||||||
|
style="font-size:4.80828px;stroke-width:0.1"
|
||||||
|
x="62.139526"
|
||||||
|
y="36.29895">parameters</tspan></text>
|
||||||
|
<path
|
||||||
|
style="fill:none;stroke:#000000;stroke-width:0.264999;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1;marker-start:url(#ArrowWide);marker-end:url(#marker12)"
|
||||||
|
d="M 6.5415415,28.501193 H 26.012669"
|
||||||
|
id="path11" />
|
||||||
|
<path
|
||||||
|
style="fill:none;stroke:#000000;stroke-width:0.264999;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1;marker-start:url(#ArrowWide);marker-end:url(#marker12)"
|
||||||
|
d="M 27.020996,28.501193 H 97.632395"
|
||||||
|
id="path13" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 9.8 KiB |
Reference in New Issue
Block a user