Electronic Shelf Label Service (ESLS)

The Electronic Shelf Label Service allows you to control and update electronic shelf labels (ESL) using Bluetooth® wireless technology. The purpose of the ESL Service is to enable communication and control between a central access point (AP) and tag devices. This service implements a complete state machine and control point command handler for ESL. The ESL Service is used in the Bluetooth: Peripheral ESL sample.

Service UUID

The 16-bit vendor-specific service UUID is 0x1857.

Characteristics

This service has the following nine characteristics.

ESL Address Characteristic (0x2BF6)

Write

Write data to the ESL Address Characteristic to configure a unique address for an ESL device.

AP Sync Key Material Characteristic (0x2BF7)

Write

The AP Sync Key Material is configured when an AP, acting as a client, writes its AP Sync Key Material value to the AP Sync Key Material characteristic.

ESL Response Key Material Characteristic (0x2BF8)

Write

The ESL Response Key Material is configured when an AP, acting as a client, writes a value to the ESL Response Key Material characteristic.

ESL Current Absolute Time Characteristic (0x2BF9)

Write

When a value is written to the ESL Current Absolute Time characteristic, the server sets its current system time to the value.

ESL Display Information Characteristic (0x2BFA)

Read

The ESL Display Information characteristic returns an array of one or more Display Data Structures when read by a client.

ESL Image Information Characteristic (0x2BFB)

Read

When read, the ESL Image Information characteristic returns the Max_Image_Index value equal to the highest Image_Index value supported by the ESL.

ESL Sensor Information Characteristic (0x2BFC)

Read

The ESL Sensor Information characteristic returns an array of one or more Sensor Information Structures when read by a client.

ESL LED Information Characteristic (0x2BFD)

Read

The ESL LED Information characteristic returns an array of one or more octets when read by a client.

ESL Control Point Characteristic (0x2BFE)

Write Without Response, Write, Notify

The ESL Control Point characteristic allows a client to write commands to an ESL while connected.

Note

The command includes an opcode and parameters. The ESL Control Point command applies to both GATT ECP characteristic and PAwR.

Configuration

An ESL is composed of three types of independent, optional elements (a display, an LED, and a sensor). You first need to set the values of the ESL tag elements as described in the following sections.

LED configuration

Use the following Kconfig options to set the LED configuration:

  • CONFIG_BT_ESL_LED_MAX sets the maximum number of LEDs available on the tag device.

    The default value is 0, which means there is no LED on the tag device. If there is an LED, the application must implement the functions led_init() and led_control() to control the LED. The ESL Service generates LED information in the GATT characteristic and a LED work item in the work queue.

  • CONFIG_BT_ESL_LED_INDICATION is an option for debugging.

    If this option is enabled, the LED is lit or flashing when the tag device is in the corresponding state.

Display configuration

Use the following Kconfig options to set the display configuration:

  • CONFIG_BT_ESL_DISPLAY_MAX sets the maximum number of displays available on the tag device.

    The default value is 0, which means there is no display on the tag device. If there is display, the application must implement the functions display_init() and display_control() to control the display. The ESL Service generates display information in the GATT characteristic and a display work item in the work queue.

  • CONFIG_ESL_DISPLAY_WIDTH and CONFIG_ESL_DISPLAY_HEIGHT set the display resolution of the tag device.

    These values can be acquired by the devicetree if the tag device has a display with a Zephyr driver. However, some tag devices use their own driver. You need to set these values accordingly.

  • CONFIG_ESL_DISPLAY_TYPE sets the display type that is defined by Bluetooth SIG assigned number.

  • CONFIG_ESL_IMAGE_FILE_SIZE sets the file size reserved for Object Transfer Service (OTS) storage backend.

    In general, the size is the width x height x bit depth plus image header.

  • CONFIG_ESL_IMAGE_BUFFER_SIZE sets the size of memory reserved for display framebuffer.

    In general, the size is the width x height x bit depth plus image header. For some display IC and storage backends, this memory size can be smaller than the image file.

  • CONFIG_BT_ESL_IMAGE_MAX sets the number of images that can be stored in an tag device.

    This value is a trade-off between power consumption and need for non-volatile memory. The image is stored in the non-volatile memory of tag device. The more images can be stored, the less often the tag device needs to be in updating state to receive new images. The less images can be stored, the less non-volatile memory is required by the tag device.

  • CONFIG_BT_ESL_STORAGE_BACKEND sets the storage backend for the image from the AP.

    The possible storage backend values are:

    • CONFIG_ESL_OTS_NVS - a lightweight key-value store optimized for small data reads and writes, not supporting the seek feature.

    • CONFIG_ESL_OTS_LFS - a full-featured filesystem optimized for larger data reads and writes, supports the seek feature.

    The choice between the two depends on the specific requirements of your application and the hardware (MCU, external flash or not) you are using.

