diff --git a/apps/ble-demo/src/main.c b/apps/ble-demo/src/main.c index 2fe1e333a2767173b1416233cffd62d7f0f68897..246f856156fed62e1585f4b244fbc1e31791ba8e 100644 --- a/apps/ble-demo/src/main.c +++ b/apps/ble-demo/src/main.c @@ -12,6 +12,15 @@ #include "font.h" +/* TYPES!!! */ + +struct uv_state { + uint16_t period; + uint16_t on_duration; + uint16_t point_in_cycle; + uint16_t intensity; +}; + /* DEFINITIONS!!! */ #define INFORMATION_UUID 0x180A /* "Device Information Service" */ @@ -20,13 +29,11 @@ #define MY_UUID( x ) 0x43, 0x72, 0xE2, 0x22, 0x0D, 0x80, 0x7D, 0x78, \ 0xE0, 0x43, 0xD5, 0xAB, x & 0xFF, ( x >> 8 ) & 0xFF, 0x38, 0xFA -#define RW_UUID MY_UUID( 0xAA10 ) -#define READ_UUID MY_UUID( 0xAA11 ) -#define WRITE_UUID MY_UUID( 0xAA12 ) -#define READ_WRITE_UUID MY_UUID( 0xAA13 ) -#define IN_UUID MY_UUID( 0xAA20 ) -#define INDICATE_UUID MY_UUID( 0xAA21 ) -#define NOTIFY_UUID MY_UUID( 0xAA22 ) +#define BANDAGE_UUID MY_UUID( 0xAA20 ) +#define BANDAGE_UV_UUID MY_UUID( 0xAA21 ) +#define BANDAGE_TEMP_UUID MY_UUID( 0xAA22 ) + +#define MAX_TEMPERATURE_TRANSFER_SIZE 4 /* PROTOTYPES!!! */ @@ -43,34 +50,48 @@ static int ble_gap_event( struct ble_gap_event* event, void* data ); static int ble_info_callback( uint16_t connection_handle, uint16_t attribute_handle, struct ble_gatt_access_ctxt* context, void* data ); -static int ble_rw_callback( uint16_t connection_handle, +static int ble_uv_callback( uint16_t connection_handle, uint16_t attribute_handle, struct ble_gatt_access_ctxt* context, void* data ); -static int ble_in_callback( uint16_t connection_handle, +static int ble_temp_callback( uint16_t connection_handle, uint16_t attribute_handle, struct ble_gatt_access_ctxt* context, void* data ); static void gpio_init( void ); static void button_handler( void* data ); -static void timeout( struct os_event* event ); +static void uv_timeout( struct os_event* event ); +static void temperature_timeout( struct os_event* event ); /* GLOBALS!!! */ static struct { uint8_t address_type; uint16_t connection_handle; - uint16_t indicate_handle; - uint16_t notify_handle; - bool indicate_status; - bool notify_status; - int8_t count; + uint16_t uv_handle; + uint16_t temp_handle; + bool temp_notify_status; } ble_state; uint8_t frame_buffer[128 / 8 * 64 + 1] = { 0x40, 0, }; uint8_t* frame = &frame_buffer[1]; const size_t frame_size = 128 / 8 * 64; -uint32_t t = 0; + +static struct { + float buffer[2048]; + size_t buffer_start; + size_t buffer_end; + struct os_callout callout; + uint16_t interval; +} temperature; +#define TEMPERATURE_BUFFER_LEN \ + ( sizeof temperature.buffer / sizeof *temperature.buffer ) + +static struct { + struct uv_state state; + struct os_callout callout; + bool on; +} uv; /* DATA!!! */ @@ -83,54 +104,84 @@ static const struct ble_gatt_svc_def services[] = { .uuid = BLE_UUID16_DECLARE( MANUFACTURER_UUID ), .access_cb = &ble_info_callback, .flags = BLE_GATT_CHR_F_READ, + /* Reading returns a string with the manufacturer + * name */ }, { .uuid = BLE_UUID16_DECLARE( MODEL_UUID ), .access_cb = &ble_info_callback, .flags = BLE_GATT_CHR_F_READ, + /* Reading returns a string with the model number */ }, { 0, }, }, }, { .type = BLE_GATT_SVC_TYPE_PRIMARY, - .uuid = BLE_UUID128_DECLARE( RW_UUID ), + .uuid = BLE_UUID128_DECLARE( BANDAGE_UUID ), .characteristics = (struct ble_gatt_chr_def[]) { { - .uuid = BLE_UUID128_DECLARE( READ_UUID ), - .access_cb = &ble_rw_callback, - .flags = BLE_GATT_CHR_F_READ, - }, - { - .uuid = BLE_UUID128_DECLARE( WRITE_UUID ), - .access_cb = &ble_rw_callback, - .flags = BLE_GATT_CHR_F_WRITE, - }, - { - .uuid = BLE_UUID128_DECLARE( READ_WRITE_UUID ), - .access_cb = &ble_rw_callback, + .uuid = BLE_UUID128_DECLARE( BANDAGE_UV_UUID ), + .access_cb = &ble_uv_callback, + .val_handle = &( ble_state.uv_handle ), .flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_WRITE, - }, - { 0, }, - }, - }, - { - .type = BLE_GATT_SVC_TYPE_PRIMARY, - .uuid = BLE_UUID128_DECLARE( IN_UUID ), - .characteristics = (struct ble_gatt_chr_def[]) { - { - .uuid = BLE_UUID128_DECLARE( INDICATE_UUID ), - .access_cb = &ble_in_callback, - .val_handle = &( ble_state.indicate_handle ), - .flags = BLE_GATT_CHR_F_INDICATE, + /* Both reads and writes have this format: + * + * struct __attribute__((packed)) { + * uint16_t period; + * uint16_t on_duration; + * uint16_t point_in_cycle; + * uint16_t intensity; + * }; + * + * ("__attribute__((packed))" means each struct + * elements takes up exactly as much space as it needs. + * Otherwise the numbers will sometimes get put 4 bytes + * apart even though they're only two bytes long.) + * + * The values period, on duration and point_in_cycle are + * all in seconds. Intensity is a value between 0 and + * 65535 (way more resolution than we need, but it's + * easier to have everything be the same data type). + * The point_in_cycle value is were we currently are in + * the period, it can be both read and written to. The + * on duration is at the start of the period. */ }, { - .uuid = BLE_UUID128_DECLARE( NOTIFY_UUID ), - .access_cb = &ble_in_callback, - .val_handle = &( ble_state.notify_handle ), - .flags = BLE_GATT_CHR_F_NOTIFY, + .uuid = BLE_UUID128_DECLARE( BANDAGE_TEMP_UUID ), + .access_cb = &ble_temp_callback, + .val_handle = &( ble_state.temp_handle ), + .flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_WRITE | + BLE_GATT_CHR_F_NOTIFY, + /* Notify sends a 32 bit float with the current + * temperature. + * + * Read sends buffered temperature data in this format + * + * struct __attribute__((packed)) { + * uint16_t length; + * uint16_t interval; + * float data[ + * length > MAX_TEMPERATURE_TRANSFER_SIZE ? + * MAX_TEMPERATURE_TRANSFER_SIZE : length]; + * }; + * + * length will be the total number of data points + * that are left to send, but reads can only send + * so much data so you get max, 50 at a time. Keep + * reading until you get a full length's worth of + * data. + * + * Writing should be a 16 bit integer with the + * number of seconds to wait between temperature + * readings. + * + * Updating the reading interval or disconnecting + * from notifications empties the readings buffer, + * so make sure you've read all that you want + * before doing that. */ }, - { 0 }, + { 0, }, }, }, { 0, } @@ -140,6 +191,8 @@ static const struct ble_gatt_svc_def services[] = { int main( void ) { + (void) text8; + sysinit(); screen_init(); @@ -148,11 +201,21 @@ int main( void ) { gpio_init(); - t = 0; - static struct os_callout timer; - os_callout_init( &timer, os_eventq_dflt_get(), - &timeout, &timer ); - os_callout_reset( &timer, OS_TICKS_PER_SEC ); + uv.state.period = 0xFFFF; + uv.state.on_duration = 0; + uv.state.point_in_cycle = 0; + uv.state.intensity = 0; + uv.on = false; + os_callout_init( &( uv.callout ), os_eventq_dflt_get(), + &uv_timeout, NULL ); + + temperature.buffer_start = 0; + temperature.buffer_end = 0; + temperature.interval = 10; + os_callout_init( &( temperature.callout ), os_eventq_dflt_get(), + &temperature_timeout, NULL ); + os_callout_reset( &( temperature.callout ), + OS_TICKS_PER_SEC * temperature.interval ); while ( 1 ) { @@ -370,8 +433,7 @@ static int ble_gap_event( struct ble_gap_event* event, void* data ) { } else { - ble_state.indicate_status = 0; - ble_state.notify_status = 0; + ble_state.temp_notify_status = 0; ble_state.connection_handle = 0; ble_advertise(); @@ -383,8 +445,7 @@ static int ble_gap_event( struct ble_gap_event* event, void* data ) { case BLE_GAP_EVENT_DISCONNECT: { - ble_state.indicate_status = 0; - ble_state.notify_status = 0; + ble_state.temp_notify_status = 0; ble_state.connection_handle = 0; ble_advertise(); @@ -395,16 +456,15 @@ static int ble_gap_event( struct ble_gap_event* event, void* data ) { case BLE_GAP_EVENT_SUBSCRIBE: { if ( event->subscribe.attr_handle == - ble_state.indicate_handle ) { - - ble_state.indicate_status = - event->subscribe.cur_indicate; + ble_state.temp_handle ) { - } else if ( event->subscribe.attr_handle == - ble_state.notify_handle ) { - - ble_state.notify_status = + ble_state.temp_notify_status = event->subscribe.cur_notify; + + if ( !event->subscribe.cur_notify ) { + temperature.buffer_start = 0; + temperature.buffer_end = 0; + } } @@ -473,102 +533,114 @@ static int ble_info_callback( uint16_t connection_handle, } -static int ble_rw_callback( uint16_t connection_handle, +static int ble_uv_callback( uint16_t connection_handle, uint16_t attribute_handle, struct ble_gatt_access_ctxt* context, void* data ) { (void) data; - (void) attribute_handle; (void) connection_handle; - if ( 0 == ble_uuid_cmp( context->chr->uuid, - BLE_UUID128_DECLARE( READ_UUID ) ) ) { - - if ( BLE_GATT_ACCESS_OP_WRITE_CHR == context->op ) { + assert( ble_state.uv_handle == attribute_handle ); - return BLE_ATT_ERR_WRITE_NOT_PERMITTED; + if ( BLE_GATT_ACCESS_OP_WRITE_CHR == context->op ) { - } else if ( BLE_GATT_ACCESS_OP_READ_CHR == context->op ) { + os_mbuf_copydata( context->om, 0, + sizeof uv.state, &( uv.state ) ); - static const char str[] = "Reading! Congratulations!"; - if ( 0 != os_mbuf_append( - context->om, str, strlen( str ) ) ) { - return BLE_ATT_ERR_INSUFFICIENT_RES; - } + if ( uv.state.point_in_cycle < uv.state.on_duration ) { - memset( frame + frame_size / 4, 0, frame_size / 8 ); - text8( "Read read", frame, 2, 0 ); - i2c_write( frame_buffer, sizeof frame_buffer ); + os_callout_reset( &( uv.callout ), OS_TICKS_PER_SEC * + ( uv.state.on_duration - uv.state.point_in_cycle ) ); } else { - assert( 0 ); + os_callout_reset( &( uv.callout ), OS_TICKS_PER_SEC * + ( uv.state.period - uv.state.point_in_cycle ) ); } - } else if ( 0 == ble_uuid_cmp( context->chr->uuid, - BLE_UUID128_DECLARE( WRITE_UUID ) ) ) { + } else if ( BLE_GATT_ACCESS_OP_READ_CHR == context->op ) { - if ( BLE_GATT_ACCESS_OP_WRITE_CHR == context->op ) { + uint16_t time = os_callout_remaining_ticks( + &( uv.callout ), os_time_get() ) / OS_TICKS_PER_SEC; + if ( uv.on ) { + uv.state.point_in_cycle = uv.state.on_duration - time - 1; + } else { + uv.state.point_in_cycle = uv.state.period - time - 1; + } - char str[256] = { 0, }; - os_mbuf_copydata( context->om, 0, sizeof str - 1, str ); + os_mbuf_append( context->om, &( uv.state ), sizeof uv.state ); - memset( frame + frame_size / 4, 0, frame_size / 8 ); - text8( str, frame, 2, 0 ); - i2c_write( frame_buffer, sizeof frame_buffer ); + } else { - } else if ( BLE_GATT_ACCESS_OP_READ_CHR == context->op ) { + assert( 0 ); - return BLE_ATT_ERR_READ_NOT_PERMITTED; + } - } else { + return 0; - assert( 0 ); +} - } +static int ble_temp_callback( uint16_t connection_handle, + uint16_t attribute_handle, struct ble_gatt_access_ctxt* context, + void* data ) { + + (void) data; + (void) connection_handle; - } else if ( 0 == ble_uuid_cmp( context->chr->uuid, - BLE_UUID128_DECLARE( READ_WRITE_UUID ) ) ) { + assert( ble_state.temp_handle == attribute_handle ); - if ( BLE_GATT_ACCESS_OP_WRITE_CHR == context->op ) { + if ( BLE_GATT_ACCESS_OP_WRITE_CHR == context->op ) { - char str[256] = { 0, }; - os_mbuf_copydata( context->om, 0, sizeof str, str ); + os_mbuf_copydata( context->om, 0, + sizeof temperature.interval, &( temperature.interval ) ); - memset( frame + frame_size / 4, 0, frame_size / 8 ); - text8( str, frame, 2, 0 ); - i2c_write( frame_buffer, sizeof frame_buffer ); + temperature.buffer_start = 0; + temperature.buffer_end = 0; - } else if ( BLE_GATT_ACCESS_OP_READ_CHR == context->op ) { + os_callout_reset( &( temperature.callout ), + OS_TICKS_PER_SEC * temperature.interval ); - static const char str[] = "R/W Reading! Congratulations!"; - if ( 0 != os_mbuf_append( - context->om, str, strlen( str ) ) ) { - return BLE_ATT_ERR_INSUFFICIENT_RES; - } - memset( frame + frame_size / 4, 0, frame_size / 8 ); - text8( "Read/write read", frame, 2, 0 ); - i2c_write( frame_buffer, sizeof frame_buffer ); + } else if ( BLE_GATT_ACCESS_OP_READ_CHR == context->op ) { + struct { + uint32_t length_interval; + float data[MAX_TEMPERATURE_TRANSFER_SIZE]; + } data; + + uint32_t length; + if ( temperature.buffer_end >= temperature.buffer_start ) { + length = temperature.buffer_end - temperature.buffer_start; } else { + length = temperature.buffer_end + TEMPERATURE_BUFFER_LEN - + temperature.buffer_start; + } - assert( 0 ); + data.length_interval = length << 16 | temperature.interval; + if ( length > MAX_TEMPERATURE_TRANSFER_SIZE ) { + length = MAX_TEMPERATURE_TRANSFER_SIZE; } - } + for ( int i = 0; i < length; i++ ) { + size_t pos = ( temperature.buffer_start + i ) % + TEMPERATURE_BUFFER_LEN; + data.data[i] = temperature.buffer[pos]; + } - return 0; + os_mbuf_append( context->om, &data, + sizeof (uint32_t) + length * sizeof (float) ); -} + temperature.buffer_start += length; + temperature.buffer_start %= TEMPERATURE_BUFFER_LEN; -static int ble_in_callback( uint16_t connection_handle, - uint16_t attribute_handle, struct ble_gatt_access_ctxt* context, - void* data ) { + } else { + + assert( 0 ); - /* Notify / Indicate only */ - return BLE_ATT_ERR_READ_NOT_PERMITTED; + } + + return 0; } @@ -598,68 +670,75 @@ static void gpio_init( void ) { static void button_handler( void* data ) { - int button = *( (int*) data ); + (void) data; +} - if ( 1 == button ) { +static void uv_timeout( struct os_event* event ) { - ble_state.count--; + if ( uv.on ) { - if ( ble_state.indicate_status ) { + hal_gpio_write( LED_RED, 1 ); + hal_gpio_write( LED_GREEN, 1 ); + hal_gpio_write( LED_BLUE, 1 ); - struct os_mbuf* om = - ble_hs_mbuf_from_flat( &( ble_state.count ), 1 ); - assert( 0 == ble_gatts_indicate_custom( - ble_state.connection_handle, - ble_state.indicate_handle, om ) ); + os_callout_reset( &( uv.callout ), + OS_TICKS_PER_SEC * + ( uv.state.period - uv.state.on_duration ) ); - } + uv.on = false; } else { - ble_state.count++; - - if ( ble_state.indicate_status ) { + if ( 0 == uv.state.on_duration ) { - struct os_mbuf* om = - ble_hs_mbuf_from_flat( &( ble_state.count ), 1 ); - assert( 0 == ble_gatts_indicate_custom( - ble_state.connection_handle, - ble_state.indicate_handle, om ) ); + return; } - } + hal_gpio_write( LED_RED, !( uv.state.intensity < 0x8000 ) ); + hal_gpio_write( LED_GREEN, !( uv.state.intensity >= 0x8000 && + uv.state.intensity < 0xC000 ) ); + hal_gpio_write( LED_BLUE, !( uv.state.intensity >= 0xC000 ) ); - char str[128]; - snprintf( str, sizeof str, "Count: %d", ble_state.count ); - memset( frame + frame_size / 8 * 3, 0, frame_size / 8 ); - text8( str, frame, 3, 0 ); - i2c_write( frame_buffer, sizeof frame_buffer ); + os_callout_reset( &( uv.callout ), + OS_TICKS_PER_SEC * uv.state.on_duration ); -} + uv.on = true; -static void timeout( struct os_event* event ) { + } - t++; +} - char str[32]; - snprintf( str, sizeof str, - "Time: %lu:%02lu", t / 60, t % 60 ); - memset( frame + frame_size / 2, 0, frame_size / 8 ); - text8( str, frame, 4, 0 ); - i2c_write( frame_buffer, sizeof frame_buffer ); +static void temperature_timeout( struct os_event* event ) { - if ( ble_state.notify_status ) { + static float current_temperature = 37.0; - struct os_mbuf* om = - ble_hs_mbuf_from_flat( str, strlen( str ) ); + if ( ble_state.temp_notify_status ) { + + struct os_mbuf* om = ble_hs_mbuf_from_flat( + ¤t_temperature, sizeof current_temperature ); assert( 0 == ble_gatts_notify_custom( ble_state.connection_handle, - ble_state.notify_handle, om ) ); + ble_state.temp_handle, om ) ); + + } else { + + temperature.buffer[temperature.buffer_end] = + current_temperature; + temperature.buffer_end++; + temperature.buffer_end %= TEMPERATURE_BUFFER_LEN; + if ( temperature.buffer_end == temperature.buffer_start ) { + temperature.buffer_start++; + temperature.buffer_start %= TEMPERATURE_BUFFER_LEN; + } } - struct os_callout* timer = (struct os_callout*) event->ev_arg; - os_callout_reset( timer, OS_TICKS_PER_SEC ); + current_temperature += 0.1; + if ( current_temperature >= 38 ) { + current_temperature = 36.1; + } + os_callout_reset( &( temperature.callout ), + OS_TICKS_PER_SEC * temperature.interval ); } diff --git a/apps/ble-demo/syscfg.yml b/apps/ble-demo/syscfg.yml index cfbd94fb7198afd17bc404cf946d4ae4c23d0db4..6e9b210d7efb5f8f263ae3a26bc443981d402cfb 100644 --- a/apps/ble-demo/syscfg.yml +++ b/apps/ble-demo/syscfg.yml @@ -7,7 +7,7 @@ syscfg.defs: value: '"0000"' DEVICE_MANUFACTURER: description: "Device manufacturer string" - value: '"Tom :)"' + value: '"C-FLEET :)"' CPUTIME_FREQ: description: "Frequency for the cputime counter" value: '50000'