diff --git a/cores/arduino/Arduino.h b/cores/arduino/Arduino.h index e656d4ee..a4cce47d 100644 --- a/cores/arduino/Arduino.h +++ b/cores/arduino/Arduino.h @@ -110,6 +110,7 @@ extern uint8_t pinmuxMode[NUM_DIGITAL_PINS]; #include "WMath.h" #include "HardwareSerial.h" #include "wiring_pulse.h" +#include "error.h" #endif // __cplusplus diff --git a/cores/arduino/CDCSerialClass.cpp b/cores/arduino/CDCSerialClass.cpp index 5cd0083d..c059cea8 100644 --- a/cores/arduino/CDCSerialClass.cpp +++ b/cores/arduino/CDCSerialClass.cpp @@ -30,11 +30,35 @@ #include "wiring_digital.h" #include "variant.h" +#define CDC_MAILBOX_TX_CHANNEL 7 +#define CDC_MAILBOX_RX_CHANNEL 6 extern void CDCSerial_Handler(void); extern void serialEventRun1(void) __attribute__((weak)); extern void serialEvent1(void) __attribute__((weak)); +static void cdc_mbox_isr(CurieMailboxMsg msg) +{ + char *rxbuffptr = (char*)msg.data; + int new_head; + for(int i = 0; i < MBOX_BYTES; i++) + { + if((uint8_t)(*(rxbuffptr+i)) != '\0') + { + new_head = (Serial._rx_buffer->head +1) % CDCACM_BUFFER_SIZE; + if(new_head != Serial._rx_buffer->tail) + { + Serial._rx_buffer->data[Serial._rx_buffer->head] = *(rxbuffptr+i); + Serial._rx_buffer->head = new_head; + } + } + else + { + break; + } + } +} + // Constructors //////////////////////////////////////////////////////////////// CDCSerialClass::CDCSerialClass(uart_init_info *info) @@ -46,9 +70,9 @@ CDCSerialClass::CDCSerialClass(uart_init_info *info) void CDCSerialClass::setSharedData(struct cdc_acm_shared_data *cdc_acm_shared_data) { - this->_shared_data = cdc_acm_shared_data; - this->_rx_buffer = cdc_acm_shared_data->rx_buffer; - this->_tx_buffer = cdc_acm_shared_data->tx_buffer; + _shared_data = cdc_acm_shared_data; + _rx_buffer = cdc_acm_shared_data->rx_buffer; + _tx_buffer = cdc_acm_shared_data->tx_buffer; } void CDCSerialClass::begin(const uint32_t dwBaudRate) @@ -62,8 +86,13 @@ void CDCSerialClass::begin(const uint32_t dwBaudRate, const uint8_t config) } -void CDCSerialClass::init(const uint32_t dwBaudRate, const uint8_t modeReg) +void CDCSerialClass::init(uint32_t dwBaudRate, const uint8_t modeReg) { + /* Set a max internal baud rate due to the limitation of the + * Inter Processor Mailbox */ + if(dwBaudRate > 115200) + dwBaudRate = 115200; + /* Set a per-byte write delay approximately equal to the time it would * take to clock out a byte on a standard UART at this baud rate */ _writeDelayUsec = 8000000 / dwBaudRate; @@ -72,7 +101,9 @@ void CDCSerialClass::init(const uint32_t dwBaudRate, const uint8_t modeReg) * Empty the Rx buffer but don't touch Tx buffer: it is drained by the * LMT one way or another */ _rx_buffer->tail = _rx_buffer->head; - + + mailbox_register(CDC_MAILBOX_RX_CHANNEL, cdc_mbox_isr); + mailbox_enable_receive(CDC_MAILBOX_RX_CHANNEL); _shared_data->device_open = true; } @@ -83,12 +114,10 @@ void CDCSerialClass::end( void ) int CDCSerialClass::available( void ) { -#define SBS CDCACM_BUFFER_SIZE - if (!_shared_data->device_open) return (0); else - return (int)(SBS + _rx_buffer->head - _rx_buffer->tail) % SBS; + return (int)(CDCACM_BUFFER_SIZE + _rx_buffer->head - _rx_buffer->tail) % CDCACM_BUFFER_SIZE; } int CDCSerialClass::availableForWrite(void) @@ -130,29 +159,61 @@ void CDCSerialClass::flush( void ) } } -size_t CDCSerialClass::write( const uint8_t uc_data ) +size_t CDCSerialClass::write(uint8_t uc_data ) { - uint32_t retries = 1; + CurieMailboxMsg cdcacm_msg; if (!_shared_data->device_open || !_shared_data->host_open) return(0); - do { - int i = (uint32_t)(_tx_buffer->head + 1) % CDCACM_BUFFER_SIZE; - // if we should be storing the received character into the location - // just before the tail (meaning that the head would advance to the - // current location of the tail), we're about to overflow the buffer - // and so we don't write the character or advance the head. - if (i != _tx_buffer->tail) { - _tx_buffer->data[_tx_buffer->head] = uc_data; - _tx_buffer->head = i; - - // Mimick the throughput of a typical UART by throttling the data - // flow according to the configured baud rate - delayMicroseconds(_writeDelayUsec); - break; + cdcacm_msg.channel = CDC_MAILBOX_TX_CHANNEL; + cdcacm_msg.data[0] = uc_data; + mailbox_write(cdcacm_msg); + delayMicroseconds(_writeDelayUsec); + return 1; +} + +size_t CDCSerialClass::write(const uint8_t *buffer, size_t size) +{ + CurieMailboxMsg cdcacm_msg; + cdcacm_msg.channel = CDC_MAILBOX_TX_CHANNEL; + if (!_shared_data->device_open || !_shared_data->host_open) + return(0); + + int msg_len = size; + + for(int i = 0;msg_len > 0; msg_len -= MBOX_BYTES, i += MBOX_BYTES) + { + /* Copy data into mailbox message */ + memset(cdcacm_msg.data, 0, MBOX_BYTES); + if(msg_len >= MBOX_BYTES) + { + memcpy(cdcacm_msg.data, buffer+i, MBOX_BYTES); } - } while (retries--); + else + { + memcpy(cdcacm_msg.data, buffer+i, msg_len); + } + /* Write to mailbox*/ + mailbox_write(cdcacm_msg); + } - return 1; + // Mimick the throughput of a typical UART by throttling the data + // flow according to the configured baud rate + delayMicroseconds(_writeDelayUsec * size); + + return size; +} + +size_t CDCSerialClass::write(const char *str) +{ + if (str == NULL) return 0; + CurieMailboxMsg cdcacm_msg; + cdcacm_msg.channel = CDC_MAILBOX_TX_CHANNEL; + if (!_shared_data->device_open || !_shared_data->host_open) + return(0); + + int msg_len = strlen(str); + + return write((const uint8_t *)str, msg_len); } diff --git a/cores/arduino/CDCSerialClass.h b/cores/arduino/CDCSerialClass.h index f240ac38..74eb7b3b 100644 --- a/cores/arduino/CDCSerialClass.h +++ b/cores/arduino/CDCSerialClass.h @@ -26,6 +26,7 @@ #include "HardwareSerial.h" #include "platform.h" #include "wiring.h" +#include "mailbox.h" #include #include @@ -36,6 +37,10 @@ class CDCSerialClass : public HardwareSerial CDCSerialClass(uart_init_info *info); void setSharedData(struct cdc_acm_shared_data *cdc_acm_shared_data); + + struct cdc_acm_shared_data *_shared_data; + struct cdc_ring_buffer *_rx_buffer; + struct cdc_ring_buffer *_tx_buffer; void begin(const uint32_t dwBaudRate); void begin(const uint32_t dwBaudRate, const uint8_t config); @@ -46,6 +51,8 @@ class CDCSerialClass : public HardwareSerial int read(void); void flush(void); size_t write(const uint8_t c); + size_t write(const char *str); + size_t write(const uint8_t *buffer, size_t size); using Print::write; // pull in write(str) and write(buf, size) from Print operator bool() { @@ -56,11 +63,7 @@ class CDCSerialClass : public HardwareSerial }; protected: - void init(const uint32_t dwBaudRate, const uint8_t config); - - struct cdc_acm_shared_data *_shared_data; - struct cdc_ring_buffer *_rx_buffer; - struct cdc_ring_buffer *_tx_buffer; + void init(uint32_t dwBaudRate, const uint8_t config); uart_init_info *info; uint32_t _writeDelayUsec; diff --git a/cores/arduino/Print.h b/cores/arduino/Print.h index 16552079..96bd3022 100644 --- a/cores/arduino/Print.h +++ b/cores/arduino/Print.h @@ -47,7 +47,7 @@ class Print void clearWriteError() { setWriteError(0); } virtual size_t write(uint8_t) = 0; - size_t write(const char *str) { + virtual size_t write(const char *str) { if (str == NULL) return 0; return write((const uint8_t *)str, strlen(str)); } diff --git a/cores/arduino/RingBuffer.h b/cores/arduino/RingBuffer.h index 0e87b7ce..04d41b5a 100644 --- a/cores/arduino/RingBuffer.h +++ b/cores/arduino/RingBuffer.h @@ -30,9 +30,9 @@ class RingBuffer { public: uint8_t *_aucBuffer; - int _iHead ; - int _iTail ; - bool _buffer_overflow ; + volatile int _iHead ; + volatile int _iTail ; + volatile bool _buffer_overflow ; RingBuffer( void ) ; void store_char( uint8_t c ) ; diff --git a/cores/arduino/UARTClass.cpp b/cores/arduino/UARTClass.cpp index 000985f2..b4c31004 100644 --- a/cores/arduino/UARTClass.cpp +++ b/cores/arduino/UARTClass.cpp @@ -168,7 +168,7 @@ int UARTClass::read( void ) void UARTClass::flush( void ) { - while (_tx_buffer->_iHead != _tx_buffer->_iTail); //wait for transmit data to be sent + while (_tx_buffer->_iHead != (_tx_buffer->_iTail)); //wait for transmit data to be sent // Wait for transmission to complete while(!uart_tx_complete(CONFIG_UART_CONSOLE_INDEX)); } @@ -183,8 +183,7 @@ size_t UARTClass::write( const uint8_t uc_data ) { // If busy we buffer int l = (_tx_buffer->_iHead + 1) % UART_BUFFER_SIZE; - while (_tx_buffer->_iTail == l) - ; // Spin locks if we're about to overwrite the buffer. This continues once the data is sent + while (_tx_buffer->_iTail == l); // Spin locks if we're about to overwrite the buffer. This continues once the data is sent _tx_buffer->_aucBuffer[_tx_buffer->_iHead] = uc_data; _tx_buffer->_iHead = l; @@ -201,21 +200,29 @@ size_t UARTClass::write( const uint8_t uc_data ) void UARTClass::IrqHandler( void ) { - uint8_t uc_data; - int ret; - ret = uart_poll_in(CONFIG_UART_CONSOLE_INDEX, &uc_data); - - while ( ret != -1 ) { - _rx_buffer->store_char(uc_data); + uart_irq_update(CONFIG_UART_CONSOLE_INDEX); + // if irq is Receiver Data Available + if(uart_irq_rx_ready(CONFIG_UART_CONSOLE_INDEX)) + { + uint8_t uc_data; + int ret; ret = uart_poll_in(CONFIG_UART_CONSOLE_INDEX, &uc_data); + + while ( ret != -1 ) { + _rx_buffer->store_char(uc_data); + ret = uart_poll_in(CONFIG_UART_CONSOLE_INDEX, &uc_data); + } } - // Do we need to keep sending data? - if (!uart_irq_tx_ready(CONFIG_UART_CONSOLE_INDEX)) + // if irq is Transmitter Holding Register + if(uart_irq_tx_ready(CONFIG_UART_CONSOLE_INDEX)) { - if (_tx_buffer->_iTail != _tx_buffer->_iHead) { - uart_poll_out(CONFIG_UART_CONSOLE_INDEX, _tx_buffer->_aucBuffer[_tx_buffer->_iTail]); - _tx_buffer->_iTail = (unsigned int)(_tx_buffer->_iTail + 1) % UART_BUFFER_SIZE; + if(_tx_buffer->_iTail != _tx_buffer->_iHead) + { + int end = (_tx_buffer->_iTail < _tx_buffer->_iHead) ? _tx_buffer->_iHead : UART_BUFFER_SIZE; + int l = min(end - _tx_buffer->_iTail, UART_FIFO_SIZE); + l = uart_fifo_fill(CONFIG_UART_CONSOLE_INDEX, _tx_buffer->_aucBuffer+_tx_buffer->_iTail, l); + _tx_buffer->_iTail = (_tx_buffer->_iTail+l)%UART_BUFFER_SIZE; } else { diff --git a/cores/arduino/Udp.h b/cores/arduino/Udp.h index dc5644b9..89f31c67 100644 --- a/cores/arduino/Udp.h +++ b/cores/arduino/Udp.h @@ -41,7 +41,8 @@ class UDP : public Stream { public: - virtual uint8_t begin(uint16_t) =0; // initialize, start listening on specified port. Returns 1 if successful, 0 if there are no sockets available to use + virtual uint8_t begin(uint16_t) =0; // initialize, start listening on specified port. Returns 1 if successful, 0 if there are no sockets available to use + virtual uint8_t beginMulticast(IPAddress, uint16_t) { return 0; } // initialize, start listening on specified multicast IP address and port. Returns 1 if successful, 0 on failure virtual void stop() =0; // Finish with the UDP socket // Sending UDP packets diff --git a/cores/arduino/error.cpp b/cores/arduino/error.cpp new file mode 100644 index 00000000..7371415e --- /dev/null +++ b/cores/arduino/error.cpp @@ -0,0 +1,49 @@ +/* +Copyright (c) 2017 Intel Corporation. All right reserved. + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +*/ + +#include "error.h" + +void error_continue() +{ + error_continue(1); +} + +void error_continue(uint8_t error_code) +{ + uint32_t exc_addr = aux_reg_read(ARC_V2_EFA); + uint32_t ecr = aux_reg_read(ARC_V2_ECR); + + pr_error(0, "Exception vector: 0x%x, cause code: 0x%x, parameter 0x%x\n", + ARC_V2_ECR_VECTOR(ecr), + ARC_V2_ECR_CODE(ecr), + ARC_V2_ECR_PARAMETER(ecr)); + pr_error(0, "Address 0x%x\n", exc_addr); + shared_data->error_code = error_code; +} + +void error_halt() +{ + error_halt(1); +} + +void error_halt(uint8_t error_code) +{ + error_continue(error_code); + __asm__("flag 0x01") ; /* Halt the CPU */ +} diff --git a/cores/arduino/error.h b/cores/arduino/error.h new file mode 100644 index 00000000..9ca0be1b --- /dev/null +++ b/cores/arduino/error.h @@ -0,0 +1,37 @@ +/* +Copyright (c) 2017 Intel Corporation. All right reserved. + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +*/ + +#ifndef _Error_h +#define _Error_h + +#include +#include "os/os.h" +#include "infra/log.h" +#include "aux_regs.h" +#include "platform.h" + +extern void error_halt(); + +extern void error_halt(uint8_t error_code); + +extern void error_continue(); + +extern void error_continue(uint8_t error_code); + +#endif diff --git a/cores/arduino/mailbox.cpp b/cores/arduino/mailbox.cpp new file mode 100644 index 00000000..f8b54786 --- /dev/null +++ b/cores/arduino/mailbox.cpp @@ -0,0 +1,163 @@ +#include +#include "interrupt.h" +#include "scss_registers.h" +#include "mailbox.h" + +#define CHANNEL_STS_MASK 0x1 +#define CHANNEL_INT_MASK 0x2 +#define CTRL_WORD_MASK 0x7FFFFFFF +#define CHALL_STATUS_MASK 0xFFFF +#define CHANNEL_STS_BITS (CHANNEL_STS_MASK | CHANNEL_INT_MASK) + +/* Mailbox channel status register */ +#define IO_REG_MAILBOX_CHALL_STS (SCSS_REGISTER_BASE + 0xAC0) + +typedef struct mbox_channel mbox_channel_t; +typedef struct mbox_intmask mbox_intmask_t; + +/* Represents the registers for a single mailbox channel */ +struct mbox_channel { + uint32_t ctrl; + uint32_t data[CHANNEL_DATA_WORDS]; + uint32_t sts; +}; + +/* Mailbox interrupt mask; right now we only care about the + * second byte, for SS mailbox interrupts (one bit per mailbox channel) */ +struct mbox_intmask { + uint8_t lmt_intmask; + uint8_t ss_intmask; + uint8_t lmt_halt; + uint8_t ss_halt; +}; + +static volatile mbox_intmask_t *intmask; +static volatile mbox_channel_t *mbox; +static void (*callbacks[NUM_MAILBOX_CHANNELS])(CurieMailboxMsg); + +void mailbox_register (int channel, void(*callback)(CurieMailboxMsg)) +{ + if (channel >= 0 && channel < NUM_MAILBOX_CHANNELS) { + callbacks[channel] = callback; + } +} + +void mailbox_unregister (int channel) +{ + if (channel >= 0 && channel < NUM_MAILBOX_CHANNELS) { + callbacks[channel] = 0; + } +} + +void mailbox_disable_receive (int channel) +{ + intmask->ss_intmask |= 1 << channel; +} + +void mailbox_enable_receive (int channel) +{ + intmask->ss_intmask &= ~(1 << channel); +} + +static void do_callback (int channel, CurieMailboxMsg& msg) +{ + void (*cb)(CurieMailboxMsg) = callbacks[channel]; + if (cb) { + cb(msg); + } +} + +static void mailbox_read (int channel, CurieMailboxMsg& msg) +{ + unsigned int i; + + /* Copy channel data into CurieMailboxMsg object */ + msg.id = mbox[channel].ctrl & CTRL_WORD_MASK; + msg.channel = channel; + + for (i = 0; i < CHANNEL_DATA_WORDS; ++i) { + msg.data[i] = mbox[channel].data[i]; + } + + /* Clear channel status & interrupt flags */ + mbox[channel].sts |= CHANNEL_STS_BITS; +} + +void mailbox_write (CurieMailboxMsg& msg) +{ + int i; + uint32_t key; + + /* Can't write if channel status flag is set */ + while ((mbox[msg.channel].sts & CHANNEL_STS_MASK)); + key = interrupt_lock(); + + /* Poplate channel payload */ + mbox[msg.channel].ctrl |= (msg.id & CTRL_WORD_MASK); + for (i = 0; i < CHANNEL_DATA_WORDS; ++i) { + mbox[msg.channel].data[i] = msg.data[i]; + } + + /* Trigger interupt to host */ + mbox[msg.channel].ctrl |= ~(CTRL_WORD_MASK); + + /* Wait for HW to set the channel status bit */ + while (!(mbox[msg.channel].sts & CHANNEL_STS_MASK)); + + /* Wait for destination processor to clear channel status bit */ + while ((mbox[msg.channel].sts & CHANNEL_STS_MASK)); + interrupt_unlock(key); +} + +static uint16_t get_chall_sts (void) +{ + return MMIO_REG_VAL(IO_REG_MAILBOX_CHALL_STS) & CHALL_STATUS_MASK; +} + +static void mailbox_isr (void) +{ + int i; + uint32_t sts; + CurieMailboxMsg msg; + + sts = get_chall_sts(); + /* Get channel number */ + for (i = 0; i < NUM_MAILBOX_CHANNELS; ++i) { + if (sts & (1 << (i * 2 + 1))) { + break; + } + } + + mailbox_read(i, msg); + do_callback(i, msg); +} + +static void mailbox_hardware_init (void) +{ + int i; + + for (i = 0; i < NUM_MAILBOX_CHANNELS; ++i) { + mbox[i].sts &= ~(CHANNEL_STS_BITS); + } +} + +static void mailbox_interrupts_init (bool master) +{ + interrupt_disable(SOC_MBOX_INTERRUPT); + + /* Mask SS mailbox interrupts for all channels; + * Unmasking is done by enableReceive */ + intmask->ss_intmask = 0xFF; + + if (master) mailbox_hardware_init(); + interrupt_connect(SOC_MBOX_INTERRUPT, mailbox_isr); + interrupt_enable(SOC_MBOX_INTERRUPT); +} + +void mailbox_init (bool master) +{ + intmask = (mbox_intmask_t *)IO_REG_MAILBOX_INT_MASK; + mbox = (mbox_channel_t *)IO_REG_MAILBOX_BASE; + memset(callbacks, 0, sizeof(callbacks)); + mailbox_interrupts_init(master); +} diff --git a/cores/arduino/mailbox.h b/cores/arduino/mailbox.h new file mode 100644 index 00000000..a72634eb --- /dev/null +++ b/cores/arduino/mailbox.h @@ -0,0 +1,22 @@ +#ifndef _MAILBOX_H_ +#define _MAILBOX_H_ + +#define NUM_MAILBOX_CHANNELS 8 +#define CHANNEL_DATA_WORDS 4 +#define MBOX_BYTES 16 + +class CurieMailboxMsg { +public: + uint32_t data[CHANNEL_DATA_WORDS]; + uint32_t id; + int channel = 0; +}; + +void mailbox_init (bool master); +void mailbox_register (int channel, void(*callback)(CurieMailboxMsg)); +void mailbox_unregister (int channel); +void mailbox_enable_receive (int channel); +void mailbox_disable_receive (int channel); +void mailbox_write(CurieMailboxMsg& msg); + +#endif diff --git a/cores/arduino/stdlib_noniso.cpp b/cores/arduino/stdlib_noniso.cpp index 14318e85..5215a041 100644 --- a/cores/arduino/stdlib_noniso.cpp +++ b/cores/arduino/stdlib_noniso.cpp @@ -199,6 +199,16 @@ char *dtostrf(double number, signed char width, unsigned char prec, char *s) return s; } + // rounding up to the precision + rounding = 0.5; + for (i = 0; i < prec; ++i) + rounding /= 10.0; + + if (number < 0.0) + number -= rounding; + else + number += rounding; + out = s; before = digitsBe4Decimal(number); @@ -215,12 +225,6 @@ char *dtostrf(double number, signed char width, unsigned char prec, char *s) number = -number; } - // rounding up to the precision - rounding = 0.5; - for (i = 0; i < prec; ++i) - rounding /= 10.0; - number += rounding; - // seperate integral and fractional parts integer = (unsigned long long) number; fraction = (double) (number - integer); @@ -235,17 +239,17 @@ char *dtostrf(double number, signed char width, unsigned char prec, char *s) out[i - 1] = ASCII_ZERO + integer; out += before; - if (!prec) goto end; - - // generate chars for each digit of the fractional part - *out++ = '.'; - for (i = 0; i < prec; ++i) { - fraction *= 10.0; - digit = ((unsigned long long) fraction) % 10; - *out++ = (char) (ASCII_ZERO + digit); + + if (prec) { + // generate chars for each digit of the fractional part + *out++ = '.'; + for (i = 0; i < prec; ++i) { + fraction *= 10.0; + digit = ((unsigned long long) fraction) % 10; + *out++ = (char) (ASCII_ZERO + digit); + } } -end: // check if padding is required if (width > 0) { delta = width - (before + prec + 1); diff --git a/drivers/amd64/WdfCoInstaller01009.dll b/drivers/amd64/WdfCoInstaller01009.dll new file mode 100644 index 00000000..1731b962 Binary files /dev/null and b/drivers/amd64/WdfCoInstaller01009.dll differ diff --git a/drivers/amd64/winusbcoinstaller2.dll b/drivers/amd64/winusbcoinstaller2.dll new file mode 100644 index 00000000..30e55025 Binary files /dev/null and b/drivers/amd64/winusbcoinstaller2.dll differ diff --git a/drivers/dpinst-amd64.exe b/drivers/dpinst-amd64.exe new file mode 100644 index 00000000..0507e738 Binary files /dev/null and b/drivers/dpinst-amd64.exe differ diff --git a/drivers/dpinst-x86.exe b/drivers/dpinst-x86.exe new file mode 100644 index 00000000..41a890d1 Binary files /dev/null and b/drivers/dpinst-x86.exe differ diff --git a/drivers/intc_composite.cat b/drivers/intc_composite.cat new file mode 100644 index 00000000..7c55789c Binary files /dev/null and b/drivers/intc_composite.cat differ diff --git a/drivers/intc_composite.inf b/drivers/intc_composite.inf new file mode 100644 index 00000000..2dc466b2 --- /dev/null +++ b/drivers/intc_composite.inf @@ -0,0 +1,46 @@ +;********************************************************************************************* +; Windows USB Composite Setup File for Arduino 101 +; +; Copyright (c) 2015 Intel Corporation +; +; For use only on Windows operating systems. +;********************************************************************************************* +[Version] +Signature = "$WINDOWS NT$" +Class = USB +ClassGUID = {4D36E978-E325-11CE-BFC1-08002BE10318} +Provider = %ProviderName% +DriverVer = 10/13/2015,1.1.0.0 +CatalogFile = intc_composite.cat + +[Manufacturer] +%ProviderName% = Generic,NTx86,NTamd64 + +[Generic.NTx86] +; Arduino 101 +%USBCompositeDevice% = Composite.Device,USB\VID_8087&PID_0AB6 ; ACM+ACM + +[Generic.NTamd64] +; Arduino 101 +%USBCompositeDevice% = Composite.Device,USB\VID_8087&PID_0AB6 ; ACM+ACM + +[ControlFlags] +ExcludeFromSelect=* + +; Common Class Generic Parent for root ID +[Composite.Device] +Include=usb.inf +Needs=Composite.Dev.NT + +[Composite.Device.Services] +Include=usb.inf +Needs=Composite.Dev.NT.Services + +[SourceDisksNames] +1=%SourceDisk%,,1 + +[Strings] +ProviderName = "Intel Corporation" +ServiceDisplayName = "Arduino 101 USB Composite Device Driver" +USBCompositeDevice = "Arduino 101 USB Composite Device" +SourceDisk = "Arduino 101 USB Composite Device Install Disk" diff --git a/drivers/intc_libusb.cat b/drivers/intc_libusb.cat new file mode 100644 index 00000000..ea90e2ca Binary files /dev/null and b/drivers/intc_libusb.cat differ diff --git a/drivers/intc_libusb.inf b/drivers/intc_libusb.inf new file mode 100644 index 00000000..cfc698d0 --- /dev/null +++ b/drivers/intc_libusb.inf @@ -0,0 +1,174 @@ +; ======== libusb 1.0 (WinUSB) device driver ========== +; +; To customize this inf file for your own device +; +; 1. Change "DeviceName" with the name you want your device to appear with +; on your system. +; +; 2. Change "VendorID" and "ProductID" according to those of your device. +; If your device is plugged in, you can retrieve these values through the +; Device Manager (regardless of whether the driver is installed or not). +; +; 3. Change "DeviceGUID" to a value that is unique on your system. For more +; information and tools to help you generate your own GUIDs, see +; http://en.wikipedia.org/wiki/Universally_Unique_Identifier. +; +; 4. Change "DeviceClassGUID" to reflect your USB Device Class. +; The following Device Classes are listed for reference: +; {745a17a0-74d3-11d0-b6fe-00a0c90f57da} : HID device +; {78a1c341-4539-11d3-b88d-00c04fad5171} : Generic WinUSB device +; +; 5. (Optional) Change the "Date" string. +; +; Note 1: if you need to create a matching cat file for this inf, you can use +; the inf2cat utility from the WinDDK, with the the following command: +; inf2cat /driver:"path_to_your inf" /os:7_X86,7_X64,Vista_X86,Vista_X64 +; +; Note 2: The co-installers provided in these files are version 1.9. +; Please refer to: +; http://blogs.msdn.com/iliast/archive/2008/03/10/why-do-we-need-wdf-coinstallers.aspx and +; http://blogs.msdn.com/iliast/archive/2009/08/13/wdf-logo-requirements-regarding-coinstallers.aspx +; for more information about co-installers and their versioning + +; ===================== Strings ======================= + +[Strings] + +; ===================================================== +; ========= START USER CONFIGURABLE SECTION =========== +; ===================================================== + +DeviceName = "Arduino 101 DFU Interface" +VendorID = "VID_8087" +ProductID = "PID_0ABA" +DeviceGUID = "{d35924d6-3e16-4a9e-9782-5524a4b79bac}" +DeviceClassGUID = "{78a1c341-4539-11d3-b88d-00c04fad5171}" +; Date MUST be in MM/DD/YYYY format +Date = "10/13/2015" + +; ===================================================== +; ========== END USER CONFIGURABLE SECTION ============ +; ===================================================== + +ProviderName = "libusb 1.0" +WinUSB_SvcDesc = "WinUSB Driver Service" +DiskName = "libusb (WinUSB) Device Install Disk" +ClassName = "libusb (WinUSB) devices" + +; ====================== Version ====================== + +[Version] +DriverVer = %Date% +Signature = "$Windows NT$" +Class = %ClassName% +ClassGuid = %DeviceClassGUID% +Provider = %ProviderName% +CatalogFile = intc_libusb.cat + +; =================== Class section =================== + +; Since the device is not a standard USB device, we define a new class for it. +[ClassInstall32] +Addreg = WinUSBDeviceClassReg + +[WinUSBDeviceClassReg] +HKR,,,0,%ClassName% +; -20 is for the USB icon +HKR,,Icon,,-20 + +; =========== Manufacturer/Models sections ============ + +[Manufacturer] +%ProviderName% = libusbDevice_WinUSB,NTx86,NTamd64 + +[libusbDevice_WinUSB.NTx86] +%DeviceName% = USB_Install, USB\%VendorID%&%ProductID% + +[libusbDevice_WinUSB.NTamd64] +%DeviceName% = USB_Install, USB\%VendorID%&%ProductID% + +; ==================== Installation =================== + +; The Include and Needs directives in the USB_Install section are required for +; installing WinUSB on Windows Vista systems. Windows XP systems ignore these +; directives. These directives should not be modified. +[USB_Install] +Include=winusb.inf +Needs=WINUSB.NT + +; The Include directive in the USB_Install.Services section includes the system- +; supplied INF for WinUSB. This INF is installed by the WinUSB co-installer if +; it is not already on the target system. The AddService directive specifies +; WinUsb.sys as the device�s function driver. These directives should not be +; modified. +[USB_Install.Services] +Include=winusb.inf +AddService=WinUSB,0x00000002,WinUSB_ServiceInstall + +; The WinUSB_ServiceInstall section contains the data for installing WinUsb.sys +; as a service. This section should not be modified. +[WinUSB_ServiceInstall] +DisplayName = %WinUSB_SvcDesc% +ServiceType = 1 +StartType = 3 +ErrorControl = 1 +ServiceBinary = %12%\WinUSB.sys + +; The KmdfService directive installs WinUsb.sys as a kernel-mode service. The +; referenced WinUSB_Install section specifies the KMDF library version. +; Usually, the version can be derived from the WdfCoInstallerxxyyy.dll with +; xx = major, yyy = minor +[USB_Install.Wdf] +KmdfService=WINUSB, WinUsb_Install + +[WinUSB_Install] +KmdfLibraryVersion=1.9 + +; USB_Install.HW is the key section in the INF. It specifies the device +; interface globally unique identifier (GUID) for your device. The AddReg +; directive puts the interface GUID in a standard registry value. When +; WinUsb.sys is loaded as the device�s function driver, it reads the registry +; value and uses the specified GUID to represent the device interface. You +; should replace the GUID in this example with one that you create specifically +; for your device. If the protocols for the device change, you should create a +; new device interface GUID. +[USB_Install.HW] +AddReg=Dev_AddReg + +[Dev_AddReg] +HKR,,DeviceInterfaceGUIDs,0x10000,%DeviceGUID% + +; The USB_Install.CoInstallers section, including the referenced AddReg and +; CopyFiles sections, contains data and instructions to install the WinUSB and +; KMDF co installers and associate them with the device. Most USB devices can +; use these sections and directives without modification. +[USB_Install.CoInstallers] +AddReg=CoInstallers_AddReg +CopyFiles=CoInstallers_CopyFiles + +[CoInstallers_AddReg] +HKR,,CoInstallers32,0x00010000,"WdfCoInstaller01009.dll,WdfCoInstaller","WinUSBCoInstaller2.dll" + +[CoInstallers_CopyFiles] +WinUSBCoInstaller2.dll +WdfCoInstaller01009.dll + +[DestinationDirs] +CoInstallers_CopyFiles=11 + +; =============== Source Media Section ================ + +; The x86 and x64 versions of Windows have separate co installers. This example +; stores them on the installation disk in folders that are named x86 and amd64 +[SourceDisksNames] +1 = %DiskName%,,,\x86 +2 = %DiskName%,,,\amd64 + +[SourceDisksFiles.x86] +WinUSBCoInstaller2.dll=1 +WdfCoInstaller01009.dll=1 + +[SourceDisksFiles.amd64] +WinUSBCoInstaller2.dll=2 +WdfCoInstaller01009.dll=2 + diff --git a/drivers/intc_serial.cat b/drivers/intc_serial.cat new file mode 100644 index 00000000..ab02985d Binary files /dev/null and b/drivers/intc_serial.cat differ diff --git a/drivers/intc_serial.inf b/drivers/intc_serial.inf new file mode 100644 index 00000000..e3e7439a --- /dev/null +++ b/drivers/intc_serial.inf @@ -0,0 +1,73 @@ +;************************************************************ +; Windows USB CDC ACM Setup File +; Copyright (c) 2000 Microsoft Corporation + + +[Version] +Signature="$Windows NT$" +Class=Ports +ClassGuid={4D36E978-E325-11CE-BFC1-08002BE10318} +Provider=%MFGNAME% +DriverVer=10/13/2015,5.1.2600.0 +CatalogFile = intc_serial.cat + +[Manufacturer] +%MFGNAME%=DeviceList, NTamd64 + +[DestinationDirs] +DefaultDestDir=12 + + +;------------------------------------------------------------------------------ +; Vendor and Product ID Definitions +;------------------------------------------------------------------------------ +; When developing your USB device, the VID and PID used in the PC side +; application program and the firmware on the microcontroller must match. +; Modify the below line to use your VID and PID. Use the format as shown below. +; Note: One INF file can be used for multiple devices with different VID and PIDs. +; For each supported device, append ",USB\VID_xxxx&PID_yyyy" to the end of the line. +;------------------------------------------------------------------------------ + +[DeviceList] +%DESCRIPTION%=DriverInstall, USB\VID_8087&PID_0AB6 + +[DeviceList.NTamd64] +%DESCRIPTION%=DriverInstall, USB\VID_8087&PID_0AB6 + + + +;------------------------------------------------------------------------------ +; String Definitions +;------------------------------------------------------------------------------ +;Modify these strings to customize your device +;------------------------------------------------------------------------------ +[Strings] +MFGFILENAME="CDC_vista" +DRIVERFILENAME ="usbser" +MFGNAME="http://www.intel.com/" +INSTDISK="Arduino 101 Driver Installer" +DESCRIPTION="Arduino 101 Serial Monitor" +SERVICE="USB RS-232 Emulation Driver" + + +[DriverInstall] +include=mdmcpq.inf,usb.inf +CopyFiles = FakeModemCopyFileSection +AddReg=DriverAddReg + +[DriverAddReg] +HKR,,DevLoader,,*ntkern +HKR,,NTMPDriver,,usbser.sys +HKR,,EnumPropPages32,,"MsPorts.dll,SerialPortPropPageProvider" + +[DriverInstall.Services] +include=mdmcpq.inf +AddService=usbser, 0x00000002, DriverService + +[DriverService] +DisplayName=%ServiceName% +ServiceType=1 +StartType=3 +ErrorControl=1 +ServiceBinary=%12%\usbser.sys +LoadOrderGroup=Base diff --git a/drivers/x86/WdfCoInstaller01009.dll b/drivers/x86/WdfCoInstaller01009.dll new file mode 100644 index 00000000..30e81af6 Binary files /dev/null and b/drivers/x86/WdfCoInstaller01009.dll differ diff --git a/drivers/x86/winusbcoinstaller2.dll b/drivers/x86/winusbcoinstaller2.dll new file mode 100644 index 00000000..fc450d2b Binary files /dev/null and b/drivers/x86/winusbcoinstaller2.dll differ diff --git a/libraries/CurieBLE/examples/central/led_control/led_control.ino b/libraries/CurieBLE/examples/Central/LedControl/LedControl.ino similarity index 77% rename from libraries/CurieBLE/examples/central/led_control/led_control.ino rename to libraries/CurieBLE/examples/Central/LedControl/LedControl.ino index 8983a2ef..2c1706a1 100644 --- a/libraries/CurieBLE/examples/central/led_control/led_control.ino +++ b/libraries/CurieBLE/examples/Central/LedControl/LedControl.ino @@ -1,22 +1,24 @@ /* - Arduino BLE Central LED Control example - Copyright (c) 2016 Arduino LLC. All right reserved. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ + * Copyright (c) 2016 Intel Corporation. All rights reserved. + * See the bottom of this file for the license terms. + */ +/* + * Sketch: LedControl.ino + * + * Description: + * This is a Central sketch that looks for a particular Sevice with a + * certain Characteristic from a Peripheral. Upon succesful discovery, + * it reads the state of a button and write that value to the + * Peripheral Characteristic. + * + * Notes: + * + * - Expected Peripheral Service: 19b10000-e8f2-537e-4f6c-d104768a1214 + * - Expected Peripheral Characteristic: 19b10001-e8f2-537e-4f6c-d104768a1214 + * - Expected Peripheral sketch: + * + */ #include @@ -37,7 +39,7 @@ void setup() { Serial.println("BLE Central - LED control"); // start scanning for peripherals - BLE.scan(); + BLE.scanForUuid("19b10000-e8f2-537e-4f6c-d104768a1214"); } void loop() { @@ -54,16 +56,13 @@ void loop() { Serial.print(peripheral.advertisedServiceUuid()); Serial.println(); - // see if peripheral is advertising the LED service - if (peripheral.advertisedServiceUuid() == "19b10000-e8f2-537e-4f6c-d104768a1214") { - // stop scanning - BLE.stopScan(); + // stop scanning + BLE.stopScan(); - controlLed(peripheral); + controlLed(peripheral); - // peripheral disconnected, start scanning again - BLE.scan(); - } + // peripheral disconnected, start scanning again + BLE.scanForUuid("19b10000-e8f2-537e-4f6c-d104768a1214"); } } @@ -124,4 +123,28 @@ void controlLed(BLEDevice peripheral) { } } } + + Serial.println("Peripheral disconnected"); } + +/* + Arduino BLE Central LED Control example + Copyright (c) 2016 Arduino LLC. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + + + diff --git a/libraries/CurieBLE/examples/central/peripheral_explorer/peripheral_explorer.ino b/libraries/CurieBLE/examples/Central/PeripheralExplorer/PeripheralExplorer.ino similarity index 80% rename from libraries/CurieBLE/examples/central/peripheral_explorer/peripheral_explorer.ino rename to libraries/CurieBLE/examples/Central/PeripheralExplorer/PeripheralExplorer.ino index 5014b7ee..b89492b1 100644 --- a/libraries/CurieBLE/examples/central/peripheral_explorer/peripheral_explorer.ino +++ b/libraries/CurieBLE/examples/Central/PeripheralExplorer/PeripheralExplorer.ino @@ -1,21 +1,21 @@ /* - Arduino BLE Central peripheral explorer example - Copyright (c) 2016 Arduino LLC. All right reserved. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. + * Copyright (c) 2016 Intel Corporation. All rights reserved. + * See the bottom of this file for the license terms. + */ - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ +/* + * Sketch:PeripheralExplorer.ino + * + * Description: + * This is a Central sketch demonstrating the discovery process + * of a Peripheral. The discovered Attributes are being + * display onto the serial output. + * + * Notes: + * + * - Expected Peripheral name: LED + * + */ #include @@ -125,7 +125,7 @@ void exploreCharacteristic(BLECharacteristic characteristic) { if (characteristic.canRead()) { // read the characteristic value characteristic.read(); - delay(1000); + if (characteristic.valueLength() > 0) { // print out the value of the characteristic @@ -133,9 +133,29 @@ void exploreCharacteristic(BLECharacteristic characteristic) { printData(characteristic.value(), characteristic.valueLength()); } } - Serial.println(); + // loop the descriptors of the characteristic and explore each + for (int i = 0; i < characteristic.descriptorCount(); i++) { + BLEDescriptor descriptor = characteristic.descriptor(i); + + exploreDescriptor(descriptor); + } +} + +void exploreDescriptor(BLEDescriptor descriptor) { + // print the UUID of the descriptor + Serial.print("\t\tDescriptor "); + Serial.print(descriptor.uuid()); + + // read the descriptor value + descriptor.read(); + + // print out the value of the descriptor + Serial.print(", value 0x"); + printData(descriptor.value(), descriptor.valueLength()); + + Serial.println(); } void printData(const unsigned char data[], int length) { @@ -150,3 +170,24 @@ void printData(const unsigned char data[], int length) { } } + +/* + Arduino BLE Central peripheral explorer example + Copyright (c) 2016 Arduino LLC. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + + diff --git a/libraries/CurieBLE/examples/central/scan/scan.ino b/libraries/CurieBLE/examples/Central/Scan/Scan.ino similarity index 84% rename from libraries/CurieBLE/examples/central/scan/scan.ino rename to libraries/CurieBLE/examples/Central/Scan/Scan.ino index 32c77c97..6af4b49f 100644 --- a/libraries/CurieBLE/examples/central/scan/scan.ino +++ b/libraries/CurieBLE/examples/Central/Scan/Scan.ino @@ -1,21 +1,19 @@ /* - Arduino BLE Central scan example - Copyright (c) 2016 Arduino LLC. All right reserved. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. + * Copyright (c) 2016 Intel Corporation. All rights reserved. + * See the bottom of this file for the license terms. + */ - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ +/* + * Sketch: Scan.ino + * + * Description: + * This is a Central sketch that performs scanning of Peripherals + * only. It does not perform connection. The Advertized info + * of a Peripheral are display. + * + * Notes: + * + */ #include @@ -68,3 +66,23 @@ void loop() { } } + +/* + Arduino BLE Central scan example + Copyright (c) 2016 Arduino LLC. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + diff --git a/libraries/CurieBLE/examples/central/scan_callback/scan_callback.ino b/libraries/CurieBLE/examples/Central/ScanCallback/ScanCallback.ino similarity index 67% rename from libraries/CurieBLE/examples/central/scan_callback/scan_callback.ino rename to libraries/CurieBLE/examples/Central/ScanCallback/ScanCallback.ino index ddb8b14c..4c47decd 100644 --- a/libraries/CurieBLE/examples/central/scan_callback/scan_callback.ino +++ b/libraries/CurieBLE/examples/Central/ScanCallback/ScanCallback.ino @@ -1,21 +1,30 @@ /* - Arduino BLE Central scan callback example - Copyright (c) 2016 Arduino LLC. All right reserved. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. + * Copyright (c) 2016 Intel Corporation. All rights reserved. + * See the bottom of this file for the license terms. + */ - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ +/* + * Sketch: ScanCallback.ino + * + * Description: + * This is a Central Sketch that scan for Peripherals without + * performing connection. It displays the Adv info for each + * Peripheral scanned. Notice that this sketch makes use of + * the Event Handler, a call back routine, to display the + * info onto the serial output. + * + * Notes: + * + * - It is highly recommended not to use the Event Handler to + * dump information to the serial monitor. Please note + * that Event Handler executes in interrupt context and it + * is expected to perform short execution task. It is due + * to the fact that the entire system timing is impact by the + * execution time of the Event Handler. Accessing the serial + * monitor is relatively time consuming, it is highly desirable + * to perform that in the background. + * + */ #include @@ -70,3 +79,25 @@ void bleCentralDiscoverHandler(BLEDevice peripheral) { Serial.println(); } + + + +/* + Arduino BLE Central scan callback example + Copyright (c) 2016 Arduino LLC. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + diff --git a/libraries/CurieBLE/examples/central/sensortag_button/sensortag_button.ino b/libraries/CurieBLE/examples/Central/SensortagButton/SensortagButton.ino similarity index 59% rename from libraries/CurieBLE/examples/central/sensortag_button/sensortag_button.ino rename to libraries/CurieBLE/examples/Central/SensortagButton/SensortagButton.ino index 7f3f1aa2..75de9267 100644 --- a/libraries/CurieBLE/examples/central/sensortag_button/sensortag_button.ino +++ b/libraries/CurieBLE/examples/Central/SensortagButton/SensortagButton.ino @@ -1,42 +1,20 @@ /* - Arduino BLE Central SensorTag button example - Copyright (c) 2016 Arduino LLC. All right reserved. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. + * Copyright (c) 2016 Intel Corporation. All rights reserved. + * See the bottom of this file for the license terms. + */ - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ +/* + * Sketch: SensortagButton.ino + * + * Description: + * This Central sketch scan for a Peripheral called the SensorTag. + * It looks for particular Service, discovers all its attributes, + * and them on the serial monitor. + * + */ #include -const int NUM_OF_SERVICE = 10; - -char *serviceUUIDArray[NUM_OF_SERVICE] = - - // These are the various services that are included in the CC2650 Sensor Tag - // If you uncomment them you can see the various services -{ //"f000aa00-0451-4000-b000-000000000000", - // "f000aa20-0451-4000-b000-000000000000", - // "f000aa40-0451-4000-b000-000000000000", - // "f000aa70-0451-4000-b000-000000000000", - // "f000aa80-0451-4000-b000-000000000000", - // "f000aa64-0451-4000-b000-000000000000", - // "f000ac00-0451-4000-b000-000000000000", - // "f000ccc0-0451-4000-b000-000000000000", - // "f000ffc0-0451-4000-b000-000000000000", - "0000ffe0-0000-1000-8000-00805f9b34fb" -}; - void setup() { Serial.begin(9600); while (!Serial); @@ -65,26 +43,12 @@ void loop() { Serial.print(peripheral.advertisedServiceUuid()); Serial.println(); - /*see if peripheral is a SensorTag - The localName SensorTag is in the Scan Response data packet - In this release we do not have the feature that gets the scan response data and hence - the local name in the scan is blank - We have to explicitly find the BLE mac address - Please use another deviice like nrfConnect app to discover the Bluetooth Address - */ - //if (peripheral.localName() == "SensorTag") { - - - /****************************************************** - * ATTENTION: - * Change to the mac address according to your device! - * Use a central app that can display the BT MAC address - * ****************************************************** - */ - - if (peripheral.address() == "24:71:89:07:27:80") - - { + /* see if peripheral is a SensorTag + * The localName, CC2650 SensorTag, is in the Scan Response Data packet. + * If this is not the expected name, please change the following + * if-statement accordingly. + */ + if (peripheral.localName() == "CC2650 SensorTag") { // stop scanning BLE.stopScan(); @@ -98,9 +62,6 @@ void loop() { void monitorSensorTagButtons(BLEDevice peripheral) { - static bool getAllServices = true; - static int serviceIndx = 0; - // connect to the peripheral Serial.println("Connecting ..."); if (peripheral.connect()) { @@ -110,34 +71,18 @@ void monitorSensorTagButtons(BLEDevice peripheral) return; } - if (getAllServices) { - // discover peripheral attributes - Serial.println("Discovering attributes ..."); - if (peripheral.discoverAttributes()) { - Serial.println("Attributes discovered"); - } else { - getAllServices = false; - Serial.println("Attribute discovery failed."); - peripheral.disconnect(); - return; - } + // discover peripheral attributes + Serial.println("Discovering attributes of service 0xffe0 ..."); + if (peripheral.discoverAttributesByService("ffe0")) { + Serial.println("Attributes discovered"); } else { - int tmp = serviceIndx; - Serial.print("Discovering Service: "); - Serial.println(serviceUUIDArray[tmp]); - if (++serviceIndx >= NUM_OF_SERVICE) - serviceIndx = 0; - if (peripheral.discoverAttributesByService(serviceUUIDArray[tmp]) == false) { - Serial.println("Can't find the Service."); - peripheral.disconnect(); - return; - } else { - Serial.println("Service discovered."); - } + Serial.println("Attribute discovery failed."); + peripheral.disconnect(); + return; } // retrieve the simple key characteristic - BLECharacteristic simpleKeyCharacteristic = peripheral.characteristic("0000ffe1-0000-1000-8000-00805f9b34fb"); + BLECharacteristic simpleKeyCharacteristic = peripheral.characteristic("ffe1"); // subscribe to the simple key characteristic Serial.println("Subscribing to simple key characteristic ..."); @@ -178,4 +123,28 @@ void monitorSensorTagButtons(BLEDevice peripheral) } } + Serial.println("SensorTag disconnected!"); } + + + +/* + Arduino BLE Central SensorTag button example + Copyright (c) 2016 Arduino LLC. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + + diff --git a/libraries/CurieBLE/examples/peripheral/BatteryMonitor_Notification/BatteryMonitor_Notification.ino b/libraries/CurieBLE/examples/Peripheral/BatteryMonitor/BatteryMonitor.ino similarity index 61% rename from libraries/CurieBLE/examples/peripheral/BatteryMonitor_Notification/BatteryMonitor_Notification.ino rename to libraries/CurieBLE/examples/Peripheral/BatteryMonitor/BatteryMonitor.ino index 2325f351..8535a697 100644 --- a/libraries/CurieBLE/examples/peripheral/BatteryMonitor_Notification/BatteryMonitor_Notification.ino +++ b/libraries/CurieBLE/examples/Peripheral/BatteryMonitor/BatteryMonitor.ino @@ -3,51 +3,55 @@ See the bottom of this file for the license terms. */ -#include - /* - This sketch can work with BatteryMonitor_Central. - - You can also use an android or IOS app that supports notifications. - This sketch example partially implements the standard Bluetooth Low-Energy Battery service - and connection interval paramater update. - For more information: https://developer.bluetooth.org/gatt/services/Pages/ServicesHome.aspx -*/ - + * Sketch: BatteryMonitor.ino + * + * Description: + * This sketch example partially implements the standard Bluetooth + * Low-Energy Battery service and connection interval paramater update. + * + * For more information: + * https://developer.bluetooth.org/gatt/services/Pages/ServicesHome.aspx + * + */ +#include BLEService batteryService("180F"); // BLE Battery Service // BLE Battery Level Characteristic" -BLEUnsignedCharCharacteristic batteryLevelChar("2A19", BLERead | BLENotify); // standard 16-bit characteristic UUID defined in the URL above - // remote clients will be able to get notifications if this characteristic changes +BLEUnsignedCharCharacteristic batteryLevelChar("2A19", // standard 16-bit characteristic UUID + BLERead | BLENotify); // remote clients will be able to +// get notifications if this characteristic changes int oldBatteryLevel = 0; // last battery level reading from analog input long previousMillis = 0; // last time the battery level was checked, in ms void setup() { - BLE.begin(); Serial.begin(9600); // initialize serial communication pinMode(13, OUTPUT); // initialize the LED on pin 13 to indicate when a central is connected + // begin initialization + BLE.begin(); + /* Set a local name for the BLE device This name will appear in advertising packets and can be used by remote devices to identify this BLE device The name can be changed but maybe be truncated based on space left in advertisement packet - If you want to make this work with the BatteryMonitor_Central sketch, do not modufy the name. */ - BLE.setLocalName("BatteryMonitorSketch"); - BLE.setAdvertisedServiceUuid(batteryService.uuid()); // add the service UUID - BLE.addService(batteryService); // Add the BLE Battery service + BLE.setLocalName("BatteryMonitor"); + BLE.setAdvertisedService(batteryService); // add the service UUID batteryService.addCharacteristic(batteryLevelChar); // add the battery level characteristic + BLE.addService(batteryService); // Add the BLE Battery service batteryLevelChar.setValue(oldBatteryLevel); // initial value for this characteristic - /* Now activate the BLE device. It will start continuously transmitting BLE + /* Start advertising BLE. It will start continuously transmitting BLE advertising packets and will be visible to remote BLE central devices - until it receives a new connection - */ + until it receives a new connection */ + // start advertising BLE.advertise(); + Serial.println("Bluetooth device active, waiting for connections..."); } @@ -71,14 +75,6 @@ void loop() { if (currentMillis - previousMillis >= 200) { previousMillis = currentMillis; updateBatteryLevel(); - - static unsigned short count = 0; - count++; - // update the connection interval - if (count % 5 == 0) { - delay(1000); - updateIntervalParams(central); - } } } // when the central disconnects, turn off the LED: @@ -98,36 +94,11 @@ void updateBatteryLevel() { if (batteryLevel != oldBatteryLevel) { // if the battery level has changed Serial.print("Battery Level % is now: "); // print it Serial.println(batteryLevel); - batteryLevelChar.writeUnsignedChar(batteryLevel); // and update the battery level characteristic + batteryLevelChar.setValue(batteryLevel); // and update the battery level characteristic oldBatteryLevel = batteryLevel; // save the level for next comparison } } -void updateIntervalParams(BLEDevice central) { - // read and update the connection interval that peer central device - static unsigned short interval = 0x60; - ble_conn_param_t m_conn_param; - // Get connection interval that peer central device wanted - //central.getConnParams(m_conn_param); - Serial.print("min interval = " ); - Serial.println(m_conn_param.interval_min ); - Serial.print("max interval = " ); - Serial.println(m_conn_param.interval_max ); - Serial.print("latency = " ); - Serial.println(m_conn_param.latency ); - Serial.print("timeout = " ); - Serial.println(m_conn_param.timeout ); - - //Update connection interval - Serial.println("set Connection Interval"); - central.setConnectionInterval(interval, interval); - - interval++; - if (interval < 0x06) - interval = 0x06; - if (interval > 0x100) - interval = 0x06; -} /* Copyright (c) 2016 Intel Corporation. All rights reserved. diff --git a/libraries/CurieBLE/examples/Peripheral/ButtonLED/ButtonLED.ino b/libraries/CurieBLE/examples/Peripheral/ButtonLED/ButtonLED.ino new file mode 100644 index 00000000..fb91c18e --- /dev/null +++ b/libraries/CurieBLE/examples/Peripheral/ButtonLED/ButtonLED.ino @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2016 Intel Corporation. All rights reserved. + * See the bottom of this file for the license terms. + */ + +#include + +const int ledPin = 13; // set ledPin to on-board LED +const int buttonPin = 4; // set buttonPin to digital pin 4 + +BLEService ledService("19B10010-E8F2-537E-4F6C-D104768A1214"); // create service + + +// create switch characteristic and allow remote device to read and write +BLECharCharacteristic ledCharacteristic("19B10011-E8F2-537E-4F6C-D104768A1214", BLERead | BLEWrite); +// create button characteristic and allow remote device to get notifications +BLECharCharacteristic buttonCharacteristic("19B10012-E8F2-537E-4F6C-D104768A1214", BLERead | BLENotify); // allows remote device to get notifications + +void setup() { + Serial.begin(9600); + pinMode(ledPin, OUTPUT); // use the LED on pin 13 as an output + pinMode(buttonPin, INPUT); // use button pin 4 as an input + + // begin initialization + BLE.begin(); + + // set the local name peripheral advertises + BLE.setLocalName("BtnLED"); + // set the UUID for the service this peripheral advertises: + BLE.setAdvertisedService(ledService); + + // add the characteristics to the service + ledService.addCharacteristic(ledCharacteristic); + ledService.addCharacteristic(buttonCharacteristic); + + // add the service + BLE.addService(ledService); + + ledCharacteristic.setValue(0); + buttonCharacteristic.setValue(0); + + // start advertising + BLE.advertise(); + + Serial.println("Bluetooth device active, waiting for connections..."); +} + +void loop() { + // poll for BLE events + BLE.poll(); + + // read the current button pin state + char buttonValue = digitalRead(buttonPin); + + // has the value changed since the last read + bool buttonChanged = (buttonCharacteristic.value() != buttonValue); + + if (buttonChanged) { + // button state changed, update characteristics + ledCharacteristic.setValue(buttonValue); + buttonCharacteristic.setValue(buttonValue); + } + + if (ledCharacteristic.written() || buttonChanged) { + // update LED, either central has written to characteristic or button state has changed + if (ledCharacteristic.value()) { + Serial.println("LED on"); + digitalWrite(ledPin, HIGH); + } else { + Serial.println("LED off"); + digitalWrite(ledPin, LOW); + } + } +} + +/* + Copyright (c) 2016 Intel Corporation. All rights reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110- + 1301 USA +*/ + \ No newline at end of file diff --git a/libraries/CurieBLE/examples/test/CallbackLED/CallbackLED.ino b/libraries/CurieBLE/examples/Peripheral/CallbackLED/CallbackLED.ino similarity index 76% rename from libraries/CurieBLE/examples/test/CallbackLED/CallbackLED.ino rename to libraries/CurieBLE/examples/Peripheral/CallbackLED/CallbackLED.ino index 7cbcd21b..c0d02e3e 100644 --- a/libraries/CurieBLE/examples/test/CallbackLED/CallbackLED.ino +++ b/libraries/CurieBLE/examples/Peripheral/CallbackLED/CallbackLED.ino @@ -3,10 +3,9 @@ * See the bottom of this file for the license terms. */ -#include "CurieBLE.h" +#include const int ledPin = 13; // set ledPin to use on-board LED -BLEPeripheral blePeripheral; // create peripheral instance BLEService ledService("19B10000-E8F2-537E-4F6C-D104768A1214"); // create service @@ -17,41 +16,47 @@ void setup() { Serial.begin(9600); pinMode(ledPin, OUTPUT); // use the LED on pin 13 as an output + // begin initialization + BLE.begin(); + // set the local name peripheral advertises - blePeripheral.setLocalName("LEDCB"); + BLE.setLocalName("LEDCB"); // set the UUID for the service this peripheral advertises - blePeripheral.setAdvertisedServiceUuid(ledService.uuid()); + BLE.setAdvertisedService(ledService); + + // add the characteristic to the service + ledService.addCharacteristic(switchChar); - // add service and characteristic - blePeripheral.addAttribute(ledService); - blePeripheral.addAttribute(switchChar); + // add service + BLE.addService(ledService); // assign event handlers for connected, disconnected to peripheral - blePeripheral.setEventHandler(BLEConnected, blePeripheralConnectHandler); - blePeripheral.setEventHandler(BLEDisconnected, blePeripheralDisconnectHandler); + BLE.setEventHandler(BLEConnected, blePeripheralConnectHandler); + BLE.setEventHandler(BLEDisconnected, blePeripheralDisconnectHandler); // assign event handlers for characteristic switchChar.setEventHandler(BLEWritten, switchCharacteristicWritten); -// set an initial value for the characteristic + // set an initial value for the characteristic switchChar.setValue(0); - // advertise the service - blePeripheral.begin(); + // start advertising + BLE.advertise(); + Serial.println(("Bluetooth device active, waiting for connections...")); } void loop() { - // poll peripheral - blePeripheral.poll(); + // poll for BLE events + BLE.poll(); } -void blePeripheralConnectHandler(BLECentral& central) { +void blePeripheralConnectHandler(BLEDevice central) { // central connected event handler Serial.print("Connected event, central: "); Serial.println(central.address()); } -void blePeripheralDisconnectHandler(BLECentral& central) { +void blePeripheralDisconnectHandler(BLEDevice central) { // central disconnected event handler Serial.print("Disconnected event, central: "); Serial.println(central.address()); @@ -87,4 +92,4 @@ void switchCharacteristicWritten(BLEDevice central, BLECharacteristic characteri License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110- 1301 USA -*/ +*/ diff --git a/libraries/CurieBLE/examples/Peripheral/LED/LED.ino b/libraries/CurieBLE/examples/Peripheral/LED/LED.ino new file mode 100644 index 00000000..258cb455 --- /dev/null +++ b/libraries/CurieBLE/examples/Peripheral/LED/LED.ino @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2016 Intel Corporation. All rights reserved. + * See the bottom of this file for the license terms. + */ + +/* + * Sketch: led.ino + * + * Description: + * This is a Peripheral sketch that works with a connected Central. + * It allows the Central to write a value and set/reset the led + * accordingly. + */ + +#include + +BLEService ledService("19B10000-E8F2-537E-4F6C-D104768A1214"); // BLE LED Service + +// BLE LED Switch Characteristic - custom 128-bit UUID, read and writable by central +BLEUnsignedCharCharacteristic switchCharacteristic("19B10001-E8F2-537E-4F6C-D104768A1214", BLERead | BLEWrite); + +const int ledPin = 13; // pin to use for the LED + +void setup() { + Serial.begin(9600); + + // set LED pin to output mode + pinMode(ledPin, OUTPUT); + + // begin initialization + BLE.begin(); + + // set advertised local name and service UUID: + BLE.setLocalName("LED"); + BLE.setAdvertisedService(ledService); + + // add the characteristic to the service + ledService.addCharacteristic(switchCharacteristic); + + // add service + BLE.addService(ledService); + + // set the initial value for the characeristic: + switchCharacteristic.setValue(0); + + // start advertising + BLE.advertise(); + + Serial.println("BLE LED Peripheral"); +} + +void loop() { + // listen for BLE peripherals to connect: + BLEDevice central = BLE.central(); + + // if a central is connected to peripheral: + if (central) { + Serial.print("Connected to central: "); + // print the central's MAC address: + Serial.println(central.address()); + + // while the central is still connected to peripheral: + while (central.connected()) { + // if the remote device wrote to the characteristic, + // use the value to control the LED: + if (switchCharacteristic.written()) { + if (switchCharacteristic.value()) { // any value other than 0 + Serial.println("LED on"); + digitalWrite(ledPin, HIGH); // will turn the LED on + } else { // a 0 value + Serial.println(F("LED off")); + digitalWrite(ledPin, LOW); // will turn the LED off + } + } + } + + // when the central disconnects, print it out: + Serial.print(F("Disconnected from central: ")); + Serial.println(central.address()); + } +} + +/* + Copyright (c) 2016 Intel Corporation. All rights reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ diff --git a/libraries/CurieBLE/examples/peripheral/MIDIBLE/MIDIBLE.ino b/libraries/CurieBLE/examples/Peripheral/MIDIBLE/MIDIBLE.ino similarity index 100% rename from libraries/CurieBLE/examples/peripheral/MIDIBLE/MIDIBLE.ino rename to libraries/CurieBLE/examples/Peripheral/MIDIBLE/MIDIBLE.ino diff --git a/libraries/CurieBLE/examples/central/BatteryMonitor_Central/BatteryMonitor_Central.ino b/libraries/CurieBLE/examples/central/BatteryMonitor_Central/BatteryMonitor_Central.ino deleted file mode 100644 index 89469631..00000000 --- a/libraries/CurieBLE/examples/central/BatteryMonitor_Central/BatteryMonitor_Central.ino +++ /dev/null @@ -1,125 +0,0 @@ -#include - -/* - This sketch example works with BatteryMonitor_Notification.ino - - BatteryMonitor_Notification will send notification to this central sketch. - This sketch will receive the notifications and output the received data in the serial monitor. - It also illustrates using a non-typed characteristic. - Set the baud rate to 115200 on the serial monitor to accomodate the speed of constant data updates -*/ - -#define LED_PIN 13 - - -void setup() -{ - // This is set to higher baud rate because accelerometer data changes very quickly - Serial.begin(9600); // initialize serial communication - while (!Serial); - pinMode(LED_PIN, OUTPUT); // initialize the LED on pin 13 to indicate when a central is connected - - /* Now activate the BLE device. It will start continuously transmitting BLE - advertising packets and will be visible to remote BLE central devices - until it receives a new connection */ - BLE.begin(); - Serial.print("My Address is: "); - Serial.println(BLE.address()); - - BLE.scanForName("BatteryMonitorSketch"); - Serial.println("Scan Started"); -} - - -void loop() -{ - BLEDevice peripheral = BLE.available(); - - if (peripheral) - { - Serial.print("Found "); - Serial.print(peripheral.address()); - Serial.print(" '"); - Serial.print(peripheral.localName()); - Serial.print("' "); - Serial.print(peripheral.advertisedServiceUuid()); - Serial.println(); - if ( peripheral.localName() == "BatteryMonitorSketch") { - BLE.stopScan(); - processNotification(peripheral); - - delay (1000); - } - - // central connected to peripheral - - //delay (4000); - // BLE.scan();//("BatteryMonitorSketch"); - } -} - -void processNotification(BLEDevice peripheral) { - if (peripheral.connect()) { - Serial.print("Connected: "); - Serial.println(peripheral.address()); - // light pin to indicate connection - digitalWrite(LED_PIN, HIGH); - } else { - Serial.println("Failed to connect!"); - return; - } - - // discover peripheral attributes - Serial.println("Discovering attributes ..."); - if (peripheral.discoverAttributes()) { - Serial.println("Attributes discovered"); - } else { - Serial.println("Attribute discovery failed!"); - peripheral.disconnect(); - digitalWrite(LED_PIN, LOW); - return; - } - BLECharacteristic batteryLevelChar = peripheral.characteristic("2A19"); - if (!batteryLevelChar) { - peripheral.disconnect(); - Serial.println("Peripheral does not have battery level characteristic!"); - digitalWrite(LED_PIN, LOW); - delay(1000); - return; - } - - if (!batteryLevelChar.subscribe()) { - Serial.println("subscription failed!"); - peripheral.disconnect(); - return; - } else { - Serial.println("Subscribed"); - } - - while (peripheral.connected()) - { - if (batteryLevelChar.valueUpdated()) { - - printData(batteryLevelChar.value(), batteryLevelChar.valueLength()); - Serial.println("%"); - - } - - } - Serial.print("Disconnected"); - Serial.println(peripheral.address()); - digitalWrite(LED_PIN, LOW); -} - - -void printData(const unsigned char data[], int length) { - for (int i = 0; i < length; i++) { - unsigned char b = data[i]; - - if (b < 16) { - Serial.print("0"); - } - - Serial.print(b); - } -} diff --git a/libraries/CurieBLE/examples/central/IMUBleCentral/IMUBleCentral.ino b/libraries/CurieBLE/examples/central/IMUBleCentral/IMUBleCentral.ino deleted file mode 100644 index 60748578..00000000 --- a/libraries/CurieBLE/examples/central/IMUBleCentral/IMUBleCentral.ino +++ /dev/null @@ -1,125 +0,0 @@ -/* - Copyright (c) 2016 Arduino LLC. All right reserved. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ -#include - -/* - This sketch example works with IMUBleNotification.ino - - IMUBleNotification.ino will send notification to this central sketch. - This sketch will receive the notifications and output the received data in the serial monitor. - It also illustrates using a non-typed characteristic. - Set the baud rate to 115200 on the serial monitor to accomodate the speed of constant data updates from IMU subsystem. -*/ - -#define LED_PIN 13 -#define MAX_IMU_RECORD 1 - -// define a structure that will serve as buffer for holding IMU data - -typedef struct { - int index; - unsigned int slot[3]; -} imuFrameType; - -imuFrameType imuBuf[MAX_IMU_RECORD]; - -void setup() -{ - // This is set to higher baud rate because accelerometer data changes very quickly - Serial.begin(9600); // initialize serial communication - while (!Serial); - pinMode(LED_PIN, OUTPUT); // initialize the LED on pin 13 to indicate when a central is connected - - /* Now activate the BLE device. It will start continuously transmitting BLE - advertising packets and will be visible to remote BLE central devices - until it receives a new connection */ - BLE.begin(); - Serial.println(BLE.address()); - - BLE.scanForName("Imu"); -} - - -void loop() -{ - BLEDevice peripheral = BLE.available(); - //pr_debug(LOG_MODULE_BLE, "%s-%d",__FUNCTION__, __LINE__); - if (peripheral) - { - Serial.println(peripheral.address()); - BLE.stopScan(); - delay (1000); - // central connected to peripheral - controlImu(peripheral); - delay (4000); - BLE.scanForName("Imu"); - } -} - -void controlImu(BLEDevice peripheral) -{ - static bool discovered = false; - // connect to the peripheral - Serial.print("Connecting ... "); - Serial.println(peripheral.address()); - - if (peripheral.connect()) - { - Serial.print("Connected: "); - Serial.println(peripheral.address()); - } - else - { - Serial.println("Failed to connect!"); - return; - } - - peripheral.discoverAttributes(); - - BLECharacteristic bleImuChar = peripheral.characteristic("F7580003-153E-D4F6-F26D-43D8D98EEB13"); - - if (!bleImuChar) - { - peripheral.disconnect(); - Serial.println("Peripheral does not have IMU characteristic!"); - delay(5000); - return; - } - bleImuChar.subscribe(); - - - discovered = false; - while (peripheral.connected()) - { - if (bleImuChar.valueUpdated()) - { - const unsigned char *cvalue = bleImuChar.value(); - const imuFrameType *value = (const imuFrameType *)cvalue; - Serial.print("\r\nCharacteristic event, written: "); - Serial.print(value->index); - Serial.print("\t"); - Serial.print(value->slot[0]); - Serial.print("\t"); - Serial.print(value->slot[1]); - Serial.print("\t"); - Serial.println(value->slot[2]); - } - } - Serial.print("Disconnected"); - Serial.println(peripheral.address()); -} diff --git a/libraries/CurieBLE/examples/peripheral/IMUBleNotification/IMUBleNotification.ino b/libraries/CurieBLE/examples/peripheral/IMUBleNotification/IMUBleNotification.ino deleted file mode 100644 index c3ac0ff0..00000000 --- a/libraries/CurieBLE/examples/peripheral/IMUBleNotification/IMUBleNotification.ino +++ /dev/null @@ -1,127 +0,0 @@ -/* - Copyright (c) 2016 Arduino LLC. All right reserved. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ -#include -#include - -/* - This sketch example works with IMUBleCentral.ino. - - This sketch will read IMU data from sensor and send notifications to IMUBleCentral.ino. - IMUBleCentral.ino will receive the notifications and output the received data. -*/ - -#define MAX_IMU_RECORD 1 - -typedef struct { - int index; - unsigned int slot[3]; -} imuFrameType; - -// Buffer to hold IMU data -imuFrameType imuBuf[MAX_IMU_RECORD]; - -unsigned seqNum = 0; - -BLEService bleImuService("F7580001-153E-D4F6-F26D-43D8D98EEB13"); // Tx IMU data Characteristic -BLECharacteristic bleImuChar("F7580003-153E-D4F6-F26D-43D8D98EEB13", // standard 128-bit characteristic UUID - BLERead | BLENotify, sizeof(imuBuf)); // remote clients will be able to - // get notifications if this characteristic changes -void setup() -{ - Serial.begin(9600); // initialize serial communication - while (!Serial); - pinMode(13, OUTPUT); // initialize the LED on pin 13 to indicate when a central is connected - - - BLE.begin(); - CurieIMU.begin(); - /* Set a local name for the BLE device - This name will appear in advertising packets - and can be used by remote devices to identify this BLE device - The name can be changed but maybe be truncated based on space left in advertisement packet */ - BLE.setLocalName("Imu"); - BLE.setAdvertisedServiceUuid(bleImuService.uuid()); // add the service UUID - - BLE.addService(bleImuService); // Add the Imu service - bleImuService.addCharacteristic(bleImuChar); // add the Imu characteristic - - /* Now activate the BLE device. It will start continuously transmitting BLE - advertising packets and will be visible to remote BLE central devices - until it receives a new connection */ - // Start the IMU - BLE.advertise(); -} - -void loop() -{ - // listen for BLE peripherals to connect: - // Since we are a peripheral we need a central object to connect to - BLEDevice central = BLE.central(); - - // if a central is connected to peripheral: - if (central) - { - Serial.print("Connected to central: "); - // print the central's MAC address: - Serial.println(central.address()); - - Serial.print("IMU buffer size: "); - Serial.println(sizeof(imuBuf)); - - // turn on the LED to indicate the connection: - digitalWrite(13, HIGH); - - long currentMillis, sentTime; - - // Send IMU data as long as the central is still connected - currentMillis = sentTime = millis(); - while (central.connected()) - { - // Take IMU data every 100 msec - if ((millis() - sentTime) >= 1000) - { - recordImuData(0); - sentTime = millis(); - bleImuChar.setValue((unsigned char *)&(imuBuf[0]), sizeof(imuBuf)); - } - } // end of while loop - - // when the central disconnects, turn off the LED: - digitalWrite(13, LOW); - Serial.print("Disconnected from central: "); - Serial.println(central.address()); - } -} - -// This function records the IMU data that we send to the central -void recordImuData(int index) -{ - /* Read IMU data. - */ - int ax, ay, az; - int gx, gy, gz; - - imuBuf[index].index = seqNum++; - CurieIMU.readMotionSensor(ax, ay, az, gx, gy, gz); - - // Encode the data into the buffer - imuBuf[index].slot[0] = (unsigned int)((ax << 16) | (ay & 0x0FFFF)); - imuBuf[index].slot[1] = (unsigned int)((az << 16) | (gx & 0x0FFFF)); - imuBuf[index].slot[2] = (unsigned int)((gy << 16) | (gz & 0x0FFFF)); -} - diff --git a/libraries/CurieBLE/examples/peripheral/led/led.ino b/libraries/CurieBLE/examples/peripheral/led/led.ino deleted file mode 100644 index 55948fd1..00000000 --- a/libraries/CurieBLE/examples/peripheral/led/led.ino +++ /dev/null @@ -1,84 +0,0 @@ -/* - Arduino BLE Peripheral LED example - Copyright (c) 2016 Arduino LLC. All right reserved. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#include - -// LED pin -#define LED_PIN 13 - -// create service -BLEService ledService("19b10000e8f2537e4f6cd104768a1214"); - -// create switch characteristic -BLECharCharacteristic switchCharacteristic("19b10001e8f2537e4f6cd104768a1214", BLERead | BLEWrite); - -BLEDescriptor switchDescriptor("2901", "switch"); - -void setup() { - Serial.begin(9600); - - // set LED pin to output mode - pinMode(LED_PIN, OUTPUT); - - // begin initialization - BLE.begin(); - Serial.println(BLE.address()); - - // set advertised local name and service UUID - BLE.setLocalName("LED"); - BLE.setAdvertisedServiceUuid(ledService.uuid()); - - switchCharacteristic.addDescriptor(switchDescriptor); - ledService.addCharacteristic(switchCharacteristic); - - // add service and characteristic - BLE.addService(ledService); - - BLE.advertise(); - - Serial.println(F("BLE LED Peripheral")); -} - -void loop() { - BLEDevice central = BLE.central(); - - if (central) { - // central connected to peripheral - Serial.print(F("Connected to central: ")); - Serial.println(central.address()); - - while (central.connected()) { - // central still connected to peripheral - if (switchCharacteristic.written()) { - // central wrote new value to characteristic, update LED - if (switchCharacteristic.value()) { - Serial.println(F("LED on")); - digitalWrite(LED_PIN, HIGH); - } else { - Serial.println(F("LED off")); - digitalWrite(LED_PIN, LOW); - } - } - } - - // central disconnected - Serial.print(F("Disconnected from central: ")); - Serial.println(central.address()); - } -} diff --git a/libraries/CurieBLE/examples/peripheral/led_callback/led_callback.ino b/libraries/CurieBLE/examples/peripheral/led_callback/led_callback.ino deleted file mode 100644 index e00bf419..00000000 --- a/libraries/CurieBLE/examples/peripheral/led_callback/led_callback.ino +++ /dev/null @@ -1,90 +0,0 @@ -/* - Arduino BLE Peripheral LED callback example - Copyright (c) 2016 Arduino LLC. All right reserved. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -// Import libraries -#include - -// LED pin -#define LED_PIN 13 - -// create service -BLEService ledService("19b10000e8f2537e4f6cd104768a1214"); - -// create switch characteristic -BLECharCharacteristic switchCharacteristic("19b10001e8f2537e4f6cd104768a1214", BLERead | BLEWrite); - -void setup() { - Serial.begin(9600); - - // set LED pin to output mode - pinMode(LED_PIN, OUTPUT); - - // begin initialization - BLE.begin(); - - // set advertised local name and service UUID - BLE.setLocalName("LED"); - BLE.setAdvertisedServiceUuid(ledService.uuid()); - - ledService.addCharacteristic(switchCharacteristic); - - // add service - BLE.addService(ledService); - - // assign event handlers for connected, disconnected to peripheral - BLE.setEventHandler(BLEConnected, bleDeviceConnectHandler); - BLE.setEventHandler(BLEDisconnected, bleDeviceDisconnectHandler); - - // assign event handlers for characteristic - switchCharacteristic.setEventHandler(BLEWritten, switchCharacteristicWritten); - - BLE.advertise(); - - Serial.println(F("BLE LED Peripheral")); -} - -void loop() { - // poll peripheral - BLE.poll(); -} - -void bleDeviceConnectHandler(BLEDevice central) { - // central connected event handler - Serial.print(F("Connected event, central: ")); - Serial.println(central.address()); -} - -void bleDeviceDisconnectHandler(BLEDevice central) { - // central disconnected event handler - Serial.print(F("Disconnected event, central: ")); - Serial.println(central.address()); -} - -void switchCharacteristicWritten(BLEDevice central, BLECharacteristic characteristic) { - // central wrote new value to characteristic, update LED - Serial.print(F("Characteristic event, writen: ")); - - if (switchCharacteristic.value()) { - Serial.println(F("LED on")); - digitalWrite(LED_PIN, HIGH); - } else { - Serial.println(F("LED off")); - digitalWrite(LED_PIN, LOW); - } -} diff --git a/libraries/CurieBLE/examples/test/CommunitySketches/AccelerometerBLE/AccelerometerBLE.ino b/libraries/CurieBLE/examples/test/CommunitySketches/AccelerometerBLE/AccelerometerBLE.ino deleted file mode 100644 index 0e660cb6..00000000 --- a/libraries/CurieBLE/examples/test/CommunitySketches/AccelerometerBLE/AccelerometerBLE.ino +++ /dev/null @@ -1,94 +0,0 @@ -#include -#include "CurieIMU.h" - - -BLEPeripheral blePeripheral; // BLE Peripheral Device (the board you're programming) -BLEService accelService("19B10010-E8F2-537E-4F6C-D104768A1214"); // BLE LED Service - -// BLE accelerometer Characteristic - custom 128-bit UUID, read by central -BLEFloatCharacteristic accelX("19B10011-E8F2-537E-4F6C-D104768A1214", BLERead | BLENotify); -BLEFloatCharacteristic accelY("19B10012-E8F2-537E-4F6C-D104768A1214", BLERead | BLENotify); -BLEFloatCharacteristic accelZ("19B10013-E8F2-537E-4F6C-D104768A1214", BLERead | BLENotify); - -long lastUpdate = 0; - -void setup() { - Serial.begin(9600); - - // set advertised local name and service UUID: - blePeripheral.setLocalName("tigoeAcc"); - blePeripheral.setAdvertisedServiceUuid(accelService.uuid()); - - // add service and characteristic: - blePeripheral.addAttribute(accelService); - blePeripheral.addAttribute(accelX); - blePeripheral.addAttribute(accelY); - blePeripheral.addAttribute(accelZ); - - CurieIMU.begin(); - - // Set the accelerometer range to 2G - CurieIMU.setAccelerometerRange(2); - // set the initial value for the characeristic: - accelX.setValue(0); - accelY.setValue(0); - accelZ.setValue(0); - - // begin advertising BLE service: - blePeripheral.begin(); - pinMode(13, OUTPUT); - Serial.println("Starting"); -} - -void loop() { - // listen for BLE peripherals to connect: - BLECentral central = blePeripheral.central(); - - // if a central is connected to peripheral: - if (central) { - digitalWrite(13, HIGH); - Serial.print("Connected to central: "); - // print the central's MAC address: - Serial.println(central.address()); - - // while the central is still connected to peripheral: - while (central.connected()) { - long now = millis(); - if (now - lastUpdate > 1000) { - updateAccelerometer(); - lastUpdate = now; - } - } - // when the central disconnects, print it out: - Serial.print("Disconnected from central: "); - Serial.println(central.address()); - digitalWrite(13, LOW); - - } -} - -void updateAccelerometer() { - int axRaw, ayRaw, azRaw; // raw accelerometer values - float ax, ay, az; - - // read raw accelerometer measurements from device - CurieIMU.readAccelerometer(axRaw, ayRaw, azRaw); - - // convert the raw accelerometer data to G's - ax = convertRawAcceleration(axRaw); - ay = convertRawAcceleration(ayRaw); - az = convertRawAcceleration(azRaw); - - accelX.setValue(ax); - accelY.setValue(ay); - accelZ.setValue(az); -} - -float convertRawAcceleration(int aRaw) { - // since we are using 2G range - // -2g maps to a raw value of -32768 - // +2g maps to a raw value of 32767 - - float a = (aRaw * 2.0) / 32768.0; - return a; -} diff --git a/libraries/CurieBLE/examples/test/CommunitySketches/Genuino101CurieBLEHeartRateMonitor/Genuino101CurieBLEHeartRateMonitor.ino b/libraries/CurieBLE/examples/test/CommunitySketches/Genuino101CurieBLEHeartRateMonitor/Genuino101CurieBLEHeartRateMonitor.ino deleted file mode 100644 index b7062f34..00000000 --- a/libraries/CurieBLE/examples/test/CommunitySketches/Genuino101CurieBLEHeartRateMonitor/Genuino101CurieBLEHeartRateMonitor.ino +++ /dev/null @@ -1,100 +0,0 @@ -/* - Copyright (c) 2015 Intel Corporation. All rights reserved. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -/* - This sketch example partially implements the standard Bluetooth Low-Energy Heart Rate service. - For more information: https://developer.bluetooth.org/gatt/services/Pages/ServicesHome.aspx -*/ - -#include - -BLEPeripheral blePeripheral; // BLE Peripheral Device (the board you're programming) -BLEService heartRateService("180D"); // BLE Heart Rate Service - -// BLE Heart Rate Measurement Characteristic" -BLECharacteristic heartRateChar("2A37", // standard 16-bit characteristic UUID - BLERead | BLENotify, 2); // remote clients will be able to get notifications if this characteristic changes - // the characteristic is 2 bytes long as the first field needs to be "Flags" as per BLE specifications - // https://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.heart_rate_measurement.xml - -int oldHeartRate = 0; // last heart rate reading from analog input -long previousMillis = 0; // last time the heart rate was checked, in ms - -void setup() { - Serial.begin(9600); // initialize serial communication - pinMode(13, OUTPUT); // initialize the LED on pin 13 to indicate when a central is connected - - /* Set a local name for the BLE device - This name will appear in advertising packets - and can be used by remote devices to identify this BLE device - The name can be changed but maybe be truncated based on space left in advertisement packet */ - blePeripheral.setLocalName("HeartRateSketch"); - blePeripheral.setAdvertisedServiceUuid(heartRateService.uuid()); // add the service UUID - blePeripheral.addAttribute(heartRateService); // Add the BLE Heart Rate service - blePeripheral.addAttribute(heartRateChar); // add the Heart Rate Measurement characteristic - - /* Now activate the BLE device. It will start continuously transmitting BLE - advertising packets and will be visible to remote BLE central devices - until it receives a new connection */ - blePeripheral.begin(); - Serial.println("Bluetooth device active, waiting for connections..."); -} - -void loop() { - // listen for BLE peripherals to connect: - BLECentral central = blePeripheral.central(); - - // if a central is connected to peripheral: - if (central) { - Serial.print("Connected to central: "); - // print the central's MAC address: - Serial.println(central.address()); - // turn on the LED to indicate the connection: - digitalWrite(13, HIGH); - - // check the heart rate measurement every 200ms - // as long as the central is still connected: - while (central.connected()) { - long currentMillis = millis(); - // if 200ms have passed, check the heart rate measurement: - if (currentMillis - previousMillis >= 200) { - previousMillis = currentMillis; - updateHeartRate(); - } - } - // when the central disconnects, turn off the LED: - digitalWrite(13, LOW); - Serial.print("Disconnected from central: "); - Serial.println(central.address()); - } -} - -void updateHeartRate() { - /* Read the current voltage level on the A0 analog input pin. - This is used here to simulate the heart rate's measurement. - */ - int heartRateMeasurement = analogRead(A0); - int heartRate = map(heartRateMeasurement, 0, 1023, 0, 100); - if (heartRate != oldHeartRate) { // if the heart rate has changed - Serial.print("Heart Rate is now: "); // print it - Serial.println(heartRate); - const unsigned char heartRateCharArray[2] = { 0, (char)heartRate }; - heartRateChar.setValue(heartRateCharArray, 2); // and update the heart rate measurement characteristic - oldHeartRate = heartRate; // save the level for next comparison - } -} diff --git a/libraries/CurieBLE/examples/test/CommunitySketches/StandardFirmataBLE/BLEStream.h b/libraries/CurieBLE/examples/test/CommunitySketches/StandardFirmataBLE/BLEStream.h deleted file mode 100644 index 87256762..00000000 --- a/libraries/CurieBLE/examples/test/CommunitySketches/StandardFirmataBLE/BLEStream.h +++ /dev/null @@ -1,243 +0,0 @@ -/* - BLEStream.h - - Based on BLESerial.cpp by Voita Molda - https://github.com/sandeepmistry/arduino-BLEPeripheral/blob/master/examples/serial/BLESerial.h - - Last updated April 4th, 2016 - */ - -#ifndef _BLE_STREAM_H_ -#define _BLE_STREAM_H_ - -#include -#if defined(_VARIANT_ARDUINO_101_X_) -#include -#define _MAX_ATTR_DATA_LEN_ BLE_MAX_ATTR_DATA_LEN -#else -//#include -#define _MAX_ATTR_DATA_LEN_ BLE_ATTRIBUTE_MAX_VALUE_LENGTH -#endif - -#define BLESTREAM_TXBUFFER_FLUSH_INTERVAL 80 -#define BLESTREAM_MIN_FLUSH_INTERVAL 8 // minimum interval for flushing the TX buffer - -// #define BLE_SERIAL_DEBUG - -class BLEStream : public BLEPeripheral, public Stream -{ - public: - BLEStream(unsigned char req = 0, unsigned char rdy = 0, unsigned char rst = 0); - - void begin(...); - bool poll(); - void end(); - void setFlushInterval(int); - - virtual int available(void); - virtual int peek(void); - virtual int read(void); - virtual void flush(void); - virtual size_t write(uint8_t byte); - using Print::write; - virtual operator bool(); - - private: - bool _connected; - unsigned long _flushed; - int _flushInterval; - static BLEStream* _instance; - - size_t _rxHead; - size_t _rxTail; - size_t _rxCount() const; - unsigned char _rxBuffer[256]; - size_t _txCount; - unsigned char _txBuffer[_MAX_ATTR_DATA_LEN_]; - - BLEService _uartService = BLEService("6E400001-B5A3-F393-E0A9-E50E24DCCA9E"); - BLEDescriptor _uartNameDescriptor = BLEDescriptor("2901", "UART"); - BLECharacteristic _rxCharacteristic = BLECharacteristic("6E400002-B5A3-F393-E0A9-E50E24DCCA9E", BLEWriteWithoutResponse, _MAX_ATTR_DATA_LEN_); - BLEDescriptor _rxNameDescriptor = BLEDescriptor("2901", "RX - Receive Data (Write)"); - BLECharacteristic _txCharacteristic = BLECharacteristic("6E400003-B5A3-F393-E0A9-E50E24DCCA9E", BLENotify, _MAX_ATTR_DATA_LEN_); - BLEDescriptor _txNameDescriptor = BLEDescriptor("2901", "TX - Transfer Data (Notify)"); - - void _received(const unsigned char* data, size_t size); - static void _received(BLECentral& /*central*/, BLECharacteristic& rxCharacteristic); -}; - - -/* - * BLEStream.cpp - * Copied here as a hack to avoid having to install the BLEPeripheral libarary even if it's - * not needed. - */ - -BLEStream* BLEStream::_instance = NULL; - -BLEStream::BLEStream(unsigned char req, unsigned char rdy, unsigned char rst) : -#if defined(_VARIANT_ARDUINO_101_X_) - BLEPeripheral() -#else - BLEPeripheral(req, rdy, rst) -#endif -{ - this->_txCount = 0; - this->_rxHead = this->_rxTail = 0; - this->_flushed = 0; - this->_flushInterval = BLESTREAM_TXBUFFER_FLUSH_INTERVAL; - BLEStream::_instance = this; - - addAttribute(this->_uartService); - addAttribute(this->_uartNameDescriptor); - setAdvertisedServiceUuid(this->_uartService.uuid()); - addAttribute(this->_rxCharacteristic); - addAttribute(this->_rxNameDescriptor); - this->_rxCharacteristic.setEventHandler(BLEWritten, BLEStream::_received); - addAttribute(this->_txCharacteristic); - addAttribute(this->_txNameDescriptor); -} - -void BLEStream::begin(...) -{ - BLEPeripheral::begin(); -#ifdef BLE_SERIAL_DEBUG - Serial.println(F("BLEStream::begin()")); -#endif -} - -bool BLEStream::poll() -{ - // BLEPeripheral::poll is called each time connected() is called - this->_connected = BLEPeripheral::connected(); - if (millis() > this->_flushed + this->_flushInterval) { - flush(); - } - return this->_connected; -} - -void BLEStream::end() -{ - this->_rxCharacteristic.setEventHandler(BLEWritten, (void(*)(BLECentral&, BLECharacteristic&))NULL); - this->_rxHead = this->_rxTail = 0; - flush(); - BLEPeripheral::disconnect(); -} - -int BLEStream::available(void) -{ -// BLEPeripheral::poll only calls delay(1) in CurieBLE so skipping it here to avoid the delay -#ifndef _VARIANT_ARDUINO_101_X_ - // TODO Need to do more testing to determine if all of these calls to BLEPeripheral::poll are - // actually necessary. Seems to run fine without them, but only minimal testing so far. - BLEPeripheral::poll(); -#endif - int retval = (this->_rxHead - this->_rxTail + sizeof(this->_rxBuffer)) % sizeof(this->_rxBuffer); -#ifdef BLE_SERIAL_DEBUG - if (retval > 0) { - Serial.print(F("BLEStream::available() = ")); - Serial.println(retval); - } -#endif - return retval; -} - -int BLEStream::peek(void) -{ -#ifndef _VARIANT_ARDUINO_101_X_ - BLEPeripheral::poll(); -#endif - if (this->_rxTail == this->_rxHead) return -1; - uint8_t byte = this->_rxBuffer[this->_rxTail]; -#ifdef BLE_SERIAL_DEBUG - Serial.print(F("BLEStream::peek() = 0x")); - Serial.println(byte, HEX); -#endif - return byte; -} - -int BLEStream::read(void) -{ -#ifndef _VARIANT_ARDUINO_101_X_ - BLEPeripheral::poll(); -#endif - if (this->_rxTail == this->_rxHead) return -1; - this->_rxTail = (this->_rxTail + 1) % sizeof(this->_rxBuffer); - uint8_t byte = this->_rxBuffer[this->_rxTail]; -#ifdef BLE_SERIAL_DEBUG - Serial.print(F("BLEStream::read() = 0x")); - Serial.println(byte, HEX); -#endif - return byte; -} - -void BLEStream::flush(void) -{ - if (this->_txCount == 0) return; -#ifndef _VARIANT_ARDUINO_101_X_ - // ensure there are available packets before sending - while(!this->_txCharacteristic.canNotify()) { - BLEPeripheral::poll(); - } -#endif - this->_txCharacteristic.setValue(this->_txBuffer, this->_txCount); - this->_flushed = millis(); - this->_txCount = 0; -#ifdef BLE_SERIAL_DEBUG - Serial.println(F("BLEStream::flush()")); -#endif -} - -size_t BLEStream::write(uint8_t byte) -{ -#ifndef _VARIANT_ARDUINO_101_X_ - BLEPeripheral::poll(); -#endif - if (this->_txCharacteristic.subscribed() == false) return 0; - this->_txBuffer[this->_txCount++] = byte; - if (this->_txCount == sizeof(this->_txBuffer)) flush(); -#ifdef BLE_SERIAL_DEBUG - Serial.print(F("BLEStream::write( 0x")); - Serial.print(byte, HEX); - Serial.println(F(") = 1")); -#endif - return 1; -} - -BLEStream::operator bool() -{ - bool retval = this->_connected = BLEPeripheral::connected(); -#ifdef BLE_SERIAL_DEBUG - Serial.print(F("BLEStream::operator bool() = ")); - Serial.println(retval); -#endif - return retval; -} - -void BLEStream::setFlushInterval(int interval) -{ - if (interval > BLESTREAM_MIN_FLUSH_INTERVAL) { - this->_flushInterval = interval; - } -} - -void BLEStream::_received(const unsigned char* data, size_t size) -{ - for (size_t i = 0; i < size; i++) { - this->_rxHead = (this->_rxHead + 1) % sizeof(this->_rxBuffer); - this->_rxBuffer[this->_rxHead] = data[i]; - } -#ifdef BLE_SERIAL_DEBUG - Serial.print(F("BLEStream::received(")); - for (int i = 0; i < size; i++) Serial.print(data[i], HEX); - Serial.println(F(")")); -#endif -} - -void BLEStream::_received(BLECentral& /*central*/, BLECharacteristic& rxCharacteristic) -{ - BLEStream::_instance->_received(rxCharacteristic.value(), rxCharacteristic.valueLength()); -} - - -#endif // _BLE_STREAM_H_ diff --git a/libraries/CurieBLE/examples/test/CommunitySketches/StandardFirmataBLE/StandardFirmataBLE.ino b/libraries/CurieBLE/examples/test/CommunitySketches/StandardFirmataBLE/StandardFirmataBLE.ino deleted file mode 100644 index cf1e3a74..00000000 --- a/libraries/CurieBLE/examples/test/CommunitySketches/StandardFirmataBLE/StandardFirmataBLE.ino +++ /dev/null @@ -1,833 +0,0 @@ -/* - Firmata is a generic protocol for communicating with microcontrollers - from software on a host computer. It is intended to work with - any host computer software package. - To download a host software package, please click on the following link - to open the list of Firmata client libraries in your default browser. - https://github.com/firmata/arduino#firmata-client-libraries - Copyright (C) 2006-2008 Hans-Christoph Steiner. All rights reserved. - Copyright (C) 2010-2011 Paul Stoffregen. All rights reserved. - Copyright (C) 2009 Shigeru Kobayashi. All rights reserved. - Copyright (C) 2009-2016 Jeff Hoefs. All rights reserved. - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - See file LICENSE.txt for further informations on licensing terms. - Last updated October 16th, 2016 -*/ - -#include -#include -#include - -//#define SERIAL_DEBUG -#include "utility/firmataDebug.h" - -/* - * Uncomment the following include to enable interfacing - * with Serial devices via hardware or software serial. - */ -// In order to use software serial, you will need to compile this sketch with -// Arduino IDE v1.6.6 or higher. Hardware serial should work back to Arduino 1.0. -//#include "utility/SerialFirmata.h" - -// follow the instructions in bleConfig.h to configure your BLE hardware -#include "bleConfig.h" - -#define I2C_WRITE 0x00 //B00000000 -#define I2C_READ 0x08 //B00001000 -#define I2C_READ_CONTINUOUSLY 0x10 //B00010000 -#define I2C_STOP_READING 0x18 //B00011000 -#define I2C_READ_WRITE_MODE_MASK 0x18 //B00011000 -#define I2C_10BIT_ADDRESS_MODE_MASK 0x20 //B00100000 -#define I2C_END_TX_MASK 0x40 //B01000000 -#define I2C_STOP_TX 1 -#define I2C_RESTART_TX 0 -#define I2C_MAX_QUERIES 8 -#define I2C_REGISTER_NOT_SPECIFIED -1 - -// the minimum interval for sampling analog input -#define MINIMUM_SAMPLING_INTERVAL 1 - -// min cannot be < 0x0006. Adjust max if necessary -#define FIRMATA_BLE_MIN_INTERVAL 0x0006 // 7.5ms (7.5 / 1.25) -#define FIRMATA_BLE_MAX_INTERVAL 0x0018 // 30ms (30 / 1.25) - -/*============================================================================== - * GLOBAL VARIABLES - *============================================================================*/ - -#ifdef FIRMATA_SERIAL_FEATURE -SerialFirmata serialFeature; -#endif - -/* analog inputs */ -int analogInputsToReport = 0; // bitwise array to store pin reporting - -/* digital input ports */ -byte reportPINs[TOTAL_PORTS]; // 1 = report this port, 0 = silence -byte previousPINs[TOTAL_PORTS]; // previous 8 bits sent - -/* pins configuration */ -byte portConfigInputs[TOTAL_PORTS]; // each bit: 1 = pin in INPUT, 0 = anything else - -/* timer variables */ -unsigned long currentMillis; // store the current value from millis() -unsigned long previousMillis; // for comparison with currentMillis -unsigned int samplingInterval = 19; // how often to run the main loop (in ms) - -/* i2c data */ -struct i2c_device_info { - byte addr; - int reg; - byte bytes; - byte stopTX; -}; - -/* for i2c read continuous more */ -i2c_device_info query[I2C_MAX_QUERIES]; - -byte i2cRxData[64]; -boolean isI2CEnabled = false; -signed char queryIndex = -1; -// default delay time between i2c read request and Wire.requestFrom() -unsigned int i2cReadDelayTime = 0; - -Servo servos[MAX_SERVOS]; -byte servoPinMap[TOTAL_PINS]; -byte detachedServos[MAX_SERVOS]; -byte detachedServoCount = 0; -byte servoCount = 0; - -boolean isResetting = false; - -// Forward declare a few functions to avoid compiler errors with older versions -// of the Arduino IDE. -void setPinModeCallback(byte, int); -void reportAnalogCallback(byte analogPin, int value); -void sysexCallback(byte, byte, byte*); - -/* utility functions */ -void wireWrite(byte data) -{ -#if ARDUINO >= 100 - Wire.write((byte)data); -#else - Wire.send(data); -#endif -} - -byte wireRead(void) -{ -#if ARDUINO >= 100 - return Wire.read(); -#else - return Wire.receive(); -#endif -} - -/*============================================================================== - * FUNCTIONS - *============================================================================*/ - -void attachServo(byte pin, int minPulse, int maxPulse) -{ - if (servoCount < MAX_SERVOS) { - // reuse indexes of detached servos until all have been reallocated - if (detachedServoCount > 0) { - servoPinMap[pin] = detachedServos[detachedServoCount - 1]; - if (detachedServoCount > 0) detachedServoCount--; - } else { - servoPinMap[pin] = servoCount; - servoCount++; - } - if (minPulse > 0 && maxPulse > 0) { - servos[servoPinMap[pin]].attach(PIN_TO_DIGITAL(pin), minPulse, maxPulse); - } else { - servos[servoPinMap[pin]].attach(PIN_TO_DIGITAL(pin)); - } - } else { - Firmata.sendString("Max servos attached"); - } -} - -void detachServo(byte pin) -{ - servos[servoPinMap[pin]].detach(); - // if we're detaching the last servo, decrement the count - // otherwise store the index of the detached servo - if (servoPinMap[pin] == servoCount && servoCount > 0) { - servoCount--; - } else if (servoCount > 0) { - // keep track of detached servos because we want to reuse their indexes - // before incrementing the count of attached servos - detachedServoCount++; - detachedServos[detachedServoCount - 1] = servoPinMap[pin]; - } - - servoPinMap[pin] = 255; -} - -void enableI2CPins() -{ - byte i; - // is there a faster way to do this? would probaby require importing - // Arduino.h to get SCL and SDA pins - for (i = 0; i < TOTAL_PINS; i++) { - if (IS_PIN_I2C(i)) { - // mark pins as i2c so they are ignore in non i2c data requests - setPinModeCallback(i, PIN_MODE_I2C); - } - } - - isI2CEnabled = true; - - Wire.begin(); -} - -/* disable the i2c pins so they can be used for other functions */ -void disableI2CPins() { - isI2CEnabled = false; - // disable read continuous mode for all devices - queryIndex = -1; -} - -void readAndReportData(byte address, int theRegister, byte numBytes, byte stopTX) { - // allow I2C requests that don't require a register read - // for example, some devices using an interrupt pin to signify new data available - // do not always require the register read so upon interrupt you call Wire.requestFrom() - if (theRegister != I2C_REGISTER_NOT_SPECIFIED) { - Wire.beginTransmission(address); - wireWrite((byte)theRegister); - Wire.endTransmission(stopTX); // default = true - // do not set a value of 0 - if (i2cReadDelayTime > 0) { - // delay is necessary for some devices such as WiiNunchuck - delayMicroseconds(i2cReadDelayTime); - } - } else { - theRegister = 0; // fill the register with a dummy value - } - - Wire.requestFrom(address, numBytes); // all bytes are returned in requestFrom - - // check to be sure correct number of bytes were returned by slave - if (numBytes < Wire.available()) { - Firmata.sendString("I2C: Too many bytes received"); - } else if (numBytes > Wire.available()) { - Firmata.sendString("I2C: Too few bytes received"); - } - - i2cRxData[0] = address; - i2cRxData[1] = theRegister; - - for (int i = 0; i < numBytes && Wire.available(); i++) { - i2cRxData[2 + i] = wireRead(); - } - - // send slave address, register and received bytes - Firmata.sendSysex(SYSEX_I2C_REPLY, numBytes + 2, i2cRxData); -} - -void outputPort(byte portNumber, byte portValue, byte forceSend) -{ - // pins not configured as INPUT are cleared to zeros - portValue = portValue & portConfigInputs[portNumber]; - // only send if the value is different than previously sent - if (forceSend || previousPINs[portNumber] != portValue) { - Firmata.sendDigitalPort(portNumber, portValue); - previousPINs[portNumber] = portValue; - } -} - -/* ----------------------------------------------------------------------------- - * check all the active digital inputs for change of state, then add any events - * to the Serial output queue using Serial.print() */ -void checkDigitalInputs(void) -{ - /* Using non-looping code allows constants to be given to readPort(). - * The compiler will apply substantial optimizations if the inputs - * to readPort() are compile-time constants. */ - if (TOTAL_PORTS > 0 && reportPINs[0]) outputPort(0, readPort(0, portConfigInputs[0]), false); - if (TOTAL_PORTS > 1 && reportPINs[1]) outputPort(1, readPort(1, portConfigInputs[1]), false); - if (TOTAL_PORTS > 2 && reportPINs[2]) outputPort(2, readPort(2, portConfigInputs[2]), false); - if (TOTAL_PORTS > 3 && reportPINs[3]) outputPort(3, readPort(3, portConfigInputs[3]), false); - if (TOTAL_PORTS > 4 && reportPINs[4]) outputPort(4, readPort(4, portConfigInputs[4]), false); - if (TOTAL_PORTS > 5 && reportPINs[5]) outputPort(5, readPort(5, portConfigInputs[5]), false); - if (TOTAL_PORTS > 6 && reportPINs[6]) outputPort(6, readPort(6, portConfigInputs[6]), false); - if (TOTAL_PORTS > 7 && reportPINs[7]) outputPort(7, readPort(7, portConfigInputs[7]), false); - if (TOTAL_PORTS > 8 && reportPINs[8]) outputPort(8, readPort(8, portConfigInputs[8]), false); - if (TOTAL_PORTS > 9 && reportPINs[9]) outputPort(9, readPort(9, portConfigInputs[9]), false); - if (TOTAL_PORTS > 10 && reportPINs[10]) outputPort(10, readPort(10, portConfigInputs[10]), false); - if (TOTAL_PORTS > 11 && reportPINs[11]) outputPort(11, readPort(11, portConfigInputs[11]), false); - if (TOTAL_PORTS > 12 && reportPINs[12]) outputPort(12, readPort(12, portConfigInputs[12]), false); - if (TOTAL_PORTS > 13 && reportPINs[13]) outputPort(13, readPort(13, portConfigInputs[13]), false); - if (TOTAL_PORTS > 14 && reportPINs[14]) outputPort(14, readPort(14, portConfigInputs[14]), false); - if (TOTAL_PORTS > 15 && reportPINs[15]) outputPort(15, readPort(15, portConfigInputs[15]), false); -} - -// ----------------------------------------------------------------------------- -/* sets the pin mode to the correct state and sets the relevant bits in the - * two bit-arrays that track Digital I/O and PWM status - */ -void setPinModeCallback(byte pin, int mode) -{ - if (Firmata.getPinMode(pin) == PIN_MODE_IGNORE) - return; - - if (Firmata.getPinMode(pin) == PIN_MODE_I2C && isI2CEnabled && mode != PIN_MODE_I2C) { - // disable i2c so pins can be used for other functions - // the following if statements should reconfigure the pins properly - disableI2CPins(); - } - if (IS_PIN_DIGITAL(pin) && mode != PIN_MODE_SERVO) { - if (servoPinMap[pin] < MAX_SERVOS && servos[servoPinMap[pin]].attached()) { - detachServo(pin); - } - } - if (IS_PIN_ANALOG(pin)) { - reportAnalogCallback(PIN_TO_ANALOG(pin), mode == PIN_MODE_ANALOG ? 1 : 0); // turn on/off reporting - } - if (IS_PIN_DIGITAL(pin)) { - if (mode == INPUT || mode == PIN_MODE_PULLUP) { - portConfigInputs[pin / 8] |= (1 << (pin & 7)); - } else { - portConfigInputs[pin / 8] &= ~(1 << (pin & 7)); - } - } - Firmata.setPinState(pin, 0); - switch (mode) { - case PIN_MODE_ANALOG: - if (IS_PIN_ANALOG(pin)) { - if (IS_PIN_DIGITAL(pin)) { - pinMode(PIN_TO_DIGITAL(pin), INPUT); // disable output driver -#if ARDUINO <= 100 - // deprecated since Arduino 1.0.1 - TODO: drop support in Firmata 2.6 - digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable internal pull-ups -#endif - } - Firmata.setPinMode(pin, PIN_MODE_ANALOG); - } - break; - case INPUT: - if (IS_PIN_DIGITAL(pin)) { - pinMode(PIN_TO_DIGITAL(pin), INPUT); // disable output driver -#if ARDUINO <= 100 - // deprecated since Arduino 1.0.1 - TODO: drop support in Firmata 2.6 - digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable internal pull-ups -#endif - Firmata.setPinMode(pin, INPUT); - } - break; - case PIN_MODE_PULLUP: - if (IS_PIN_DIGITAL(pin)) { - pinMode(PIN_TO_DIGITAL(pin), INPUT_PULLUP); - Firmata.setPinMode(pin, PIN_MODE_PULLUP); - Firmata.setPinState(pin, 1); - } - break; - case OUTPUT: - if (IS_PIN_DIGITAL(pin)) { - if (Firmata.getPinMode(pin) == PIN_MODE_PWM) { - // Disable PWM if pin mode was previously set to PWM. - digitalWrite(PIN_TO_DIGITAL(pin), LOW); - } - pinMode(PIN_TO_DIGITAL(pin), OUTPUT); - Firmata.setPinMode(pin, OUTPUT); - } - break; - case PIN_MODE_PWM: - if (IS_PIN_PWM(pin)) { - pinMode(PIN_TO_PWM(pin), OUTPUT); - analogWrite(PIN_TO_PWM(pin), 0); - Firmata.setPinMode(pin, PIN_MODE_PWM); - } - break; - case PIN_MODE_SERVO: - if (IS_PIN_DIGITAL(pin)) { - Firmata.setPinMode(pin, PIN_MODE_SERVO); - if (servoPinMap[pin] == 255 || !servos[servoPinMap[pin]].attached()) { - // pass -1 for min and max pulse values to use default values set - // by Servo library - attachServo(pin, -1, -1); - } - } - break; - case PIN_MODE_I2C: - if (IS_PIN_I2C(pin)) { - // mark the pin as i2c - // the user must call I2C_CONFIG to enable I2C for a device - Firmata.setPinMode(pin, PIN_MODE_I2C); - } - break; - case PIN_MODE_SERIAL: -#ifdef FIRMATA_SERIAL_FEATURE - serialFeature.handlePinMode(pin, PIN_MODE_SERIAL); -#endif - break; - default: - Firmata.sendString("Unknown pin mode"); // TODO: put error msgs in EEPROM - } - // TODO: save status to EEPROM here, if changed -} - -/* - * Sets the value of an individual pin. Useful if you want to set a pin value but - * are not tracking the digital port state. - * Can only be used on pins configured as OUTPUT. - * Cannot be used to enable pull-ups on Digital INPUT pins. - */ -void setPinValueCallback(byte pin, int value) -{ - if (pin < TOTAL_PINS && IS_PIN_DIGITAL(pin)) { - if (Firmata.getPinMode(pin) == OUTPUT) { - Firmata.setPinState(pin, value); - digitalWrite(PIN_TO_DIGITAL(pin), value); - } - } -} - -void analogWriteCallback(byte pin, int value) -{ - if (pin < TOTAL_PINS) { - switch (Firmata.getPinMode(pin)) { - case PIN_MODE_SERVO: - if (IS_PIN_DIGITAL(pin)) - servos[servoPinMap[pin]].write(value); - Firmata.setPinState(pin, value); - break; - case PIN_MODE_PWM: - if (IS_PIN_PWM(pin)) - analogWrite(PIN_TO_PWM(pin), value); - Firmata.setPinState(pin, value); - break; - } - } -} - -void digitalWriteCallback(byte port, int value) -{ - byte pin, lastPin, pinValue, mask = 1, pinWriteMask = 0; - - if (port < TOTAL_PORTS) { - // create a mask of the pins on this port that are writable. - lastPin = port * 8 + 8; - if (lastPin > TOTAL_PINS) lastPin = TOTAL_PINS; - for (pin = port * 8; pin < lastPin; pin++) { - // do not disturb non-digital pins (eg, Rx & Tx) - if (IS_PIN_DIGITAL(pin)) { - // do not touch pins in PWM, ANALOG, SERVO or other modes - if (Firmata.getPinMode(pin) == OUTPUT || Firmata.getPinMode(pin) == INPUT) { - pinValue = ((byte)value & mask) ? 1 : 0; - if (Firmata.getPinMode(pin) == OUTPUT) { - pinWriteMask |= mask; - } else if (Firmata.getPinMode(pin) == INPUT && pinValue == 1 && Firmata.getPinState(pin) != 1) { - // only handle INPUT here for backwards compatibility -#if ARDUINO > 100 - pinMode(pin, INPUT_PULLUP); -#else - // only write to the INPUT pin to enable pullups if Arduino v1.0.0 or earlier - pinWriteMask |= mask; -#endif - } - Firmata.setPinState(pin, pinValue); - } - } - mask = mask << 1; - } - writePort(port, (byte)value, pinWriteMask); - } -} - - -// ----------------------------------------------------------------------------- -/* sets bits in a bit array (int) to toggle the reporting of the analogIns - */ -//void FirmataClass::setAnalogPinReporting(byte pin, byte state) { -//} -void reportAnalogCallback(byte analogPin, int value) -{ - if (analogPin < TOTAL_ANALOG_PINS) { - if (value == 0) { - analogInputsToReport = analogInputsToReport & ~ (1 << analogPin); - } else { - analogInputsToReport = analogInputsToReport | (1 << analogPin); - // prevent during system reset or all analog pin values will be reported - // which may report noise for unconnected analog pins - if (!isResetting) { - // Send pin value immediately. This is helpful when connected via - // ethernet, wi-fi or bluetooth so pin states can be known upon - // reconnecting. - Firmata.sendAnalog(analogPin, analogRead(analogPin)); - } - } - } - // TODO: save status to EEPROM here, if changed -} - -void reportDigitalCallback(byte port, int value) -{ - if (port < TOTAL_PORTS) { - reportPINs[port] = (byte)value; - // Send port value immediately. This is helpful when connected via - // ethernet, wi-fi or bluetooth so pin states can be known upon - // reconnecting. - if (value) outputPort(port, readPort(port, portConfigInputs[port]), true); - } - // do not disable analog reporting on these 8 pins, to allow some - // pins used for digital, others analog. Instead, allow both types - // of reporting to be enabled, but check if the pin is configured - // as analog when sampling the analog inputs. Likewise, while - // scanning digital pins, portConfigInputs will mask off values from any - // pins configured as analog -} - -/*============================================================================== - * SYSEX-BASED commands - *============================================================================*/ - -void sysexCallback(byte command, byte argc, byte *argv) -{ - byte mode; - byte stopTX; - byte slaveAddress; - byte data; - int slaveRegister; - unsigned int delayTime; - - switch (command) { - case I2C_REQUEST: - mode = argv[1] & I2C_READ_WRITE_MODE_MASK; - if (argv[1] & I2C_10BIT_ADDRESS_MODE_MASK) { - Firmata.sendString("10-bit addressing not supported"); - return; - } - else { - slaveAddress = argv[0]; - } - - // need to invert the logic here since 0 will be default for client - // libraries that have not updated to add support for restart tx - if (argv[1] & I2C_END_TX_MASK) { - stopTX = I2C_RESTART_TX; - } - else { - stopTX = I2C_STOP_TX; // default - } - - switch (mode) { - case I2C_WRITE: - Wire.beginTransmission(slaveAddress); - for (byte i = 2; i < argc; i += 2) { - data = argv[i] + (argv[i + 1] << 7); - wireWrite(data); - } - Wire.endTransmission(); - delayMicroseconds(70); - break; - case I2C_READ: - if (argc == 6) { - // a slave register is specified - slaveRegister = argv[2] + (argv[3] << 7); - data = argv[4] + (argv[5] << 7); // bytes to read - } - else { - // a slave register is NOT specified - slaveRegister = I2C_REGISTER_NOT_SPECIFIED; - data = argv[2] + (argv[3] << 7); // bytes to read - } - readAndReportData(slaveAddress, (int)slaveRegister, data, stopTX); - break; - case I2C_READ_CONTINUOUSLY: - if ((queryIndex + 1) >= I2C_MAX_QUERIES) { - // too many queries, just ignore - Firmata.sendString("too many queries"); - break; - } - if (argc == 6) { - // a slave register is specified - slaveRegister = argv[2] + (argv[3] << 7); - data = argv[4] + (argv[5] << 7); // bytes to read - } - else { - // a slave register is NOT specified - slaveRegister = (int)I2C_REGISTER_NOT_SPECIFIED; - data = argv[2] + (argv[3] << 7); // bytes to read - } - queryIndex++; - query[queryIndex].addr = slaveAddress; - query[queryIndex].reg = slaveRegister; - query[queryIndex].bytes = data; - query[queryIndex].stopTX = stopTX; - break; - case I2C_STOP_READING: - byte queryIndexToSkip; - // if read continuous mode is enabled for only 1 i2c device, disable - // read continuous reporting for that device - if (queryIndex <= 0) { - queryIndex = -1; - } else { - queryIndexToSkip = 0; - // if read continuous mode is enabled for multiple devices, - // determine which device to stop reading and remove it's data from - // the array, shifiting other array data to fill the space - for (byte i = 0; i < queryIndex + 1; i++) { - if (query[i].addr == slaveAddress) { - queryIndexToSkip = i; - break; - } - } - - for (byte i = queryIndexToSkip; i < queryIndex + 1; i++) { - if (i < I2C_MAX_QUERIES) { - query[i].addr = query[i + 1].addr; - query[i].reg = query[i + 1].reg; - query[i].bytes = query[i + 1].bytes; - query[i].stopTX = query[i + 1].stopTX; - } - } - queryIndex--; - } - break; - default: - break; - } - break; - case I2C_CONFIG: - delayTime = (argv[0] + (argv[1] << 7)); - - if (delayTime > 0) { - i2cReadDelayTime = delayTime; - } - - if (!isI2CEnabled) { - enableI2CPins(); - } - - break; - case SERVO_CONFIG: - if (argc > 4) { - // these vars are here for clarity, they'll optimized away by the compiler - byte pin = argv[0]; - int minPulse = argv[1] + (argv[2] << 7); - int maxPulse = argv[3] + (argv[4] << 7); - - if (IS_PIN_DIGITAL(pin)) { - if (servoPinMap[pin] < MAX_SERVOS && servos[servoPinMap[pin]].attached()) { - detachServo(pin); - } - attachServo(pin, minPulse, maxPulse); - setPinModeCallback(pin, PIN_MODE_SERVO); - } - } - break; - case SAMPLING_INTERVAL: - if (argc > 1) { - samplingInterval = argv[0] + (argv[1] << 7); - if (samplingInterval < MINIMUM_SAMPLING_INTERVAL) { - samplingInterval = MINIMUM_SAMPLING_INTERVAL; - } - } else { - //Firmata.sendString("Not enough data"); - } - break; - case EXTENDED_ANALOG: - if (argc > 1) { - int val = argv[1]; - if (argc > 2) val |= (argv[2] << 7); - if (argc > 3) val |= (argv[3] << 14); - analogWriteCallback(argv[0], val); - } - break; - case CAPABILITY_QUERY: - Firmata.write(START_SYSEX); - Firmata.write(CAPABILITY_RESPONSE); - for (byte pin = 0; pin < TOTAL_PINS; pin++) { - if (IS_PIN_DIGITAL(pin)) { - Firmata.write((byte)INPUT); - Firmata.write(1); - Firmata.write((byte)PIN_MODE_PULLUP); - Firmata.write(1); - Firmata.write((byte)OUTPUT); - Firmata.write(1); - } - if (IS_PIN_ANALOG(pin)) { - Firmata.write(PIN_MODE_ANALOG); - Firmata.write(10); // 10 = 10-bit resolution - } - if (IS_PIN_PWM(pin)) { - Firmata.write(PIN_MODE_PWM); - Firmata.write(8); // 8 = 8-bit resolution - } - if (IS_PIN_DIGITAL(pin)) { - Firmata.write(PIN_MODE_SERVO); - Firmata.write(14); - } - if (IS_PIN_I2C(pin)) { - Firmata.write(PIN_MODE_I2C); - Firmata.write(1); // TODO: could assign a number to map to SCL or SDA - } -#ifdef FIRMATA_SERIAL_FEATURE - serialFeature.handleCapability(pin); -#endif - Firmata.write(127); - } - Firmata.write(END_SYSEX); - break; - case PIN_STATE_QUERY: - if (argc > 0) { - byte pin = argv[0]; - Firmata.write(START_SYSEX); - Firmata.write(PIN_STATE_RESPONSE); - Firmata.write(pin); - if (pin < TOTAL_PINS) { - Firmata.write(Firmata.getPinMode(pin)); - Firmata.write((byte)Firmata.getPinState(pin) & 0x7F); - if (Firmata.getPinState(pin) & 0xFF80) Firmata.write((byte)(Firmata.getPinState(pin) >> 7) & 0x7F); - if (Firmata.getPinState(pin) & 0xC000) Firmata.write((byte)(Firmata.getPinState(pin) >> 14) & 0x7F); - } - Firmata.write(END_SYSEX); - } - break; - case ANALOG_MAPPING_QUERY: - Firmata.write(START_SYSEX); - Firmata.write(ANALOG_MAPPING_RESPONSE); - for (byte pin = 0; pin < TOTAL_PINS; pin++) { - Firmata.write(IS_PIN_ANALOG(pin) ? PIN_TO_ANALOG(pin) : 127); - } - Firmata.write(END_SYSEX); - break; - - case SERIAL_MESSAGE: -#ifdef FIRMATA_SERIAL_FEATURE - serialFeature.handleSysex(command, argc, argv); -#endif - break; - } -} - -/*============================================================================== - * SETUP() - *============================================================================*/ - -void systemResetCallback() -{ - isResetting = true; - -#ifdef FIRMATA_SERIAL_FEATURE - serialFeature.reset(); -#endif - - if (isI2CEnabled) { - disableI2CPins(); - } - - for (byte i = 0; i < TOTAL_PORTS; i++) { - reportPINs[i] = false; // by default, reporting off - portConfigInputs[i] = 0; // until activated - previousPINs[i] = 0; - } - - for (byte i = 0; i < TOTAL_PINS; i++) { - // pins with analog capability default to analog input - // otherwise, pins default to digital output - if (IS_PIN_ANALOG(i)) { - // turns off pullup, configures everything - setPinModeCallback(i, PIN_MODE_ANALOG); - } else if (IS_PIN_DIGITAL(i)) { - // sets the output to 0, configures portConfigInputs - setPinModeCallback(i, OUTPUT); - } - - servoPinMap[i] = 255; - } - // by default, do not report any analog inputs - analogInputsToReport = 0; - - detachedServoCount = 0; - servoCount = 0; - - isResetting = false; -} - -void setup() -{ - DEBUG_BEGIN(9600); - - Firmata.setFirmwareVersion(FIRMATA_FIRMWARE_MAJOR_VERSION, FIRMATA_FIRMWARE_MINOR_VERSION); - - Firmata.attach(ANALOG_MESSAGE, analogWriteCallback); - Firmata.attach(DIGITAL_MESSAGE, digitalWriteCallback); - Firmata.attach(REPORT_ANALOG, reportAnalogCallback); - Firmata.attach(REPORT_DIGITAL, reportDigitalCallback); - Firmata.attach(SET_PIN_MODE, setPinModeCallback); - Firmata.attach(SET_DIGITAL_PIN_VALUE, setPinValueCallback); - Firmata.attach(START_SYSEX, sysexCallback); - Firmata.attach(SYSTEM_RESET, systemResetCallback); - - stream.setLocalName(FIRMATA_BLE_LOCAL_NAME); - - // set the BLE connection interval - this is the fastest interval you can read inputs - stream.setConnectionInterval(FIRMATA_BLE_MIN_INTERVAL, FIRMATA_BLE_MAX_INTERVAL); - // set how often the BLE TX buffer is flushed (if not full) - stream.setFlushInterval(FIRMATA_BLE_MAX_INTERVAL); - -#ifdef BLE_REQ - for (byte i = 0; i < TOTAL_PINS; i++) { - if (IS_IGNORE_BLE_PINS(i)) { - Firmata.setPinMode(i, PIN_MODE_IGNORE); - } - } -#endif - - stream.begin(); - Firmata.begin(stream); - - systemResetCallback(); // reset to default config -} - -/*============================================================================== - * LOOP() - *============================================================================*/ -void loop() -{ - byte pin, analogPin; - - // do not process data if no BLE connection is established - // poll will send the TX buffer at the specified flush interval or when the buffer is full - if (!stream.poll()) return; - - /* DIGITALREAD - as fast as possible, check for changes and output them to the - * Stream buffer using Stream.write() */ - checkDigitalInputs(); - - /* STREAMREAD - processing incoming messagse as soon as possible, while still - * checking digital inputs. */ - while (Firmata.available()) - Firmata.processInput(); - - currentMillis = millis(); - if (currentMillis - previousMillis > samplingInterval) { - previousMillis = currentMillis; - /* ANALOGREAD - do all analogReads() at the configured sampling interval */ - for (pin = 0; pin < TOTAL_PINS; pin++) { - if (IS_PIN_ANALOG(pin) && Firmata.getPinMode(pin) == PIN_MODE_ANALOG) { - analogPin = PIN_TO_ANALOG(pin); - if (analogInputsToReport & (1 << analogPin)) { - Firmata.sendAnalog(analogPin, analogRead(analogPin)); - } - } - } - // report i2c data for all device with read continuous mode enabled - if (queryIndex > -1) { - for (byte i = 0; i < queryIndex + 1; i++) { - readAndReportData(query[i].addr, query[i].reg, query[i].bytes, query[i].stopTX); - } - } - } - -#ifdef FIRMATA_SERIAL_FEATURE - serialFeature.update(); -#endif -} diff --git a/libraries/CurieBLE/examples/test/CommunitySketches/StandardFirmataBLE/bleConfig.h b/libraries/CurieBLE/examples/test/CommunitySketches/StandardFirmataBLE/bleConfig.h deleted file mode 100644 index aeb96a81..00000000 --- a/libraries/CurieBLE/examples/test/CommunitySketches/StandardFirmataBLE/bleConfig.h +++ /dev/null @@ -1,112 +0,0 @@ -/*================================================================================================== - * BLE CONFIGURATION - * - * If you are using an Arduino 101, you do not need to make any changes to this file (unless you - * need a unique ble local name (see below). If you are using another supported BLE board or shield, - * follow the instructions for the specific board or shield below. - * - * Make sure you have the Intel Curie Boards package v1.0.6 or higher installed via the Arduino - * Boards Manager. - * - * Supported boards and shields: - * - Arduino 101 (recommended) - * - RedBearLab BLE Shield (v2) ** to be verified ** - * - RedBearLab BLE Nano ** works with modifications ** - * - *================================================================================================*/ - -// change this to a unique name per board if running StandardFirmataBLE on multiple boards -// within the same physical space -#define FIRMATA_BLE_LOCAL_NAME "FIRMATA" - -/* - * RedBearLab BLE Shield - * - * If you are using a RedBearLab BLE shield, uncomment the define below. - * Also, change the define for BLE_RST if you have the jumper set to pin 7 rather than pin 4. - * - * You will need to use the shield with an Arduino Zero, Due, Mega, or other board with sufficient - * Flash and RAM. Arduino Uno, Leonardo and other ATmega328p and Atmega32u4 boards to not have - * enough memory to run StandardFirmataBLE. - * - * TODO: verify if this works and with which boards it works. - * - * Test script: https://gist.github.com/soundanalogous/927360b797574ed50e27 - */ -//#define REDBEAR_BLE_SHIELD - -#ifdef REDBEAR_BLE_SHIELD -#include -#include -#include "utility/BLEStream.h" - -#define BLE_REQ 9 -#define BLE_RDY 8 -#define BLE_RST 4 // 4 or 7 via jumper on shield - -BLEStream stream(BLE_REQ, BLE_RDY, BLE_RST); -#endif - - -/*================================================================================================== - * END BLE CONFIGURATION - you should not need to change anything below this line - *================================================================================================*/ - -/* - * Arduino 101 - * - * Make sure you have the Intel Curie Boards package v1.0.6 or higher installed via the Arduino - * Boards Manager. - * - * Test script: https://gist.github.com/soundanalogous/927360b797574ed50e27 - */ -#ifdef _VARIANT_ARDUINO_101_X_ -#include -#include "BLEStream.h" -BLEStream stream; -#endif - - -/* - * RedBearLab BLE Nano (with default switch settings) - * - * Blocked on this issue: https://github.com/RedBearLab/nRF51822-Arduino/issues/46 - * Works with modifications. See comments at top of the test script referenced below. - * When the RBL nRF51822-Arduino library issue is resolved, this should work witout - * any modifications. - * - * Test script: https://gist.github.com/soundanalogous/d39bb3eb36333a0906df - * - * Note: If you have changed the solder jumpers on the Nano you may encounter issues since - * the pins are currently mapped in Firmata only for the default (factory) jumper settings. - */ -// #ifdef BLE_NANO -// #include -// #include "utility/BLEStream.h" -// BLEStream stream; -// #endif - - -/* - * RedBearLab Blend and Blend Micro - * - * StandardFirmataBLE requires too much Flash and RAM to run on the ATmega32u4-based Blend - * and Blend Micro boards. It may work with ConfigurableFirmata selecting only analog and/or - * digital I/O. - */ -// #if defined(BLEND_MICRO) || defined(BLEND) -// #include -// #include -// #include "utility/BLEStream.h" - -// #define BLE_REQ 6 -// #define BLE_RDY 7 -// #define BLE_RST 4 - -// BLEStream stream(BLE_REQ, BLE_RDY, BLE_RST); -// #endif - - -#if defined(BLE_REQ) && defined(BLE_RDY) && defined(BLE_RST) -#define IS_IGNORE_BLE_PINS(p) ((p) == BLE_REQ || (p) == BLE_RDY || (p) == BLE_RST) -#endif diff --git a/libraries/CurieBLE/examples/test/CommunitySketches/StarterKit101_BLE/StarterKit101_BLE.ino b/libraries/CurieBLE/examples/test/CommunitySketches/StarterKit101_BLE/StarterKit101_BLE.ino deleted file mode 100644 index 641af931..00000000 --- a/libraries/CurieBLE/examples/test/CommunitySketches/StarterKit101_BLE/StarterKit101_BLE.ino +++ /dev/null @@ -1,37 +0,0 @@ -#include -// change the next line based on what your smartphone is configured to advertise -const String deviceName = "Nexus 5X"; -const int rssiTrigger = -50; -const int ledPin = 13; - -void setup() { - Serial.begin(9600); - BLE.begin(); - pinMode(ledPin, OUTPUT); - BLE.setEventHandler(BLEDiscovered, bleCentralDiscoverHandler); - while (!Serial) ; - Serial.println("Bluetooth device active, start scanning..."); - BLE.scan(true); -} - -void loop() { - BLE.poll(); -} - -void bleCentralDiscoverHandler(BLEDevice peripheral) { - if (peripheral.hasLocalName()) { - Serial.println(peripheral.localName()); - if (peripheral.localName().indexOf(deviceName) != -1) { - Serial.println(" found"); - Serial.print("Rssi: "); - Serial.println(peripheral.rssi()); - if (peripheral.rssi() > rssiTrigger) { - Serial.println("LED ON"); - digitalWrite(ledPin, HIGH); - } else { - Serial.println("LED OFF"); - digitalWrite(ledPin, LOW); - } - } - } -} diff --git a/libraries/CurieBLE/examples/test/central/central.ino b/libraries/CurieBLE/examples/test/central/central.ino deleted file mode 100644 index 5bc13524..00000000 --- a/libraries/CurieBLE/examples/test/central/central.ino +++ /dev/null @@ -1,86 +0,0 @@ - -#include "CurieBLE.h" - -// LED pin -#define LED_PIN 13 - -void setup() { - Serial.begin(9600); - Serial.println("test---"); - - // set LED pin to output mode - pinMode(LED_PIN, OUTPUT); - - // begin initialization - BLE.begin(); - Serial.println(BLE.address()); - - BLE.scanForName("LED"); -} - -void controlLed(BLEDevice &peripheral) -{ - static bool discovered = false; - // connect to the peripheral - Serial.print("Connecting ... "); - Serial.println(peripheral.address()); - - if (peripheral.connect()) - { - Serial.print("Connected: "); - Serial.println(peripheral.address()); - } - else - { - Serial.println("Failed to connect!"); - return; - } - - peripheral.discoverAttributes(); - - BLECharacteristic ledCharacteristic = peripheral.characteristic("19b10101-e8f2-537e-4f6c-d104768a1214"); - - if (!ledCharacteristic) - { - peripheral.disconnect(); - Serial.println("Peripheral does not have LED characteristic!"); - delay(5000); - return; - } - - - unsigned char ledstate = 0; - - discovered = false; - while (peripheral.connected()) - { - if (ledstate == 1) - { - ledstate = 0; - } - else - { - ledstate = 1; - } - ledCharacteristic.write(&ledstate, sizeof(ledstate)); - delay(5000); - } - Serial.print("Disconnected"); - Serial.println(peripheral.address()); -} - -void loop() { - BLEDevice peripheral = BLE.available(); - if (peripheral) - { - Serial.println(peripheral.address()); - BLE.stopScan(); - delay (1000); - // central connected to peripheral - controlLed(peripheral); - delay (4000); - BLE.scanForName("LED"); - } -} - - diff --git a/libraries/CurieBLE/examples/test/notification/notification.ino b/libraries/CurieBLE/examples/test/notification/notification.ino deleted file mode 100644 index 542102bb..00000000 --- a/libraries/CurieBLE/examples/test/notification/notification.ino +++ /dev/null @@ -1,78 +0,0 @@ - -#include "CurieBLE.h" - -// LED pin -#define LED_PIN 13 - -// create service -BLEService ledService("19b10100e8f2537e4f6cd104768a1214"); - -BLECharacteristic switchCharacteristic("19b10101e8f2537e4f6cd104768a1214", BLERead | BLEWrite | BLENotify, 1); - -BLEDescriptor switchDescriptor("2901", "switch"); - -void setup() { - Serial.begin(9600); - Serial.println("test---"); - - // set LED pin to output mode - pinMode(LED_PIN, OUTPUT); - - // begin initialization - BLE.begin(); - Serial.println(BLE.address()); - - // set advertised local name and service UUID - BLE.setLocalName("LED"); - BLE.setAdvertisedServiceUuid(ledService.uuid()); - - // add service and characteristic - BLE.addService(ledService); - ledService.addCharacteristic(switchCharacteristic); - switchCharacteristic.addDescriptor(switchDescriptor); - unsigned char test = 1; - switchCharacteristic.writeValue(&test,1); - BLE.advertise(); -} - -void loop() { - static int i = 0; - BLEDevice central = BLE.central(); - bool temp = central; -i++; - if (temp) { - // central connected to peripheral - Serial.print(i); - Serial.print(F("Connected to central: ")); - Serial.println(central.address()); - - Serial.print(temp); - - unsigned char ledstate = 0; - - while (central.connected()) { - // central still connected to peripheral - if (switchCharacteristic.canNotify()) - { - - if (ledstate == 1) - { - ledstate = 0; - digitalWrite(LED_PIN, LOW); - } - else - { - ledstate = 1; - digitalWrite(LED_PIN, HIGH); - } - switchCharacteristic.writeValue(&ledstate, sizeof(ledstate)); - delay(5000); - } - } - - // central disconnected - Serial.print(F("Disconnected from central: ")); - Serial.println(central.address()); - } - //delay (1000); -} diff --git a/libraries/CurieBLE/examples/test/notifycentral/notifycentral.ino b/libraries/CurieBLE/examples/test/notifycentral/notifycentral.ino deleted file mode 100644 index 47086b18..00000000 --- a/libraries/CurieBLE/examples/test/notifycentral/notifycentral.ino +++ /dev/null @@ -1,89 +0,0 @@ - -#include "CurieBLE.h" - -// LED pin -#define LED_PIN 13 - -void setup() { - Serial.begin(9600); - Serial.println("test---"); - - // set LED pin to output mode - pinMode(LED_PIN, OUTPUT); - - // begin initialization - BLE.begin(); - Serial.println(BLE.address()); - - BLE.scanForName("LED"); -} - -void controlLed(BLEDevice &peripheral) -{ - static bool discovered = false; - // connect to the peripheral - Serial.print("Connecting ... "); - Serial.println(peripheral.address()); - - if (peripheral.connect()) - { - Serial.print("Connected: "); - Serial.println(peripheral.address()); - } - else - { - Serial.println("Failed to connect!"); - return; - } - - peripheral.discoverAttributes(); - - BLECharacteristic ledCharacteristic = peripheral.characteristic("19b10101-e8f2-537e-4f6c-d104768a1214"); - - if (!ledCharacteristic) - { - peripheral.disconnect(); - Serial.println("Peripheral does not have LED characteristic!"); - delay(5000); - return; - } - ledCharacteristic.subscribe(); - - - discovered = false; - while (peripheral.connected()) - { - if (ledCharacteristic.valueUpdated()) - { - char ledValue = *ledCharacteristic.value(); - - if (ledValue) { - Serial.println(F("LED on")); - digitalWrite(LED_PIN, HIGH); - } else { - Serial.println(F("LED off")); - digitalWrite(LED_PIN, LOW); - } - } - } - Serial.print("Disconnected"); - Serial.println(peripheral.address()); -} - -void loop() { - //pr_debug(LOG_MODULE_BLE, "%s-%d",__FUNCTION__, __LINE__); - BLEDevice peripheral = BLE.available(); - //pr_debug(LOG_MODULE_BLE, "%s-%d",__FUNCTION__, __LINE__); - if (peripheral) - { - Serial.println(peripheral.address()); - BLE.stopScan(); - delay (1000); - // central connected to peripheral - controlLed(peripheral); - delay (4000); - BLE.scanForName("LED"); - } -} - - diff --git a/libraries/CurieBLE/examples/test/test/test.ino b/libraries/CurieBLE/examples/test/test/test.ino deleted file mode 100644 index bd4da60c..00000000 --- a/libraries/CurieBLE/examples/test/test/test.ino +++ /dev/null @@ -1,71 +0,0 @@ - -#include "CurieBLE.h" - -// LED pin -#define LED_PIN 13 - -// create service -BLEService ledService("19b10100e8f2537e4f6cd104768a1214"); - -BLECharacteristic switchCharacteristic("19b10101e8f2537e4f6cd104768a1214", BLERead | BLEWrite | BLENotify, 1); - -BLEDescriptor switchDescriptor("2901", "switch"); - -void setup() { - Serial.begin(9600); - Serial.println("test---"); - - // set LED pin to output mode - pinMode(LED_PIN, OUTPUT); - - // begin initialization - BLE.begin(); - Serial.println(BLE.address()); - - // set advertised local name and service UUID - BLE.setLocalName("LED"); - BLE.setAdvertisedServiceUuid(ledService.uuid()); - - // add service and characteristic - BLE.addService(ledService); - ledService.addCharacteristic(switchCharacteristic); - switchCharacteristic.addDescriptor(switchDescriptor); - unsigned char test = 1; - switchCharacteristic.writeValue(&test,1); - BLE.advertise(); -} - -void loop() { - static int i = 0; - BLEDevice central = BLE.central(); - bool temp = central; -i++; - if (temp) { - // central connected to peripheral - Serial.print(i); - Serial.print(F("Connected to central: ")); - Serial.println(central.address()); - - Serial.print(temp); - - while (central.connected()) { - // central still connected to peripheral - if (switchCharacteristic.written()) { - char ledValue = *switchCharacteristic.value(); - // central wrote new value to characteristic, update LED - if (ledValue) { - Serial.println(F("LED on")); - digitalWrite(LED_PIN, HIGH); - } else { - Serial.println(F("LED off")); - digitalWrite(LED_PIN, LOW); - } - } - } - - // central disconnected - Serial.print(F("Disconnected from central: ")); - Serial.println(central.address()); - } - //delay (1000); -} diff --git a/libraries/CurieBLE/keywords.txt b/libraries/CurieBLE/keywords.txt index 2db97095..91104ee0 100644 --- a/libraries/CurieBLE/keywords.txt +++ b/libraries/CurieBLE/keywords.txt @@ -5,7 +5,7 @@ ####################################### # Datatypes (KEYWORD1) ####################################### - +CurieBLE KEYWORD1 BLEAttributeWithValue KEYWORD1 BLEBoolCharacteristic KEYWORD1 BLEByteCharacteristic KEYWORD1 @@ -104,6 +104,8 @@ setTxPower KEYWORD2 setConnectable KEYWORD2 setDeviceName KEYWORD2 addService KEYWORD2 +addCharacteristic KEYWORD2 +addDescriptor KEYWORD2 advertise KEYWORD2 stopAdvertise KEYWORD2 central KEYWORD2 diff --git a/libraries/CurieBLE/src/BLECharacteristic.cpp b/libraries/CurieBLE/src/BLECharacteristic.cpp index f8432b11..1416cef3 100644 --- a/libraries/CurieBLE/src/BLECharacteristic.cpp +++ b/libraries/CurieBLE/src/BLECharacteristic.cpp @@ -248,6 +248,11 @@ bool BLECharacteristic::setValue(const unsigned char value[], unsigned short len return writeValue(value, (int)length); } +bool BLECharacteristic::setValue(const char* value) +{ + return this->setValue((const unsigned char *)value, strlen(value)); +} + bool BLECharacteristic::writeValue(const byte value[], int length) { return writeValue(value, length, 0); @@ -278,6 +283,10 @@ bool BLECharacteristic::writeValue(const byte value[], int length, int offset) characteristicImp->valueLength()); BLEDeviceManager::instance()->startAdvertising(); } + } else { + // not associated with a service yet + _setValue(value, length); + retVar = true; } return retVar; } @@ -294,8 +303,8 @@ bool BLECharacteristic::broadcast() if (BLEDeviceManager::instance()->advertising()) { BLEDeviceManager::instance()->stopAdvertising(); - BLEDeviceManager::instance()->startAdvertising(); } + BLEDeviceManager::instance()->startAdvertising(); return _broadcast; } @@ -367,14 +376,14 @@ bool BLECharacteristic::canUnsubscribe() return retVar; } -bool BLECharacteristic::read() +bool BLECharacteristic::read(bool blocked) { bool retVar = false; BLECharacteristicImp *characteristicImp = getImplementation(); if (NULL != characteristicImp) { - retVar = characteristicImp->read(); + retVar = characteristicImp->read(blocked); } return retVar; } @@ -439,15 +448,20 @@ int BLECharacteristic::addDescriptor(BLEDescriptor& descriptor) else if (BLEUtils::isLocalBLE(_bledev) == true) { // Only support the GATT server that create the service in local device. - _chrc_local_imp = new BLECharacteristicImp(*this, _bledev); + // Consider to add multi-descriptor if (NULL == _chrc_local_imp) { - retVar = BLE_STATUS_NO_MEMORY; + _chrc_local_imp = new BLECharacteristicImp(*this, _bledev); } - else + + if (NULL != _chrc_local_imp) { retVar = _chrc_local_imp->addDescriptor(descriptor); } + else + { + retVar = BLE_STATUS_NO_MEMORY; + } } return retVar; } diff --git a/libraries/CurieBLE/src/BLECharacteristic.h b/libraries/CurieBLE/src/BLECharacteristic.h index c1887c73..79fbfed3 100644 --- a/libraries/CurieBLE/src/BLECharacteristic.h +++ b/libraries/CurieBLE/src/BLECharacteristic.h @@ -180,6 +180,15 @@ class BLECharacteristic: public BLEAttributeWithValue */ bool setValue(const unsigned char value[], unsigned short length); + /** + * Set the current value of the Characteristic with a String + * + * @param value New string value to set, strings exceeding maxLength will be truncated + * + * @return bool true set value success, false on error + */ + bool setValue(const char* value); + /** * @brief Write the value of the characteristic * @@ -320,8 +329,9 @@ class BLECharacteristic: public BLEAttributeWithValue * @return bool true - Success, false - Failed * * @note Only for GATT client. Schedule read request to the GATT server + * Arduino requests to have read, by default, be blocking. */ - virtual bool read(); + virtual bool read(bool blocked = true); /** * @brief Write the charcteristic value diff --git a/libraries/CurieBLE/src/BLECommon.h b/libraries/CurieBLE/src/BLECommon.h index 76e6b804..37ac49df 100644 --- a/libraries/CurieBLE/src/BLECommon.h +++ b/libraries/CurieBLE/src/BLECommon.h @@ -103,6 +103,7 @@ typedef ble_status_t BleStatus; #define BLE_MAX_CONN_CFG 2 #define BLE_MAX_ADV_BUFFER_CFG 3 +#define BLE_MAX_ADV_FILTER_SIZE_CFG 20 typedef bool (*ble_advertise_handle_cb_t)(uint8_t type, const uint8_t *dataPtr, uint8_t data_len, const bt_addr_le_t *addrPtr); diff --git a/libraries/CurieBLE/src/BLEDescriptor.cpp b/libraries/CurieBLE/src/BLEDescriptor.cpp index 31c4ba7e..eb624532 100644 --- a/libraries/CurieBLE/src/BLEDescriptor.cpp +++ b/libraries/CurieBLE/src/BLEDescriptor.cpp @@ -35,28 +35,19 @@ BLEDescriptor::BLEDescriptor(BLEDescriptorImp* descriptorImp, const BLEDevice *bleDev): _bledev(bleDev), _value_size(0), - _value(NULL) + _value(NULL), + _internal(descriptorImp) { _properties = descriptorImp->properties(); memset(_uuid_cstr, 0, sizeof (_uuid_cstr)); BLEUtils::uuidBT2String(descriptorImp->bt_uuid(), _uuid_cstr); - - _value_size = descriptorImp->valueSize(); - _value = (unsigned char*)malloc(_value_size); - if (NULL == _value) - { - memcpy(_value, descriptorImp->value(), _value_size); - } - else - { - errno = ENOMEM; - } } BLEDescriptor::BLEDescriptor(const char* uuid, const unsigned char value[], unsigned short valueLength): - _bledev() + _bledev(), + _internal(NULL) { bt_uuid_128_t uuid_tmp; memset(_uuid_cstr, 0, sizeof (_uuid_cstr)); @@ -65,15 +56,16 @@ BLEDescriptor::BLEDescriptor(const char* uuid, _bledev.setAddress(*BLEUtils::bleGetLoalAddress()); - _value_size = valueLength > BLE_MAX_ATTR_LONGDATA_LEN ? BLE_MAX_ATTR_LONGDATA_LEN : valueLength; + _value_size = (valueLength > BLE_MAX_ATTR_LONGDATA_LEN) ? BLE_MAX_ATTR_LONGDATA_LEN : valueLength; _value = (unsigned char*)malloc(_value_size); - if (NULL == _value) + if (NULL != _value) { memcpy(_value, value, _value_size); } else { errno = ENOMEM; + _value_size = 0; } } @@ -82,22 +74,27 @@ BLEDescriptor::BLEDescriptor(const char* uuid, BLEDescriptor(uuid, (const unsigned char*)value, strlen(value)) {} -BLEDescriptor::BLEDescriptor(const BLEDescriptor& rhs) +BLEDescriptor::BLEDescriptor(const BLEDescriptor& rhs): + _bledev(&rhs._bledev), + _properties(rhs._properties), + _value_size(0), + _value(NULL), + _internal(rhs._internal) { - _value = (unsigned char*)malloc(rhs._value_size); // Sid. KW: allocate memory for _value, not local - if (_value) - { - memcpy(_value, rhs._value, rhs._value_size); - _value_size = rhs._value_size; - } - else + memcpy(_uuid_cstr, rhs._uuid_cstr, sizeof(_uuid_cstr)); + if (NULL == _internal && rhs._value_size > 0) { - _value_size = 0; - errno = ENOMEM; + _value = (unsigned char*)malloc(rhs._value_size); // Sid. KW: allocate memory for _value, not local + if (_value) + { + memcpy(_value, rhs._value, rhs._value_size); + _value_size = rhs._value_size; + } + else + { + errno = ENOMEM; + } } - memcpy(_uuid_cstr, rhs._uuid_cstr, sizeof(_uuid_cstr)); - _properties = rhs._properties; - _bledev = BLEDevice(&rhs._bledev); } BLEDescriptor& BLEDescriptor::operator= (const BLEDescriptor& rhs) @@ -107,23 +104,27 @@ BLEDescriptor& BLEDescriptor::operator= (const BLEDescriptor& rhs) memcpy(_uuid_cstr, rhs._uuid_cstr, sizeof(_uuid_cstr)); _properties = rhs._properties; _bledev = BLEDevice(&rhs._bledev); - if (_value_size < rhs._value_size) + _internal = rhs._internal; + if (NULL == _internal && rhs._value_size > 0) { - _value_size = rhs._value_size; + if (_value_size < rhs._value_size) + { + _value_size = rhs._value_size; + + if (NULL != _value) + free(_value); + _value = (unsigned char*)malloc(_value_size); + } if (NULL != _value) - free(_value); - _value = (unsigned char*)malloc(_value_size); - } - - if (NULL != _value) - { - memcpy(_value, rhs._value, rhs._value_size); - } - else - { - _value_size = 0; - errno = ENOMEM; + { + memcpy(_value, rhs._value, rhs._value_size); + } + else + { + _value_size = 0; + errno = ENOMEM; + } } } return *this; @@ -145,12 +146,22 @@ const char* BLEDescriptor::uuid() const const byte* BLEDescriptor::value() const { - return _value; + const byte* ret = _value; + if (NULL != _internal) + { + ret = _internal->value(); + } + return ret; } int BLEDescriptor::valueLength() const { - return _value_size; + int ret = _value_size; + if (NULL != _internal) + { + ret = _internal->valueLength(); + } + return ret; } BLEDescriptor::operator bool() const @@ -166,6 +177,22 @@ unsigned char BLEDescriptor::properties() const int BLEDescriptor::valueSize() const { - return _value_size; + int ret = _value_size; + if (NULL != _internal) + { + ret = _internal->valueSize(); + } + return ret; +} + +bool BLEDescriptor::read() +{ + bool retVar = false; + + if (NULL != _internal) + { + retVar = _internal->read(); + } + return retVar; } diff --git a/libraries/CurieBLE/src/BLEDescriptor.h b/libraries/CurieBLE/src/BLEDescriptor.h index e1a79f2a..9e95de7d 100644 --- a/libraries/CurieBLE/src/BLEDescriptor.h +++ b/libraries/CurieBLE/src/BLEDescriptor.h @@ -37,73 +37,92 @@ class BLEDescriptor virtual ~BLEDescriptor(); + /** + * @brief Get the descriptor's UUID string + * + * @param none + * + * @return const char* The UUID string + * + * @note none + */ const char* uuid() const; - virtual const byte* value() const; // returns the value buffer - virtual int valueLength() const; // returns the current length of the value - - virtual operator bool() const; // is the descriptor valid (discovered from peripheral) - - unsigned char properties() const; - int valueSize() const; -private: - char _uuid_cstr[37]; // The characteristic UUID - BLEDevice _bledev; - - unsigned char _properties; // The characteristic property - - unsigned short _value_size; // The value size - unsigned char* _value; // The value. Will delete after create the _internal - - - // The API reserved for feature release - // move here for temp /** - * @brief Write the value of the descriptor + * @brief Get the value of descriptor * - * @param value The value buffer that want to write to descriptor + * @param none * - * @param length The value buffer's length + * @return const byte* The value buffer * - * @return bool true - Success, false - Failed + * @note none + */ + virtual const byte* value() const; + + /** + * @brief Get the current length of the value + * + * @param none + * + * @return int The current length of the value string * * @note none */ - //virtual bool writeValue(const byte value[], int length); + virtual int valueLength() const; /** - * @brief Write the value of the descriptor + * @brief Is the descriptor valid + * + * @param none * - * @param value The value buffer that want to write to descriptor + * @return bool true/false * - * @param length The value buffer's length + * @note none + */ + virtual operator bool() const; + + /** + * @brief Read the descriptor value * - * @param offset The offset in the descriptor's data + * @param none * * @return bool true - Success, false - Failed * + * @note Only for GATT client. Schedule read request to the GATT server + */ + bool read(); + + /** + * @brief Get the property mask of the descriptor + * + * @param none + * + * @return unsigned char The property mask of the descriptor + * * @note none */ - //bool writeValue(const byte value[], int length, int offset); + unsigned char properties() const; /** - * @brief Write the value of the descriptor + * @brief Get the maximum size of the value * - * @param value The value string that want to write to descriptor + * @param none * - * @return bool true - Success, false - Failed + * @return int The maximum size of the value * * @note none */ - //bool writeValue(const char* value); - //virtual byte operator[] (int offset) const; // returns a byte of the value at the specified offset - - // GATT client Write the value of the descriptor - //virtual bool write(const byte value[], int length); - //bool write(const byte value[], int length, int offset); - //bool write(const char* value); - //bool read(); + int valueSize() const; +private: + char _uuid_cstr[37]; // The characteristic UUID + BLEDevice _bledev; + + unsigned char _properties; // The characteristic property + + unsigned short _value_size; // The value size + unsigned char* _value; // The value. Will delete after create the _internal + BLEDescriptorImp *_internal; // The real implementation of Descriptor }; #endif diff --git a/libraries/CurieBLE/src/BLEDevice.cpp b/libraries/CurieBLE/src/BLEDevice.cpp index e59b5462..f4713cf8 100644 --- a/libraries/CurieBLE/src/BLEDevice.cpp +++ b/libraries/CurieBLE/src/BLEDevice.cpp @@ -19,6 +19,8 @@ #include "CurieBLE.h" #include "BLEDevice.h" +#include "./internal/ble_client.h" + #include "./internal/BLEUtils.h" #include "./internal/BLEProfileManager.h" @@ -51,6 +53,7 @@ BLEDevice::BLEDevice(const bt_addr_le_t* bleaddress): BLEDevice() { memcpy(&_bt_addr, bleaddress, sizeof(_bt_addr)); + BLEDeviceManager::instance()->getConnectionInterval(this, &_conn_param); } BLEDevice::BLEDevice(const BLEDevice* bledevice) @@ -82,7 +85,12 @@ void BLEDevice::poll() } void BLEDevice::end() -{} +{ + if (BLEUtils::isLocalBLE(*this)) + { + BLEDeviceManager::instance()->end(); + } +} bool BLEDevice::connected() const { @@ -133,6 +141,17 @@ void BLEDevice::setManufacturerData(const unsigned char manufacturerData[], BLEDeviceManager::instance()->setManufacturerData(manufacturerData, manufacturerDataLength); } +bool BLEDevice::getManufacturerData (unsigned char* manu_data, + unsigned char& manu_data_len) const +{ + return BLEDeviceManager::instance()->getManufacturerData(this, manu_data, manu_data_len); +} + +bool BLEDevice::hasManufacturerData() const +{ + return BLEDeviceManager::instance()->hasManufacturerData(this); +} + void BLEDevice::setLocalName(const char *localName) { BLEDeviceManager::instance()->setLocalName(localName); @@ -143,11 +162,54 @@ void BLEDevice::setAdvertisingInterval(float advertisingInterval) BLEDeviceManager::instance()->setAdvertisingInterval(advertisingInterval); } +void BLEDevice::setConnectionInterval(int minInterval, + int maxInterval, + uint16_t latency, + uint16_t timeout) +{ + uint16_t minVal = (uint16_t)MSEC_TO_UNITS(minInterval, UNIT_1_25_MS); + uint16_t maxVal = (uint16_t)MSEC_TO_UNITS(maxInterval, UNIT_1_25_MS); + uint16_t timeoutVal = MSEC_TO_UNITS(timeout, UNIT_10_MS); + _conn_param.interval_min = minVal; + _conn_param.interval_max = maxVal; + _conn_param.timeout = timeoutVal; + _conn_param.latency = latency; + BLEDeviceManager::instance()->setConnectionInterval(this); +} + void BLEDevice::setConnectionInterval(int minimumConnectionInterval, int maximumConnectionInterval) { - // TODO: Update the connection interval need more discussion + uint16_t minVal = (uint16_t)MSEC_TO_UNITS(minimumConnectionInterval, UNIT_1_25_MS); + uint16_t maxVal = (uint16_t)MSEC_TO_UNITS(maximumConnectionInterval, UNIT_1_25_MS); + _conn_param.interval_min = minVal; + _conn_param.interval_max = maxVal; + + BLEDeviceManager::instance()->setConnectionInterval(this); +} + +int BLEDevice::getConnectionInterval() +{ + bt_le_conn_param_t conn_param; + + BLEDeviceManager::instance()->getConnectionInterval(this, &conn_param); + return UNITS_TO_MSEC((int)conn_param.interval_max, UNIT_1_25_MS); +} + +int BLEDevice::getConnectionTimeout() +{ + bt_le_conn_param_t conn_param; + + BLEDeviceManager::instance()->getConnectionInterval(this, &conn_param); + return UNITS_TO_MSEC(conn_param.timeout, UNIT_10_MS);; +} +int BLEDevice::getConnectionLatency() +{ + bt_le_conn_param_t conn_param; + + BLEDeviceManager::instance()->getConnectionInterval(this, &conn_param); + return conn_param.latency; } bool BLEDevice::setTxPower(int txPower) @@ -236,38 +298,22 @@ bool BLEDevice::startScan(bool withDuplicates) } else { - return BLEDeviceManager::instance()->startScanning(); + return BLEDeviceManager::instance()->startScanningNewPeripherals(); } } - -void BLEDevice::scan() -{ - scan(false); -} - void BLEDevice::scan(bool withDuplicates) { BLEDeviceManager::instance()->clearAdvertiseCritical(); startScan(withDuplicates); } -void BLEDevice::scanForName(String name) -{ - scanForName(name, false); -} - void BLEDevice::scanForName(String name, bool withDuplicates) { BLEDeviceManager::instance()->setAdvertiseCritical(name); startScan(withDuplicates); } -void BLEDevice::scanForUuid(String uuid) -{ - scanForUuid(uuid, false); -} - void BLEDevice::scanForUuid(String uuid, bool withDuplicates) { BLEService service_temp(uuid.c_str()); @@ -275,6 +321,12 @@ void BLEDevice::scanForUuid(String uuid, bool withDuplicates) startScan(withDuplicates); } +void BLEDevice::scanForAddress(String macaddr, bool withDuplicates) +{ + BLEDeviceManager::instance()->setAdvertiseCritical(macaddr.c_str()); + startScan(withDuplicates); +} + void BLEDevice::stopScan() { BLEDeviceManager::instance()->stopScanning(); diff --git a/libraries/CurieBLE/src/BLEDevice.h b/libraries/CurieBLE/src/BLEDevice.h index 590d933a..23279446 100644 --- a/libraries/CurieBLE/src/BLEDevice.h +++ b/libraries/CurieBLE/src/BLEDevice.h @@ -59,6 +59,16 @@ class BLEDevice */ BLEDevice(const BLEDevice* bledevice); BLEDevice(const BLEDevice& bledevice); + /** + * @brief The BLE device constructure + * + * @param[in] bleaddress BLE device address + * + * @return none + * + * @note none + */ + BLEDevice(const bt_addr_le_t* bleaddress); virtual ~BLEDevice(); @@ -181,6 +191,11 @@ class BLEDevice void setManufacturerData(const unsigned char manufacturerData[], unsigned char manufacturerDataLength); + bool getManufacturerData (unsigned char* manu_data, + unsigned char& manu_data_len) const; + + bool hasManufacturerData() const; + /** * Set the local name that the BLE Peripheral Device advertises * @@ -217,10 +232,10 @@ class BLEDevice * * @note none */ - //void setConnectionInterval(int minimumConnectionInterval, - // int maximumConnectionInterval, - // uint16_t latency, - // uint16_t timeout); + void setConnectionInterval(int minimumConnectionInterval, + int maximumConnectionInterval, + uint16_t latency, + uint16_t timeout); /** * @brief Set the min and max connection interval and send connection @@ -237,6 +252,10 @@ class BLEDevice void setConnectionInterval(int minimumConnectionInterval, int maximumConnectionInterval); + int getConnectionInterval(); + int getConnectionTimeout(); + int getConnectionLatency(); + /** * @brief Set TX power of the radio in dBM * @@ -346,82 +365,78 @@ class BLEDevice //void scanForAddress(String address); // Not include in baseline. Add here as feature for feature release. /** - * @brief Start scanning for peripherals without filter + * @brief Start scanning for peripherals with the option of accepting all detectable + * Peripherals or just the newly detected. * - * @param none + * @param[in] withDuplicates true - return all detectable Peripherals. + * false- return a detected Peripheral only once. * * @return none * - * @note none + * @note When, withDuplicates = true, accept all detectable Peripherals. + * No Peripheral filtering process applied to the scan result. + * By default, withDuplicates = false, a detected Peripheral is + * reported once. */ - void scan(); + void scan(bool withDuplicates = false); /** - * @brief Start scanning for peripherals with filter - * - * @param[in] withDuplicates true - with duplicate filter - * false- without duplicate filter - * - * @return none - * - * @note option to filter out duplicate addresses for Arduino. - * The current only support fileter duplicate mode. - */ - void scan(bool withDuplicates); - - /** - * @brief Start scanning for peripherals and filter by device name in ADV - * - * @param name The device's local name. - * - * @return none - * - * @note option to filter out duplicate addresses for Arduino. - * The current only support fileter duplicate mode. - */ - void scanForName(String name); - - /** - * @brief Start scanning for peripherals and filter by device name in ADV + * @brief Start scanning for peripherals and filter by device name in ADV and + * the option of accepting all detectable Peripherals or just the + * newly detected. * * @param[in] name The device's local name. * - * @param[in] withDuplicates true - with duplicate filter - * false- without duplicate filter + * @param[in] withDuplicates true - return all detectable Peripherals. + * false- return a detected Peripheral only once. * * @return none * - * @note option to filter out duplicate addresses for Arduino. - * The current only support fileter duplicate mode. + * @note When, withDuplicates = true, accept all detectable Peripherals. + * No Peripheral filtering process applied to the scan result. + * By default, withDuplicates = false, a detected Peripheral is + * reported once. */ - void scanForName(String name, bool withDuplicates); + void scanForName(String name, bool withDuplicates = false); /** - * @brief Start scanning for peripherals and filter by service in ADV + * @brief Start scanning for peripherals and filter by service in ADV and + * the option of accepting all detectable Peripherals or just the + * newly detected. * - * @param service The service + * @param[in] service The service + * + * @param[in] withDuplicates true - return all detectable Peripherals. + * false- return a detected Peripheral only once. * * @return none * - * @note none + * @note When, withDuplicates = true, accept all detectable Peripherals. + * No Peripheral filtering process applied to the scan result. + * By default, withDuplicates = false, a detected Peripheral is + * reported once. */ - void scanForUuid(String uuid); + void scanForUuid(String uuid, bool withDuplicates = false); /** - * @brief Start scanning for peripherals and filter by service in ADV + * @brief Start scanning for peripherals and filter by MAC address and + * the option of accepting all detectable Peripherals or just the + * newly detected. * - * @param[in] service The service + * @param[in] macaddr The Peripheral MAC address * - * @param[in] withDuplicates true - with duplicate filter - * false- without duplicate filter + * @param[in] withDuplicates true - return all detectable Peripherals. + * false- return a detected Peripheral only once. * * @return none * - * @note option to filter out duplicate addresses for Arduino. - * The current only support fileter duplicate mode. + * @note When, withDuplicates = true, accept all detectable Peripherals. + * No Peripheral filtering process applied to the scan result. + * By default, withDuplicates = false, a detected Peripheral is + * reported once. */ - void scanForUuid(String uuid, bool withDuplicates); - + void scanForAddress(String macaddr, bool withDuplicates = false); + /** * @brief Stop scanning for peripherals * @@ -633,6 +648,7 @@ class BLEDevice void setEventHandler(BLEDeviceEvent event, BLEDeviceEventHandler eventHandler); // set an event handler (callback) protected: + friend class BLEDescriptorImp; friend class BLECharacteristicImp; friend class BLEServiceImp; friend class BLEDeviceManager; @@ -648,41 +664,36 @@ class BLEDevice bt_gatt_read_params_t *params, const void *data, uint16_t length); + friend uint8_t profile_descriptor_read_rsp_process(bt_conn_t *conn, + int err, + bt_gatt_read_params_t *params, + const void *data, + uint16_t length); const bt_addr_le_t* bt_le_address() const; const bt_le_conn_param* bt_conn_param() const; void setAddress(const bt_addr_le_t& addr); void setAdvertiseData(const uint8_t* adv_data, uint8_t len); - /** - * @brief The BLE device constructure - * - * @param[in] bleaddress BLE device address - * - * @return none - * - * @note none - */ - BLEDevice(const bt_addr_le_t* bleaddress); private: void preCheckProfile(); /** - * @brief Start scanning for peripherals with/without duplicate filter + * @brief Start scanning for peripherals with the option of accepting all + * detectable Peripherals or just the newly detected. * - * @param[in] withDuplicates true - with duplicate filter - * false- without duplicate filter + * @param[in] withDuplicates true - return all detectable Peripherals. + * false- return a detected Peripheral only once. * * @return none * - * @note option to filter out duplicate addresses for Arduino. - * The current only support fileter duplicate mode. + * @note When, withDuplicates = true, accept all detectable Peripherals. */ bool startScan(bool withDuplicates); private: bt_addr_le_t _bt_addr; - bt_le_conn_param _conn_param; + bt_le_conn_param_t _conn_param; }; #endif diff --git a/libraries/CurieBLE/src/BLEPeripheral.cpp b/libraries/CurieBLE/src/BLEPeripheral.cpp index 84b85c88..2bcee466 100644 --- a/libraries/CurieBLE/src/BLEPeripheral.cpp +++ b/libraries/CurieBLE/src/BLEPeripheral.cpp @@ -55,67 +55,37 @@ BLEPeripheral::~BLEPeripheral(void) void BLEPeripheral::setAdvertisedServiceUuid(const char* advertisedServiceUuid) { - if (!_initCalled) { - init(); - } - BLE.setAdvertisedServiceUuid(advertisedServiceUuid); } + void BLEPeripheral::setLocalName(const char* localName) { - if (!_initCalled) { - init(); - } - BLE.setLocalName(localName); } - void BLEPeripheral::setDeviceName(const char *deviceName) { - if (!_initCalled) { - init(); - } - BLE.setDeviceName(deviceName); } void BLEPeripheral::setAppearance(const unsigned short appearance) { - if (!_initCalled) { - init(); - } - BLE.setAppearance(appearance); } void BLEPeripheral::setConnectionInterval(const unsigned short minConnInterval, const unsigned short maxConnInterval) { - if (!_initCalled) { - init(); - } - BLE.setConnectionInterval(minConnInterval, maxConnInterval); } void BLEPeripheral::addAttribute(BLEService& service) { - if (!_initCalled) - { - init(); - } - BLE.addService(service); _lastService = &service; } void BLEPeripheral::addAttribute(BLECharacteristic& characteristic) { - if (!_initCalled) - { - init(); - } - if (_lastService) { _lastService->addCharacteristic(characteristic); @@ -125,11 +95,6 @@ void BLEPeripheral::addAttribute(BLECharacteristic& characteristic) void BLEPeripheral::addAttribute(BLEDescriptor& descriptor) { - if (!_initCalled) - { - init(); - } - if (_lastCharacteristic) { _lastCharacteristic->addDescriptor(descriptor); @@ -181,7 +146,8 @@ BLECentral BLEPeripheral::central(void) bool BLEPeripheral::connected(void) { - return BLE.connected(); + BLEDevice centralBle = BLE.central(); + return centralBle.connected(); } void BLEPeripheral::init() @@ -189,7 +155,6 @@ void BLEPeripheral::init() if (!_initCalled) { BLE.begin(); - memset(m_eventHandlers, 0, sizeof(m_eventHandlers)); _initCalled = true; } } diff --git a/libraries/CurieBLE/src/internal/BLECallbacks.cpp b/libraries/CurieBLE/src/internal/BLECallbacks.cpp index b6234750..328c196b 100644 --- a/libraries/CurieBLE/src/internal/BLECallbacks.cpp +++ b/libraries/CurieBLE/src/internal/BLECallbacks.cpp @@ -77,7 +77,13 @@ ssize_t profile_longwrite_process(struct bt_conn *conn, const void *buf, uint16_t len, uint16_t offset) { - BLECharacteristicImp *blecharacteritic = (BLECharacteristicImp*)attr->user_data; + BLEAttribute *bleattr = (BLEAttribute *)attr->user_data; + BLEAttributeType type = bleattr->type(); + if (BLETypeCharacteristic != type) + { + return 0; + } + BLECharacteristicImp *blecharacteritic = (BLECharacteristicImp*)bleattr; blecharacteritic->setBuffer((const uint8_t *) buf, len, offset); @@ -88,7 +94,13 @@ int profile_longflush_process(struct bt_conn *conn, const struct bt_gatt_attr *attr, uint8_t flags) { - BLECharacteristicImp *blecharacteritic = (BLECharacteristicImp*)attr->user_data; + BLEAttribute *bleattr = (BLEAttribute *)attr->user_data; + BLEAttributeType type = bleattr->type(); + if (BLETypeCharacteristic != type) + { + return 0; + } + BLECharacteristicImp *blecharacteritic = (BLECharacteristicImp*)bleattr; switch (flags) { @@ -145,7 +157,7 @@ uint8_t profile_read_rsp_process(bt_conn_t *conn, const void *data, uint16_t length) { - if (NULL == data) + if (NULL == data && 0 != length) { return BT_GATT_ITER_STOP; } @@ -161,6 +173,31 @@ uint8_t profile_read_rsp_process(bt_conn_t *conn, return BT_GATT_ITER_STOP; } +uint8_t profile_descriptor_read_rsp_process(bt_conn_t *conn, + int err, + bt_gatt_read_params_t *params, + const void *data, + uint16_t length) +{ + if (NULL == data) + { + return BT_GATT_ITER_STOP; + } + BLEDescriptorImp *descriptor = NULL; + BLEDevice bleDevice(bt_conn_get_dst(conn)); + + // Get characteristic by handle params->single.handle + descriptor = BLEProfileManager::instance()->descriptor(bleDevice, params->single.handle); + + //pr_debug(LOG_MODULE_BLE, "%s-%d", __FUNCTION__, __LINE__); + if (descriptor) + { + descriptor->writeValue((const unsigned char *)data, length, params->single.offset); + } + //pr_debug(LOG_MODULE_BLE, "%s-%d: desc len-%d", __FUNCTION__, __LINE__, descriptor->valueLength()); + return BT_GATT_ITER_STOP; +} + uint8_t profile_service_read_rsp_process(bt_conn_t *conn, int err, bt_gatt_read_params_t *params, @@ -172,6 +209,23 @@ uint8_t profile_service_read_rsp_process(bt_conn_t *conn, return ret; } +uint8_t profile_characteristic_read_rsp_process(bt_conn_t *conn, + int err, + bt_gatt_read_params_t *params, + const void *data, + uint16_t length) +{ + BLEDevice bleDevice(bt_conn_get_dst(conn)); + BLEServiceImp* service_imp = BLEProfileManager::instance()->getServiceBySubHandle(bleDevice, params->single.handle); + + uint8_t ret = service_imp->characteristicReadRspProc(conn, + err, + params, + data, + length); + pr_debug(LOG_MODULE_BLE, "%s-%d:ret-%d", __FUNCTION__, __LINE__, ret); + return ret; +} void bleConnectEventHandler(bt_conn_t *conn, @@ -223,4 +277,9 @@ void ble_central_device_found(const bt_addr_le_t *addr, ad, len); } +void ble_on_write_no_rsp_complete(struct bt_conn *conn, uint8_t err, + const void *data) +{ + BLECharacteristicImp::writeResponseReceived(conn, err, data); +} diff --git a/libraries/CurieBLE/src/internal/BLECallbacks.h b/libraries/CurieBLE/src/internal/BLECallbacks.h index 882c134a..deffe92a 100644 --- a/libraries/CurieBLE/src/internal/BLECallbacks.h +++ b/libraries/CurieBLE/src/internal/BLECallbacks.h @@ -28,6 +28,13 @@ uint8_t profile_read_rsp_process(bt_conn_t *conn, int err, bt_gatt_read_params_t *params, const void *data, uint16_t length); + +uint8_t profile_descriptor_read_rsp_process(bt_conn_t *conn, + int err, + bt_gatt_read_params_t *params, + const void *data, + uint16_t length); + int profile_longflush_process(struct bt_conn *conn, const struct bt_gatt_attr *attr, uint8_t flags); @@ -74,5 +81,13 @@ uint8_t profile_service_read_rsp_process(bt_conn_t *conn, const void *data, uint16_t length); +void ble_on_write_no_rsp_complete(struct bt_conn *conn, uint8_t err, + const void *data); +uint8_t profile_characteristic_read_rsp_process(bt_conn_t *conn, + int err, + bt_gatt_read_params_t *params, + const void *data, + uint16_t length); + #endif diff --git a/libraries/CurieBLE/src/internal/BLECharacteristicImp.cpp b/libraries/CurieBLE/src/internal/BLECharacteristicImp.cpp index a5a60c57..a7098e96 100644 --- a/libraries/CurieBLE/src/internal/BLECharacteristicImp.cpp +++ b/libraries/CurieBLE/src/internal/BLECharacteristicImp.cpp @@ -27,6 +27,7 @@ bt_uuid_16_t BLECharacteristicImp::_gatt_chrc_uuid = {BT_UUID_TYPE_16, BT_UUID_GATT_CHRC_VAL}; bt_uuid_16_t BLECharacteristicImp::_gatt_ccc_uuid = {BT_UUID_TYPE_16, BT_UUID_GATT_CCC_VAL}; +volatile bool BLECharacteristicImp::_gattc_writing = false; BLECharacteristicImp::BLECharacteristicImp(const bt_uuid_t* uuid, unsigned char properties, @@ -170,6 +171,7 @@ BLECharacteristicImp::BLECharacteristicImp(BLECharacteristic& characteristic, if (NULL != characteristic._value) { memcpy(_value, characteristic._value, _value_size); + _value_length = _value_size; } // Update BLE device object @@ -259,6 +261,7 @@ bool BLECharacteristicImp::setValue(const unsigned char value[], uint16_t length) { _setValue(value, length, 0); + _value_updated = true; if (BLEUtils::isLocalBLE(_ble_device) == true) { // GATT server @@ -535,6 +538,26 @@ BLECharacteristicImp::valueHandle() return handle; } +BLEDescriptorImp* BLECharacteristicImp::descriptor(uint16_t handle) +{ + BLEDescriptorImp* descriptorImp = NULL; + BLEDescriptorNodePtr node = link_node_get_first(&_descriptors_header); + while (NULL != node) + { + descriptorImp = node->value; + if (handle == descriptorImp->valueHandle()) + { + break; + } + node = node->next; + } + if (NULL == node) + { + descriptorImp = NULL; + } + return descriptorImp; +} + void BLECharacteristicImp::_setValue(const uint8_t value[], uint16_t length, uint16_t offset) { @@ -554,7 +577,6 @@ BLECharacteristicImp::_setValue(const uint8_t value[], uint16_t length, uint16_t } } - _value_updated = true; memcpy(_value + offset, value, length); _value_length = length; } @@ -593,9 +615,10 @@ bt_uuid_t* BLECharacteristicImp::getClientCharacteristicConfigUuid(void) return (bt_uuid_t*) &_gatt_ccc_uuid; } -bool BLECharacteristicImp::read() +bool BLECharacteristicImp::read(bool blocked) { int retval = 0; + bool ret_bool = false; bt_conn_t* conn = NULL; if (true == BLEUtils::isLocalBLE(_ble_device)) @@ -629,12 +652,30 @@ bool BLECharacteristicImp::read() // Send read request retval = bt_gatt_read(conn, &_read_params); - bt_conn_unref(conn); if (0 == retval) { _reading = true; + ret_bool = true; + + // Block the call + if (blocked == true) + { + while (_reading == true && ret_bool) + { + delay(5); + ret_bool = _ble_device.connected(); + } + } } - return _reading; + bt_conn_unref(conn); + return ret_bool; +} + +void BLECharacteristicImp::writeResponseReceived(struct bt_conn *conn, + uint8_t err, + const void *data) +{ + _gattc_writing = false; } bool BLECharacteristicImp::write(const unsigned char value[], @@ -643,7 +684,7 @@ bool BLECharacteristicImp::write(const unsigned char value[], int retval = 0; bt_conn_t* conn = NULL; - if (true == BLEUtils::isLocalBLE(_ble_device)) + if (true == BLEUtils::isLocalBLE(_ble_device) || true == _gattc_writing) { // GATT server can't write return false; @@ -655,12 +696,28 @@ bool BLECharacteristicImp::write(const unsigned char value[], return false; } - // Send read request - retval = bt_gatt_write_without_response(conn, - _value_handle, - value, - length, - false); + // Send write request + if (_gatt_chrc.properties & BT_GATT_CHRC_WRITE) + { + _gattc_writing = true; + retval = bt_gatt_write(conn, + _value_handle, + 0, + value, + length, + ble_on_write_no_rsp_complete); + while (_gattc_writing) + { + delay(2); + } + } else if (_gatt_chrc.properties & BT_GATT_CHRC_WRITE_WITHOUT_RESP) + { + retval = bt_gatt_write_without_response(conn, + _value_handle, + value, + length, + false); + } bt_conn_unref(conn); return (0 == retval); } diff --git a/libraries/CurieBLE/src/internal/BLECharacteristicImp.h b/libraries/CurieBLE/src/internal/BLECharacteristicImp.h index c6cee5ab..af5e9839 100644 --- a/libraries/CurieBLE/src/internal/BLECharacteristicImp.h +++ b/libraries/CurieBLE/src/internal/BLECharacteristicImp.h @@ -146,18 +146,18 @@ class BLECharacteristicImp: public BLEAttribute{ /** * @brief Schedule the read request to read the characteristic in peripheral * - * @param[in] none + * @param[in] blocked Flag the call is blocked or un-blocked * * @return bool Indicate the success or error * - * @note Only for central device + * @note Only for GATT client + * Default it is block call as per Arduino request */ - bool read(); + bool read(bool blocked = true); /** * @brief Schedule the write request to update the characteristic in peripheral * - * @param[in] peripheral The peripheral device that want to be updated * @param[in] value New value to set, as a byte array. Data is stored in internal copy. * @param[in] length Length, in bytes, of valid data in the array to write. * Must not exceed maxLength set for this characteristic. @@ -168,6 +168,10 @@ class BLECharacteristicImp: public BLEAttribute{ */ bool write(const unsigned char value[], uint16_t length); + + static void writeResponseReceived(struct bt_conn *conn, + uint8_t err, + const void *data); int descriptorCount() const; uint8_t discoverResponseProc(bt_conn_t *conn, @@ -184,6 +188,8 @@ class BLECharacteristicImp: public BLEAttribute{ friend class BLEProfileManager; friend class BLEServiceImp; friend class BLECharacteristic; + + BLEDescriptorImp* descriptor(uint16_t handle); /** * Constructor for BLE Characteristic * @@ -324,7 +330,8 @@ class BLECharacteristicImp: public BLEAttribute{ bt_gatt_subscribe_params_t _sub_params; bool _subscribed; - bool _reading; + volatile bool _reading; + static volatile bool _gattc_writing; bt_gatt_read_params_t _read_params; // GATT read parameter typedef LinkNode BLEDescriptorLinkNodeHeader; diff --git a/libraries/CurieBLE/src/internal/BLEDescriptorImp.cpp b/libraries/CurieBLE/src/internal/BLEDescriptorImp.cpp index 0586bc09..d773f63c 100644 --- a/libraries/CurieBLE/src/internal/BLEDescriptorImp.cpp +++ b/libraries/CurieBLE/src/internal/BLEDescriptorImp.cpp @@ -23,11 +23,15 @@ #include "internal/ble_client.h" #include "BLECallbacks.h" +#include "BLEUtils.h" BLEDescriptorImp::BLEDescriptorImp(BLEDevice& bledevice, BLEDescriptor &descriptor): - BLEAttribute(descriptor.uuid(), BLETypeDescriptor), - _value_handle(0) + BLEAttribute(descriptor.uuid(), BLETypeDescriptor), + _value_handle(0), + _bledev(bledevice), + _reading(false), + _attr_desc_value(NULL) { _properties = descriptor.properties(); @@ -45,21 +49,22 @@ BLEDescriptorImp::BLEDescriptorImp(const bt_uuid_t* uuid, uint16_t handle, BLEDevice& bledevice): BLEAttribute(uuid, BLETypeDescriptor), + _value_length(0), _value_handle(handle), - _properties(properties) + _value(NULL), + _properties(properties), + _bledev(bledevice), + _reading(false), + _attr_desc_value(NULL) { - _value_length = BLE_MAX_ATTR_DATA_LEN; - _value = (unsigned char*)malloc(_value_length); - - if (_value) - memset(_value, 0, _value_length); - else - _value_length = 0; + memset(&_read_params, 0, sizeof(_read_params)); } BLEDescriptorImp::BLEDescriptorImp(const BLEDescriptorImp& rhs) : - BLEAttribute(rhs) + BLEAttribute(rhs), + _reading(false), + _attr_desc_value(rhs._attr_desc_value) { _value_length = rhs._value_length; _value = (unsigned char *)malloc(_value_length); @@ -70,30 +75,29 @@ BLEDescriptorImp::BLEDescriptorImp(const BLEDescriptorImp& rhs) : _value_handle = rhs._value_handle; _properties = rhs._properties; - _descriptor_uuid = rhs._descriptor_uuid; _bledev = BLEDevice(&rhs._bledev); } BLEDescriptorImp& BLEDescriptorImp::operator=(const BLEDescriptorImp& that) { - if (this != &that) { + if (this != &that) + { + BLEAttribute::operator=(that); + if (_value) + free(_value); - BLEAttribute::operator=(that); - if (_value) - free(_value); + _value_length = that._value_length; + _value = (unsigned char *)malloc(_value_length); + if (_value) + memcpy(_value, that._value, sizeof(_value_length)); + else + _value_length = 0; - _value_length = that._value_length; - _value = (unsigned char *)malloc(_value_length); - if (_value) - memcpy(_value, that._value, sizeof(_value_length)); - else - _value_length = 0; - - _value_handle = that._value_handle; - _properties = that._properties; - _descriptor_uuid = that._descriptor_uuid; - _bledev = BLEDevice(&that._bledev); + _value_handle = that._value_handle; + _properties = that._properties; + _bledev = BLEDevice(&that._bledev); + _attr_desc_value = that._attr_desc_value; } return *this; } @@ -136,6 +140,24 @@ int BLEDescriptorImp::updateProfile(bt_gatt_attr_t *attr_start, int& index) return 1; } +uint16_t +BLEDescriptorImp::valueHandle() const +{ + uint16_t handle = 0; + if (NULL != _attr_desc_value) + { + //GATT server + handle = _attr_desc_value->handle; + } + else + { + // GATT client + handle = _value_handle; + } + + return handle; +} + unsigned char BLEDescriptorImp::properties() const { return _properties; @@ -146,4 +168,102 @@ int BLEDescriptorImp::valueSize() const return _value_length; } +bool BLEDescriptorImp::read() +{ + int retval = 0; + bt_conn_t* conn = NULL; + bool ret_bool = true; + + if (true == BLEUtils::isLocalBLE(_bledev)) + { + // GATT server can't read + return false; + } + + if (_reading) + { + // Already in reading state + return false; + } + + _read_params.func = profile_descriptor_read_rsp_process; + _read_params.handle_count = 1; + _read_params.single.handle = _value_handle; + _read_params.single.offset = 0; + + if (0 == _read_params.single.handle) + { + // Discover not complete + return false; + } + + conn = bt_conn_lookup_addr_le(_bledev.bt_le_address()); + if (NULL == conn) + { + return false; + } + + // Send read request + retval = bt_gatt_read(conn, &_read_params); + bt_conn_unref(conn); + if (0 == retval) + { + _reading = true; + } + + // Block the read + while (_reading == true && ret_bool) + { + delay(5); + ret_bool = _bledev.connected(); + } + return _reading; +} + +bool BLEDescriptorImp::writeValue(const byte value[], + int length, + int offset) +{ + bool ret = true; + int total_length = length + offset; + int write_len = length; + + if (_reading) + { + _reading = false; + } + + if (total_length > BLE_MAX_ATTR_DATA_LEN) + { + return false; + } + + if (NULL == _value) + { + _value_length = length + offset; + _value = (unsigned char*)malloc(_value_length); + + if (NULL != _value) + { + memset(_value, 0, _value_length); + } + else + { + _value_length = 0; + ret = false; + } + } + + if (_value_length < total_length) + { + write_len = _value_length - offset; + } + + if (NULL != _value) + { + memcpy(_value + offset, value, write_len); + } + return ret; +} + diff --git a/libraries/CurieBLE/src/internal/BLEDescriptorImp.h b/libraries/CurieBLE/src/internal/BLEDescriptorImp.h index 32fceb1a..701f3f83 100644 --- a/libraries/CurieBLE/src/internal/BLEDescriptorImp.h +++ b/libraries/CurieBLE/src/internal/BLEDescriptorImp.h @@ -59,12 +59,80 @@ class BLEDescriptorImp: public BLEAttribute{ * @return unsigned short size of Descriptor value in bytes */ unsigned short valueLength(void) const; - + + /** + * @brief Fill the attribute for profile register structure + * + * @param bt_gatt_attr_t * The start pointer of the profile register structure array + * + * @param int& The current index in the profile structure array + * + * @return int Filled structure counter + * + * @note none + */ int updateProfile(bt_gatt_attr_t *attr_start, int& index); unsigned char operator[] (int offset) const; + + /** + * @brief Get the property mask of the descriptor + * + * @param none + * + * @return unsigned char The property mask of the descriptor + * + * @note none + */ unsigned char properties() const; + + /** + * @brief Get the maximum size of the value + * + * @param none + * + * @return int The maximum size of the value + * + * @note none + */ int valueSize() const; + + /** + * @brief Get the descriptor value handle + * + * @param none + * + * @return none + * + * @note none + */ + uint16_t valueHandle() const; + + /** + * @brief Write the value of the descriptor + * + * @param value The value buffer that want to write to descriptor + * + * @param length The value buffer's length + * + * @param offset The offset in the descriptor's data + * + * @return bool true - Success, false - Failed + * + * @note none + */ + bool writeValue(const byte value[], int length, int offset); + + /** + * @brief Read the descriptor value + * + * @param none + * + * @return bool true - Success, false - Failed + * + * @note Only for GATT client. Schedule read request to the GATT server + */ + bool read(); protected: @@ -75,9 +143,12 @@ class BLEDescriptorImp: public BLEAttribute{ unsigned char* _value; unsigned char _properties; // The characteristic property - bt_uuid_128 _descriptor_uuid; - BLEDevice _bledev; + + bool _reading; + bt_gatt_read_params_t _read_params; // GATT read parameter + + bt_gatt_attr_t *_attr_desc_value; // GATT server only }; #endif // _BLE_DESCRIPTOR_H_INCLUDED diff --git a/libraries/CurieBLE/src/internal/BLEDeviceManager.cpp b/libraries/CurieBLE/src/internal/BLEDeviceManager.cpp index 930e9faf..d5ddd181 100644 --- a/libraries/CurieBLE/src/internal/BLEDeviceManager.cpp +++ b/libraries/CurieBLE/src/internal/BLEDeviceManager.cpp @@ -33,9 +33,15 @@ BLEDeviceManager* BLEDeviceManager::_instance; BLEDeviceManager::BLEDeviceManager(): _min_conn_interval(0), _max_conn_interval(0), + _peer_temp_dev_index(0), _adv_critical_local_name(""), + _wait_for_connect_peripheral_adv_data_len(0), + _wait_for_connect_peripheral_scan_rsp_data_len(0), _wait_for_connect_peripheral_adv_rssi(0), + _available_for_connect_peripheral_adv_data_len(0), + _available_for_connect_peripheral_scan_rsp_data_len(0), _available_for_connect_peripheral_adv_rssi(0), + _available_for_connect_peripheral_connectable(false), _connecting(false), _has_service_uuid(false), _has_service_solicit_uuid(false), @@ -44,20 +50,17 @@ BLEDeviceManager::BLEDeviceManager(): _service_data_length(0), _adv_type(0), _adv_data_idx(0), + _scan_rsp_data_idx(0), _local_name(""), _state(BLE_PERIPH_STATE_NOT_READY), _local_ble(NULL), - _peer_peripheral_index(0) + _peer_peripheral_index(0), + _duplicate_filter_header(0), + _duplicate_filter_tail(0), + _adv_duplicate_filter_enabled(false) { memset(&_local_bda, 0, sizeof(_local_bda)); - memset(&_wait_for_connect_peripheral, 0, sizeof(_wait_for_connect_peripheral)); - memset(&_service_uuid, 0, sizeof(_service_uuid)); - memset(&_service_solicit_uuid, 0, sizeof(_service_solicit_uuid)); - memset(&_service_data_uuid, 0, sizeof(_service_data_uuid)); - memset(_service_data, 0, sizeof(_service_data)); - memset(_service_data_buf, 0, sizeof(_service_data_buf)); - memset(_adv_data, 0, sizeof(_adv_data)); memset(&_peer_central, 0, sizeof (bt_addr_le_t)); @@ -75,19 +78,49 @@ BLEDeviceManager::BLEDeviceManager(): memset(_peer_adv_buffer, 0, sizeof(_peer_adv_buffer)); memset(_peer_adv_mill, 0, sizeof(_peer_adv_mill)); + memset(_peer_adv_data, 0, sizeof(_peer_adv_data)); + memset(_peer_adv_data_len, 0, sizeof(_peer_adv_data_len)); + memset(_peer_scan_rsp_data, 0, sizeof(_peer_scan_rsp_data)); + memset(_peer_scan_rsp_data_len, -1, sizeof(_peer_scan_rsp_data_len)); + memset(_peer_adv_rssi, 0, sizeof(_peer_adv_rssi)); + + memset(_peer_adv_connectable, 0, sizeof(_peer_adv_connectable)); + + memset(_peer_temp_adv_buffer, 0, sizeof(_peer_temp_adv_buffer)); + memset(_peer_temp_adv_data, 0, sizeof(_peer_temp_adv_data)); + memset(_peer_temp_adv_data_len, 0, sizeof(_peer_temp_adv_data_len)); + memset(_peer_temp_adv_connectable, 0, sizeof(_peer_adv_connectable)); + memset(&_adv_accept_critical, 0, sizeof(_adv_accept_critical)); memset(&_adv_critical_service_uuid, 0, sizeof(_adv_critical_service_uuid)); + memset(&_adv_accept_device, 0, sizeof(_adv_accept_device)); + + memset(&_wait_for_connect_peripheral, 0, sizeof(_wait_for_connect_peripheral)); + memset(&_wait_for_connect_peripheral_adv_data, 0, sizeof(_wait_for_connect_peripheral_adv_data)); + memset(&_wait_for_connect_peripheral_scan_rsp_data, 0, sizeof(_wait_for_connect_peripheral_scan_rsp_data)); + + memset(&_available_for_connect_peripheral_adv_data, 0, sizeof(_available_for_connect_peripheral_adv_data)); + memset(&_available_for_connect_peripheral_scan_rsp_data, 0, sizeof(_available_for_connect_peripheral_scan_rsp_data)); + + memset(&_service_uuid, 0, sizeof(_service_uuid)); + memset(&_service_solicit_uuid, 0, sizeof(_service_solicit_uuid)); + memset(_manufacturer_data, 0, sizeof(_manufacturer_data)); + + memset(&_service_data_uuid, 0, sizeof(_service_data_uuid)); + memset(_service_data, 0, sizeof(_service_data)); + memset(_service_data_buf, 0, sizeof(_service_data_buf)); + + memset(_adv_data, 0, sizeof(_adv_data)); + memset(_scan_rsp_data, 0, sizeof(_scan_rsp_data)); memset(_peer_peripheral, 0, sizeof(_peer_peripheral)); memset(_peer_peripheral_adv_data, 0, sizeof(_peer_peripheral_adv_data)); memset(_peer_peripheral_adv_data_len, 0, sizeof(_peer_peripheral_adv_data_len)); + memset(_peer_peripheral_scan_rsp_data, 0, sizeof(_peer_peripheral_scan_rsp_data)); + memset(_peer_peripheral_scan_rsp_data_len, 0, sizeof(_peer_peripheral_scan_rsp_data_len)); memset(_peer_peripheral_adv_rssi, 0, sizeof(_peer_peripheral_adv_rssi)); memset(_device_events, 0, sizeof(_device_events)); - memset(_manufacturer_data, 0, sizeof(_manufacturer_data)); - memset(_peer_adv_data, 0, sizeof(_peer_adv_data)); - memset(_peer_adv_data_len, 0, sizeof(_peer_adv_data_len)); - memset(_peer_adv_rssi, 0, sizeof(_peer_adv_rssi)); } BLEDeviceManager::~BLEDeviceManager() @@ -97,11 +130,11 @@ BLEDeviceManager::~BLEDeviceManager() bool BLEDeviceManager::begin(BLEDevice *device) { - if (NULL == _local_ble && false == *device) + if (NULL == _local_ble) { _local_ble = device; - _local_ble->setAddress(_local_bda); bt_le_set_mac_address(_local_bda); + // Set device name setDeviceName(); _state = BLE_PERIPH_STATE_READY; @@ -133,7 +166,12 @@ void BLEDeviceManager::poll() } void BLEDeviceManager::end() -{} +{ + stopScanning(); + stopAdvertising(); + // Disconnect the connections + disconnect(&BLE); +} bool BLEDeviceManager::connected(const BLEDevice *device) const { @@ -249,17 +287,31 @@ void BLEDeviceManager::setAdvertisingInterval(float advertisingInterval) _adv_param.interval_max = interval; } -void BLEDeviceManager::setConnectionInterval(float minimumConnectionInterval, - float maximumConnectionInterval, - uint16_t latency, - uint16_t timeout) +void BLEDeviceManager::getConnectionInterval(BLEDevice *device, + bt_le_conn_param* conn_param) { + bt_conn_t* conn = bt_conn_lookup_addr_le(device->bt_le_address()); + if (NULL != conn) + { + conn_param->interval_max = conn->le.interval; + conn_param->interval_min = conn->le.interval; + conn_param->latency = conn->le.latency; + conn_param->timeout = conn->le.timeout; + bt_conn_unref(conn); + } } -void BLEDeviceManager::setConnectionInterval(float minimumConnectionInterval, - float maximumConnectionInterval) +int BLEDeviceManager::setConnectionInterval(BLEDevice *device) { - + bt_conn_t* conn = bt_conn_lookup_addr_le(device->bt_le_address()); + int ret = 0; + if (NULL != conn) + { + ret = bt_conn_le_param_update(conn, device->bt_conn_param()); + pr_debug(LOG_MODULE_BLE, "%s-ret:%d",__FUNCTION__, ret); + bt_conn_unref(conn); + } + return ret; } bool BLEDeviceManager::setTxPower(int txPower) @@ -287,7 +339,10 @@ void BLEDeviceManager::setDeviceName(const char* deviceName) if (len > BLE_MAX_DEVICE_NAME) len = BLE_MAX_DEVICE_NAME; memcpy(_device_name, deviceName, len); - setDeviceName(); + if (NULL != _local_ble) + { + setDeviceName(); + } } } @@ -303,109 +358,132 @@ void BLEDeviceManager::setAppearance(unsigned short appearance) _appearance = appearance; } +BLE_STATUS_T +BLEDeviceManager::setAdvertiseData(uint8_t type, const uint8_t* data, uint8_t length) +{ + uint8_t lengthOfAdv = 0; // Flags data length + uint8_t lengthOfScanRsp = 0; // Flags data length + bt_data_t *fill_area = NULL; + + // Get the length of the Advertisement + for (uint8_t i = 0; i < _adv_data_idx; i++) + { + lengthOfAdv += _adv_data[i].data_len + 2; + } + + for (uint8_t i = 0; i < _scan_rsp_data_idx; i++) + { + lengthOfAdv += _scan_rsp_data[i].data_len + 2; + } + + + if (((length + lengthOfAdv) < BLE_MAX_ADV_SIZE) && + (_adv_data_idx < ARRAY_SIZE(_adv_data))) + { + fill_area = &_adv_data[_adv_data_idx]; + _adv_data_idx++; + } + else if ((length + lengthOfScanRsp) < BLE_MAX_ADV_SIZE && + (_scan_rsp_data_idx < ARRAY_SIZE(_scan_rsp_data))) + { + fill_area = &_scan_rsp_data[_scan_rsp_data_idx]; + _scan_rsp_data_idx++; + } + else + { + // Service data block is too large. + return BLE_STATUS_ERROR_PARAMETER; + } + + if (fill_area) + { + fill_area->type = type; + fill_area->data = data; + fill_area->data_len = length; + + pr_info(LOG_MODULE_BLE, "ADV type %d Len - %d",type, length); + } + return BLE_STATUS_SUCCESS; +} + BLE_STATUS_T BLEDeviceManager::_advDataInit(void) { - uint8_t lengthTotal = 2; // Flags data length + BLE_STATUS_T ret = BLE_STATUS_SUCCESS; + // Clear the indexs _adv_data_idx = 0; + _scan_rsp_data_idx = 0; /* Add flags */ _adv_type = (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR); - _adv_data[_adv_data_idx].type = BT_DATA_FLAGS; - _adv_data[_adv_data_idx].data = &_adv_type; - _adv_data[_adv_data_idx].data_len = 1; - _adv_data_idx++; + ret = setAdvertiseData (BT_DATA_FLAGS, &_adv_type, sizeof(_adv_type)); - if (_has_service_uuid) + if (_has_service_solicit_uuid && + (BLE_STATUS_SUCCESS == ret)) { uint8_t type; uint8_t length; uint8_t *data = NULL; - pr_info(LOG_MODULE_BLE, "ADV Type-%d", _service_uuid.uuid.type); - if (BT_UUID_TYPE_16 == _service_uuid.uuid.type) + pr_info(LOG_MODULE_BLE, "ADV Type-%d", _service_solicit_uuid.uuid.type); + if (BT_UUID_TYPE_16 == _service_solicit_uuid.uuid.type) { - //UINT16_TO_LESTREAM(adv_tmp, uuid.uuid16); - data = (uint8_t *)&(((bt_uuid_16_t *)&_service_uuid)->val); + data = (uint8_t *)&(((bt_uuid_16_t *)&_service_solicit_uuid)->val); length = UUID_SIZE_16; - type = BT_DATA_UUID16_ALL; + type = BT_DATA_SOLICIT16; } - else // Sid. KW, default is BT_UUID_TYPE_128 + else // Sid. KW, default is BT_UUID_TYPE_128 { - data = _service_uuid.val; + data = _service_solicit_uuid.val; length = UUID_SIZE_128; - type = BT_DATA_UUID128_ALL; - } - - // if (data) // Sid. KW, data is always initialized - { - _adv_data[_adv_data_idx].type = type; - _adv_data[_adv_data_idx].data = data; - _adv_data[_adv_data_idx].data_len = length; - _adv_data_idx++; - lengthTotal += length; - - pr_info(LOG_MODULE_BLE, "Service UUID Len -%d", length); + type = BT_DATA_SOLICIT128; } + + ret = setAdvertiseData(type, data, length); } - if (_has_service_solicit_uuid) + if (_has_service_uuid && + (BLE_STATUS_SUCCESS == ret)) { uint8_t type; uint8_t length; uint8_t *data = NULL; - pr_info(LOG_MODULE_BLE, "ADV Type-%d", _service_solicit_uuid.uuid.type); - if (BT_UUID_TYPE_16 == _service_solicit_uuid.uuid.type) + pr_info(LOG_MODULE_BLE, "ADV Type-%d", _service_uuid.uuid.type); + if (BT_UUID_TYPE_16 == _service_uuid.uuid.type) { - //UINT16_TO_LESTREAM(adv_tmp, uuid.uuid16); - data = (uint8_t *)&(((bt_uuid_16_t *)&_service_solicit_uuid)->val); + data = (uint8_t *)&(((bt_uuid_16_t *)&_service_uuid)->val); length = UUID_SIZE_16; - type = BT_DATA_SOLICIT16; + type = BT_DATA_UUID16_ALL; } - else // Sid. KW, default is BT_UUID_TYPE_128 + else // Sid. KW, default is BT_UUID_TYPE_128 { - data = _service_solicit_uuid.val; + data = _service_uuid.val; length = UUID_SIZE_128; - type = BT_DATA_SOLICIT128; - } - // Sid. KW, data is always initialized. if (data) - { - _adv_data[_adv_data_idx].type = type; - _adv_data[_adv_data_idx].data = data; - _adv_data[_adv_data_idx].data_len = length; - _adv_data_idx++; - lengthTotal += length; - - pr_info(LOG_MODULE_BLE, "Service UUID Len -%d", length); + type = BT_DATA_UUID128_ALL; } + ret = setAdvertiseData(type, data, length); } - - if (_local_name.length() > 0) + + if (_manufacturer_data_length > 0 && + (BLE_STATUS_SUCCESS == ret)) { - /* Add device name (truncated if too long) */ - _adv_data[_adv_data_idx].type = BT_DATA_NAME_COMPLETE; - _adv_data[_adv_data_idx].data = (const uint8_t*)_local_name.c_str(); - _adv_data[_adv_data_idx].data_len = _local_name.length(); - _adv_data_idx++; - - lengthTotal += _local_name.length(); - pr_info(LOG_MODULE_BLE, "Local Name -%s", _local_name.c_str()); - pr_info(LOG_MODULE_BLE, "Local Name Len -%d", _local_name.length()); + ret = setAdvertiseData (BT_DATA_MANUFACTURER_DATA, + _manufacturer_data, + _manufacturer_data_length); } - - if (_manufacturer_data_length > 0) + + if (_local_name.length() > 0 && + (BLE_STATUS_SUCCESS == ret)) { - // Add manufacturer data - _adv_data[_adv_data_idx].type = BT_DATA_MANUFACTURER_DATA; - _adv_data[_adv_data_idx].data = _manufacturer_data; - _adv_data[_adv_data_idx].data_len = _manufacturer_data_length; - _adv_data_idx++; - - lengthTotal += _manufacturer_data_length; + uint8_t length = _local_name.length(); + ret = setAdvertiseData (BT_DATA_NAME_COMPLETE, + (const uint8_t*)_local_name.c_str(), + length); } - if (_service_data_length > 0) + if (_service_data_length > 0 && + (BLE_STATUS_SUCCESS == ret)) { /* Add Service Data (if it will fit) */ @@ -423,29 +501,18 @@ BLEDeviceManager::_advDataInit(void) return BLE_STATUS_ERROR_PARAMETER; } - _adv_data[_adv_data_idx].type = BT_DATA_SVC_DATA16; - _adv_data[_adv_data_idx].data = _service_data_buf; - _adv_data[_adv_data_idx].data_len = block_len; - _adv_data_idx++; + ret = setAdvertiseData (BT_DATA_SVC_DATA16, + _service_data_buf, + block_len); uint8_t *adv_tmp = _service_data_buf; - //UINT16_TO_LESTREAM(adv_tmp, (((bt_uuid_16_t *)&_service_data_uuid)->val)); memcpy(adv_tmp, &((bt_uuid_16_t*)&_service_data_uuid)->val, sizeof(uint16_t)); adv_tmp += 2; memcpy(adv_tmp, _service_data, _service_data_length); - - lengthTotal += block_len; - pr_info(LOG_MODULE_BLE, "SVC Len -%d", block_len); } - - if (lengthTotal > BLE_MAX_ADV_SIZE) - { - pr_error(LOG_MODULE_BLE, "ADV Total length-%d", lengthTotal); - // Service data block is too large. - return BLE_STATUS_ERROR_PARAMETER; - } - return BLE_STATUS_SUCCESS; + + return ret; } BLE_STATUS_T BLEDeviceManager::startAdvertising() @@ -462,7 +529,9 @@ BLE_STATUS_T BLEDeviceManager::startAdvertising() if (_state != BLE_PERIPH_STATE_READY) return BLE_STATUS_WRONG_STATE; - ret = bt_le_adv_start(&_adv_param, _adv_data, _adv_data_idx, NULL, 0); + ret = bt_le_adv_start(&_adv_param, + _adv_data, _adv_data_idx, + _scan_rsp_data, _scan_rsp_data_idx); if (0 != ret) { pr_error(LOG_MODULE_APP, "[ADV] Start failed. Error: %d", ret); @@ -523,9 +592,32 @@ BLEDevice BLEDeviceManager::peripheral() return temp; } -bool BLEDeviceManager::startScanning() +void BLEDeviceManager::_clearAdvertiseBuffer() +{ + + // Clear the previous found ADV + memset(_peer_temp_adv_buffer, 0, sizeof(_peer_temp_adv_buffer)); + memset(_peer_temp_adv_data, 0, sizeof(_peer_temp_adv_data)); + memset(_peer_temp_adv_data_len, 0, sizeof(_peer_temp_adv_data_len)); + memset(_peer_temp_adv_connectable, 0, sizeof(_peer_adv_connectable)); + + memset(_peer_adv_buffer, 0, sizeof(_peer_adv_buffer)); + memset(_peer_adv_mill, 0, sizeof(_peer_adv_mill)); + memset(_peer_adv_data, 0, sizeof(_peer_adv_data)); + memset(_peer_adv_data_len, 0, sizeof(_peer_adv_data_len)); + memset(_peer_scan_rsp_data, 0, sizeof(_peer_scan_rsp_data)); + memset(_peer_scan_rsp_data_len, 0, sizeof(_peer_scan_rsp_data_len)); + memset(_peer_adv_rssi, 0, sizeof(_peer_adv_rssi)); + +} + +bool BLEDeviceManager::startScanningWithDuplicates() { - _scan_param.filter_dup = BT_HCI_LE_SCAN_FILTER_DUP_ENABLE;//BT_HCI_LE_SCAN_FILTER_DUP_DISABLE; + _adv_duplicate_filter_enabled = false; + _scan_param.filter_dup = BT_HCI_LE_SCAN_FILTER_DUP_ENABLE; + + _clearAdvertiseBuffer(); + int err = bt_le_scan_start(&_scan_param, ble_central_device_found); if (err) { @@ -535,8 +627,14 @@ bool BLEDeviceManager::startScanning() return true; } -bool BLEDeviceManager::startScanningWithDuplicates() +bool BLEDeviceManager::startScanningNewPeripherals() { + _adv_duplicate_filter_enabled = true; + memset(_peer_duplicate_address_buffer, 0, sizeof(_peer_duplicate_address_buffer)); + _duplicate_filter_header = _duplicate_filter_tail = 0; + + _clearAdvertiseBuffer(); + _scan_param.filter_dup = BT_HCI_LE_SCAN_FILTER_DUP_ENABLE; int err = bt_le_scan_start(&_scan_param, ble_central_device_found); if (err) @@ -544,7 +642,7 @@ bool BLEDeviceManager::startScanningWithDuplicates() pr_info(LOG_MODULE_BLE, "Scanning failed to start (err %d)\n", err); return false; } - return false; + return true; } bool BLEDeviceManager::stopScanning() @@ -562,6 +660,7 @@ bool BLEDeviceManager::stopScanning() void BLEDeviceManager::clearAdvertiseCritical() { memset(&_adv_accept_critical, 0, sizeof(_adv_accept_critical)); + memset(&_adv_accept_device, 0, sizeof(_adv_accept_device)); //memset(&_adv_critical_service_uuid, 0, sizeof(_adv_critical_service_uuid)); } @@ -598,48 +697,124 @@ void BLEDeviceManager::setAdvertiseCritical(BLEService& service) _adv_accept_critical.data = data; } -bool BLEDeviceManager::hasLocalName(const BLEDevice* device) const +void BLEDeviceManager::setAdvertiseCritical(const char* macaddress) +{ + BLEUtils::macAddressString2BT(macaddress, _adv_accept_device); +} + +bool BLEDeviceManager::getDataFromAdvertiseByType(const BLEDevice* device, + const uint8_t eir_type, + const uint8_t* &data, + uint8_t &data_len) const { - if (BLEUtils::isLocalBLE(*device) == true) - { - return (_local_name.length() != 0); - } - const uint8_t* adv_data = NULL; uint8_t adv_data_len = 0; + bool retval = false; + bool scan_response_proced = false; + getDeviceAdvertiseBuffer(device->bt_le_address(), adv_data, adv_data_len); - if (NULL == adv_data) - { - return false; - } - - while (adv_data_len > 1) - { - uint8_t len = adv_data[0]; - uint8_t type = adv_data[1]; - /* Check for early termination */ - if (len == 0) + while (NULL != adv_data) + { + while (adv_data_len > 1) { - return false; - } + uint8_t len = adv_data[0]; + uint8_t type = adv_data[1]; - if ((len + 1) > adv_data_len) { // Sid. KW, can't be (adv_data_len < 2) - pr_info(LOG_MODULE_BLE, "AD malformed\n"); - return false; - } + /* Check for early termination */ + if ((len == 0) || ((len + 1) > adv_data_len)) { + break; + } + + if (type == eir_type) + { + if (len >= BLE_MAX_ADV_SIZE) + { + len = BLE_MAX_ADV_SIZE-1; + } + data = &adv_data[2]; + data_len = len - 1; + retval = true; + break; + } - if (type == BT_DATA_NAME_COMPLETE) + adv_data_len -= len + 1; + adv_data += len + 1; + } + if (retval == true || scan_response_proced == true) { - return true; + break; } + getDeviceScanResponseBuffer(device->bt_le_address(), + adv_data, + adv_data_len); + scan_response_proced = true; + } + return retval; +} - adv_data_len -= len + 1; - adv_data += len + 1; + +bool BLEDeviceManager::hasLocalName(const BLEDevice* device) const +{ + if (BLEUtils::isLocalBLE(*device) == true) + { + return (_local_name.length() != 0); } - return false; + + const uint8_t* local_name = NULL; + uint8_t local_name_len = 0; + bool retval = getDataFromAdvertiseByType(device, + BT_DATA_NAME_COMPLETE, + local_name, + local_name_len); + if (false == retval) + { + retval = getDataFromAdvertiseByType(device, + BT_DATA_NAME_SHORTENED, + local_name, + local_name_len); + } + return retval; +} + +bool BLEDeviceManager::hasManufacturerData(const BLEDevice* device) const +{ + if (BLEUtils::isLocalBLE(*device) == true) + { + return (_manufacturer_data_length != 0); + } + + const uint8_t* manufactgurer_data = NULL; + uint8_t manufactgurer_data_len = 0; + return getDataFromAdvertiseByType(device, + BT_DATA_MANUFACTURER_DATA, + manufactgurer_data, + manufactgurer_data_len); +} + +bool BLEDeviceManager::getManufacturerData (const BLEDevice* device, + uint8_t* manu_data, + uint8_t&manu_data_len) const +{ + if (BLEUtils::isLocalBLE(*device) == true) + { + return (_manufacturer_data_length != 0); + } + + const uint8_t* manufactgurer_data = NULL; + uint8_t manufactgurer_data_len = 0; + bool retval = getDataFromAdvertiseByType(device, + BT_DATA_MANUFACTURER_DATA, + manufactgurer_data, + manufactgurer_data_len); + if (retval) + { + memcpy (manu_data, manufactgurer_data, manufactgurer_data_len); + manu_data_len = manufactgurer_data_len; + } + return retval; } bool BLEDeviceManager::hasAdvertisedServiceUuid(const BLEDevice* device) const @@ -694,6 +869,41 @@ void BLEDeviceManager::getDeviceAdvertiseBuffer(const bt_addr_le_t* addr, return; } +void BLEDeviceManager::getDeviceScanResponseBuffer(const bt_addr_le_t* addr, + const uint8_t* &adv_data, + uint8_t &adv_len) const +{ + const bt_addr_le_t* temp = NULL; + // Connected device + for (int i = 0; i < BLE_MAX_CONN_CFG; i++) + { + temp = &_peer_peripheral[i]; + if (bt_addr_le_cmp(temp, addr) == 0) + { + adv_data = _peer_peripheral_scan_rsp_data[i]; + adv_len = _peer_peripheral_scan_rsp_data_len[i]; + return; + } + } + + // Connecting device + if (bt_addr_le_cmp(&_wait_for_connect_peripheral, addr) == 0) + { + adv_data = _wait_for_connect_peripheral_scan_rsp_data; + adv_len = _wait_for_connect_peripheral_scan_rsp_data_len; + return; + } + + // Available device + if (bt_addr_le_cmp(&_available_for_connect_peripheral, addr) == 0) + { + adv_data = _available_for_connect_peripheral_scan_rsp_data; + adv_len = _available_for_connect_peripheral_scan_rsp_data_len; + return; + } + return; +} + int BLEDeviceManager::advertisedServiceUuidCount(const BLEDevice* device) const { const uint8_t* adv_data = NULL; @@ -721,18 +931,18 @@ int BLEDeviceManager::advertisedServiceUuidCount(const BLEDevice* device) const uint8_t type = adv_data[1]; /* Check for early termination */ - if (len == 0) + if (len == 0 || ((len + 1) > adv_data_len)) { return service_cnt; } - if ((len + 1) > adv_data_len) { // Sid. KW, can't be (adv_data_len < 2) - pr_info(LOG_MODULE_BLE, "AD malformed\n"); - return service_cnt; - } - + /* Sid, 2/15/2017. Sandeep reported that Apple devices may use + BT_DATA_UUID16_SOME and BT_DATA_UUID128_SOME in addition to ALL. + Practically, these types are same as ALL. */ if (type == BT_DATA_UUID16_ALL || - type == BT_DATA_UUID128_ALL) + type == BT_DATA_UUID128_ALL || + type == BT_DATA_UUID16_SOME || + type == BT_DATA_UUID128_SOME) { service_cnt++; } @@ -749,54 +959,34 @@ String BLEDeviceManager::localName(const BLEDevice* device) const { return _local_name; } - const uint8_t* adv_data = NULL; - uint8_t adv_data_len = 0; - char localname_string[BLE_MAX_ADV_SIZE]; - memset(localname_string, 0, sizeof(localname_string)); - - getDeviceAdvertiseBuffer(device->bt_le_address(), - adv_data, - adv_data_len); - if (NULL == adv_data) { - String temp(localname_string); - return temp; + const uint8_t* local_name = NULL; + uint8_t local_name_len = 0; + String temp(""); + char local_name_buff[BLE_MAX_ADV_SIZE]; + bool retval = getDataFromAdvertiseByType(device, + BT_DATA_NAME_COMPLETE, + local_name, + local_name_len); + if (false == retval) + { + retval = getDataFromAdvertiseByType(device, + BT_DATA_NAME_SHORTENED, + local_name, + local_name_len); } - while (adv_data_len > 1) + if (true == retval) { - uint8_t len = adv_data[0]; - uint8_t type = adv_data[1]; - - /* Check for early termination */ - if (len == 0) { - String temp(localname_string); - return temp; - } - - if ((len + 1) > adv_data_len) { // Sid. KW, cannot be (adv_data_len < 2) - pr_info(LOG_MODULE_BLE, "AD malformed\n"); - String temp(localname_string); - return temp; - } - - if (type == BT_DATA_NAME_COMPLETE) + if (local_name_len >= BLE_MAX_ADV_SIZE) { - if (len >= BLE_MAX_ADV_SIZE) - { - len = BLE_MAX_ADV_SIZE-1; - } - uint8_t copy_len = len - 1; - memcpy(localname_string, &adv_data[2], copy_len); - localname_string[copy_len] = '\0'; - break; + local_name_len = BLE_MAX_ADV_SIZE - 1; } - - adv_data_len -= len + 1; - adv_data += len + 1; + memcpy(local_name_buff, local_name, local_name_len); + local_name_buff[local_name_len] = '\0'; + temp = local_name_buff; } - - String temp(localname_string); + return temp; } @@ -840,25 +1030,23 @@ String BLEDeviceManager::advertisedServiceUuid(const BLEDevice* device, int inde uint8_t type = adv_data[1]; /* Check for early termination */ - if (len == 0) + if (len == 0 || ((len + 1) > adv_data_len)) { - return String(uuid_string); - } - - if ((len + 1) > adv_data_len) { // Sid. KW, cannot be adv_data_len < 2 - pr_info(LOG_MODULE_BLE, "AD malformed\n"); - return String(uuid_string); + break; } if (type == BT_DATA_UUID16_ALL || - type == BT_DATA_UUID128_ALL) + type == BT_DATA_UUID128_ALL || + type == BT_DATA_UUID16_SOME || + type == BT_DATA_UUID128_SOME) { service_cnt++; } if (index < service_cnt) { - if (type == BT_DATA_UUID16_ALL) + if (type == BT_DATA_UUID16_ALL || + type == BT_DATA_UUID16_SOME) { service_uuid.uuid.type = BT_UUID_TYPE_16; memcpy(&BT_UUID_16(&service_uuid.uuid)->val, &adv_data[2], 2); @@ -914,13 +1102,20 @@ bool BLEDeviceManager::connect(BLEDevice &device) uint64_t timestamp = millis(); uint64_t timestampcur = timestamp; bool ret = true; + if (_available_for_connect_peripheral_connectable == false) + { + return false; + } + bt_addr_le_copy(&_wait_for_connect_peripheral, device.bt_le_address()); // Buffer the ADV data memcpy(_wait_for_connect_peripheral_adv_data, _available_for_connect_peripheral_adv_data, BLE_MAX_ADV_SIZE); + memcpy(_wait_for_connect_peripheral_scan_rsp_data, _available_for_connect_peripheral_scan_rsp_data, BLE_MAX_ADV_SIZE); _wait_for_connect_peripheral_adv_data_len = _available_for_connect_peripheral_adv_data_len; + _wait_for_connect_peripheral_scan_rsp_data_len = _available_for_connect_peripheral_scan_rsp_data_len; _wait_for_connect_peripheral_adv_rssi = _available_for_connect_peripheral_adv_rssi; - - startScanning(); + + startScanningWithDuplicates(); pr_debug(LOG_MODULE_BLE, "%s-%d", __FUNCTION__, __LINE__); // Wait for the connection @@ -986,6 +1181,10 @@ bool BLEDeviceManager::connectToDevice(BLEDevice &device) _wait_for_connect_peripheral_adv_data, BLE_MAX_ADV_SIZE); _peer_peripheral_adv_data_len[i] = _wait_for_connect_peripheral_adv_data_len; + memcpy(_peer_peripheral_scan_rsp_data[i], + _wait_for_connect_peripheral_scan_rsp_data, + BLE_MAX_ADV_SIZE); + _peer_peripheral_scan_rsp_data_len[i] = _wait_for_connect_peripheral_scan_rsp_data_len; _peer_peripheral_adv_rssi[i] = _wait_for_connect_peripheral_adv_rssi; } } @@ -1051,11 +1250,12 @@ void BLEDeviceManager::handleConnectEvent(bt_conn_t *conn, uint8_t err) } else { + // Peripheral has established the connection with this Central device memset(&_wait_for_connect_peripheral, 0, sizeof(_wait_for_connect_peripheral)); _connecting = false; - // Peripheral has established the connection with this Central device - BLEProfileManager::instance()->handleConnectedEvent(bt_conn_get_dst(conn)); } + // The peripheral and central can work as GATT server. Reserve one buffer for peer device + BLEProfileManager::instance()->handleConnectedEvent(bt_conn_get_dst(conn)); if (NULL != _device_events[BLEConnected]) { @@ -1087,6 +1287,8 @@ void BLEDeviceManager::handleDisconnectEvent(bt_conn_t *conn, uint8_t reason) memset(_peer_peripheral_adv_data[i], 0, BLE_MAX_ADV_SIZE); _peer_peripheral_adv_data_len[i] = 0; _peer_peripheral_adv_rssi[i] = 0; + memset(_peer_peripheral_scan_rsp_data[i], 0, BLE_MAX_ADV_SIZE); + _peer_peripheral_scan_rsp_data_len[i] = 0; break; } } @@ -1141,6 +1343,38 @@ bool BLEDeviceManager::advertiseDataProc(uint8_t type, return false; } +bool BLEDeviceManager::deviceInDuplicateFilterBuffer(const bt_addr_le_t* addr) +{ + bool retVal = false; + for (uint8_t i = 0; + i < (sizeof(_peer_duplicate_address_buffer) / sizeof(bt_addr_le_t)); + i++) + { + if (0 == bt_addr_le_cmp(addr, &_peer_duplicate_address_buffer[i])) + { + retVal = true; + break; + } + } + return retVal; +} + +void BLEDeviceManager::updateDuplicateFilter(const bt_addr_le_t* addr) +{ + uint8_t i = (_duplicate_filter_header + 1) % (ARRAY_SIZE(_peer_duplicate_address_buffer)); + if (deviceInDuplicateFilterBuffer(addr)) + { + return; + } + bt_addr_le_copy(&_peer_duplicate_address_buffer[_duplicate_filter_header], + addr); + if (i == _duplicate_filter_tail) + { + _duplicate_filter_tail = (_duplicate_filter_tail + 1) % (ARRAY_SIZE(_peer_duplicate_address_buffer)); + } + _duplicate_filter_header = i; +} + BLEDevice BLEDeviceManager::available() { BLEDevice tempdevice; @@ -1154,8 +1388,15 @@ BLEDevice BLEDeviceManager::available() { uint64_t timestamp_delta = timestamp - _peer_adv_mill[i]; temp = &_peer_adv_buffer[i]; - if ((timestamp_delta <= 2000) && (max_delta < timestamp_delta)) + if ((timestamp_delta <= 2000) && (max_delta < timestamp_delta) && (_peer_scan_rsp_data_len[i] >= 0 || !_peer_adv_connectable[i])) { + // Eable the duplicate filter + if (_adv_duplicate_filter_enabled && + true == deviceInDuplicateFilterBuffer(temp)) + { + _peer_adv_mill[i] -= 2000; // Invalid the item + continue; + } max_delta = timestamp_delta; index = i; } @@ -1170,11 +1411,17 @@ BLEDevice BLEDeviceManager::available() tempdevice.setAddress(*temp); bt_addr_le_copy(&_available_for_connect_peripheral, temp); memcpy(_available_for_connect_peripheral_adv_data, _peer_adv_data[index], BLE_MAX_ADV_SIZE); + memcpy(_available_for_connect_peripheral_scan_rsp_data, _peer_scan_rsp_data[index], BLE_MAX_ADV_SIZE); + _available_for_connect_peripheral_scan_rsp_data_len = _peer_scan_rsp_data_len[index]; _available_for_connect_peripheral_adv_data_len = _peer_adv_data_len[index]; _available_for_connect_peripheral_adv_rssi = _peer_adv_rssi[index]; - - pr_debug(LOG_MODULE_BLE, "%s-%d:Con addr-%s", __FUNCTION__, __LINE__, BLEUtils::macAddressBT2String(*temp).c_str()); + _available_for_connect_peripheral_connectable = _peer_adv_connectable[index]; + //pr_debug(LOG_MODULE_BLE, "%s-%d:Con addr-%s", __FUNCTION__, __LINE__, BLEUtils::macAddressBT2String(*temp).c_str()); _peer_adv_mill[index] -= 2000; // Set it as expired + if (_adv_duplicate_filter_enabled) + { + updateDuplicateFilter(temp); + } } } return tempdevice; @@ -1183,7 +1430,8 @@ BLEDevice BLEDeviceManager::available() bool BLEDeviceManager::setAdvertiseBuffer(const bt_addr_le_t* bt_addr, const uint8_t *ad, uint8_t data_len, - int8_t rssi) + int8_t rssi, + bool connectable) { bt_addr_le_t* temp = NULL; uint64_t timestamp = millis(); @@ -1200,7 +1448,10 @@ bool BLEDeviceManager::setAdvertiseBuffer(const bt_addr_le_t* bt_addr, { max_delta = timestamp_delta; if (max_delta > 2000) // expired + { index = i; + _peer_scan_rsp_data_len[index] = -1; // Invalid the scan response + } } if (bt_addr_le_cmp(temp, bt_addr) == 0) @@ -1229,12 +1480,163 @@ bool BLEDeviceManager::setAdvertiseBuffer(const bt_addr_le_t* bt_addr, _peer_adv_rssi[index] = rssi; // Update the timestamp _peer_adv_mill[index] = timestamp; + _peer_adv_connectable[index] = connectable; + retval = true; + } + + return retval; +} + +bool BLEDeviceManager::setScanRespBuffer(const bt_addr_le_t* bt_addr, + const uint8_t *ad, + uint8_t data_len, + int8_t rssi) +{ + bt_addr_le_t* temp = NULL; + uint64_t timestamp = millis(); + uint8_t index = BLE_MAX_ADV_BUFFER_CFG; + uint8_t i = 0; + bool retval = false; + //pr_debug(LOG_MODULE_BLE, "%s-%d-1", __FUNCTION__, __LINE__); + for (i = 0; i < BLE_MAX_ADV_BUFFER_CFG; i++) + { + temp = &_peer_adv_buffer[i]; + + if (bt_addr_le_cmp(temp, bt_addr) == 0) + { + // The device alread in the buffer + index = i; + break; + } + } + + //pr_debug(LOG_MODULE_BLE, "%s-%d", __FUNCTION__, __LINE__); + if (index < BLE_MAX_ADV_BUFFER_CFG) + { + if (data_len > BLE_MAX_ADV_SIZE) + { + data_len = BLE_MAX_ADV_SIZE; + } + memcpy(_peer_scan_rsp_data[index], ad, data_len); + _peer_scan_rsp_data_len[index] = data_len; + //_peer_adv_rssi[index] = rssi; + // Update the timestamp + _peer_adv_mill[index] = timestamp; retval = true; } return retval; } + +uint8_t BLEDeviceManager::getTempAdvertiseIndexFromBuffer(const bt_addr_le_t* bt_addr) +{ + bt_addr_le_t* temp = NULL; + uint8_t i = 0; + + for (i = 0; i < BLE_MAX_ADV_BUFFER_CFG; i++) + { + temp = &_peer_temp_adv_buffer[i]; + + if (bt_addr_le_cmp(temp, bt_addr) == 0) + { + // The device alread in the buffer + break; + } + } + + return i; +} + +void BLEDeviceManager::setTempAdvertiseBuffer(const bt_addr_le_t* bt_addr, + int8_t rssi, + const uint8_t *ad, + uint8_t data_len, + bool connectable) +{ + bt_addr_le_t* temp = NULL; + uint8_t i = getTempAdvertiseIndexFromBuffer(bt_addr); + if (i >= BLE_MAX_ADV_BUFFER_CFG) + { + _peer_temp_dev_index = (_peer_temp_dev_index + 1) % BLE_MAX_ADV_BUFFER_CFG; + i = _peer_temp_dev_index; + } + + temp = &_peer_temp_adv_buffer[i]; + memcpy(temp, bt_addr, sizeof (bt_addr_le_t)); + if (data_len > BLE_MAX_ADV_SIZE) + { + data_len = BLE_MAX_ADV_SIZE; + } + + memcpy(_peer_temp_adv_data[i], ad, data_len); + _peer_temp_adv_data_len[i] = data_len; + _peer_temp_adv_connectable[i] = connectable; + + return; +} + +void BLEDeviceManager::advertiseAcceptHandler(const bt_addr_le_t *addr, + int8_t rssi, + uint8_t type, + const uint8_t *ad, + uint8_t data_len) +{ + if (true == BLEUtils::macAddressValid(_wait_for_connect_peripheral)) + { + // Not add to the buffer when try to establish the connection + if (true == BLEUtils::macAddressSame(*addr, _wait_for_connect_peripheral)) + { + BLEDevice testdev(addr); + stopScanning(); + connectToDevice(testdev); + } + } + else + { + const uint8_t *adv_data = ad; + uint8_t adv_data_len = data_len; + bool connectable = (BT_LE_ADV_NONCONN_IND != type); + bool update_advertise_data = true; + // The critical is accepted + // Find the oldest and expired buffer + if (BT_LE_ADV_SCAN_RSP == type) + { + update_advertise_data = false; + pr_debug(LOG_MODULE_BLE, "%s-%d", __FUNCTION__, __LINE__); + if (false == setScanRespBuffer(addr, ad, data_len, rssi)) + { + // Find the device in the ADV temp buffer + uint8_t tempIndex = getTempAdvertiseIndexFromBuffer(addr); + if (tempIndex < BLE_MAX_ADV_BUFFER_CFG) + { + adv_data = _peer_temp_adv_data[tempIndex]; + adv_data_len = _peer_temp_adv_data_len[tempIndex]; + connectable = _peer_temp_adv_connectable[tempIndex]; + update_advertise_data = true; + } + } + } + pr_debug(LOG_MODULE_BLE, "%s-%d", __FUNCTION__, __LINE__); + + if (true == update_advertise_data) + { + if (false == setAdvertiseBuffer(addr, + adv_data, + adv_data_len, + rssi, + connectable)) + { + pr_info(LOG_MODULE_BLE, "No buffer to store the ADV\n"); + } + else if (BT_LE_ADV_SCAN_RSP == type) + { + setScanRespBuffer(addr, ad, data_len, rssi); + } + } + } +} + void BLEDeviceManager::handleDeviceFound(const bt_addr_le_t *addr, int8_t rssi, uint8_t type, @@ -1245,53 +1647,52 @@ void BLEDeviceManager::handleDeviceFound(const bt_addr_le_t *addr, uint8_t real_adv_len = data_len; /* We're only interested in connectable events */ - if (type == BT_LE_ADV_IND || type == BT_LE_ADV_DIRECT_IND) + //pr_debug(LOG_MODULE_BLE, "%s-%d", __FUNCTION__, __LINE__); + // Filter address + if (BLEUtils::macAddressValid(_adv_accept_device) == true && + (memcmp(addr->val, _adv_accept_device.val, sizeof (addr->val)) != 0)) { - //pr_debug(LOG_MODULE_BLE, "%s-%d", __FUNCTION__, __LINE__); - while (data_len > 1) - { - uint8_t len = data[0]; - - /* Check for early termination */ - if (len == 0) - { - return; - } + pr_debug(LOG_MODULE_BLE, "%s-%d", __FUNCTION__, __LINE__); + return; + } + + while (data_len > 1) + { + uint8_t len = data[0]; - if ((len + 1) > data_len) { // Sid. KW, cannot be (data_len < 2) - pr_info(LOG_MODULE_BLE, "AD malformed\n"); - return; - } + /* Check for early termination */ + if (len == 0) + { + return; + } - if (true == advertiseDataProc(data[1], &data[2], len - 1)) - { - if (true == BLEUtils::macAddressValid(_wait_for_connect_peripheral)) - { - // Not add to the buffer when try to establish the connection - if (true == BLEUtils::macAddressSame(*addr, _wait_for_connect_peripheral)) - { - BLEDevice testdev(addr); - stopScanning(); - connectToDevice(testdev); - } - } - else - { - // The critical is accepted - // Find the oldest and expired buffer - if(false == setAdvertiseBuffer(addr, ad, real_adv_len, rssi)) - { - pr_info(LOG_MODULE_BLE, "No buffer to store the ADV\n"); - } - } - pr_debug(LOG_MODULE_BLE, "%s-%d: Done", __FUNCTION__, __LINE__); - return; - } + if ((len + 1) > data_len) { // Sid. KW, cannot be (data_len < 2) + pr_info(LOG_MODULE_BLE, "AD malformed\n"); + return; + } - data_len -= len + 1; - data += len + 1; + if (true == advertiseDataProc(data[1], &data[2], len - 1)) + { + advertiseAcceptHandler(addr, rssi, type, ad, real_adv_len); + //pr_debug(LOG_MODULE_BLE, "%s-%d: Done", __FUNCTION__, __LINE__); + return; } - //pr_debug(LOG_MODULE_BLE, "%s: done", __FUNCTION__); + + data_len -= len + 1; + data += len + 1; + } + //pr_debug(LOG_MODULE_BLE, "%s: done", __FUNCTION__); + // Doesn't accept the ADV/scan data + // Check it in the buffer + if (BT_LE_ADV_SCAN_RSP == type) + { + // Find the ADV and set response + setScanRespBuffer(addr, ad, real_adv_len, rssi); + } + else + { + // Add advertise into buffer + setTempAdvertiseBuffer(addr, rssi, ad, real_adv_len, BT_LE_ADV_NONCONN_IND != type); } } diff --git a/libraries/CurieBLE/src/internal/BLEDeviceManager.h b/libraries/CurieBLE/src/internal/BLEDeviceManager.h index 3ad80a41..60aa6f17 100644 --- a/libraries/CurieBLE/src/internal/BLEDeviceManager.h +++ b/libraries/CurieBLE/src/internal/BLEDeviceManager.h @@ -140,6 +140,10 @@ class BLEDeviceManager */ void setManufacturerData(const unsigned char manufacturerData[], unsigned char manufacturerDataLength); + bool getManufacturerData (const BLEDevice* device, + uint8_t* manu_data, + uint8_t&manu_data_len) const; + bool hasManufacturerData(const BLEDevice* device) const; /** * Set the local name that the BLE Peripheral Device advertises @@ -177,26 +181,9 @@ class BLEDeviceManager * * @note none */ - void setConnectionInterval(float minimumConnectionInterval, - float maximumConnectionInterval, - uint16_t latency, - uint16_t timeout); - - /** - * @brief Set the min and max connection interval and send connection - * update request in both BLE peripheral and central - * - * @param[in] intervalmin Minimum Connection Interval (ms) - * - * @param[in] intervalmax Maximum Connection Interval (ms) - * - * @return none - * - * @note none - */ - void setConnectionInterval(float minimumConnectionInterval, - float maximumConnectionInterval); - + int setConnectionInterval (BLEDevice *device); + void getConnectionInterval(BLEDevice *device, + bt_le_conn_param* conn_param); /** * @brief Set TX power of the radio in dBM * @@ -305,7 +292,8 @@ class BLEDeviceManager void clearAdvertiseCritical(); void setAdvertiseCritical(String name); void setAdvertiseCritical(BLEService& service); - bool startScanning(); // start scanning for peripherals + void setAdvertiseCritical(const char* macaddress); + bool startScanningNewPeripherals(); // start scanning for new peripherals, don't report the detected ones bool startScanningWithDuplicates(); // start scanning for peripherals, and report all duplicates bool stopScanning(); // stop scanning for peripherals @@ -349,18 +337,47 @@ class BLEDeviceManager protected: private: + BLE_STATUS_T setAdvertiseData (uint8_t type, + const uint8_t* data, + uint8_t length); BLE_STATUS_T _advDataInit(void); + void _clearAdvertiseBuffer(); bool advertiseDataProc(uint8_t type, const uint8_t *dataPtr, uint8_t data_len); bool setAdvertiseBuffer(const bt_addr_le_t* bt_addr, const uint8_t *ad, uint8_t data_len, - int8_t rssi); + int8_t rssi, + bool connectable); void getDeviceAdvertiseBuffer(const bt_addr_le_t* addr, const uint8_t* &adv_data, uint8_t &adv_len) const; + bool setScanRespBuffer(const bt_addr_le_t* bt_addr, + const uint8_t *ad, + uint8_t data_len, + int8_t rssi); + void getDeviceScanResponseBuffer(const bt_addr_le_t* addr, + const uint8_t* &adv_data, + uint8_t &adv_len) const; + bool getDataFromAdvertiseByType(const BLEDevice* device, + const uint8_t eir_type, + const uint8_t* &data, + uint8_t &data_len) const; bool disconnectSingle(const bt_addr_le_t *peer); + void updateDuplicateFilter(const bt_addr_le_t* addr); + bool deviceInDuplicateFilterBuffer(const bt_addr_le_t* addr); + void advertiseAcceptHandler(const bt_addr_le_t *addr, + int8_t rssi, + uint8_t type, + const uint8_t *ad, + uint8_t data_len); + void setTempAdvertiseBuffer(const bt_addr_le_t* bt_addr, + int8_t rssi, + const uint8_t *ad, + uint8_t data_len, + bool connectable); + uint8_t getTempAdvertiseIndexFromBuffer(const bt_addr_le_t* bt_addr); private: uint16_t _min_conn_interval; @@ -374,20 +391,38 @@ class BLEDeviceManager uint64_t _peer_adv_mill[BLE_MAX_ADV_BUFFER_CFG]; // The ADV found time stamp uint8_t _peer_adv_data[BLE_MAX_ADV_BUFFER_CFG][BLE_MAX_ADV_SIZE]; uint8_t _peer_adv_data_len[BLE_MAX_ADV_BUFFER_CFG]; + uint8_t _peer_scan_rsp_data[BLE_MAX_ADV_BUFFER_CFG][BLE_MAX_ADV_SIZE]; + int8_t _peer_scan_rsp_data_len[BLE_MAX_ADV_BUFFER_CFG]; int8_t _peer_adv_rssi[BLE_MAX_ADV_BUFFER_CFG]; + bool _peer_adv_connectable[BLE_MAX_ADV_BUFFER_CFG]; + + // The accept critical may include in scan response + bt_addr_le_t _peer_temp_adv_buffer[BLE_MAX_ADV_BUFFER_CFG]; + uint8_t _peer_temp_dev_index; + uint8_t _peer_temp_adv_data[BLE_MAX_ADV_BUFFER_CFG][BLE_MAX_ADV_SIZE]; + uint8_t _peer_temp_adv_data_len[BLE_MAX_ADV_BUFFER_CFG]; + bool _peer_temp_adv_connectable[BLE_MAX_ADV_BUFFER_CFG]; + + // The critical for central scan bt_data_t _adv_accept_critical; // The filters for central device String _adv_critical_local_name; bt_uuid_128_t _adv_critical_service_uuid; + bt_addr_le_t _adv_accept_device; bt_addr_le_t _wait_for_connect_peripheral; uint8_t _wait_for_connect_peripheral_adv_data[BLE_MAX_ADV_SIZE]; uint8_t _wait_for_connect_peripheral_adv_data_len; + uint8_t _wait_for_connect_peripheral_scan_rsp_data[BLE_MAX_ADV_SIZE]; + uint8_t _wait_for_connect_peripheral_scan_rsp_data_len; int8_t _wait_for_connect_peripheral_adv_rssi; bt_addr_le_t _available_for_connect_peripheral; uint8_t _available_for_connect_peripheral_adv_data[BLE_MAX_ADV_SIZE]; uint8_t _available_for_connect_peripheral_adv_data_len; + uint8_t _available_for_connect_peripheral_scan_rsp_data[BLE_MAX_ADV_SIZE]; + uint8_t _available_for_connect_peripheral_scan_rsp_data_len; int8_t _available_for_connect_peripheral_adv_rssi; + bool _available_for_connect_peripheral_connectable; volatile bool _connecting; // For peripheral @@ -408,6 +443,8 @@ class BLEDeviceManager uint8_t _adv_type; bt_data_t _adv_data[6]; // KW: fount _advDataInit() can use 6 slots. size_t _adv_data_idx; + bt_data_t _scan_rsp_data[6]; + size_t _scan_rsp_data_idx; String _local_name; // Peripheral states @@ -429,7 +466,13 @@ class BLEDeviceManager uint8_t _peer_peripheral_index; uint8_t _peer_peripheral_adv_data[BLE_MAX_CONN_CFG][BLE_MAX_ADV_SIZE]; uint8_t _peer_peripheral_adv_data_len[BLE_MAX_CONN_CFG]; + uint8_t _peer_peripheral_scan_rsp_data[BLE_MAX_CONN_CFG][BLE_MAX_ADV_SIZE]; + uint8_t _peer_peripheral_scan_rsp_data_len[BLE_MAX_CONN_CFG]; uint8_t _peer_peripheral_adv_rssi[BLE_MAX_CONN_CFG]; + bt_addr_le_t _peer_duplicate_address_buffer[BLE_MAX_ADV_FILTER_SIZE_CFG]; + uint8_t _duplicate_filter_header; + uint8_t _duplicate_filter_tail; + bool _adv_duplicate_filter_enabled; BLEDeviceEventHandler _device_events[BLEDeviceLastEvent]; }; diff --git a/libraries/CurieBLE/src/internal/BLEProfileManager.cpp b/libraries/CurieBLE/src/internal/BLEProfileManager.cpp index c3b9cd58..aba7981b 100644 --- a/libraries/CurieBLE/src/internal/BLEProfileManager.cpp +++ b/libraries/CurieBLE/src/internal/BLEProfileManager.cpp @@ -25,7 +25,7 @@ #include "BLECallbacks.h" #include "BLEUtils.h" -BLEDevice BLE; +BLEDevice BLE(BLEUtils::bleGetLoalAddress()); BLEProfileManager* BLEProfileManager::_instance = NULL; @@ -337,6 +337,30 @@ void BLEProfileManager::clearProfile(BLEServiceLinkNodeHeader* serviceHeader) } } +BLEDescriptorImp* BLEProfileManager::descriptor(const BLEDevice &bledevice, uint16_t handle) +{ + BLEDescriptorImp* descriptorImp = NULL; + BLEServiceLinkNodeHeader* serviceHeader = getServiceHeader(bledevice); + if (NULL == serviceHeader) + { + // Doesn't find the service + return NULL; + } + + BLEServiceNodePtr node = serviceHeader->next; + while (node != NULL) + { + BLEServiceImp *service = node->value; + descriptorImp = service->descriptor(handle); + if (NULL != descriptorImp) + { + break; + } + node = node->next; + } + return descriptorImp; +} + BLECharacteristicImp* BLEProfileManager::characteristic(const BLEDevice &bledevice, int index) { BLECharacteristicImp* characteristicImp = NULL; @@ -507,6 +531,40 @@ BLEServiceImp* BLEProfileManager::service(const BLEDevice &bledevice, int index) return serviceImp; } +BLEServiceImp* BLEProfileManager::getServiceBySubHandle(const BLEDevice &bledevice, uint16_t handle) const +{ + BLEServiceImp* serviceImp = NULL; + uint16_t start_handle; + uint16_t end_handle; + + const BLEServiceLinkNodeHeader* serviceHeader = getServiceHeader(bledevice); + if (NULL == serviceHeader) + { + // Doesn't find the service + return NULL; + } + BLEServiceNodePtr node = serviceHeader->next; + + while (node != NULL) + { + serviceImp = node->value; + start_handle = serviceImp->startHandle(); + end_handle = serviceImp->endHandle(); + if (handle >= start_handle && handle <= end_handle) + { + break; + } + node = node->next; + } + + if (NULL == node) + { + serviceImp = NULL; + } + + return serviceImp; +} + void BLEProfileManager::handleConnectedEvent(const bt_addr_le_t* deviceAddr) { int index = getUnusedIndex(); diff --git a/libraries/CurieBLE/src/internal/BLEProfileManager.h b/libraries/CurieBLE/src/internal/BLEProfileManager.h index 02c42c9c..1c05fc99 100644 --- a/libraries/CurieBLE/src/internal/BLEProfileManager.h +++ b/libraries/CurieBLE/src/internal/BLEProfileManager.h @@ -73,6 +73,7 @@ class BLEProfileManager{ inline bool hasRegisterProfile(){return _profile_registered;} + BLEDescriptorImp* descriptor(const BLEDevice &bledevice, uint16_t handle); /** * @brief Get the BLE's Characteristic implementation object by uuid and index * @@ -98,6 +99,7 @@ class BLEProfileManager{ BLEServiceImp* service(const BLEDevice &bledevice, const char * uuid) const; BLEServiceImp* service(const BLEDevice &bledevice, int index) const; BLEServiceImp* service(const BLEDevice &bledevice, const bt_uuid_t* uuid) const; + BLEServiceImp* getServiceBySubHandle(const BLEDevice &bledevice, uint16_t handle) const; int serviceCount(const BLEDevice &bledevice) const; int characteristicCount(const BLEDevice &bledevice) const; diff --git a/libraries/CurieBLE/src/internal/BLEServiceImp.cpp b/libraries/CurieBLE/src/internal/BLEServiceImp.cpp index 4f4d3dc1..d5d7afe6 100644 --- a/libraries/CurieBLE/src/internal/BLEServiceImp.cpp +++ b/libraries/CurieBLE/src/internal/BLEServiceImp.cpp @@ -26,6 +26,7 @@ #include "BLECharacteristicImp.h" bt_uuid_16_t BLEServiceImp::_gatt_primary_uuid = {BT_UUID_TYPE_16, BT_UUID_GATT_PRIMARY_VAL}; +bt_gatt_read_params_t BLEServiceImp::_read_params; bt_uuid_t *BLEServiceImp::getPrimayUuid(void) { @@ -36,6 +37,7 @@ BLEServiceImp::BLEServiceImp(BLEService& service): BLEAttribute(service.uuid(), BLETypeService), _start_handle(0), _end_handle(0xFFFF), + _reading(false), _cur_discover_chrc(NULL) { memset(&_characteristics_header, 0, sizeof(_characteristics_header)); @@ -46,6 +48,7 @@ BLEServiceImp::BLEServiceImp(const bt_uuid_t* uuid): BLEAttribute(uuid, BLETypeService), _start_handle(0), _end_handle(0xFFFF), + _reading(false), _cur_discover_chrc(NULL) { memset(&_characteristics_header, 0, sizeof(_characteristics_header)); @@ -174,6 +177,29 @@ void BLEServiceImp::releaseCharacteristic() } +BLEDescriptorImp* BLEServiceImp::descriptor(uint16_t handle) +{ + BLEDescriptorImp* descriptorImp = NULL; + + BLECharacteristicImp* characteristicImp = NULL; + BLECharacteristicNodePtr node = link_node_get_first(&_characteristics_header); + while (NULL != node) + { + characteristicImp = node->value; + descriptorImp = characteristicImp->descriptor(handle); + if (descriptorImp != NULL) + { + break; + } + node = node->next; + } + if (NULL == node) + { + descriptorImp = NULL; + } + return descriptorImp; +} + BLECharacteristicImp* BLEServiceImp::characteristic(int index) { BLECharacteristicImp* characteristicImp = NULL; @@ -242,10 +268,17 @@ BLECharacteristicImp* BLEServiceImp::characteristic(const char* uuid) bool BLEServiceImp::discovering() { - return (_cur_discover_chrc != NULL); + return (_cur_discover_chrc != NULL || _reading); } bool BLEServiceImp::discoverAttributes(BLEDevice* device) +{ + return discoverAttributes(device, _start_handle, _end_handle); +} + +bool BLEServiceImp::discoverAttributes(BLEDevice* device, + uint16_t start_handle, + uint16_t end_handle) { pr_debug(LOG_MODULE_BLE, "%s-%d", __FUNCTION__, __LINE__); int err; @@ -273,8 +306,8 @@ bool BLEServiceImp::discoverAttributes(BLEDevice* device) return false; } temp = &_discover_params; - temp->start_handle = _start_handle; - temp->end_handle = _end_handle; + temp->start_handle = start_handle; + temp->end_handle = end_handle; temp->uuid = NULL; temp->type = BT_GATT_DISCOVER_CHARACTERISTIC; temp->func = profile_discover_process; @@ -309,21 +342,34 @@ uint8_t BLEServiceImp::discoverResponseProc(bt_conn_t *conn, //const bt_uuid_t* chrc_uuid = attr->uuid; uint16_t chrc_handle = attr->handle + 1; struct bt_gatt_chrc* psttemp = (struct bt_gatt_chrc*)attr->user_data; - int retval = (int)addCharacteristic(device, - psttemp->uuid, - chrc_handle, - psttemp->properties); + const bt_uuid_t* chrc_uuid = psttemp->uuid; - //pr_debug(LOG_MODULE_BLE, "%s-%d:handle-%d:%d", __FUNCTION__, __LINE__,attr->handle, chrc_handle); - if (BLE_STATUS_SUCCESS != retval) + uint16_t le16; + memcpy(&le16, &BT_UUID_16(chrc_uuid)->val, sizeof(le16)); + if (chrc_uuid->type == BT_UUID_TYPE_16 && + le16 == 0) { - pr_error(LOG_MODULE_BLE, "%s-%d: Error-%d", - __FUNCTION__, __LINE__, retval); - errno = ENOMEM; + // Read the UUID + readCharacteristic(device, chrc_handle); + retVal = BT_GATT_ITER_CONTINUE; } else { - retVal = BT_GATT_ITER_CONTINUE; + int retval = (int)addCharacteristic(device, + psttemp->uuid, + chrc_handle, + psttemp->properties); + + if (BLE_STATUS_SUCCESS != retval) + { + pr_error(LOG_MODULE_BLE, "%s-%d: Error-%d", + __FUNCTION__, __LINE__, retval); + errno = ENOMEM; + } + else + { + retVal = BT_GATT_ITER_CONTINUE; + } } } break; @@ -335,8 +381,8 @@ uint8_t BLEServiceImp::discoverResponseProc(bt_conn_t *conn, if (NULL != _cur_discover_chrc) { retVal = _cur_discover_chrc->discoverResponseProc(conn, - attr, - params); + attr, + params); } break; } @@ -347,7 +393,7 @@ uint8_t BLEServiceImp::discoverResponseProc(bt_conn_t *conn, } } - pr_debug(LOG_MODULE_BLE, "%s-%d:ret-%d",__FUNCTION__, __LINE__, retVal); + //pr_debug(LOG_MODULE_BLE, "%s-%d:ret-%d",__FUNCTION__, __LINE__, retVal); if (retVal == BT_GATT_ITER_STOP) { if (errno == ENOMEM) @@ -355,36 +401,135 @@ uint8_t BLEServiceImp::discoverResponseProc(bt_conn_t *conn, _cur_discover_chrc = NULL; return retVal; } - const BLECharacteristicLinkNodeHeader* chrcHeader = &_characteristics_header; - BLECharacteristicImp* chrcCurImp = NULL; - BLECharacteristicNodePtr node = chrcHeader->next; - pr_debug(LOG_MODULE_BLE, "%s-%d: node-%p",__FUNCTION__, __LINE__, node); - // Discover next service - while (node != NULL) + if (false == _reading) { - chrcCurImp = node->value; - - if (NULL == _cur_discover_chrc) + discoverNextCharacteristic(device); + } + } + return retVal; +} + +void BLEServiceImp::discoverNextCharacteristic(BLEDevice &bledevice) +{ + const BLECharacteristicLinkNodeHeader* chrcHeader = &_characteristics_header; + BLECharacteristicImp* chrcCurImp = NULL; + BLECharacteristicNodePtr node = chrcHeader->next; + + //pr_debug(LOG_MODULE_BLE, "%s-%d: node-%p",__FUNCTION__, __LINE__, node); + // Discover next service + while (node != NULL) + { + chrcCurImp = node->value; + + if (NULL == _cur_discover_chrc) + { + bool result = chrcCurImp->discoverAttributes(&bledevice); + pr_debug(LOG_MODULE_BLE, "%s-%d",__FUNCTION__, __LINE__); + if (result == true) { - bool result = chrcCurImp->discoverAttributes(&device); - pr_debug(LOG_MODULE_BLE, "%s-%d",__FUNCTION__, __LINE__); - if (result == true) - { - // Record the current discovering service - _cur_discover_chrc = chrcCurImp; - break; - } + // Record the current discovering service + _cur_discover_chrc = chrcCurImp; + break; } - else if (_cur_discover_chrc == chrcCurImp) + } + else if (_cur_discover_chrc == chrcCurImp) + { + // Find next discoverable service + _cur_discover_chrc = NULL; + } + node = node->next; + } +} + +bool BLEServiceImp::readCharacteristic(const BLEDevice &bledevice, uint16_t handle) +{ + int retval = 0; + bt_conn_t* conn = NULL; + + if (true == BLEUtils::isLocalBLE(bledevice)) + { + // GATT server can't write + return false; + } + + if (_reading) + { + return false; + } + + _read_params.func = profile_characteristic_read_rsp_process; + _read_params.handle_count = 1; + _read_params.single.handle = handle - 1; + _read_params.single.offset = 0; + + if (0 == _read_params.single.handle) + { + // Discover not complete + return false; + } + + conn = bt_conn_lookup_addr_le(bledevice.bt_le_address()); + if (NULL == conn) + { + return false; + } + // Send read request + retval = bt_gatt_read(conn, &_read_params); + bt_conn_unref(conn); + if (0 == retval) + { + _reading = true; + } + pr_debug(LOG_MODULE_BLE, "%s-%d", __FUNCTION__, __LINE__); + return _reading; +} + +uint8_t BLEServiceImp::characteristicReadRspProc(bt_conn_t *conn, + int err, + bt_gatt_read_params_t *params, + const void *data, + uint16_t length) +{ + _reading = false; + if (NULL == data) + { + return BT_GATT_ITER_STOP; + } + BLEDevice bleDevice(bt_conn_get_dst(conn)); + + pr_debug(LOG_MODULE_BLE, "%s-%d:length-%d", __FUNCTION__, __LINE__, length); + if (length == UUID_SIZE_128 + 3) + { + const uint8_t* rspdata = (const uint8_t*) data; + bt_uuid_128_t uuid_tmp; + uint16_t chrc_handle = rspdata[1] | (rspdata[2] << 8); + uuid_tmp.uuid.type = BT_UUID_TYPE_128; + memcpy(uuid_tmp.val, &rspdata[3], UUID_SIZE_128); + int retval = (int)addCharacteristic(bleDevice, + (const bt_uuid_t*)&uuid_tmp, + chrc_handle, + rspdata[0]); + + if (BLE_STATUS_SUCCESS != retval) + { + pr_error(LOG_MODULE_BLE, "%s-%d: Error-%d", + __FUNCTION__, __LINE__, retval); + errno = ENOMEM; + } + else + { + if (false == discovering()) { - // Find next discoverable service - _cur_discover_chrc = NULL; + if (false == discoverAttributes(&bleDevice, chrc_handle + 1, _end_handle)) + { + discoverNextCharacteristic(bleDevice); + } } - node = node->next; } } - return retVal; + pr_debug(LOG_MODULE_BLE, "%s-%d", __FUNCTION__, __LINE__); + + return BT_GATT_ITER_STOP; } - diff --git a/libraries/CurieBLE/src/internal/BLEServiceImp.h b/libraries/CurieBLE/src/internal/BLEServiceImp.h index d6c63389..f40ffd36 100644 --- a/libraries/CurieBLE/src/internal/BLEServiceImp.h +++ b/libraries/CurieBLE/src/internal/BLEServiceImp.h @@ -57,6 +57,8 @@ class BLEServiceImp: public BLEAttribute{ uint16_t handle, unsigned char properties); int getCharacteristicCount(); + + BLEDescriptorImp* descriptor(uint16_t handle); BLECharacteristicImp* characteristic(const bt_uuid_t* uuid); BLECharacteristicImp* characteristic(const char* uuid); @@ -71,6 +73,12 @@ class BLEServiceImp: public BLEAttribute{ uint8_t discoverResponseProc(bt_conn_t *conn, const bt_gatt_attr_t *attr, bt_gatt_discover_params_t *params); + + uint8_t characteristicReadRspProc(bt_conn_t *conn, + int err, + bt_gatt_read_params_t *params, + const void *data, + uint16_t length); bool discovering(); static bt_uuid_t *getPrimayUuid(void); @@ -81,6 +89,13 @@ class BLEServiceImp: public BLEAttribute{ int updateProfile(bt_gatt_attr_t *attr_start, int& index); + +private: + void discoverNextCharacteristic(BLEDevice &bledevice); + bool readCharacteristic(const BLEDevice &bledevice, uint16_t handle); + bool discoverAttributes(BLEDevice* device, + uint16_t start_handle, + uint16_t end_handle); private: typedef LinkNode BLECharacteristicLinkNodeHeader; typedef LinkNode* BLECharacteristicNodePtr; @@ -89,6 +104,9 @@ class BLEServiceImp: public BLEAttribute{ uint16_t _start_handle; uint16_t _end_handle; + static bt_gatt_read_params_t _read_params; + bool _reading; + void releaseCharacteristic(); BLECharacteristicImp *_cur_discover_chrc; diff --git a/libraries/CurieI2S/examples/I2SDMA_TXCallBack/I2SDMA_TXCallBack.ino b/libraries/CurieI2S/examples/I2SDMA_TXCallBack/I2SDMA_TXCallBack.ino index 8cfc478e..52b8de4c 100644 --- a/libraries/CurieI2S/examples/I2SDMA_TXCallBack/I2SDMA_TXCallBack.ino +++ b/libraries/CurieI2S/examples/I2SDMA_TXCallBack/I2SDMA_TXCallBack.ino @@ -10,7 +10,7 @@ #include const int BUFF_SIZE=64; -boolean blinkState = true; // state of the LED +bool blinkState = true; // state of the LED uint32_t dataBuff[BUFF_SIZE]; uint32_t loop_count = 0; void setup() diff --git a/libraries/CurieIMU/examples/FreeFallDetect/FreeFallDetect.ino b/libraries/CurieIMU/examples/FreeFallDetect/FreeFallDetect.ino index ca88e457..d964270a 100644 --- a/libraries/CurieIMU/examples/FreeFallDetect/FreeFallDetect.ino +++ b/libraries/CurieIMU/examples/FreeFallDetect/FreeFallDetect.ino @@ -10,7 +10,7 @@ #include "CurieIMU.h" -boolean blinkState = false; // state of the LED +bool blinkState = false; // state of the LED unsigned long loopTime = 0; // get the time since program started unsigned long interruptsTime = 0; // get the time when free fall event is detected diff --git a/libraries/CurieIMU/examples/MotionDetect/MotionDetect.ino b/libraries/CurieIMU/examples/MotionDetect/MotionDetect.ino index 400ad461..cb94d85a 100644 --- a/libraries/CurieIMU/examples/MotionDetect/MotionDetect.ino +++ b/libraries/CurieIMU/examples/MotionDetect/MotionDetect.ino @@ -10,7 +10,7 @@ #include "CurieIMU.h" -boolean blinkState = false; // state of the LED +bool blinkState = false; // state of the LED unsigned long loopTime = 0; // get the time since program started unsigned long interruptsTime = 0; // get the time when motion event is detected diff --git a/libraries/CurieIMU/examples/RawImuDataSerial/RawImuDataSerial.ino b/libraries/CurieIMU/examples/RawImuDataSerial/RawImuDataSerial.ino index d61da508..08eed73b 100644 --- a/libraries/CurieIMU/examples/RawImuDataSerial/RawImuDataSerial.ino +++ b/libraries/CurieIMU/examples/RawImuDataSerial/RawImuDataSerial.ino @@ -35,7 +35,7 @@ int ax, ay, az; // accelerometer values int gx, gy, gz; // gyrometer values const int ledPin = 13; // activity LED pin -boolean blinkState = false; // state of the LED +bool blinkState = false; // state of the LED int calibrateOffsets = 1; // int to determine whether calibration takes place or not diff --git a/libraries/CurieIMU/examples/ShockDetect/ShockDetect.ino b/libraries/CurieIMU/examples/ShockDetect/ShockDetect.ino index 467299a2..9f2d7a9e 100644 --- a/libraries/CurieIMU/examples/ShockDetect/ShockDetect.ino +++ b/libraries/CurieIMU/examples/ShockDetect/ShockDetect.ino @@ -10,7 +10,7 @@ #include "CurieIMU.h" -boolean blinkState = false; // state of the LED +bool blinkState = false; // state of the LED void setup() { Serial.begin(9600); // initialize Serial communication diff --git a/libraries/CurieIMU/examples/StepCount/StepCount.ino b/libraries/CurieIMU/examples/StepCount/StepCount.ino index aafc9483..9ebcadb0 100644 --- a/libraries/CurieIMU/examples/StepCount/StepCount.ino +++ b/libraries/CurieIMU/examples/StepCount/StepCount.ino @@ -20,9 +20,9 @@ */ const int ledPin = 13; -boolean stepEventsEnabeled = true; // whether you're polling or using events +bool stepEventsEnabeled = true; // whether you're polling or using events long lastStepCount = 0; // step count on previous polling check -boolean blinkState = false; // state of the LED +bool blinkState = false; // state of the LED void setup() { Serial.begin(9600); // initialize Serial communication diff --git a/libraries/CurieIMU/examples/ZeroMotionDetect/ZeroMotionDetect.ino b/libraries/CurieIMU/examples/ZeroMotionDetect/ZeroMotionDetect.ino index 56fc3a9d..1f7d11fe 100644 --- a/libraries/CurieIMU/examples/ZeroMotionDetect/ZeroMotionDetect.ino +++ b/libraries/CurieIMU/examples/ZeroMotionDetect/ZeroMotionDetect.ino @@ -9,7 +9,7 @@ */ #include "CurieIMU.h" -boolean ledState = false; // state of the LED +bool ledState = false; // state of the LED void setup() { Serial.begin(9600); // initialize Serial communication while(!Serial) ; // wait for serial port to connect. diff --git a/libraries/CurieIMU/keywords.txt b/libraries/CurieIMU/keywords.txt index 1c64688b..11bd0056 100644 --- a/libraries/CurieIMU/keywords.txt +++ b/libraries/CurieIMU/keywords.txt @@ -14,6 +14,7 @@ CurieIMUClass KEYWORD1 begin KEYWORD1 +dataReady KEYWORD1 getGyroRate KEYWORD1 setGyroRate KEYWORD1 getAccelerometerRate KEYWORD1 @@ -64,7 +65,7 @@ readAcceleration KEYWORD1 readRotation KEYWORD1 readAccelerometer KEYWORD1 -readAccelerometerScaled KEYWORD1 +readAccelerometerScaled KEYWORD1 readGyro KEYWORD1 readGyroScaled KEYWORD1 readTemperature KEYWORD1 @@ -84,6 +85,9 @@ CurieIMU KEYWORD2 # Constants (LITERAL1) ####################################### +ACCEL LITERAL1 +GYRO LITERAL1 + X_AXIS LITERAL1 Y_AXIS LITERAL1 Z_AXIS LITERAL1 diff --git a/libraries/CurieIMU/src/BMI160.cpp b/libraries/CurieIMU/src/BMI160.cpp index d1bf2a22..c8945b38 100644 --- a/libraries/CurieIMU/src/BMI160.cpp +++ b/libraries/CurieIMU/src/BMI160.cpp @@ -78,6 +78,11 @@ uint8_t BMI160Class::reg_read_bits(uint8_t reg, unsigned pos, unsigned len) return b; } +int BMI160Class::isBitSet(uint8_t value, unsigned bit) +{ + return value & (1 << bit); +} + /******************************************************************************/ /** Power on and prepare for general usage. @@ -85,8 +90,10 @@ uint8_t BMI160Class::reg_read_bits(uint8_t reg, unsigned pos, unsigned len) * after start-up). This function also sets both the accelerometer and the gyroscope * to default range settings, namely +/- 2g and +/- 250 degrees/sec. */ -void BMI160Class::initialize() +void BMI160Class::initialize(unsigned int flags) { + sensors_enabled = 0; + /* Issue a soft-reset to bring the device into a clean state */ reg_write(BMI160_RA_CMD, BMI160_CMD_SOFT_RESET); delay(1); @@ -95,26 +102,36 @@ void BMI160Class::initialize() reg_read(0x7F); delay(1); - /* Power up the accelerometer */ - reg_write(BMI160_RA_CMD, BMI160_CMD_ACC_MODE_NORMAL); - delay(1); - /* Wait for power-up to complete */ - while (0x1 != reg_read_bits(BMI160_RA_PMU_STATUS, + if (flags & ACCEL) { + /* Power up the accelerometer */ + reg_write(BMI160_RA_CMD, BMI160_CMD_ACC_MODE_NORMAL); + delay(1); + + /* Wait for power-up to complete */ + while (0x1 != reg_read_bits(BMI160_RA_PMU_STATUS, BMI160_ACC_PMU_STATUS_BIT, BMI160_ACC_PMU_STATUS_LEN)) + delay(1); + + sensors_enabled |= ACCEL; + } + + if (flags & GYRO) { + /* Power up the gyroscope */ + reg_write(BMI160_RA_CMD, BMI160_CMD_GYR_MODE_NORMAL); delay(1); - /* Power up the gyroscope */ - reg_write(BMI160_RA_CMD, BMI160_CMD_GYR_MODE_NORMAL); - delay(1); - /* Wait for power-up to complete */ - while (0x1 != reg_read_bits(BMI160_RA_PMU_STATUS, + /* Wait for power-up to complete */ + while (0x1 != reg_read_bits(BMI160_RA_PMU_STATUS, BMI160_GYR_PMU_STATUS_BIT, BMI160_GYR_PMU_STATUS_LEN)) - delay(1); + delay(1); + + sensors_enabled |= GYRO; + } - setFullScaleGyroRange(BMI160_GYRO_RANGE_250); - setFullScaleAccelRange(BMI160_ACCEL_RANGE_2G); + setFullScaleGyroRange(BMI160_GYRO_RANGE_250, 250.0f); + setFullScaleAccelRange(BMI160_ACCEL_RANGE_2G, 2.0f); /* Only PIN1 interrupts currently supported - map all interrupts to PIN1 */ reg_write(BMI160_RA_INT_MAP_0, 0xFF); @@ -131,6 +148,17 @@ uint8_t BMI160Class::getDeviceID() { return reg_read(BMI160_RA_CHIP_ID); } +/* Checks if the specified sensors are enabled (sensors are specified using + * bit flags defined by CurieIMUSensor enum). If 0 is passed, checks if *any* + * sensors are enabled */ +bool BMI160Class::isEnabled(unsigned int sensors) +{ + if (sensors == 0) + return sensors_enabled > 0; + + return (sensors_enabled & sensors) > 0; +} + /** Verify the SPI connection. * Make sure the device is connected and responds as expected. * @return True if connection is valid, false otherwise @@ -330,10 +358,11 @@ uint8_t BMI160Class::getFullScaleGyroRange() { * @param range New full-scale gyroscope range value * @see getFullScaleGyroRange() */ -void BMI160Class::setFullScaleGyroRange(uint8_t range) { +void BMI160Class::setFullScaleGyroRange(uint8_t range, float real) { reg_write_bits(BMI160_RA_GYRO_RANGE, range, BMI160_GYRO_RANGE_SEL_BIT, BMI160_GYRO_RANGE_SEL_LEN); + gyro_range = real; } /** Get full-scale accelerometer range. @@ -362,10 +391,11 @@ uint8_t BMI160Class::getFullScaleAccelRange() { * @see getFullScaleAccelRange() * @see BMI160AccelRange */ -void BMI160Class::setFullScaleAccelRange(uint8_t range) { +void BMI160Class::setFullScaleAccelRange(uint8_t range, float real) { reg_write_bits(BMI160_RA_ACCEL_RANGE, range, BMI160_ACCEL_RANGE_SEL_BIT, BMI160_ACCEL_RANGE_SEL_LEN); + accel_range = real; } /** Get accelerometer offset compensation enabled value. @@ -2386,19 +2416,3 @@ uint8_t BMI160Class::getRegister(uint8_t reg) { void BMI160Class::setRegister(uint8_t reg, uint8_t data) { reg_write(reg, data); } - -/** Check if new gyroscope data is available - * @return True if new data is available, else false. - */ -bool BMI160Class::gyroDataReady() -{ - return reg_read_bits(BMI160_RA_STATUS, BMI160_STATUS_DRDY_GYR, 1); -} - -/** Check if new accelerometer data is available - * @return True if new data is available, else false. - */ -bool BMI160Class::accelDataReady() -{ - return reg_read_bits(BMI160_RA_STATUS, BMI160_STATUS_DRDY_ACC, 1); -} diff --git a/libraries/CurieIMU/src/BMI160.h b/libraries/CurieIMU/src/BMI160.h index 1384f1c4..dfdc7531 100644 --- a/libraries/CurieIMU/src/BMI160.h +++ b/libraries/CurieIMU/src/BMI160.h @@ -267,6 +267,12 @@ THE SOFTWARE. #define BMI160_RA_CMD 0x7E +/* Bit flags for selecting individual sensors */ +typedef enum { + GYRO = 0x1, + ACCEL = 0x2 +} CurieIMUSensor; + /** * Interrupt Latch Mode options * @see setInterruptLatch() @@ -471,9 +477,10 @@ typedef enum { class BMI160Class { public: - void initialize(); + void initialize(unsigned int flags); bool testConnection(); + bool isEnabled(unsigned int sensors); uint8_t getGyroRate(); void setGyroRate(uint8_t rate); @@ -487,9 +494,9 @@ class BMI160Class { void setAccelDLPFMode(uint8_t bandwidth); uint8_t getFullScaleGyroRange(); - void setFullScaleGyroRange(uint8_t range); + void setFullScaleGyroRange(uint8_t range, float real); uint8_t getFullScaleAccelRange(); - void setFullScaleAccelRange(uint8_t range); + void setFullScaleAccelRange(uint8_t range, float real); void autoCalibrateGyroOffset(); bool getGyroOffsetEnabled(); @@ -640,6 +647,7 @@ class BMI160Class { uint8_t getDeviceID(); + int isBitSet(uint8_t value, unsigned bit); uint8_t getRegister(uint8_t reg); void setRegister(uint8_t reg, uint8_t data); @@ -653,8 +661,10 @@ class BMI160Class { void setInterruptLatch(uint8_t latch); void resetInterrupt(); - bool gyroDataReady(); - bool accelDataReady(); + /* Use a bitmask to track which sensors are enabled */ + unsigned sensors_enabled; + float accel_range; + float gyro_range; protected: virtual int serial_buffer_transfer(uint8_t *buf, unsigned tx_cnt, unsigned rx_cnt) = 0; diff --git a/libraries/CurieIMU/src/CurieIMU.cpp b/libraries/CurieIMU/src/CurieIMU.cpp index 8b24c5a5..2b2d5466 100644 --- a/libraries/CurieIMU/src/CurieIMU.cpp +++ b/libraries/CurieIMU/src/CurieIMU.cpp @@ -32,7 +32,8 @@ * on the Curie module, before calling BMI160::initialize() to activate the * BMI160 accelerometer and gyroscpoe with default settings. */ -bool CurieIMUClass::begin() + +bool CurieIMUClass::configure_imu(unsigned int sensors) { ss_spi_init(SPI_SENSING_1, 2000, SPI_BUSMODE_0, SPI_8_BIT, SPI_SE_1); @@ -41,13 +42,26 @@ bool CurieIMUClass::begin() serial_buffer_transfer(&dummy_reg, 1, 1); /* The SPI interface is ready - now invoke the base class initialization */ - BMI160Class::initialize(); + initialize(sensors); /** Verify the SPI connection. * MakgetGyroRatee sure the device is connected and responds as expected. * @return True if connection is valid, false otherwise */ - return (CURIE_IMU_CHIP_ID == getDeviceID()); + if (CURIE_IMU_CHIP_ID != getDeviceID()) + return false; + + return true; +} + +bool CurieIMUClass::begin() +{ + return configure_imu(GYRO | ACCEL); +} + +bool CurieIMUClass::begin(unsigned int sensors) +{ + return configure_imu(sensors); } void CurieIMUClass::end() @@ -55,6 +69,48 @@ void CurieIMUClass::end() ss_spi_disable(SPI_SENSING_1); } +bool CurieIMUClass::dataReady() +{ + uint8_t stat; + + /* If no sensors are enabled */ + if (!isEnabled(0)) + return false; + + /* Read status register */ + stat = getRegister(BMI160_RA_STATUS); + + if (isEnabled(GYRO) && !isBitSet(stat, BMI160_STATUS_DRDY_GYR)) + return false; + + if (isEnabled(ACCEL) && !isBitSet(stat, BMI160_STATUS_DRDY_ACC)) + return false; + + return true; +} + +bool CurieIMUClass::dataReady(unsigned int sensors) +{ + uint8_t stat; + + /* If no sensors enabled, or no data requested */ + if (sensors == 0 || !isEnabled(0)) + return false; + + /* Read status register */ + stat = getRegister(BMI160_RA_STATUS); + + if ((sensors & GYRO) && isEnabled(GYRO) && + !isBitSet(stat, BMI160_STATUS_DRDY_GYR)) + return false; + + if ((sensors & ACCEL) && isEnabled(ACCEL) && + !isBitSet(stat, BMI160_STATUS_DRDY_ACC)) + return false; + + return true; +} + int CurieIMUClass::getGyroRate() { int rate; @@ -222,25 +278,26 @@ int CurieIMUClass::getGyroRange() void CurieIMUClass::setGyroRange(int range) { BMI160GyroRange bmiRange; + float real; if (range >= 2000) { bmiRange = BMI160_GYRO_RANGE_2000; - gyro_range = 2000.0f; + real = 2000.0f; } else if (range >= 1000) { bmiRange = BMI160_GYRO_RANGE_1000; - gyro_range = 1000.0f; + real = 1000.0f; } else if (range >= 500) { bmiRange = BMI160_GYRO_RANGE_500; - gyro_range = 500.0f; + real = 500.0f; } else if (range >= 250) { bmiRange = BMI160_GYRO_RANGE_250; - gyro_range = 250.0f; + real = 250.0f; } else { bmiRange = BMI160_GYRO_RANGE_125; - gyro_range = 125.0f; + real = 125.0f; } - setFullScaleGyroRange(bmiRange); + setFullScaleGyroRange(bmiRange, real); } int CurieIMUClass::getAccelerometerRange() @@ -272,22 +329,23 @@ int CurieIMUClass::getAccelerometerRange() void CurieIMUClass::setAccelerometerRange(int range) { BMI160AccelRange bmiRange; + float real; if (range <= 2) { bmiRange = BMI160_ACCEL_RANGE_2G; - accel_range = 2.0f; + real = 2.0f; } else if (range <= 4) { bmiRange = BMI160_ACCEL_RANGE_4G; - accel_range = 4.0f; + real = 4.0f; } else if (range <= 8) { bmiRange = BMI160_ACCEL_RANGE_8G; - accel_range = 8.0f; + real = 8.0f; } else { bmiRange = BMI160_ACCEL_RANGE_16G; - accel_range = 16.0f; + real = 16.0f; } - setFullScaleAccelRange(bmiRange); + setFullScaleAccelRange(bmiRange, real); } void CurieIMUClass::autoCalibrateGyroOffset() @@ -760,7 +818,7 @@ void CurieIMUClass::setTapDetectionThreshold(float threshold) case 16: default: - bmiThreshold = (threshold - 2500) / 500.0; + bmiThreshold = (threshold - 250) / 500.0; break; } diff --git a/libraries/CurieIMU/src/CurieIMU.h b/libraries/CurieIMU/src/CurieIMU.h index 8056b135..3a7a0dc4 100644 --- a/libraries/CurieIMU/src/CurieIMU.h +++ b/libraries/CurieIMU/src/CurieIMU.h @@ -94,9 +94,13 @@ class CurieIMUClass : public BMI160Class { friend void bmi160_pin1_isr(void); public: + bool begin(unsigned int sensors); bool begin(void); void end(void); + bool dataReady(); + bool dataReady(unsigned int sensors); + // supported values: 25, 50, 100, 200, 400, 800, 1600, 3200 (Hz) int getGyroRate(); void setGyroRate(int rate); @@ -207,11 +211,9 @@ class CurieIMUClass : public BMI160Class { void detachInterrupt(void); private: + bool configure_imu(unsigned int sensors); int serial_buffer_transfer(uint8_t *buf, unsigned tx_cnt, unsigned rx_cnt); - float accel_range; - float gyro_range; - float getFreefallDetectionThreshold(); void setFreefallDetectionThreshold(float threshold); float getShockDetectionThreshold(); diff --git a/libraries/CuriePowerManagement/README.md b/libraries/CuriePowerManagement/README.md new file mode 100644 index 00000000..8b472632 --- /dev/null +++ b/libraries/CuriePowerManagement/README.md @@ -0,0 +1,296 @@ +Table of Contents +================= + + * [CuriePower](#curiepower) + * [CuriePower API reference](#curiepower-api-reference) + * [Functions](#functions) + * [CuriePower.doze()](#curiepowerdoze) + * [CuriePower.doze(int duration)](#curiepowerdozeint-duration) + * [CuriePower.idle()](#curiepoweridle) + * [CuriePower.idle(int duration)](#curiepoweridleint-duration) + * [CuriePower.sleep()](#curiepowersleep) + * [CuriePower.sleep(int duration)](#curiepowersleepint-duration) + * [CuriePower.deepSleep()](#curiepowerdeepsleep) + * [CuriePower.deepSleep(int duration)](#curiepowerdeepsleepint-duration) + * [CuriePower.attachInterruptWakeup(uint32_t pin, voidFuncPtr callback, uint32_t mode)](#curiepowerattachinterruptwakeupuint32_t-pin-voidfuncptr-callback-uint32_t-mode) + * [CuriePower.detachInterruptWakeup(uint32_t pin)](#curiepowerdetachinterruptwakeupuint32_t-pin) + * [Tutorials](#tutorials) + * [Tutorial #1: TimedWakeup Example](#tutorial-1-timedwakeup-example) + * [Tutorial #2: WakeFromIMU Example](#tutorial-2-wakefromimu-example) + +# CuriePower +CuriePower is a Power Management library for Curie based boards such as the Arduino101/Genuino101 and tinyTILE + +# CuriePower API reference + +## Functions + +### ``CuriePower.doze()`` + +``` +void CuriePower.doze() +``` + +Places the SoC in "doze" mode which switches the system clock to the internal 32.768 kHz RTC oscillator. + +*Parameters* + +none + +*Return value* + +none + +### ``CuriePower.doze(int duration)`` + +``` +void CuriePower.doze(int duration) +``` + + +Places the SoC in "doze" mode which switches the system clock to the internal 32.768 kHz RTC oscillator for `duration` milliseconds + + +*Parameters* + +1. `int duration` : number in milliseconds to doze + +*Return value* + +none + +### ``CuriePower.idle()`` + +``` +void CuriePower.idle() +``` + +Places the SoC into "doze" mode then enters an infinite loop, effectively stopping all operations until a wake interrupt is generated. + +*Parameters* + +none + +*Return value* + +none + +### ``CuriePower.idle(int duration)`` + +``` +void CuriePower.idle(int duration) +``` + + +Places the SoC in "doze" mode and enters an infinite loop for `duration` milliseconds + + +*Parameters* + +1. `int duration` : number in milliseconds to idle + +*Return value* + +none + +### ``CuriePower.sleep()`` + +``` +void CuriePower.sleep() +``` + +Places the SoC into a sleep state, stopping all operations, until a wake interrupt is generated + +*Parameters* + +none + +*Return value* + +none + +### ``CuriePower.sleep(int duration)`` + +``` +void CuriePower.sleep(int duration) +``` + + +Places the SoC into a sleep state for `duration` milliseconds + + +*Parameters* + +1. `int duration` : number in milliseconds to sleep + +*Return value* + +none + +### ``CuriePower.deepSleep()`` + +``` +void CuriePower.deepSleep() +``` + +Places the SoC into a deep sleep state, stopping all operations, until a wake interrupt is generated + +*Parameters* + +none + +*Return value* + +none + +### ``CuriePower.deepSleep(int duration)`` + +``` +void CuriePower.deepSleep(int duration) +``` + + +Places the SoC into a deep sleep state for `duration` milliseconds + + +*Parameters* + +1. `int duration` : number in milliseconds to deep sleep + +*Return value* + +none + +### ``CuriePower.attachInterruptWakeup(uint32_t pin, voidFuncPtr callback, uint32_t mode)`` + +``` +void CuriePower.attachInterruptWakeup(uint32_t pin, voidFuncPtr callback, uint32_t mode) +``` + +Attaches a wakeup interrupt to digital pin `pin`. `callback` is the function to be called when the wakeup interrupt occurs. + +*Parameters* + +none + +*Return value* + +none + +### ``CuriePower.detachInterruptWakeup(uint32_t pin)`` + +``` +void CuriePower.detachInterruptWakeup(uint32_t pin) +``` + +Removes any wakeup interrupt attached to digital pin `pin`. + +*Parameters* + +none + +*Return value* + +none + +# Tutorials + +## Tutorial #1: TimedWakeup Example + +This sketch demonstrates the simplest way to use the CuriePower library. It blinks the LED a few times, goes to sleep for a certain amount of time then goes back at the start of loop() + +```cpp +#include + +void setup() { + pinMode(LED_BUILTIN, OUTPUT); +} + +void loop() { + for(int i = 0; i < 5; i++) + { + digitalWrite(LED_BUILTIN, HIGH); + delay(100); + digitalWrite(LED_BUILTIN, LOW); + delay(100); + } + PM.sleep(1000); +} +``` + +The line of code that is most interesting here is: +```cpp +PM.sleep(1000); +``` +This puts the SoC into sleep, drawing significantly less power, for 1000ms or 1s. + +In what situations is this most useful? + +Let's says you have a battery powered project that reads a sensor value once every second and saves it to an SD card. +Simply using delay() will work but you will notice that you will run out of battery pretty fast. That is because even though the code is not doing much inside delay, it is still running everything at full clock speed and all peripherals are turned on. +When we put the SoC to sleep, several things are turned off. This includes most of the peripherals. voltage rails, and some clocks. Basically, it draws much less power and no code is running until a wake interrupt is generated. + +Many Arduino projects typically have a loop where you read a sensor, do something with that reading, and then delay for a set amount of time. +In most cases, reading the sensor and doing something with that reading takes very little time, much smaller than the delay duration. This means that we are wasting a lot of power inside the delay doing nothing. +By placing the SoC to sleep instead of just waiting inside the delay, we can save a considerable amount of power in most applications. + + +## Tutorial #2: WakeFromIMU Example + +This sketch uses CuriePower library and the CurieIMU library together and demonstrates the use of an interrupt to wake the Curie SoC from sleep. + +```cpp +#include +#include "CurieIMU.h" + + +void setup() { + pinMode(LED_BUILTIN, OUTPUT); + CurieIMU.begin(); + CurieIMU.attachInterrupt(wakeup); + CurieIMU.setDetectionThreshold(CURIE_IMU_MOTION, 20); // 100mg + CurieIMU.setDetectionDuration(CURIE_IMU_MOTION, 10); // trigger times of consecutive slope data points + CurieIMU.interrupts(CURIE_IMU_MOTION); + +} + +void loop() { + PM.sleep(); + digitalWrite(LED_BUILTIN, HIGH); + delay(3000); + digitalWrite(LED_BUILTIN, LOW); +} + +void wakeup() +{ + PM.wakeFromDoze(); + // This function will be called once on device wakeup + // You can do some little operations here (like changing variables which will be used in the loop) + // Remember to avoid calling delay() and long running functions since this functions executes in interrupt context +} +``` + +If you look at the beginning of loop() you will see: +```cpp +PM.sleep(); +``` +This line of code puts the SoC into a sleep state. The SoC will remain in a sleep state until it is woken by an interrupt. +If no interrupt triggers the SoC to wake up, it will stay in a sleep state forever(or until the battery runs out). +This is specifically useful in applications that are not periodic, like in this example sketch where the SoC stays at a sleep state until the Arduino101 detects motion, or more precisely the Bosch BMI160 [6-Axis Accelerometer/Gyroscope] sensor detects the motion and triggers an interrupt to wake the Curie Soc from sleep. + +Inside setup() we have: +```cpp +CurieIMU.attachInterrupt(wakeup); +CurieIMU.setDetectionThreshold(CURIE_IMU_MOTION, 20); // 100mg +CurieIMU.setDetectionDuration(CURIE_IMU_MOTION, 10); // trigger times of consecutive slope data points +CurieIMU.interrupts(CURIE_IMU_MOTION); +``` +These lines of code attaches a method called wakeup() which is called whenever motion is detected. Since the interrupt signal generated by the Bosch BMI160 sensor is already internally connected to AON(Always On) interrupt of the SoC, it automatically wakes the SoC from sleep. +However, since we are using the attachInterrupt() method of the CurieIMU Library instead of the one from the CuriePower Library we still need to do one more thing after the SoC is taken out of a sleep state. + +Inside the wakeup() method: +```cpp +PM.wakeFromDoze(); +``` +This line of code simply takes the SoC out of the Doze state, switching it from using the internal RTC 32.768 KHz as the main clock, back to the 32Mhz oscillator. +At this point the SoC runs back at full speed ready to do stuff quickly and then go back to sleep to save power. diff --git a/libraries/CuriePowerManagement/examples/TimedWakeup/TimedWakeup.ino b/libraries/CuriePowerManagement/examples/TimedWakeup/TimedWakeup.ino new file mode 100644 index 00000000..baeb4dec --- /dev/null +++ b/libraries/CuriePowerManagement/examples/TimedWakeup/TimedWakeup.ino @@ -0,0 +1,16 @@ +#include + +void setup() { + pinMode(LED_BUILTIN, OUTPUT); +} + +void loop() { + for(int i = 0; i < 5; i++) + { + digitalWrite(LED_BUILTIN, HIGH); + delay(100); + digitalWrite(LED_BUILTIN, LOW); + delay(100); + } + PM.sleep(1000); +} \ No newline at end of file diff --git a/libraries/CuriePowerManagement/examples/WakeFromIMU/WakeFromIMU.ino b/libraries/CuriePowerManagement/examples/WakeFromIMU/WakeFromIMU.ino new file mode 100644 index 00000000..7cf2015c --- /dev/null +++ b/libraries/CuriePowerManagement/examples/WakeFromIMU/WakeFromIMU.ino @@ -0,0 +1,28 @@ +#include +#include "CurieIMU.h" + + +void setup() { + pinMode(LED_BUILTIN, OUTPUT); + CurieIMU.begin(); + CurieIMU.attachInterrupt(wakeup); + CurieIMU.setDetectionThreshold(CURIE_IMU_MOTION, 20); // 100mg + CurieIMU.setDetectionDuration(CURIE_IMU_MOTION, 10); // trigger times of consecutive slope data points + CurieIMU.interrupts(CURIE_IMU_MOTION); + +} + +void loop() { + PM.sleep(); + digitalWrite(LED_BUILTIN, HIGH); + delay(3000); + digitalWrite(LED_BUILTIN, LOW); +} + +void wakeup() +{ + PM.wakeFromDoze(); + // This function will be called once on device wakeup + // You can do some little operations here (like changing variables which will be used in the loop) + // Remember to avoid calling delay() and long running functions since this functions executes in interrupt context +} diff --git a/libraries/CuriePowerManagement/keywords.txt b/libraries/CuriePowerManagement/keywords.txt new file mode 100644 index 00000000..7051dfac --- /dev/null +++ b/libraries/CuriePowerManagement/keywords.txt @@ -0,0 +1,24 @@ +####################################### +# Syntax Coloring Map For Curie Power Library +####################################### + +####################################### +# Datatypes (KEYWORD1) +####################################### + +####################################### +# Methods and Functions (KEYWORD2) +####################################### +sleep KEYWORD2 +deepSleep KEYWORD2 +idle KEYWORD2 +doze KEYWORD2 +wakeFromDoze KEYWORD2 + +####################################### +# Instances (KEYWORD2) +####################################### + +####################################### +# Constants (LITERAL1) +####################################### diff --git a/libraries/CuriePowerManagement/library.properties b/libraries/CuriePowerManagement/library.properties new file mode 100644 index 00000000..83a2661e --- /dev/null +++ b/libraries/CuriePowerManagement/library.properties @@ -0,0 +1,9 @@ +name=CuriePowerManagement +version=1.0 +author=Intel +maintainer=Intel +sentence=Curie Power Management library for Curie based boards. +paragraph=Allows to manage the power states of Curie based boards. +category=Device Control +url= +architectures=arc32 diff --git a/libraries/CuriePowerManagement/src/Power.cpp b/libraries/CuriePowerManagement/src/Power.cpp new file mode 100644 index 00000000..450c2ad7 --- /dev/null +++ b/libraries/CuriePowerManagement/src/Power.cpp @@ -0,0 +1,478 @@ +#include "Power.h" + +Power PM; +uint32_t arc_restore_addr; +uint32_t cpu_context[33]; + +typedef void (*user_cb)(void); + +static void sleepInterruptHandler(void) +{ + unsigned int flags = interrupt_lock(); + PM.wakeFromDoze(); + PM.wakeFromSleepCallback(); + interrupt_unlock(flags); +} + +static void dozeInterruptHandler(void) +{ + unsigned int flags = interrupt_lock(); + PM.wakeFromDoze(); + interrupt_unlock(flags); +} + +static void soc_gpio_sleep_isr() +{ + if(soc_sleeping || soc_dozing) + { + unsigned int flags = interrupt_lock(); + PM.wakeFromDoze(); + wsrc_t wsrc; + while (wsrc_get_newest_attached(&wsrc)){ + PinDescription *p = &g_APinDescription[wsrc.id]; + uint32_t mask = 0x1 << p->ulGPIOId; + if(p->ulGPIOPort == SOC_GPIO_32){ + uint32_t status = shared_data->pm_int_status; + if((status>>p->ulGPIOId)&0x1){ + //call user callback + user_cb cb = (user_cb)wsrc.callback; + cb(); + } + } + } + interrupt_unlock(flags); + } + soc_sleeping = false; +} + +static void soc_aongpio_sleep_isr() +{ + if(soc_sleeping || soc_dozing){ + unsigned int flags = interrupt_lock(); + PM.wakeFromDoze(); + wsrc_t wsrc; + while (wsrc_get_newest_attached(&wsrc)){ + PinDescription *p = &g_APinDescription[wsrc.id]; + uint32_t mask = 0x1 << p->ulGPIOId; + if(p->ulGPIOPort == SOC_GPIO_32){ + // Save interrupt status + uint32_t status = MMIO_REG_VAL_FROM_BASE(SOC_GPIO_AON_BASE_ADDR, SOC_GPIO_INTSTATUS); + // Mask the pending interrupts + MMIO_REG_VAL_FROM_BASE(SOC_GPIO_AON_BASE_ADDR, SOC_GPIO_INTMASK) |= status; + shared_data->pm_int_status = status; + // Clear interrupt flag (write 1 to clear) + MMIO_REG_VAL_FROM_BASE(SOC_GPIO_AON_BASE_ADDR, SOC_GPIO_PORTA_EOI) = status; + if((status>>p->ulGPIOId)&0x1){ + //call user callback + user_cb cb = (user_cb)wsrc.callback; + cb(); + } + } + } + interrupt_unlock(flags); + } + soc_sleeping = false; +} + +static void ss_gpio0_sleep_isr() +{ + if(soc_sleeping || soc_dozing){ + unsigned int flags = interrupt_lock(); + PM.wakeFromDoze(); + wsrc_t wsrc; + while (wsrc_get_newest_attached(&wsrc)) { + PinDescription *p = &g_APinDescription[wsrc.id]; + uint32_t mask = 0x1 << p->ulGPIOId; + if(p->ulGPIOPort == SS_GPIO_8B0){ + uint32_t status = shared_data->pm_int_status; + if((status>>p->ulGPIOId)&0x1){ + //call user callback + user_cb cb = (user_cb)wsrc.callback; + cb(); + } + } + } + interrupt_unlock(flags); + } + soc_sleeping = false; +} + +static void ss_gpio1_sleep_isr() +{ + if(soc_sleeping || soc_dozing){ + unsigned int flags = interrupt_lock(); + PM.wakeFromDoze(); + wsrc_t wsrc; + while (wsrc_get_newest_attached(&wsrc)) { + PinDescription *p = &g_APinDescription[wsrc.id]; + uint32_t mask = 0x1 << p->ulGPIOId; + if(p->ulGPIOPort == SS_GPIO_8B1){ + uint32_t status = shared_data->pm_int_status; + if((status>>p->ulGPIOId)&0x1){ + //call user callback + user_cb cb = (user_cb)wsrc.callback; + cb(); + } + } + } + interrupt_unlock(flags); + } + soc_sleeping = false; +} + +static void aontimer_isr() +{ + if(soc_sleeping || soc_dozing){ + unsigned int flags = interrupt_lock(); + interrupt_disable(IRQ_ALWAYS_ON_TMR); + *AONPT_CFG = 0; + PM.wakeFromDoze(); + interrupt_unlock(flags); + //wait until quark core is running + volatile uint32_t psts = (MMIO_REG_VAL(P_STS))&0x7; + while(psts){ + psts = (MMIO_REG_VAL(P_STS))&0x7; + } + PM.wakeFromSleepCallback(); + } + soc_sleeping = false; +} + +Power::Power() +{ + +} + +void Power::doze() +{ + //actually attach the interrupts + enableWakeInterrupts(); + turnOffUSB(); + soc_dozing = true; + //switch from external crystal oscillator to internal hybrid oscillator + switchToHybridOscillator(); + + //Set system clock to the RTC Crystal Oscillator + uint32_t current_val = MMIO_REG_VAL(CCU_SYS_CLK_CTL); + MMIO_REG_VAL(CCU_SYS_CLK_CTL) = current_val & 0xFFFFFFFE; + + //Powerdown hybrid oscillator + current_val = MMIO_REG_VAL(OSC0_CFG1); + MMIO_REG_VAL(OSC0_CFG1) = current_val | 0x00000004; +} + +void Power::doze(int duration) +{ + doze(); + delayTicks(millisToRTCTicks(duration)); + wakeFromDoze(); +} + +void Power::idle() +{ + doze(); + while(soc_dozing); +} + +void Power::idle(int duration) +{ + enableAONPTimerInterrrupt(duration); + idle(); +} + +void Power::wakeFromDoze() +{ + //Powerup hybrid oscillator + uint32_t current_val = MMIO_REG_VAL(OSC0_CFG1); + MMIO_REG_VAL(OSC0_CFG1) = current_val & 0xFFFFFFFB; + + //Set system clock to the Hybrid Oscillator + current_val = MMIO_REG_VAL(CCU_SYS_CLK_CTL); + MMIO_REG_VAL(CCU_SYS_CLK_CTL) = current_val | 0x00000001; + + //switch back to the external crystal oscillator + void switchToCrystalOscillator(); + + turnOnUSB(); + soc_dozing = false; +} + +void Power::sleep() +{ + soc_sleeping = true; + //disable low power mode on OPM_2P6 regulator + MMIO_REG_VAL(SLP_CFG) &= ~(1 << LPMODE_EN); + + uint32_t creg_mst0_ctrl = 0; + creg_mst0_ctrl = READ_ARC_REG(QM_SS_CREG_BASE); + + /* + * Clock gate the sensor peripherals at CREG level. + * This clock gating is independent of the peripheral-specific clock + * gating provided in ss_clk.h . + */ + creg_mst0_ctrl |= (QM_SS_IO_CREG_MST0_CTRL_ADC_CLK_GATE | + QM_SS_IO_CREG_MST0_CTRL_I2C1_CLK_GATE | + QM_SS_IO_CREG_MST0_CTRL_I2C0_CLK_GATE | + QM_SS_IO_CREG_MST0_CTRL_SPI1_CLK_GATE | + QM_SS_IO_CREG_MST0_CTRL_SPI0_CLK_GATE); + + WRITE_ARC_REG(creg_mst0_ctrl, QM_SS_CREG_BASE); + + //Send request to put quark core to sleep + //x86_C2LPRequest(); //can only wake Quark core using AON_GPIO, RTC, AON_Timer, and AON_Comparators + x86_C2Request(); + doze(); + + __asm__ __volatile__( + "sleep %0" + : + : "i"(QM_SS_SLEEP_MODE_CORE_TIMERS_RTC_OFF)); + + creg_mst0_ctrl &= ~(QM_SS_IO_CREG_MST0_CTRL_ADC_CLK_GATE | + QM_SS_IO_CREG_MST0_CTRL_I2C1_CLK_GATE | + QM_SS_IO_CREG_MST0_CTRL_I2C0_CLK_GATE | + QM_SS_IO_CREG_MST0_CTRL_SPI1_CLK_GATE | + QM_SS_IO_CREG_MST0_CTRL_SPI0_CLK_GATE); + + WRITE_ARC_REG(creg_mst0_ctrl, QM_SS_CREG_BASE); + soc_sleeping = false; +} + +void Power::sleep(int duration) +{ + enableAONPTimerInterrrupt(duration); + sleep(); +} + +void Power::deepSleep() +{ + sleep(); +} + +void Power::deepSleep(int duration) +{ + sleep(duration); +} + +inline void Power::wakeFromSleepCallback(void) +{ + //ToDo: check table and call apprpriate CBs + if(pmCB != NULL) + pmCB(); + //ToDo: unregister all sleep IRQs +} + +inline void Power::wakeFromDozeCallback(void) +{ + //ToDo: check table and call apprpriate CBs + if(pmCB != NULL) + pmCB(); +} + +void Power::attachInterruptWakeup(uint32_t pin, voidFuncPtr callback, uint32_t mode) +{ + if (pin > NUM_WAKEUP) { + return; + } + + if (pin <= GPIO_END) { + wsrc_register_gpio(pin, callback, mode); + } + else{ + wsrc_register_id(pin, callback); + } +} + +void Power::detachInterruptWakeup(uint32_t pin) +{ + wsrc_unregister(pin); + if (pin <= GPIO_END) { + detachInterrupt(pin); + } +} + +//Privates + +void Power::turnOffUSB() +{ + MMIO_REG_VAL(USB_PHY_CFG0) |= 0x00000001; +} + +void Power::turnOnUSB() +{ + MMIO_REG_VAL(USB_PHY_CFG0) &= 0xFFFFFFFE; +} + +void Power::switchToHybridOscillator() +{ + //read trim value from OTP + uint32_t trimMask = *(uint16_t*)OSCTRIM_ADDR << 20; + MMIO_REG_VAL(OSC0_CFG1) = 0x00000002 | trimMask; //switch to internal hybrid oscillator using trim value from OTP + //ToDo: wait for hybrid oscillator to stabilize +} + +void Power::switchToCrystalOscillator() +{ + MMIO_REG_VAL(OSC0_CFG1) = 0x00070009; + while(!(MMIO_REG_VAL(OSC0_STAT) & 0x00000002)); //wait till crystal oscillator is stable +} + +void Power::setRTCCMR(int seconds) +{ + MMIO_REG_VAL(RTC_CMR) = readRTC_CCVR() + seconds; +} + +uint32_t Power::readRTC_CCVR() +{ + return *RTC_CCVR; +} + +uint32_t Power::millisToRTCTicks(int milliseconds) +{ + return (uint32_t)((double)milliseconds*32.768); +} + +void Power::enableRTCInterrupt(int seconds) +{ + setRTCCMR(seconds); + MMIO_REG_VAL(RTC_MASK_INT) &= 0xFFFFFEFE; + MMIO_REG_VAL(RTC_CCR) |= 0x00000001; + MMIO_REG_VAL(RTC_CCR) &= 0xFFFFFFFD; + volatile uint32_t read = MMIO_REG_VAL(RTC_EOI); + + pmCB = &wakeFromRTC; + interrupt_disable(IRQ_RTC_INTR); + interrupt_connect(IRQ_RTC_INTR , &sleepInterruptHandler); + delayTicks(6400); //2ms + interrupt_enable(IRQ_RTC_INTR); +} + +void Power::enableAONGPIOInterrupt(int aon_gpio, int mode) +{ + switch(mode){ + case CHANGE: //not supported just do the same as FALLING + MMIO_REG_VAL(AON_GPIO_INTTYPE_LEVEL) |= 1 << aon_gpio; + MMIO_REG_VAL(AON_GPIO_INT_POL) &= ~(1 << aon_gpio); + break; + case RISING: + MMIO_REG_VAL(AON_GPIO_INTTYPE_LEVEL) |= 1 << aon_gpio; + MMIO_REG_VAL(AON_GPIO_INT_POL) |= 1 << aon_gpio; + break; + case FALLING: + MMIO_REG_VAL(AON_GPIO_INTTYPE_LEVEL) |= 1 << aon_gpio; + MMIO_REG_VAL(AON_GPIO_INT_POL) &= ~(1 << aon_gpio); + break; + case HIGH: + MMIO_REG_VAL(AON_GPIO_INTTYPE_LEVEL) &= ~(1 << aon_gpio); + MMIO_REG_VAL(AON_GPIO_INT_POL) |= 1 << aon_gpio; + break; + case LOW: + MMIO_REG_VAL(AON_GPIO_INTTYPE_LEVEL) &= ~(1 << aon_gpio); + MMIO_REG_VAL(AON_GPIO_INT_POL) &= ~(1 << aon_gpio); + break; + default: + MMIO_REG_VAL(AON_GPIO_INTTYPE_LEVEL) &= ~(1 << aon_gpio); + MMIO_REG_VAL(AON_GPIO_INT_POL) &= ~(1 << aon_gpio); + break; + }; + + MMIO_REG_VAL(AON_GPIO_SWPORTA_DDR) &= ~(1 << aon_gpio); + MMIO_REG_VAL(AON_GPIO_INTMASK) &= ~(1 << aon_gpio); + MMIO_REG_VAL(AON_GPIO_INTEN) |= 1 << aon_gpio; + + *AON_GPIO_MASK_INT &= 0xFFFFFEFE; + interrupt_disable(IRQ_ALWAYS_ON_GPIO); + interrupt_connect(IRQ_ALWAYS_ON_GPIO , &soc_aongpio_sleep_isr); + interrupt_enable(IRQ_ALWAYS_ON_GPIO); +} + +void Power::enableAONPTimerInterrrupt(int millis) +{ + WRITE_ARC_REG(QM_IRQ_AONPT_0_INT_VECTOR, QM_SS_AUX_IRQ_SELECT); + WRITE_ARC_REG(QM_SS_IRQ_LEVEL_SENSITIVE, QM_SS_AUX_IRQ_TRIGGER); + + interrupt_disable(IRQ_ALWAYS_ON_TMR); + pmCB = resetAONPTimer; + *AONPT_CFG = millisToRTCTicks(millis); + interrupt_connect(IRQ_ALWAYS_ON_TMR , &aontimer_isr); + *AON_TIMER_MASK_INT &= 0xFFFFFEFE; + *AONPT_CTRL |= 0x00000002; + *AONPT_CTRL |= 0x00000001; + volatile uint32_t aonpt_stat = *AONPT_STAT; + while(aonpt_stat){ + *AONPT_CTRL &= 0xFFFFFFFE; + *AONPT_CTRL |= 0x00000001; + aonpt_stat = *AONPT_STAT; + //delayTicks(1000); + } + interrupt_enable(IRQ_ALWAYS_ON_TMR); +} + +void Power::enableWakeInterrupts() +{ + void (*fptr)(void); + wsrc_t wsrc; + + while (wsrc_get_newest_attached(&wsrc)) { + switch(wsrc.irq){ + case IRQ_ALWAYS_ON_GPIO: + enableAONGPIOInterrupt((wsrc.id-GPIO_END), wsrc_gpio_mode(wsrc.status)); + break; + case IRQ_ALWAYS_ON_TMR: + break; + case IRQ_RTC_INTR: + break; + case IRQ_GPIO0_INTR: + attachInterrupt(wsrc.id, &ss_gpio0_sleep_isr, wsrc_gpio_mode(wsrc.status)); + interrupt_enable(wsrc.irq); + break; + case IRQ_GPIO1_INTR: + attachInterrupt(wsrc.id, &ss_gpio1_sleep_isr, wsrc_gpio_mode(wsrc.status)); + interrupt_enable(wsrc.irq); + break; + case IRQ_GPIO_INTR: + attachInterrupt(wsrc.id, &soc_gpio_sleep_isr, wsrc_gpio_mode(wsrc.status)); + interrupt_enable(wsrc.irq); + break; + case IRQ_TIMER1: + break; + default: + break; + } + } +} + +void Power::resetAONPTimer() +{ + interrupt_disable(IRQ_ALWAYS_ON_TMR); + *AON_TIMER_MASK_INT |= 0xFFFFF1F1; + *AONPT_CFG = 0; + *AONPT_CTRL |= 0x00000001; + WRITE_ARC_REG(QM_IRQ_AONPT_0_INT_VECTOR, QM_SS_AUX_IRQ_SELECT); + WRITE_ARC_REG(QM_SS_IRQ_EDGE_SENSITIVE, QM_SS_AUX_IRQ_TRIGGER); +} + +void Power::wakeFromRTC() +{ + MMIO_REG_VAL(RTC_MASK_INT) |= 0x00000101; + interrupt_disable(IRQ_RTC_INTR); + volatile uint32_t read = MMIO_REG_VAL(RTC_EOI); +} + +void Power::x86_C2Request() +{ + switchToHybridOscillator(); + //request for the x86 core go into C2 sleep + MMIO_REG_VAL(CCU_LP_CLK_CTL) &= 0xFFFFFFFC; + volatile uint32_t c2 = MMIO_REG_VAL(P_LVL2); +} + +void Power::x86_C2LPRequest() +{ + switchToHybridOscillator(); + //request for the x86 core go into C2LP sleep + MMIO_REG_VAL(CCU_LP_CLK_CTL) &= 0xFFFFFFFE; + MMIO_REG_VAL(CCU_LP_CLK_CTL) |= 0x00000002; + volatile uint32_t c2lp = MMIO_REG_VAL(P_LVL2); +} diff --git a/libraries/CuriePowerManagement/src/Power.h b/libraries/CuriePowerManagement/src/Power.h new file mode 100644 index 00000000..dfd919b6 --- /dev/null +++ b/libraries/CuriePowerManagement/src/Power.h @@ -0,0 +1,133 @@ +#define OSC0_STAT 0xB0800004 +#define OSC0_CFG1 0xB0800008 + +#define CCU_SS_PERIPH_CLK_GATE_CTL 0xB0800028 +#define CCU_LP_CLK_CTL 0xB080002C +#define CCU_SYS_CLK_CTL 0xB0800038 +#define P_LVL2 0xB0800504 +#define PM1C 0xB0800518 +#define SLP_CFG 0xB0800550 +#define SS_STS 0xB0800604 + +#define AONC_CNT 0xB0800700 +#define AONC_CFG 0xB0800704 +#define AONPT_CNT 0xB0800708 +#define AONPT_STAT (volatile int*)0xB080070C +#define AONPT_CTRL (volatile int*)0xB0800710 +#define AONPT_CFG (volatile int*)0xB0800714 + +#define USB_PLL_CFG0 0xB0800014 +#define USB_PHY_CFG0 0xB0800800 + +#define RTC_CCVR (volatile int*)0xB0000400 // Current Counter Value Register +#define RTC_CMR 0xB0000404 +#define RTC_CCR 0xB000040C +#define RTC_EOI 0xB0000418 + +#define RTC_MASK_INT 0xB0800478 +#define AON_TIMER_MASK_INT (volatile int*)0xB08004C8 +#define AON_GPIO_MASK_INT (volatile int*)0xB08004D4 + +#define AON_GPIO_SWPORTA_DR 0xB0800B00 +#define AON_GPIO_SWPORTA_DDR 0xB0800B04 +#define AON_GPIO_SWPORTA_CTL 0xB0800B08 +#define AON_GPIO_INTEN 0xB0800B30 +#define AON_GPIO_INTMASK 0xB0800B34 +#define AON_GPIO_INTTYPE_LEVEL 0xB0800B38 +#define AON_GPIO_INT_POL 0xB0800B3C +#define AON_GPIO_DEBOUNCE 0xB0888B48 +#define AON_GPIO_PORTA_EOI 0xB0800B4C + +#define OSCTRIM_ADDR 0xffffe1f8 + +#define QM_SS_SLEEP_MODE_CORE_OFF (0x0) +#define QM_SS_SLEEP_MODE_CORE_OFF_TIMER_OFF (0x20) +#define QM_SS_SLEEP_MODE_CORE_TIMERS_RTC_OFF (0x60) + +#define P_STS 0xB0800560 + +#define LPMODE_EN 8 + +#include +#include +#include +#include +#include +#include "qmsi/qm_sensor_regs.h" +#include "qmsi/ss_power_states.h" +#include "wsrc.h" + +static volatile bool soc_sleeping = false; +static volatile bool soc_dozing = false; + +class Power +{ + public: + Power(); + + //puts the SoC into "doze" mode which lowers the system clock speed to 32k + void doze(); + + void doze(int duration); + + void idle(); + + void idle(int duration); + + void wakeFromDoze(); + + void sleep(); + + void sleep(int duration); + + void deepSleep(); + + void deepSleep(int duration); + + void wakeFromSleepCallback(void); + + void wakeFromDozeCallback(void); + + void attachInterruptWakeup(uint32_t pin, voidFuncPtr callback, uint32_t mode); + + void detachInterruptWakeup(uint32_t pin); + + uint32_t arc_restore_addr; + + private: + void turnOffUSB(); + + void turnOnUSB(); + + void switchToHybridOscillator(); + + void switchToCrystalOscillator(); + + void setRTCCMR(int seconds); + + uint32_t readRTC_CCVR(); + + bool isSleeping = false; + + uint32_t millisToRTCTicks(int milliseconds); + + void enableRTCInterrupt(int seconds); + + void enableAONGPIOInterrupt(int aon_gpio, int mode); + + void enableAONPTimerInterrrupt(int millis); + + void enableWakeInterrupts(); + + static void resetAONPTimer(); + + static void wakeFromRTC(); + + void x86_C2Request(); + + void x86_C2LPRequest(); + + void (*pmCB)(); +}; + +extern Power PM; diff --git a/libraries/CuriePowerManagement/src/qmsi/power_states.h b/libraries/CuriePowerManagement/src/qmsi/power_states.h new file mode 100644 index 00000000..eb5fecf0 --- /dev/null +++ b/libraries/CuriePowerManagement/src/qmsi/power_states.h @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2016, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of the Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INTEL CORPORATION OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __POWER_STATES_H__ +#define __POWER_STATES_H__ + +/** + * SoC Power mode control for Quark SE Microcontrollers. + * + * Available SoC states are: + * - Low Power Sensing Standby (LPSS) + * - Sleep + * + * LPSS can only be enabled from the Sensor core, + * refer to @ref ss_power_soc_lpss_enable for further details. + * + * @defgroup groupSoCPower Quark SE SoC Power states + * @{ + */ + +/** + * Enter SoC sleep state. + * + * Put the SoC into sleep state until next SoC wake event. + * + * - Core well is turned off + * - Always on well is on + * - Hybrid Clock is off + * - RTC Clock is on + * + * Possible SoC wake events are: + * - Low Power Comparator Interrupt + * - AON GPIO Interrupt + * - AON Timer Interrupt + * - RTC Interrupt + */ +void power_soc_sleep(void); + +/** + * Enter SoC deep sleep state. + * + * Put the SoC into deep sleep state until next SoC wake event. + * + * - Core well is turned off + * - Always on well is on + * - Hybrid Clock is off + * - RTC Clock is on + * + * Possible SoC wake events are: + * - Low Power Comparator Interrupt + * - AON GPIO Interrupt + * - AON Timer Interrupt + * - RTC Interrupt + * + * This function puts 1P8V regulators and 3P3V into Linear Mode. + */ +void power_soc_deep_sleep(void); + +/** + * @} + */ + +#endif /* __POWER_STATES_H__ */ diff --git a/libraries/CuriePowerManagement/src/qmsi/qm_interrupt_router_regs.h b/libraries/CuriePowerManagement/src/qmsi/qm_interrupt_router_regs.h new file mode 100644 index 00000000..216612e9 --- /dev/null +++ b/libraries/CuriePowerManagement/src/qmsi/qm_interrupt_router_regs.h @@ -0,0 +1,207 @@ +/* + * Copyright (c) 2016, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of the Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INTEL CORPORATION OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __QM_INTERRUPT_ROUTER_REGS_H__ +#define __QM_INTERRUPT_ROUTER_REGS_H__ + +/** + * Quark SE SoC Event Router registers. + * + * @defgroup groupQUARKSESEEVENTROUTER SoC Event Router (SE) + * @{ + */ + +/** + * Masks for single source interrupts in the Event Router. + * To enable: reg &= ~(MASK) + * To disable: reg |= MASK; + */ +#define QM_IR_INT_LMT_MASK BIT(0) +#define QM_IR_INT_SS_MASK BIT(8) + +/* Masks for single source halts in the Event Router. */ +#define QM_IR_INT_LMT_HALT_MASK BIT(16) +#define QM_IR_INT_SS_HALT_MASK BIT(24) + +/* Event Router Unmask interrupts for a peripheral. */ +#define QM_IR_UNMASK_LMT_INTERRUPTS(_peripheral_) \ + (_peripheral_ &= ~(QM_IR_INT_LMT_MASK)) +#define QM_IR_UNMASK_SS_INTERRUPTS(_peripheral_) \ + (_peripheral_ &= ~(QM_IR_INT_SS_MASK)) + +/* Mask interrupts for a peripheral. */ +#define QM_IR_MASK_LMT_INTERRUPTS(_peripheral_) \ + (_peripheral_ |= QM_IR_INT_LMT_MASK) +#define QM_IR_MASK_SS_INTERRUPTS(_peripheral_) \ + (_peripheral_ |= QM_IR_INT_SS_MASK) + +/* Unmask halt for a peripheral. */ +#define QM_IR_UNMASK_LMT_HALTS(_peripheral_) \ + (_peripheral_ &= ~(QM_IR_INT_LMT_HALT_MASK)) +#define QM_IR_UNMASK_SS_HALTS(_peripheral_) \ + (_peripheral_ &= ~(QM_IR_INT_SS_HALT_MASK)) + +/* Mask halt for a peripheral. */ +#define QM_IR_MASK_LMT_HALTS(_peripheral_) \ + (_peripheral_ |= QM_IR_INT_LMT_HALT_MASK) +#define QM_IR_MASK_SS_HALTS(_peripheral_) \ + (_peripheral_ |= QM_IR_INT_SS_HALT_MASK) + +#define QM_IR_GET_LMT_MASK(_peripheral_) (_peripheral_ & QM_IR_INT_LMT_MASK) +#define QM_IR_GET_LMT_HALT_MASK(_peripheral_) \ + (_peripheral_ & QM_IR_INT_LMT_HALT_MASK) + +#define QM_IR_GET_SS_MASK(_peripheral_) (_peripheral_ & QM_IR_INT_SS_MASK) +#define QM_IR_GET_SS_HALT_MASK(_peripheral_) \ + (_peripheral_ & QM_IR_INT_SS_HALT_MASK) + +/* Define macros for use by the active core. */ +#if (QM_LAKEMONT) +#define QM_IR_UNMASK_INTERRUPTS(_peripheral_) \ + QM_IR_UNMASK_LMT_INTERRUPTS(_peripheral_) +#define QM_IR_MASK_INTERRUPTS(_peripheral_) \ + QM_IR_MASK_LMT_INTERRUPTS(_peripheral_) +#define QM_IR_UNMASK_HALTS(_peripheral_) QM_IR_UNMASK_LMT_HALTS(_peripheral_) +#define QM_IR_MASK_HALTS(_peripheral_) QM_IR_MASK_LMT_HALTS(_peripheral_) + +#define QM_IR_INT_MASK QM_IR_INT_LMT_MASK +#define QM_IR_INT_HALT_MASK QM_IR_INT_LMT_HALT_MASK +#define QM_IR_GET_MASK(_peripheral_) QM_IR_GET_LMT_MASK(_peripheral_) +#define QM_IR_GET_HALT_MASK(_peripheral_) QM_IR_GET_LMT_HALT_MASK(_peripheral_) + +#elif(QM_SENSOR) +#define QM_IR_UNMASK_INTERRUPTS(_peripheral_) \ + QM_IR_UNMASK_SS_INTERRUPTS(_peripheral_) +#define QM_IR_MASK_INTERRUPTS(_peripheral_) \ + QM_IR_MASK_SS_INTERRUPTS(_peripheral_) +#define QM_IR_UNMASK_HALTS(_peripheral_) QM_IR_UNMASK_SS_HALTS(_peripheral_) +#define QM_IR_MASK_HALTS(_peripheral_) QM_IR_MASK_SS_HALTS(_peripheral_) + +#define QM_IR_INT_MASK QM_IR_INT_SS_MASK +#define QM_IR_INT_HALT_MASK QM_IR_INT_SS_HALT_MASK +#define QM_IR_GET_MASK(_peripheral_) QM_IR_GET_SS_MASK(_peripheral_) +#define QM_IR_GET_HALT_MASK(_peripheral_) QM_IR_GET_SS_HALT_MASK(_peripheral_) +#else +#error "No active core selected." +#endif + +/** SS I2C Interrupt register map. */ +typedef struct { + QM_RW uint32_t err_mask; + QM_RW uint32_t rx_avail_mask; + QM_RW uint32_t tx_req_mask; + QM_RW uint32_t stop_det_mask; +} int_ss_i2c_reg_t; + +/** SS SPI Interrupt register map. */ +typedef struct { + QM_RW uint32_t err_int_mask; + QM_RW uint32_t rx_avail_mask; + QM_RW uint32_t tx_req_mask; +} int_ss_spi_reg_t; + +/** Interrupt register map. */ +typedef struct { + QM_RW uint32_t ss_adc_0_error_int_mask; /**< Sensor ADC 0 Error. */ + QM_RW uint32_t ss_adc_0_int_mask; /**< Sensor ADC 0. */ + QM_RW uint32_t ss_gpio_0_int_mask; /**< Sensor GPIO 0. */ + QM_RW uint32_t ss_gpio_1_int_mask; /**< Sensor GPIO 1. */ + int_ss_i2c_reg_t ss_i2c_0_int; /**< Sensor I2C 0 Masks. */ + int_ss_i2c_reg_t ss_i2c_1_int; /**< Sensor I2C 1 Masks. */ + int_ss_spi_reg_t ss_spi_0_int; /**< Sensor SPI 0 Masks. */ + int_ss_spi_reg_t ss_spi_1_int; /**< Sensor SPI 1 Masks. */ + QM_RW uint32_t i2c_master_0_int_mask; /**< I2C Master 0. */ + QM_RW uint32_t i2c_master_1_int_mask; /**< I2C Master 1. */ + QM_R uint32_t reserved; + QM_RW uint32_t spi_master_0_int_mask; /**< SPI Master 0. */ + QM_RW uint32_t spi_master_1_int_mask; /**< SPI Master 1. */ + QM_RW uint32_t spi_slave_0_int_mask; /**< SPI Slave 0. */ + QM_RW uint32_t uart_0_int_mask; /**< UART 0. */ + QM_RW uint32_t uart_1_int_mask; /**< UART 1. */ + QM_RW uint32_t i2s_0_int_mask; /**< I2S 0. */ + QM_RW uint32_t gpio_0_int_mask; /**< GPIO 0. */ + QM_RW uint32_t pwm_0_int_mask; /**< PWM 0. */ + QM_RW uint32_t usb_0_int_mask; /**< USB 0. */ + QM_RW uint32_t rtc_0_int_mask; /**< RTC 0. */ + QM_RW uint32_t wdt_0_int_mask; /**< WDT 0. */ + QM_RW uint32_t dma_0_int_0_mask; /**< DMA 0 Ch 0. */ + QM_RW uint32_t dma_0_int_1_mask; /**< DMA 0 Ch 1. */ + QM_RW uint32_t dma_0_int_2_mask; /**< DMA 0 Ch 2. */ + QM_RW uint32_t dma_0_int_3_mask; /**< DMA 0 Ch 3. */ + QM_RW uint32_t dma_0_int_4_mask; /**< DMA 0 Ch 4. */ + QM_RW uint32_t dma_0_int_5_mask; /**< DMA 0 Ch 5. */ + QM_RW uint32_t dma_0_int_6_mask; /**< DMA 0 Ch 6. */ + QM_RW uint32_t dma_0_int_7_mask; /**< DMA 0 Ch 7. */ + /** Mailbox 0 Combined 8 Channel Host and Sensor Masks. */ + QM_RW uint32_t mailbox_0_int_mask; + /** Comparator Sensor Halt Mask. */ + QM_RW uint32_t comparator_0_ss_halt_int_mask; + /** Comparator Host Halt Mask. */ + QM_RW uint32_t comparator_0_host_halt_int_mask; + /** Comparator Sensor Mask. */ + QM_RW uint32_t comparator_0_ss_int_mask; + /** Comparator Host Mask. */ + QM_RW uint32_t comparator_0_host_int_mask; + QM_RW uint32_t host_bus_error_int_mask; /**< Host bus error. */ + QM_RW uint32_t dma_0_error_int_mask; /**< DMA 0 Error. */ + QM_RW uint32_t sram_mpr_0_int_mask; /**< SRAM MPR 0. */ + QM_RW uint32_t flash_mpr_0_int_mask; /**< Flash MPR 0. */ + QM_RW uint32_t flash_mpr_1_int_mask; /**< Flash MPR 1. */ + QM_RW uint32_t aonpt_0_int_mask; /**< AONPT 0. */ + QM_RW uint32_t adc_0_pwr_int_mask; /**< ADC 0 PWR. */ + QM_RW uint32_t adc_0_cal_int_mask; /**< ADC 0 CAL. */ + QM_RW uint32_t aon_gpio_0_int_mask; /**< AON GPIO 0. */ + QM_RW uint32_t lock_int_mask_reg; /**< Interrupt Mask Lock Register. */ +} qm_interrupt_router_reg_t; + +/* Number of SCSS interrupt mask registers (excluding mask lock register). */ +#define QM_INTERRUPT_ROUTER_MASK_NUMREG \ + ((sizeof(qm_interrupt_router_reg_t) / sizeof(uint32_t)) - 1) + +/* Default POR SCSS interrupt mask (all interrupts masked). */ +#define QM_INTERRUPT_ROUTER_MASK_DEFAULT (0xFFFFFFFF) + +#if (UNIT_TEST) +qm_interrupt_router_reg_t test_interrupt_router; +#define QM_INTERRUPT_ROUTER \ + ((qm_interrupt_router_reg_t *)(&test_interrupt_router)) + +#else +/* System control subsystem interrupt masking register block. */ +#define QM_INTERRUPT_ROUTER_BASE (0xB0800400) +#define QM_INTERRUPT_ROUTER \ + ((qm_interrupt_router_reg_t *)QM_INTERRUPT_ROUTER_BASE) +#endif + +#define QM_IR_DMA_ERROR_HOST_MASK (0x000000FF) +#define QM_IR_DMA_ERROR_SS_MASK (0x0000FF00) + +/** @} */ + +#endif /* __QM_INTERRUPT_ROUTER_REGS_H__ */ diff --git a/libraries/CuriePowerManagement/src/qmsi/qm_sensor_regs.h b/libraries/CuriePowerManagement/src/qmsi/qm_sensor_regs.h new file mode 100644 index 00000000..324d001e --- /dev/null +++ b/libraries/CuriePowerManagement/src/qmsi/qm_sensor_regs.h @@ -0,0 +1,673 @@ +/* + * Copyright (c) 2016, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of the Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INTEL CORPORATION OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __SENSOR_REGISTERS_H__ +#define __SENSOR_REGISTERS_H__ + +/** + * Quark SE SoC Sensor Subsystem Registers. + * + * For detailed description please read the SOC datasheet. + * + * @defgroup groupSSSEREG SoC Registers (Sensor Subsystem) + * @{ + */ + +#define BIT(x) (1U << (x)) + +/* Bitwise OR operation macro for registers in the auxiliary memory space. */ +#define QM_SS_REG_AUX_OR(reg, mask) \ + (__builtin_arc_sr(__builtin_arc_lr(reg) | (mask), reg)) +/* Bitwise NAND operation macro for registers in the auxiliary memory space. */ +#define QM_SS_REG_AUX_NAND(reg, mask) \ + (__builtin_arc_sr(__builtin_arc_lr(reg) & (~(mask)), reg)) + +/* Sensor Subsystem status32 register. */ +#define QM_SS_AUX_STATUS32 (0xA) +/** Interrupt priority threshold. */ +#define QM_SS_STATUS32_E_MASK (0x1E) +/** Interrupt enable. */ +#define QM_SS_STATUS32_IE_MASK BIT(31) +/* Sensor Subsystem control register. */ +#define QM_SS_AUX_IC_CTRL (0x11) +/* Sensor Subsystem cache invalidate register. */ +#define QM_SS_AUX_IC_IVIL (0x19) +/* Sensor Subsystem vector base register. */ +#define QM_SS_AUX_INT_VECTOR_BASE (0x25) + +/** + * @name SS Interrupt + * @{ + */ + +#define QM_SS_EXCEPTION_NUM (16) /* Exceptions and traps in ARC EM core. */ +#define QM_SS_INT_TIMER_NUM (2) /* Internal interrupts in ARC EM core. */ +#define QM_SS_IRQ_SENSOR_NUM (18) /* IRQ's from the Sensor Subsystem. */ +#define QM_SS_IRQ_COMMON_NUM (32) /* IRQ's from the common SoC fabric. */ +#define QM_SS_INT_VECTOR_NUM \ + (QM_SS_EXCEPTION_NUM + QM_SS_INT_TIMER_NUM + QM_SS_IRQ_SENSOR_NUM + \ + QM_SS_IRQ_COMMON_NUM) +#define QM_SS_IRQ_NUM (QM_SS_IRQ_SENSOR_NUM + QM_SS_IRQ_COMMON_NUM) + +/** + * SS IRQ context type. + * + * Applications should not modify the content. + * This structure is only intended to be used by + * qm_irq_save_context and qm_irq_restore_context functions. + */ +typedef struct { + uint32_t status32_irq_threshold; /**< STATUS32 Interrupt Threshold. */ + uint32_t status32_irq_enable; /**< STATUS32 Interrupt Enable. */ + uint32_t irq_ctrl; /**< Interrupt Context Saving Control Register. */ + + /** + * IRQ configuration: + * - IRQ Priority:BIT(6):BIT(2) + * - IRQ Trigger:BIT(1) + * - IRQ Enable:BIT(0) + */ + uint8_t irq_config[QM_SS_INT_VECTOR_NUM - 1]; +} qm_irq_context_t; + +/** General Purpose register map. */ +typedef struct { + volatile uint32_t gps0; /**< General Purpose Sticky Register 0 */ + volatile uint32_t gps1; /**< General Purpose Sticky Register 1 */ + volatile uint32_t gps2; /**< General Purpose Sticky Register 2 */ + volatile uint32_t gps3; /**< General Purpose Sticky Register 3 */ + volatile uint32_t reserved; + volatile uint32_t gp0; /**< General Purpose Scratchpad Register 0 */ + volatile uint32_t gp1; /**< General Purpose Scratchpad Register 1 */ + volatile uint32_t gp2; /**< General Purpose Scratchpad Register 2 */ + volatile uint32_t gp3; /**< General Purpose Scratchpad Register 3 */ + volatile uint32_t reserved1; + volatile uint32_t id; /**< Identification Register */ + volatile uint32_t rev; /**< Revision Register */ + volatile uint32_t wo_sp; /**< Write-One-to-Set Scratchpad Register */ + volatile uint32_t + wo_st; /**< Write-One-to-Set Sticky Scratchpad Register */ +} qm_scss_gp_reg_t; + +#define QM_SCSS_GP_BASE (0xB0800100) +#define QM_SCSS_GP ((qm_scss_gp_reg_t *)QM_SCSS_GP_BASE) + +/* The GPS0 register usage. */ +#define QM_GPS0_BIT_FM (0) /**< Start Firmware Manager. */ +#define QM_GPS0_BIT_X86_WAKEUP (1) /**< Lakemont core reset type. */ +#define QM_GPS0_BIT_SENSOR_WAKEUP (2) /**< Sensor core reset type. */ + +/** System Core register map. */ +typedef struct { + volatile uint32_t osc0_cfg0; /**< Hybrid Oscillator Configuration 0. */ + volatile uint32_t osc0_stat1; /**< Hybrid Oscillator status 1. */ + volatile uint32_t osc0_cfg1; /**< Hybrid Oscillator configuration 1. */ + volatile uint32_t osc1_stat0; /**< RTC Oscillator status 0. */ + volatile uint32_t osc1_cfg0; /**< RTC Oscillator Configuration 0. */ + volatile uint32_t usb_pll_cfg0; /**< USB Phase lock look configuration. */ + volatile uint32_t + ccu_periph_clk_gate_ctl; /**< Peripheral Clock Gate Control. */ + volatile uint32_t + ccu_periph_clk_div_ctl0; /**< Peripheral Clock Divider Control. 0 */ + volatile uint32_t + ccu_gpio_db_clk_ctl; /**< Peripheral Clock Divider Control 1. */ + volatile uint32_t + ccu_ext_clock_ctl; /**< External Clock Control Register. */ + /** Sensor Subsystem peripheral clock gate control. */ + volatile uint32_t ccu_ss_periph_clk_gate_ctl; + volatile uint32_t ccu_lp_clk_ctl; /**< System Low Power Clock Control. */ + volatile uint32_t reserved; + volatile uint32_t ccu_mlayer_ahb_ctl; /**< AHB Control Register. */ + volatile uint32_t ccu_sys_clk_ctl; /**< System Clock Control Register. */ + volatile uint32_t osc_lock_0; /**< Clocks Lock Register. */ +} qm_scss_ccu_reg_t; + +#define QM_SCSS_CCU ((qm_scss_ccu_reg_t *)SCSS_REGISTER_BASE) + +/** Power Management register map. */ +typedef struct { + volatile uint32_t p_lvl2; /**< Processor level 2 */ + volatile uint32_t reserved[4]; + volatile uint32_t pm1c; /**< Power management 1 control */ + volatile uint32_t reserved1[9]; + volatile uint32_t aon_vr; /**< AON Voltage Regulator */ + volatile uint32_t plat3p3_vr; /**< Platform 3p3 voltage regulator */ + volatile uint32_t plat1p8_vr; /**< Platform 1p8 voltage regulator */ + volatile uint32_t host_vr; /**< Host Voltage Regulator */ + volatile uint32_t slp_cfg; /**< Sleeping Configuration */ + /** Power Management Network (PMNet) Control and Status */ + volatile uint32_t pmnetcs; + volatile uint32_t pm_wait; /**< Power Management Wait */ + volatile uint32_t reserved2; + volatile uint32_t p_sts; /**< Processor Status */ + volatile uint32_t reserved3[3]; + volatile uint32_t rstc; /**< Reset Control */ + volatile uint32_t rsts; /**< Reset Status */ + volatile uint32_t reserved4[6]; + volatile uint32_t vr_lock; /**< Voltage regulator lock */ + volatile uint32_t pm_lock; /**< Power Management Lock */ +} qm_scss_pmu_reg_t; + +#define QM_SCSS_PMU_BASE (0xB0800504) +#define QM_SCSS_PMU ((qm_scss_pmu_reg_t *)QM_SCSS_PMU_BASE) + +#define QM_SS_CFG_ARC_RUN_REQ_A BIT(24) +#define QM_P_STS_HALT_INTERRUPT_REDIRECTION BIT(26) +#define QM_P_STS_ARC_HALT BIT(14) + +#define QM_AON_VR_VSEL_MASK (0xFFE0) +#define QM_AON_VR_VSEL_1V2 (0x8) +#define QM_AON_VR_VSEL_1V35 (0xB) +#define QM_AON_VR_VSEL_1V8 (0x10) +#define QM_AON_VR_EN BIT(7) +#define QM_AON_VR_VSTRB BIT(5) + +#define QM_SCSS_SLP_CFG_LPMODE_EN BIT(8) +#define QM_SCSS_SLP_CFG_RTC_DIS BIT(7) +#define QM_SCSS_PM1C_SLPEN BIT(13) +#define QM_SCSS_HOST_VR_EN BIT(7) +#define QM_SCSS_PLAT3P3_VR_EN BIT(7) +#define QM_SCSS_PLAT1P8_VR_EN BIT(7) +#define QM_SCSS_HOST_VR_VREG_SEL BIT(6) +#define QM_SCSS_PLAT3P3_VR_VREG_SEL BIT(6) +#define QM_SCSS_PLAT1P8_VR_VREG_SEL BIT(6) +#define QM_SCSS_VR_ROK BIT(10) +#define QM_SCSS_VR_EN BIT(7) +#define QM_SCSS_VR_VREG_SEL BIT(6) + +#define QM_SCSS_CCU_SS_LPS_EN BIT(0) + +typedef enum { + QM_SS_IRQ_LEVEL_SENSITIVE = 0, + QM_SS_IRQ_EDGE_SENSITIVE = 1 +} qm_ss_irq_trigger_t; + +#define QM_SS_AUX_IRQ_CTRL (0xE) +#define QM_SS_AUX_IRQ_HINT (0x201) +#define QM_SS_AUX_IRQ_PRIORITY (0x206) +#define QM_SS_AUX_IRQ_STATUS (0x406) +#define QM_SS_AUX_IRQ_SELECT (0x40B) +#define QM_SS_AUX_IRQ_ENABLE (0x40C) +#define QM_SS_AUX_IRQ_TRIGGER (0x40D) + +/** Always-On Timer Interrupt. */ +#define QM_IRQ_AONPT_0_INT 28 +#define QM_IRQ_AONPT_0_INT_MASK_OFFSET 32 +#define QM_IRQ_AONPT_0_INT_VECTOR 64 + +/** RTC Single Interrupt. */ +#define QM_IRQ_RTC_0_INT 11 +#define QM_IRQ_RTC_0_INT_MASK_OFFSET 12 +#define QM_IRQ_RTC_0_INT_VECTOR 47 + +/** @} */ + +/** + * @name SS Timer + * @{ + */ + +typedef enum { + QM_SS_TIMER_COUNT = 0, + QM_SS_TIMER_CONTROL, + QM_SS_TIMER_LIMIT +} qm_ss_timer_reg_t; + +/** + * Sensor Subsystem Timers. + */ +typedef enum { QM_SS_TIMER_0 = 0, QM_SS_TIMER_NUM } qm_ss_timer_t; + +/* + * SS TIMER context type. + * + * Application should not modify the content. + * This structure is only intended to be used by the qm_ss_timer_save_context + * and qm_ss_timer_restore_context functions. + */ +typedef struct { + uint32_t timer_count; /**< Timer count. */ + uint32_t timer_control; /**< Timer control. */ + uint32_t timer_limit; /**< Timer limit. */ +} qm_ss_timer_context_t; + +#define QM_SS_TIMER_0_BASE (0x21) +#define QM_SS_TIMER_1_BASE (0x100) +#define QM_SS_TSC_BASE QM_SS_TIMER_1_BASE + +#define QM_SS_TIMER_CONTROL_INT_EN_OFFSET (0) +#define QM_SS_TIMER_CONTROL_NON_HALTED_OFFSET (1) +#define QM_SS_TIMER_CONTROL_WATCHDOG_OFFSET (2) +#define QM_SS_TIMER_CONTROL_INT_PENDING_OFFSET (3) +/** @} */ + +/** + * GPIO registers and definitions. + * + * @name SS GPIO + * @{ + */ + +/** Sensor Subsystem GPIO register block type. */ +typedef enum { + QM_SS_GPIO_SWPORTA_DR = 0, + QM_SS_GPIO_SWPORTA_DDR, + QM_SS_GPIO_INTEN = 3, + QM_SS_GPIO_INTMASK, + QM_SS_GPIO_INTTYPE_LEVEL, + QM_SS_GPIO_INT_POLARITY, + QM_SS_GPIO_INTSTATUS, + QM_SS_GPIO_DEBOUNCE, + QM_SS_GPIO_PORTA_EOI, + QM_SS_GPIO_EXT_PORTA, + QM_SS_GPIO_LS_SYNC +} qm_ss_gpio_reg_t; + +/** + * SS GPIO context type. + * + * Application should not modify the content. + * This structure is only intended to be used by the qm_ss_gpio_save_context and + * qm_ss_gpio_restore_context functions. + */ +typedef struct { + uint32_t gpio_swporta_dr; /**< Port A Data. */ + uint32_t gpio_swporta_ddr; /**< Port A Data Direction. */ + uint32_t gpio_inten; /**< Interrupt Enable. */ + uint32_t gpio_intmask; /**< Interrupt Mask. */ + uint32_t gpio_inttype_level; /**< Interrupt Type. */ + uint32_t gpio_int_polarity; /**< Interrupt Polarity. */ + uint32_t gpio_debounce; /**< Debounce Enable. */ + uint32_t gpio_ls_sync; /**< Synchronization Level. */ +} qm_ss_gpio_context_t; + +#define QM_SS_GPIO_NUM_PINS (16) +#define QM_SS_GPIO_LS_SYNC_CLK_EN BIT(31) +#define QM_SS_GPIO_LS_SYNC_SYNC_LVL BIT(0) + +/** Sensor Subsystem GPIO. */ +typedef enum { QM_SS_GPIO_0 = 0, QM_SS_GPIO_1, QM_SS_GPIO_NUM } qm_ss_gpio_t; + +#define QM_SS_GPIO_0_BASE (0x80017800) +#define QM_SS_GPIO_1_BASE (0x80017900) + +/** @} */ + +/** + * I2C registers and definitions. + * + * @name SS I2C + * @{ + */ + +/** Sensor Subsystem I2C register block type. */ +typedef enum { + QM_SS_I2C_CON = 0, + QM_SS_I2C_DATA_CMD, + QM_SS_I2C_SS_SCL_CNT, + QM_SS_I2C_FS_SCL_CNT = 0x04, + QM_SS_I2C_INTR_STAT = 0x06, + QM_SS_I2C_INTR_MASK, + QM_SS_I2C_TL, + QM_SS_I2C_INTR_CLR = 0x0A, + QM_SS_I2C_STATUS, + QM_SS_I2C_TXFLR, + QM_SS_I2C_RXFLR, + QM_SS_I2C_SDA_CONFIG, + QM_SS_I2C_TX_ABRT_SOURCE, + QM_SS_I2C_ENABLE_STATUS = 0x11 +} qm_ss_i2c_reg_t; + +/** + * SS I2C context type. + * + * Application should not modify the content. + * This structure is only intended to be used by the qm_ss_gpio_save_context and + * qm_ss_gpio_restore_context functions. + */ +typedef struct { + uint32_t i2c_con; + uint32_t i2c_ss_scl_cnt; + uint32_t i2c_fs_scl_cnt; +} qm_ss_i2c_context_t; + +#define QM_SS_I2C_CON_ENABLE BIT(0) +#define QM_SS_I2C_CON_ABORT BIT(1) +#define QM_SS_I2C_CON_SPEED_SS BIT(3) +#define QM_SS_I2C_CON_SPEED_FS BIT(4) +#define QM_SS_I2C_CON_SPEED_MASK (0x18) +#define QM_SS_I2C_CON_IC_10BITADDR BIT(5) +#define QM_SS_I2C_CON_IC_10BITADDR_OFFSET (5) +#define QM_SS_I2C_CON_IC_10BITADDR_MASK (5) +#define QM_SS_I2C_CON_RESTART_EN BIT(7) +#define QM_SS_I2C_CON_TAR_SAR_OFFSET (9) +#define QM_SS_I2C_CON_TAR_SAR_MASK (0x7FE00) +#define QM_SS_I2C_CON_TAR_SAR_10_BIT_MASK (0x3FF) +#define QM_SS_I2C_CON_SPKLEN_OFFSET (22) +#define QM_SS_I2C_CON_SPKLEN_MASK (0x3FC00000) +#define QM_SS_I2C_CON_CLK_ENA BIT(31) + +#define QM_SS_I2C_DATA_CMD_CMD BIT(8) +#define QM_SS_I2C_DATA_CMD_STOP BIT(9) +#define QM_SS_I2C_DATA_CMD_PUSH (0xC0000000) +#define QM_SS_I2C_DATA_CMD_POP (0x80000000) + +#define QM_SS_I2C_SS_FS_SCL_CNT_HCNT_OFFSET (16) +#define QM_SS_I2C_SS_FS_SCL_CNT_16BIT_MASK (0xFFFF) + +#define QM_SS_I2C_INTR_STAT_RX_UNDER BIT(0) +#define QM_SS_I2C_INTR_STAT_RX_OVER BIT(1) +#define QM_SS_I2C_INTR_STAT_RX_FULL BIT(2) +#define QM_SS_I2C_INTR_STAT_TX_OVER BIT(3) +#define QM_SS_I2C_INTR_STAT_TX_EMPTY BIT(4) +#define QM_SS_I2C_INTR_STAT_TX_ABRT BIT(6) + +#define QM_SS_I2C_INTR_MASK_ALL (0x0) +#define QM_SS_I2C_INTR_MASK_RX_UNDER BIT(0) +#define QM_SS_I2C_INTR_MASK_RX_OVER BIT(1) +#define QM_SS_I2C_INTR_MASK_RX_FULL BIT(2) +#define QM_SS_I2C_INTR_MASK_TX_OVER BIT(3) +#define QM_SS_I2C_INTR_MASK_TX_EMPTY BIT(4) +#define QM_SS_I2C_INTR_MASK_TX_ABRT BIT(6) + +#define QM_SS_I2C_TL_TX_TL_OFFSET (16) +#define QM_SS_I2C_TL_RX_TL_MASK (0xFF) +#define QM_SS_I2C_TL_TX_TL_MASK (0xFF0000) + +#define QM_SS_I2C_INTR_CLR_ALL (0xFF) +#define QM_SS_I2C_INTR_CLR_TX_ABRT BIT(6) + +#define QM_SS_I2C_TX_ABRT_SOURCE_NAK_MASK (0x09) +#define QM_SS_I2C_TX_ABRT_SOURCE_ALL_MASK (0x1FFFF) +#define QM_SS_I2C_TX_ABRT_SBYTE_NORSTRT BIT(9) +#define QM_SS_I2C_TX_ABRT_SOURCE_ART_LOST BIT(12) + +#define QM_SS_I2C_ENABLE_CONTROLLER_EN BIT(0) +#define QM_SS_I2C_ENABLE_STATUS_IC_EN BIT(0) + +#define QM_SS_I2C_STATUS_BUSY_MASK (0x21) +#define QM_SS_I2C_STATUS_RFNE BIT(3) +#define QM_SS_I2C_STATUS_TFE BIT(2) +#define QM_SS_I2C_STATUS_TFNF BIT(1) + +#define QM_SS_I2C_IC_LCNT_MAX (65525) +#define QM_SS_I2C_IC_LCNT_MIN (8) +#define QM_SS_I2C_IC_HCNT_MAX (65525) +#define QM_SS_I2C_IC_HCNT_MIN (6) + +#define QM_SS_I2C_FIFO_SIZE (8) + +/** Sensor Subsystem I2C */ +typedef enum { QM_SS_I2C_0 = 0, QM_SS_I2C_1, QM_SS_I2C_NUM } qm_ss_i2c_t; + +#define QM_SS_I2C_0_BASE (0x80012000) +#define QM_SS_I2C_1_BASE (0x80012100) + +/** @} */ +/** Sensor Subsystem ADC @{*/ + +/** Sensor Subsystem ADC registers */ +typedef enum { + QM_SS_ADC_SET = 0, /**< ADC and sequencer settings register. */ + QM_SS_ADC_DIVSEQSTAT, /**< ADC clock and sequencer status register. */ + QM_SS_ADC_SEQ, /**< ADC sequence entry register. */ + QM_SS_ADC_CTRL, /**< ADC control register. */ + QM_SS_ADC_INTSTAT, /**< ADC interrupt status register. */ + QM_SS_ADC_SAMPLE /**< ADC sample register. */ +} qm_ss_adc_reg_t; + +/** Sensor Subsystem ADC */ +typedef enum { + QM_SS_ADC_0 = 0, /**< ADC first module. */ + QM_SS_ADC_NUM +} qm_ss_adc_t; + +/** + * SS ADC context type. + * + * The application should not modify the content of this structure. + * + * This structure is intented to be used by qm_ss_adc_save_context and + * qm_ss_adc_restore_context functions only. + */ +typedef struct { + uint32_t adc_set; /**< ADC settings. */ + uint32_t adc_divseqstat; /**< ADC clock divider and sequencer status. */ + uint32_t adc_seq; /**< ADC sequencer entry. */ + uint32_t adc_ctrl; /**< ADC control. */ +} qm_ss_adc_context_t; + +/* SS ADC register base. */ +#define QM_SS_ADC_BASE (0x80015000) + +/* For 1MHz, the max divisor is 7. */ +#define QM_SS_ADC_DIV_MAX (7) + +#define QM_SS_ADC_FIFO_LEN (32) + +#define QM_SS_ADC_SET_POP_RX BIT(31) +#define QM_SS_ADC_SET_FLUSH_RX BIT(30) +#define QM_SS_ADC_SET_THRESHOLD_MASK (0x3F000000) +#define QM_SS_ADC_SET_THRESHOLD_OFFSET (24) +#define QM_SS_ADC_SET_SEQ_ENTRIES_MASK (0x3F0000) +#define QM_SS_ADC_SET_SEQ_ENTRIES_OFFSET (16) +#define QM_SS_ADC_SET_SEQ_MODE BIT(13) +#define QM_SS_ADC_SET_SAMPLE_WIDTH_MASK (0x1F) + +#define QM_SS_ADC_DIVSEQSTAT_CLK_RATIO_MASK (0x1FFFFF) + +#define QM_SS_ADC_CTRL_CLR_SEQERROR BIT(19) +#define QM_SS_ADC_CTRL_CLR_UNDERFLOW BIT(18) +#define QM_SS_ADC_CTRL_CLR_OVERFLOW BIT(17) +#define QM_SS_ADC_CTRL_CLR_DATA_A BIT(16) +#define QM_SS_ADC_CTRL_MSK_SEQERROR BIT(11) +#define QM_SS_ADC_CTRL_MSK_UNDERFLOW BIT(10) +#define QM_SS_ADC_CTRL_MSK_OVERFLOW BIT(9) +#define QM_SS_ADC_CTRL_MSK_DATA_A BIT(8) +#define QM_SS_ADC_CTRL_SEQ_TABLE_RST BIT(6) +#define QM_SS_ADC_CTRL_SEQ_PTR_RST BIT(5) +#define QM_SS_ADC_CTRL_SEQ_START BIT(4) +#define QM_SS_ADC_CTRL_CLK_ENA BIT(2) +#define QM_SS_ADC_CTRL_ADC_ENA BIT(1) + +#define QM_SS_ADC_CTRL_MSK_ALL_INT (0xF00) +#define QM_SS_ADC_CTRL_CLR_ALL_INT (0xF0000) + +#define QM_SS_ADC_SEQ_DELAYODD_OFFSET (21) +#define QM_SS_ADC_SEQ_MUXODD_OFFSET (16) +#define QM_SS_ADC_SEQ_DELAYEVEN_OFFSET (5) + +#define QM_SS_ADC_SEQ_DUMMY (0x480) + +#define QM_SS_ADC_INTSTAT_SEQERROR BIT(3) +#define QM_SS_ADC_INTSTAT_UNDERFLOW BIT(2) +#define QM_SS_ADC_INTSTAT_OVERFLOW BIT(1) +#define QM_SS_ADC_INTSTAT_DATA_A BIT(0) + +/** End of Sensor Subsystem ADC @}*/ + +/** + * CREG Registers. + * + * @name SS CREG + * @{ + */ + +/* Sensor Subsystem CREG */ +typedef enum { + QM_SS_IO_CREG_MST0_CTRL = 0x0, /**< Master control register. */ + QM_SS_IO_CREG_SLV0_OBSR = 0x80, /**< Slave control register. */ + QM_SS_IO_CREG_SLV1_OBSR = 0x180 /**< Slave control register. */ +} qm_ss_creg_reg_t; + +/* MST0_CTRL fields */ +#define QM_SS_IO_CREG_MST0_CTRL_ADC_PWR_MODE_OFFSET (1) +#define QM_SS_IO_CREG_MST0_CTRL_ADC_PWR_MODE_MASK (0x7) +#define QM_SS_IO_CREG_MST0_CTRL_ADC_DELAY_OFFSET (3) +#define QM_SS_IO_CREG_MST0_CTRL_ADC_DELAY_MASK (0xFFF8) +#define QM_SS_IO_CREG_MST0_CTRL_ADC_CAL_REQ BIT(16) +#define QM_SS_IO_CREG_MST0_CTRL_ADC_CAL_CMD_OFFSET (17) +#define QM_SS_IO_CREG_MST0_CTRL_ADC_CAL_CMD_MASK (0xE0000) +#define QM_SS_IO_CREG_MST0_CTRL_ADC_CAL_VAL_OFFSET (20) +#define QM_SS_IO_CREG_MST0_CTRL_ADC_CAL_VAL_MASK (0x7F00000) +#define QM_SS_IO_CREG_MST0_CTRL_ADC_CAL_VAL_MAX (0x7F) +#define QM_SS_IO_CREG_MST0_CTRL_SPI1_CLK_GATE BIT(27) +#define QM_SS_IO_CREG_MST0_CTRL_SPI0_CLK_GATE BIT(28) +#define QM_SS_IO_CREG_MST0_CTRL_I2C0_CLK_GATE BIT(29) +#define QM_SS_IO_CREG_MST0_CTRL_I2C1_CLK_GATE BIT(30) +#define QM_SS_IO_CREG_MST0_CTRL_ADC_CLK_GATE BIT(31) +/* SLV0_OBSR fields */ +#define QM_SS_IO_CREG_SLV0_OBSR_ADC_CAL_VAL_OFFSET (5) +#define QM_SS_IO_CREG_SLV0_OBSR_ADC_CAL_VAL_MASK (0xFE0) +#define QM_SS_IO_CREG_SLV0_OBSR_ADC_CAL_ACK BIT(4) +#define QM_SS_IO_CREG_SLV0_OBSR_ADC_PWR_MODE_STS BIT(3) + +#define SS_CLK_PERIPH_ALL_IN_CREG \ + (SS_CLK_PERIPH_ADC | SS_CLK_PERIPH_I2C_1 | SS_CLK_PERIPH_I2C_0 | \ + SS_CLK_PERIPH_SPI_1 | SS_CLK_PERIPH_SPI_0) + +/* SS CREG base. */ +#define QM_SS_CREG_BASE (0x80018000) + +/** @} */ + +/** + * I2C registers and definitions. + * + * @name SS SPI + * @{ + */ + +/** Sensor Subsystem SPI register map. */ +typedef enum { + QM_SS_SPI_CTRL = 0, /**< SPI control register. */ + QM_SS_SPI_SPIEN = 2, /**< SPI enable register. */ + QM_SS_SPI_TIMING = 4, /**< SPI serial clock divider value. */ + QM_SS_SPI_FTLR, /**< Threshold value for TX/RX FIFO. */ + QM_SS_SPI_TXFLR = 7, /**< Number of valid data entries in TX FIFO. */ + QM_SS_SPI_RXFLR, /**< Number of valid data entries in RX FIFO. */ + QM_SS_SPI_SR, /**< SPI status register. */ + QM_SS_SPI_INTR_STAT, /**< Interrupt status register. */ + QM_SS_SPI_INTR_MASK, /**< Interrupt mask register. */ + QM_SS_SPI_CLR_INTR, /**< Interrupt clear register. */ + QM_SS_SPI_DR, /**< RW buffer for FIFOs. */ +} qm_ss_spi_reg_t; + +/** + * Sensor Subsystem SPI context type. + * + * Applications should not modify the content. + * This structure is only intended to be used by + * the qm_ss_spi_save_context and qm_ss_spi_restore_context functions. + */ +typedef struct { + uint32_t spi_ctrl; /**< Control Register. */ + uint32_t spi_spien; /**< SPI Enable Register. */ + uint32_t spi_timing; /**< Timing Register. */ +} qm_ss_spi_context_t; + +/** Sensor Subsystem SPI modules. */ +typedef enum { + QM_SS_SPI_0 = 0, /**< SPI module 0 */ + QM_SS_SPI_1, /**< SPI module 1 */ + QM_SS_SPI_NUM +} qm_ss_spi_t; + +#define QM_SS_SPI_0_BASE (0x80010000) +#define QM_SS_SPI_1_BASE (0x80010100) + +#define QM_SS_SPI_CTRL_DFS_OFFS (0) +#define QM_SS_SPI_CTRL_DFS_MASK (0x0000000F) +#define QM_SS_SPI_CTRL_BMOD_OFFS (6) +#define QM_SS_SPI_CTRL_BMOD_MASK (0x000000C0) +#define QM_SS_SPI_CTRL_SCPH BIT(6) +#define QM_SS_SPI_CTRL_SCPOL BIT(7) +#define QM_SS_SPI_CTRL_TMOD_OFFS (8) +#define QM_SS_SPI_CTRL_TMOD_MASK (0x00000300) +#define QM_SS_SPI_CTRL_SRL BIT(11) +#define QM_SS_SPI_CTRL_CLK_ENA BIT(15) +#define QM_SS_SPI_CTRL_NDF_OFFS (16) +#define QM_SS_SPI_CTRL_NDF_MASK (0xFFFF0000) + +#define QM_SS_SPI_SPIEN_EN BIT(0) +#define QM_SS_SPI_SPIEN_SER_OFFS (4) +#define QM_SS_SPI_SPIEN_SER_MASK (0x000000F0) + +#define QM_SS_SPI_TIMING_SCKDV_OFFS (0) +#define QM_SS_SPI_TIMING_SCKDV_MASK (0x0000FFFF) +#define QM_SS_SPI_TIMING_RSD_OFFS (16) +#define QM_SS_SPI_TIMING_RSD_MASK (0x00FF0000) + +#define QM_SS_SPI_FTLR_RFT_OFFS (0) +#define QM_SS_SPI_FTLR_RFT_MASK (0x0000FFFF) +#define QM_SS_SPI_FTLR_TFT_OFFS (16) +#define QM_SS_SPI_FTLR_TFT_MASK (0xFFFF0000) + +#define QM_SS_SPI_SR_BUSY BIT(0) +#define QM_SS_SPI_SR_TFNF BIT(1) +#define QM_SS_SPI_SR_TFE BIT(2) +#define QM_SS_SPI_SR_RFNE BIT(3) +#define QM_SS_SPI_SR_RFF BIT(4) + +#define QM_SS_SPI_INTR_TXEI BIT(0) +#define QM_SS_SPI_INTR_TXOI BIT(1) +#define QM_SS_SPI_INTR_RXUI BIT(2) +#define QM_SS_SPI_INTR_RXOI BIT(3) +#define QM_SS_SPI_INTR_RXFI BIT(4) +#define QM_SS_SPI_INTR_ALL (0x0000001F) + +#define QM_SS_SPI_INTR_STAT_TXEI QM_SS_SPI_INTR_TXEI +#define QM_SS_SPI_INTR_STAT_TXOI QM_SS_SPI_INTR_TXOI +#define QM_SS_SPI_INTR_STAT_RXUI QM_SS_SPI_INTR_RXUI +#define QM_SS_SPI_INTR_STAT_RXOI QM_SS_SPI_INTR_RXOI +#define QM_SS_SPI_INTR_STAT_RXFI QM_SS_SPI_INTR_RXFI + +#define QM_SS_SPI_INTR_MASK_TXEI QM_SS_SPI_INTR_TXEI +#define QM_SS_SPI_INTR_MASK_TXOI QM_SS_SPI_INTR_TXOI +#define QM_SS_SPI_INTR_MASK_RXUI QM_SS_SPI_INTR_RXUI +#define QM_SS_SPI_INTR_MASK_RXOI QM_SS_SPI_INTR_RXOI +#define QM_SS_SPI_INTR_MASK_RXFI QM_SS_SPI_INTR_RXFI + +#define QM_SS_SPI_CLR_INTR_TXEI QM_SS_SPI_INTR_TXEI +#define QM_SS_SPI_CLR_INTR_TXOI QM_SS_SPI_INTR_TXOI +#define QM_SS_SPI_CLR_INTR_RXUI QM_SS_SPI_INTR_RXUI +#define QM_SS_SPI_CLR_INTR_RXOI QM_SS_SPI_INTR_RXOI +#define QM_SS_SPI_CLR_INTR_RXFI QM_SS_SPI_INTR_RXFI + +#define QM_SS_SPI_DR_DR_OFFS (0) +#define QM_SS_SPI_DR_DR_MASK (0x0000FFFF) +#define QM_SS_SPI_DR_WR BIT(30) +#define QM_SS_SPI_DR_STROBE BIT(31) +#define QM_SS_SPI_DR_W_MASK (0xc0000000) +#define QM_SS_SPI_DR_R_MASK (0x80000000) + +/** @} */ +/** @} */ + +#endif /* __SENSOR_REGISTERS_H__ */ diff --git a/libraries/CuriePowerManagement/src/qmsi/qm_soc_interrupts.h b/libraries/CuriePowerManagement/src/qmsi/qm_soc_interrupts.h new file mode 100644 index 00000000..9acd4c35 --- /dev/null +++ b/libraries/CuriePowerManagement/src/qmsi/qm_soc_interrupts.h @@ -0,0 +1,410 @@ +/* + * Copyright (c) 2016, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of the Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INTEL CORPORATION OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __QM_SOC_INTERRUPTS_H__ +#define __QM_SOC_INTERRUPTS_H__ + +/** + * Quark SE SoC Interrupts. + * + * @defgroup groupQUARKSESEINT SoC Interrupts (SE) + * @{ + */ + +#if (QM_LAKEMONT) + +/* x86 internal interrupt vectors. */ +#define QM_X86_DIVIDE_ERROR_INT (0) +#define QM_X86_DEBUG_EXCEPTION_INT (1) +#define QM_X86_NMI_INTERRUPT_INT (2) +#define QM_X86_BREAKPOINT_INT (3) +#define QM_X86_OVERFLOW_INT (4) +#define QM_X86_BOUND_RANGE_EXCEEDED_INT (5) +#define QM_X86_INVALID_OPCODE_INT (6) +#define QM_X86_DEVICE_NOT_AVAILABLE_INT (7) +#define QM_X86_DOUBLE_FAULT_INT (8) +#define QM_X86_INTEL_RESERVED_09_INT (9) +#define QM_X86_INVALID_TSS_INT (10) +#define QM_X86_SEGMENT_NOT_PRESENT_INT (11) +#define QM_X86_STACK_SEGMENT_FAULT_INT (12) +#define QM_X86_GENERAL_PROTECT_FAULT_INT (13) +#define QM_X86_PAGE_FAULT_INT (14) +#define QM_X86_INTEL_RESERVED_15_INT (15) +#define QM_X86_FLOATING_POINT_ERROR_INT (16) +#define QM_X86_ALIGNMENT_CHECK_INT (17) +#define QM_X86_INTEL_RESERVED_18_INT (18) +#define QM_X86_INTEL_RESERVED_19_INT (19) +#define QM_X86_INTEL_RESERVED_20_INT (20) +#define QM_X86_INTEL_RESERVED_21_INT (21) +#define QM_X86_INTEL_RESERVED_22_INT (22) +#define QM_X86_INTEL_RESERVED_23_INT (23) +#define QM_X86_INTEL_RESERVED_24_INT (24) +#define QM_X86_INTEL_RESERVED_25_INT (25) +#define QM_X86_INTEL_RESERVED_26_INT (26) +#define QM_X86_INTEL_RESERVED_27_INT (27) +#define QM_X86_INTEL_RESERVED_28_INT (28) +#define QM_X86_INTEL_RESERVED_29_INT (29) +#define QM_X86_INTEL_RESERVED_30_INT (30) +#define QM_X86_INTEL_RESERVED_31_INT (31) + +#define QM_X86_PIC_TIMER_INT_VECTOR (32) + +#endif /* QM_LAKEMONT */ + +#if (QM_SENSOR) + +/* ARC EM processor internal interrupt vector assignments. */ +#define QM_ARC_RESET_INT (0) +#define QM_ARC_MEMORY_ERROR_INT (1) +#define QM_ARC_INSTRUCTION_ERROR_INT (2) +#define QM_ARC_MACHINE_CHECK_EXCEPTION_INT (3) +#define QM_ARC_INSTRUCTION_TLB_MISS_INT (4) +#define QM_ARC_DATA_TLB_MISS_INT (5) +#define QM_ARC_PROTECTION_VIOLATION_INT (6) +#define QM_ARC_PRIVILEGE_VIOLATION_INT (7) +#define QM_ARC_SOFTWARE_INTERRUPT_INT (8) +#define QM_ARC_TRAP_INT (9) +#define QM_ARC_EXTENSION_INSTRUCTION_EXCEPTION_INT (10) +#define QM_ARC_DIVIDE_BY_ZERO_INT (11) +#define QM_ARC_DATA_CACHE_CONSISTENCY_ERROR_INT (12) +#define QM_ARC_MISALIGNED_DATA_ACCESS_INT (13) +#define QM_ARC_RESERVED_14_INT (14) +#define QM_ARC_RESERVED_15_INT (15) +#define QM_ARC_TIMER_0_INT (16) +#define QM_ARC_TIMER_1_INT (17) + +#endif /* QM_SENSOR */ + +#if (QM_SENSOR) +/** + * Sensor Sub-System Specific IRQs and interrupt vectors. + * + * @name SS Interrupt + * @{ + */ + +#define QM_SS_EXCEPTION_NUM (16) /* Exceptions and traps in ARC EM core. */ +#define QM_SS_INT_TIMER_NUM (2) /* Internal interrupts in ARC EM core. */ +#define QM_SS_IRQ_SENSOR_NUM (18) /* IRQ's from the Sensor Subsystem. */ +#define QM_SS_IRQ_COMMON_NUM (32) /* IRQ's from the common SoC fabric. */ +#define QM_SS_INT_VECTOR_NUM \ + (QM_SS_EXCEPTION_NUM + QM_SS_INT_TIMER_NUM + QM_SS_IRQ_SENSOR_NUM + \ + QM_SS_IRQ_COMMON_NUM) +#define QM_SS_IRQ_NUM (QM_SS_IRQ_SENSOR_NUM + QM_SS_IRQ_COMMON_NUM) + +/* + * The following definitions are Sensor Subsystem interrupt irq and vector + * numbers: + * #define QM_SS_xxx - irq number + * #define QM_SS_xxx_VECTOR - vector number + */ + +/** Sensor Subsystem ADC Rx Fifo Error Interrupt. */ +#define QM_SS_IRQ_ADC_0_ERROR_INT 0 +#define QM_SS_IRQ_ADC_0_ERROR_INT_VECTOR 18 + +/** Sensor Subsystem ADC Data Available Interrupt. */ +#define QM_SS_IRQ_ADC_0_INT 1 +#define QM_SS_IRQ_ADC_0_INT_VECTOR 19 + +/** Sensor Subsystem GPIO Single Interrupt 0 */ +#define QM_SS_IRQ_GPIO_0_INT 2 +#define QM_SS_IRQ_GPIO_0_INT_VECTOR 20 + +/** Sensor Subsystem GPIO Single Interrupt 1. */ +#define QM_SS_IRQ_GPIO_1_INT 3 +#define QM_SS_IRQ_GPIO_1_INT_VECTOR 21 + +/** Sensor Subsystem I2C 0 Error Interrupt. */ +#define QM_SS_IRQ_I2C_0_ERROR_INT 4 +#define QM_SS_IRQ_I2C_0_ERROR_INT_VECTOR 22 + +/** Sensor Subsystem I2C 0 Data Available Interrupt. */ +#define QM_SS_IRQ_I2C_0_RX_AVAIL_INT 5 +#define QM_SS_IRQ_I2C_0_RX_AVAIL_INT_VECTOR 23 + +/** Sensor Subsystem I2C 0 Data Required Interrupt. */ +#define QM_SS_IRQ_I2C_0_TX_REQ_INT 6 +#define QM_SS_IRQ_I2C_0_TX_REQ_INT_VECTOR 24 + +/** Sensor Subsystem I2C 0 Stop Detect Interrupt. */ +#define QM_SS_IRQ_I2C_0_STOP_DET_INT 7 +#define QM_SS_IRQ_I2C_0_STOP_DET_INT_VECTOR 25 + +/** Sensor Subsystem I2C 1 Error Interrupt. */ +#define QM_SS_IRQ_I2C_1_ERROR_INT 8 +#define QM_SS_IRQ_I2C_1_ERROR_INT_VECTOR 26 + +/** Sensor Subsystem I2C 1 Data Available Interrupt. */ +#define QM_SS_IRQ_I2C_1_RX_AVAIL_INT 9 +#define QM_SS_IRQ_I2C_1_RX_AVAIL_INT_VECTOR 27 + +/** Sensor Subsystem I2C 1 Data Required Interrupt. */ +#define QM_SS_IRQ_I2C_1_TX_REQ_INT 10 +#define QM_SS_IRQ_I2C_1_TX_REQ_INT_VECTOR 28 + +/** Sensor Subsystem I2C 1 Stop Detect Interrupt. */ +#define QM_SS_IRQ_I2C_1_STOP_DET_INT 11 +#define QM_SS_IRQ_I2C_1_STOP_DET_INT_VECTOR 29 + +/** Sensor Subsystem SPI 0 Error Interrupt. */ +#define QM_SS_IRQ_SPI_0_ERROR_INT 12 +#define QM_SS_IRQ_SPI_0_ERROR_INT_VECTOR 30 + +/** Sensor Subsystem SPI 0 Data Available Interrupt. */ +#define QM_SS_IRQ_SPI_0_RX_AVAIL_INT 13 +#define QM_SS_IRQ_SPI_0_RX_AVAIL_INT_VECTOR 31 + +/** Sensor Subsystem SPI 0 Data Required Interrupt. */ +#define QM_SS_IRQ_SPI_0_TX_REQ_INT 14 +#define QM_SS_IRQ_SPI_0_TX_REQ_INT_VECTOR 32 + +/** Sensor Subsystem SPI 1 Error Interrupt. */ +#define QM_SS_IRQ_SPI_1_ERROR_INT 15 +#define QM_SS_IRQ_SPI_1_ERROR_INT_VECTOR 33 + +/** Sensor Subsystem SPI 1 Data Available Interrupt. */ +#define QM_SS_IRQ_SPI_1_RX_AVAIL_INT 16 +#define QM_SS_IRQ_SPI_1_RX_AVAIL_INT_VECTOR 34 + +/** Sensor Subsystem SPI 1 Data Required Interrupt. */ +#define QM_SS_IRQ_SPI_1_TX_REQ_INT 17 +#define QM_SS_IRQ_SPI_1_TX_REQ_INT_VECTOR 35 + +typedef enum { + QM_SS_INT_PRIORITY_0 = 0, + QM_SS_INT_PRIORITY_1 = 1, + QM_SS_INT_PRIORITY_15 = 15, + QM_SS_INT_PRIORITY_NUM +} qm_ss_irq_priority_t; + +typedef enum { QM_SS_INT_DISABLE = 0, QM_SS_INT_ENABLE = 1 } qm_ss_irq_mask_t; + +typedef enum { + QM_SS_IRQ_LEVEL_SENSITIVE = 0, + QM_SS_IRQ_EDGE_SENSITIVE = 1 +} qm_ss_irq_trigger_t; + +#define QM_SS_AUX_IRQ_CTRL (0xE) +#define QM_SS_AUX_IRQ_HINT (0x201) +#define QM_SS_AUX_IRQ_PRIORITY (0x206) +#define QM_SS_AUX_IRQ_STATUS (0x406) +#define QM_SS_AUX_IRQ_SELECT (0x40B) +#define QM_SS_AUX_IRQ_ENABLE (0x40C) +#define QM_SS_AUX_IRQ_TRIGGER (0x40D) + +/** @} */ + +#endif /* QM_SENSOR */ + +/** + * @name Common SoC IRQs and Interrupts + * @{ + */ + +/* IRQs and interrupt vectors. + * + * Any IRQ > 1 actually has a event router mask register offset of +1. + * The vector numbers must be defined without arithmetic expressions nor + * parentheses because they are expanded as token concatenation. + */ + +/** I2C Master 0 Single Interrupt. */ +#define QM_IRQ_I2C_0_INT 0 +#define QM_IRQ_I2C_0_INT_MASK_OFFSET 0 +#define QM_IRQ_I2C_0_INT_VECTOR 36 + +/** I2C Master 1 Single Interrupt. */ +#define QM_IRQ_I2C_1_INT 1 +#define QM_IRQ_I2C_1_INT_MASK_OFFSET 1 +#define QM_IRQ_I2C_1_INT_VECTOR 37 + +/** SPI Master 0 Single Interrupt. */ +#define QM_IRQ_SPI_MASTER_0_INT 2 +#define QM_IRQ_SPI_MASTER_0_INT_MASK_OFFSET 3 +#define QM_IRQ_SPI_MASTER_0_INT_VECTOR 38 + +/** SPI Master 1 Single Interrupt. */ +#define QM_IRQ_SPI_MASTER_1_INT 3 +#define QM_IRQ_SPI_MASTER_1_INT_MASK_OFFSET 4 +#define QM_IRQ_SPI_MASTER_1_INT_VECTOR 39 + +/** SPI Slave Single Interrupt. */ +#define QM_IRQ_SPI_SLAVE_0_INT 4 +#define QM_IRQ_SPI_SLAVE_0_INT_MASK_OFFSET 5 +#define QM_IRQ_SPI_SLAVE_0_INT_VECTOR 40 + +/** UART 0 Single Interrupt. */ +#define QM_IRQ_UART_0_INT 5 +#define QM_IRQ_UART_0_INT_MASK_OFFSET 6 +#define QM_IRQ_UART_0_INT_VECTOR 41 + +/** UART 1 Single Interrupt. */ +#define QM_IRQ_UART_1_INT 6 +#define QM_IRQ_UART_1_INT_MASK_OFFSET 7 +#define QM_IRQ_UART_1_INT_VECTOR 42 + +/** I2S Single Interrupt. */ +#define QM_IRQ_I2S_0_INT 7 +#define QM_IRQ_I2S_0_INT_MASK_OFFSET 8 +#define QM_IRQ_I2S_0_INT_VECTOR 43 + +/** GPIO Single Interrupt. */ +#define QM_IRQ_GPIO_0_INT 8 +#define QM_IRQ_GPIO_0_INT_MASK_OFFSET 9 +#define QM_IRQ_GPIO_0_INT_VECTOR 44 + +/** PWM/Timer Single Interrupt. */ +#define QM_IRQ_PWM_0_INT 9 +#define QM_IRQ_PWM_0_INT_MASK_OFFSET 10 +#define QM_IRQ_PWM_0_INT_VECTOR 45 + +/** USB Single Interrupt. */ +#define QM_IRQ_USB_0_INT (10) +#define QM_IRQ_USB_0_INT_MASK_OFFSET (11) +#define QM_IRQ_USB_0_INT_VECTOR 46 + +/** RTC Single Interrupt. */ +#define QM_IRQ_RTC_0_INT 11 +#define QM_IRQ_RTC_0_INT_MASK_OFFSET 12 +#define QM_IRQ_RTC_0_INT_VECTOR 47 + +/** WDT Single Interrupt. */ +#define QM_IRQ_WDT_0_INT 12 +#define QM_IRQ_WDT_0_INT_MASK_OFFSET 13 +#define QM_IRQ_WDT_0_INT_VECTOR 48 + +/** DMA Channel 0 Single Interrupt. */ +#define QM_IRQ_DMA_0_INT_0 13 +#define QM_IRQ_DMA_0_INT_0_MASK_OFFSET 14 +#define QM_IRQ_DMA_0_INT_0_VECTOR 49 + +/** DMA Channel 1 Single Interrupt. */ +#define QM_IRQ_DMA_0_INT_1 14 +#define QM_IRQ_DMA_0_INT_1_MASK_OFFSET 15 +#define QM_IRQ_DMA_0_INT_1_VECTOR 50 + +/** DMA Channel 2 Single Interrupt. */ +#define QM_IRQ_DMA_0_INT_2 15 +#define QM_IRQ_DMA_0_INT_2_MASK_OFFSET 16 +#define QM_IRQ_DMA_0_INT_2_VECTOR 51 + +/** DMA Channel 3 Single Interrupt. */ +#define QM_IRQ_DMA_0_INT_3 16 +#define QM_IRQ_DMA_0_INT_3_MASK_OFFSET 17 +#define QM_IRQ_DMA_0_INT_3_VECTOR 52 + +/** DMA Channel 4 Single Interrupt. */ +#define QM_IRQ_DMA_0_INT_4 17 +#define QM_IRQ_DMA_0_INT_4_MASK_OFFSET 18 +#define QM_IRQ_DMA_0_INT_4_VECTOR 53 + +/** DMA Channel 5 Single Interrupt. */ +#define QM_IRQ_DMA_0_INT_5 18 +#define QM_IRQ_DMA_0_INT_5_MASK_OFFSET 19 +#define QM_IRQ_DMA_0_INT_5_VECTOR 54 + +/** DMA Channel 6 Single Interrupt. */ +#define QM_IRQ_DMA_0_INT_6 19 +#define QM_IRQ_DMA_0_INT_6_MASK_OFFSET 20 +#define QM_IRQ_DMA_0_INT_6_VECTOR 55 + +/** DMA Channel 7 Single Interrupt. */ +#define QM_IRQ_DMA_0_INT_7 20 +#define QM_IRQ_DMA_0_INT_7_MASK_OFFSET 21 +#define QM_IRQ_DMA_0_INT_7_VECTOR 56 + +/** + * 8 Mailbox Channel Interrupts Routed to Single Interrupt + * with 8bit Mask per Destination. + */ +#define QM_IRQ_MAILBOX_0_INT 21 +#define QM_IRQ_MAILBOX_0_INT_MASK_OFFSET 22 +#define QM_IRQ_MAILBOX_0_INT_VECTOR 57 + +/** + * 19 Comparators Routed to Single Interrupt with 19bit Mask per Destination. + */ +#define QM_IRQ_COMPARATOR_0_INT 22 +#define QM_IRQ_COMPARATOR_0_INT_MASK_OFFSET 26 +#define QM_IRQ_COMPARATOR_0_INT_VECTOR 58 + +/** System and Power Management Single Interrupt. */ +#define QM_IRQ_PMU_0_INT 23 +#define QM_IRQ_PMU_0_INT_MASK_OFFSET 26 +#define QM_IRQ_PMU_0_INT_VECTOR 58 + +/** + * 8 DMA Channel Error Interrupts Routed to Single Interrupt with 8bit Mask + * per Destination. + */ +#define QM_IRQ_DMA_0_ERROR_INT 24 +#define QM_IRQ_DMA_0_ERROR_INT_MASK_OFFSET 28 +#define QM_IRQ_DMA_0_ERROR_INT_VECTOR 60 + +/** Internal SRAM Memory Protection Error Single Interrupt. */ +#define QM_IRQ_SRAM_MPR_0_INT 25 +#define QM_IRQ_SRAM_MPR_0_INT_MASK_OFFSET 29 +#define QM_IRQ_SRAM_MPR_0_INT_VECTOR 61 + +/** Internal Flash Controller 0 Memory Protection Error Single Interrupt. */ +#define QM_IRQ_FLASH_MPR_0_INT 26 +#define QM_IRQ_FLASH_MPR_0_INT_MASK_OFFSET 30 +#define QM_IRQ_FLASH_MPR_0_INT_VECTOR 62 + +/** Internal Flash Controller 1 Memory Protection Error Single Interrupt. */ +#define QM_IRQ_FLASH_MPR_1_INT 27 +#define QM_IRQ_FLASH_MPR_1_INT_MASK_OFFSET 31 +#define QM_IRQ_FLASH_MPR_1_INT_VECTOR 63 + +/** Always-On Timer Interrupt. */ +#define QM_IRQ_AONPT_0_INT 28 +#define QM_IRQ_AONPT_0_INT_MASK_OFFSET 32 +#define QM_IRQ_AONPT_0_INT_VECTOR 64 + +/** ADC power sequence done. */ +#define QM_SS_IRQ_ADC_0_PWR_INT 29 +#define QM_SS_IRQ_ADC_0_PWR_INT_MASK_OFFSET 33 +#define QM_SS_IRQ_ADC_0_PWR_INT_VECTOR 65 + +/** ADC calibration done. */ +#define QM_SS_IRQ_ADC_0_CAL_INT 30 +#define QM_SS_IRQ_ADC_0_CAL_INT_MASK_OFFSET 34 +#define QM_SS_IRQ_ADC_0_CAL_INT_VECTOR 66 + +/** Always-On GPIO Interrupt. */ +#define QM_IRQ_AON_GPIO_0_INT 31 +#define QM_IRQ_AON_GPIO_0_INT_MASK_OFFSET 35 +#define QM_IRQ_AON_GPIO_0_INT_VECTOR 67 + +/** @} */ + +/** @} */ + +#endif /* __QM_SOC_INTERRUPTS_H__ */ diff --git a/libraries/CuriePowerManagement/src/qmsi/qm_soc_regs.h b/libraries/CuriePowerManagement/src/qmsi/qm_soc_regs.h new file mode 100644 index 00000000..54887384 --- /dev/null +++ b/libraries/CuriePowerManagement/src/qmsi/qm_soc_regs.h @@ -0,0 +1,2105 @@ +/* + * Copyright (c) 2016, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of the Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INTEL CORPORATION OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __REGISTERS_H__ +#define __REGISTERS_H__ + +#include "qm_common.h" +#include "qm_soc_interrupts.h" +#include "qm_interrupt_router_regs.h" + +/** + * Quark SE SoC Registers. + * + * @defgroup groupQUARKSESEREG SoC Registers (SE) + * @{ + */ + +#define QUARK_SE (1) +#define HAS_4_TIMERS (1) +#define HAS_AON_GPIO (1) +#define HAS_MAILBOX (1) +#define HAS_USB (1) + +#if !defined(QM_SENSOR) +#define HAS_APIC (1) +#endif + +/** + * @name System Core + * @{ + */ + +/** System Core register map. */ +typedef struct { + QM_RW uint32_t osc0_cfg0; /**< Hybrid Oscillator Configuration 0. */ + QM_RW uint32_t osc0_stat1; /**< Hybrid Oscillator status 1. */ + QM_RW uint32_t osc0_cfg1; /**< Hybrid Oscillator configuration 1. */ + QM_RW uint32_t osc1_stat0; /**< RTC Oscillator status 0. */ + QM_RW uint32_t osc1_cfg0; /**< RTC Oscillator Configuration 0. */ + QM_RW uint32_t usb_pll_cfg0; /**< USB Phase lock look configuration. */ + QM_RW uint32_t + ccu_periph_clk_gate_ctl; /**< Peripheral Clock Gate Control. */ + QM_RW uint32_t + ccu_periph_clk_div_ctl0; /**< Peripheral Clock Divider Control. 0 */ + QM_RW uint32_t + ccu_gpio_db_clk_ctl; /**< Peripheral Clock Divider Control 1. */ + QM_RW uint32_t + ccu_ext_clock_ctl; /**< External Clock Control Register. */ + /** Sensor Subsystem peripheral clock gate control. */ + QM_RW uint32_t ccu_ss_periph_clk_gate_ctl; + QM_RW uint32_t ccu_lp_clk_ctl; /**< System Low Power Clock Control. */ + QM_RW uint32_t reserved; + QM_RW uint32_t ccu_mlayer_ahb_ctl; /**< AHB Control Register. */ + QM_RW uint32_t ccu_sys_clk_ctl; /**< System Clock Control Register. */ + QM_RW uint32_t osc_lock_0; /**< Clocks Lock Register. */ +} qm_scss_ccu_reg_t; + +#if (UNIT_TEST) +qm_scss_ccu_reg_t test_scss_ccu; +#define QM_SCSS_CCU ((qm_scss_ccu_reg_t *)(&test_scss_ccu)) + +#else +#define QM_SCSS_CCU_BASE (0xB0800000) +#define QM_SCSS_CCU ((qm_scss_ccu_reg_t *)QM_SCSS_CCU_BASE) +#endif + +/* Hybrid oscillator output select select (0=Silicon, 1=Crystal) */ +#define QM_OSC0_MODE_SEL BIT(3) +#define QM_OSC0_PD BIT(2) +#define QM_OSC1_PD BIT(1) + +/* Enable Crystal oscillator. */ +#define QM_OSC0_EN_CRYSTAL BIT(0) + +/* Crystal oscillator parameters. */ +#define OSC0_CFG1_OSC0_FADJ_XTAL_MASK (0x000F0000) +#define OSC0_CFG1_OSC0_FADJ_XTAL_OFFS (16) +#define OSC0_CFG0_OSC0_XTAL_COUNT_VALUE_MASK (0x00600000) +#define OSC0_CFG0_OSC0_XTAL_COUNT_VALUE_OFFS (21) + +/* Silicon Oscillator parameters. */ +#define OSC0_CFG1_FTRIMOTP_MASK (0x3FF00000) +#define OSC0_CFG1_FTRIMOTP_OFFS (20) +#define OSC0_CFG1_SI_FREQ_SEL_MASK (0x00000300) +#define OSC0_CFG1_SI_FREQ_SEL_OFFS (8) + +#define QM_OSC0_MODE_SEL BIT(3) +#define QM_OSC0_LOCK_SI BIT(0) +#define QM_OSC0_LOCK_XTAL BIT(1) +#define QM_OSC0_EN_SI_OSC BIT(1) + +#define QM_SI_OSC_1V2_MODE BIT(0) + +/* Peripheral clock divider control. */ +#define QM_CCU_PERIPH_PCLK_DIV_OFFSET (1) +#define QM_CCU_PERIPH_PCLK_DIV_EN BIT(0) + +/* Clock enable / disable register. */ +#define QM_CCU_MLAYER_AHB_CTL (REG_VAL(0xB0800034)) + +/* System clock control */ +#define QM_CCU_SYS_CLK_SEL BIT(0) +#define QM_SCSS_CCU_SYS_CLK_SEL BIT(0) +#define QM_SCSS_CCU_C2_LP_EN BIT(1) +#define QM_SCSS_CCU_SS_LPS_EN BIT(0) +#define QM_CCU_RTC_CLK_EN BIT(1) +#define QM_CCU_RTC_CLK_DIV_EN BIT(2) +#define QM_CCU_SYS_CLK_DIV_EN BIT(7) +#define QM_CCU_SYS_CLK_DIV_MASK (0x00000300) + +#define QM_OSC0_SI_FREQ_SEL_DEF_MASK (0xFFFFFCFF) +#define QM_CCU_GPIO_DB_DIV_OFFSET (2) +#define QM_CCU_GPIO_DB_CLK_DIV_EN BIT(1) +#define QM_CCU_GPIO_DB_CLK_EN BIT(0) +#define QM_CCU_RTC_CLK_DIV_OFFSET (3) +#define QM_CCU_SYS_CLK_DIV_OFFSET (8) +#define QM_CCU_DMA_CLK_EN BIT(6) + +/** @} */ + +/** + * @name General Purpose + * @{ + */ + +/** General Purpose register map. */ +typedef struct { + QM_RW uint32_t gps0; /**< General Purpose Sticky Register 0 */ + QM_RW uint32_t gps1; /**< General Purpose Sticky Register 1 */ + QM_RW uint32_t gps2; /**< General Purpose Sticky Register 2 */ + QM_RW uint32_t gps3; /**< General Purpose Sticky Register 3 */ + QM_RW uint32_t reserved; + QM_RW uint32_t gp0; /**< General Purpose Scratchpad Register 0 */ + QM_RW uint32_t gp1; /**< General Purpose Scratchpad Register 1 */ + QM_RW uint32_t gp2; /**< General Purpose Scratchpad Register 2 */ + QM_RW uint32_t gp3; /**< General Purpose Scratchpad Register 3 */ + QM_RW uint32_t reserved1; + QM_RW uint32_t id; /**< Identification Register */ + QM_RW uint32_t rev; /**< Revision Register */ + QM_RW uint32_t wo_sp; /**< Write-One-to-Set Scratchpad Register */ + QM_RW uint32_t + wo_st; /**< Write-One-to-Set Sticky Scratchpad Register */ +} qm_scss_gp_reg_t; + +#if (UNIT_TEST) +qm_scss_gp_reg_t test_scss_gp; +#define QM_SCSS_GP ((qm_scss_gp_reg_t *)(&test_scss_gp)) + +#else +#define QM_SCSS_GP_BASE (0xB0800100) +#define QM_SCSS_GP ((qm_scss_gp_reg_t *)QM_SCSS_GP_BASE) +#endif + +/* The GPS0 register usage. */ +#define QM_GPS0_BIT_FM (0) /**< Start Firmware Manager. */ +#define QM_GPS0_BIT_X86_WAKEUP (1) /**< Lakemont core reset type. */ +#define QM_GPS0_BIT_SENSOR_WAKEUP (2) /**< Sensor core reset type. */ + +/** @} */ + +/** + * @name Memory Control + * @{ + */ + +/** Memory Control register map. */ +typedef struct { + QM_RW uint32_t mem_ctrl; /**< Memory control */ +} qm_scss_mem_reg_t; + +#if (UNIT_TEST) +qm_scss_mem_reg_t test_scss_mem; +#define QM_SCSS_MEM ((qm_scss_mem_reg_t *)(&test_scss_mem)) + +#else +#define QM_SCSS_MEM_BASE (0xB0800200) +#define QM_SCSS_MEM ((qm_scss_mem_reg_t *)QM_SCSS_MEM_BASE) +#endif + +/** @} */ + +/** + * @name Comparator + * @{ + */ + +/** Comparator register map. */ +typedef struct { + QM_RW uint32_t cmp_en; /**< Comparator enable. */ + QM_RW uint32_t cmp_ref_sel; /**< Comparator reference select. */ + QM_RW uint32_t + cmp_ref_pol; /**< Comparator reference polarity select register. */ + QM_RW uint32_t cmp_pwr; /**< Comparator power enable register. */ + QM_RW uint32_t reserved[6]; + QM_RW uint32_t cmp_stat_clr; /**< Comparator clear register. */ +} qm_scss_cmp_reg_t; + +#if (UNIT_TEST) +qm_scss_cmp_reg_t test_scss_cmp; +#define QM_SCSS_CMP ((qm_scss_cmp_reg_t *)(&test_scss_cmp)) + +#else +#define QM_SCSS_CMP_BASE (0xB0800300) +#define QM_SCSS_CMP ((qm_scss_cmp_reg_t *)QM_SCSS_CMP_BASE) +#endif + +#define QM_AC_HP_COMPARATORS_MASK (0x7FFC0) + +/** @} */ + +/** + * @name APIC + * @{ + */ + +typedef struct { + QM_RW uint32_t reg; + QM_RW uint32_t pad[3]; +} apic_reg_pad_t; + +/** APIC register block type. */ +typedef struct { + QM_RW apic_reg_pad_t reserved0[2]; + QM_RW apic_reg_pad_t id; /**< LAPIC ID */ + QM_RW apic_reg_pad_t version; /**< LAPIC version*/ + QM_RW apic_reg_pad_t reserved1[4]; + QM_RW apic_reg_pad_t tpr; /**< Task priority*/ + QM_RW apic_reg_pad_t apr; /**< Arbitration priority */ + QM_RW apic_reg_pad_t ppr; /**< Processor priority */ + QM_RW apic_reg_pad_t eoi; /**< End of interrupt */ + QM_RW apic_reg_pad_t rrd; /**< Remote read */ + QM_RW apic_reg_pad_t ldr; /**< Logical destination */ + QM_RW apic_reg_pad_t dfr; /**< Destination format */ + QM_RW apic_reg_pad_t svr; /**< Spurious vector */ + QM_RW apic_reg_pad_t isr[8]; /**< In-service */ + QM_RW apic_reg_pad_t tmr[8]; /**< Trigger mode */ + QM_RW apic_reg_pad_t irr[8]; /**< Interrupt request */ + QM_RW apic_reg_pad_t esr; /**< Error status */ + QM_RW apic_reg_pad_t reserved2[6]; + QM_RW apic_reg_pad_t lvtcmci; /**< Corrected Machine Check vector */ + QM_RW apic_reg_pad_t icr[2]; /**< Interrupt command */ + QM_RW apic_reg_pad_t lvttimer; /**< Timer vector */ + QM_RW apic_reg_pad_t lvtts; /**< Thermal sensor vector */ + QM_RW apic_reg_pad_t lvtpmcr; /**< Perfmon counter vector */ + QM_RW apic_reg_pad_t lvtlint0; /**< Local interrupt 0 vector */ + QM_RW apic_reg_pad_t lvtlint1; /**< Local interrupt 1 vector */ + QM_RW apic_reg_pad_t lvterr; /**< Error vector */ + QM_RW apic_reg_pad_t timer_icr; /**< Timer initial count */ + QM_RW apic_reg_pad_t timer_ccr; /**< Timer current count */ + QM_RW apic_reg_pad_t reserved3[4]; + QM_RW apic_reg_pad_t timer_dcr; /**< Timer divide configuration */ +} qm_lapic_reg_t; + +#if (HAS_APIC) +/* + * The size of IOAPIC redirection table, as returned by _ioapic_get_redtbl_size + * function. + */ +#define QM_IOAPIC_NUM_RTES (32) + +/** + * IRQ context type. + * + * Applications should not modify the content. + * This structure is only intended to be used by + * qm_irq_save_context and qm_irq_restore_context functions. + */ +typedef struct { + /** Redirection Table Entries. */ + uint32_t redtbl_entries[QM_IOAPIC_NUM_RTES]; +} qm_irq_context_t; +#endif + +/** + * PIC TIMER context type. + * + * Applications should not modify the content. + * This structure is only intended to be used by the qm_pic_timer_save_context + * and qm_pic_timer_restore_context functions. + */ +typedef struct { + uint32_t timer_icr; /**< Initial Count Register. */ + uint32_t timer_dcr; /**< Divide Configuration Register. */ + uint32_t lvttimer; /**< Timer Entry in Local Vector Table. */ +} qm_pic_timer_context_t; + +#if (UNIT_TEST) +qm_lapic_reg_t test_lapic; +#define QM_LAPIC ((qm_lapic_reg_t *)(&test_lapic)) + +#else +/* Local APIC. */ +#define QM_LAPIC_BASE (0xFEE00000) +#define QM_LAPIC ((qm_lapic_reg_t *)QM_LAPIC_BASE) +#endif + +#define QM_INT_CONTROLLER QM_LAPIC + +/* + * Quark SE has a HW limitation that prevents a LAPIC EOI from being broadcast + * into IOAPIC. To trigger this manually we must write the vector number being + * serviced into the IOAPIC EOI register. + */ +#if defined(ENABLE_EXTERNAL_ISR_HANDLING) || defined(QM_SENSOR) +#define QM_ISR_EOI(vector) +#else +#define QM_ISR_EOI(vector) \ + do { \ + QM_INT_CONTROLLER->eoi.reg = 0; \ + QM_IOAPIC->eoi.reg = vector; \ + } while (0) +#endif + +typedef struct { + QM_RW apic_reg_pad_t ioregsel; /**< Register selector. */ + QM_RW apic_reg_pad_t iowin; /**< Register window. */ + QM_RW apic_reg_pad_t reserved[2]; + QM_RW apic_reg_pad_t eoi; /**< EOI register. */ +} qm_ioapic_reg_t; + +#define QM_IOAPIC_REG_VER (0x01) /* IOAPIC version. */ +#define QM_IOAPIC_REG_REDTBL (0x10) /* Redirection table base. */ + +#if (UNIT_TEST) +qm_ioapic_reg_t test_ioapic; +#define QM_IOAPIC ((qm_ioapic_reg_t *)(&test_ioapic)) + +#else +/* IO / APIC base address. */ +#define QM_IOAPIC_BASE (0xFEC00000) +#define QM_IOAPIC ((qm_ioapic_reg_t *)QM_IOAPIC_BASE) +#endif + +/** @} */ + +/** + * @name Power Management + * @{ + */ + +/** Power Management register map. */ +typedef struct { + QM_RW uint32_t p_lvl2; /**< Processor level 2 */ + QM_RW uint32_t reserved[4]; + QM_RW uint32_t pm1c; /**< Power management 1 control */ + QM_RW uint32_t reserved1[9]; + QM_RW uint32_t aon_vr; /**< AON Voltage Regulator */ + QM_RW uint32_t plat3p3_vr; /**< Platform 3p3 voltage regulator */ + QM_RW uint32_t plat1p8_vr; /**< Platform 1p8 voltage regulator */ + QM_RW uint32_t host_vr; /**< Host Voltage Regulator */ + QM_RW uint32_t slp_cfg; /**< Sleeping Configuration */ + /** Power Management Network (PMNet) Control and Status */ + QM_RW uint32_t pmnetcs; + QM_RW uint32_t pm_wait; /**< Power Management Wait */ + QM_RW uint32_t reserved2; + QM_RW uint32_t p_sts; /**< Processor Status */ + QM_RW uint32_t reserved3[3]; + QM_RW uint32_t rstc; /**< Reset Control */ + QM_RW uint32_t rsts; /**< Reset Status */ + QM_RW uint32_t reserved4[6]; + QM_RW uint32_t vr_lock; /**< Voltage regulator lock */ + QM_RW uint32_t pm_lock; /**< Power Management Lock */ +} qm_scss_pmu_reg_t; + +#if (UNIT_TEST) +qm_scss_pmu_reg_t test_scss_pmu; +#define QM_SCSS_PMU ((qm_scss_pmu_reg_t *)(&test_scss_pmu)) + +#else +#define QM_SCSS_PMU_BASE (0xB0800504) +#define QM_SCSS_PMU ((qm_scss_pmu_reg_t *)QM_SCSS_PMU_BASE) +#endif + +#define QM_SS_CFG_ARC_RUN_REQ_A BIT(24) +#define QM_P_STS_HALT_INTERRUPT_REDIRECTION BIT(26) +#define QM_P_STS_ARC_HALT BIT(14) + +#define QM_AON_VR_VSEL_MASK (0xFFE0) +#define QM_AON_VR_VSEL_1V2 (0x8) +#define QM_AON_VR_VSEL_1V35 (0xB) +#define QM_AON_VR_VSEL_1V8 (0x10) +#define QM_AON_VR_EN BIT(7) +#define QM_AON_VR_VSTRB BIT(5) + +#define QM_SCSS_SLP_CFG_LPMODE_EN BIT(8) +#define QM_SCSS_SLP_CFG_RTC_DIS BIT(7) +#define QM_SCSS_PM1C_SLPEN BIT(13) +#define QM_SCSS_HOST_VR_EN BIT(7) +#define QM_SCSS_PLAT3P3_VR_EN BIT(7) +#define QM_SCSS_PLAT1P8_VR_EN BIT(7) +#define QM_SCSS_HOST_VR_VREG_SEL BIT(6) +#define QM_SCSS_PLAT3P3_VR_VREG_SEL BIT(6) +#define QM_SCSS_PLAT1P8_VR_VREG_SEL BIT(6) +#define QM_SCSS_VR_ROK BIT(10) +#define QM_SCSS_VR_EN BIT(7) +#define QM_SCSS_VR_VREG_SEL BIT(6) + +/** @} */ + +/** + * @name Sensor Subsystem + * @{ + */ + +/** Sensor Subsystem register map. */ +typedef struct { + QM_RW uint32_t ss_cfg; /**< Sensor Subsystem Configuration */ + QM_RW uint32_t ss_sts; /**< Sensor Subsystem status */ +} qm_scss_ss_reg_t; + +#if (UNIT_TEST) +qm_scss_ss_reg_t test_scss_ss; +#define QM_SCSS_SS ((qm_scss_ss_reg_t *)(&test_scss_ss)) + +#else +#define QM_SCSS_SS_BASE (0xB0800600) +#define QM_SCSS_SS ((qm_scss_ss_reg_t *)QM_SCSS_SS_BASE) +#endif + +#define QM_SS_STS_HALT_INTERRUPT_REDIRECTION BIT(26) + +/** @} */ + +/** + * @name Always-on Counters. + * @{ + */ + +/** Number of Always-on counter controllers. */ +typedef enum { QM_AONC_0 = 0, QM_AONC_NUM } qm_aonc_t; + +/** Always-on Counter Controller register map. */ +typedef struct { + QM_RW uint32_t aonc_cnt; /**< Always-on counter register. */ + QM_RW uint32_t aonc_cfg; /**< Always-on counter enable. */ + QM_RW uint32_t aonpt_cnt; /**< Always-on periodic timer. */ + QM_RW uint32_t + aonpt_stat; /**< Always-on periodic timer status register. */ + QM_RW uint32_t aonpt_ctrl; /**< Always-on periodic timer control. */ + QM_RW uint32_t + aonpt_cfg; /**< Always-on periodic timer configuration register. */ +} qm_aonc_reg_t; + +#if (UNIT_TEST) +qm_aonc_reg_t test_aonc; +#define QM_AONC ((qm_aonc_reg_t *)(&test_aonc)) + +#else +#define QM_AONC_BASE (0xB0800700) +#define QM_AONC ((qm_aonc_reg_t *)QM_AONC_BASE) +#endif + +/** @} */ + +/** + * @name Peripheral Registers + * @{ + */ + +/** Peripheral Registers register map. */ +typedef struct { + QM_RW uint32_t usb_phy_cfg0; /**< USB Configuration */ + QM_RW uint32_t periph_cfg0; /**< Peripheral Configuration */ + QM_RW uint32_t reserved[2]; + QM_RW uint32_t cfg_lock; /**< Configuration Lock */ +} qm_scss_peripheral_reg_t; + +#if (UNIT_TEST) +qm_scss_peripheral_reg_t test_scss_peripheral; +#define QM_SCSS_PERIPHERAL ((qm_scss_peripheral_reg_t *)(&test_scss_peripheral)) + +#else +#define QM_SCSS_PERIPHERAL_BASE (0xB0800800) +#define QM_SCSS_PERIPHERAL ((qm_scss_peripheral_reg_t *)QM_SCSS_PERIPHERAL_BASE) +#endif + +/** @} */ + +/** + * @name Pin MUX + * @{ + */ + +/** Pin MUX register map. */ +typedef struct { + QM_RW uint32_t pmux_pullup[4]; /**< Pin Mux Pullup */ + QM_RW uint32_t pmux_slew[4]; /**< Pin Mux Slew Rate */ + QM_RW uint32_t pmux_in_en[4]; /**< Pin Mux Input Enable */ + QM_RW uint32_t pmux_sel[5]; /**< Pin Mux Select */ + QM_RW uint32_t reserved[2]; + QM_RW uint32_t pmux_pullup_lock; /**< Pin Mux Pullup Lock */ + QM_RW uint32_t pmux_slew_lock; /**< Pin Mux Slew Rate Lock */ + QM_RW uint32_t pmux_sel_lock[3]; /**< Pin Mux Select Lock */ + QM_RW uint32_t pmux_in_en_lock; /**< Pin Mux Slew Rate Lock */ +} qm_scss_pmux_reg_t; + +#if (UNIT_TEST) +qm_scss_pmux_reg_t test_scss_pmux; +#define QM_SCSS_PMUX ((qm_scss_pmux_reg_t *)(&test_scss_pmux)) + +#else +#define QM_SCSS_PMUX_BASE (0xB0800900) +#define QM_SCSS_PMUX ((qm_scss_pmux_reg_t *)QM_SCSS_PMUX_BASE) +#endif + +/* Pin MUX slew rate registers and settings */ +#define QM_PMUX_SLEW_4MA_DRIVER (0xFFFFFFFF) +#define QM_PMUX_SLEW0 (REG_VAL(0xB0800910)) +#define QM_PMUX_SLEW1 (REG_VAL(0xB0800914)) +#define QM_PMUX_SLEW2 (REG_VAL(0xB0800918)) +#define QM_PMUX_SLEW3 (REG_VAL(0xB080091C)) + +/** @} */ + +/** + * @name ID + * @{ + */ + +/** Information register map. */ +typedef struct { + QM_RW uint32_t id; +} qm_scss_info_reg_t; + +#if (UNIT_TEST) +qm_scss_info_reg_t test_scss_info; +#define QM_SCSS_INFO ((qm_scss_info_reg_t *)(&test_scss_info)) + +#else +#define QM_SCSS_INFO_BASE (0xB0801000) +#define QM_SCSS_INFO ((qm_scss_info_reg_t *)QM_SCSS_INFO_BASE) +#endif + +/** @} */ + +/** + * @name Mailbox + * @{ + */ + +#define HAS_MAILBOX (1) +#define NUM_MAILBOXES (8) + +#define HAS_MAILBOX_LAKEMONT_DEST (1) +#define HAS_MAILBOX_SENSOR_SUB_SYSTEM_DEST (1) + +/** + * Mailbox MBOX_CH_CTRL_N Mailbox Channel Control Word Register + * + * 31 RW/1S/V MBOX_CH_CTRL_INT Mailbox Channel Control Word interrupt + * 30:0 RW MBOX_CH_CTRL Mailbox Channel Control Word + */ +#define QM_MBOX_CH_CTRL_INT BIT(31) +#define QM_MBOX_CH_CTRL_MASK (0x7FFFFFFF) +#define QM_MBOX_CH_CTRL_SHIFT (0) + +/* + * Mailbox Channel Status MBOX_CH_STS_N + * + * 31:2 RO reserved + * 1 RW/1C/V MBOX_CH_STS_CTRL_INT Mailbox Channel Interrupt Status + * - Bit set when message sent, indicates pending interrupt + * - Bit set when a mailbox channel interrupt is pending.. + * - Bit cleared by writing 1 + * - Bit should be cleared by the receivers isr + * 0 RW/1C/V MBOX_CH_STS Mailbox Channel Status + * - Bit set when message sent, indicates pending data + * - Bit cleared by writing 1 + * - Bit should be cleared by the receiver after + * consuming the message. + */ +#define QM_MBOX_CH_STS_CTRL_INT BIT(1) +#define QM_MBOX_CH_STS BIT(0) + +#define QM_MBOX_STATUS_MASK (QM_MBOX_CH_STS | QM_MBOX_CH_STS_CTRL_INT) + +/** + * Mailbox MBOX_CHALL_STS Channel Status Bits Register + * + * 31:16 RO reserved + * 15:0 RO/V MBOX_CHALL_STS Channel Status Bits + */ +#define QM_MBOX_CHALL_STS(N) BIT((N * 2)) +#define QM_MBOX_CHALL_INT_STS(N) BIT((N * 2) + 1) + +/** + * Mailbox interrupt routing mask register INT_MAILBOX_MASK + * + * There is only 1 Mailbox interrupt mask register. + * The register contains masks for all 8 mailbox channels. + * + * Note that the Mailbox interrupt mask register does not follow + * the same layout as most other interrupt mask registers in the SCSS. + * + * Mask bit positions for INT_MAILBOX_MASK are listed here: + * + * 31:24 RW/P/L INT_MAILBOX_SS_HALT_MASK Mailbox SS Halt interrupt mask + * 23:16 RW/P/L INT_MAILBOX_HOST_HALT_MASK Mailbox Host Halt interrupt mask + * 15:8 RW/P/L INT_MAILBOX_SS_MASK Mailbox SS interrupt mask + * 7:0 RW/P/L INT_MAILBOX_HOST_MASK Mailbox Host interrupt mask + */ +#define QM_MBOX_SS_HALT_MASK_OFFSET (24) +#define QM_MBOX_SS_HALT_MASK_MASK (0xFF000000) +#define QM_MBOX_HOST_HALT_MASK_OFFSET (16) +#define QM_MBOX_HOST_HALT_MASK_MASK (0x00FF0000) +#define QM_MBOX_SS_MASK_OFFSET (8) +#define QM_MBOX_SS_MASK_MASK (0x0000FF00) +#define QM_MBOX_HOST_MASK_OFFSET (0) +#define QM_MBOX_HOST_MASK_MASK (0x000000FF) + +/** + * Mailbox Interrupt Mask enable/disable definitions + * + * \#defines use the channel number to determine the register and bit shift to + * use. + * The interrupt destination adds an offset to the bit shift. + */ +#define QM_MBOX_ENABLE_LMT_INT_MASK(N) \ + QM_INTERRUPT_ROUTER->mailbox_0_int_mask &= \ + ~(BIT(N + QM_MBOX_HOST_MASK_OFFSET)) +#define QM_MBOX_DISABLE_LMT_INT_MASK(N) \ + QM_INTERRUPT_ROUTER->mailbox_0_int_mask |= \ + (BIT(N + QM_MBOX_HOST_MASK_OFFSET)) +#define QM_MBOX_ENABLE_SS_INT_MASK(N) \ + QM_INTERRUPT_ROUTER->mailbox_0_int_mask &= \ + ~(BIT(N + QM_MBOX_SS_MASK_OFFSET)) +#define QM_MBOX_DISABLE_SS_INT_MASK(N) \ + QM_INTERRUPT_ROUTER->mailbox_0_int_mask |= \ + (BIT(N + QM_MBOX_SS_MASK_OFFSET)) + +/** + * Mailbox Interrupt Halt Mask enable/disable definitions + * + * \#defines use the channel number to determine the register and bit shift to + * use. + * The interrupt destination adds an offset to the bit shift, + * see above for the bit position layout + */ +#define QM_MBOX_ENABLE_LMT_INT_HALT_MASK(N) \ + QM_INTERRUPT_ROUTER->mailbox_0_int_mask &= \ + ~(BIT(N + QM_MBOX_HOST_HALT_MASK_OFFSET)) +#define QM_MBOX_DISABLE_LMT_INT_HALT_MASK(N) \ + QM_INTERRUPT_ROUTER->mailbox_0_int_mask |= \ + (BIT(N + QM_MBOX_HOST_HALT_MASK_OFFSET)) +#define QM_MBOX_ENABLE_SS_INT_HALT_MASK(N) \ + QM_INTERRUPT_ROUTER->mailbox_0_int_mask &= \ + ~(BIT(N + QM_MBOX_SS_HALT_MASK_OFFSET)) +#define QM_MBOX_DISABLE_SS_INT_HALT_MASK(N) \ + QM_INTERRUPT_ROUTER->mailbox_0_int_mask |= \ + (BIT(N + QM_MBOX_SS_HALT_MASK_OFFSET)) + +/** + * Mailbox interrupt mask definitions to return the current mask values + */ +#define QM_MBOX_SS_INT_HALT_MASK \ + ((QM_MBOX_SS_HALT_MASK_MASK & \ + QM_INTERRUPT_ROUTER->mailbox_0_int_mask) >> \ + QM_MBOX_SS_HALT_MASK_OFFSET) +#define QM_MBOX_LMT_INT_HALT_MASK \ + ((QM_MBOX_HOST_HALT_MASK_MASK & \ + QM_INTERRUPT_ROUTER->mailbox_0_int_mask) >> \ + QM_MBOX_SS_HALT_MASK_OFFSET) +#define QM_MBOX_SS_INT_MASK \ + ((QM_MBOX_SS_MASK_MASK & QM_INTERRUPT_ROUTER->mailbox_0_int_mask) >> \ + QM_MBOX_SS_MASK_OFFSET) +#define QM_MBOX_LMT_INT_MASK \ + (QM_MBOX_HOST_MASK_MASK & QM_INTERRUPT_ROUTER->mailbox_0_int_mask) + +/** + * Mailbox interrupt macros to determine if the specified mailbox interrupt mask + * has been locked. + */ +#define QM_MBOX_SS_INT_LOCK_HALT_MASK(N) \ + (QM_INTERRUPT_ROUTER->lock_int_mask_reg & BIT(3)) +#define QM_MBOX_LMT_INT_LOCK_HALT_MASK(N) \ + (QM_INTERRUPT_ROUTER->lock_int_mask_reg & BIT(2)) +#define QM_MBOX_SS_INT_LOCK_MASK(N) \ + (QM_INTERRUPT_ROUTER->lock_int_mask_reg & BIT(1)) +#define QM_MBOX_LMT_INT_LOCK_MASK(N) \ + (QM_INTERRUPT_ROUTER->lock_int_mask_reg & BIT(0)) + +/** Mailbox register structure. */ +typedef struct { + QM_RW uint32_t ch_ctrl; /**< Channel Control Word */ + QM_RW uint32_t ch_data[4]; /**< Channel Payload Data Word 0 */ + QM_RW uint32_t ch_sts; /**< Channel status */ +} qm_mailbox_t; + +/** Mailbox register map. */ +typedef struct { + qm_mailbox_t mbox[NUM_MAILBOXES]; /**< 8 Mailboxes */ + QM_RW uint32_t mbox_chall_sts; /**< All channel status */ +} qm_mailbox_reg_t; + +#if (UNIT_TEST) +qm_mailbox_reg_t test_mailbox; +#define QM_MAILBOX ((qm_mailbox_reg_t *)(&test_mailbox)) + +#else +#define QM_MAILBOX_BASE (0xB0800A00) +#define QM_MAILBOX ((qm_mailbox_reg_t *)QM_MAILBOX_BASE) +#endif + +/** @} */ + +/** + * @name PWM / Timer + * @{ + */ + +/** Number of PWM / Timer controllers. */ +typedef enum { QM_PWM_0 = 0, QM_PWM_NUM } qm_pwm_t; + +/** PWM ID type. */ +typedef enum { + QM_PWM_ID_0 = 0, + QM_PWM_ID_1, + QM_PWM_ID_2, + QM_PWM_ID_3, + QM_PWM_ID_NUM +} qm_pwm_id_t; + +/** PWM / Timer channel register map. */ +typedef struct { + QM_RW uint32_t loadcount; /**< Load Count */ + QM_RW uint32_t currentvalue; /**< Current Value */ + QM_RW uint32_t controlreg; /**< Control */ + QM_RW uint32_t eoi; /**< End Of Interrupt */ + QM_RW uint32_t intstatus; /**< Interrupt Status */ +} qm_pwm_channel_t; + +/** PWM / Timer register map. */ +typedef struct { + qm_pwm_channel_t timer[QM_PWM_ID_NUM]; /**< 4 Timers */ + QM_RW uint32_t reserved[20]; + QM_RW uint32_t timersintstatus; /**< Timers Interrupt Status */ + QM_RW uint32_t timerseoi; /**< Timers End Of Interrupt */ + QM_RW uint32_t timersrawintstatus; /**< Timers Raw Interrupt Status */ + QM_RW uint32_t timerscompversion; /**< Timers Component Version */ + QM_RW uint32_t + timer_loadcount2[QM_PWM_ID_NUM]; /**< Timer Load Count 2 */ +} qm_pwm_reg_t; + +/** + * PWM context type. + * + * Applications should not modify the content. + * This structure is only intended to be used by + * the qm_pwm_save_context and qm_pwm_restore_context functions. + */ +typedef struct { + struct { + uint32_t loadcount; /**< Load Count 1. */ + uint32_t loadcount2; /**< Load Count 2. */ + uint32_t controlreg; /**< Control Register. */ + } channel[QM_PWM_ID_NUM]; +} qm_pwm_context_t; + +#if (UNIT_TEST) +qm_pwm_reg_t test_pwm_t; +#define QM_PWM ((qm_pwm_reg_t *)(&test_pwm_t)) + +#else +/* PWM register base address. */ +#define QM_PWM_BASE (0xB0000800) +/* PWM register block. */ +#define QM_PWM ((qm_pwm_reg_t *)QM_PWM_BASE) +#endif + +#define PWM_START (1) + +#define QM_PWM_CONF_MODE_MASK (0xA) +#define QM_PWM_CONF_INT_EN_MASK (0x4) + +#define QM_PWM_INTERRUPT_MASK_OFFSET (0x2) + +/** + * Timer N Control (TimerNControlReg) + * + * 31:4 RO reserved + * 3 RW Timer PWM + * 1 - PWM Mode + * 0 - Timer Mode + * 2 RW Timer Interrupt Mask, set to 1b to mask interrupt. + * 1 RW Timer Mode + * 1 - user-defined count mode + * 0 - free-running mode + * 0 RW Timer Enable + * 0 - Disable PWM/Timer + * 1 - Enable PWM/Timer + */ + +#define QM_PWM_TIMERNCONTROLREG_TIMER_ENABLE (BIT(0)) +#define QM_PWM_TIMERNCONTROLREG_TIMER_MODE (BIT(1)) +#define QM_PWM_TIMERNCONTROLREG_TIMER_INTERRUPT_MASK (BIT(2)) +#define QM_PWM_TIMERNCONTROLREG_TIMER_PWM (BIT(3)) + +#define QM_PWM_MODE_TIMER_FREE_RUNNING_VALUE (0) +#define QM_PWM_MODE_TIMER_COUNT_VALUE (QM_PWM_TIMERNCONTROLREG_TIMER_MODE) +#define QM_PWM_MODE_PWM_VALUE \ + (QM_PWM_TIMERNCONTROLREG_TIMER_PWM | QM_PWM_TIMERNCONTROLREG_TIMER_MODE) + +/** @} */ + +/** + * @name WDT + * @{ + */ + +/** Number of WDT controllers. */ +typedef enum { QM_WDT_0 = 0, QM_WDT_NUM } qm_wdt_t; + +/** Watchdog timer register map. */ +typedef struct { + QM_RW uint32_t wdt_cr; /**< Control Register */ + QM_RW uint32_t wdt_torr; /**< Timeout Range Register */ + QM_RW uint32_t wdt_ccvr; /**< Current Counter Value Register */ + QM_RW uint32_t wdt_crr; /**< Current Restart Register */ + QM_RW uint32_t wdt_stat; /**< Interrupt Status Register */ + QM_RW uint32_t wdt_eoi; /**< Interrupt Clear Register */ + QM_RW uint32_t wdt_comp_param_5; /**< Component Parameters */ + QM_RW uint32_t wdt_comp_param_4; /**< Component Parameters */ + QM_RW uint32_t wdt_comp_param_3; /**< Component Parameters */ + QM_RW uint32_t wdt_comp_param_2; /**< Component Parameters */ + QM_RW uint32_t + wdt_comp_param_1; /**< Component Parameters Register 1 */ + QM_RW uint32_t wdt_comp_version; /**< Component Version Register */ + QM_RW uint32_t wdt_comp_type; /**< Component Type Register */ +} qm_wdt_reg_t; + +/* + * WDT context type. + * + * Application should not modify the content. + * This structure is only intended to be used by the qm_wdt_save_context and + * qm_wdt_restore_context functions. + */ +typedef struct { + uint32_t wdt_cr; /**< Control Register. */ + uint32_t wdt_torr; /**< Timeout Range Register. */ +} qm_wdt_context_t; + +#if (UNIT_TEST) +qm_wdt_reg_t test_wdt; +#define QM_WDT ((qm_wdt_reg_t *)(&test_wdt)) + +#else +/* WDT register base address. */ +#define QM_WDT_BASE (0xB0000000) + +/* WDT register block. */ +#define QM_WDT ((qm_wdt_reg_t *)QM_WDT_BASE) +#endif + +/* Watchdog enable. */ +#define QM_WDT_CR_WDT_ENABLE (BIT(0)) +/* Watchdog mode. */ +#define QM_WDT_CR_RMOD (BIT(1)) +/* Watchdog mode offset. */ +#define QM_WDT_CR_RMOD_OFFSET (1) +/* Watchdog Timeout Mask. */ +#define QM_WDT_TORR_TOP_MASK (0xF) + +/** + * WDT timeout table (in clock cycles): + * Each table entry corresponds with the value loaded + * into the WDT at the time of a WDT reload for the + * corresponding timeout range register value. + * + * TORR | Timeout (Clock Cycles) + * 0. | 2^16 (65536) + * 1. | 2^17 (131072) + * 2. | 2^18 (262144) + * 3. | 2^19 (524288) + * 4. | 2^20 (1048576) + * 5. | 2^21 (2097152) + * 6. | 2^22 (4194304) + * 7. | 2^23 (8388608) + * 8. | 2^24 (16777216) + * 9. | 2^25 (33554432) + * 10. | 2^26 (67108864) + * 11. | 2^27 (134217728) + * 12. | 2^28 (268435456) + * 13. | 2^29 (536870912) + * 14. | 2^30 (1073741824) + * 15. | 2^31 (2147483648) + */ + +/** @} */ + +/** + * @name UART + * @{ + */ + +/* Break character Bit. */ +#define QM_UART_LCR_BREAK BIT(6) +/* Divisor Latch Access Bit. */ +#define QM_UART_LCR_DLAB BIT(7) + +/* Request to Send Bit. */ +#define QM_UART_MCR_RTS BIT(1) +/* Loopback Enable Bit. */ +#define QM_UART_MCR_LOOPBACK BIT(4) +/* Auto Flow Control Enable Bit. */ +#define QM_UART_MCR_AFCE BIT(5) + +/* FIFO Enable Bit. */ +#define QM_UART_FCR_FIFOE BIT(0) +/* Reset Receive FIFO. */ +#define QM_UART_FCR_RFIFOR BIT(1) +/* Reset Transmit FIFO. */ +#define QM_UART_FCR_XFIFOR BIT(2) + +/* Default FIFO RX & TX Thresholds, half full for both. */ +#define QM_UART_FCR_DEFAULT_TX_RX_THRESHOLD (0xB0) +/* Change TX Threshold to empty, keep RX Threshold to default. */ +#define QM_UART_FCR_TX_0_RX_1_2_THRESHOLD (0x80) + +/* Transmit Holding Register Empty. */ +#define QM_UART_IIR_THR_EMPTY (0x02) +/* Received Data Available. */ +#define QM_UART_IIR_RECV_DATA_AVAIL (0x04) +/* Receiver Line Status. */ +#define QM_UART_IIR_RECV_LINE_STATUS (0x06) +/* Character Timeout. */ +#define QM_UART_IIR_CHAR_TIMEOUT (0x0C) +/* Interrupt ID Mask. */ +#define QM_UART_IIR_IID_MASK (0x0F) + +/* Data Ready Bit. */ +#define QM_UART_LSR_DR BIT(0) +/* Overflow Error Bit. */ +#define QM_UART_LSR_OE BIT(1) +/* Parity Error Bit. */ +#define QM_UART_LSR_PE BIT(2) +/* Framing Error Bit. */ +#define QM_UART_LSR_FE BIT(3) +/* Break Interrupt Bit. */ +#define QM_UART_LSR_BI BIT(4) +/* Transmit Holding Register Empty Bit. */ +#define QM_UART_LSR_THRE BIT(5) +/* Transmitter Empty Bit. */ +#define QM_UART_LSR_TEMT BIT(6) +/* Receiver FIFO Error Bit. */ +#define QM_UART_LSR_RFE BIT(7) + +/* Enable Received Data Available Interrupt. */ +#define QM_UART_IER_ERBFI BIT(0) +/* Enable Transmit Holding Register Empty Interrupt. */ +#define QM_UART_IER_ETBEI BIT(1) +/* Enable Receiver Line Status Interrupt. */ +#define QM_UART_IER_ELSI BIT(2) +/* Programmable THRE Interrupt Mode. */ +#define QM_UART_IER_PTIME BIT(7) + +/* Line Status Errors. */ +#define QM_UART_LSR_ERROR_BITS \ + (QM_UART_LSR_OE | QM_UART_LSR_PE | QM_UART_LSR_FE | QM_UART_LSR_BI) + +/* FIFO Depth. */ +#define QM_UART_FIFO_DEPTH (16) +/* FIFO Half Depth. */ +#define QM_UART_FIFO_HALF_DEPTH (QM_UART_FIFO_DEPTH / 2) + +/* Divisor Latch High Offset. */ +#define QM_UART_CFG_BAUD_DLH_OFFS 16 +/* Divisor Latch Low Offset. */ +#define QM_UART_CFG_BAUD_DLL_OFFS 8 +/* Divisor Latch Fraction Offset. */ +#define QM_UART_CFG_BAUD_DLF_OFFS 0 +/* Divisor Latch High Mask. */ +#define QM_UART_CFG_BAUD_DLH_MASK (0xFF << QM_UART_CFG_BAUD_DLH_OFFS) +/* Divisor Latch Low Mask. */ +#define QM_UART_CFG_BAUD_DLL_MASK (0xFF << QM_UART_CFG_BAUD_DLL_OFFS) +/* Divisor Latch Fraction Mask. */ +#define QM_UART_CFG_BAUD_DLF_MASK (0xFF << QM_UART_CFG_BAUD_DLF_OFFS) + +/* Divisor Latch Packing Helper. */ +#define QM_UART_CFG_BAUD_DL_PACK(dlh, dll, dlf) \ + (dlh << QM_UART_CFG_BAUD_DLH_OFFS | dll << QM_UART_CFG_BAUD_DLL_OFFS | \ + dlf << QM_UART_CFG_BAUD_DLF_OFFS) + +/* Divisor Latch High Unpacking Helper. */ +#define QM_UART_CFG_BAUD_DLH_UNPACK(packed) \ + ((packed & QM_UART_CFG_BAUD_DLH_MASK) >> QM_UART_CFG_BAUD_DLH_OFFS) +/* Divisor Latch Low Unpacking Helper. */ +#define QM_UART_CFG_BAUD_DLL_UNPACK(packed) \ + ((packed & QM_UART_CFG_BAUD_DLL_MASK) >> QM_UART_CFG_BAUD_DLL_OFFS) +/* Divisor Latch Fraction Unpacking Helper. */ +#define QM_UART_CFG_BAUD_DLF_UNPACK(packed) \ + ((packed & QM_UART_CFG_BAUD_DLF_MASK) >> QM_UART_CFG_BAUD_DLF_OFFS) + +/** Number of UART controllers. */ +typedef enum { QM_UART_0 = 0, QM_UART_1, QM_UART_NUM } qm_uart_t; + +/** UART register map. */ +typedef struct { + QM_RW uint32_t rbr_thr_dll; /**< Rx Buffer/ Tx Holding/ Div Latch Low */ + QM_RW uint32_t ier_dlh; /**< Interrupt Enable / Divisor Latch High */ + QM_RW uint32_t iir_fcr; /**< Interrupt Identification / FIFO Control */ + QM_RW uint32_t lcr; /**< Line Control */ + QM_RW uint32_t mcr; /**< MODEM Control */ + QM_RW uint32_t lsr; /**< Line Status */ + QM_RW uint32_t msr; /**< MODEM Status */ + QM_RW uint32_t scr; /**< Scratchpad */ + QM_RW uint32_t reserved[23]; + QM_RW uint32_t usr; /**< UART Status */ + QM_RW uint32_t reserved1[9]; + QM_RW uint32_t htx; /**< Halt Transmission */ + QM_RW uint32_t dmasa; /**< DMA Software Acknowledge */ + QM_RW uint32_t reserved2[5]; + QM_RW uint32_t dlf; /**< Divisor Latch Fraction */ + QM_RW uint32_t padding[0xCF]; /* (0x400 - 0xC4) / 4 */ +} qm_uart_reg_t; + +/** + * UART context to be saved between sleep/resume. + * + * Application should not modify the content. + * This structure is only intended to be used by the qm_uart_save_context and + * qm_uart_restore_context functions. + */ +typedef struct { + uint32_t ier; /**< Interrupt Enable Register. */ + uint32_t dlh; /**< Divisor Latch High. */ + uint32_t dll; /**< Divisor Latch Low. */ + uint32_t lcr; /**< Line Control. */ + uint32_t mcr; /**< Modem Control. */ + uint32_t scr; /**< Scratchpad. */ + uint32_t htx; /**< Halt Transmission. */ + uint32_t dlf; /**< Divisor Latch Fraction. */ +} qm_uart_context_t; + +#if (UNIT_TEST) +qm_uart_reg_t test_uart_instance; +qm_uart_reg_t *test_uart[QM_UART_NUM]; +#define QM_UART test_uart + +#else +/* UART register base address. */ +#define QM_UART_0_BASE (0xB0002000) +#define QM_UART_1_BASE (0xB0002400) +/* UART register block. */ +extern qm_uart_reg_t *qm_uart[QM_UART_NUM]; +#define QM_UART qm_uart +#endif + +/** @} */ + +/** + * @name SPI + * @{ + */ + +/** Number of SPI controllers (only master driver available). */ +typedef enum { QM_SPI_MST_0 = 0, QM_SPI_MST_1, QM_SPI_NUM } qm_spi_t; + +/** SPI register map. */ +typedef struct { + QM_RW uint32_t ctrlr0; /**< Control Register 0 */ + QM_RW uint32_t ctrlr1; /**< Control Register 1 */ + QM_RW uint32_t ssienr; /**< SSI Enable Register */ + QM_RW uint32_t mwcr; /**< Microwire Control Register */ + QM_RW uint32_t ser; /**< Slave Enable Register */ + QM_RW uint32_t baudr; /**< Baud Rate Select */ + QM_RW uint32_t txftlr; /**< Transmit FIFO Threshold Level */ + QM_RW uint32_t rxftlr; /**< Receive FIFO Threshold Level */ + QM_RW uint32_t txflr; /**< Transmit FIFO Level Register */ + QM_RW uint32_t rxflr; /**< Receive FIFO Level Register */ + QM_RW uint32_t sr; /**< Status Register */ + QM_RW uint32_t imr; /**< Interrupt Mask Register */ + QM_RW uint32_t isr; /**< Interrupt Status Register */ + QM_RW uint32_t risr; /**< Raw Interrupt Status Register */ + QM_RW uint32_t txoicr; /**< Tx FIFO Overflow Interrupt Clear Register*/ + QM_RW uint32_t rxoicr; /**< Rx FIFO Overflow Interrupt Clear Register */ + QM_RW uint32_t rxuicr; /**< Rx FIFO Underflow Interrupt Clear Register*/ + QM_RW uint32_t msticr; /**< Multi-Master Interrupt Clear Register */ + QM_RW uint32_t icr; /**< Interrupt Clear Register */ + QM_RW uint32_t dmacr; /**< DMA Control Register */ + QM_RW uint32_t dmatdlr; /**< DMA Transmit Data Level */ + QM_RW uint32_t dmardlr; /**< DMA Receive Data Level */ + QM_RW uint32_t idr; /**< Identification Register */ + QM_RW uint32_t ssi_comp_version; /**< coreKit Version ID register */ + QM_RW uint32_t dr[36]; /**< Data Register */ + QM_RW uint32_t rx_sample_dly; /**< RX Sample Delay Register */ + QM_RW uint32_t padding[0xC4]; /* (0x400 - 0xF0) / 4 */ +} qm_spi_reg_t; + +/** + * SPI context type. + * + * Applications should not modify the content. + * This structure is only intended to be used by + * the qm_spi_save_context and qm_spi_restore_context functions. + */ +typedef struct { + uint32_t ctrlr0; /**< Control Register 0. */ + uint32_t ser; /**< Slave Enable Register. */ + uint32_t baudr; /**< Baud Rate Select. */ +} qm_spi_context_t; + +#if (UNIT_TEST) +qm_spi_reg_t test_spi; +qm_spi_reg_t *test_spi_controllers[QM_SPI_NUM]; + +#define QM_SPI test_spi_controllers + +#else +/* SPI Master register base address. */ +#define QM_SPI_MST_0_BASE (0xB0001000) +#define QM_SPI_MST_1_BASE (0xB0001400) +extern qm_spi_reg_t *qm_spi_controllers[QM_SPI_NUM]; +#define QM_SPI qm_spi_controllers + +/* SPI Slave register base address. */ +#define QM_SPI_SLV_BASE (0xB0001800) +#endif + +/* SPI Ctrlr0 register. */ +#define QM_SPI_CTRLR0_DFS_32_MASK (0x001F0000) +#define QM_SPI_CTRLR0_TMOD_MASK (0x00000300) +#define QM_SPI_CTRLR0_SCPOL_SCPH_MASK (0x000000C0) +#define QM_SPI_CTRLR0_FRF_MASK (0x00000030) +#define QM_SPI_CTRLR0_DFS_32_OFFSET (16) +#define QM_SPI_CTRLR0_TMOD_OFFSET (8) +#define QM_SPI_CTRLR0_SCPOL_SCPH_OFFSET (6) +#define QM_SPI_CTRLR0_FRF_OFFSET (4) + +/* SPI SSI Enable register. */ +#define QM_SPI_SSIENR_SSIENR BIT(0) + +/* SPI Status register. */ +#define QM_SPI_SR_BUSY BIT(0) +#define QM_SPI_SR_TFNF BIT(1) +#define QM_SPI_SR_TFE BIT(2) +#define QM_SPI_SR_RFNE BIT(3) +#define QM_SPI_SR_RFF BIT(4) + +/* SPI Interrupt Mask register. */ +#define QM_SPI_IMR_MASK_ALL (0x00) +#define QM_SPI_IMR_TXEIM BIT(0) +#define QM_SPI_IMR_TXOIM BIT(1) +#define QM_SPI_IMR_RXUIM BIT(2) +#define QM_SPI_IMR_RXOIM BIT(3) +#define QM_SPI_IMR_RXFIM BIT(4) + +/* SPI Interrupt Status register. */ +#define QM_SPI_ISR_TXEIS BIT(0) +#define QM_SPI_ISR_TXOIS BIT(1) +#define QM_SPI_ISR_RXUIS BIT(2) +#define QM_SPI_ISR_RXOIS BIT(3) +#define QM_SPI_ISR_RXFIS BIT(4) + +/* SPI Raw Interrupt Status register. */ +#define QM_SPI_RISR_TXEIR BIT(0) +#define QM_SPI_RISR_TXOIR BIT(1) +#define QM_SPI_RISR_RXUIR BIT(2) +#define QM_SPI_RISR_RXOIR BIT(3) +#define QM_SPI_RISR_RXFIR BIT(4) + +/* SPI DMA control. */ +#define QM_SPI_DMACR_RDMAE BIT(0) +#define QM_SPI_DMACR_TDMAE BIT(1) + +/** @} */ + +/** + * @name RTC + * @{ + */ + +/** Number of RTC controllers. */ +typedef enum { QM_RTC_0 = 0, QM_RTC_NUM } qm_rtc_t; + +/** RTC register map. */ +typedef struct { + QM_RW uint32_t rtc_ccvr; /**< Current Counter Value Register */ + QM_RW uint32_t rtc_cmr; /**< Current Match Register */ + QM_RW uint32_t rtc_clr; /**< Counter Load Register */ + QM_RW uint32_t rtc_ccr; /**< Counter Control Register */ + QM_RW uint32_t rtc_stat; /**< Interrupt Status Register */ + QM_RW uint32_t rtc_rstat; /**< Interrupt Raw Status Register */ + QM_RW uint32_t rtc_eoi; /**< End of Interrupt Register */ + QM_RW uint32_t rtc_comp_version; /**< End of Interrupt Register */ +} qm_rtc_reg_t; + +#define QM_RTC_CCR_INTERRUPT_ENABLE BIT(0) +#define QM_RTC_CCR_INTERRUPT_MASK BIT(1) +#define QM_RTC_CCR_ENABLE BIT(2) + +#if (UNIT_TEST) +qm_rtc_reg_t test_rtc; +#define QM_RTC ((qm_rtc_reg_t *)(&test_rtc)) + +#else +/* RTC register base address. */ +#define QM_RTC_BASE (0xB0000400) + +/* RTC register block. */ +#define QM_RTC ((qm_rtc_reg_t *)QM_RTC_BASE) +#endif + +/** @} */ + +/** + * @name I2C + * @{ + */ + +/** Number of I2C controllers. */ +typedef enum { QM_I2C_0 = 0, QM_I2C_1, QM_I2C_NUM } qm_i2c_t; + +/** I2C register map. */ +typedef struct { + QM_RW uint32_t ic_con; /**< Control Register */ + QM_RW uint32_t ic_tar; /**< Master Target Address */ + QM_RW uint32_t ic_sar; /**< Slave Address */ + QM_RW uint32_t ic_hs_maddr; /**< High Speed Master ID */ + QM_RW uint32_t ic_data_cmd; /**< Data Buffer and Command */ + QM_RW uint32_t + ic_ss_scl_hcnt; /**< Standard Speed Clock SCL High Count */ + QM_RW uint32_t + ic_ss_scl_lcnt; /**< Standard Speed Clock SCL Low Count */ + QM_RW uint32_t ic_fs_scl_hcnt; /**< Fast Speed Clock SCL High Count */ + QM_RW uint32_t + ic_fs_scl_lcnt; /**< Fast Speed I2C Clock SCL Low Count */ + QM_RW uint32_t + ic_hs_scl_hcnt; /**< High Speed I2C Clock SCL High Count */ + QM_RW uint32_t + ic_hs_scl_lcnt; /**< High Speed I2C Clock SCL Low Count */ + QM_RW uint32_t ic_intr_stat; /**< Interrupt Status */ + QM_RW uint32_t ic_intr_mask; /**< Interrupt Mask */ + QM_RW uint32_t ic_raw_intr_stat; /**< Raw Interrupt Status */ + QM_RW uint32_t ic_rx_tl; /**< Receive FIFO Threshold Level */ + QM_RW uint32_t ic_tx_tl; /**< Transmit FIFO Threshold Level */ + QM_RW uint32_t + ic_clr_intr; /**< Clear Combined and Individual Interrupt */ + QM_RW uint32_t ic_clr_rx_under; /**< Clear RX_UNDER Interrupt */ + QM_RW uint32_t ic_clr_rx_over; /**< Clear RX_OVER Interrupt */ + QM_RW uint32_t ic_clr_tx_over; /**< Clear TX_OVER Interrupt */ + QM_RW uint32_t ic_clr_rd_req; /**< Clear RD_REQ Interrupt */ + QM_RW uint32_t ic_clr_tx_abrt; /**< Clear TX_ABRT Interrupt */ + QM_RW uint32_t ic_clr_rx_done; /**< Clear RX_DONE Interrupt */ + QM_RW uint32_t ic_clr_activity; /**< Clear ACTIVITY Interrupt */ + QM_RW uint32_t ic_clr_stop_det; /**< Clear STOP_DET Interrupt */ + QM_RW uint32_t ic_clr_start_det; /**< Clear START_DET Interrupt */ + QM_RW uint32_t ic_clr_gen_call; /**< Clear GEN_CALL Interrupt */ + QM_RW uint32_t ic_enable; /**< Enable */ + QM_RW uint32_t ic_status; /**< Status */ + QM_RW uint32_t ic_txflr; /**< Transmit FIFO Level */ + QM_RW uint32_t ic_rxflr; /**< Receive FIFO Level */ + QM_RW uint32_t ic_sda_hold; /**< SDA Hold */ + QM_RW uint32_t ic_tx_abrt_source; /**< Transmit Abort Source */ + QM_RW uint32_t reserved; + QM_RW uint32_t ic_dma_cr; /**< SDA Setup */ + QM_RW uint32_t ic_dma_tdlr; /**< DMA Transmit Data Level Register */ + QM_RW uint32_t ic_dma_rdlr; /**< I2C Receive Data Level Register */ + QM_RW uint32_t ic_sda_setup; /**< SDA Setup */ + QM_RW uint32_t ic_ack_general_call; /**< General Call Ack */ + QM_RW uint32_t ic_enable_status; /**< Enable Status */ + QM_RW uint32_t ic_fs_spklen; /**< SS and FS Spike Suppression Limit */ + QM_RW uint32_t ic_hs_spklen; /**< HS spike suppression limit */ + QM_RW uint32_t reserved1[19]; + QM_RW uint32_t ic_comp_param_1; /**< Configuration Parameters */ + QM_RW uint32_t ic_comp_version; /**< Component Version */ + QM_RW uint32_t ic_comp_type; /**< Component Type */ + QM_RW uint32_t padding[0xC0]; /* Padding (0x400-0xFC)/4 */ +} qm_i2c_reg_t; + +/** + * I2C context to be saved between sleep/resume. + * + * Application should not modify the content. + * This structure is only intended to be used by the qm_i2c_save_context and + * qm_i2c_restore_context functions. + */ +typedef struct { + uint32_t con; /**< Control Register. */ + uint32_t sar; /**< Slave Address. */ + uint32_t ss_scl_hcnt; /**< Standard Speed Clock SCL High Count. */ + uint32_t ss_scl_lcnt; /**< Standard Speed Clock SCL Low Count. */ + uint32_t fs_scl_hcnt; /**< Fast Speed Clock SCL High Count. */ + uint32_t fs_scl_lcnt; /**< Fast Speed I2C Clock SCL Low Count. */ + uint32_t enable; /**< Enable. */ + uint32_t fs_spklen; /**< SS and FS Spike Suppression Limit. */ + uint32_t ic_intr_mask; /**< I2C Interrupt Mask. */ +} qm_i2c_context_t; + +#if (UNIT_TEST) +qm_i2c_reg_t test_i2c_instance[QM_I2C_NUM]; +qm_i2c_reg_t *test_i2c[QM_I2C_NUM]; + +#define QM_I2C test_i2c + +#else +/* I2C Master register base address. */ +#define QM_I2C_0_BASE (0xB0002800) +#define QM_I2C_1_BASE (0xB0002C00) + +/** I2C register block. */ +extern qm_i2c_reg_t *qm_i2c[QM_I2C_NUM]; +#define QM_I2C qm_i2c +#endif + +#define QM_I2C_IC_ENABLE_CONTROLLER_EN BIT(0) +#define QM_I2C_IC_ENABLE_CONTROLLER_ABORT BIT(1) +#define QM_I2C_IC_ENABLE_STATUS_IC_EN BIT(0) +#define QM_I2C_IC_CON_MASTER_MODE BIT(0) +#define QM_I2C_IC_CON_SLAVE_DISABLE BIT(6) +#define QM_I2C_IC_CON_10BITADDR_MASTER BIT(4) +#define QM_I2C_IC_CON_10BITADDR_MASTER_OFFSET (4) +#define QM_I2C_IC_CON_10BITADDR_SLAVE BIT(3) +#define QM_I2C_IC_CON_10BITADDR_SLAVE_OFFSET (3) +#define QM_I2C_IC_CON_SPEED_OFFSET (1) +#define QM_I2C_IC_CON_SPEED_SS BIT(1) +#define QM_I2C_IC_CON_SPEED_FS_FSP BIT(2) +#define QM_I2C_IC_CON_SPEED_MASK (0x06) +#define QM_I2C_IC_CON_RESTART_EN BIT(5) +#define QM_I2C_IC_CON_STOP_DET_IFADDRESSED BIT(7) +#define QM_I2C_IC_DATA_CMD_READ BIT(8) +#define QM_I2C_IC_DATA_CMD_STOP_BIT_CTRL BIT(9) +#define QM_I2C_IC_DATA_CMD_LSB_MASK (0x000000FF) +#define QM_I2C_IC_RAW_INTR_STAT_RX_FULL BIT(2) +#define QM_I2C_IC_RAW_INTR_STAT_TX_ABRT BIT(6) +#define QM_I2C_IC_RAW_INTR_STAT_GEN_CALL BIT(11) +#define QM_I2C_IC_RAW_INTR_STAT_RESTART_DETECTED BIT(12) +#define QM_I2C_IC_TX_ABRT_SOURCE_NAK_MASK (0x1F) +#define QM_I2C_IC_TX_ABRT_SOURCE_ARB_LOST BIT(12) +#define QM_I2C_IC_TX_ABRT_SOURCE_ABRT_SBYTE_NORSTRT BIT(9) +#define QM_I2C_IC_TX_ABRT_SOURCE_ALL_MASK (0x1FFFF) +#define QM_I2C_IC_STATUS_BUSY_MASK (0x00000060) +#define QM_I2C_IC_STATUS_RFF BIT(4) +#define QM_I2C_IC_STATUS_RFNE BIT(3) +#define QM_I2C_IC_STATUS_TFE BIT(2) +#define QM_I2C_IC_STATUS_TNF BIT(1) +#define QM_I2C_IC_INTR_MASK_ALL (0x00) +#define QM_I2C_IC_INTR_MASK_RX_UNDER BIT(0) +#define QM_I2C_IC_INTR_MASK_RX_OVER BIT(1) +#define QM_I2C_IC_INTR_MASK_RX_FULL BIT(2) +#define QM_I2C_IC_INTR_MASK_TX_OVER BIT(3) +#define QM_I2C_IC_INTR_MASK_TX_EMPTY BIT(4) +#define QM_I2C_IC_INTR_MASK_RD_REQ BIT(5) +#define QM_I2C_IC_INTR_MASK_TX_ABORT BIT(6) +#define QM_I2C_IC_INTR_MASK_RX_DONE BIT(7) +#define QM_I2C_IC_INTR_MASK_ACTIVITY BIT(8) +#define QM_I2C_IC_INTR_MASK_STOP_DETECTED BIT(9) +#define QM_I2C_IC_INTR_MASK_START_DETECTED BIT(10) +#define QM_I2C_IC_INTR_MASK_GEN_CALL_DETECTED BIT(11) +#define QM_I2C_IC_INTR_MASK_RESTART_DETECTED BIT(12) +#define QM_I2C_IC_INTR_STAT_RX_UNDER BIT(0) +#define QM_I2C_IC_INTR_STAT_RX_OVER BIT(1) +#define QM_I2C_IC_INTR_STAT_RX_FULL BIT(2) +#define QM_I2C_IC_INTR_STAT_TX_OVER BIT(3) +#define QM_I2C_IC_INTR_STAT_TX_EMPTY BIT(4) +#define QM_I2C_IC_INTR_STAT_RD_REQ BIT(5) +#define QM_I2C_IC_INTR_STAT_TX_ABRT BIT(6) +#define QM_I2C_IC_INTR_STAT_RX_DONE BIT(7) +#define QM_I2C_IC_INTR_STAT_STOP_DETECTED BIT(9) +#define QM_I2C_IC_INTR_STAT_START_DETECTED BIT(10) +#define QM_I2C_IC_INTR_STAT_GEN_CALL_DETECTED BIT(11) +#define QM_I2C_IC_LCNT_MAX (65525) +#define QM_I2C_IC_LCNT_MIN (8) +#define QM_I2C_IC_HCNT_MAX (65525) +#define QM_I2C_IC_HCNT_MIN (6) + +#define QM_I2C_FIFO_SIZE (16) + +/* I2C DMA */ +#define QM_I2C_IC_DMA_CR_RX_ENABLE BIT(0) +#define QM_I2C_IC_DMA_CR_TX_ENABLE BIT(1) + +/** @} */ + +/** + * @name GPIO + * @{ + */ + +/** Number of GPIO controllers. */ +typedef enum { QM_GPIO_0 = 0, QM_AON_GPIO_0 = 1, QM_GPIO_NUM } qm_gpio_t; + +/** GPIO register map. */ +typedef struct { + QM_RW uint32_t gpio_swporta_dr; /**< Port A Data */ + QM_RW uint32_t gpio_swporta_ddr; /**< Port A Data Direction */ + QM_RW uint32_t gpio_swporta_ctl; /**< Port A Data Source */ + QM_RW uint32_t reserved[9]; + QM_RW uint32_t gpio_inten; /**< Interrupt Enable */ + QM_RW uint32_t gpio_intmask; /**< Interrupt Mask */ + QM_RW uint32_t gpio_inttype_level; /**< Interrupt Type */ + QM_RW uint32_t gpio_int_polarity; /**< Interrupt Polarity */ + QM_RW uint32_t gpio_intstatus; /**< Interrupt Status */ + QM_RW uint32_t gpio_raw_intstatus; /**< Raw Interrupt Status */ + QM_RW uint32_t gpio_debounce; /**< Debounce Enable */ + QM_RW uint32_t gpio_porta_eoi; /**< Clear Interrupt */ + QM_RW uint32_t gpio_ext_porta; /**< Port A External Port */ + QM_RW uint32_t reserved1[3]; + QM_RW uint32_t gpio_ls_sync; /**< Synchronization Level */ + QM_RW uint32_t reserved2; + QM_RW uint32_t gpio_int_bothedge; /**< Interrupt both edge type */ + QM_RW uint32_t reserved3; + QM_RW uint32_t gpio_config_reg2; /**< GPIO Configuration Register 2 */ + QM_RW uint32_t gpio_config_reg1; /**< GPIO Configuration Register 1 */ +} qm_gpio_reg_t; + +/** + * GPIO context type. + * + * Application should not modify the content. + * This structure is only intended to be used by the qm_gpio_save_context and + * qm_gpio_restore_context functions. + */ +typedef struct { + uint32_t gpio_swporta_dr; /**< Port A Data. */ + uint32_t gpio_swporta_ddr; /**< Port A Data Direction. */ + uint32_t gpio_swporta_ctl; /**< Port A Data Source. */ + uint32_t gpio_inten; /**< Interrupt Enable. */ + uint32_t gpio_intmask; /**< Interrupt Mask. */ + uint32_t gpio_inttype_level; /**< Interrupt Type. */ + uint32_t gpio_int_polarity; /**< Interrupt Polarity. */ + uint32_t gpio_debounce; /**< Debounce Enable. */ + uint32_t gpio_ls_sync; /**< Synchronization Level. */ + uint32_t gpio_int_bothedge; /**< Interrupt both edge type. */ +} qm_gpio_context_t; + +#define QM_NUM_GPIO_PINS (32) +#define QM_NUM_AON_GPIO_PINS (6) + +#if (UNIT_TEST) +qm_gpio_reg_t test_gpio_instance; +qm_gpio_reg_t *test_gpio[QM_GPIO_NUM]; + +#define QM_GPIO test_gpio +#else + +/* GPIO register base address */ +#define QM_GPIO_BASE (0xB0000C00) +#define QM_AON_GPIO_BASE (QM_SCSS_CCU_BASE + 0xB00) + +/** GPIO register block */ +extern qm_gpio_reg_t *qm_gpio[QM_GPIO_NUM]; +#define QM_GPIO qm_gpio +#endif + +/** @} */ + +/** + * @name Flash + * @{ + */ + +/** Number of Flash controllers. */ +typedef enum { QM_FLASH_0 = 0, QM_FLASH_1, QM_FLASH_NUM } qm_flash_t; + +/** Flash register map. */ +typedef struct { + QM_RW uint32_t tmg_ctrl; /**< TMG_CTRL. */ + QM_RW uint32_t rom_wr_ctrl; /**< ROM_WR_CTRL. */ + QM_RW uint32_t rom_wr_data; /**< ROM_WR_DATA. */ + QM_RW uint32_t flash_wr_ctrl; /**< FLASH_WR_CTRL. */ + QM_RW uint32_t flash_wr_data; /**< FLASH_WR_DATA. */ + QM_RW uint32_t flash_stts; /**< FLASH_STTS. */ + QM_RW uint32_t ctrl; /**< CTRL. */ + QM_RW uint32_t fpr_rd_cfg[4]; /**< 4 FPR_RD_CFG registers. */ + QM_RW uint32_t + mpr_wr_cfg; /**< Flash Write Protection Control Register. */ + QM_RW uint32_t mpr_vsts; /**< Protection Status Register. */ +} qm_flash_reg_t; + +/** + * Flash context type. + * + * Applications should not modify the content. + * This structure is only intended to be used by the + * qm_flash_save_context and qm_flash_restore_context functions. + */ +typedef struct { + /** Flash Timing Control Register. */ + uint32_t tmg_ctrl; + /** Control Register. */ + uint32_t ctrl; +} qm_flash_context_t; + +#if (UNIT_TEST) +qm_flash_reg_t test_flash_instance; +qm_flash_reg_t *test_flash[QM_FLASH_NUM]; +uint8_t test_flash_page[0x800]; + +#define QM_FLASH test_flash + +#define QM_FLASH_REGION_SYS_1_BASE (test_flash_page) +#define QM_FLASH_REGION_SYS_0_BASE (test_flash_page) +#define QM_FLASH_REGION_OTP_0_BASE (test_flash_page) + +#define QM_FLASH_PAGE_MASK (0xCFF) +#define QM_FLASH_MAX_ADDR (0xFFFFFFFF) +#else + +/* Flash physical address mappings */ + +#define QM_FLASH_REGION_SYS_1_BASE (0x40030000) +#define QM_FLASH_REGION_SYS_0_BASE (0x40000000) +#define QM_FLASH_REGION_OTP_0_BASE (0xFFFFE000) + +#define QM_FLASH_PAGE_MASK (0x3F800) +#define QM_FLASH_MAX_ADDR (0x30000) + +/* Flash controller register base address. */ +#define QM_FLASH_BASE_0 (0xB0100000) +#define QM_FLASH_BASE_1 (0xB0200000) + +/* Flash controller register block. */ +extern qm_flash_reg_t *qm_flash[QM_FLASH_NUM]; +#define QM_FLASH qm_flash + +#endif + +#define QM_FLASH_REGION_DATA_BASE_OFFSET (0x00) +#define QM_FLASH_MAX_WAIT_STATES (0xF) +#define QM_FLASH_MAX_US_COUNT (0x3F) +#define QM_FLASH_MAX_PAGE_NUM \ + (QM_FLASH_MAX_ADDR / (4 * QM_FLASH_PAGE_SIZE_DWORDS)) +#define QM_FLASH_CLK_SLOW BIT(14) +#define QM_FLASH_LVE_MODE BIT(5) + +/* Flash mask to clear timing. */ +#define QM_FLASH_TMG_DEF_MASK (0xFFFFFC00) +/* Flash mask to clear micro seconds. */ +#define QM_FLASH_MICRO_SEC_COUNT_MASK (0x3F) +/* Flash mask to clear wait state. */ +#define QM_FLASH_WAIT_STATE_MASK (0x3C0) +/* Flash wait state offset bit. */ +#define QM_FLASH_WAIT_STATE_OFFSET (6) +/* Flash write disable offset bit. */ +#define QM_FLASH_WRITE_DISABLE_OFFSET (4) +/* Flash write disable value. */ +#define QM_FLASH_WRITE_DISABLE_VAL BIT(4) + +/* Flash page erase request. */ +#define ER_REQ BIT(1) +/* Flash page erase done. */ +#define ER_DONE (1) +/* Flash page write request. */ +#define WR_REQ (1) +/* Flash page write done. */ +#define WR_DONE BIT(1) + +/* Flash write address offset. */ +#define WR_ADDR_OFFSET (2) +/* Flash perform mass erase includes OTP region. */ +#define MASS_ERASE_INFO BIT(6) +/* Flash perform mass erase. */ +#define MASS_ERASE BIT(7) + +#define QM_FLASH_ADDRESS_MASK (0x7FF) +/* Increment by 4 bytes each time, but there is an offset of 2, so 0x10. */ +#define QM_FLASH_ADDR_INC (0x10) + +/* Flash page size in dwords. */ +#define QM_FLASH_PAGE_SIZE_DWORDS (0x200) +/* Flash page size in bytes. */ +#define QM_FLASH_PAGE_SIZE_BYTES (0x800) +/* Flash page size in bits. */ +#define QM_FLASH_PAGE_SIZE_BITS (11) + +/** @} */ + +/** + * @name Flash Protection Region + * @{ + */ + +/** + * FPR register map. + */ +typedef enum { + QM_FPR_0, /**< FPR 0. */ + QM_FPR_1, /**< FPR 1. */ + QM_FPR_2, /**< FPR 2. */ + QM_FPR_3, /**< FPR 3. */ + QM_FPR_NUM +} qm_fpr_id_t; + +/** + * FPR context type. + * + * Applications should not modify the content. + * This structure is only intended to be used by the + * qm_fpr_save_context and qm_fpr_restore_context functions. + */ +typedef struct { + /** Flash Protection Region Read Control Register. */ + uint32_t fpr_rd_cfg[QM_FPR_NUM]; +} qm_fpr_context_t; + +/** @} */ + +/** + * @name Memory Protection Region + * @{ + */ + +/* MPR identifier */ +typedef enum { + QM_MPR_0 = 0, /**< Memory Protection Region 0. */ + QM_MPR_1, /**< Memory Protection Region 1. */ + QM_MPR_2, /**< Memory Protection Region 2. */ + QM_MPR_3, /**< Memory Protection Region 3. */ + QM_MPR_NUM /**< Number of Memory Protection Regions. */ +} qm_mpr_id_t; + +/** Memory Protection Region register map. */ +typedef struct { + QM_RW uint32_t mpr_cfg[4]; /**< MPR CFG */ + QM_RW uint32_t mpr_vdata; /**< MPR_VDATA */ + QM_RW uint32_t mpr_vsts; /**< MPR_VSTS */ +} qm_mpr_reg_t; + +/** + * MPR context type. + * + * Application should not modify the content. + * This structure is only intended to be used by the qm_mpr_save_context and + * qm_mpr_restore_context functions. + */ +typedef struct { + uint32_t mpr_cfg[QM_MPR_NUM]; /**< MPR Configuration Register. */ +} qm_mpr_context_t; + +#if (UNIT_TEST) +qm_mpr_reg_t test_mpr; + +#define QM_MPR ((qm_mpr_reg_t *)(&test_mpr)) + +#else + +#define QM_MPR_BASE (0xB0400000) +#define QM_MPR ((qm_mpr_reg_t *)QM_MPR_BASE) + +#endif + +#define QM_MPR_RD_EN_OFFSET (20) +#define QM_MPR_RD_EN_MASK 0x700000 +#define QM_MPR_WR_EN_OFFSET (24) +#define QM_MPR_WR_EN_MASK 0x7000000 +#define QM_MPR_EN_LOCK_OFFSET (30) +#define QM_MPR_EN_LOCK_MASK 0xC0000000 +#define QM_MPR_UP_BOUND_OFFSET (10) +#define QM_MPR_VSTS_VALID BIT(31) +/** @} */ + +#define QM_OSC0_PD BIT(2) + +#define QM_CCU_EXTERN_DIV_OFFSET (3) +#define QM_CCU_EXT_CLK_DIV_EN BIT(2) + +/** + * @name Peripheral Clock + * @{ + */ + +/** Peripheral clock type. */ +typedef enum { + CLK_PERIPH_REGISTER = BIT(0), /**< Peripheral Clock Gate Enable. */ + CLK_PERIPH_CLK = BIT(1), /**< Peripheral Clock Enable. */ + CLK_PERIPH_I2C_M0 = BIT(2), /**< I2C Master 0 Clock Enable. */ + CLK_PERIPH_I2C_M1 = BIT(3), /**< I2C Master 1 Clock Enable. */ + CLK_PERIPH_SPI_S = BIT(4), /**< SPI Slave Clock Enable. */ + CLK_PERIPH_SPI_M0 = BIT(5), /**< SPI Master 0 Clock Enable. */ + CLK_PERIPH_SPI_M1 = BIT(6), /**< SPI Master 1 Clock Enable. */ + CLK_PERIPH_GPIO_INTERRUPT = BIT(7), /**< GPIO Interrupt Clock Enable. */ + CLK_PERIPH_GPIO_DB = BIT(8), /**< GPIO Debounce Clock Enable. */ + CLK_PERIPH_I2S = BIT(9), /**< I2S Clock Enable. */ + CLK_PERIPH_WDT_REGISTER = BIT(10), /**< Watchdog Clock Enable. */ + CLK_PERIPH_RTC_REGISTER = BIT(11), /**< RTC Clock Gate Enable. */ + CLK_PERIPH_PWM_REGISTER = BIT(12), /**< PWM Clock Gate Enable. */ + CLK_PERIPH_GPIO_REGISTER = BIT(13), /**< GPIO Clock Gate Enable. */ + CLK_PERIPH_SPI_M0_REGISTER = + BIT(14), /**< SPI Master 0 Clock Gate Enable. */ + CLK_PERIPH_SPI_M1_REGISTER = + BIT(15), /**< SPI Master 1 Clock Gate Enable. */ + CLK_PERIPH_SPI_S_REGISTER = + BIT(16), /**< SPI Slave Clock Gate Enable. */ + CLK_PERIPH_UARTA_REGISTER = BIT(17), /**< UARTA Clock Gate Enable. */ + CLK_PERIPH_UARTB_REGISTER = BIT(18), /**< UARTB Clock Gate Enable. */ + CLK_PERIPH_I2C_M0_REGISTER = + BIT(19), /**< I2C Master 0 Clock Gate Enable. */ + CLK_PERIPH_I2C_M1_REGISTER = + BIT(20), /**< I2C Master 1 Clock Gate Enable. */ + CLK_PERIPH_I2S_REGISTER = BIT(21), /**< I2S Clock Gate Enable. */ + CLK_PERIPH_ALL = 0x3FFFFF /**< Quark SE peripherals Mask. */ +} clk_periph_t; + +/* Default mask values */ +#define CLK_EXTERN_DIV_DEF_MASK (0xFFFFFFE3) +#define CLK_SYS_CLK_DIV_DEF_MASK (0xFFFFFC7F) +#define CLK_RTC_DIV_DEF_MASK (0xFFFFFF83) +#define CLK_GPIO_DB_DIV_DEF_MASK (0xFFFFFFE1) +#define CLK_PERIPH_DIV_DEF_MASK (0xFFFFFFF9) + +/** @} */ + +/** + * @name DMA + * @{ + */ + +/** DMA instances. */ +typedef enum { + QM_DMA_0, /**< DMA controller id. */ + QM_DMA_NUM /**< Number of DMA controllers. */ +} qm_dma_t; + +/** DMA channel IDs. */ +typedef enum { + QM_DMA_CHANNEL_0 = 0, /**< DMA channel id for channel 0 */ + QM_DMA_CHANNEL_1, /**< DMA channel id for channel 1 */ + QM_DMA_CHANNEL_2, /**< DMA channel id for channel 2 */ + QM_DMA_CHANNEL_3, /**< DMA channel id for channel 3 */ + QM_DMA_CHANNEL_4, /**< DMA channel id for channel 4 */ + QM_DMA_CHANNEL_5, /**< DMA channel id for channel 5 */ + QM_DMA_CHANNEL_6, /**< DMA channel id for channel 6 */ + QM_DMA_CHANNEL_7, /**< DMA channel id for channel 7 */ + QM_DMA_CHANNEL_NUM /**< Number of DMA channels */ +} qm_dma_channel_id_t; + +/** DMA hardware handshake interfaces. */ +typedef enum { + DMA_HW_IF_UART_A_TX = 0x0, /**< UART_A_TX */ + DMA_HW_IF_UART_A_RX = 0x1, /**< UART_A_RX */ + DMA_HW_IF_UART_B_TX = 0x2, /**< UART_B_TX*/ + DMA_HW_IF_UART_B_RX = 0x3, /**< UART_B_RX */ + DMA_HW_IF_SPI_MASTER_0_TX = 0x4, /**< SPI_Master_0_TX */ + DMA_HW_IF_SPI_MASTER_0_RX = 0x5, /**< SPI_Master_0_RX */ + DMA_HW_IF_SPI_MASTER_1_TX = 0x6, /**< SPI_Master_1_TX */ + DMA_HW_IF_SPI_MASTER_1_RX = 0x7, /**< SPI_Master_1_RX */ + DMA_HW_IF_SPI_SLAVE_TX = 0x8, /**< SPI_Slave_TX */ + DMA_HW_IF_SPI_SLAVE_RX = 0x9, /**< SPI_Slave_RX */ + DMA_HW_IF_I2S_PLAYBACK = 0xa, /**< I2S_Playback channel */ + DMA_HW_IF_I2S_CAPTURE = 0xb, /**< I2S_Capture channel */ + DMA_HW_IF_I2C_MASTER_0_TX = 0xc, /**< I2C_Master_0_TX */ + DMA_HW_IF_I2C_MASTER_0_RX = 0xd, /**< I2C_Master_0_RX */ + DMA_HW_IF_I2C_MASTER_1_TX = 0xe, /**< I2C_Master_1_TX */ + DMA_HW_IF_I2C_MASTER_1_RX = 0xf, /**< I2C_Master_1_RX */ +} qm_dma_handshake_interface_t; + +/** DMA channel register map. */ +typedef struct { + QM_RW uint32_t sar_low; /**< SAR */ + QM_RW uint32_t sar_high; /**< SAR */ + QM_RW uint32_t dar_low; /**< DAR */ + QM_RW uint32_t dar_high; /**< DAR */ + QM_RW uint32_t llp_low; /**< LLP */ + QM_RW uint32_t llp_high; /**< LLP */ + QM_RW uint32_t ctrl_low; /**< CTL */ + QM_RW uint32_t ctrl_high; /**< CTL */ + QM_RW uint32_t src_stat_low; /**< SSTAT */ + QM_RW uint32_t src_stat_high; /**< SSTAT */ + QM_RW uint32_t dst_stat_low; /**< DSTAT */ + QM_RW uint32_t dst_stat_high; /**< DSTAT */ + QM_RW uint32_t src_stat_addr_low; /**< SSTATAR */ + QM_RW uint32_t src_stat_addr_high; /**< SSTATAR */ + QM_RW uint32_t dst_stat_addr_low; /**< DSTATAR */ + QM_RW uint32_t dst_stat_addr_high; /**< DSTATAR */ + QM_RW uint32_t cfg_low; /**< CFG */ + QM_RW uint32_t cfg_high; /**< CFG */ + QM_RW uint32_t src_sg_low; /**< SGR */ + QM_RW uint32_t src_sg_high; /**< SGR */ + QM_RW uint32_t dst_sg_low; /**< DSR */ + QM_RW uint32_t dst_sg_high; /**< DSR */ +} qm_dma_chan_reg_t; + +/* DMA channel control register offsets and masks. */ +#define QM_DMA_CTL_L_INT_EN_MASK BIT(0) +#define QM_DMA_CTL_L_DST_TR_WIDTH_OFFSET (1) +#define QM_DMA_CTL_L_DST_TR_WIDTH_MASK (0x7 << QM_DMA_CTL_L_DST_TR_WIDTH_OFFSET) +#define QM_DMA_CTL_L_SRC_TR_WIDTH_OFFSET (4) +#define QM_DMA_CTL_L_SRC_TR_WIDTH_MASK (0x7 << QM_DMA_CTL_L_SRC_TR_WIDTH_OFFSET) +#define QM_DMA_CTL_L_DINC_OFFSET (7) +#define QM_DMA_CTL_L_DINC_MASK (0x3 << QM_DMA_CTL_L_DINC_OFFSET) +#define QM_DMA_CTL_L_SINC_OFFSET (9) +#define QM_DMA_CTL_L_SINC_MASK (0x3 << QM_DMA_CTL_L_SINC_OFFSET) +#define QM_DMA_CTL_L_DEST_MSIZE_OFFSET (11) +#define QM_DMA_CTL_L_DEST_MSIZE_MASK (0x7 << QM_DMA_CTL_L_DEST_MSIZE_OFFSET) +#define QM_DMA_CTL_L_SRC_MSIZE_OFFSET (14) +#define QM_DMA_CTL_L_SRC_MSIZE_MASK (0x7 << QM_DMA_CTL_L_SRC_MSIZE_OFFSET) +#define QM_DMA_CTL_L_TT_FC_OFFSET (20) +#define QM_DMA_CTL_L_TT_FC_MASK (0x7 << QM_DMA_CTL_L_TT_FC_OFFSET) +#define QM_DMA_CTL_L_LLP_DST_EN_MASK BIT(27) +#define QM_DMA_CTL_L_LLP_SRC_EN_MASK BIT(28) +#define QM_DMA_CTL_H_BLOCK_TS_OFFSET (0) +#define QM_DMA_CTL_H_BLOCK_TS_MASK (0xfff << QM_DMA_CTL_H_BLOCK_TS_OFFSET) +#define QM_DMA_CTL_H_BLOCK_TS_MAX 4095 +#define QM_DMA_CTL_H_BLOCK_TS_MIN 1 + +/* DMA channel config register offsets and masks. */ +#define QM_DMA_CFG_L_CH_SUSP_MASK BIT(8) +#define QM_DMA_CFG_L_FIFO_EMPTY_MASK BIT(9) +#define QM_DMA_CFG_L_HS_SEL_DST_OFFSET 10 +#define QM_DMA_CFG_L_HS_SEL_DST_MASK BIT(QM_DMA_CFG_L_HS_SEL_DST_OFFSET) +#define QM_DMA_CFG_L_HS_SEL_SRC_OFFSET 11 +#define QM_DMA_CFG_L_HS_SEL_SRC_MASK BIT(QM_DMA_CFG_L_HS_SEL_SRC_OFFSET) +#define QM_DMA_CFG_L_DST_HS_POL_OFFSET 18 +#define QM_DMA_CFG_L_DST_HS_POL_MASK BIT(QM_DMA_CFG_L_DST_HS_POL_OFFSET) +#define QM_DMA_CFG_L_SRC_HS_POL_OFFSET 19 +#define QM_DMA_CFG_L_SRC_HS_POL_MASK BIT(QM_DMA_CFG_L_SRC_HS_POL_OFFSET) +#define QM_DMA_CFG_L_RELOAD_SRC_MASK BIT(30) +#define QM_DMA_CFG_L_RELOAD_DST_MASK BIT(31) +#define QM_DMA_CFG_H_DS_UPD_EN_OFFSET (5) +#define QM_DMA_CFG_H_DS_UPD_EN_MASK BIT(QM_DMA_CFG_H_DS_UPD_EN_OFFSET) +#define QM_DMA_CFG_H_SS_UPD_EN_OFFSET (6) +#define QM_DMA_CFG_H_SS_UPD_EN_MASK BIT(QM_DMA_CFG_H_SS_UPD_EN_OFFSET) +#define QM_DMA_CFG_H_SRC_PER_OFFSET (7) +#define QM_DMA_CFG_H_SRC_PER_MASK (0xf << QM_DMA_CFG_H_SRC_PER_OFFSET) +#define QM_DMA_CFG_H_DEST_PER_OFFSET (11) +#define QM_DMA_CFG_H_DEST_PER_MASK (0xf << QM_DMA_CFG_H_DEST_PER_OFFSET) + +/** DMA interrupt register map. */ +typedef struct { + QM_RW uint32_t raw_tfr_low; /**< RawTfr */ + QM_RW uint32_t raw_tfr_high; /**< RawTfr */ + QM_RW uint32_t raw_block_low; /**< RawBlock */ + QM_RW uint32_t raw_block_high; /**< RawBlock */ + QM_RW uint32_t raw_src_trans_low; /**< RawSrcTran */ + QM_RW uint32_t raw_src_trans_high; /**< RawSrcTran */ + QM_RW uint32_t raw_dst_trans_low; /**< RawDstTran */ + QM_RW uint32_t raw_dst_trans_high; /**< RawDstTran */ + QM_RW uint32_t raw_err_low; /**< RawErr */ + QM_RW uint32_t raw_err_high; /**< RawErr */ + QM_RW uint32_t status_tfr_low; /**< StatusTfr */ + QM_RW uint32_t status_tfr_high; /**< StatusTfr */ + QM_RW uint32_t status_block_low; /**< StatusBlock */ + QM_RW uint32_t status_block_high; /**< StatusBlock */ + QM_RW uint32_t status_src_trans_low; /**< StatusSrcTran */ + QM_RW uint32_t status_src_trans_high; /**< StatusSrcTran */ + QM_RW uint32_t status_dst_trans_low; /**< StatusDstTran */ + QM_RW uint32_t status_dst_trans_high; /**< StatusDstTran */ + QM_RW uint32_t status_err_low; /**< StatusErr */ + QM_RW uint32_t status_err_high; /**< StatusErr */ + QM_RW uint32_t mask_tfr_low; /**< MaskTfr */ + QM_RW uint32_t mask_tfr_high; /**< MaskTfr */ + QM_RW uint32_t mask_block_low; /**< MaskBlock */ + QM_RW uint32_t mask_block_high; /**< MaskBlock */ + QM_RW uint32_t mask_src_trans_low; /**< MaskSrcTran */ + QM_RW uint32_t mask_src_trans_high; /**< MaskSrcTran */ + QM_RW uint32_t mask_dst_trans_low; /**< MaskDstTran */ + QM_RW uint32_t mask_dst_trans_high; /**< MaskDstTran */ + QM_RW uint32_t mask_err_low; /**< MaskErr */ + QM_RW uint32_t mask_err_high; /**< MaskErr */ + QM_RW uint32_t clear_tfr_low; /**< ClearTfr */ + QM_RW uint32_t clear_tfr_high; /**< ClearTfr */ + QM_RW uint32_t clear_block_low; /**< ClearBlock */ + QM_RW uint32_t clear_block_high; /**< ClearBlock */ + QM_RW uint32_t clear_src_trans_low; /**< ClearSrcTran */ + QM_RW uint32_t clear_src_trans_high; /**< ClearSrcTran */ + QM_RW uint32_t clear_dst_trans_low; /**< ClearDstTran */ + QM_RW uint32_t clear_dst_trans_high; /**< ClearDstTran */ + QM_RW uint32_t clear_err_low; /**< ClearErr */ + QM_RW uint32_t clear_err_high; /**< ClearErr */ + QM_RW uint32_t status_int_low; /**< StatusInt */ + QM_RW uint32_t status_int_high; /**< StatusInt */ +} qm_dma_int_reg_t; + +/* DMA interrupt status register bits. */ +#define QM_DMA_INT_STATUS_TFR BIT(0) +#define QM_DMA_INT_STATUS_BLOCK BIT(1) +#define QM_DMA_INT_STATUS_ERR BIT(4) + +/** DMA miscellaneous register map. */ +typedef struct { + QM_RW uint32_t cfg_low; /**< DmaCfgReg */ + QM_RW uint32_t cfg_high; /**< DmaCfgReg */ + QM_RW uint32_t chan_en_low; /**< ChEnReg */ + QM_RW uint32_t chan_en_high; /**< ChEnReg */ + QM_RW uint32_t id_low; /**< DmaIdReg */ + QM_RW uint32_t id_high; /**< DmaIdReg */ + QM_RW uint32_t test_low; /**< DmaTestReg */ + QM_RW uint32_t test_high; /**< DmaTestReg */ + QM_RW uint32_t reserved[4]; /**< Reserved */ +} qm_dma_misc_reg_t; + +/* Channel write enable in the misc channel enable register. */ +#define QM_DMA_MISC_CHAN_EN_WE_OFFSET (8) + +/* Controller enable bit in the misc config register. */ +#define QM_DMA_MISC_CFG_DMA_EN BIT(0) + +typedef struct { + QM_RW qm_dma_chan_reg_t chan_reg[8]; /**< Channel Register */ + QM_RW qm_dma_int_reg_t int_reg; /**< Interrupt Register */ + QM_RW uint32_t reserved[12]; /**< Reserved (SW HS) */ + QM_RW qm_dma_misc_reg_t misc_reg; /**< Miscellaneous Register */ +} qm_dma_reg_t; + +/** + * DMA context type. + * + * Applications should not modify the content. + * This structure is only intended to be used by + * the qm_dma_save_context and qm_dma_restore_context functions. + */ +typedef struct { + struct { + uint32_t ctrl_low; /**< Channel Control Lower. */ + uint32_t cfg_low; /**< Channel Configuration Lower. */ + uint32_t cfg_high; /**< Channel Configuration Upper. */ + uint32_t llp_low; /**< Channel Linked List Pointer. */ + } channel[QM_DMA_CHANNEL_NUM]; + uint32_t misc_cfg_low; /**< DMA Configuration. */ +} qm_dma_context_t; + +#if (UNIT_TEST) +qm_dma_reg_t test_dma_instance[QM_DMA_NUM]; +qm_dma_reg_t *test_dma[QM_DMA_NUM]; +#define QM_DMA test_dma +#else +#define QM_DMA_BASE (0xB0700000) +extern qm_dma_reg_t *qm_dma[QM_DMA_NUM]; +#define QM_DMA qm_dma +#endif + +/** @} */ + +/** + * @name USB + * @{ + */ + +#define QM_USB_EP_DIR_IN_MASK (0x80) +#define QM_USB_IN_EP_NUM (6) +#define QM_USB_OUT_EP_NUM (4) +#define QM_USB_MAX_PACKET_SIZE (64) + +/** Number of USB controllers. */ +typedef enum { QM_USB_0 = 0, QM_USB_NUM } qm_usb_t; + +typedef enum { + QM_USB_IN_EP_0 = 0, + QM_USB_IN_EP_1 = 1, + QM_USB_IN_EP_2 = 2, + QM_USB_IN_EP_3 = 3, + QM_USB_IN_EP_4 = 4, + QM_USB_IN_EP_5 = 5, + QM_USB_OUT_EP_0 = 6, + QM_USB_OUT_EP_1 = 7, + QM_USB_OUT_EP_2 = 8, + QM_USB_OUT_EP_3 = 9 +} qm_usb_ep_idx_t; + +/** USB register map. */ + +/** IN Endpoint Registers. */ +typedef struct { + QM_RW uint32_t diepctl; + QM_R uint32_t reserved; + QM_RW uint32_t diepint; + QM_R uint32_t reserved1; + QM_RW uint32_t dieptsiz; + QM_RW uint32_t diepdma; + QM_RW uint32_t dtxfsts; + QM_R uint32_t reserved2; +} qm_usb_in_ep_reg_t; + +/** OUT Endpoint Registers. */ +typedef struct { + QM_RW uint32_t doepctl; + QM_R uint32_t reserved; + QM_RW uint32_t doepint; + QM_R uint32_t reserved1; + QM_RW uint32_t doeptsiz; + QM_RW uint32_t doepdma; + QM_R uint32_t reserved2[2]; +} qm_usb_out_ep_reg_t; + +/** + * USB Register block type. + */ +typedef struct { + QM_RW uint32_t gotgctl; /**< OTG Control. */ + QM_RW uint32_t gotgint; /**< OTG Interrupt. */ + QM_RW uint32_t gahbcfg; /**< AHB Configuration. */ + QM_RW uint32_t gusbcfg; /**< USB Configuration. */ + QM_RW uint32_t grstctl; /**< Reset Register. */ + QM_RW uint32_t gintsts; /**< Interrupt Status. */ + QM_RW uint32_t gintmsk; /**< Interrupt Mask. */ + QM_R uint32_t grxstsr; /**< Receive Status Read/Pop. */ + QM_R uint32_t grxstsp; /**< Receive Status Read/Pop. */ + QM_R uint32_t grxfsiz; /**< Receive FIFO Size. */ + QM_R uint32_t gnptxfsiz; /**< Non-periodic Transmit FIFO Size. */ + QM_R uint32_t reserved[5]; + QM_R uint32_t gsnpsid; /**< Synopsys ID. */ + QM_R uint32_t ghwcfg1; /**< HW config - Endpoint direction. */ + QM_R uint32_t ghwcfg2; /**< HW config 2. */ + QM_R uint32_t ghwcfg3; /**< HW config 3. */ + QM_R uint32_t ghwcfg4; /**< HW config 4. */ + QM_RW uint32_t gdfifocfg; /**< Global DFIFO Configuration. */ + QM_R uint32_t reserved1[43]; + QM_RW uint32_t dieptxf1; + QM_RW uint32_t dieptxf2; + QM_RW uint32_t dieptxf3; + QM_RW uint32_t dieptxf4; + QM_RW uint32_t dieptxf5; + QM_R uint32_t reserved2[442]; + QM_RW uint32_t dcfg; /**< Device config. */ + QM_RW uint32_t dctl; /**< Device control. */ + QM_RW uint32_t dsts; /**< Device Status. */ + QM_R uint32_t reserved3; + QM_RW uint32_t diepmsk; /**< IN EP Common Interrupt Mask. */ + QM_RW uint32_t doepmsk; /**< OUT EP Common Interrupt Mask. */ + QM_R uint32_t daint; /**< Device Interrupt Register. */ + QM_RW uint32_t daintmsk; /**< Device Interrupt Mask Register. */ + QM_R uint32_t reserved4[2]; + QM_RW uint32_t dvbusdis; /**< VBUS discharge time register. */ + QM_RW uint32_t dvbuspulse; /**< Device VBUS discharge time. */ + QM_RW uint32_t dthrctl; /**< Device Threshold Ctrl. */ + QM_RW uint32_t diepempmsk; /**< IN EP FIFO Empty Intr Mask. */ + QM_R uint32_t reserved5[50]; + qm_usb_in_ep_reg_t in_ep_reg[QM_USB_IN_EP_NUM]; + QM_R uint32_t reserved6[80]; + qm_usb_out_ep_reg_t out_ep_reg[QM_USB_OUT_EP_NUM]; +} qm_usb_reg_t; + +#if (UNIT_TEST) +qm_usb_reg_t test_usb; +#define QM_USB ((qm_usb_reg_t *)(&test_usb)) +#else +#define QM_USB_0_BASE (0xB0500000) +/* USB controller base address */ +#define QM_USB ((qm_usb_reg_t *)QM_USB_0_BASE) +#endif + +/* USB PLL enable bit */ +#define QM_USB_PLL_PDLD BIT(0) +/* USB PLL has locked when this bit is 1 */ +#define QM_USB_PLL_LOCK BIT(14) +/* Default values to setup the USB PLL */ +#define QM_USB_PLL_CFG0_DEFAULT (0x00001904) + +/* USB PLL register */ +#if (UNIT_TEST) +uint32_t test_usb_pll; +#define QM_USB_PLL_CFG0 (test_usb_pll) +#else +#define QM_USB_PLL_CFG0 (REG_VAL(0xB0800014)) +#endif + +/* USB clock enable bit */ +#define QM_CCU_USB_CLK_EN BIT(1) + +/** @} */ + +/** + * @name Hardware Fixes + * @{ + */ + +/* Refer to "HARDWARE_ISSUES.rst" for fix description. */ +#define FIX_1 (1) + +/** @} */ + +/** + * @name Versioning + * @{ + */ + +#if (UNIT_TEST) +uint32_t test_rom_version; +#define ROM_VERSION_ADDRESS &test_rom_version; +#else +#define ROM_VERSION_ADDRESS (0xFFFFFFEC); +#endif + +/** @} */ + +/** @} */ + +#endif /* __REGISTERS_H__ */ diff --git a/libraries/CuriePowerManagement/src/qmsi/ss_power_states.h b/libraries/CuriePowerManagement/src/qmsi/ss_power_states.h new file mode 100644 index 00000000..f4dd80b9 --- /dev/null +++ b/libraries/CuriePowerManagement/src/qmsi/ss_power_states.h @@ -0,0 +1,295 @@ +/* + * Copyright (c) 2016, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of the Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INTEL CORPORATION OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __QM_SS_POWER_STATES_H__ +#define __QM_SS_POWER_STATES_H__ + +#include "qm_sensor_regs.h" + +/** + * SS Power mode control for Quark SE Microcontrollers. + * + * @defgroup groupSSPower SS Power states + * @{ + */ + +/** + * Sensor Subsystem SS1 Timers mode type. + */ +typedef enum { + SS_POWER_CPU_SS1_TIMER_OFF = 0, /**< Disable SS Timers in SS1. */ + SS_POWER_CPU_SS1_TIMER_ON /**< Keep SS Timers enabled in SS1. */ +} ss_power_cpu_ss1_mode_t; + +/** + * Enable LPSS state entry. + * + * Put the SoC into LPSS on next C2/C2LP and SS2 state combination.
+ * This function needs to be called on the Sensor Core to + * Clock Gate ADC, I2C0, I2C1, SPI0 and SPI1 sensor peripherals.
+ * Clock Gating sensor peripherals is a requirement to enter LPSS state.
+ * After LPSS, ss_power_soc_lpss_disable needs to be called to + * restore clock gating.
+ * + * This needs to be called before any transition to C2/C2LP and SS2 + * in order to enter LPSS.
+ * SoC Hybrid Clock is gated in this state.
+ * Core Well Clocks are gated.
+ * RTC is the only clock running. + * + * Possible SoC wake events are: + * - Low Power Comparator Interrupt + * - AON GPIO Interrupt + * - AON Timer Interrupt + * - RTC Interrupt + */ +//void ss_power_soc_lpss_enable(void); + +/** + * Enter SoC sleep state and restore after wake up. + * + * Put the ARC core into sleep state until next SoC wake event + * and continue execution after wake up where the application stopped. + * + * If the library is built with ENABLE_RESTORE_CONTEXT=1, then this function + * will use the arc_restore_addr to save restore trap address which brings back + * the ARC CPU to the point where this function was called. + * This means that applications should refrain from using them. + * + * This function calls qm_ss_save_context and qm_ss_restore_context + * in order to restore execution where it stopped. + * All power management transitions are done by power_soc_sleep(). + */ +//void ss_power_soc_sleep_restore(void); +/** + * Enter SoC sleep state and restore after wake up. + * + * Put the ARC core into sleep state until next SoC wake event + * and continue execution after wake up where the application stopped. + * + * If the library is built with ENABLE_RESTORE_CONTEXT=1, then this function + * will use the arc_restore_addr to save restore trap address which brings back + * the ARC CPU to the point where this function was called. + * This means that applications should refrain from using them. + * + * This function calls qm_ss_save_context and qm_ss_restore_context + * in order to restore execution where it stopped. + * All power management transitions are done by power_soc_deep_sleep(). + */ +//void ss_power_soc_deep_sleep_restore(void); + +/** + * Save context, enter ARC SS1 power save state and restore after wake up. + * + * This routine is same as ss_power_soc_sleep_restore(), just instead of + * going to sleep it will go to SS1 power save state. + * Note: this function has a while(1) which will spin until we enter + * (and exit) sleep and the power state change will be managed by the other + * core. + */ +//void ss_power_sleep_wait(void); + +/** + * Enable the SENSOR startup restore flag. + */ +//void power_soc_set_ss_restore_flag(void); + +/** + * Disable LPSS state entry. + * + * Clear LPSS enable flag.
+ * Disable Clock Gating of ADC, I2C0, I2C1, SPI0 and SPI1 sensor + * peripherals.
+ * This will prevent entry in LPSS when cores are in C2/C2LP and SS2 states. + */ +//void ss_power_soc_lpss_disable(void); + +/** + * Enter Sensor SS1 state. + * + * Put the Sensor Subsystem into SS1.
+ * Processor Clock is gated in this state. + * + * A wake event causes the Sensor Subsystem to transition to SS0.
+ * A wake event is a sensor subsystem interrupt. + * + * According to the mode selected, Sensor Subsystem Timers can be disabled. + * + * @param[in] mode Mode selection for SS1 state. + */ +//void ss_power_cpu_ss1(const ss_power_cpu_ss1_mode_t mode); + +/** + * Enter Sensor SS2 state or SoC LPSS state. + * + * Put the Sensor Subsystem into SS2.
+ * Sensor Complex Clock is gated in this state.
+ * Sensor Peripherals are gated in this state.
+ * + * This enables entry in LPSS if: + * - Sensor Subsystem is in SS2 + * - Lakemont is in C2 or C2LP + * - LPSS entry is enabled + * + * A wake event causes the Sensor Subsystem to transition to SS0.
+ * There are two kinds of wake event depending on the Sensor Subsystem + * and SoC state: + * - SS2: a wake event is a Sensor Subsystem interrupt + * - LPSS: a wake event is a Sensor Subsystem interrupt or a Lakemont interrupt + * + * LPSS wake events apply if LPSS is entered. + * If Host wakes the SoC from LPSS, + * Sensor also transitions back to SS0. + */ +//void ss_power_cpu_ss2(void); + +/** + * Save resume vector. + * + * Saves the resume vector in the global "arc_restore_addr" location. + * The ARC will jump to the resume vector once a wake up event is + * triggered and x86 resumes the ARC. + */ +#define qm_ss_set_resume_vector(_restore_label, arc_restore_addr) \ + __asm__ __volatile__("mov r0, @arc_restore_addr\n\t" \ + "st " #_restore_label ", [r0]\n\t" \ + : /* Output operands. */ \ + : /* Input operands. */ \ + : /* Clobbered registers list. */ \ + "r0") + +/* Save execution context. + * + * This routine saves CPU registers onto cpu_context, + * array. + * + */ +#define qm_ss_save_context(cpu_context) \ + __asm__ __volatile__("push_s r0\n\t" \ + "mov r0, @cpu_context\n\t" \ + "st r1, [r0, 4]\n\t" \ + "st r2, [r0, 8]\n\t" \ + "st r3, [r0, 12]\n\t" \ + "st r4, [r0, 16]\n\t" \ + "st r5, [r0, 20]\n\t" \ + "st r6, [r0, 24]\n\t" \ + "st r7, [r0, 28]\n\t" \ + "st r8, [r0, 32]\n\t" \ + "st r9, [r0, 36]\n\t" \ + "st r10, [r0, 40]\n\t" \ + "st r11, [r0, 44]\n\t" \ + "st r12, [r0, 48]\n\t" \ + "st r13, [r0, 52]\n\t" \ + "st r14, [r0, 56]\n\t" \ + "st r15, [r0, 60]\n\t" \ + "st r16, [r0, 64]\n\t" \ + "st r17, [r0, 68]\n\t" \ + "st r18, [r0, 72]\n\t" \ + "st r19, [r0, 76]\n\t" \ + "st r20, [r0, 80]\n\t" \ + "st r21, [r0, 84]\n\t" \ + "st r22, [r0, 88]\n\t" \ + "st r23, [r0, 92]\n\t" \ + "st r24, [r0, 96]\n\t" \ + "st r25, [r0, 100]\n\t" \ + "st r26, [r0, 104]\n\t" \ + "st r27, [r0, 108]\n\t" \ + "st r28, [r0, 112]\n\t" \ + "st r29, [r0, 116]\n\t" \ + "st r30, [r0, 120]\n\t" \ + "st r31, [r0, 124]\n\t" \ + "lr r31, [ic_ctrl]\n\t" \ + "st r31, [r0, 128]\n\t" \ + : /* Output operands. */ \ + : /* Input operands. */ \ + [ic_ctrl] "i"(QM_SS_AUX_IC_CTRL) \ + : /* Clobbered registers list. */ \ + "r0") + +/* Restore execution context. + * + * This routine restores CPU registers from cpu_context, + * array. + * + * This routine is called from the bootloader to restore the execution context + * from before entering in sleep mode. + */ +#define qm_ss_restore_context(_restore_label, cpu_context) \ + __asm__ __volatile__( \ + #_restore_label \ + ":\n\t" \ + "mov r0, @cpu_context\n\t" \ + "ld r1, [r0, 4]\n\t" \ + "ld r2, [r0, 8]\n\t" \ + "ld r3, [r0, 12]\n\t" \ + "ld r4, [r0, 16]\n\t" \ + "ld r5, [r0, 20]\n\t" \ + "ld r6, [r0, 24]\n\t" \ + "ld r7, [r0, 28]\n\t" \ + "ld r8, [r0, 32]\n\t" \ + "ld r9, [r0, 36]\n\t" \ + "ld r10, [r0, 40]\n\t" \ + "ld r11, [r0, 44]\n\t" \ + "ld r12, [r0, 48]\n\t" \ + "ld r13, [r0, 52]\n\t" \ + "ld r14, [r0, 56]\n\t" \ + "ld r15, [r0, 60]\n\t" \ + "ld r16, [r0, 64]\n\t" \ + "ld r17, [r0, 68]\n\t" \ + "ld r18, [r0, 72]\n\t" \ + "ld r19, [r0, 76]\n\t" \ + "ld r20, [r0, 80]\n\t" \ + "ld r21, [r0, 84]\n\t" \ + "ld r22, [r0, 88]\n\t" \ + "ld r23, [r0, 92]\n\t" \ + "ld r24, [r0, 96]\n\t" \ + "ld r25, [r0, 100]\n\t" \ + "ld r26, [r0, 104]\n\t" \ + "ld r27, [r0, 108]\n\t" \ + "ld r28, [r0, 112]\n\t" \ + "ld r29, [r0, 116]\n\t" \ + "ld r30, [r0, 120]\n\t" \ + "ld r31, [r0, 124]\n\t" \ + "ld r0, [r0, 128]\n\t" \ + "sr r0, [ic_ctrl]\n\t" \ + "pop_s r0\n\t" \ + "sr 0,[0x101]\n\t" /* Setup Sensor Subsystem TimeStamp Counter */ \ + "sr 0,[0x100]\n\t" \ + "sr -1,[0x102]\n\t" \ + : /* Output operands. */ \ + : /* Input operands. */ \ + [ic_ctrl] "i"(QM_SS_AUX_IC_CTRL) \ + : /* Clobbered registers list. */ \ + "r0") + +/** + * @} + */ + +#endif /* __QM_SS_POWER_STATES_H__ */ diff --git a/libraries/CuriePowerManagement/src/wsrc.c b/libraries/CuriePowerManagement/src/wsrc.c new file mode 100644 index 00000000..abc8c1f2 --- /dev/null +++ b/libraries/CuriePowerManagement/src/wsrc.c @@ -0,0 +1,172 @@ +#include +#include "dccm/dccm_alloc.h" +#include "wsrc.h" +#include "string.h" + +#ifdef __cplusplus + extern "C" { +#endif + +static uint8_t new_index = 0; +static uint8_t old_index = 0; +static uint8_t num_active = 0; +static wsrc_active_t wsrc_active[MAX_ATTACHABLE]; + +wsrc_entry_t wsrc_table[NUM_WAKEUP] = { + { .irq = IRQ_GPIO1_INTR, .status = 0 }, /* I00 */ + { .irq = IRQ_GPIO1_INTR, .status = 0 }, /* I01 */ + { .irq = IRQ_GPIO_INTR, .status = 0 }, /* I02 */ + { .irq = IRQ_GPIO1_INTR, .status = 0 }, /* I03 */ + { .irq = IRQ_GPIO_INTR, .status = 0 }, /* I04 */ + { .irq = IRQ_GPIO1_INTR, .status = 0 }, /* I05 */ + { .irq = IRQ_GPIO1_INTR, .status = 0 }, /* I06 */ + { .irq = IRQ_GPIO_INTR, .status = 0 }, /* I07 */ + { .irq = IRQ_GPIO_INTR, .status = 0 }, /* I08 */ + { .irq = IRQ_GPIO1_INTR, .status = 0 }, /* I09 */ + { .irq = IRQ_GPIO_INTR, .status = 0 }, /* I010 */ + { .irq = IRQ_GPIO_INTR, .status = 0 }, /* I011 */ + { .irq = IRQ_GPIO_INTR, .status = 0 }, /* I012 */ + { .irq = IRQ_GPIO_INTR, .status = 0 }, /* I013 */ + { .irq = IRQ_GPIO0_INTR, .status = 0 }, /* I014 */ + { .irq = IRQ_GPIO0_INTR, .status = 0 }, /* I015 */ + { .irq = IRQ_GPIO0_INTR, .status = 0 }, /* I016 */ + { .irq = IRQ_GPIO0_INTR, .status = 0 }, /* I017 */ + { .irq = IRQ_GPIO0_INTR, .status = 0 }, /* I018 */ + { .irq = IRQ_GPIO0_INTR, .status = 0 }, /* I019 */ + { .irq = IRQ_GPIO0_INTR, .status = 0 }, /* I020 */ + { .irq = IRQ_GPIO_INTR, .status = 0 }, /* I021 */ + { .irq = IRQ_GPIO_INTR, .status = 0 }, /* I022 */ + { .irq = IRQ_GPIO_INTR, .status = 0 }, /* I023 */ + { .irq = IRQ_GPIO_INTR, .status = 0 }, /* I024 */ + { .irq = IRQ_GPIO_INTR, .status = 0 }, /* I025 */ + { .irq = IRQ_ALWAYS_ON_GPIO, .status = 1 }, /* IO26 AON_GPIO0*/ + { .irq = IRQ_ALWAYS_ON_GPIO, .status = 1 }, /* IO27 AON_GPIO1*/ + { .irq = IRQ_ALWAYS_ON_GPIO, .status = 1 }, /* IO28 AON_GPIO2*/ + { .irq = IRQ_ALWAYS_ON_GPIO, .status = 1 }, /* IO29 AON_GPIO3*/ + { .irq = IRQ_ALWAYS_ON_GPIO, .status = 1 }, /* BLE_WAKEUP */ + { .irq = IRQ_ALWAYS_ON_GPIO, .status = 1 }, /* IMU_WAKEUP */ + { .irq = IRQ_I2S_INTR, .status = 0 }, /* I2S_WAKEUP */ + { .irq = IRQ_I2C0_RX_AVAIL, .status = 0 }, /* WIRE_RX_WAKEUP */ + { .irq = IRQ_USB_INTR, .status = 0 }, /* SERIAL_WAKEUP */ + { .irq = IRQ_UART1_INTR, .status = 0 }, /* SERIAL1_WAKEUP */ + { .irq = IRQ_ADC_IRQ, .status = 0 }, /* ADC_WAKEUP */ + { .irq = IRQ_ALWAYS_ON_TMR, .status = 0 }, /* AON_TIMER_WAKEUP */ + { .irq = IRQ_TIMER1, .status = 0 }, /* TIMER1_WAKEUP */ + { .irq = IRQ_PWM_TIMER_INTR, .status = 0 }, /* PWM_TIMER_WAKEUP */ + { .irq = IRQ_SPI1_RX_AVAIL, .status = 0 }, /* SPI_RX_WAKEUP */ + { .irq = IRQ_SPI0_RX_AVAIL, .status = 0 }, /* SPI1_RX_WAKEUP */ + { .irq = IRQ_RTC_INTR, .status = 1 }, /* RTC_WAKEUP */ + { .irq = IRQ_WDOG_INTR, .status = 0 }, /* WATCHDOG_WAKEUP */ + { .irq = IRQ_MAILBOXES_INTR, .status = 0 }, /* MAILBOX_WAKEUP */ + { .irq = IRQ_COMPARATORS_INTR, .status = 1},/* COMPARATORS_WAKEUP*/ +}; + +static void wsrc_set_active (uint8_t index, void (*cb)(void)) +{ + if (num_active < MAX_ATTACHABLE) { + wsrc_active[num_active].cb = (uint32_t)cb; + wsrc_active[num_active++].index = index; + ++new_index; + } +} + +static void wsrc_clear_active (uint8_t index) +{ + unsigned int i, j; + + for (i = 0; i < num_active; i++) { + + /* Look for this value in wsrc_active ... */ + if (wsrc_active[i].index == index) { + + /* ... and shift over all remaining values that follow it */ + for (j = i + 1; j < num_active; j++) { + wsrc_active[j - 1] = wsrc_active[j]; + } + --num_active; + --new_index; + break; + } + } +} + +int wsrc_getIndex(int id) +{ + for (int i = 0; i < num_active; i++) { + if (wsrc_active[i].index == id){ + return i; + } + } + return 0; +} + +int wsrc_get_newest_attached (wsrc_t *wsrc) +{ + uint8_t i; + + if(num_active == 0){ + return 0; + } + + if (new_index == 0 || !wsrc) { + new_index = num_active; + return 0; + } + + i = wsrc_active[--new_index].index; + + wsrc->irq = wsrc_table[i].irq; + wsrc->callback = wsrc_active[new_index].cb; + wsrc->status = wsrc_table[i].status; + wsrc->id = i; + + return 1; +} + +int wsrc_get_oldest_attached (wsrc_t *wsrc) +{ + uint8_t i; + + if (old_index == num_active || !wsrc) { + old_index = 0; + return 0; + } + + i = wsrc_active[old_index].index; + + wsrc->irq = wsrc_table[i].irq; + wsrc->callback = wsrc_active[old_index++].cb; + wsrc->status = wsrc_table[i].status; + wsrc->id = i; + + return 1; +} + +void wsrc_register_gpio (uint32_t pin, void (*callback)(void), uint32_t mode) +{ + /* Set interrupt mode */ + wsrc_set_gpio_mode(SRC_STAT(pin), mode); + + if (!wsrc_wakeup(SRC_STAT(pin))) { + wsrc_set_active(pin, callback); + wsrc_set_wakeup(SRC_STAT(pin)); + } +} + +void wsrc_register_id (int id, void (*callback)(void)) +{ + if (!wsrc_wakeup(SRC_STAT(id))) { + wsrc_set_active(id, callback); + wsrc_set_wakeup(SRC_STAT(id)); + } +} + +void wsrc_unregister (int id) +{ + wsrc_clear_active(id); + wsrc_clear_wakeup(SRC_STAT(id)); +} + +#ifdef __cplusplus +} +#endif diff --git a/libraries/CuriePowerManagement/src/wsrc.h b/libraries/CuriePowerManagement/src/wsrc.h new file mode 100644 index 00000000..d4e0fcb5 --- /dev/null +++ b/libraries/CuriePowerManagement/src/wsrc.h @@ -0,0 +1,113 @@ +#ifndef WSRC_H_ +#define WSRC_H_ + +#ifdef __cplusplus + extern "C" { +#endif + +#include "board.h" +#include "pins_arduino.h" + +#define GPIO_START 0 +#define GPIO_END (NUM_DIGITAL_PINS - 6) + +#define GPIO_MODE_MASK 0x38 +#define SRC_STAT(src) (wsrc_table[src].status) + +#define MAX_ATTACHABLE 10 +#define wsrc_cansleep(stat) (stat & 1) +#define wsrc_working(stat) (stat & 2) +#define wsrc_wakeup(stat) (stat & 4) +#define wsrc_set_cansleep(stat) (stat |= 1) +#define wsrc_clear_cansleep(stat) (stat &= ~1) +#define wsrc_set_working(stat) (stat |= 2) +#define wsrc_clear_working(stat) (stat &= ~2) +#define wsrc_set_wakeup(stat) (stat |= 4) +#define wsrc_clear_wakeup(stat) (stat &= ~4) +#define wsrc_gpio_mode(stat) ((stat & GPIO_MODE_MASK) >> 3) +#define wsrc_set_gpio_mode(stat, mode)({\ + stat &= ~GPIO_MODE_MASK;\ + stat |= (mode << 3);\ + }); + +enum { + /* TODO: not all of these can actually be used as wakeup sources. + * find out which ones they are. */ + AON_GPIO0 = GPIO_END , + AON_GPIO1 = GPIO_END + 1, + AON_GPIO2 = GPIO_END + 2, + AON_GPIO3 = GPIO_END + 3 , + IMU_WAKEUP = GPIO_END + 4, + BLE_WAKEUP = GPIO_END + 5, + I2S_WAKEUP = GPIO_END + 6, + WIRE_RX_WAKEUP = GPIO_END + 7, + SERIAL_WAKEUP = GPIO_END + 8, + SERIAL1_WAKEUP = GPIO_END + 9, + ADC_WAKEUP = GPIO_END + 10, + AON_TIMER_WAKEUP = GPIO_END + 11, + TIMER1_WAKEUP = GPIO_END + 12, + PWM_TIMER_WAKEUP = GPIO_END + 13, + SPI_RX_WAKEUP = GPIO_END + 14, + SPI1_RX_WAKEUP = GPIO_END + 15, + RTC_WAKEUP = GPIO_END + 16, + WATCHDOG_WAKEUP = GPIO_END + 17, + MAILBOX_WAKEUP = GPIO_END + 18, + COMPARATORS_WAKEUP = GPIO_END + 19, + NUM_WAKEUP = GPIO_END + 20 +}; + +struct wsrc_entry { + /* IRQ associated with this wakeup source */ + uint8_t irq; + /* Status flags; + * + * Bit 0: sleep: indicates if this wakeup source can be used in + * deeper sleep modes (if unset, can only be used in + * doze mode) + * Bit 1: working: indicates this entry is waiting for something + * to complete in interrupt context (e.g. + * interrupt-based UART transfer in progress) + * Bit 2: wakeup: indicates this entry is to be used as a wakeup + * source + * Bits 3-5: GPIO mode: 0 - LOW + * 1 - HIGH + * 2 - CHANGE + * 3 - FALLING + * 4 - RISING + * + * Bits 6-7: Reserved. */ + volatile uint8_t status; +} __attribute__((packed)); + +struct wsrc_active { + uint32_t cb; + uint8_t index; +} __attribute__((packed)); + +struct wsrc { + uint32_t callback; + uint8_t status; + uint8_t irq; + uint8_t id; +}; + +typedef struct wsrc wsrc_t; +typedef struct wsrc_entry wsrc_entry_t; +typedef struct wsrc_active wsrc_active_t; + +extern wsrc_entry_t wsrc_table[NUM_WAKEUP]; + +void wsrc_table_init (void); +void wsrc_register_gpio (uint32_t pin, void (*callback)(void), uint32_t mode); +void wsrc_register_id (int id, void (*callback)(void)); +void wsrc_unregister (int id); +int wsrc_getIndex(int id); + +int wsrc_get_newest_attached (wsrc_t *wsrc); +int wsrc_get_oldest_attached (wsrc_t *wsrc); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libraries/CurieSerialFlash/CurieSerialFlash.h b/libraries/CurieSerialFlash/CurieSerialFlash.h new file mode 100644 index 00000000..47ce73d9 --- /dev/null +++ b/libraries/CurieSerialFlash/CurieSerialFlash.h @@ -0,0 +1,4 @@ +#if !defined (__arc__) +#error These examples only work with onboard SPI flash on Arduino/Genuino 101 board +#endif +#include "SerialFlash.h" diff --git a/libraries/SerialFlash/examples/CopyFromSerial/CopyFromSerial.ino b/libraries/CurieSerialFlash/examples/CopyFromSerial/CopyFromSerial.ino similarity index 96% rename from libraries/SerialFlash/examples/CopyFromSerial/CopyFromSerial.ino rename to libraries/CurieSerialFlash/examples/CopyFromSerial/CopyFromSerial.ino index 6d1af440..68a30af3 100644 --- a/libraries/SerialFlash/examples/CopyFromSerial/CopyFromSerial.ino +++ b/libraries/CurieSerialFlash/examples/CopyFromSerial/CopyFromSerial.ino @@ -57,9 +57,12 @@ * Enjoy! * * SerialFlash library API: https://github.com/PaulStoffregen/SerialFlash + * + * This example depends on Paul Stoffregen's SerialFlash library. + * Download at https://github.com/PaulStoffregen/SerialFlash. */ -#include +#include #include //Buffer sizes @@ -79,15 +82,12 @@ #define BYTE_ESCAPE 0x7d #define BYTE_SEPARATOR 0x7c -#define CSPIN 21 - void setup(){ - Serial.begin(9600); // initialize Serial communication - while(!Serial) ; // wait for serial port to connect. + Serial.begin(9600); //Teensy serial is always at full USB speed and buffered... the baud rate here is required but ignored pinMode(13, OUTPUT); - SerialFlash.begin(CSPIN); + SerialFlash.begin(ONBOARD_FLASH_SPI_PORT, ONBOARD_FLASH_CS_PIN); //We start by formatting the flash... uint8_t id[5]; diff --git a/libraries/SerialFlash/examples/EraseEverything/EraseEverything.ino b/libraries/CurieSerialFlash/examples/EraseEverything/EraseEverything.ino similarity index 90% rename from libraries/SerialFlash/examples/EraseEverything/EraseEverything.ino rename to libraries/CurieSerialFlash/examples/EraseEverything/EraseEverything.ino index d3b3f4d7..43425324 100644 --- a/libraries/SerialFlash/examples/EraseEverything/EraseEverything.ino +++ b/libraries/CurieSerialFlash/examples/EraseEverything/EraseEverything.ino @@ -1,10 +1,9 @@ -//SerialFlash library API: https://github.com/PaulStoffregen/SerialFlash +// This example depends on Paul Stoffregen's SerialFlash library +// Download at https://github.com/PaulStoffregen/SerialFlash -#include +#include #include -const int FlashChipSelect = 21; // digital pin for flash chip CS pin - SerialFlashFile file; const unsigned long testIncrement = 4096; @@ -26,7 +25,7 @@ void setup() { while (!Serial && (millis() - startMillis < 10000)) ; delay(100); - SerialFlash.begin(FlashChipSelect); + SerialFlash.begin(ONBOARD_FLASH_SPI_PORT, ONBOARD_FLASH_CS_PIN); unsigned char id[5]; SerialFlash.readID(id); unsigned long size = SerialFlash.capacity(id); diff --git a/libraries/SerialFlash/examples/FileWrite/FileWrite.ino b/libraries/CurieSerialFlash/examples/FileWrite/FileWrite.ino similarity index 81% rename from libraries/SerialFlash/examples/FileWrite/FileWrite.ino rename to libraries/CurieSerialFlash/examples/FileWrite/FileWrite.ino index dbeb438a..e9f5ab9a 100755 --- a/libraries/SerialFlash/examples/FileWrite/FileWrite.ino +++ b/libraries/CurieSerialFlash/examples/FileWrite/FileWrite.ino @@ -1,6 +1,7 @@ -//SerialFlash library API: https://github.com/PaulStoffregen/SerialFlash +// This example depends on Paul Stoffregen's SerialFlash library +// Download at https://github.com/PaulStoffregen/SerialFlash -#include +#include #include #define FSIZE 256 @@ -8,8 +9,6 @@ const char *filename = "myfile.txt"; const char *contents = "0123456789ABCDEF"; -const int FlashChipSelect = 21; // digital pin for flash chip CS pin - void setup() { Serial.begin(9600); @@ -18,7 +17,7 @@ void setup() { delay(100); // Init. SPI Flash chip - if (!SerialFlash.begin(FlashChipSelect)) { + if (!SerialFlash.begin(ONBOARD_FLASH_SPI_PORT, ONBOARD_FLASH_CS_PIN)) { Serial.println("Unable to access SPI Flash chip"); } @@ -47,4 +46,4 @@ bool create_if_not_exists (const char *filename) { } void loop() { -} +} diff --git a/libraries/SerialFlash/examples/ListFiles/ListFiles.ino b/libraries/CurieSerialFlash/examples/ListFiles/ListFiles.ino similarity index 84% rename from libraries/SerialFlash/examples/ListFiles/ListFiles.ino rename to libraries/CurieSerialFlash/examples/ListFiles/ListFiles.ino index bc15b89b..6dfda8b7 100644 --- a/libraries/SerialFlash/examples/ListFiles/ListFiles.ino +++ b/libraries/CurieSerialFlash/examples/ListFiles/ListFiles.ino @@ -1,10 +1,9 @@ -// SerialFlash library API: https://github.com/PaulStoffregen/SerialFlash +// This example depends on Paul Stoffregen's SerialFlash library +// Download at https://github.com/PaulStoffregen/SerialFlash -#include +#include #include -const int FlashChipSelect = 21; // digital pin for flash chip CS pin - void setup() { //uncomment these if using Teensy audio shield //SPI.setSCK(14); // Audio shield has SCK on pin 14 @@ -22,7 +21,7 @@ void setup() { delay(100); Serial.println("All Files on SPI Flash chip:"); - if (!SerialFlash.begin(FlashChipSelect)) { + if (!SerialFlash.begin(ONBOARD_FLASH_SPI_PORT, ONBOARD_FLASH_CS_PIN)) { error("Unable to access SPI Flash chip"); } diff --git a/libraries/SerialFlash/examples/RawHardwareTest/RawHardwareTest.ino b/libraries/CurieSerialFlash/examples/RawHardwareTest/RawHardwareTest.ino similarity index 98% rename from libraries/SerialFlash/examples/RawHardwareTest/RawHardwareTest.ino rename to libraries/CurieSerialFlash/examples/RawHardwareTest/RawHardwareTest.ino index 74afa10a..a124010f 100644 --- a/libraries/SerialFlash/examples/RawHardwareTest/RawHardwareTest.ino +++ b/libraries/CurieSerialFlash/examples/RawHardwareTest/RawHardwareTest.ino @@ -18,13 +18,13 @@ // https://github.com/PaulStoffregen/SerialFlash/issues // You MUST post the complete output of this program, and // the exact part number and manufacturer of the chip. +// +// This example depends on Paul Stoffregen's SerialFlash library +// Download at https://github.com/PaulStoffregen/SerialFlash - -#include +#include #include -const int FlashChipSelect = 21; // digital pin for flash chip CS pin - SerialFlashFile file; const unsigned long testIncrement = 4096; @@ -46,7 +46,7 @@ void setup() { delay(100); Serial.println("Raw SerialFlash Hardware Test"); - SerialFlash.begin(FlashChipSelect); + SerialFlash.begin(ONBOARD_FLASH_SPI_PORT, ONBOARD_FLASH_CS_PIN); if (test()) { Serial.println(); diff --git a/libraries/CurieSoftwareSerial/src/SoftwareSerial.cpp b/libraries/CurieSoftwareSerial/src/SoftwareSerial.cpp index 8be77370..4d3a6365 100644 --- a/libraries/CurieSoftwareSerial/src/SoftwareSerial.cpp +++ b/libraries/CurieSoftwareSerial/src/SoftwareSerial.cpp @@ -226,9 +226,7 @@ SoftwareSerial::SoftwareSerial(uint32_t receivePin, uint32_t transmitPin, bool i _inverse_logic(inverse_logic) { _inverse_logic = inverse_logic; - setTX(transmitPin); _transmitPin = transmitPin; - setRX(receivePin); _receivePin = receivePin; _receive_buffer = (char*)dccm_malloc(_SS_MAX_RX_BUFF); } @@ -272,6 +270,9 @@ uint16_t SoftwareSerial::subtract_cap(uint16_t num, uint16_t sub) { void SoftwareSerial::begin(long speed) { + setTX(_transmitPin); + setRX(_receivePin); + _rx_delay_centering = _rx_delay_intrabit = _rx_delay_stopbit = _tx_delay = 0; //pre-calculate delays _bit_delay = (F_CPU/speed); diff --git a/libraries/CurieTimerOne/keywords.txt b/libraries/CurieTimerOne/keywords.txt index 734a16df..87562f6a 100644 --- a/libraries/CurieTimerOne/keywords.txt +++ b/libraries/CurieTimerOne/keywords.txt @@ -6,29 +6,29 @@ # Datatypes (KEYWORD1) ####################################### -CurieTimer KEYWORD1 +CurieTimer KEYWORD1 ####################################### # Methods and Functions (KEYWORD2) ####################################### -initialize KEYWORD2 -setPeriod KEYWORD2 -start KEYWORD2 -stop KEYWORD2 -restart KEYWORD2 -resume KEYWORD2 -setPwmDuty KEYWORD2 -pwm KEYWORD2 -disablePwm KEYWORD2 -attachInterrupt KEYWORD2 -detachInterrupt KEYWORD2 -kill KEYWORD2 -readTickCount KEYWORD2 -rdRstTickCount KEYWORD2 -pause KEYWORD2 -pwmStart KEYWORD2 -pwmStop KEYWORD2 +initialize KEYWORD2 +setPeriod KEYWORD2 +start KEYWORD2 +stop KEYWORD2 +restart KEYWORD2 +resume KEYWORD2 +setPwmDuty KEYWORD2 +pwm KEYWORD2 +disablePwm KEYWORD2 +attachInterrupt KEYWORD2 +detachInterrupt KEYWORD2 +kill KEYWORD2 +readTickCount KEYWORD2 +rdRstTickCount KEYWORD2 +pause KEYWORD2 +pwmStart KEYWORD2 +pwmStop KEYWORD2 ####################################### # Instances (KEYWORD2) ####################################### -CurieTimerOne KEYWORD2 +CurieTimerOne KEYWORD2 diff --git a/libraries/EEPROM/src/EEPROM.cpp b/libraries/EEPROM/src/EEPROM.cpp new file mode 100644 index 00000000..de567eed --- /dev/null +++ b/libraries/EEPROM/src/EEPROM.cpp @@ -0,0 +1,125 @@ +/* + EEPROM.h - EEPROM library + Original Copyright (c) 2006 David A. Mellis. All right reserved. + New version by Christopher Andrews 2015. + Curie porting by Intel and Arduino LLC - 2016 + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include "EEPROM.h" + +EEPROMClass EEPROM; + +void CurieClear() +{ + //erase the 2k bytes of the eeprom section inside the otp area + *(uint32_t*)(ROM_WR_CTRL) = 0x4002; + //wait for erase to be complete + #if 0 + // TODO: wait for FLASH_STTS.ER_DONE to be set to 1 + while(((*(uint32_t*)FLASH_STTS) & 0x01) == 0) { + delay(1); + } + #endif + delay(5); +} + +void CurieRestoreMemory(uint32_t* buffer, uint32_t size) +{ + uint32_t rom_wr_ctrl = 0; + uint32_t address; + + for (uint32_t i=0; i 0x7FF)) + { + return 0; + } + int offset = address%4; + uint32_t value = *(uint32_t*)(EEPROM_ADDR+(address/4)*4); + value = (value >> ((3-offset)*8)) & 0xFF; + return (uint8_t)value; +} + +uint32_t CurieRead32(uint32_t address) +{ + if((address > 0x7FF)) + { + return 0; + } + uint32_t value = *(uint32_t*)(EEPROM_ADDR+(address/4)*4); + return value; +} + +void CurieWrite8(uint32_t address, uint8_t data) +{ + //make sure address is valid + if((address > 0x7FF)) + { + return; + } + + uint8_t currentValue = CurieRead8(address); + //only do something if value is different from what is currently stored + if(currentValue==data) + { + return; + } + + uint32_t currentDword = CurieRead32(address); + + int offset = address%4; + + uint32_t data32 = (currentDword & ~(uint32_t)(0xFF << ((3-offset)*8))); + data32 = data32 | (data << ((3-offset)*8)); + + if (currentValue != 0xFF) { + uint32_t dump[EEPROM_SIZE/4]; + memcpy(dump, (uint32_t *)EEPROM_ADDR, EEPROM_SIZE); + dump[(address >> 2)] = data32; + CurieClear(); + CurieRestoreMemory((uint32_t *)dump, EEPROM_SIZE/sizeof(uint32_t)); + return; + } + + uint32_t rom_wr_ctrl = 0; + + //store data into ROM_WR_DATA register + *(uint32_t*)(ROM_WR_DATA) = data32; + address = ((address >> 2) << 2) + EEPROM_OFFSET; + //shift left 2 bits to store offset into bits 19:2 (WR_ADDR) + rom_wr_ctrl = (address)<<2; + rom_wr_ctrl |= 0x00000001; //set (WR_REQ) bit + *(uint32_t*)(ROM_WR_CTRL) = rom_wr_ctrl; + + delay(5); //give it enough time to finish writing +} diff --git a/libraries/EEPROM/src/EEPROM.h b/libraries/EEPROM/src/EEPROM.h index c52737c7..ac5e05f4 100644 --- a/libraries/EEPROM/src/EEPROM.h +++ b/libraries/EEPROM/src/EEPROM.h @@ -16,8 +16,8 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef EEPROM_h -#define EEPROM_h +#ifndef EEPROM_H +#define EEPROM_H #define ROM_WR_CTRL 0xb0100004 #define ROM_WR_DATA 0xb0100008 @@ -28,112 +28,17 @@ #define EEPROM_SIZE 2048 //EEPROM size in bytes - #include #include "Arduino.h" /* Curie specific implementation of "atomic" read8 and write8 on OTP flash storage */ -void CurieClear() -{ - //erase the 2k bytes of the eeprom section inside the otp area - *(uint32_t*)(ROM_WR_CTRL) = 0x4002; - //wait for erase to be complete - #if 0 - while(((*(uint32_t*)FLASH_STTS) & 0x01) == 0) { // TODO: wait for FLASH_STTS.ER_DONE to be set to 1 - delay(1); - } - #endif - delay(5); -} - -void CurieRestoreMemory(uint32_t* buffer, uint32_t size) -{ - uint32_t rom_wr_ctrl = 0; - uint32_t address; - - for (uint32_t i=0; i 0x7FF)) - { - return 0; - } - int offset = address%4; - uint32_t value = *(uint32_t*)(EEPROM_ADDR+(address/4)*4); - value = (value >> ((3-offset)*8)) & 0xFF; - return (uint8_t)value; -} - -uint32_t CurieRead32(uint32_t address) -{ - if((address > 0x7FF)) - { - return 0; - } - uint32_t value = *(uint32_t*)(EEPROM_ADDR+(address/4)*4); - return value; -} - -void CurieWrite8(uint32_t address, uint8_t data) -{ - //make sure address is valid - if((address > 0x7FF)) - { - return; - } - - uint8_t currentValue = CurieRead8(address); - //only do something if value is different from what is currently stored - if(currentValue==data) - { - return; - } - - uint32_t currentDword = CurieRead32(address); - - int offset = address%4; - - uint32_t data32 = (currentDword & ~(uint32_t)(0xFF << ((3-offset)*8))); - data32 = data32 | (data << ((3-offset)*8)); - - if (currentValue != 0xFF) { - uint32_t dump[EEPROM_SIZE/4]; - memcpy(dump, (uint32_t *)EEPROM_ADDR, EEPROM_SIZE); - dump[(address >> 2)] = data32; - CurieClear(); - CurieRestoreMemory((uint32_t *)dump, EEPROM_SIZE/sizeof(uint32_t)); - return; - } - - uint32_t rom_wr_ctrl = 0; - - //store data into ROM_WR_DATA register - *(uint32_t*)(ROM_WR_DATA) = data32; - address = ((address >> 2) << 2) + EEPROM_OFFSET; - rom_wr_ctrl = (address)<<2; //shift left 2 bits to store offset into bits 19:2 (WR_ADDR) - rom_wr_ctrl |= 0x00000001; //set (WR_REQ) bit - *(uint32_t*)(ROM_WR_CTRL) = rom_wr_ctrl; +void CurieClear(); +void CurieRestoreMemory(uint32_t* buffer, uint32_t size); - delay(3); //give it enough time to finish writing -} +uint8_t CurieRead8(uint32_t address); +uint32_t CurieRead32(uint32_t address); +void CurieWrite8(uint32_t address, uint8_t data); /*** EERef class. @@ -252,5 +157,5 @@ struct EEPROMClass{ } }; -static EEPROMClass EEPROM; -#endif \ No newline at end of file +extern EEPROMClass EEPROM; +#endif diff --git a/libraries/MemoryFree/README.md b/libraries/MemoryFree/README.md new file mode 100644 index 00000000..d08aa930 --- /dev/null +++ b/libraries/MemoryFree/README.md @@ -0,0 +1,41 @@ +## MemoryFree library for Arduino/Genuino101 and tinyTILE + +This library is a re-write of http://playground.arduino.cc/Code/AvailableMemory +specifically for Curie-based devices. This library defines the same header file +`MemoryFree.h`, and provides the function `freeMemory()`. In addition, two extra +functions are provided; `freeHeap()`, for heap space only, and `freeStack()`, +for free stack space. `freeStack()` can also be used to detect a stack overflow. + +The rewrite is necessary for two reasons: + +* AVR-based boards use a different implementation of `malloc()` than Curie-based + boards, and in order to determine the amount of free heap space, we depend + on specific symbols defined by the `malloc()` implementation. The `malloc()` + implementation used by Curie-based devices + [can be seen here](https://github.com/foss-for-synopsys-dwc-arc-processors/glibc). + +* Curie-based boards have a different memory layout than AVR-based boards. See + the [linker script](https://github.com/01org/corelibs-arduino101/blob/master/variants/arduino_101/linker_scripts/flash.ld) + for Arduino/Genuino 101 for details of the memory layout + for Curie-based devices. + +## Functions + + +`int freeHeap (void)` + +Returns the number of bytes free in the heap, i.e. the number of bytes free +to be allocated using `malloc()`. + +`int freeStack (void)` + +Returns the number of bytes free in the stack, i.e. the space between the +current stack frame and the end of the stack area. This function will return +a negative number in the event of a stack overflow, representing the size of +the overflow; for example, a return value of -20 means that the current stack +frame is 20 bytes past the end of the stack area. + +`int freeMemory (void)` + +Returns the number of bytes free in both the stack and the heap. If a stack +overflow has occurred, only the number of bytes free in the heap is returned. diff --git a/libraries/MemoryFree/examples/freeMemory/freeMemory.ino b/libraries/MemoryFree/examples/freeMemory/freeMemory.ino new file mode 100644 index 00000000..15c08d28 --- /dev/null +++ b/libraries/MemoryFree/examples/freeMemory/freeMemory.ino @@ -0,0 +1,50 @@ +/* + * freeMemory.ino: This sketch demonstrates the use of the freeMemory() + * function to measure the amount of free memory available in the system, + * before and after using 'malloc' to allocate some memory. + * + * Copyright (c) 2016 Intel Corporation. All rights reserved. + * See the bottom of this file for the license terms. + */ + +#include + +void setup () { + Serial.begin(9600); + while(!Serial); +} + +void loop() { + char *p; + + Serial.println("Free memory: " + String(freeMemory())); + Serial.println("Allocating 24 bytes ..."); + + p = (char *)malloc(24); + Serial.println("Free memory: " + String(freeMemory())); + + Serial.println("Freeing 24 bytes ..."); + free(p); + Serial.println("Free memory: " + String(freeMemory())); + + delay(2000); +} + +/* + * Copyright (c) 2017 Intel Corporation. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ diff --git a/libraries/MemoryFree/keywords.txt b/libraries/MemoryFree/keywords.txt new file mode 100644 index 00000000..9da291a1 --- /dev/null +++ b/libraries/MemoryFree/keywords.txt @@ -0,0 +1,11 @@ +####################################### +# Syntax Coloring Map For MemoryFree +####################################### + +####################################### +# Methods and Functions (KEYWORD2) +####################################### + +freeStack KEYWORD2 +freeHeap KEYWORD2 +freeMemory KEYWORD2 diff --git a/libraries/MemoryFree/library.properties b/libraries/MemoryFree/library.properties new file mode 100644 index 00000000..1acd530e --- /dev/null +++ b/libraries/MemoryFree/library.properties @@ -0,0 +1,10 @@ +name=MemoryFree +version=1.0 +author=Erik Nyquist +maintainer=Erik Nyquist +sentence=Determines the amount of available memory in the heap +paragraph=Determines the amount of memory, in bytes, that is available for allocation using malloc() +category=Uncategorized +url= +architectures=arc32 + diff --git a/libraries/MemoryFree/src/MemoryFree.cpp b/libraries/MemoryFree/src/MemoryFree.cpp new file mode 100644 index 00000000..8fbba7ee --- /dev/null +++ b/libraries/MemoryFree/src/MemoryFree.cpp @@ -0,0 +1,58 @@ +/* + * MemoryFree.cpp: taken from http://playground.arduino.cc/Code/AvailableMemory, + * re-written for the Arduino 101 which uses a different malloc implementation. + * + * Arduino 101 malloc source: + * https://github.com/foss-for-synopsys-dwc-arc-processors/glibc + * + * mallinfo() struct details: + * http://man7.org/linux/man-pages/man3/mallinfo.3.html + * + * Copyright (c) 2017 Intel Corporation. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include +#include "MemoryFree.h" + +extern char __start_heap; +extern char __end_heap; +extern char __stack_size; +extern char __stack_start; + +int freeStack() { + int stack_end; + int mark; + + stack_end = ((int)&__stack_start) - ((int)&__stack_size); + return ((int)&mark) - stack_end; +} + +int freeHeap (void) { + int hsize; + struct mallinfo mi; + + mi = mallinfo(); + hsize = (int)&__end_heap - (int)&__start_heap; + return (hsize - mi.arena) + mi.fordblks; +} + +int freeMemory (void) { + int heap = freeHeap(); + int stack = freeStack(); + return (stack < 0) ? heap : stack + heap; +} diff --git a/libraries/MemoryFree/src/MemoryFree.h b/libraries/MemoryFree/src/MemoryFree.h new file mode 100644 index 00000000..bf532bc2 --- /dev/null +++ b/libraries/MemoryFree/src/MemoryFree.h @@ -0,0 +1,48 @@ +/* + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef MEMORYFREE_H +#define MEMORYFREE_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* freeHeap: returns the size (in bytes) of unused space on the heap, + * i.e. the number of bytes available for allocation by 'malloc()' */ +int freeHeap(void); + +/* freeStack: returns the size (in bytes) of remaining free space in the stack, + * i.e. the difference between our current position in the stack, and the end + * of usable stack space. + * + * NOTE: This function will return a negative number to indicate a stack + * overflow, i.e. a return value of -20 means you have overrun the allocated + * stack area by 20 bytes. */ +int freeStack(void); + +/* freeMemory: returns the combined free memory in both the stack and heap, + * except in the case where a stack overflow has occurred (i.e. freeStack + * returns a negative number). In this case, only the amount of free heap + * space will be returned. */ +int freeMemory(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libraries/SPI/examples/DigitalPotControl/DigitalPotControl.ino b/libraries/SPI/examples/DigitalPotControl/DigitalPotControl.ino index b135a74f..a06f1133 100644 --- a/libraries/SPI/examples/DigitalPotControl/DigitalPotControl.ino +++ b/libraries/SPI/examples/DigitalPotControl/DigitalPotControl.ino @@ -63,9 +63,11 @@ void loop() { void digitalPotWrite(int address, int value) { // take the SS pin low to select the chip: digitalWrite(slaveSelectPin, LOW); + delay(100); // send in the address and value via SPI: SPI.transfer(address); SPI.transfer(value); + delay(100); // take the SS pin high to de-select the chip: digitalWrite(slaveSelectPin, HIGH); } diff --git a/libraries/SPI/keywords.txt b/libraries/SPI/keywords.txt index ff058279..05834754 100644 --- a/libraries/SPI/keywords.txt +++ b/libraries/SPI/keywords.txt @@ -7,7 +7,7 @@ ####################################### SPI KEYWORD1 -SPI1 KEYWORD1 +SPI1 KEYWORD1 ####################################### # Methods and Functions (KEYWORD2) diff --git a/libraries/SerialFlash/SerialFlash.h b/libraries/SerialFlash/SerialFlash.h deleted file mode 100644 index e56df624..00000000 --- a/libraries/SerialFlash/SerialFlash.h +++ /dev/null @@ -1,132 +0,0 @@ -/* SerialFlash Library - for filesystem-like access to SPI Serial Flash memory - * https://github.com/PaulStoffregen/SerialFlash - * Copyright (C) 2015, Paul Stoffregen, paul@pjrc.com - * - * Development of this library was funded by PJRC.COM, LLC by sales of Teensy. - * Please support PJRC's efforts to develop open source software by purchasing - * Teensy or other genuine PJRC products. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice, development funding notice, and this permission - * notice shall be included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#ifndef SerialFlash_h_ -#define SerialFlash_h_ - -#include -#include - -class SerialFlashFile; - -class SerialFlashChip -{ -public: - static bool begin(uint8_t pin = 6); - static uint32_t capacity(const uint8_t *id); - static uint32_t blockSize(); - static void sleep(); - static void wakeup(); - static void readID(uint8_t *buf); - static void readSerialNumber(uint8_t *buf); - static void read(uint32_t addr, void *buf, uint32_t len); - static bool ready(); - static void wait(); - static void write(uint32_t addr, const void *buf, uint32_t len); - static void eraseAll(); - static void eraseBlock(uint32_t addr); - - static SerialFlashFile open(const char *filename); - static bool create(const char *filename, uint32_t length, uint32_t align = 0); - static bool createErasable(const char *filename, uint32_t length) { - return create(filename, length, blockSize()); - } - static bool exists(const char *filename); - static bool remove(const char *filename); - static bool remove(SerialFlashFile &file); - static void opendir() { dirindex = 0; } - static bool readdir(char *filename, uint32_t strsize, uint32_t &filesize); -private: - static uint16_t dirindex; // current position for readdir() - static uint8_t flags; // chip features - static uint8_t busy; // 0 = ready - // 1 = suspendable program operation - // 2 = suspendable erase operation - // 3 = busy for realz!! -}; - -extern SerialFlashChip SerialFlash; - - -class SerialFlashFile -{ -public: - SerialFlashFile() : address(0) { - } - operator bool() { - if (address > 0) return true; - return false; - } - uint32_t read(void *buf, uint32_t rdlen) { - if (offset + rdlen > length) { - if (offset >= length) return 0; - rdlen = length - offset; - } - SerialFlash.read(address + offset, buf, rdlen); - offset += rdlen; - return rdlen; - } - uint32_t write(const void *buf, uint32_t wrlen) { - if (offset + wrlen > length) { - if (offset >= length) return 0; - wrlen = length - offset; - } - SerialFlash.write(address + offset, buf, wrlen); - offset += wrlen; - return wrlen; - } - void seek(uint32_t n) { - offset = n; - } - uint32_t position() { - return offset; - } - uint32_t size() { - return length; - } - uint32_t available() { - if (offset >= length) return 0; - return length - offset; - } - void erase(); - void flush() { - } - void close() { - } - uint32_t getFlashAddress() { - return address; - } -protected: - friend class SerialFlashChip; - uint32_t address; // where this file's data begins in the Flash, or zero - uint32_t length; // total length of the data in the Flash chip - uint32_t offset; // current read/write offset in the file - uint16_t dirindex; -}; - - -#endif diff --git a/libraries/SerialFlash/SerialFlashChip.cpp b/libraries/SerialFlash/SerialFlashChip.cpp deleted file mode 100644 index 4e467f57..00000000 --- a/libraries/SerialFlash/SerialFlashChip.cpp +++ /dev/null @@ -1,523 +0,0 @@ -/* SerialFlash Library - for filesystem-like access to SPI Serial Flash memory - * https://github.com/PaulStoffregen/SerialFlash - * Copyright (C) 2015, Paul Stoffregen, paul@pjrc.com - * - * Development of this library was funded by PJRC.COM, LLC by sales of Teensy. - * Please support PJRC's efforts to develop open source software by purchasing - * Teensy or other genuine PJRC products. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice, development funding notice, and this permission - * notice shall be included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#include "SerialFlash.h" -#include "util/SerialFlash_directwrite.h" - -#define CSASSERT() DIRECT_WRITE_LOW(cspin_basereg, cspin_bitmask) -#define CSRELEASE() DIRECT_WRITE_HIGH(cspin_basereg, cspin_bitmask) -#define SPICONFIG SPISettings(50000000, MSBFIRST, SPI_MODE0) - -#if defined(__arc__) -// Use SPI1 on Arduino 101 (accesses chip already on the board) -#define SPIPORT SPI1 -#elif 0 -// Add cases here, if you wish to use other SPI ports... -#else -// Otherwise, use the normal SPI port. -#define SPIPORT SPI -#endif - -uint16_t SerialFlashChip::dirindex = 0; -uint8_t SerialFlashChip::flags = 0; -uint8_t SerialFlashChip::busy = 0; - -static volatile IO_REG_TYPE *cspin_basereg; -static IO_REG_TYPE cspin_bitmask; - -#define FLAG_32BIT_ADDR 0x01 // larger than 16 MByte address -#define FLAG_STATUS_CMD70 0x02 // requires special busy flag check -#define FLAG_DIFF_SUSPEND 0x04 // uses 2 different suspend commands -#define FLAG_MULTI_DIE 0x08 // multiple die, don't read cross 32M barrier -#define FLAG_256K_BLOCKS 0x10 // has 256K erase blocks -#define FLAG_DIE_MASK 0xC0 // top 2 bits count during multi-die erase - -void SerialFlashChip::wait(void) -{ - uint32_t status; - //Serial.print("wait-"); - while (1) { - SPIPORT.beginTransaction(SPICONFIG); - CSASSERT(); - if (flags & FLAG_STATUS_CMD70) { - // some Micron chips require this different - // command to detect program and erase completion - SPIPORT.transfer(0x70); - status = SPIPORT.transfer(0); - CSRELEASE(); - SPIPORT.endTransaction(); - //Serial.printf("b=%02x.", status & 0xFF); - if ((status & 0x80)) break; - } else { - // all others work by simply reading the status reg - SPIPORT.transfer(0x05); - status = SPIPORT.transfer(0); - CSRELEASE(); - SPIPORT.endTransaction(); - //Serial.printf("b=%02x.", status & 0xFF); - if (!(status & 1)) break; - } - } - busy = 0; - //Serial.println(); -} - -void SerialFlashChip::read(uint32_t addr, void *buf, uint32_t len) -{ - uint8_t *p = (uint8_t *)buf; - uint8_t b, f, status, cmd; - - memset(p, 0, len); - f = flags; - SPIPORT.beginTransaction(SPICONFIG); - b = busy; - if (b) { - // read status register ... chip may no longer be busy - CSASSERT(); - if (flags & FLAG_STATUS_CMD70) { - SPIPORT.transfer(0x70); - status = SPIPORT.transfer(0); - if ((status & 0x80)) b = 0; - } else { - SPIPORT.transfer(0x05); - status = SPIPORT.transfer(0); - if (!(status & 1)) b = 0; - } - CSRELEASE(); - if (b == 0) { - // chip is no longer busy :-) - busy = 0; - } else if (b < 3) { - // TODO: this may not work on Spansion chips - // which apparently have 2 different suspend - // commands, for program vs erase - CSASSERT(); - SPIPORT.transfer(0x06); // write enable (Micron req'd) - CSRELEASE(); - delayMicroseconds(1); - cmd = 0x75; //Suspend program/erase for almost all chips - // but Spansion just has to be different for program suspend! - if ((f & FLAG_DIFF_SUSPEND) && (b == 1)) cmd = 0x85; - CSASSERT(); - SPIPORT.transfer(cmd); // Suspend command - CSRELEASE(); - if (f & FLAG_STATUS_CMD70) { - // Micron chips don't actually suspend until flags read - CSASSERT(); - SPIPORT.transfer(0x70); - do { - status = SPIPORT.transfer(0); - } while (!(status & 0x80)); - CSRELEASE(); - } else { - CSASSERT(); - SPIPORT.transfer(0x05); - do { - status = SPIPORT.transfer(0); - } while ((status & 0x01)); - CSRELEASE(); - } - } else { - // chip is busy with an operation that can not suspend - SPIPORT.endTransaction(); // is this a good idea? - wait(); // should we wait without ending - b = 0; // the transaction?? - SPIPORT.beginTransaction(SPICONFIG); - } - } - do { - uint32_t rdlen = len; - if (f & FLAG_MULTI_DIE) { - if ((addr & 0xFE000000) != ((addr + len - 1) & 0xFE000000)) { - rdlen = 0x2000000 - (addr & 0x1FFFFFF); - } - } - CSASSERT(); - // TODO: FIFO optimize.... - if (f & FLAG_32BIT_ADDR) { - SPIPORT.transfer(0x03); - SPIPORT.transfer16(addr >> 16); - SPIPORT.transfer16(addr); - } else { - SPIPORT.transfer16(0x0300 | ((addr >> 16) & 255)); - SPIPORT.transfer16(addr); - } - SPIPORT.transfer(p, rdlen); - CSRELEASE(); - p += rdlen; - addr += rdlen; - len -= rdlen; - } while (len > 0); - if (b) { - CSASSERT(); - SPIPORT.transfer(0x06); // write enable (Micron req'd) - CSRELEASE(); - delayMicroseconds(1); - cmd = 0x7A; - if ((f & FLAG_DIFF_SUSPEND) && (b == 1)) cmd = 0x8A; - CSASSERT(); - SPIPORT.transfer(cmd); // Resume program/erase - CSRELEASE(); - } - SPIPORT.endTransaction(); -} - -void SerialFlashChip::write(uint32_t addr, const void *buf, uint32_t len) -{ - const uint8_t *p = (const uint8_t *)buf; - uint32_t max, pagelen; - - //Serial.printf("WR: addr %08X, len %d\n", addr, len); - do { - if (busy) wait(); - SPIPORT.beginTransaction(SPICONFIG); - CSASSERT(); - // write enable command - SPIPORT.transfer(0x06); - CSRELEASE(); - max = 256 - (addr & 0xFF); - pagelen = (len <= max) ? len : max; - //Serial.printf("WR: addr %08X, pagelen %d\n", addr, pagelen); - delayMicroseconds(1); // TODO: reduce this, but prefer safety first - CSASSERT(); - if (flags & FLAG_32BIT_ADDR) { - SPIPORT.transfer(0x02); // program page command - SPIPORT.transfer16(addr >> 16); - SPIPORT.transfer16(addr); - } else { - SPIPORT.transfer16(0x0200 | ((addr >> 16) & 255)); - SPIPORT.transfer16(addr); - } - addr += pagelen; - len -= pagelen; - do { - SPIPORT.transfer(*p++); - } while (--pagelen > 0); - CSRELEASE(); - busy = 4; - SPIPORT.endTransaction(); - } while (len > 0); -} - -void SerialFlashChip::eraseAll() -{ - if (busy) wait(); - uint8_t id[5]; - readID(id); - //Serial.printf("ID: %02X %02X %02X\n", id[0], id[1], id[2]); - if (id[0] == 0x20 && id[2] >= 0x20 && id[2] <= 0x22) { - // Micron's multi-die chips require special die erase commands - // N25Q512A 20 BA 20 2 dies 32 Mbyte/die 65 nm transitors - // N25Q00AA 20 BA 21 4 dies 32 Mbyte/die 65 nm transitors - // MT25QL02GC 20 BA 22 2 dies 128 Mbyte/die 45 nm transitors - uint8_t die_count = 2; - if (id[2] == 0x21) die_count = 4; - uint8_t die_index = flags >> 6; - //Serial.printf("Micron die erase %d\n", die_index); - flags &= 0x3F; - if (die_index >= die_count) return; // all dies erased :-) - uint8_t die_size = 2; // in 16 Mbyte units - if (id[2] == 0x22) die_size = 8; - SPIPORT.beginTransaction(SPICONFIG); - CSASSERT(); - SPIPORT.transfer(0x06); // write enable command - CSRELEASE(); - delayMicroseconds(1); - CSASSERT(); - // die erase command - SPIPORT.transfer(0xC4); - SPIPORT.transfer16((die_index * die_size) << 8); - SPIPORT.transfer16(0x0000); - CSRELEASE(); - //Serial.printf("Micron erase begin\n"); - flags |= (die_index + 1) << 6; - } else { - // All other chips support the bulk erase command - SPIPORT.beginTransaction(SPICONFIG); - CSASSERT(); - // write enable command - SPIPORT.transfer(0x06); - CSRELEASE(); - delayMicroseconds(1); - CSASSERT(); - // bulk erase command - SPIPORT.transfer(0xC7); - CSRELEASE(); - SPIPORT.endTransaction(); - } - busy = 3; -} - -void SerialFlashChip::eraseBlock(uint32_t addr) -{ - uint8_t f = flags; - if (busy) wait(); - SPIPORT.beginTransaction(SPICONFIG); - CSASSERT(); - SPIPORT.transfer(0x06); // write enable command - CSRELEASE(); - delayMicroseconds(1); - CSASSERT(); - if (f & FLAG_32BIT_ADDR) { - SPIPORT.transfer(0xD8); - SPIPORT.transfer16(addr >> 16); - SPIPORT.transfer16(addr); - } else { - SPIPORT.transfer16(0xD800 | ((addr >> 16) & 255)); - SPIPORT.transfer16(addr); - } - CSRELEASE(); - SPIPORT.endTransaction(); - busy = 2; -} - - -bool SerialFlashChip::ready() -{ - uint32_t status; - if (!busy) return true; - SPIPORT.beginTransaction(SPICONFIG); - CSASSERT(); - if (flags & FLAG_STATUS_CMD70) { - // some Micron chips require this different - // command to detect program and erase completion - SPIPORT.transfer(0x70); - status = SPIPORT.transfer(0); - CSRELEASE(); - SPIPORT.endTransaction(); - //Serial.printf("ready=%02x\n", status & 0xFF); - if ((status & 0x80) == 0) return false; - } else { - // all others work by simply reading the status reg - SPIPORT.transfer(0x05); - status = SPIPORT.transfer(0); - CSRELEASE(); - SPIPORT.endTransaction(); - //Serial.printf("ready=%02x\n", status & 0xFF); - if ((status & 1)) return false; - } - busy = 0; - if (flags & 0xC0) { - // continue a multi-die erase - eraseAll(); - return false; - } - return true; -} - - -#define ID0_WINBOND 0xEF -#define ID0_SPANSION 0x01 -#define ID0_MICRON 0x20 -#define ID0_MACRONIX 0xC2 -#define ID0_SST 0xBF - -//#define FLAG_32BIT_ADDR 0x01 // larger than 16 MByte address -//#define FLAG_STATUS_CMD70 0x02 // requires special busy flag check -//#define FLAG_DIFF_SUSPEND 0x04 // uses 2 different suspend commands -//#define FLAG_256K_BLOCKS 0x10 // has 256K erase blocks - -bool SerialFlashChip::begin(uint8_t pin) -{ - uint8_t id[5]; - uint8_t f; - uint32_t size; - - cspin_basereg = PIN_TO_BASEREG(pin); - cspin_bitmask = PIN_TO_BITMASK(pin); - SPIPORT.begin(); - pinMode(pin, OUTPUT); - CSRELEASE(); - readID(id); - f = 0; - size = capacity(id); - if (size > 16777216) { - // more than 16 Mbyte requires 32 bit addresses - f |= FLAG_32BIT_ADDR; - SPIPORT.beginTransaction(SPICONFIG); - if (id[0] == ID0_SPANSION) { - // spansion uses MSB of bank register - CSASSERT(); - SPIPORT.transfer16(0x1780); // bank register write - CSRELEASE(); - } else { - // micron & winbond & macronix use command - CSASSERT(); - SPIPORT.transfer(0x06); // write enable - CSRELEASE(); - delayMicroseconds(1); - CSASSERT(); - SPIPORT.transfer(0xB7); // enter 4 byte addr mode - CSRELEASE(); - } - SPIPORT.endTransaction(); - if (id[0] == ID0_MICRON) f |= FLAG_MULTI_DIE; - } - if (id[0] == ID0_SPANSION) { - // Spansion has separate suspend commands - f |= FLAG_DIFF_SUSPEND; - if (!id[4]) { - // Spansion chips with id[4] == 0 use 256K sectors - f |= FLAG_256K_BLOCKS; - } - } - if (id[0] == ID0_MICRON) { - // Micron requires busy checks with a different command - f |= FLAG_STATUS_CMD70; // TODO: all or just multi-die chips? - } - flags = f; - readID(id); - return true; -} - -// chips tested: https://github.com/PaulStoffregen/SerialFlash/pull/12#issuecomment-169596992 -// -void SerialFlashChip::sleep() -{ - if (busy) wait(); - SPIPORT.beginTransaction(SPICONFIG); - CSASSERT(); - SPIPORT.transfer(0xB9); // Deep power down command - CSRELEASE(); -} - -void SerialFlashChip::wakeup() -{ - SPIPORT.beginTransaction(SPICONFIG); - CSASSERT(); - SPIPORT.transfer(0xAB); // Wake up from deep power down command - CSRELEASE(); -} - -void SerialFlashChip::readID(uint8_t *buf) -{ - if (busy) wait(); - SPIPORT.beginTransaction(SPICONFIG); - CSASSERT(); - SPIPORT.transfer(0x9F); - buf[0] = SPIPORT.transfer(0); // manufacturer ID - buf[1] = SPIPORT.transfer(0); // memory type - buf[2] = SPIPORT.transfer(0); // capacity - if (buf[0] == ID0_SPANSION) { - buf[3] = SPIPORT.transfer(0); // ID-CFI - buf[4] = SPIPORT.transfer(0); // sector size - } - CSRELEASE(); - SPIPORT.endTransaction(); - //Serial.printf("ID: %02X %02X %02X\n", buf[0], buf[1], buf[2]); -} - -void SerialFlashChip::readSerialNumber(uint8_t *buf) //needs room for 8 bytes -{ - if (busy) wait(); - SPIPORT.beginTransaction(SPICONFIG); - CSASSERT(); - SPIPORT.transfer(0x4B); - SPIPORT.transfer16(0); - SPIPORT.transfer16(0); - for (int i=0; i<8; i++) { - buf[i] = SPIPORT.transfer(0); - } - CSRELEASE(); - SPIPORT.endTransaction(); -// Serial.printf("Serial Number: %02X %02X %02X %02X %02X %02X %02X %02X\n", buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]); -} - -uint32_t SerialFlashChip::capacity(const uint8_t *id) -{ - uint32_t n = 1048576; // unknown chips, default to 1 MByte - - if (id[2] >= 16 && id[2] <= 31) { - n = 1ul << id[2]; - } else - if (id[2] >= 32 && id[2] <= 37) { - n = 1ul << (id[2] - 6); - } else - if ((id[0]==0 && id[1]==0 && id[2]==0) || - (id[0]==255 && id[1]==255 && id[2]==255)) { - n = 0; - } - //Serial.printf("capacity %lu\n", n); - return n; -} - -uint32_t SerialFlashChip::blockSize() -{ - // Spansion chips >= 512 mbit use 256K sectors - if (flags & FLAG_256K_BLOCKS) return 262144; - // everything else seems to have 64K sectors - return 65536; -} - - - - -/* -Chip Uniform Sector Erase - 20/21 52 D8/DC - ----- -- ----- -W25Q64CV 4 32 64 -W25Q128FV 4 32 64 -S25FL127S 64 -N25Q512A 4 64 -N25Q00AA 4 64 -S25FL512S 256 -SST26VF032 4 -*/ - - - -// size sector busy pgm/erase chip -// Part Mbyte kbyte ID bytes cmd suspend erase -// ---- ---- ----- -------- --- ------- ----- -// Winbond W25Q64CV 8 64 EF 40 17 -// Winbond W25Q128FV 16 64 EF 40 18 05 single 60 & C7 -// Winbond W25Q256FV 32 64 EF 40 19 -// Spansion S25FL064A 8 ? 01 02 16 -// Spansion S25FL127S 16 64 01 20 18 05 -// Spansion S25FL128P 16 64 01 20 18 -// Spansion S25FL256S 32 64 01 02 19 05 60 & C7 -// Spansion S25FL512S 64 256 01 02 20 -// Macronix MX25L12805D 16 ? C2 20 18 -// Macronix MX66L51235F 64 C2 20 1A -// Numonyx M25P128 16 ? 20 20 18 -// Micron M25P80 1 ? 20 20 14 -// Micron N25Q128A 16 64 20 BA 18 -// Micron N25Q512A 64 ? 20 BA 20 70 single C4 x2 -// Micron N25Q00AA 128 64 20 BA 21 single C4 x4 -// Micron MT25QL02GC 256 64 20 BA 22 70 C4 x2 -// SST SST25WF010 1/8 ? BF 25 02 -// SST SST25WF020 1/4 ? BF 25 03 -// SST SST25WF040 1/2 ? BF 25 04 -// SST SST25VF016B 1 ? BF 25 41 -// SST26VF016 ? BF 26 01 -// SST26VF032 ? BF 26 02 -// SST25VF032 4 64 BF 25 4A -// SST26VF064 8 ? BF 26 43 -// LE25U40CMC 1/2 64 62 06 13 - -SerialFlashChip SerialFlash; diff --git a/libraries/SerialFlash/SerialFlashDirectory.cpp b/libraries/SerialFlash/SerialFlashDirectory.cpp deleted file mode 100644 index 116c14ec..00000000 --- a/libraries/SerialFlash/SerialFlashDirectory.cpp +++ /dev/null @@ -1,395 +0,0 @@ -/* SerialFlash Library - for filesystem-like access to SPI Serial Flash memory - * https://github.com/PaulStoffregen/SerialFlash - * Copyright (C) 2015, Paul Stoffregen, paul@pjrc.com - * - * Development of this library was funded by PJRC.COM, LLC by sales of Teensy. - * Please support PJRC's efforts to develop open source software by purchasing - * Teensy or other genuine PJRC products. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice, development funding notice, and this permission - * notice shall be included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#include "SerialFlash.h" - -/* On-chip SerialFlash file allocation data structures: - - uint32_t signature = 0xFA96554C; - uint16_t maxfiles - uint16_t stringssize // div by 4 - uint16_t hashes[maxfiles] - struct { - uint32_t file_begin - uint32_t file_length - uint16_t string_index // div4 - } fileinfo[maxfiles] - char strings[stringssize] - -A 32 bit signature is stored at the beginning of the flash memory. -If 0xFFFFFFFF is seen, the entire chip should be assumed blank. -If any value other than 0xFA96554C is found, a different data format -is stored. This could should refuse to access the flash. - -The next 4 bytes store number of files and size of the strings -section, which allow the position of every other item to be found. -The string section size is the 16 bit integer times 4, which allows -up to 262140 bytes for string data. - -An array of 16 bit filename hashes allows for quick linear search -for potentially matching filenames. A hash value of 0xFFFF indicates -no file is allocated for the remainder of the array. - -Following the hashes, and array of 10 byte structs give the location -and length of the file's actual data, and the offset of its filename -in the strings section. - -Strings are null terminated. The remainder of the chip is file data. -*/ - -#define DEFAULT_MAXFILES 600 -#define DEFAULT_STRINGS_SIZE 25560 - - -static uint32_t check_signature(void) -{ - uint32_t sig[2]; - - SerialFlash.read(0, sig, 8); - //Serial.printf("sig: %08X %08X\n", sig[0], sig[1]); - if (sig[0] == 0xFA96554C) return sig[1]; - if (sig[0] == 0xFFFFFFFF) { - sig[0] = 0xFA96554C; - sig[1] = ((uint32_t)(DEFAULT_STRINGS_SIZE/4) << 16) | DEFAULT_MAXFILES; - SerialFlash.write(0, sig, 8); - while (!SerialFlash.ready()) ; // TODO: timeout - SerialFlash.read(0, sig, 8); - if (sig[0] == 0xFA96554C) return sig[1]; - } - return 0; -} - -static uint16_t filename_hash(const char *filename) -{ - // http://isthe.com/chongo/tech/comp/fnv/ - uint32_t hash = 2166136261; - const char *p; - - for (p=filename; *p; p++) { - hash ^= *p; - hash *= 16777619; - } - hash = (hash % (uint32_t)0xFFFE) + 1; // all values except 0000 & FFFF - return hash; -} - -static bool filename_compare(const char *filename, uint32_t straddr) -{ - unsigned int i; - const char *p; - char buf[16]; - - p = filename; - while (1) { - SerialFlash.read(straddr, buf, sizeof(buf)); - straddr += sizeof(buf); - for (i=0; i < sizeof(buf); i++) { - if (*p++ != buf[i]) return false; - if (buf[i] == 0) return true; - } - } -} - -#if 0 -void pbuf(const void *buf, uint32_t len) -{ - const uint8_t *p = (const uint8_t *)buf; - do { - Serial.printf("%02X ", *p++); - } while (--len > 0); - Serial.println(); -} -#endif - -SerialFlashFile SerialFlashChip::open(const char *filename) -{ - uint32_t maxfiles, straddr; - uint16_t hash, hashtable[8]; - uint32_t i, n, index=0; - uint32_t buf[3]; - SerialFlashFile file; - - maxfiles = check_signature(); - //Serial.printf("sig: %08X\n", maxfiles); - if (!maxfiles) return file; - maxfiles &= 0xFFFF; - hash = filename_hash(filename); - //Serial.printf("hash %04X for \"%s\"\n", hash, filename); - while (index < maxfiles) { - n = 8; - if (n > maxfiles - index) n = maxfiles - index; - SerialFlash.read(8 + index * 2, hashtable, n * 2); - //Serial.printf(" read %u: ", 8 + index * 2); - //pbuf(hashtable, n * 2); - for (i=0; i < n; i++) { - if (hashtable[i] == hash) { - //Serial.printf(" hash match at index %u\n", index+i); - buf[2] = 0; - SerialFlash.read(8 + maxfiles * 2 + (index+i) * 10, buf, 10); - - //Serial.printf(" maxf=%d, index=%d, i=%d\n", maxfiles, index, i); - //Serial.printf(" read %u: ", 8 + maxfiles * 2 + (index+i) * 10); - //pbuf(buf, 10); - straddr = 8 + maxfiles * 12 + buf[2] * 4; - //Serial.printf(" straddr = %u\n", straddr); - if (filename_compare(filename, straddr)) { - //Serial.printf(" match!\n"); - //Serial.printf(" addr = %u\n", buf[0]); - //Serial.printf(" len = %u\n", buf[1]); - file.address = buf[0]; - file.length = buf[1]; - file.offset = 0; - file.dirindex = index + i; - return file; - } - } else if (hashtable[i] == 0xFFFF) { - return file; - } - } - index += n; - } - return file; -} - -bool SerialFlashChip::exists(const char *filename) -{ - SerialFlashFile file = open(filename); - return (bool)file; -} - -bool SerialFlashChip::remove(const char *filename) -{ - SerialFlashFile file = open(filename); - return remove(file); -} - -bool SerialFlashChip::remove(SerialFlashFile &file) -{ - // To "remove" a file, we simply zero its hash in the lookup - // table, so it can't be found by open(). The space on the - // flash memory is not freed. - if (!file) return false; - uint16_t hash; - SerialFlash.read(8 + file.dirindex * 2, &hash, 2); - //Serial.printf("remove hash %04X at %d index\n", hash, file.dirindex); - hash ^= 0xFFFF; // write zeros to all ones - SerialFlash.write(8 + file.dirindex * 2, &hash, 2); - while (!SerialFlash.ready()) ; // wait... TODO: timeout - SerialFlash.read(8 + file.dirindex * 2, &hash, 2); - if (hash != 0) { - //Serial.printf("remove failed, hash %04X\n", hash); - return false; - } - file.address = 0; - file.length = 0; - return true; -} - -static uint32_t find_first_unallocated_file_index(uint32_t maxfiles) -{ - uint16_t hashtable[8]; - uint32_t i, n, index=0; - - do { - n = 8; - if (index + n > maxfiles) n = maxfiles - index; - SerialFlash.read(8 + index * 2, hashtable, n * 2); - for (i=0; i < n; i++) { - if (hashtable[i] == 0xFFFF) return index + i; - } - index += n; - } while (index < maxfiles); - return 0xFFFFFFFF; -} - -static uint32_t string_length(uint32_t addr) -{ - char buf[16]; - const char *p; - uint32_t len=0; - - while (1) { - SerialFlash.read(addr, buf, sizeof(buf)); - for (p=buf; p < buf + sizeof(buf); p++) { - len++; - if (*p == 0) return len; - } - addr += sizeof(buf); - } -} - -// uint32_t signature = 0xFA96554C; -// uint16_t maxfiles -// uint16_t stringssize // div by 4 -// uint16_t hashes[maxfiles] -// struct { -// uint32_t file_begin -// uint32_t file_length -// uint16_t string_index // div 4 -// } fileinfo[maxfiles] -// char strings[stringssize] - -bool SerialFlashChip::create(const char *filename, uint32_t length, uint32_t align) -{ - uint32_t maxfiles, stringsize; - uint32_t index, buf[3]; - uint32_t address, straddr, len; - SerialFlashFile file; - - // check if the file already exists - if (exists(filename)) return false; - - // first, get the filesystem parameters - maxfiles = check_signature(); - if (!maxfiles) return false; - stringsize = (maxfiles & 0xFFFF0000) >> 14; - maxfiles &= 0xFFFF; - - // find the first unused slot for this file - index = find_first_unallocated_file_index(maxfiles); - if (index >= maxfiles) return false; - //Serial.printf("index = %u\n", index); - // compute where to store the filename and actual data - straddr = 8 + maxfiles * 12; - if (index == 0) { - address = straddr + stringsize; - } else { - buf[2] = 0; - SerialFlash.read(8 + maxfiles * 2 + (index-1) * 10, buf, 10); - address = buf[0] + buf[1]; - straddr += buf[2] * 4; - straddr += string_length(straddr); - straddr = (straddr + 3) & 0x0003FFFC; - } - //Serial.printf("straddr = %u\n", straddr); - //Serial.printf("address = %u\n", address); - //Serial.printf("length = %u\n", length); - if (align > 0) { - // for files aligned to sectors, adjust addr & len - address += align - 1; - address /= align; - address *= align; - //Serial.printf("align address = %u\n", address); - length += align - 1; - length /= align; - length *= align; - //Serial.printf("align length = %u\n", length); - } else { - // always align every file to a page boundary - // for predictable write latency and to guarantee - // write suspend for reading another file can't - // conflict on the same page (2 files never share - // a write page). - address = (address + 255) & 0xFFFFFF00; - } - //Serial.printf("address = %u\n", address); - // last check, if enough space exists... - len = strlen(filename); - // TODO: check for enough string space for filename - - // 5 bytes, to allow for extra 2 bytes in Spansion device IDs - uint8_t id[5]; - SerialFlash.readID(id); - if (address + length > SerialFlash.capacity(id)) return false; - - SerialFlash.write(straddr, filename, len+1); - buf[0] = address; - buf[1] = length; - buf[2] = (straddr - (8 + maxfiles * 12)) / 4; - SerialFlash.write(8 + maxfiles * 2 + index * 10, buf, 10); - //Serial.printf(" write %u: ", 8 + maxfiles * 2 + index * 10); - //pbuf(buf, 10); - while (!SerialFlash.ready()) ; // TODO: timeout - - buf[0] = filename_hash(filename); - //Serial.printf("hash = %04X\n", buf[0]); - SerialFlash.write(8 + index * 2, buf, 2); - while (!SerialFlash.ready()) ; // TODO: timeout - return true; -} - -bool SerialFlashChip::readdir(char *filename, uint32_t strsize, uint32_t &filesize) -{ - uint32_t maxfiles, index, straddr; - uint32_t i, n; - uint32_t buf[2]; - uint16_t hash; - char str[16], *p=filename; - - filename[0] = 0; - maxfiles = check_signature(); - if (!maxfiles) return false; - maxfiles &= 0xFFFF; - index = dirindex; - while (1) { - if (index >= maxfiles) return false; - //Serial.printf("readdir, index = %u\n", index); - SerialFlash.read(8 + index * 2, &hash, 2); - if (hash != 0) break; - index++; // skip deleted entries - } - dirindex = index + 1; - buf[1] = 0; - SerialFlash.read(8 + 4 + maxfiles * 2 + index * 10, buf, 6); - if (buf[0] == 0xFFFFFFFF) return false; - filesize = buf[0]; - straddr = 8 + maxfiles * 12 + buf[1] * 4; - //Serial.printf(" length = %u\n", buf[0]); - //Serial.printf(" straddr = %u\n", straddr); - - while (strsize) { - n = strsize; - if (n > sizeof(str)) n = sizeof(str); - SerialFlash.read(straddr, str, n); - for (i=0; i < n; i++) { - *p++ = str[i]; - if (str[i] == 0) { - //Serial.printf(" name = %s\n", filename); - return true; - } - } - strsize -= n; - straddr += n; - } - *(p - 1) = 0; - //Serial.printf(" name(overflow) = %s\n", filename); - return true; -} - - -void SerialFlashFile::erase() -{ - uint32_t i, blocksize; - - blocksize = SerialFlash.blockSize(); - if (address & (blocksize - 1)) return; // must begin on a block boundary - if (length & (blocksize - 1)) return; // must be exact number of blocks - for (i=0; i < length; i += blocksize) { - SerialFlash.eraseBlock(address + i); - } -} - diff --git a/libraries/SerialFlash/keywords.txt b/libraries/SerialFlash/keywords.txt deleted file mode 100644 index 1e473961..00000000 --- a/libraries/SerialFlash/keywords.txt +++ /dev/null @@ -1,9 +0,0 @@ -SerialFlash KEYWORD1 -SerialFlashFile KEYWORD1 -createWritable KEYWORD2 -erase KEYWORD2 -eraseAll KEYWORD2 -ready KEYWORD2 -create KEYWORD2 -createWritable KEYWORD2 -getAddress KEYWORD2 diff --git a/libraries/SerialFlash/util/SerialFlash_directwrite.h b/libraries/SerialFlash/util/SerialFlash_directwrite.h deleted file mode 100644 index d323a055..00000000 --- a/libraries/SerialFlash/util/SerialFlash_directwrite.h +++ /dev/null @@ -1,204 +0,0 @@ -#ifndef SerialFlash_directwrite_h -#define SerialFlash_directwrite_h - -#include - -// Adapted from OneWire.h - -#if ARDUINO >= 100 -#include "Arduino.h" // for delayMicroseconds, digitalPinToBitMask, etc -#else -#include "WProgram.h" // for delayMicroseconds -#include "pins_arduino.h" // for digitalPinToBitMask, etc -#endif - -// Platform specific I/O definitions - -#if defined(__AVR__) -#define PIN_TO_BASEREG(pin) (portInputRegister(digitalPinToPort(pin))) -#define PIN_TO_BITMASK(pin) (digitalPinToBitMask(pin)) -#define IO_REG_TYPE uint8_t -#define IO_REG_ASM asm("r30") -#define DIRECT_READ(base, mask) (((*(base)) & (mask)) ? 1 : 0) -#define DIRECT_MODE_INPUT(base, mask) ((*((base)+1)) &= ~(mask)) -#define DIRECT_MODE_OUTPUT(base, mask) ((*((base)+1)) |= (mask)) -#define DIRECT_WRITE_LOW(base, mask) ((*((base)+2)) &= ~(mask)) -#define DIRECT_WRITE_HIGH(base, mask) ((*((base)+2)) |= (mask)) - -#elif defined(__MK20DX128__) || defined(__MK20DX256__) || defined(__MK66FX1M0__) || defined(__MK64FX512__) -#define PIN_TO_BASEREG(pin) (portOutputRegister(pin)) -#define PIN_TO_BITMASK(pin) (1) -#define IO_REG_TYPE uint8_t -#define IO_REG_ASM -#define DIRECT_READ(base, mask) (*((base)+512)) -#define DIRECT_MODE_INPUT(base, mask) (*((base)+640) = 0) -#define DIRECT_MODE_OUTPUT(base, mask) (*((base)+640) = 1) -#define DIRECT_WRITE_LOW(base, mask) (*((base)+256) = 1) -#define DIRECT_WRITE_HIGH(base, mask) (*((base)+128) = 1) - -#elif defined(__MKL26Z64__) -#define PIN_TO_BASEREG(pin) (portOutputRegister(pin)) -#define PIN_TO_BITMASK(pin) (digitalPinToBitMask(pin)) -#define IO_REG_TYPE uint8_t -#define IO_REG_ASM -#define DIRECT_READ(base, mask) ((*((base)+16) & (mask)) ? 1 : 0) -#define DIRECT_MODE_INPUT(base, mask) (*((base)+20) &= ~(mask)) -#define DIRECT_MODE_OUTPUT(base, mask) (*((base)+20) |= (mask)) -#define DIRECT_WRITE_LOW(base, mask) (*((base)+8) = (mask)) -#define DIRECT_WRITE_HIGH(base, mask) (*((base)+4) = (mask)) - -#elif defined(__SAM3X8E__) -#define PIN_TO_BASEREG(pin) (&(digitalPinToPort(pin)->PIO_PER)) -#define PIN_TO_BITMASK(pin) (digitalPinToBitMask(pin)) -#define IO_REG_TYPE uint32_t -#define IO_REG_ASM -#define DIRECT_READ(base, mask) (((*((base)+15)) & (mask)) ? 1 : 0) -#define DIRECT_MODE_INPUT(base, mask) ((*((base)+5)) = (mask)) -#define DIRECT_MODE_OUTPUT(base, mask) ((*((base)+4)) = (mask)) -#define DIRECT_WRITE_LOW(base, mask) ((*((base)+13)) = (mask)) -#define DIRECT_WRITE_HIGH(base, mask) ((*((base)+12)) = (mask)) -#ifndef PROGMEM -#define PROGMEM -#endif -#ifndef pgm_read_byte -#define pgm_read_byte(addr) (*(const uint8_t *)(addr)) -#endif - -#elif defined(__PIC32MX__) -#define PIN_TO_BASEREG(pin) (portModeRegister(digitalPinToPort(pin))) -#define PIN_TO_BITMASK(pin) (digitalPinToBitMask(pin)) -#define IO_REG_TYPE uint32_t -#define IO_REG_ASM -#define DIRECT_READ(base, mask) (((*(base+4)) & (mask)) ? 1 : 0) //PORTX + 0x10 -#define DIRECT_MODE_INPUT(base, mask) ((*(base+2)) = (mask)) //TRISXSET + 0x08 -#define DIRECT_MODE_OUTPUT(base, mask) ((*(base+1)) = (mask)) //TRISXCLR + 0x04 -#define DIRECT_WRITE_LOW(base, mask) ((*(base+8+1)) = (mask)) //LATXCLR + 0x24 -#define DIRECT_WRITE_HIGH(base, mask) ((*(base+8+2)) = (mask)) //LATXSET + 0x28 - -#elif defined(ARDUINO_ARCH_ESP8266) -#define PIN_TO_BASEREG(pin) ((volatile uint32_t*) GPO) -#define PIN_TO_BITMASK(pin) (1 << pin) -#define IO_REG_TYPE uint32_t -#define IO_REG_ASM -#define DIRECT_READ(base, mask) ((GPI & (mask)) ? 1 : 0) //GPIO_IN_ADDRESS -#define DIRECT_MODE_INPUT(base, mask) (GPE &= ~(mask)) //GPIO_ENABLE_W1TC_ADDRESS -#define DIRECT_MODE_OUTPUT(base, mask) (GPE |= (mask)) //GPIO_ENABLE_W1TS_ADDRESS -#define DIRECT_WRITE_LOW(base, mask) (GPOC = (mask)) //GPIO_OUT_W1TC_ADDRESS -#define DIRECT_WRITE_HIGH(base, mask) (GPOS = (mask)) //GPIO_OUT_W1TS_ADDRESS - -#elif defined(__SAMD21G18A__) -#define PIN_TO_BASEREG(pin) portModeRegister(digitalPinToPort(pin)) -#define PIN_TO_BITMASK(pin) (digitalPinToBitMask(pin)) -#define IO_REG_TYPE uint32_t -#define IO_REG_ASM -#define DIRECT_READ(base, mask) (((*((base)+8)) & (mask)) ? 1 : 0) -#define DIRECT_MODE_INPUT(base, mask) ((*((base)+1)) = (mask)) -#define DIRECT_MODE_OUTPUT(base, mask) ((*((base)+2)) = (mask)) -#define DIRECT_WRITE_LOW(base, mask) ((*((base)+5)) = (mask)) -#define DIRECT_WRITE_HIGH(base, mask) ((*((base)+6)) = (mask)) - -#elif defined(RBL_NRF51822) -#define PIN_TO_BASEREG(pin) (0) -#define PIN_TO_BITMASK(pin) (pin) -#define IO_REG_TYPE uint32_t -#define IO_REG_ASM -#define DIRECT_READ(base, pin) nrf_gpio_pin_read(pin) -#define DIRECT_WRITE_LOW(base, pin) nrf_gpio_pin_clear(pin) -#define DIRECT_WRITE_HIGH(base, pin) nrf_gpio_pin_set(pin) -#define DIRECT_MODE_INPUT(base, pin) nrf_gpio_cfg_input(pin, NRF_GPIO_PIN_NOPULL) -#define DIRECT_MODE_OUTPUT(base, pin) nrf_gpio_cfg_output(pin) - -#elif defined(__arc__) /* Arduino101/Genuino101 specifics */ - -#include "scss_registers.h" -#include "portable.h" -#include "avr/pgmspace.h" - -#define GPIO_ID(pin) (g_APinDescription[pin].ulGPIOId) -#define GPIO_TYPE(pin) (g_APinDescription[pin].ulGPIOType) -#define GPIO_BASE(pin) (g_APinDescription[pin].ulGPIOBase) -#define DIR_OFFSET_SS 0x01 -#define DIR_OFFSET_SOC 0x04 -#define EXT_PORT_OFFSET_SS 0x0A -#define EXT_PORT_OFFSET_SOC 0x50 - -/* GPIO registers base address */ -#define PIN_TO_BASEREG(pin) ((volatile uint32_t *)g_APinDescription[pin].ulGPIOBase) -#define PIN_TO_BITMASK(pin) pin -#define IO_REG_TYPE uint32_t -#define IO_REG_ASM - -static inline __attribute__((always_inline)) -IO_REG_TYPE directRead(volatile IO_REG_TYPE *base, IO_REG_TYPE pin) -{ - IO_REG_TYPE ret; - if (SS_GPIO == GPIO_TYPE(pin)) { - ret = READ_ARC_REG(((IO_REG_TYPE)base + EXT_PORT_OFFSET_SS)); - } else { - ret = MMIO_REG_VAL_FROM_BASE((IO_REG_TYPE)base, EXT_PORT_OFFSET_SOC); - } - return ((ret >> GPIO_ID(pin)) & 0x01); -} - -static inline __attribute__((always_inline)) -void directModeInput(volatile IO_REG_TYPE *base, IO_REG_TYPE pin) -{ - if (SS_GPIO == GPIO_TYPE(pin)) { - WRITE_ARC_REG(READ_ARC_REG((((IO_REG_TYPE)base) + DIR_OFFSET_SS)) & ~(0x01 << GPIO_ID(pin)), - ((IO_REG_TYPE)(base) + DIR_OFFSET_SS)); - } else { - MMIO_REG_VAL_FROM_BASE((IO_REG_TYPE)base, DIR_OFFSET_SOC) &= ~(0x01 << GPIO_ID(pin)); - } -} - -static inline __attribute__((always_inline)) -void directModeOutput(volatile IO_REG_TYPE *base, IO_REG_TYPE pin) -{ - if (SS_GPIO == GPIO_TYPE(pin)) { - WRITE_ARC_REG(READ_ARC_REG(((IO_REG_TYPE)(base) + DIR_OFFSET_SS)) | (0x01 << GPIO_ID(pin)), - ((IO_REG_TYPE)(base) + DIR_OFFSET_SS)); - } else { - MMIO_REG_VAL_FROM_BASE((IO_REG_TYPE)base, DIR_OFFSET_SOC) |= (0x01 << GPIO_ID(pin)); - } -} - -static inline __attribute__((always_inline)) -void directWriteLow(volatile IO_REG_TYPE *base, IO_REG_TYPE pin) -{ - if (SS_GPIO == GPIO_TYPE(pin)) { - WRITE_ARC_REG(READ_ARC_REG(base) & ~(0x01 << GPIO_ID(pin)), base); - } else { - MMIO_REG_VAL(base) &= ~(0x01 << GPIO_ID(pin)); - } -} - -static inline __attribute__((always_inline)) -void directWriteHigh(volatile IO_REG_TYPE *base, IO_REG_TYPE pin) -{ - if (SS_GPIO == GPIO_TYPE(pin)) { - WRITE_ARC_REG(READ_ARC_REG(base) | (0x01 << GPIO_ID(pin)), base); - } else { - MMIO_REG_VAL(base) |= (0x01 << GPIO_ID(pin)); - } -} - -#define DIRECT_READ(base, pin) directRead(base, pin) -#define DIRECT_MODE_INPUT(base, pin) directModeInput(base, pin) -#define DIRECT_MODE_OUTPUT(base, pin) directModeOutput(base, pin) -#define DIRECT_WRITE_LOW(base, pin) directWriteLow(base, pin) -#define DIRECT_WRITE_HIGH(base, pin) directWriteHigh(base, pin) - -#else -#define PIN_TO_BASEREG(pin) (0) -#define PIN_TO_BITMASK(pin) (pin) -#define IO_REG_TYPE unsigned int -#define IO_REG_ASM -#define DIRECT_READ(base, pin) digitalRead(pin) -#define DIRECT_WRITE_LOW(base, pin) digitalWrite(pin, LOW) -#define DIRECT_WRITE_HIGH(base, pin) digitalWrite(pin, HIGH) -#define DIRECT_MODE_INPUT(base, pin) pinMode(pin,INPUT) -#define DIRECT_MODE_OUTPUT(base, pin) pinMode(pin,OUTPUT) - -#endif - -#endif diff --git a/libraries/Wire/examples/bus_scan/bus_scan.ino b/libraries/Wire/examples/bus_scan/bus_scan.ino index 65fc0946..22ef7495 100644 --- a/libraries/Wire/examples/bus_scan/bus_scan.ino +++ b/libraries/Wire/examples/bus_scan/bus_scan.ino @@ -47,7 +47,7 @@ void setup() while(!Serial); } -boolean toggle = false; // state of the LED +bool toggle = false; // state of the LED void loop() { toggle = !toggle; diff --git a/platform.txt b/platform.txt index 308ce967..66812628 100644 --- a/platform.txt +++ b/platform.txt @@ -5,7 +5,7 @@ # https://github.com/arduino/Arduino/wiki/Arduino-IDE-1.5---3rd-party-Hardware-specification name=Intel Curie (32-bit) Boards -version=2.0.0 +version=2.1.0 # Arduino 101 compile variables # ---------------------- @@ -71,8 +71,7 @@ recipe.ar.pattern="{compiler.path}{compiler.ar.cmd}" {compiler.ar.flags} {compil recipe.c.combine.pattern="{compiler.path}{compiler.c.elf.cmd}" {compiler.c.elf.flags} "-T{build.variant.path}/{build.ldscript}" "-Wl,-Map,{build.path}/{build.project_name}.map" {compiler.c.elf.extra_flags} -o "{build.path}/{build.project_name}.elf" "-L{build.path}" "-L{build.variant.path}" -Wl,--whole-archive "-l{build.variant_system_lib}" -Wl,--no-whole-archive -Wl,--start-group "-l{build.variant_system_lib}" -lnsim -lc -lm -lgcc {object_files} "{build.path}/{archive_file}" ## Save output with debug symbols (.debug.elf file). Uncomment if you wish to use OpenOCD to debug. -recipe.hooks.objcopy.preobjcopy.1.pattern=cp -f "{build.path}/{build.project_name}.elf" "{build.path}/../arduino101_sketch.debug.elf" -recipe.hooks.objcopy.preobjcopy.1.pattern.windows={runtime.tools.arduino101load.path}/arduino101load/arduino101copy.exe "{build.path}\{build.project_name}.elf" "{build.path}\..\arduino101_sketch.debug.elf" +recipe.hooks.objcopy.preobjcopy.1.pattern="{runtime.tools.arduino101load.path}/arduino101load" -c -from="{build.path}/{build.project_name}.elf" -to="{build.path}/../arduino101_sketch.debug.elf" ## Create output (.bin file) recipe.objcopy.bin.pattern="{compiler.path}{compiler.elf2bin.cmd}" {compiler.elf2bin.flags} {compiler.elf2hex.extra_flags} "{build.path}/{build.project_name}.elf" "{build.path}/{build.project_name}.bin" @@ -91,25 +90,29 @@ recipe.output.save_file={build.project_name}.{build.variant}.hex recipe.size.pattern="{compiler.path}{compiler.size.cmd}" -A "{build.path}/{build.project_name}.elf" recipe.size.regex=^(?:text|ctors|rodata|datas)\s+([0-9]+).* -# BLE firmware check +# Firmware check # ------------------- tools.arduino101load.ble.fw.string="ATP1BLE00R-1631C4439" tools.arduino101load.ble.fw.position=169984 +# Dummy RTOS walues - don't update RTOS if not strictly needed +tools.arduino101load.rtos.fw.string="firmware_1.8.0_arduino101" +tools.arduino101load.rtos.fw.position=147424 +#not ideal - should be inherited by the platform +tools.arduino101load.version=2.2.0 # Arc Uploader/Programmers tools # ------------------- -tools.arduino101load.cmd.path={runtime.tools.arduino101load.path}/arduino101load/arduino101load +tools.arduino101load.cmd.path={runtime.tools.arduino101load.path}/arduino101load -tools.arduino101load.upload.params.verbose=verbose -tools.arduino101load.upload.params.quiet=quiet +tools.arduino101load.upload.params.verbose=-v +tools.arduino101load.upload.params.quiet=-q -tools.arduino101load.upload.pattern="{cmd.path}" "{runtime.tools.arduino101load.path}/x86/bin" {build.path}/{build.project_name}.bin {serial.port} "{upload.verbose}" {ble.fw.string} {ble.fw.position} +tools.arduino101load.upload.pattern="{cmd.path}" "-dfu={runtime.tools.dfu-util.path}" "-bin={build.path}/{build.project_name}.bin" -port={serial.port} "{upload.verbose}" -ble_fw_str={ble.fw.string} -ble_fw_pos={ble.fw.position} -rtos_fw_str={rtos.fw.string} -rtos_fw_pos={rtos.fw.position} -core={version} # This is needed to avoid an error on unexistent fields tools.arduino101load.erase.params.verbose= tools.arduino101load.erase.params.quiet= tools.arduino101load.erase.pattern= -tools.arduino101load.bootloader.params.verbose= -tools.arduino101load.bootloader.params.quiet= -tools.arduino101load.bootloader.pattern={runtime.tools.flashpack.path}/flash_dfu.sh -tools.arduino101load.bootloader.pattern.windows={runtime.tools.flashpack.path}/flash_dfu.bat +tools.arduino101load.bootloader.params.verbose=-v +tools.arduino101load.bootloader.params.quiet=-q +tools.arduino101load.bootloader.pattern="{cmd.path}" "-dfu={runtime.tools.dfu-util.path}" -port={serial.port} "{bootloader.verbose}" -f -core={version} diff --git a/post_install.bat b/post_install.bat new file mode 100644 index 00000000..73e16e14 --- /dev/null +++ b/post_install.bat @@ -0,0 +1,10 @@ +@echo off +set ARGS=/A /SE /SW /SA +if "%PROCESSOR_ARCHITECTURE%" == "AMD64" ( + drivers\dpinst-amd64.exe %ARGS% +) ELSE IF "%PROCESSOR_ARCHITEW6432%" == "AMD64" ( + drivers\dpinst-amd64.exe %ARGS% +) ELSE ( + drivers\dpinst-x86.exe %ARGS% +) +exit /b 0 diff --git a/scripts/create_dfu_udev_rule b/scripts/create_dfu_udev_rule new file mode 100755 index 00000000..4e64ea64 --- /dev/null +++ b/scripts/create_dfu_udev_rule @@ -0,0 +1,17 @@ +#!/bin/bash +# + +if [ "$(id -u)" != "0" ]; then + echo "This script must be run as root" + exit +fi + +NAME=99-arduino-101.rules + +echo >/etc/udev/rules.d/$NAME +echo \# Arduino 101 in DFU Mode >>/etc/udev/rules.d/$NAME +echo SUBSYSTEM==\"tty\", ENV{ID_REVISION}==\"8087\", ENV{ID_MODEL_ID}==\"0ab6\", MODE=\"0666\", ENV{ID_MM_DEVICE_IGNORE}=\"1\", ENV{ID_MM_CANDIDATE}=\"0\" >>/etc/udev/rules.d/$NAME +echo SUBSYSTEM==\"usb\", ATTR{idVendor}==\"8087\", ATTR{idProduct}==\"0aba\", MODE=\"0666\", ENV{ID_MM_DEVICE_IGNORE}=\"1\" >>/etc/udev/rules.d/$NAME + +udevadm control --reload-rules +udevadm trigger diff --git a/system/libarc32_arduino101/Makefile b/system/libarc32_arduino101/Makefile index a9ef7d07..bccd2ab3 100644 --- a/system/libarc32_arduino101/Makefile +++ b/system/libarc32_arduino101/Makefile @@ -17,6 +17,7 @@ C_SRC+=$(wildcard $(PWD)/framework/src/os/*.c) ARCH=ARC CC=arc-elf32-gcc AS=arc-elf32-as +STRIP=arc-elf32-strip RM=rm -f INSTALL=install @@ -56,6 +57,9 @@ $(TARGET_LIB): $(C_OBJ) $(ASM_OBJ) @echo "Link $@" @$(AR) rcs $@ $^ +strip: $(TARGET_LIB) + @$(STRIP) --strip-unneeded $^ + %.o: %.S @echo "Assembling $<" $(CC) -c $(CFLAGS) $< -o $@ diff --git a/system/libarc32_arduino101/drivers/ns16550.c b/system/libarc32_arduino101/drivers/ns16550.c index f4e529e5..575d43af 100644 --- a/system/libarc32_arduino101/drivers/ns16550.c +++ b/system/libarc32_arduino101/drivers/ns16550.c @@ -340,7 +340,7 @@ unsigned char uart_poll_out( ) { /* wait for transmitter to ready to accept a character */ - while ((INBYTE(LSR(which)) & LSR_TEMT) == 0) + while ((INBYTE(LSR(which)) & LSR_THRE) == 0) ; OUTBYTE(THR(which), outChar); @@ -352,6 +352,8 @@ unsigned char uart_poll_out( * * uart_fifo_fill - fill FIFO with data * +* It is up to the caller to make sure that FIFO capcity is not exceeded +* * RETURNS: number of bytes sent */ @@ -362,8 +364,9 @@ int uart_fifo_fill(int which, /* UART on which to send */ { int i; - for (i = 0; i < size && (INBYTE(LSR(which)) & - LSR_BOTH_EMPTY) != 0; i++) { + for (i = 0; i < size && (INBYTE(LSR(which)) & + LSR_BOTH_EMPTY) != 0; i++) + { OUTBYTE(THR(which), txData[i]); } return i; @@ -622,7 +625,6 @@ void uart_int_connect(int which, /* UART to which to connect */ ) { interrupt_connect((unsigned int)uart[which].irq, isr); - interrupt_priority_set ((int)uart[which].irq, uart[which].intPri); interrupt_enable((unsigned int)uart[which].irq); /* set the Host Processor Interrupt Routing Mask */ SOC_UNMASK_INTERRUPTS(INT_UART_0_MASK + (which * UART_REG_ADDR_INTERVAL)); @@ -641,6 +643,19 @@ uint8_t uart_tx_complete(int which) return INBYTE(LSR(which)) & LSR_TEMT; } +/******************************************************************************* +* +* uart_tx_complete - check if tx holding register is empty +* +* RETURNS: zero if register is non-empty, +* non-zero if register is empty (ready to receive new data) +*/ + +uint8_t uart_tx_ready(int which) +{ + return INBYTE(LSR(which)) & LSR_THRE; +} + /******************************************************************************* * * uart_loop_enable - enable loopback diff --git a/system/libarc32_arduino101/drivers/soc_gpio.c b/system/libarc32_arduino101/drivers/soc_gpio.c index c06f14e4..382f8c61 100644 --- a/system/libarc32_arduino101/drivers/soc_gpio.c +++ b/system/libarc32_arduino101/drivers/soc_gpio.c @@ -34,6 +34,7 @@ #include "soc_register.h" #include "portable.h" +#include "platform.h" #define GPIO_CLKENA_POS (31) #define GPIO_LS_SYNC_POS (0) @@ -429,6 +430,8 @@ static void soc_gpio_ISR_proc( uint32_t dev_id ) uint32_t status = MMIO_REG_VAL_FROM_BASE(dev->reg_base, SOC_GPIO_INTSTATUS); // Mask the pending interrupts MMIO_REG_VAL_FROM_BASE(dev->reg_base, SOC_GPIO_INTMASK) |= status; + // Save a copy of the INTSTATUS register + shared_data->pm_int_status = status; // Clear interrupt flag (write 1 to clear) MMIO_REG_VAL_FROM_BASE(dev->reg_base, SOC_GPIO_PORTA_EOI) = status; diff --git a/system/libarc32_arduino101/drivers/soc_gpio.h b/system/libarc32_arduino101/drivers/soc_gpio.h index 401011cb..a2623f2d 100644 --- a/system/libarc32_arduino101/drivers/soc_gpio.h +++ b/system/libarc32_arduino101/drivers/soc_gpio.h @@ -43,6 +43,7 @@ #include "data_type.h" #include "gpio.h" +#include "platform.h" // soc gpio 32 bit count #if defined(CONFIG_SOC_GPIO_32) diff --git a/system/libarc32_arduino101/drivers/ss_gpio_iface.c b/system/libarc32_arduino101/drivers/ss_gpio_iface.c index 9d8543b6..fad7743e 100644 --- a/system/libarc32_arduino101/drivers/ss_gpio_iface.c +++ b/system/libarc32_arduino101/drivers/ss_gpio_iface.c @@ -37,6 +37,7 @@ #include "io_config.h" #include "eiaextensions.h" #include "portable.h" +#include "platform.h" /* EIA GPIO device registers */ #define SWPORTA_DR (0x00) /* GPIO Port A Data Register*/ @@ -355,6 +356,8 @@ static void ss_gpio_ISR_proc( uint32_t dev_id ) uint32_t status = REG_READ( INTSTATUS ); /* Mask the pending IRQ in order to avoid a storm of interrupts */ REG_WRITE(INTMASK, REG_READ(INTMASK) | status); + // Save a copy of the INTSTATUS register + shared_data->pm_int_status = status; // Clear interrupt flag (write 1 to clear) REG_WRITE( PORTA_EOI, status ); diff --git a/system/libarc32_arduino101/drivers/ss_gpio_iface.h b/system/libarc32_arduino101/drivers/ss_gpio_iface.h index 86630387..58acfc7b 100644 --- a/system/libarc32_arduino101/drivers/ss_gpio_iface.h +++ b/system/libarc32_arduino101/drivers/ss_gpio_iface.h @@ -41,6 +41,7 @@ #include "data_type.h" #include "gpio.h" +#include "platform.h" #define SS_GPIO_8B0_BITS (8) #define SS_GPIO_8B1_BITS (8) diff --git a/system/libarc32_arduino101/framework/include/platform.h b/system/libarc32_arduino101/framework/include/platform.h index 583fcf71..801f87f5 100644 --- a/system/libarc32_arduino101/framework/include/platform.h +++ b/system/libarc32_arduino101/framework/include/platform.h @@ -40,6 +40,7 @@ #define NUM_CPU 4 #define CDCACM_BUFFER_SIZE 256 +#define SHARED_BUFFER_SIZE 64 struct cdc_ring_buffer { @@ -62,6 +63,30 @@ struct cdc_acm_shared_data { int device_open; }; +struct shared_ring_buffer +{ + /** Ring buffer data */ + volatile uint8_t data[SHARED_BUFFER_SIZE]; + /** Ring buffer head index, modified by producer */ + volatile int head; + /** Ring buffer tail index, modified by consumer */ + volatile int tail; + + /** Buffer status + * 0 - locked by X86 core + * 1 - locked by arc core + * 2 - available to be taken by any core + **/ + volatile int flag; +}; + +struct ipm_shared_data +{ + struct shared_ring_buffer *quark_buffer; + struct shared_ring_buffer *arc_buffer; +}; + + /** * LMT / ARC global shared structure. This structure lies in the beginning of * the RAM. @@ -109,6 +134,30 @@ struct platform_shared_block_ { * The ARC core counts on QRK to find valid pointers in place. */ struct cdc_acm_shared_data * cdc_acm_buffers; + + struct cdc_acm_shared_data cdc_acm_buffers_obj; + + struct cdc_ring_buffer cdc_acm_shared_rx_buffer; + struct cdc_ring_buffer cdc_acm_shared_tx_buffer; + + struct ipm_shared_data *ipm_shared_data_ptr; + + struct ipm_shared_data ipm_shared_data_obj; + + struct shared_ring_buffer quark_to_ARC; + struct shared_ring_buffer ARC_to_quark; + + uint32_t arc_cpu_context[33]; + + uint32_t pm_status; + + void* arc_restore_addr; + + void* quark_restore_addr; + + uint32_t pm_int_status; + + uint8_t error_code; }; #define RAM_START 0xA8000000 diff --git a/variants/arduino_101/libarc32drv_arduino101.a b/variants/arduino_101/libarc32drv_arduino101.a index e739392b..db6e5b45 100644 Binary files a/variants/arduino_101/libarc32drv_arduino101.a and b/variants/arduino_101/libarc32drv_arduino101.a differ diff --git a/variants/arduino_101/linker_scripts/flash.ld b/variants/arduino_101/linker_scripts/flash.ld index 03344a54..7ba34942 100644 --- a/variants/arduino_101/linker_scripts/flash.ld +++ b/variants/arduino_101/linker_scripts/flash.ld @@ -40,7 +40,7 @@ OUTPUT_FORMAT("elf32-littlearc", "elf32-bigarc", "elf32-littlearc") MEMORY { FLASH (rx) : ORIGIN = 0x40034000, LENGTH = 152K - SRAM (wx) : ORIGIN = 0xa800e000, LENGTH = 24K + SRAM (wx) : ORIGIN = 0xa800a000, LENGTH = 40K DCCM (wx) : ORIGIN = 0x80000000, LENGTH = 8K } @@ -52,7 +52,7 @@ __firq_stack_size = 1024; /* Minimum heap size to allocate * Actual heap size might be bigger due to page size alignment */ -__HEAP_SIZE_MIN = 8192; +__HEAP_SIZE_MIN = 16384; /* This should be set to the page size used by the malloc implementation */ __PAGE_SIZE = 4096; @@ -113,6 +113,7 @@ SECTIONS __data_ram_start = .; *(.data) *(".data.*") + . = ALIGN(4); } > SRAM __data_ram_end = .; diff --git a/variants/arduino_101/pins_arduino.h b/variants/arduino_101/pins_arduino.h index e447277c..8be94f07 100644 --- a/variants/arduino_101/pins_arduino.h +++ b/variants/arduino_101/pins_arduino.h @@ -25,7 +25,7 @@ #ifndef Pins_Arduino_h #define Pins_Arduino_h -#define NUM_DIGITAL_PINS 29 +#define NUM_DIGITAL_PINS 32 #define NUM_ANALOG_INPUTS 6 #define NUM_PWM 4 #define NUM_UARTS 1 diff --git a/variants/arduino_101/variant.cpp b/variants/arduino_101/variant.cpp index 6993d2f5..ebcf884c 100644 --- a/variants/arduino_101/variant.cpp +++ b/variants/arduino_101/variant.cpp @@ -21,6 +21,7 @@ #include "cfw_platform.h" #include "platform.h" +#include "mailbox.h" // Add for debug corelib #ifdef CONFIGURE_DEBUG_CORELIB_ENABLED @@ -87,15 +88,18 @@ PinDescription g_APinDescription[]= { 5, SS_GPIO_8B0, SS_GPIO, SS_GPIO_8B0_BASE_ADDR, 13, GPIO_MUX_MODE, INVALID, INVALID, 13, INPUT_MODE }, // Arduino IO17 { 6, SS_GPIO_8B0, SS_GPIO, SS_GPIO_8B0_BASE_ADDR, 14, GPIO_MUX_MODE, INVALID, INVALID, 14, INPUT_MODE }, // Arduino IO18 { 1, SS_GPIO_8B0, SS_GPIO, SS_GPIO_8B0_BASE_ADDR, 9, GPIO_MUX_MODE, INVALID, INVALID, 9, INPUT_MODE }, // Arduino IO19 - { 0, SS_GPIO_8B0, SS_GPIO, SS_GPIO_8B0_BASE_ADDR, 8, GPIO_MUX_MODE, INVALID, INVALID, INVALID, INPUT_MODE }, // Arduino IO20 + { 0, SS_GPIO_8B0, SS_GPIO, SS_GPIO_8B0_BASE_ADDR, 8, GPIO_MUX_MODE, INVALID, INVALID, INVALID, INPUT_MODE }, // Arduino IO20 { 24, SOC_GPIO_32, SOC_GPIO, SOC_GPIO_BASE_ADDR, 58, GPIO_MUX_MODE, INVALID, INVALID, INVALID, INPUT_MODE }, // Arduino IO21 { 12, SOC_GPIO_32, SOC_GPIO, SOC_GPIO_BASE_ADDR, 46, GPIO_MUX_MODE, INVALID, INVALID, INVALID, INPUT_MODE }, // Arduino IO22 { 13, SOC_GPIO_32, SOC_GPIO, SOC_GPIO_BASE_ADDR, 47, GPIO_MUX_MODE, INVALID, INVALID, INVALID, INPUT_MODE }, // Arduino IO23 { 14, SOC_GPIO_32, SOC_GPIO, SOC_GPIO_BASE_ADDR, 48, GPIO_MUX_MODE, INVALID, INVALID, INVALID, INPUT_MODE }, // Arduino IO24 { 26, SOC_GPIO_32, SOC_GPIO, SOC_GPIO_BASE_ADDR, 60, GPIO_MUX_MODE, INVALID, INVALID, INVALID, INPUT_MODE }, // Arduino IO25 - { 1, SOC_GPIO_32, SOC_GPIO, SOC_GPIO_AON_BASE_ADDR, 1, GPIO_MUX_MODE, INVALID, INVALID, INVALID, INPUT_MODE }, // Arduino IO26 - { 2, SOC_GPIO_32, SOC_GPIO, SOC_GPIO_AON_BASE_ADDR, 2, GPIO_MUX_MODE, INVALID, INVALID, INVALID, INPUT_MODE }, // Arduino IO27 - { 3, SOC_GPIO_32, SOC_GPIO, SOC_GPIO_AON_BASE_ADDR, 3, GPIO_MUX_MODE, INVALID, INVALID, INVALID, INPUT_MODE }, // Arduino IO28 + { 0, SOC_GPIO_32, SOC_GPIO, SOC_GPIO_AON_BASE_ADDR, 0, GPIO_MUX_MODE, INVALID, INVALID, INVALID, INPUT_MODE }, // Arduino IO26 *soft reset button + { 1, SOC_GPIO_32, SOC_GPIO, SOC_GPIO_AON_BASE_ADDR, 1, GPIO_MUX_MODE, INVALID, INVALID, INVALID, INPUT_MODE }, // Arduino IO27 + { 2, SOC_GPIO_32, SOC_GPIO, SOC_GPIO_AON_BASE_ADDR, 2, GPIO_MUX_MODE, INVALID, INVALID, INVALID, INPUT_MODE }, // Arduino IO28 + { 3, SOC_GPIO_32, SOC_GPIO, SOC_GPIO_AON_BASE_ADDR, 3, GPIO_MUX_MODE, INVALID, INVALID, INVALID, INPUT_MODE }, // Arduino IO29 + { 4, SOC_GPIO_32, SOC_GPIO, SOC_GPIO_AON_BASE_ADDR, 4, GPIO_MUX_MODE, INVALID, INVALID, INVALID, INPUT_MODE }, // Arduino IO30 *imu_int + { 5, SOC_GPIO_32, SOC_GPIO, SOC_GPIO_AON_BASE_ADDR, 5, GPIO_MUX_MODE, INVALID, INVALID, INVALID, INPUT_MODE }, // Arduino IO31 *ble_int } ; uint32_t pwmPeriod[] = {PWM_PERIOD, PWM_PERIOD/2, PWM_PERIOD/2, PWM_PERIOD}; @@ -176,6 +180,7 @@ void variantGpioInit(void) PinDescription *p = &g_APinDescription[pin]; SET_PIN_MODE(p->ulSocPin, p->ulPinMode); pinmuxMode[pin] = GPIO_MUX_MODE; + pinMode(pin, INPUT); } } @@ -250,6 +255,9 @@ void initVariant( void ) *SYS_CLK_CTL |= 1 << CCU_RTC_CLK_DIV_EN; cfw_platform_init(); + + /* Ready the mailbox for use (but don't initialise HW; x86 does that) */ + mailbox_init(false); // Add for debug corelib #ifdef CONFIGURE_DEBUG_CORELIB_ENABLED diff --git a/variants/arduino_101/variant.h b/variants/arduino_101/variant.h index 4ee93f05..2736252f 100644 --- a/variants/arduino_101/variant.h +++ b/variants/arduino_101/variant.h @@ -113,6 +113,12 @@ extern "C"{ * ADC */ +/* + * ONBOARD SPI FLASH + */ +#define ONBOARD_FLASH_SPI_PORT SPI1 +#define ONBOARD_FLASH_CS_PIN 21 + /* EAI ADC device registers */ #define ADC_SET (0x80015000) #define ADC_DIVSEQSTAT (0x80015001)