Sensor configuration

Use the following Kconfig option to set the sensor configuration:

  • CONFIG_BT_ESL_SENSOR_MAX sets the maximum number of sensors available on the tag device.

    The default value is 0, which means there is no sensor on the tag device. If the tag device has a sensor, the application must implement the functions sensor_init() and sensor_control() to read the sensor.

Debugging configuration

You can also use the following Kconfig options for debugging purposes:

  • CONFIG_ESL_SHELL enables the shell command for controlling the tag device.

  • CONFIG_BT_ESL_DEMO_SECURITY enables removal of bonding data after the tag device is disconnected.

  • CONFIG_BT_ESL_FORGET_PROVISION_DATA enables removal of provisioning data after the tag device is disconnected.

  • CONFIG_BT_ESL_UNSYNCHRONIZED_TIMEOUT enables overriding the mandatory 60 minutes unsynchronized timeout value defined by Bluetooth SIG.

  • CONFIG_BT_ESL_UNASSOCIATED_TIMEOUT enables overriding the mandatory 60 minutes unassociated timeout value defined by Bluetooth SIG.

Usage

To use ESL Service in your application, complete the following steps:

  1. Configure all elements of your ESL tag devices.

  2. Declare the bt_esl_init_param structure.

  3. Fill in the element information to the members of the structure.

  4. Implement all required callback functions.

  5. Implement the ots_storage_init() function.

  6. Call the bt_esl_init() function.

Application integration

Callbacks

The ESL Service requires a number of callback functions to control the hardware. Your application must implement callback functions depending on the hardware used on the tag device. To implement the tag device functionality, several callback functions are needed. These callbacks are used to control the display, LEDs, and sensors, as well as to buffer and write image data to storage. This section explains why these callbacks are needed and how to implement them.

LED Callbacks

You need to implement the following callbacks for the LEDs:

  • The led_init() callback is used to initialize the LEDs on the tag device.

    To implement this callback, you need to write a function that calls it.

  • The led_control() callback is used to change the LED state, for example on/off, brightness, or color (if an SRGB is LED used).

    This function is called when the ESL tag device decides to change the LED flashing pattern. The function takes the following three arguments:

    • LED index

    • Color and brightness to be controlled

    • A boolean value indicating whether to turn on or off the LED

    To implement this callback, you need to write a function that takes these arguments and performs the necessary operations to change the LED state.

Display Callbacks

You need to implement the following callbacks if the tag device has a display:

  • The display_init() callback is used to initialize the display device unless the display driver does that (for example initializes the memory region for framebuffer or sets the font type).

    To implement this callback, you need to write a function that initializes the display device.

  • The display_control() callback is used to change the image displayed on the tag device.

    This function is called when the tag device decides to change the image. The function takes the following three arguments:

    • The index of the display device

    • The index of the image

    • A boolean value indicating whether to turn on or off the display

    To implement this callback, you need to write a function that takes these arguments and performs the necessary operations to change the image on the display device.

  • The display_unassociated() callback is used to show information on the display device to help the user inspect the tag device to be associated.

    This function is called when the tag device is booting up and unassociated. To implement this callback, you need to write a function that takes the index of the display device and displays the necessary information on the device.

  • The display_associated() callback is used to show information on the display device to indicate that the tag device has been associated.

    This function is called when the tag device is booting up and associated but not synced or commanded to display an image. To implement this callback, you need to write a function that takes the index of the display device and displays the necessary information on the device.

