BLE-writeable Display Puck with an e-paper display. Built on the Puck IOT platform.
Dependencies: Puck lz mbed seeedstudio-epaper
The Display puck is a puck with an e-paper display that can show arbitrary black and white images received over Bluetooth LE.
A tutorial for the Display Puck is available on GitHub.
Tutorials and in-depth documentation for the Puck platform is available at the project's GitHub page
Diff: main.cpp
- Revision:
- 3:4ff226c4fe2a
- Parent:
- 1:42882ba4c901
- Child:
- 5:5491fb58107e
--- a/main.cpp Fri Jul 18 09:22:36 2014 +0000 +++ b/main.cpp Tue Jul 29 14:03:29 2014 +0000 @@ -1,14 +1,22 @@ #include <mbed.h> -#include <EPD.h> -#include "mbed.h" -#include "BLEDevice.h" +#include "EPD.h" #include "lz.h" -Serial py(USBTX, USBRX); -BLEDevice ble; -DigitalOut myled(LED1); + +#define LOG_LEVEL_VERBOSE +#include "Puck.h" + +int receiveIndex = 0; + +Puck* puck = &Puck::getPuck(); -int receive_index = 0; + +EPD_Class EPD(p0, p2, p3, p8, p5, p6, p7); + + +const UUID DISPLAY_SERVICE_UUID = UUID(stringToUUID("bftj display ")); +const UUID COMMAND_UUID = UUID(stringToUUID("bftj display com")); +const UUID DATA_UUID = UUID(stringToUUID("bftj display dat")); /* @@ -47,183 +55,102 @@ #define COMMAND_BEGIN_UPPER 4 #define COMMAND_BEGIN_LOWER 5 -//#define IMAGE_SIZE 5808 -//#define Y_SIZE 176 -//#define X_SIZE 264 #define IMAGE_SIZE 2904 +#define BUFFER_SIZE 2917 #define Y_SIZE 88 #define X_SIZE 264 -#define RECEIVE_BUFFER_SIZE 1000 -uint8_t image[IMAGE_SIZE]; -uint8_t receive_buffer[RECEIVE_BUFFER_SIZE]; +uint8_t buffer[BUFFER_SIZE]; + +int currentCommand = COMMAND_NOOP; + + +void reverseBufferSegment(int from, int to) { + for(int i = from; i < (to + from + 1) / 2; i++) { + int i2 = to + from - i - 1; + int temp = buffer[i]; + buffer[i] = buffer[i2]; + buffer[i2] = temp; + } + LOG_DEBUG("Reversed buffer from index %i to index %i.\n", from, to); +} + -extern GattService display_service; -extern GattCharacteristic command, data; -int current_command = COMMAND_NOOP; - -bool isConnected = false; -bool isAdvertising = false; - -const static uint8_t beaconPayload[] = { - 0x00, 0x4C, // Company identifier code (0x004C == Apple) - 0x02, // ID - 0x15, // length of the remaining payload - 0xE2, 0x0A, 0x39, 0xF4, 0x73, 0xF5, 0x4B, 0xC4, // UUID - 0xA1, 0x2F, 0x17, 0xD1, 0xAD, 0x07, 0xA9, 0x61, - 0x13, 0x37, // the major value to differenciate a location - 0xFA, 0xCC, // the minor value to differenciate a location - 0xC0 // 2's complement of the Tx power (-56dB) (now modified) -}; - -void onDataWritten(uint16_t handle) -{ - for (int i = 0; i < display_service.getCharacteristicCount(); i++) { - GattCharacteristic* characteristic = display_service.getCharacteristic(i); - characteristic->getMaxLength(); - if (characteristic->getHandle() == handle) { - uint16_t max_length = characteristic->getMaxLength(); - ble.readCharacteristicValue(handle, characteristic->getValuePtr(), &max_length); +void onCommandWritten(uint8_t* value) { + currentCommand = value[0]; + LOG_DEBUG("Received command: %i.\n", currentCommand); + + switch(currentCommand) { + + case COMMAND_BEGIN_UPPER: + case COMMAND_BEGIN_LOWER: + receiveIndex = BUFFER_SIZE; + break; + + case COMMAND_CLEAR: + LOG_INFO("Clearing display.\n"); + EPD.begin(EPD_2_7); + EPD.start(); + EPD.clear(); + EPD.end(); break; - } + + case COMMAND_IMAGE_UPPER: + LOG_INFO("Writing image to top half of display.\n"); + reverseBufferSegment(receiveIndex, BUFFER_SIZE); + LOG_DEBUG("LZ_Uncompress(in: 0x%x, out 0x%x, insize: %i)\n", buffer + receiveIndex, buffer, BUFFER_SIZE - receiveIndex); + LZ_Uncompress(buffer + receiveIndex, buffer, BUFFER_SIZE - receiveIndex); + LOG_INFO("Uncompressed %i bytes of data.\n", BUFFER_SIZE - receiveIndex); + EPD.begin(EPD_2_7); + EPD.start(); + EPD.image(buffer, 0, EPD.lines_per_display / 2); + EPD.end(); + break; + + case COMMAND_IMAGE_LOWER: + LOG_INFO("Writing image to bottom half of display.\n"); + reverseBufferSegment(receiveIndex, BUFFER_SIZE); + LZ_Uncompress(buffer + receiveIndex, buffer, BUFFER_SIZE - receiveIndex); + LOG_INFO("Uncompressed %i bytes of data.\n", BUFFER_SIZE - receiveIndex); + EPD.begin(EPD_2_7); + EPD.start(); + EPD.image(buffer, EPD.lines_per_display / 2, EPD.lines_per_display); + EPD.end(); + break; + } - if (command.getHandle() == handle) { - current_command = command.getValuePtr()[0]; - - - py.printf("cmd: %i\n", current_command); - - if(current_command == COMMAND_BEGIN_UPPER || current_command == COMMAND_BEGIN_LOWER) { - receive_index = 0; - } - } - - if (data.getHandle() == handle) { - uint8_t* value = data.getValuePtr(); - for(int i = 0; i < 20 && receive_index < IMAGE_SIZE; i++) { - receive_buffer[receive_index++] = value[i]; - } - if (receive_index == IMAGE_SIZE) { - receive_index = 0; - } + currentCommand = COMMAND_NOOP; +} + +void onDataWritten(uint8_t* value) { + LOG_VERBOSE("Data written, receiveIndex: %i\n", receiveIndex); + for(int i = 0; i < 20 && receiveIndex > 0; i++) { + buffer[--receiveIndex] = value[i]; } } -void disconnectionCallback(void) -{ - py.printf("Disconnected!\n"); - isConnected = false; -} - - void connectionCallback(void) -{ - py.printf("Connected!\n"); - isConnected = true; - isAdvertising = false; -} - -void uncompress_image() { - LZ_Uncompress(receive_buffer, image, receive_index); -} - -//uint8_t image[5808]; - -void clear(){ - for(int i=0;i<IMAGE_SIZE;i++){ - image[i] = 0; - } -} - -void set_pixel(int x, int y, int color) { - int byte_x = x / 8; - int byte_w = X_SIZE / 8; - int byte_offset = x % 8; - int byte = image[byte_x + byte_w * y]; - if(color) { - byte |= 1 << byte_offset; - } else { - byte &= ~(1 << byte_offset); - } - image[byte_x + byte_w * y] = byte; -} int main() { + LOG_INFO("Starting puck.\n"); + DigitalOut SD_CS(p4); DigitalOut WORD_STOCK_CS(p26); SD_CS = 1; WORD_STOCK_CS = 1; - clear(); - - EPD_Class EPD(p0, p2, p3, p8, p5, p6, p7); + puck->addCharacteristic(DISPLAY_SERVICE_UUID, COMMAND_UUID, 1); + puck->addCharacteristic(DISPLAY_SERVICE_UUID, DATA_UUID, 20); - EPD.begin(EPD_2_7); - EPD.start(); - EPD.clear(); - EPD.end(); - ble.init(); - ble.onDisconnection(disconnectionCallback); - ble.onConnection(connectionCallback); - ble.onDataWritten(onDataWritten); + puck->onCharacteristicWrite(&COMMAND_UUID, onCommandWritten); + puck->onCharacteristicWrite(&DATA_UUID, onDataWritten); - - ble.addService(display_service); + puck->init(0x5EED); - myled = 1; + puck->countFreeMemory(); - py.printf("Starting up.\n"); - - current_command = COMMAND_NOOP; + currentCommand = COMMAND_NOOP; - while (true) { - ble.waitForEvent(); - myled = !myled; - - if(current_command == COMMAND_CLEAR) { - - py.printf("Clearing.\n"); - EPD.begin(EPD_2_7); - EPD.start(); - EPD.clear(); - EPD.end(); - current_command = COMMAND_NOOP; - } - - - if(current_command == COMMAND_IMAGE_UPPER) { - py.printf("Uppering.\n"); - uncompress_image(); - EPD.begin(EPD_2_7); - EPD.start(); - EPD.image(image, 0, EPD.lines_per_display / 2); - EPD.end(); - current_command = COMMAND_NOOP; - } - - - if(current_command == COMMAND_IMAGE_LOWER) { - py.printf("Lowering.\n"); - uncompress_image(); - EPD.begin(EPD_2_7); - EPD.start(); - EPD.image(image, EPD.lines_per_display / 2, EPD.lines_per_display); - EPD.end(); - current_command = COMMAND_NOOP; - } - - - if(!isConnected && !isAdvertising) { - ble.clearAdvertisingPayload(); - ble.accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED); - ble.setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED); - ble.setAdvertisingInterval(160); /* 100ms; in multiples of 0.625ms. */ - ble.accumulateAdvertisingPayload(GapAdvertisingData::MANUFACTURER_SPECIFIC_DATA, - beaconPayload, sizeof(beaconPayload)); - ble.startAdvertising(); - py.printf("Restarting the advertising process\n"); - isAdvertising = true; - } - } + while (puck->drive()); } \ No newline at end of file