If you want to use a font library to print text on the display, you need to implement the following callbacks:

  • The display_clear_font() callback is used to clear the framebuffer allocated by the font library for a specified display.

    This function is a callback for the font library and clears the framebuffer allocated by the font library for the specified display. The function disables all images on the display by clearing the framebuffer. To implement this callback, you need to write a function that takes the index of the display device and clears the framebuffer.

  • The display_print_font() callback is used to print text on the specified display using the font library.

    This function is a callback for the font library and prints text on the specified display using the font library. The text is printed at the specified position with the specified font. To implement this callback, you need to write a function that takes the index of the display device, the text to print, and the position to print the text. This callback should only change framebuffer and not update the display.

  • The display_update_font() callback is used to finalize the Character Framebuffer (CFB) or font library and check if the Electronic Paper Display (EPD) needs to be re-initialized.

    This function updates the display by flushing any pending updates to the display buffer and checks if the EPD needs to be re-initialized. To implement this callback, you need to write a function that takes the index of the display device and write font framebuffer to display.

Sensor Callbacks

You need to implement the following callbacks if the tag device has a sensor:

  • The sensor_init() callback is used to initialize the sensor device.

    To implement this callback, you need to write a function that initializes the sensor device.

  • The sensor_control() callback is used to read sensor data when requested by the tag device.

    This function takes the following two output arguments:

    • The length of the sensor data

    • A pointer to the sensor data reading

    To implement this callback, you need to write a function that takes the index of the sensor and stores the sensor data to the sensor_data structure. If the sensor reading is successful, value 0 is returned. If the sensor reading is not fast enough or fails, value -EBUSY is returned. The ESL Service will generate a response based on the return value of this function.

Image storage callbacks

The tag device with a display requires several callbacks to be implemented. One of the mandatory features of the tag devices is to receive and store image data from the AP through OTS (Object Transfer Service), and to read image data to the framebuffer from storage when the image on the display needs to be changed. You need to implement the following callbacks if the tag device has a display. The implementation varies depending on the storage backend (NVS or LittleFS).

  • The buffer_img() callback is used to buffer image data from AP when OTS (Object Transfer Service) write operation callback called.

    Image data from OTS may come in fragments, and some filesystems support seek while others do not. This callback should either buffer all fragments into img_obj_buf and write them once for a storage backend not supporting the seek feature, or write chunck by chunk to a storage backend supporting the seek feature.

  • The write_img_to_storage() callback is used to write image data to the storage backend when a chunk of image or all of the fragments from OTS are received.

    To implement this callback, you need to write a function that takes the image index, length, and offset and writes the image data to the storage backend.

  • The read_img_from_storage() callback is used to read image data from the storage backend to framebuffer when the tag device needs to change the image on the display.

    To implement this callback, you need to write a function that takes the image index, data pointer, length, and offset and reads the image data from the storage backend.

    Note

    For a storage backend supporting the seek feature and a display driver IC supporting partial update, the read_img_from_storage() callback can only read the changed part of the image from the storage backend to the framebuffer. The display driver IC will only update the changed part of the image on the display.

    For a storage backend that does not support the seek feature, the read_img_from_storage() callback can only read the whole image from the storage backend to the framebuffer. The display driver IC will update the whole image on the display.

  • The read_img_size_from_storage() callback is used to read the image size from the storage backend when the tag device needs to change the image on the display.

    To implement this callback, you need to write a function that takes the image index and returns the image size.

  • The delete_imgs() callback is used to remove all images from the storage backend when received factory reset op code.

    To implement this callback, you need to write a function that removes all images from the storage backend.

API documentation

Header file: ../services/esl.h
Source files: ../services/esl.c