summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--boot_loader/bl_autobaud.c279
-rw-r--r--boot_loader/bl_can.c1403
-rw-r--r--boot_loader/bl_can.h64
-rw-r--r--boot_loader/bl_can_timing.h241
-rw-r--r--boot_loader/bl_check.c266
-rw-r--r--boot_loader/bl_check.h39
-rw-r--r--boot_loader/bl_commands.h242
-rw-r--r--boot_loader/bl_config.c164
-rw-r--r--boot_loader/bl_config.h.tmpl950
-rw-r--r--boot_loader/bl_crc32.c267
-rw-r--r--boot_loader/bl_crc32.h49
-rw-r--r--boot_loader/bl_crystal.h79
-rw-r--r--boot_loader/bl_decrypt.c64
-rw-r--r--boot_loader/bl_decrypt.h35
-rw-r--r--boot_loader/bl_emac.c1914
-rw-r--r--boot_loader/bl_flash.c218
-rw-r--r--boot_loader/bl_flash.h127
-rw-r--r--boot_loader/bl_hooks.h72
-rw-r--r--boot_loader/bl_i2c.c149
-rw-r--r--boot_loader/bl_i2c.h70
-rw-r--r--boot_loader/bl_link.icf83
-rw-r--r--boot_loader/bl_link.ld51
-rw-r--r--boot_loader/bl_link.sct45
-rw-r--r--boot_loader/bl_link_ccs.cmd63
-rw-r--r--boot_loader/bl_main.c913
-rw-r--r--boot_loader/bl_packet.c295
-rw-r--r--boot_loader/bl_packet.h37
-rw-r--r--boot_loader/bl_ssi.c161
-rw-r--r--boot_loader/bl_ssi.h92
-rw-r--r--boot_loader/bl_startup_ccs.s645
-rw-r--r--boot_loader/bl_startup_ewarm.S612
-rw-r--r--boot_loader/bl_startup_gcc.S630
-rw-r--r--boot_loader/bl_startup_rvmdk.S653
-rw-r--r--boot_loader/bl_startup_sourcerygxx.S630
-rw-r--r--boot_loader/bl_uart.c156
-rw-r--r--boot_loader/bl_uart.h81
-rw-r--r--boot_loader/bl_usb.c2166
-rw-r--r--boot_loader/bl_usbfuncs.c1915
-rw-r--r--boot_loader/bl_usbfuncs.h505
-rw-r--r--boot_loader/readme.txt28
-rw-r--r--boot_loader/uip-conf.h108
-rw-r--r--boot_loader/usbdfu.h420
-rw-r--r--nfclib/debug.h74
-rw-r--r--nfclib/directmode.c1059
-rw-r--r--nfclib/directmode.h78
-rw-r--r--nfclib/iso14443-4.c164
-rw-r--r--nfclib/iso14443-4.h33
-rw-r--r--nfclib/iso14443a.c1141
-rw-r--r--nfclib/iso14443a.h65
-rw-r--r--nfclib/iso14443b.c339
-rw-r--r--nfclib/iso14443b.h51
-rw-r--r--nfclib/iso15693.c694
-rw-r--r--nfclib/iso15693.h62
-rw-r--r--nfclib/llcp.c1051
-rw-r--r--nfclib/llcp.h248
-rw-r--r--nfclib/nfc.c241
-rw-r--r--nfclib/nfc.h42
-rw-r--r--nfclib/nfc_dep.c597
-rw-r--r--nfclib/nfc_dep.h109
-rw-r--r--nfclib/nfc_f.c166
-rw-r--r--nfclib/nfc_f.h48
-rw-r--r--nfclib/nfc_p2p.c1993
-rw-r--r--nfclib/nfc_p2p.h1536
-rw-r--r--nfclib/snep.c760
-rw-r--r--nfclib/snep.h206
-rw-r--r--nfclib/ssitrf79x0.c826
-rw-r--r--nfclib/ssitrf79x0.h62
-rw-r--r--nfclib/trf79x0.c1961
-rw-r--r--nfclib/trf79x0.h400
-rw-r--r--nfclib/trf79x0_hw_example.h489
-rw-r--r--nfclib/types.h36
-rw-r--r--sensorlib/Makefile88
-rw-r--r--sensorlib/ak8963.c666
-rw-r--r--sensorlib/ak8963.h160
-rw-r--r--sensorlib/ak8975.c558
-rw-r--r--sensorlib/ak8975.h148
-rw-r--r--sensorlib/bmp180.c919
-rw-r--r--sensorlib/bmp180.h207
-rw-r--r--sensorlib/bq27510g3.c1398
-rw-r--r--sensorlib/bq27510g3.h210
-rw-r--r--sensorlib/ccs/.ccsproject9
-rw-r--r--sensorlib/ccs/.cproject147
-rw-r--r--sensorlib/ccs/.project140
-rw-r--r--sensorlib/ccs/.settings/org.eclipse.cdt.codan.core.prefs3
-rw-r--r--sensorlib/ccs/Debug/sensorlib.libbin0 -> 953848 bytes
-rw-r--r--sensorlib/ccs/macros.ini_initial1
-rw-r--r--sensorlib/cm3218.c468
-rw-r--r--sensorlib/cm3218.h149
-rw-r--r--sensorlib/comp_dcm.c634
-rw-r--r--sensorlib/comp_dcm.h120
-rw-r--r--sensorlib/ewarm/Exe/sensorlib.abin0 -> 740558 bytes
-rw-r--r--sensorlib/gcc/libsensor.abin0 -> 87204 bytes
-rw-r--r--sensorlib/hw_ak8963.h209
-rw-r--r--sensorlib/hw_ak8975.h177
-rw-r--r--sensorlib/hw_bmp180.h349
-rw-r--r--sensorlib/hw_bq27510g3.h148
-rw-r--r--sensorlib/hw_cm3218.h96
-rw-r--r--sensorlib/hw_isl29023.h128
-rw-r--r--sensorlib/hw_kxti9.h619
-rw-r--r--sensorlib/hw_l3gd20h.h468
-rw-r--r--sensorlib/hw_lsm303d.h1017
-rw-r--r--sensorlib/hw_lsm303dlhc.h1034
-rw-r--r--sensorlib/hw_mpu6050.h1313
-rw-r--r--sensorlib/hw_mpu9150.h1454
-rw-r--r--sensorlib/hw_sht21.h76
-rw-r--r--sensorlib/hw_tmp006.h75
-rw-r--r--sensorlib/hw_tmp100.h93
-rw-r--r--sensorlib/i2cm_drv.c2256
-rw-r--r--sensorlib/i2cm_drv.h544
-rw-r--r--sensorlib/isl29023.c668
-rw-r--r--sensorlib/isl29023.h166
-rw-r--r--sensorlib/kxti9.c777
-rw-r--r--sensorlib/kxti9.h170
-rw-r--r--sensorlib/l3gd20h.c722
-rw-r--r--sensorlib/l3gd20h.h158
-rw-r--r--sensorlib/lsm303d.c835
-rw-r--r--sensorlib/lsm303d.h186
-rw-r--r--sensorlib/lsm303dlhc_accel.c662
-rw-r--r--sensorlib/lsm303dlhc_accel.h163
-rw-r--r--sensorlib/lsm303dlhc_mag.c615
-rw-r--r--sensorlib/lsm303dlhc_mag.h164
-rw-r--r--sensorlib/magneto.c248
-rw-r--r--sensorlib/magneto.h92
-rw-r--r--sensorlib/mpu6050.c879
-rw-r--r--sensorlib/mpu6050.h174
-rw-r--r--sensorlib/mpu9150.c1180
-rw-r--r--sensorlib/mpu9150.h187
-rw-r--r--sensorlib/quaternion.c286
-rw-r--r--sensorlib/quaternion.h70
-rw-r--r--sensorlib/readme.txt21
-rw-r--r--sensorlib/rvmdk/sensorlib.libbin0 -> 879928 bytes
-rw-r--r--sensorlib/sensorlib.ewp833
-rw-r--r--sensorlib/sensorlib.uvopt524
-rw-r--r--sensorlib/sensorlib.uvproj510
-rw-r--r--sensorlib/sht21.c564
-rw-r--r--sensorlib/sht21.h156
-rw-r--r--sensorlib/tmp006.c606
-rw-r--r--sensorlib/tmp006.h157
-rw-r--r--sensorlib/tmp100.c582
-rw-r--r--sensorlib/tmp100.h156
-rw-r--r--sensorlib/vector.c139
-rw-r--r--sensorlib/vector.h61
142 files changed, 60304 insertions, 0 deletions
diff --git a/boot_loader/bl_autobaud.c b/boot_loader/bl_autobaud.c
new file mode 100644
index 0000000..1600c71
--- /dev/null
+++ b/boot_loader/bl_autobaud.c
@@ -0,0 +1,279 @@
+//*****************************************************************************
+//
+// bl_autobaud.c - Automatic baud rate detection code.
+//
+// Copyright (c) 2006-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
+//
+//*****************************************************************************
+
+#include <stdint.h>
+#include "inc/hw_gpio.h"
+#include "inc/hw_memmap.h"
+#include "inc/hw_nvic.h"
+#include "inc/hw_types.h"
+#include "bl_config.h"
+#include "boot_loader/bl_uart.h"
+
+//*****************************************************************************
+//
+// If using auto-baud, make sure that the data buffer is large enough.
+//
+//*****************************************************************************
+#if defined(UART_ENABLE_UPDATE) && defined(UART_AUTOBAUD) && (BUFFER_SIZE < 20)
+#error ERROR: BUFFER_SIZE must be >= 20!
+#endif
+
+//*****************************************************************************
+//
+//! \addtogroup bl_autobaud_api
+//! @{
+//
+//*****************************************************************************
+#if defined(UART_ENABLE_UPDATE) && defined(UART_AUTOBAUD) || defined(DOXYGEN)
+
+//*****************************************************************************
+//
+// This define holds the multiplier for the pulse detection algorithm. The
+// value is used to generate a fractional difference detection of
+// 1 / PULSE_DETECTION_MULT.
+//
+//*****************************************************************************
+#define PULSE_DETECTION_MULT 3
+
+//*****************************************************************************
+//
+// This define holds the minimum number of edges to successfully sync to a
+// pattern of 2 bytes.
+//
+//*****************************************************************************
+#define MIN_EDGE_COUNT 18
+
+//*****************************************************************************
+//
+// This global holds the number of edges that have been stored in the global
+// buffer g_pui32DataBuffer.
+//
+//*****************************************************************************
+static volatile uint32_t g_ui32TickIndex;
+
+//*****************************************************************************
+//
+// The data buffer that is used for receiving packets is used to hold the edge
+// times during auto-baud. The buffer is not used for receiving packets while
+// auto-baud is in progress, so this does not present problems.
+//
+//*****************************************************************************
+extern uint32_t g_pui32DataBuffer[];
+
+//*****************************************************************************
+//
+//! Handles the UART Rx GPIO interrupt.
+//!
+//! When an edge is detected on the UART Rx pin, this function is called to
+//! save the time of the edge. These times are later used to determine the
+//! ratio of the UART baud rate to the processor clock rate.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+GPIOIntHandler(void)
+{
+ uint32_t ui32Temp;
+
+ //
+ // Clear the GPIO interrupt source.
+ //
+ HWREG(GPIO_PORTA_BASE + GPIO_O_ICR) = UART_RX;
+
+ //
+ // While we still have space in our buffer, store the current system tick
+ // count and return from interrupt.
+ //
+ if(g_ui32TickIndex < 20)
+ {
+ ui32Temp = HWREG(NVIC_ST_CURRENT);
+ g_pui32DataBuffer[g_ui32TickIndex++] = ui32Temp;
+ }
+}
+
+//*****************************************************************************
+//
+//! Performs auto-baud on the UART port.
+//!
+//! \param pui32Ratio is the ratio of the processor's crystal frequency to the
+//! baud rate being used by the UART port for communications.
+//!
+//! This function attempts to synchronize to the updater program that is trying
+//! to communicate with the boot loader. The UART port is monitored for edges
+//! using interrupts. Once enough edges are detected, the boot loader
+//! determines the ratio of baud rate and crystal frequency needed to program
+//! the UART.
+//!
+//! \return Returns a value of 0 to indicate that this call successfully
+//! synchronized with the other device communicating over the UART, and a
+//! negative value to indicate that this function did not successfully
+//! synchronize with the other UART device.
+//
+//*****************************************************************************
+int
+UARTAutoBaud(uint32_t *pui32Ratio)
+{
+ int32_t i32Pulse, i32ValidPulses, i32Temp, i32Total;
+ volatile int32_t i32Delay;
+
+ //
+ // Configure and enable SysTick. Set the reload value to the maximum;
+ // there are only 24 bits in the register but loading 32 bits of ones is
+ // more efficient.
+ //
+ HWREG(NVIC_ST_RELOAD) = 0xffffffff;
+ HWREG(NVIC_ST_CTRL) = NVIC_ST_CTRL_CLK_SRC | NVIC_ST_CTRL_ENABLE;
+
+ //
+ // Reset the counters that control the pulse detection.
+ //
+ i32ValidPulses = 0;
+ i32Total = 0;
+ g_ui32TickIndex = 0;
+
+ //
+ // Set the pad(s) for standard push-pull operation.
+ //
+ HWREG(GPIO_PORTA_BASE + GPIO_O_PUR) |= UART_RX;
+ HWREG(GPIO_PORTA_BASE + GPIO_O_DEN) |= UART_RX;
+
+ //
+ // Interrupt on both edges.
+ //
+ HWREG(GPIO_PORTA_BASE + GPIO_O_IBE) = UART_RX;
+
+ //
+ // Clear out all of the gpio interrupts in this register.
+ //
+ HWREG(GPIO_PORTA_BASE + GPIO_O_ICR) = UART_RX;
+
+ //
+ // Enable the GPIO pin corresponding to the UART RX pin.
+ //
+ HWREG(GPIO_PORTA_BASE + GPIO_O_IM) = UART_RX;
+
+ //
+ // Enable GPIOA Interrupt.
+ //
+ HWREG(NVIC_EN0) = 1;
+
+ //
+ // Wait for MIN_EDGE_COUNT to pass to collect enough edges.
+ //
+ while(g_ui32TickIndex < MIN_EDGE_COUNT)
+ {
+ }
+
+ //
+ // Disable GPIOA Interrupt.
+ //
+ HWREG(NVIC_DIS0) = 1;
+
+ //
+ // Calculate the pulse widths from the array of tick times.
+ //
+ for(i32Pulse = 0; i32Pulse < (MIN_EDGE_COUNT - 1); i32Pulse++)
+ {
+ i32Temp = (((int32_t)g_pui32DataBuffer[i32Pulse] -
+ (int32_t)g_pui32DataBuffer[i32Pulse + 1]) & 0x00ffffff);
+ g_pui32DataBuffer[i32Pulse] = i32Temp;
+ }
+
+ //
+ // This loops handles checking for consecutive pulses that have pulse
+ // widths that are within an acceptable margin.
+ //
+ for(i32Pulse = 0; i32Pulse < (MIN_EDGE_COUNT - 1); i32Pulse++)
+ {
+ //
+ // Calculate the absolute difference between two consecutive pulses.
+ //
+ i32Temp = (int32_t)g_pui32DataBuffer[i32Pulse];
+ i32Temp -= (int32_t)g_pui32DataBuffer[i32Pulse + 1];
+ if(i32Temp < 0)
+ {
+ i32Temp *= -1;
+ }
+
+ //
+ // This pulse detection code uses the following algorithm:
+ // If the following is true then we have consecutive acceptable pulses
+ // abs(Pulse[n] - Pulse[n + 1]) < Pulse[n + 1] / PULSE_DETECTION_MULT
+ // or
+ // PULSE_DETECTION_MULT * abs(Pulse[n] - Pulse[n + 1]) < Pulse[n + 1]
+ //
+ if((i32Temp * PULSE_DETECTION_MULT) <
+ (int32_t)g_pui32DataBuffer[i32Pulse + 1])
+ {
+ i32Total += (int32_t)g_pui32DataBuffer[i32Pulse];
+ i32ValidPulses++;
+ }
+ else
+ {
+ i32ValidPulses = 0;
+ i32Total = 0;
+ }
+
+ //
+ // Once we have 7 pulses calculate the ratio needed to program the
+ // UART.
+ //
+ if(i32ValidPulses == 7)
+ {
+ //
+ // Add in the last pulse and calculate the ratio.
+ //
+ i32Total += (int32_t)g_pui32DataBuffer[i32Pulse];
+ *pui32Ratio = i32Total >> 1;
+
+ //
+ // Wait for at least 2 UART clocks since we only wait for 18 of 20
+ // that are coming from the host. If we don't wait, we can turn
+ // on the UART while the last two pulses come down.
+ //
+ for(i32Delay = i32Total; i32Delay; i32Delay--)
+ {
+ }
+
+ //
+ // Indicate a successful auto baud operation.
+ //
+ return(0);
+ }
+ }
+
+ //
+ // Automatic baud rate detection failed.
+ //
+ return(-1);
+}
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
+#endif
diff --git a/boot_loader/bl_can.c b/boot_loader/bl_can.c
new file mode 100644
index 0000000..9cf5c0b
--- /dev/null
+++ b/boot_loader/bl_can.c
@@ -0,0 +1,1403 @@
+//*****************************************************************************
+//
+// bl_can.c - Functions to transfer data via the CAN port.
+//
+// Copyright (c) 2008-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
+//
+//*****************************************************************************
+
+#include <stdint.h>
+#include "inc/hw_can.h"
+#include "inc/hw_gpio.h"
+#include "inc/hw_memmap.h"
+#include "inc/hw_nvic.h"
+#include "inc/hw_flash.h"
+#include "inc/hw_sysctl.h"
+#include "inc/hw_types.h"
+#include "inc/hw_uart.h"
+#include "bl_config.h"
+#include "boot_loader/bl_can.h"
+#include "boot_loader/bl_can_timing.h"
+#include "boot_loader/bl_check.h"
+#include "boot_loader/bl_crystal.h"
+#include "boot_loader/bl_flash.h"
+#include "boot_loader/bl_hooks.h"
+#include "boot_loader/bl_uart.h"
+
+//*****************************************************************************
+//
+//! \addtogroup bl_can_api
+//! @{
+//
+//*****************************************************************************
+#if defined(CAN_ENABLE_UPDATE) || defined(DOXYGEN)
+
+//*****************************************************************************
+//
+// The results that can be returned by the CAN APIs.
+//
+//*****************************************************************************
+#define CAN_CMD_SUCCESS 0x00
+#define CAN_CMD_FAIL 0x01
+
+//*****************************************************************************
+//
+// Macros used to generate correct pin definitions.
+//
+//*****************************************************************************
+#define CAN_RX_PIN_M (1 << CAN_RX_PIN)
+#define CAN_TX_PIN_M (1 << CAN_TX_PIN)
+
+//*****************************************************************************
+//
+// Convenience macros for accessing CAN registers.
+//
+//*****************************************************************************
+#define CANRegWrite(ui32Address, ui32Value) \
+ HWREG(ui32Address) = ui32Value
+
+#define CANRegRead(ui32Address) \
+ HWREG(ui32Address)
+
+//*****************************************************************************
+//
+// The message object number and index to the local message object memory to
+// use when accessing the messages.
+//
+//*****************************************************************************
+#define MSG_OBJ_BCAST_RX_ID 1
+#define MSG_OBJ_BCAST_TX_ID 2
+
+//*****************************************************************************
+//
+// A prototype for the function (in the startup code) for calling the
+// application.
+//
+//*****************************************************************************
+extern void StartApplication(void);
+
+//*****************************************************************************
+//
+// A prototype for the function (in the startup code) for a predictable length
+// delay.
+//
+//*****************************************************************************
+extern void Delay(uint32_t ui32Count);
+
+//*****************************************************************************
+//
+// Holds the current address to write to when data is received via the Send
+// Data Command.
+//
+//*****************************************************************************
+static uint32_t g_ui32TransferAddress;
+
+//*****************************************************************************
+//
+// Holds the remaining bytes expected to be received.
+//
+//*****************************************************************************
+static uint32_t g_ui32TransferSize;
+
+//*****************************************************************************
+//
+// The buffer used to receive data from the update.
+//
+//*****************************************************************************
+static uint8_t g_pui8CommandBuffer[8];
+
+//*****************************************************************************
+//
+// These globals are used to store the first two words to prevent a partial
+// image from being booted.
+//
+//*****************************************************************************
+static uint32_t g_ui32StartValues[2];
+static uint32_t g_ui32StartSize;
+static uint32_t g_ui32StartAddress;
+
+//*****************************************************************************
+//
+// The active interface when the UART bridge is enabled.
+//
+//*****************************************************************************
+#ifdef CAN_UART_BRIDGE
+static uint32_t g_ui32Interface;
+#define IFACE_UNKNOWN 0
+#define IFACE_CAN 1
+#define IFACE_UART 2
+#endif
+
+//*****************************************************************************
+//
+//! Initializes the CAN controller after reset.
+//!
+//! After reset, the CAN controller is left in the disabled state. However,
+//! the memory used for message objects contains undefined values and must be
+//! cleared prior to enabling the CAN controller the first time. This prevents
+//! unwanted transmission or reception of data before the message objects are
+//! configured. This function must be called before enabling the controller
+//! the first time.
+//!
+//! \return None.
+//
+//*****************************************************************************
+static void
+CANInit(void)
+{
+ int iMsg;
+
+ //
+ // Place CAN controller in init state, regardless of previous state. This
+ // will put the controller in idle, and allow the message object RAM to be
+ // programmed.
+ //
+ CANRegWrite(CAN0_BASE + CAN_O_CTL, CAN_CTL_INIT | CAN_CTL_CCE);
+
+ //
+ // Loop through to program all 32 message objects
+ //
+ for(iMsg = 1; iMsg <= 32; iMsg++)
+ {
+ //
+ // Wait for busy bit to clear.
+ //
+ while(CANRegRead(CAN0_BASE + CAN_O_IF1CRQ) & CAN_IF1CRQ_BUSY)
+ {
+ }
+
+ //
+ // Clear the message value bit in the arbitration register. This
+ // indicates the message is not valid and is a "safe" condition to
+ // leave the message object.
+ //
+ CANRegWrite(CAN0_BASE + CAN_O_IF1CMSK,
+ CAN_IF1CMSK_WRNRD | CAN_IF1CMSK_ARB | CAN_IF1CMSK_CONTROL);
+ CANRegWrite(CAN0_BASE + CAN_O_IF1ARB2, 0);
+ CANRegWrite(CAN0_BASE + CAN_O_IF1MCTL, 0);
+
+ //
+ // Initiate programming of the message object
+ //
+ CANRegWrite(CAN0_BASE + CAN_O_IF1CRQ, iMsg);
+ }
+
+ //
+ // Acknowledge any pending status interrupts.
+ //
+ CANRegRead(CAN0_BASE + CAN_O_STS);
+}
+
+//*****************************************************************************
+//
+//! This function configures the message object used to receive commands.
+//!
+//! This function configures the message object used to receive all firmware
+//! update messages. This will not actually read the data from the message it
+//! is used to prepare the message object to receive the data when it is sent.
+//!
+//! \return None.
+//
+//*****************************************************************************
+static void
+CANMessageSetRx(void)
+{
+ uint16_t ui16CmdMaskReg;
+ uint16_t ui16MaskReg[2];
+ uint16_t ui16ArbReg[2];
+ uint16_t ui16MsgCtrl;
+
+ //
+ // Wait for busy bit to clear
+ //
+ while(CANRegRead(CAN0_BASE + CAN_O_IF1CRQ) & CAN_IF1CRQ_BUSY)
+ {
+ }
+
+ //
+ // This is always a write to the Message object as this call is setting a
+ // message object. This call will also always set all size bits so it sets
+ // both data bits. The call will use the CONTROL register to set control
+ // bits so this bit needs to be set as well.
+ //
+ // Set the MASK bit so that this gets transferred to the Message Object.
+ // Set the Arb bit so that this gets transferred to the Message object.
+ //
+ ui16CmdMaskReg = (CAN_IF1CMSK_WRNRD | CAN_IF1CMSK_DATAA |
+ CAN_IF1CMSK_DATAB | CAN_IF1CMSK_CONTROL |
+ CAN_IF1CMSK_MASK | CAN_IF1CMSK_ARB);
+
+ //
+ // Set the UMASK bit to enable using the mask register.
+ // Set the data length since this is set for all transfers. This is also a
+ // single transfer and not a FIFO transfer so set EOB bit.
+ //
+ ui16MsgCtrl = CAN_IF1MCTL_UMASK | CAN_IF1MCTL_EOB;
+
+ //
+ // Configure the Mask Registers.
+ //
+ //
+ // Set the 29 bits of Identifier mask that were requested.
+ //
+ ui16MaskReg[0] = (uint16_t)LM_API_UPD;
+
+ //
+ // If the caller wants to filter on the extended ID bit then set it.
+ //
+ ui16MaskReg[1] =
+ (uint16_t)(CAN_IF1MSK2_MXTD | (LM_API_UPD >> 16));
+
+ //
+ // Set the 29 bit version of the Identifier for this message object.
+ // Mark the message as valid and set the extended ID bit.
+ //
+ ui16ArbReg[0] = LM_API_UPD & CAN_IF1ARB1_ID_M;
+ ui16ArbReg[1] = (((LM_API_UPD >> 16) & CAN_IF1ARB2_ID_M) |
+ (CAN_IF1ARB2_MSGVAL | CAN_IF1ARB2_XTD));
+
+ //
+ // Write out the registers to program the message object.
+ //
+ CANRegWrite(CAN0_BASE + CAN_O_IF1CMSK, ui16CmdMaskReg);
+ CANRegWrite(CAN0_BASE + CAN_O_IF1MSK1, ui16MaskReg[0]);
+ CANRegWrite(CAN0_BASE + CAN_O_IF1MSK2, ui16MaskReg[1]);
+ CANRegWrite(CAN0_BASE + CAN_O_IF1ARB1, ui16ArbReg[0]);
+ CANRegWrite(CAN0_BASE + CAN_O_IF1ARB2, ui16ArbReg[1]);
+ CANRegWrite(CAN0_BASE + CAN_O_IF1MCTL, ui16MsgCtrl);
+
+ //
+ // Transfer the message object to the message object specific by
+ // MSG_OBJ_BCAST_RX_ID.
+ //
+ CANRegWrite(CAN0_BASE + CAN_O_IF1CRQ,
+ MSG_OBJ_BCAST_RX_ID & CAN_IF1CRQ_MNUM_M);
+}
+
+//*****************************************************************************
+//
+//! This function reads data from the receive message object.
+//!
+//! \param pui8Data is a pointer to the buffer to store the data read from the
+//! CAN controller.
+//! \param pui32MsgID is a pointer to the ID that was received with the data.
+//!
+//! This function will reads and acknowledges the data read from the message
+//! object used to receive all CAN firmware update messages. It will also
+//! return the message identifier as this holds the API number that was
+//! attached to the data. This message identifier should be one of the
+//! LM_API_UPD_* definitions.
+//!
+//! \return The number of valid bytes returned in the \e pui8Data buffer or
+//! 0xffffffff if data was overwritten in the buffer.
+//
+//*****************************************************************************
+static uint32_t
+CANMessageGetRx(uint8_t *pui8Data, uint32_t *pui32MsgID)
+{
+ uint16_t ui16CmdMaskReg;
+ uint16_t ui16ArbReg0, ui16ArbReg1;
+ uint16_t ui16MsgCtrl;
+ uint32_t ui32Bytes;
+ uint16_t *pui16Data;
+
+ //
+ // This is always a read to the Message object as this call is setting a
+ // message object.
+ // Clear a pending interrupt and new data in a message object.
+ //
+ ui16CmdMaskReg = (CAN_IF2CMSK_DATAA | CAN_IF2CMSK_DATAB |
+ CAN_IF1CMSK_CONTROL | CAN_IF2CMSK_CLRINTPND |
+ CAN_IF2CMSK_ARB);
+
+ //
+ // Set up the request for data from the message object.
+ //
+ CANRegWrite(CAN0_BASE + CAN_O_IF2CMSK, ui16CmdMaskReg);
+
+ //
+ // Transfer the message object to the message object specific by
+ // MSG_OBJ_BCAST_RX_ID.
+ //
+ CANRegWrite(CAN0_BASE + CAN_O_IF2CRQ,
+ MSG_OBJ_BCAST_RX_ID & CAN_IF1CRQ_MNUM_M);
+
+ //
+ // Wait for busy bit to clear
+ //
+ while(CANRegRead(CAN0_BASE + CAN_O_IF2CRQ) & CAN_IF1CRQ_BUSY)
+ {
+ }
+
+ //
+ // Read out the IF Registers.
+ //
+ ui16ArbReg0 = CANRegRead(CAN0_BASE + CAN_O_IF2ARB1);
+ ui16ArbReg1 = CANRegRead(CAN0_BASE + CAN_O_IF2ARB2);
+ ui16MsgCtrl = CANRegRead(CAN0_BASE + CAN_O_IF2MCTL);
+
+ //
+ // Set the 29 bit version of the Identifier for this message object.
+ //
+ *pui32MsgID = ((ui16ArbReg1 & CAN_IF1ARB2_ID_M) << 16) | ui16ArbReg0;
+
+ //
+ // See if there is new data available.
+ //
+ if((ui16MsgCtrl & (CAN_IF1MCTL_NEWDAT | CAN_IF1MCTL_MSGLST)) ==
+ CAN_IF1MCTL_NEWDAT)
+ {
+ //
+ // Get the amount of data needed to be read.
+ //
+ ui32Bytes = ui16MsgCtrl & CAN_IF1MCTL_DLC_M;
+
+ //
+ // Read out the data from the CAN registers 16 bits at a time.
+ //
+ pui16Data = (uint16_t *)pui8Data;
+
+ pui16Data[0] = CANRegRead(CAN0_BASE + CAN_O_IF2DA1);
+ pui16Data[1] = CANRegRead(CAN0_BASE + CAN_O_IF2DA2);
+ pui16Data[2] = CANRegRead(CAN0_BASE + CAN_O_IF2DB1);
+ pui16Data[3] = CANRegRead(CAN0_BASE + CAN_O_IF2DB2);
+
+ //
+ // Now clear out the new data flag.
+ //
+ CANRegWrite(CAN0_BASE + CAN_O_IF2CMSK, CAN_IF1CMSK_NEWDAT);
+
+ //
+ // Transfer the message object to the message object specific by
+ // MSG_OBJ_BCAST_RX_ID.
+ //
+ CANRegWrite(CAN0_BASE + CAN_O_IF2CRQ, MSG_OBJ_BCAST_RX_ID);
+
+ //
+ // Wait for busy bit to clear
+ //
+ while(CANRegRead(CAN0_BASE + CAN_O_IF2CRQ) & CAN_IF2CRQ_BUSY)
+ {
+ }
+ }
+ else
+ {
+ //
+ // Data was lost so inform the caller.
+ //
+ ui32Bytes = 0xffffffff;
+ }
+ return(ui32Bytes);
+}
+
+//*****************************************************************************
+//
+//! This function sends data using the transmit message object.
+//!
+//! \param ui32Id is the ID to use with this message.
+//! \param pui8Data is a pointer to the buffer with the data to be sent.
+//! \param ui32Size is the number of bytes to send and should not be more than
+//! 8 bytes.
+//!
+//! This function will reads and acknowledges the data read from the message
+//! object used to receive all CAN firmware update messages. It will also
+//! return the message identifier as this holds the API number that was
+//! attached to the data. This message identifier should be one of the
+//! LM_API_UPD_* definitions.
+//!
+//! \return None.
+//
+//*****************************************************************************
+static void
+CANMessageSetTx(uint32_t ui32Id, const uint8_t *pui8Data, uint32_t ui32Size)
+{
+ uint16_t ui16CmdMaskReg;
+ uint16_t ui16ArbReg0, ui16ArbReg1;
+ uint16_t ui16MsgCtrl;
+ uint16_t *pui16Data;
+
+ //
+ // Wait for busy bit to clear
+ //
+ while(CANRegRead(CAN0_BASE + CAN_O_IF1CRQ) & CAN_IF1CRQ_BUSY)
+ {
+ }
+
+ //
+ // This is always a write to the Message object as this call is setting a
+ // message object. This call will also always set all size bits so it sets
+ // both data bits. The call will use the CONTROL register to set control
+ // bits so this bit needs to be set as well.
+ //
+ ui16CmdMaskReg = (CAN_IF1CMSK_WRNRD | CAN_IF1CMSK_DATAA |
+ CAN_IF1CMSK_DATAB | CAN_IF1CMSK_CONTROL |
+ CAN_IF1CMSK_ARB);
+
+ //
+ // Set the 29 bit version of the Identifier for this message object.
+ //
+ ui16ArbReg0 = ui32Id & CAN_IF1ARB1_ID_M;
+
+ //
+ // Mark the message as valid and set the extended ID bit.
+ //
+ ui16ArbReg1 = (((ui32Id >> 16) & CAN_IF1ARB2_ID_M) |
+ (CAN_IF1ARB2_DIR | CAN_IF1ARB2_MSGVAL | CAN_IF1ARB2_XTD));
+
+ //
+ // Set the TXRQST bit and the reset the rest of the register.
+ // Set the data length since this is set for all transfers. This is also a
+ // single transfer and not a FIFO transfer so set EOB bit.
+ //
+ //
+ ui16MsgCtrl = (CAN_IF1MCTL_TXRQST | CAN_IF1MCTL_EOB |
+ (ui32Size & CAN_IF1MCTL_DLC_M));
+
+ pui16Data = (uint16_t *)pui8Data;
+
+ //
+ // Write the data out to the CAN Data registers if needed.
+ //
+ CANRegWrite(CAN0_BASE + CAN_O_IF1DA1, pui16Data[0]);
+ CANRegWrite(CAN0_BASE + CAN_O_IF1DA2, pui16Data[1]);
+ CANRegWrite(CAN0_BASE + CAN_O_IF1DB1, pui16Data[2]);
+ CANRegWrite(CAN0_BASE + CAN_O_IF1DB2, pui16Data[3]);
+
+ //
+ // Write out the registers to program the message object.
+ //
+ CANRegWrite(CAN0_BASE + CAN_O_IF1CMSK, ui16CmdMaskReg);
+ CANRegWrite(CAN0_BASE + CAN_O_IF1ARB1, ui16ArbReg0);
+ CANRegWrite(CAN0_BASE + CAN_O_IF1ARB2, ui16ArbReg1);
+ CANRegWrite(CAN0_BASE + CAN_O_IF1MCTL, ui16MsgCtrl);
+
+ //
+ // Transfer the message object to the message object specifiec by
+ // MSG_OBJ_BCAST_RX_ID.
+ //
+ CANRegWrite(CAN0_BASE + CAN_O_IF1CRQ,
+ (MSG_OBJ_BCAST_TX_ID) & CAN_IF1CRQ_MNUM_M);
+}
+
+//*****************************************************************************
+//
+//! Configures the CAN interface.
+//!
+//! \param ui32SetTiming determines if the CAN bit timing should be configured.
+//!
+//! This function configures the CAN controller, preparing it for use by
+//! the boot loader. If the \e ui32SetTiming parameter is 0, the bit timing
+//! for the CAN bus will be left alone. This occurs when the boot loader was
+//! entered from a running application that already has configured the timing
+//! for the system. When \e ui32SetTiming is non-zero the bit timing will be
+//! set to the defaults defined in the <tt>bl_config.h</tt> file in the
+//! project.
+//!
+//! \return None.
+//
+//*****************************************************************************
+static void
+ConfigureCANInterface(uint32_t ui32SetTiming)
+{
+ //
+ // Reset the state of all the message object and the state of the CAN
+ // module to a known state.
+ //
+ CANInit();
+
+ //
+ // If a device identifier was specified then this was due to an update from
+ // a running CAN application so don't change the CAN bit timing.
+ //
+ if(ui32SetTiming != 0)
+ {
+ //
+ // Set the bit fields of the bit timing register according to the
+ // parms.
+ //
+ CANRegWrite(CAN0_BASE + CAN_O_BIT, CAN_BIT_TIMING);
+
+ //
+ // Set the divider upper bits in the extension register.
+ //
+ CANRegWrite(CAN0_BASE + CAN_O_BRPE, 0);
+ }
+
+ //
+ // Take the CAN0 device out of INIT state.
+ //
+ CANRegWrite(CAN0_BASE + CAN_O_CTL, 0);
+
+ //
+ // Configure the broadcast receive message object.
+ //
+ CANMessageSetRx();
+}
+
+//*****************************************************************************
+//
+// Reads the next packet that is sent to the boot loader.
+//
+//*****************************************************************************
+static uint32_t
+PacketRead(uint8_t *pui8Data, uint32_t *pui32Size)
+{
+ uint32_t ui32MsgID;
+
+#ifdef CAN_UART_BRIDGE
+ uint32_t ui32Size, ui32Length, ui32Mode, ui32Char;
+ uint8_t pui8Buffer[12];
+
+ //
+ // Initialize the size and length of the packet.
+ //
+ ui32Length = 0;
+ ui32Size = 0;
+
+ //
+ // If no interface has been determined then wait for either CAN or UART
+ // data until either responds.
+ //
+ if(g_ui32Interface == IFACE_UNKNOWN)
+ {
+ //
+ // Wait for CAN or UART data.
+ //
+ while((CANRegRead(CAN0_BASE + CAN_O_NWDA1) == 0) &&
+ ((HWREG(UART0_BASE + UART_O_FR) & UART_FR_RXFE) == UART_FR_RXFE))
+ {
+ }
+
+ //
+ // If the UART FIFO was empty then the loop exited due to a CAN
+ // message.
+ //
+ if((HWREG(UART0_BASE + UART_O_FR) & UART_FR_RXFE) == UART_FR_RXFE)
+ {
+ g_ui32Interface = IFACE_CAN;
+ }
+ else
+ {
+ //
+ // The UART FIFO was not empty so the UART interface was used.
+ //
+ g_ui32Interface = IFACE_UART;
+ }
+ }
+
+ //
+ // Read a data packet from the CAN controller.
+ //
+ if(g_ui32Interface == IFACE_CAN)
+ {
+#endif
+ //
+ // Wait until a packet has been received.
+ //
+ while(CANRegRead(CAN0_BASE + CAN_O_NWDA1) == 0)
+ {
+ }
+
+ //
+ // Read the packet.
+ //
+ *pui32Size = CANMessageGetRx(pui8Data, &ui32MsgID);
+#ifdef CAN_UART_BRIDGE
+ }
+ else
+ {
+ //
+ // Read a data packet from the UART controller.
+ //
+ ui32Mode = 0;
+
+ while(1)
+ {
+ //
+ // Wait until a char is available.
+ //
+ while(HWREG(UART0_BASE + UART_O_FR) & UART_FR_RXFE)
+ {
+ }
+
+ //
+ // Now get the char.
+ //
+ ui32Char = HWREG(UART0_BASE + UART_O_DR);
+
+ if(ui32Char == 0xff)
+ {
+ ui32Mode = 1;
+ ui32Length = 0;
+ }
+ else if(ui32Mode == 1)
+ {
+ if(ui32Char > 12)
+ {
+ ui32Mode = 0;
+ }
+ else
+ {
+ ui32Size = ui32Char;
+ ui32Mode = 2;
+ }
+ }
+ else if(ui32Mode == 3)
+ {
+ if(ui32Char == 0xfe)
+ {
+ pui8Buffer[ui32Length++] = 0xff;
+ ui32Mode = 2;
+ }
+ else if(ui32Char == 0xfd)
+ {
+ pui8Buffer[ui32Length++] = 0xfe;
+ ui32Mode = 2;
+ }
+ else
+ {
+ ui32Mode = 0;
+ }
+ }
+ else if(ui32Mode == 2)
+ {
+ if(ui32Char == 0xfe)
+ {
+ ui32Mode = 3;
+ }
+ else
+ {
+ pui8Buffer[ui32Length++] = ui32Char;
+ }
+ }
+
+ if((ui32Length == ui32Size) && (ui32Mode == 2))
+ {
+ ui32MsgID = *(uint32_t *)pui8Buffer;
+
+ if((ui32MsgID & (CAN_MSGID_MFR_M | CAN_MSGID_DTYPE_M)) ==
+ LM_API_UPD)
+ {
+ *(uint32_t *)pui8Data =
+ *(uint32_t *)(pui8Buffer + 4);
+ *(uint32_t *)(pui8Data + 4) =
+ *(uint32_t *)(pui8Buffer + 8);
+ *pui32Size = ui32Size - 4;
+ break;
+ }
+ }
+ }
+ }
+#endif
+
+ //
+ // Return the message ID of the packet that was received.
+ //
+ return(ui32MsgID);
+}
+
+//*****************************************************************************
+//
+// This function writes out an individual character over the UART and
+// handles sending out special sequences for handling 0xff and 0xfe values.
+//
+//*****************************************************************************
+#ifdef CAN_UART_BRIDGE
+static void
+UARTBridgeWrite(uint32_t ui32Char)
+{
+ //
+ // See if the character being sent is 0xff.
+ //
+ if(ui32Char == 0xff)
+ {
+ //
+ // Send 0xfe 0xfe, the escaped version of 0xff. A sign extended
+ // version of 0xfe is used to avoid the check below for 0xfe, thereby
+ // avoiding an infinite loop. Only the lower 8 bits are actually sent,
+ // so 0xfe is what is actually transmitted.
+ //
+ UARTBridgeWrite(0xfffffffe);
+ UARTBridgeWrite(0xfffffffe);
+ }
+
+ //
+ // Otherwise, see if the character being sent is 0xfe.
+ //
+ else if(ui32Char == 0xfe)
+ {
+ //
+ // Send 0xfe 0xfd, the escaped version of 0xfe. A sign extended
+ // version of 0xfe is used to avoid the check above for 0xfe, thereby
+ // avoiding an infinite loop. Only the lower 8 bits are actually sent,
+ // so 0xfe is what is actually transmitted.
+ //
+ UARTBridgeWrite(0xfffffffe);
+ UARTBridgeWrite(0xfd);
+ }
+
+ //
+ // Otherwise, simply send this character.
+ //
+ else
+ {
+ //
+ // Wait until space is available in the UART transmit FIFO.
+ //
+ while(HWREG(UART0_BASE + UART_O_FR) & UART_FR_TXFF)
+ {
+ }
+
+ //
+ // Send the char.
+ //
+ HWREG(UART0_BASE + UART_O_DR) = ui32Char & 0xff;
+ }
+}
+#endif
+
+//*****************************************************************************
+//
+// Sends a packet to the controller that is communicating with the boot loader.
+//
+//*****************************************************************************
+static void
+PacketWrite(uint32_t ui32Id, const uint8_t *pui8Data, uint32_t ui32Size)
+{
+ uint32_t ui32Idx;
+
+#ifdef CAN_UART_BRIDGE
+ //
+ // Check if the boot loader is in CAN mode.
+ //
+ if(g_ui32Interface == IFACE_CAN)
+ {
+#endif
+ //
+ // Wait until the previous packet has been sent, providing a time out so
+ // that the boot loader does not hang here.
+ //
+ for(ui32Idx = 1000;
+ (ui32Idx != 0) && (CANRegRead(CAN0_BASE + CAN_O_TXRQ1) != 0);
+ ui32Idx--)
+ {
+ }
+
+ //
+ // If the previous packet was sent, then send this packet.
+ //
+ if(ui32Idx != 0)
+ {
+ CANMessageSetTx(ui32Id, pui8Data, ui32Size);
+ }
+#ifdef CAN_UART_BRIDGE
+ }
+ else
+ {
+ //
+ // The boot loader is in UART modes so write the packet using the UART
+ // functions. Write the start pattern followed by the size, and the ID.
+ //
+ UARTBridgeWrite(0xffffffff);
+ UARTBridgeWrite(ui32Size + 4);
+ UARTBridgeWrite(ui32Id & 0xff);
+ UARTBridgeWrite((ui32Id >> 8) & 0xff);
+ UARTBridgeWrite((ui32Id >> 16) & 0xff);
+ UARTBridgeWrite((ui32Id >> 24) & 0xff);
+
+ //
+ // Now write out the remaining data bytes.
+ //
+ while(ui32Size--)
+ {
+ UARTBridgeWrite(*pui8Data++);
+ }
+ }
+#endif
+}
+
+//*****************************************************************************
+//
+//! This is the main routine for handling updating over CAN.
+//!
+//! This function accepts boot loader commands over CAN to perform a firmware
+//! update over the CAN bus. This function assumes that the CAN bus timing
+//! and message objects have been configured elsewhere.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+UpdaterCAN(void)
+{
+ uint32_t ui32Bytes;
+ uint32_t ui32Cmd;
+ uint32_t ui32FlashSize;
+ uint32_t ui32Temp;
+ uint8_t ui8Status;
+
+#ifdef ENABLE_UPDATE_CHECK
+ //
+ // Check the application is valid and check the pin to see if an update is
+ // being requested.
+ //
+ if(g_ui32Forced == 1)
+ {
+ //
+ // Send out the CAN request.
+ //
+#ifdef CAN_UART_BRIDGE
+ g_ui32Interface = IFACE_CAN;
+#endif
+ PacketWrite(LM_API_UPD_REQUEST, 0, 0);
+
+ //
+ // Send out the UART request.
+ //
+#ifdef CAN_UART_BRIDGE
+ g_ui32Interface = IFACE_UART;
+ PacketWrite(LM_API_UPD_REQUEST, 0, 0);
+ g_ui32Interface = IFACE_UNKNOWN;
+#endif
+
+ //
+ // Wait only 50ms for the response and move on otherwise.
+ //
+ Delay(CRYSTAL_FREQ / 20);
+
+ //
+ // Wait until a packet has been received.
+ //
+#ifdef CAN_UART_BRIDGE
+ if((CANRegRead(CAN0_BASE + CAN_O_NWDA1) == 0) &&
+ ((HWREG(UART0_BASE + UART_O_FR) & UART_FR_RXFE) == UART_FR_RXFE))
+#else
+ if(CANRegRead(CAN0_BASE + CAN_O_NWDA1) == 0)
+#endif
+ {
+ //
+ // Call the application.
+ //
+ StartApplication();
+ }
+ }
+#endif
+
+ //
+ // Loop forever processing packets.
+ //
+ while(1)
+ {
+ //
+ // Read the next packet.
+ //
+ ui32Bytes = 0;
+ ui32Cmd = PacketRead(g_pui8CommandBuffer, &ui32Bytes);
+
+ //
+ // Handle this packet.
+ //
+ ui8Status = CAN_CMD_SUCCESS;
+ switch(ui32Cmd)
+ {
+ //
+ // This is an update request packet.
+ //
+ case LM_API_UPD_REQUEST:
+ {
+ //
+ // This packet is ignored (other than generating an ACK).
+ //
+ break;
+ }
+
+ //
+ // This is a ping packet.
+ //
+ case LM_API_UPD_PING:
+ {
+ //
+ // This packet is ignored (other than generating an ACK).
+ //
+ break;
+ }
+
+ //
+ // This is a reset packet.
+ //
+ case LM_API_UPD_RESET:
+ {
+ //
+ // Perform a software reset request. This will cause the
+ // microcontroller to reset; no further code will be executed.
+ //
+ HWREG(NVIC_APINT) = (NVIC_APINT_VECTKEY |
+ NVIC_APINT_SYSRESETREQ);
+
+ //
+ // The microcontroller should have reset, so this should never
+ // be reached. Just in case, loop forever.
+ //
+ while(1)
+ {
+ }
+ }
+
+ //
+ // This is a data packet.
+ //
+ case LM_API_UPD_SEND_DATA:
+ {
+ //
+ // If this is overwriting the boot loader then the application
+ // has already been erased so now erase the boot loader.
+ //
+ if(g_ui32TransferAddress == 0)
+ {
+ //
+ // Clear the flash access interrupt.
+ //
+ BL_FLASH_CL_ERR_FN_HOOK();
+
+ //
+ // Erase the application before the boot loader.
+ //
+ for(ui32Temp = 0; ui32Temp < APP_START_ADDRESS;
+ ui32Temp += FLASH_PAGE_SIZE)
+ {
+ //
+ // Erase this block.
+ //
+ BL_FLASH_ERASE_FN_HOOK(ui32Temp);
+ }
+
+ //
+ // Return an error if an access violation occurred.
+ //
+ if(BL_FLASH_ERROR_FN_HOOK())
+ {
+ //
+ // Setting g_ui32TransferSize to zero makes
+ // COMMAND_SEND_DATA fail to accept any more data.
+ //
+ g_ui32TransferSize = 0;
+
+ //
+ // Indicate that the flash erase failed.
+ //
+ ui8Status = CAN_CMD_FAIL;
+ }
+ }
+
+ //
+ // Check if there are any more bytes to receive.
+ //
+ if(g_ui32TransferSize >= ui32Bytes)
+ {
+ //
+ // Decrypt the data if required.
+ //
+#ifdef BL_DECRYPT_FN_HOOK
+ BL_DECRYPT_FN_HOOK(g_pui8CommandBuffer, ui32Bytes);
+#endif
+
+ //
+ // Clear the flash access interrupt.
+ //
+ BL_FLASH_CL_ERR_FN_HOOK();
+
+ //
+ // Skip the first transfer.
+ //
+ if(g_ui32StartSize == g_ui32TransferSize)
+ {
+ g_ui32StartValues[0] =
+ *((uint32_t *)&g_pui8CommandBuffer[0]);
+ g_ui32StartValues[1] =
+ *((uint32_t *)&g_pui8CommandBuffer[4]);
+ }
+ else
+ {
+ //
+ // Loop over the words to program.
+ //
+ BL_FLASH_PROGRAM_FN_HOOK(g_ui32TransferAddress,
+ g_pui8CommandBuffer,
+ ui32Bytes);
+ }
+
+ //
+ // Return an error if an access violation occurred.
+ //
+ if(BL_FLASH_ERROR_FN_HOOK())
+ {
+ //
+ // Indicate that the flash programming failed.
+ //
+ ui8Status = CAN_CMD_FAIL;
+ }
+ else
+ {
+ //
+ // Now update the address to program.
+ //
+ g_ui32TransferSize -= ui32Bytes;
+ g_ui32TransferAddress += ui32Bytes;
+
+ //
+ // If a progress hook function has been provided, call
+ // it here.
+ //
+#ifdef BL_PROGRESS_FN_HOOK
+ BL_PROGRESS_FN_HOOK(g_ui32StartSize -
+ g_ui32TransferSize,
+ g_ui32StartSize);
+#endif
+ }
+ }
+ else
+ {
+ //
+ // This indicates that too much data is being sent to the
+ // device.
+ //
+ ui8Status = CAN_CMD_FAIL;
+ }
+
+ //
+ // If the last expected bytes were received then write out the
+ // first two words of the image to allow it to boot.
+ //
+ if(g_ui32TransferSize == 0)
+ {
+ //
+ // Loop over the words to program.
+ //
+ BL_FLASH_PROGRAM_FN_HOOK(g_ui32StartAddress,
+ (uint8_t *)&g_ui32StartValues,
+ 8);
+
+ //
+ // If an end signal hook function has been provided, call
+ // it here since we have finished a download.
+ //
+#ifdef BL_END_FN_HOOK
+ BL_END_FN_HOOK();
+#endif
+ }
+ break;
+ }
+
+ //
+ // This is a start download packet.
+ //
+ case LM_API_UPD_DOWNLOAD:
+ {
+ //
+ // Get the application address and size from the packet data.
+ //
+ g_ui32TransferAddress =
+ *((uint32_t *)&g_pui8CommandBuffer[0]);
+ g_ui32TransferSize = *((uint32_t *)&g_pui8CommandBuffer[4]);
+ g_ui32StartSize = g_ui32TransferSize;
+ g_ui32StartAddress = g_ui32TransferAddress;
+
+ //
+ // Check for a valid starting address and image size.
+ //
+ if(!BL_FLASH_AD_CHECK_FN_HOOK(g_ui32TransferAddress,
+ g_ui32TransferSize))
+ {
+ //
+ // Set the code to an error to indicate that the last
+ // command failed. This informs the updater program
+ // that the download command failed.
+ //
+ ui8Status = CAN_CMD_FAIL;
+
+ //
+ // This packet has been handled.
+ //
+ break;
+ }
+
+ //
+ // Only erase the space that we need if we are not protecting
+ // the code, otherwise erase the entire flash.
+ //
+#ifdef FLASH_CODE_PROTECTION
+ ui32FlashSize = BL_FLASH_SIZE_FN_HOOK();
+#ifdef FLASH_RSVD_SPACE
+ if((ui32FlashSize - FLASH_RSVD_SPACE) != g_ui32TransferAddress)
+ {
+ ui32FlashSize -= FLASH_RSVD_SPACE;
+ }
+#endif
+#else
+ ui32FlashSize = g_ui32TransferAddress + g_ui32TransferSize;
+#endif
+
+ //
+ // Clear the flash access interrupt.
+ //
+ BL_FLASH_CL_ERR_FN_HOOK();
+
+ //
+ // Leave the boot loader present until we start getting an
+ // image.
+ //
+ for(ui32Temp = g_ui32TransferAddress; ui32Temp < ui32FlashSize;
+ ui32Temp += FLASH_PAGE_SIZE)
+ {
+ //
+ // Erase this block.
+ //
+ BL_FLASH_ERASE_FN_HOOK(ui32Temp);
+ }
+
+ //
+ // Return an error if an access violation occurred.
+ //
+ if(BL_FLASH_ERROR_FN_HOOK())
+ {
+ ui8Status = CAN_CMD_FAIL;
+ }
+
+ //
+ // See if the command was successful.
+ //
+ if(ui8Status != CAN_CMD_SUCCESS)
+ {
+ //
+ // Setting g_ui32TransferSize to zero makes
+ // COMMAND_SEND_DATA fail to accept any data.
+ //
+ g_ui32TransferSize = 0;
+ }
+#ifdef BL_START_FN_HOOK
+ else
+ {
+ //
+ // If a start signal hook function has been provided, call
+ // it here since we are about to start a new download.
+ //
+ BL_START_FN_HOOK();
+ }
+#endif
+
+ break;
+ }
+
+ //
+ // This is an unknown packet.
+ //
+ default:
+ {
+ //
+ // Set the status to indicate a failure.
+ //
+ ui8Status = CAN_CMD_FAIL;
+ break;
+ }
+ }
+
+ //
+ // Send an ACK packet in response to indicate that the packet was
+ // received. The status in the ACK data indicates if the command was
+ // successfully processed.
+ //
+ PacketWrite(LM_API_UPD_ACK, &ui8Status, 1);
+ }
+}
+
+//*****************************************************************************
+//
+// Configures the UART used for CAN traffic bridging.
+//
+//*****************************************************************************
+#ifdef CAN_UART_BRIDGE
+void
+ConfigureBridge(void)
+{
+ //
+ // Enable the GPIO module if necessary.
+ //
+#if (CAN_RX_PERIPH != SYSCTL_RCGC2_GPIOA) && \
+ (CAN_TX_PERIPH != SYSCTL_RCGC2_GPIOA)
+ HWREG(SYSCTL_RCGC2) |= SYSCTL_RCGC2_GPIOA;
+#endif
+
+ //
+ // Enable the UART module.
+ //
+ HWREG(SYSCTL_RCGC1) |= SYSCTL_RCGC1_UART0;
+
+ //
+ // Enable the GPIO pins used for the UART.
+ //
+ HWREG(GPIO_PORTA_BASE + GPIO_O_AFSEL) |= 0x3;
+ HWREG(GPIO_PORTA_BASE + GPIO_O_DEN) |= 0x03;
+
+ //
+ // Configure the UART.
+ //
+ HWREG(UART0_BASE + UART_O_IBRD) = UART_BAUD_RATIO(115200) >> 6;
+ HWREG(UART0_BASE + UART_O_FBRD) = (UART_BAUD_RATIO(115200) &
+ UART_FBRD_DIVFRAC_M);
+ HWREG(UART0_BASE + UART_O_LCRH) = UART_LCRH_WLEN_8 | UART_LCRH_FEN;
+ HWREG(UART0_BASE + UART_O_CTL) = (UART_CTL_UARTEN | UART_CTL_TXE |
+ UART_CTL_RXE);
+}
+#endif
+
+//*****************************************************************************
+//
+//! This is the application entry point to the CAN updater.
+//!
+//! This function should only be entered from a running application and not
+//! when running the boot loader with no application present.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+AppUpdaterCAN(void)
+{
+ //
+ // If the boot loader is being called from the application the UART needs
+ // to be configured.
+ //
+#ifdef CAN_UART_BRIDGE
+ ConfigureBridge();
+#endif
+
+ //
+ // Configure the CAN controller but don't change the bit timing.
+ //
+ ConfigureCANInterface(0);
+
+ //
+ // Call the main update routine.
+ //
+ UpdaterCAN();
+}
+
+//*****************************************************************************
+//
+//! Generic configuration is handled in this function.
+//!
+//! This function is called by the start up code to perform any configuration
+//! necessary before calling the update routine.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+ConfigureCAN(void)
+{
+#ifdef CRYSTAL_FREQ
+ //
+ // Since the crystal frequency was specified, enable the main oscillator
+ // and clock the processor from it.
+ //
+ HWREG(SYSCTL_RCC) &= ~(SYSCTL_RCC_MOSCDIS);
+
+ //
+ // Delay while the main oscillator starts up.
+ //
+ Delay(524288);
+
+ //
+ // Set the crystal frequency and switch to the main oscillator.
+ //
+ HWREG(SYSCTL_RCC) = ((HWREG(SYSCTL_RCC) &
+ ~(SYSCTL_RCC_XTAL_M | SYSCTL_RCC_OSCSRC_M)) |
+ XTAL_VALUE | SYSCTL_RCC_OSCSRC_MAIN);
+#endif
+
+ //
+ // Enable the CAN controller.
+ //
+ HWREG(SYSCTL_RCGC0) |= SYSCTL_RCGC0_CAN0;
+
+#if CAN_RX_PERIPH == CAN_TX_PERIPH
+ //
+ // Enable the GPIO associated with CAN0
+ //
+ HWREG(SYSCTL_RCGC2) |= CAN_RX_PERIPH;
+
+ //
+ // Wait a while before accessing the peripheral.
+ //
+ Delay(3);
+
+ //
+ // Set the alternate function selects.
+ //
+ HWREG(CAN_RX_PORT + GPIO_O_AFSEL) |= CAN_RX_PIN_M | CAN_TX_PIN_M;
+
+ //
+ // Set the pin type to it's digital function.
+ //
+ HWREG(CAN_RX_PORT + GPIO_O_DEN) |= CAN_RX_PIN_M | CAN_TX_PIN_M;
+
+#else
+ //
+ // Enable the GPIO associated with CAN0
+ //
+ HWREG(SYSCTL_RCGC2) |= CAN_RX_PERIPH | CAN_TX_PERIPH;
+
+ //
+ // Wait a while before accessing the peripheral.
+ //
+ Delay(3);
+
+ //
+ // Set the alternate function selects.
+ //
+ HWREG(CAN_RX_PORT + GPIO_O_AFSEL) |= CAN_RX_PIN_M;
+ HWREG(CAN_TX_PORT + GPIO_O_AFSEL) |= CAN_TX_PIN_M;
+
+ //
+ // Set the pin type to it's digital function.
+ //
+ HWREG(CAN_RX_PORT + GPIO_O_DEN) |= CAN_RX_PIN_M;
+ HWREG(CAN_TX_PORT + GPIO_O_DEN) |= CAN_TX_PIN_M;
+#endif
+
+ //
+ // Configure the UART used for bridging.
+ //
+#ifdef CAN_UART_BRIDGE
+ ConfigureBridge();
+#endif
+
+ //
+ // Configure the CAN interface.
+ //
+ ConfigureCANInterface(1);
+}
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
+#endif
diff --git a/boot_loader/bl_can.h b/boot_loader/bl_can.h
new file mode 100644
index 0000000..504a410
--- /dev/null
+++ b/boot_loader/bl_can.h
@@ -0,0 +1,64 @@
+//*****************************************************************************
+//
+// bl_can.h - Definitions for the CAN transport functions.
+//
+// Copyright (c) 2008-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
+//
+//*****************************************************************************
+
+#ifndef __BL_CAN_H__
+#define __BL_CAN_H__
+
+//*****************************************************************************
+//
+// These defines are used to define the range of values that are used for
+// the CAN update protocol.
+//
+//*****************************************************************************
+#define CAN_MSGID_DTYPE_UPDATE 0x1f000000
+#define CAN_MSGID_MFR_LM 0x00020000
+
+//*****************************************************************************
+//
+// The masks of the fields that are used in the message identifier.
+//
+//*****************************************************************************
+#define CAN_MSGID_DEVNO_M 0x0000003f
+#define CAN_MSGID_API_M 0x0000ffc0
+#define CAN_MSGID_MFR_M 0x00ff0000
+#define CAN_MSGID_DTYPE_M 0x1f000000
+#define CAN_MSGID_DEVNO_S 0
+#define CAN_MSGID_API_S 6
+#define CAN_MSGID_MFR_S 16
+#define CAN_MSGID_DTYPE_S 24
+
+//*****************************************************************************
+//
+// Firmware Update API definitions.
+//
+//*****************************************************************************
+#define LM_API_UPD (CAN_MSGID_MFR_LM | CAN_MSGID_DTYPE_UPDATE)
+#define LM_API_UPD_PING (LM_API_UPD | (0 << CAN_MSGID_API_S))
+#define LM_API_UPD_DOWNLOAD (LM_API_UPD | (1 << CAN_MSGID_API_S))
+#define LM_API_UPD_SEND_DATA (LM_API_UPD | (2 << CAN_MSGID_API_S))
+#define LM_API_UPD_RESET (LM_API_UPD | (3 << CAN_MSGID_API_S))
+#define LM_API_UPD_ACK (LM_API_UPD | (4 << CAN_MSGID_API_S))
+#define LM_API_UPD_REQUEST (LM_API_UPD | (6 << CAN_MSGID_API_S))
+
+#endif // __BL_CAN_H__
diff --git a/boot_loader/bl_can_timing.h b/boot_loader/bl_can_timing.h
new file mode 100644
index 0000000..f0aaa0c
--- /dev/null
+++ b/boot_loader/bl_can_timing.h
@@ -0,0 +1,241 @@
+//*****************************************************************************
+//
+// bl_can_timing.h - Timing definitions for the CAN controller.
+//
+// Copyright (c) 2008-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
+//
+//*****************************************************************************
+
+#ifndef __BL_CAN_TIMING_H__
+#define __BL_CAN_TIMING_H__
+
+#ifdef CAN_ENABLE_UPDATE
+
+//*****************************************************************************
+//
+// This macro is used to generate the proper value for CAN_BIT_TIMING. The
+// values selected for each crystal/bit rate combination assumes a propagation
+// delay of 300ns (which will always be rounded up to the next integer multiple
+// of the CAN time quanta).
+//
+//*****************************************************************************
+#define CAN_BIT_REG(seg1, seg2, sjw, brp) \
+ ((((seg2 - 1) << CAN_BIT_TSEG2_S) & \
+ CAN_BIT_TSEG2_M) | \
+ (((seg1 - 1) << CAN_BIT_TSEG1_S) & \
+ CAN_BIT_TSEG1_M) | \
+ (((sjw - 1) << CAN_BIT_SJW_S) & \
+ CAN_BIT_SJW_M) | \
+ (((brp - 1) << CAN_BIT_BRP_S) & \
+ CAN_BIT_BRP_M))
+
+//*****************************************************************************
+//
+// The settings for a 16MHz crystal frequency.
+//
+//*****************************************************************************
+#if CRYSTAL_FREQ == 16000000
+#if CAN_BIT_RATE == 1000000
+#define CAN_BIT_TIMING CAN_BIT_REG(10, 5, 4, 1) // tProp = 312ns
+#elif CAN_BIT_RATE == 500000
+#define CAN_BIT_TIMING CAN_BIT_REG(9, 6, 4, 2) // tProp = 375ns
+#elif CAN_BIT_RATE == 250000
+#define CAN_BIT_TIMING CAN_BIT_REG(4, 3, 3, 8) // tProp = 500ns
+#elif CAN_BIT_RATE == 125000
+#define CAN_BIT_TIMING CAN_BIT_REG(8, 7, 4, 8) // tProp = 500ns
+#elif CAN_BIT_RATE == 50000
+#define CAN_BIT_TIMING CAN_BIT_REG(8, 7, 4, 20) // tProp = 1250ns
+#elif CAN_BIT_RATE == 20000
+#define CAN_BIT_TIMING CAN_BIT_REG(8, 7, 4, 50) // tProp = 3125ns
+#else
+#error Invalid CAN_BIT_RATE value used with a 16MHz crystal.
+#endif
+
+//*****************************************************************************
+//
+// The settings for a 12MHz crystal frequency.
+//
+//*****************************************************************************
+#elif CRYSTAL_FREQ == 12000000
+#if CAN_BIT_RATE == 1000000
+#define CAN_BIT_TIMING CAN_BIT_REG(8, 3, 3, 1) // tProp = 416ns
+#elif CAN_BIT_RATE == 500000
+#define CAN_BIT_TIMING CAN_BIT_REG(7, 4, 4, 2) // tProp = 500ns
+#elif CAN_BIT_RATE == 250000
+#define CAN_BIT_TIMING CAN_BIT_REG(6, 5, 4, 4) // tProp = 333ns
+#elif CAN_BIT_RATE == 125000
+#define CAN_BIT_TIMING CAN_BIT_REG(8, 7, 4, 6) // tProp = 500ns
+#elif CAN_BIT_RATE == 50000
+#define CAN_BIT_TIMING CAN_BIT_REG(8, 7, 4, 15) // tProp = 1250ns
+#elif CAN_BIT_RATE == 20000
+#define CAN_BIT_TIMING CAN_BIT_REG(6, 5, 4, 50) // tProp = 4166ns
+#else
+#error Invalid CAN_BIT_RATE value used with a 12MHz crystal.
+#endif
+
+//*****************************************************************************
+//
+// The settings for a 10MHz crystal frequency.
+//
+//*****************************************************************************
+#elif CRYSTAL_FREQ == 10000000
+#if CAN_BIT_RATE == 1000000
+#define CAN_BIT_TIMING CAN_BIT_REG(6, 3, 3, 1) // tProp = 300ns
+#elif CAN_BIT_RATE == 500000
+#define CAN_BIT_TIMING CAN_BIT_REG(11, 8, 4, 1) // tProp = 300ns
+#elif CAN_BIT_RATE == 250000
+#define CAN_BIT_TIMING CAN_BIT_REG(5, 4, 4, 4) // tProp = 400ns
+#elif CAN_BIT_RATE == 125000
+#define CAN_BIT_TIMING CAN_BIT_REG(8, 7, 4, 5) // tProp = 500ns
+#elif CAN_BIT_RATE == 50000
+#define CAN_BIT_TIMING CAN_BIT_REG(5, 4, 4, 20) // tProp = 2000ns
+#elif CAN_BIT_RATE == 20000
+#define CAN_BIT_TIMING CAN_BIT_REG(5, 4, 4, 50) // tProp = 5000ns
+#else
+#error Invalid CAN_BIT_RATE value used with a 10MHz crystal.
+#endif
+
+//*****************************************************************************
+//
+// The settings for a 8MHz crystal frequency.
+//
+//*****************************************************************************
+#elif CRYSTAL_FREQ == 8000000
+#if CAN_BIT_RATE == 1000000
+#define CAN_BIT_TIMING CAN_BIT_REG(5, 2, 2, 1) // tProp = 375ns
+#elif CAN_BIT_RATE == 500000
+#define CAN_BIT_TIMING CAN_BIT_REG(9, 6, 4, 1) // tProp = 375ns
+#elif CAN_BIT_RATE == 250000
+#define CAN_BIT_TIMING CAN_BIT_REG(4, 3, 3, 4) // tProp = 500ns
+#elif CAN_BIT_RATE == 125000
+#define CAN_BIT_TIMING CAN_BIT_REG(8, 7, 4, 4) // tProp = 500ns
+#elif CAN_BIT_RATE == 50000
+#define CAN_BIT_TIMING CAN_BIT_REG(8, 7, 4, 10) // tProp = 1250ns
+#elif CAN_BIT_RATE == 20000
+#define CAN_BIT_TIMING CAN_BIT_REG(8, 7, 4, 25) // tProp = 3125ns
+#else
+#error Invalid CAN_BIT_RATE value used with a 8MHz crystal.
+#endif
+
+//*****************************************************************************
+//
+// The settings for a 6MHz crystal frequency.
+//
+//*****************************************************************************
+#elif CRYSTAL_FREQ == 6000000
+#if CAN_BIT_RATE == 500000
+#define CAN_BIT_TIMING CAN_BIT_REG(7, 4, 4, 1) // tProp = 500ns
+#elif CAN_BIT_RATE == 250000
+#define CAN_BIT_TIMING CAN_BIT_REG(6, 5, 4, 2) // tProp = 333ns
+#elif CAN_BIT_RATE == 125000
+#define CAN_BIT_TIMING CAN_BIT_REG(8, 7, 4, 3) // tProp = 500ns
+#elif CAN_BIT_RATE == 50000
+#define CAN_BIT_TIMING CAN_BIT_REG(6, 5, 4, 10) // tProp = 1666ns
+#elif CAN_BIT_RATE == 20000
+#define CAN_BIT_TIMING CAN_BIT_REG(6, 5, 4, 25) // tProp = 4166ns
+#else
+#error Invalid CAN_BIT_RATE value used with a 6MHz crystal.
+#endif
+
+//*****************************************************************************
+//
+// The settings for a 5MHz crystal frequency.
+//
+//*****************************************************************************
+#elif CRYSTAL_FREQ == 5000000
+#if CAN_BIT_RATE == 500000
+#define CAN_BIT_TIMING CAN_BIT_REG(6, 3, 3, 1) // tProp = 600ns
+#elif CAN_BIT_RATE == 250000
+#define CAN_BIT_TIMING CAN_BIT_REG(5, 4, 4, 2) // tProp = 400ns
+#elif CAN_BIT_RATE == 125000
+#define CAN_BIT_TIMING CAN_BIT_REG(5, 4, 4, 4) // tProp = 800ns
+#elif CAN_BIT_RATE == 50000
+#define CAN_BIT_TIMING CAN_BIT_REG(5, 4, 4, 10) // tProp = 2000ns
+#elif CAN_BIT_RATE == 20000
+#define CAN_BIT_TIMING CAN_BIT_REG(5, 4, 4, 25) // tProp = 5000ns
+#else
+#error Invalid CAN_BIT_RATE value used with a 5MHz crystal.
+#endif
+
+//*****************************************************************************
+//
+// The settings for a 4MHz crystal frequency.
+//
+//*****************************************************************************
+#elif CRYSTAL_FREQ == 4000000
+#if CAN_BIT_RATE == 500000
+#define CAN_BIT_TIMING CAN_BIT_REG(5, 2, 2, 1) // tProp = 750ns
+#elif CAN_BIT_RATE == 250000
+#define CAN_BIT_TIMING CAN_BIT_REG(4, 3, 3, 2) // tProp = 500ns
+#elif CAN_BIT_RATE == 125000
+#define CAN_BIT_TIMING CAN_BIT_REG(8, 7, 4, 2) // tProp = 500ns
+#elif CAN_BIT_RATE == 50000
+#define CAN_BIT_TIMING CAN_BIT_REG(8, 7, 4, 5) // tProp = 1250ns
+#elif CAN_BIT_RATE == 20000
+#define CAN_BIT_TIMING CAN_BIT_REG(5, 4, 4, 20) // tProp = 5000ns
+#else
+#error Invalid CAN_BIT_RATE value used with a 4MHz crystal.
+#endif
+
+//*****************************************************************************
+//
+// The settings for a 2MHz crystal frequency.
+//
+//*****************************************************************************
+#elif CRYSTAL_FREQ == 2000000
+#if CAN_BIT_RATE == 250000
+#define CAN_BIT_TIMING CAN_BIT_REG(4, 3, 3, 1) // tProp = 500ns
+#elif CAN_BIT_RATE == 125000
+#define CAN_BIT_TIMING CAN_BIT_REG(8, 7, 4, 1) // tProp = 500ns
+#elif CAN_BIT_RATE == 50000
+#define CAN_BIT_TIMING CAN_BIT_REG(5, 4, 4, 4) // tProp = 2000ns
+#elif CAN_BIT_RATE == 20000
+#define CAN_BIT_TIMING CAN_BIT_REG(5, 4, 4, 10) // tProp = 5000ns
+#else
+#error Invalid CAN_BIT_RATE value used with a 2MHz crystal.
+#endif
+
+//*****************************************************************************
+//
+// The settings for a 1MHz crystal frequency.
+//
+//*****************************************************************************
+#elif CRYSTAL_FREQ == 1000000
+#if CAN_BIT_RATE == 125000
+#define CAN_BIT_TIMING CAN_BIT_REG(4, 3, 3, 1) // tProp = 1000ns
+#elif CAN_BIT_RATE == 50000
+#define CAN_BIT_TIMING CAN_BIT_REG(5, 4, 4, 2) // tProp = 2000ns
+#elif CAN_BIT_RATE == 20000
+#define CAN_BIT_TIMING CAN_BIT_REG(5, 4, 4, 5) // tProp = 5000ns
+#else
+#error Invalid CAN_BIT_RATE value used with a 1MHz crystal.
+#endif
+
+//*****************************************************************************
+//
+// An unsupported crystal frequency was specified.
+//
+//*****************************************************************************
+#else
+#error The CRYSTAL_FREQ value is not supported by the CAN controller.
+#endif
+
+#endif
+
+#endif // __BL_CAN_TIMING_H__
diff --git a/boot_loader/bl_check.c b/boot_loader/bl_check.c
new file mode 100644
index 0000000..b481013
--- /dev/null
+++ b/boot_loader/bl_check.c
@@ -0,0 +1,266 @@
+//*****************************************************************************
+//
+// bl_check.c - Code to check for a forced update.
+//
+// Copyright (c) 2006-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
+//
+//*****************************************************************************
+
+#include <stdint.h>
+#include <stdbool.h>
+#include "inc/hw_gpio.h"
+#include "inc/hw_memmap.h"
+#include "inc/hw_sysctl.h"
+#include "inc/hw_types.h"
+#include "bl_config.h"
+#include "boot_loader/bl_check.h"
+#include "boot_loader/bl_hooks.h"
+#ifdef CHECK_CRC
+#include "boot_loader/bl_crc32.h"
+#endif
+
+//*****************************************************************************
+//
+//! \addtogroup bl_check_api
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// This global is used to remember if a forced update occurred.
+//
+//*****************************************************************************
+#ifdef ENABLE_UPDATE_CHECK
+uint32_t g_ui32Forced;
+#endif
+
+//*****************************************************************************
+//
+// A prototype for the function (in the startup code) for a predictable length
+// delay.
+//
+//*****************************************************************************
+extern void Delay(uint32_t ui32Count);
+
+//*****************************************************************************
+//
+//! Checks a GPIO for a forced update.
+//!
+//! This function checks the state of a GPIO to determine if a update is being
+//! requested.
+//!
+//! \return Returns a non-zero value if an update is being requested and zero
+//! otherwise.
+//
+//*****************************************************************************
+#ifdef ENABLE_UPDATE_CHECK
+uint32_t
+CheckGPIOForceUpdate(void)
+{
+ //
+ // Enable the required GPIO module.
+ //
+ HWREG(SYSCTL_RCGC2) |= FORCED_UPDATE_PERIPH;
+
+ //
+ // Wait a while before accessing the peripheral.
+ //
+ Delay(3);
+
+#ifdef FORCED_UPDATE_KEY
+ //
+ // Unlock the GPIO Access.
+ //
+ HWREG(FORCED_UPDATE_PORT + GPIO_O_LOCK) = FORCED_UPDATE_KEY;
+ HWREG(FORCED_UPDATE_PORT + GPIO_O_CR) = 1 << FORCED_UPDATE_PIN;
+#endif
+
+ //
+ // Enable the pin used to see if an update is being requested.
+ //
+ HWREG(FORCED_UPDATE_PORT + GPIO_O_DEN) |= 1 << FORCED_UPDATE_PIN;
+#ifdef FORCED_UPDATE_WPU
+ //
+ // Set the output drive strength.
+ //
+ HWREG(FORCED_UPDATE_PORT + GPIO_O_DR2R) |= 1 << FORCED_UPDATE_PIN;
+
+ //
+ // Enable the weak pull up.
+ //
+ HWREG(FORCED_UPDATE_PORT + GPIO_O_PUR) |= 1 << FORCED_UPDATE_PIN;
+
+ //
+ // Make sure that the analog mode select register is clear for this pin.
+ //
+ HWREG(FORCED_UPDATE_PORT + GPIO_O_AMSEL) &= ~(1 << FORCED_UPDATE_PIN);
+#endif
+#ifdef FORCED_UPDATE_WPD
+ //
+ // Set the output drive strength.
+ //
+ HWREG(FORCED_UPDATE_PORT + GPIO_O_DR2R) |= 1 << FORCED_UPDATE_PIN;
+
+ //
+ // Enable the weak pull down.
+ //
+ HWREG(FORCED_UPDATE_PORT + GPIO_O_PDR) |= 1 << FORCED_UPDATE_PIN;
+
+ //
+ // Make sure that the analog mode select register is clear for this pin.
+ // This register only appears in DustDevil-class (and later) devices, but
+ // is a harmless write on Sandstorm- and Fury-class devices.
+ //
+ HWREG(FORCED_UPDATE_PORT + GPIO_O_AMSEL) &= ~(1 << FORCED_UPDATE_PIN);
+#endif
+
+#ifdef FORCED_UPDATE_KEY
+ //
+ // Unlock the GPIO Access.
+ //
+ HWREG(FORCED_UPDATE_PORT + GPIO_O_LOCK) = FORCED_UPDATE_KEY;
+ HWREG(FORCED_UPDATE_PORT + GPIO_O_CR) = 0;
+#endif
+
+ //
+ // Wait a while before reading the pin.
+ //
+ Delay(1000);
+
+ //
+ // Check the pin to see if an update is being requested.
+ //
+ if(HWREG(FORCED_UPDATE_PORT + (1 << (FORCED_UPDATE_PIN + 2))) ==
+ (FORCED_UPDATE_POLARITY << FORCED_UPDATE_PIN))
+ {
+ //
+ // Remember that this was a forced update.
+ //
+ g_ui32Forced = 1;
+
+ return(1);
+ }
+
+ //
+ // No update is being requested so return 0.
+ //
+ return(0);
+}
+#endif
+
+//*****************************************************************************
+//
+//! Checks if an update is needed or is being requested.
+//!
+//! This function detects if an update is being requested or if there is no
+//! valid code presently located on the microcontroller. This is used to tell
+//! whether or not to enter update mode.
+//!
+//! \return Returns a non-zero value if an update is needed or is being
+//! requested and zero otherwise.
+//
+//*****************************************************************************
+uint32_t
+CheckForceUpdate(void)
+{
+#ifdef CHECK_CRC
+ uint32_t ui32Retcode;
+#endif
+
+#ifdef BL_CHECK_UPDATE_FN_HOOK
+ //
+ // If the update check function is hooked, call the application to determine
+ // how to proceed.
+ //
+ return(BL_CHECK_UPDATE_FN_HOOK());
+#else
+ uint32_t *pui32App;
+
+#ifdef ENABLE_UPDATE_CHECK
+ g_ui32Forced = 0;
+#endif
+
+ //
+ // See if the first location is 0xfffffffff or something that does not
+ // look like a stack pointer, or if the second location is 0xffffffff or
+ // something that does not look like a reset vector.
+ //
+ pui32App = (uint32_t *)APP_START_ADDRESS;
+ if((pui32App[0] == 0xffffffff) ||
+ ((pui32App[0] & 0xfff00000) != 0x20000000) ||
+ (pui32App[1] == 0xffffffff) ||
+ ((pui32App[1] & 0xfff00001) != 0x00000001))
+ {
+ return(1);
+ }
+
+ //
+ // If required, scan the image for an embedded CRC and ensure that it
+ // matches the current CRC of the image.
+ //
+#ifdef CHECK_CRC
+ InitCRC32Table();
+ ui32Retcode = CheckImageCRC32(pui32App);
+
+ //
+ // If ENFORCE_CRC is defined, we only boot the image if the CRC is
+ // present in the image information header and the value calculated
+ // matches the value in the header. If ENFORCE_CRC is not defined, we
+ // the image if the CRC is good but also if the length field of the header
+ // is zero (which typically indicates that the post-build step of running
+ // binpack to add the length and CRC to the header was not run).
+ //
+#ifdef ENFORCE_CRC
+ if(ui32Retcode != CHECK_CRC_OK)
+#else
+ if((ui32Retcode != CHECK_CRC_OK) && (ui32Retcode != CHECK_CRC_NO_LENGTH))
+#endif
+ {
+ //
+ // The CRC32 image check failed indicating that the image is
+ // corrupt (or doesn't have the CRC embedded correctly). Either way,
+ // fail the update check and force the boot loader to retain control.
+ //
+ return(2);
+ }
+#endif
+
+#ifdef ENABLE_UPDATE_CHECK
+ //
+ // If simple GPIO checking is configured, determine whether or not to force
+ // an update.
+ //
+ return(CheckGPIOForceUpdate());
+#else
+ //
+ // GPIO checking is not required so, if we get here, a valid image exists
+ // and no update is needed.
+ //
+ return(0);
+#endif
+#endif
+}
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
diff --git a/boot_loader/bl_check.h b/boot_loader/bl_check.h
new file mode 100644
index 0000000..a3e0519
--- /dev/null
+++ b/boot_loader/bl_check.h
@@ -0,0 +1,39 @@
+//*****************************************************************************
+//
+// bl_check.h - Definitions for the forced update check function.
+//
+// Copyright (c) 2007-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
+//
+//*****************************************************************************
+
+#ifndef __BL_CHECK_H__
+#define __BL_CHECK_H__
+
+//*****************************************************************************
+//
+// Prototype for the forced update check function.
+//
+//*****************************************************************************
+extern uint32_t CheckForceUpdate(void);
+#ifdef ENABLE_UPDATE_CHECK
+extern uint32_t CheckGPIOForceUpdate(void);
+extern uint32_t g_ui32Forced;
+#endif
+
+#endif // __BL_CHECK_H__
diff --git a/boot_loader/bl_commands.h b/boot_loader/bl_commands.h
new file mode 100644
index 0000000..f666e15
--- /dev/null
+++ b/boot_loader/bl_commands.h
@@ -0,0 +1,242 @@
+//*****************************************************************************
+//
+// bl_commands.h - The list of commands and return messages supported by the
+// boot loader.
+//
+// Copyright (c) 2006-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
+//
+//*****************************************************************************
+
+#ifndef __BL_COMMANDS_H__
+#define __BL_COMMANDS_H__
+
+//*****************************************************************************
+//
+// This command is used to receive an acknowledge from the the boot loader
+// proving that communication has been established. This command is a single
+// byte.
+//
+// The format of the command is as follows:
+//
+// uint8_t ui8Command[1];
+//
+// ui8Command[0] = COMMAND_PING;
+//
+//*****************************************************************************
+#define COMMAND_PING 0x20
+
+//*****************************************************************************
+//
+// This command is sent to the boot loader to indicate where to store data and
+// how many bytes will be sent by the COMMAND_SEND_DATA commands that follow.
+// The command consists of two 32-bit values that are both transferred MSB
+// first. The first 32-bit value is the address to start programming data
+// into, while the second is the 32-bit size of the data that will be sent.
+// This command also triggers an erasure of the full application area in the
+// flash or possibly the entire flash depending on the address used. This
+// causes the command to take longer to send the ACK/NAK in response to the
+// command. This command should be followed by a COMMAND_GET_STATUS to ensure
+// that the program address and program size were valid for the microcontroller
+// running the boot loader.
+//
+// The format of the command is as follows:
+//
+// uint8_t ui8Command[9];
+//
+// ui8Command[0] = COMMAND_DOWNLOAD;
+// ui8Command[1] = Program Address [31:24];
+// ui8Command[2] = Program Address [23:16];
+// ui8Command[3] = Program Address [15:8];
+// ui8Command[4] = Program Address [7:0];
+// ui8Command[5] = Program Size [31:24];
+// ui8Command[6] = Program Size [23:16];
+// ui8Command[7] = Program Size [15:8];
+// ui8Command[8] = Program Size [7:0];
+//
+//*****************************************************************************
+#define COMMAND_DOWNLOAD 0x21
+
+//*****************************************************************************
+//
+// This command is sent to the boot loader to transfer execution control to the
+// specified address. The command is followed by a 32-bit value, transferred
+// MSB first, that is the address to which execution control is transferred.
+//
+// The format of the command is as follows:
+//
+// uint8_t ui8Command[5];
+//
+// ui8Command[0] = COMMAND_RUN;
+// ui8Command[1] = Run Address [31:24];
+// ui8Command[2] = Run Address [23:16];
+// ui8Command[3] = Run Address [15:8];
+// ui8Command[4] = Run Address [7:0];
+//
+//*****************************************************************************
+#define COMMAND_RUN 0x22
+
+//*****************************************************************************
+//
+// This command returns the status of the last command that was issued.
+// Typically this command should be received after every command is sent to
+// ensure that the previous command was successful or, if unsuccessful, to
+// properly respond to a failure. The command requires one byte in the data of
+// the packet and the boot loader should respond by sending a packet with one
+// byte of data that contains the current status code.
+//
+// The format of the command is as follows:
+//
+// uint8_t ui8Command[1];
+//
+// ui8Command[0] = COMMAND_GET_STATUS;
+//
+// The following are the definitions for the possible status values that can be
+// returned from the boot loader when <tt>COMMAND_GET_STATUS</tt> is sent to
+// the microcontroller.
+//
+// COMMAND_RET_SUCCESS
+// COMMAND_RET_UNKNOWN_CMD
+// COMMAND_RET_INVALID_CMD
+// COMMAND_RET_INVALID_ADD
+// COMMAND_RET_FLASH_FAIL
+// COMMAND_RET_CRC_FAIL
+//
+//*****************************************************************************
+#define COMMAND_GET_STATUS 0x23
+
+//*****************************************************************************
+//
+// This command should only follow a COMMAND_DOWNLOAD command or another
+// COMMAND_SEND_DATA command, if more data is needed. Consecutive send data
+// commands automatically increment the address and continue programming from
+// the previous location. The transfer size is limited by the size of the
+// receive buffer in the boot loader (as configured by the BUFFER_SIZE
+// parameter). The command terminates programming once the number of bytes
+// indicated by the COMMAND_DOWNLOAD command has been received. Each time this
+// function is called, it should be followed by a COMMAND_GET_STATUS command to
+// ensure that the data was successfully programmed into the flash. If the
+// boot loader sends a NAK to this command, the boot loader will not increment
+// the current address to allow retransmission of the previous data.
+//
+// The format of the command is as follows:
+//
+// uint8_t ui8Command[9];
+//
+// ui8Command[0] = COMMAND_SEND_DATA;
+// ui8Command[1] = Data[0];
+// ui8Command[2] = Data[1];
+// ui8Command[3] = Data[2];
+// ui8Command[4] = Data[3];
+// ui8Command[5] = Data[4];
+// ui8Command[6] = Data[5];
+// ui8Command[7] = Data[6];
+// ui8Command[8] = Data[7];
+//
+//*****************************************************************************
+#define COMMAND_SEND_DATA 0x24
+
+//*****************************************************************************
+//
+// This command is used to tell the boot loader to reset. This is used after
+// downloading a new image to the microcontroller to cause the new application
+// or the new boot loader to start from a reset. The normal boot sequence
+// occurs and the image runs as if from a hardware reset. It can also be used
+// to reset the boot loader if a critical error occurs and the host device
+// wants to restart communication with the boot loader.
+//
+// The format of the command is as follows:
+//
+// uint8_t ui8Command[1];
+//
+// ui8Command[0] = COMMAND_RESET;
+//
+// The boot loader responds with an ACK signal to the host device before
+// actually executing the software reset on the microcontroller running the
+// boot loader. This informs the updater application that the command was
+// received successfully and the part will be reset.
+//
+//*****************************************************************************
+#define COMMAND_RESET 0x25
+
+//*****************************************************************************
+//
+// This is returned in response to a COMMAND_GET_STATUS command and indicates
+// that the previous command completed successful.
+//
+//*****************************************************************************
+#define COMMAND_RET_SUCCESS 0x40
+
+//*****************************************************************************
+//
+// This is returned in response to a COMMAND_GET_STATUS command and indicates
+// that the command sent was an unknown command.
+//
+//*****************************************************************************
+#define COMMAND_RET_UNKNOWN_CMD 0x41
+
+//*****************************************************************************
+//
+// This is returned in response to a COMMAND_GET_STATUS command and indicates
+// that the previous command was formatted incorrectly.
+//
+//*****************************************************************************
+#define COMMAND_RET_INVALID_CMD 0x42
+
+//*****************************************************************************
+//
+// This is returned in response to a COMMAND_GET_STATUS command and indicates
+// that the previous download command contained an invalid address value.
+//
+//*****************************************************************************
+#define COMMAND_RET_INVALID_ADR 0x43
+
+//*****************************************************************************
+//
+// This is returned in response to a COMMAND_GET_STATUS command and indicates
+// that an attempt to program or erase the flash has failed.
+//
+//*****************************************************************************
+#define COMMAND_RET_FLASH_FAIL 0x44
+
+//*****************************************************************************
+//
+// This is returned in response to a COMMAND_GET_STATUS command and indicates
+// that the boot loader is configured to check the embedded CRC32 in the
+// downloaded image but the check failed. This status can only be returned
+// after the last COMMAND_SEND_DATA has been received and processed, and only
+// if CHECK_CRC is defined in the boot loader configuration.
+//
+//*****************************************************************************
+#define COMMAND_RET_CRC_FAIL 0x45
+
+//*****************************************************************************
+//
+// This is the value that is sent to acknowledge a packet.
+//
+//*****************************************************************************
+#define COMMAND_ACK 0xcc
+
+//*****************************************************************************
+//
+// This is the value that is sent to not-acknowledge a packet.
+//
+//*****************************************************************************
+#define COMMAND_NAK 0x33
+
+#endif // __BL_COMMANDS_H__
diff --git a/boot_loader/bl_config.c b/boot_loader/bl_config.c
new file mode 100644
index 0000000..9c26068
--- /dev/null
+++ b/boot_loader/bl_config.c
@@ -0,0 +1,164 @@
+//*****************************************************************************
+//
+// bl_config.c - A dummy C file to generate bl_config.in from bl_config.h.
+//
+// Copyright (c) 2007-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
+//
+//*****************************************************************************
+
+#include "bl_config.h"
+
+//*****************************************************************************
+//
+// Since the RV-MDK assembler is not able to run assembly code through the C
+// preprocessor, the relevant contents of bl_config.h need to be converted to
+// assembly format for inclusion into the RV-MDK startup code. This file
+// performs this conversion when manually run through the C preprocessor via:
+//
+// armcc --device DLM -o bl_config.inc -E bl_config.c
+//
+// This file does not contain valid C code and will fail to compile (-E tells
+// the compiler to preprocess but not attempt to compile the code).
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// Define an assembler symbol for the stack size.
+//
+//*****************************************************************************
+_STACK_SIZE equ STACK_SIZE
+
+//*****************************************************************************
+//
+// Define an assembler symbol for the application starting address.
+//
+//*****************************************************************************
+_APP_START_ADDRESS equ APP_START_ADDRESS
+
+//*****************************************************************************
+//
+// Define an assembler symbol for the application vector table address.
+//
+//*****************************************************************************
+_VTABLE_START_ADDRESS equ VTABLE_START_ADDRESS
+
+//*****************************************************************************
+//
+// Define an assembler symbol if the MOSCFAIL handler is enabled.
+//
+//*****************************************************************************
+#ifdef ENABLE_MOSCFAIL_HANDLER
+_ENABLE_MOSCFAIL_HANDLER equ 1
+#endif
+
+//*****************************************************************************
+//
+// Define an assembler symbol if update via the UART is enabled.
+//
+//*****************************************************************************
+#ifdef UART_ENABLE_UPDATE
+_UART_ENABLE_UPDATE equ 1
+#endif
+
+//*****************************************************************************
+//
+// Define an assember symbol if UART autobauding is enabled.
+//
+//*****************************************************************************
+#ifdef UART_AUTOBAUD
+_UART_AUTOBAUD equ 1
+#endif
+
+//*****************************************************************************
+//
+// Define an assembler symbol if update via Ethernet is enabled.
+//
+//*****************************************************************************
+#ifdef ENET_ENABLE_UPDATE
+_ENET_ENABLE_UPDATE equ 1
+#endif
+
+//*****************************************************************************
+//
+// Define an assembler symbol if update via CAN is enabled.
+//
+//*****************************************************************************
+#ifdef CAN_ENABLE_UPDATE
+_CAN_ENABLE_UPDATE equ 1
+#endif
+
+//*****************************************************************************
+//
+// Define an assembler symbol if update via USB is enabled.
+//
+//*****************************************************************************
+#ifdef USB_ENABLE_UPDATE
+_USB_ENABLE_UPDATE equ 1
+#endif
+
+//*****************************************************************************
+//
+// Define an assembler symbol if a hardware initialization hook is provided.
+//
+//*****************************************************************************
+#ifdef BL_HW_INIT_FN_HOOK
+#define _quote(x) #x
+#define quote(x) _quote(x)
+ gbls _BL_HW_INIT_FN_HOOK
+_BL_HW_INIT_FN_HOOK sets quote(BL_HW_INIT_FN_HOOK)
+#undef _quote
+#undef quote
+#endif
+
+//*****************************************************************************
+//
+// Define an assembler symbol if an initialization hook is provided.
+//
+//*****************************************************************************
+#ifdef BL_INIT_FN_HOOK
+#define _quote(x) #x
+#define quote(x) _quote(x)
+ gbls _BL_INIT_FN_HOOK
+_BL_INIT_FN_HOOK sets quote(BL_INIT_FN_HOOK)
+#undef _quote
+#undef quote
+#endif
+
+//*****************************************************************************
+//
+// Define an assembler symbol if a re-initialization hook is provided.
+//
+//*****************************************************************************
+#ifdef BL_REINIT_FN_HOOK
+#define _quote(x) #x
+#define quote(x) _quote(x)
+ gbls _BL_REINIT_FN_HOOK
+_BL_REINIT_FN_HOOK sets quote(BL_REINIT_FN_HOOK)
+#undef _quote
+#undef quote
+#endif
+
+//*****************************************************************************
+//
+// The assembler will require an end statement at the end of the output
+// bl_config.inc file.
+//
+//*****************************************************************************
+ end
diff --git a/boot_loader/bl_config.h.tmpl b/boot_loader/bl_config.h.tmpl
new file mode 100644
index 0000000..99ab978
--- /dev/null
+++ b/boot_loader/bl_config.h.tmpl
@@ -0,0 +1,950 @@
+//*****************************************************************************
+//
+// bl_config.h - The configurable parameters of the boot loader.
+//
+// Copyright (c) 2010-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
+//
+//*****************************************************************************
+
+#ifndef __BL_CONFIG_H__
+#define __BL_CONFIG_H__
+
+//*****************************************************************************
+//
+// The following defines are used to configure the operation of the boot
+// loader. For each define, its interactions with other defines are described.
+// First is the dependencies (i.e. the defines that must also be defined if it
+// is defined), next are the exclusives (i.e. the defines that can not be
+// defined if it is defined), and finally are the requirements (i.e. the
+// defines that must be defined if it is defined).
+//
+// The following defines must be defined in order for the boot loader to
+// operate:
+//
+// One of CAN_ENABLE_UPDATE, ENET_ENABLE_UPDATE, I2C_ENABLE_UPDATE,
+// SSI_ENABLE_UPDATE, UART_ENABLE_UPDATE, or USB_ENABLE_UPDATE
+// APP_START_ADDRESS
+// STACK_SIZE
+// BUFFER_SIZE
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// The frequency of the crystal used to clock the microcontroller.
+//
+// This defines the crystal frequency used by the microcontroller running the
+// boot loader. If this is unknown at the time of production, then use the
+// UART_AUTOBAUD feature to properly configure the UART.
+//
+// Depends on: None
+// Exclusive of: None
+// Requires: None
+//
+//*****************************************************************************
+#define CRYSTAL_FREQ 8000000
+
+//*****************************************************************************
+//
+// This enables the boosting of the LDO voltage to 2.75V. For boot loader
+// configurations that enable the PLL (for example, using the Ethernet port)
+// on a part that has the PLL errata, this should be enabled. This applies to
+// revision A2 of Fury-class devices.
+//
+// Depends on: None
+// Exclusive of: None
+// Requires: None
+//
+//*****************************************************************************
+//#define BOOST_LDO_VOLTAGE
+
+//*****************************************************************************
+//
+// The starting address of the application. This must be a multiple of 1024
+// bytes (making it aligned to a page boundary). A vector table is expected at
+// this location, and the perceived validity of the vector table (stack located
+// in SRAM, reset vector located in flash) is used as an indication of the
+// validity of the application image.
+//
+// The flash image of the boot loader must not be larger than this value.
+//
+// Depends on: None
+// Exclusive of: None
+// Requires: None
+//
+//*****************************************************************************
+#define APP_START_ADDRESS 0x00001000
+
+//*****************************************************************************
+//
+// The address at which the application locates its exception vector table.
+// This must be a multiple of 1KB (making it aligned to a page boundary).
+// Typically, an application will start with its vector table and this value
+// will default to APP_START_ADDRESS. This option is provided to cater for
+// applications which run from external memory which may not be accessible by
+// the NVIC (the vector table offset register is only 30 bits long).
+//
+// Depends on: None
+// Exclusive of: None
+// Requires: None
+//
+//*****************************************************************************
+#define VTABLE_START_ADDRESS 0x00001000
+
+//*****************************************************************************
+//
+// The size of a single, erasable page in the flash. This must be a power
+// of 2. The default value of 1KB represents the page size for the internal
+// flash on all Tiva MCUs and this value should only be overridden if
+// configuring a boot loader to access external flash devices with a page size
+// different from this.
+//
+// Depends on: None
+// Exclusive of: None
+// Requires: None
+//
+//*****************************************************************************
+#define FLASH_PAGE_SIZE 0x00000400
+
+//*****************************************************************************
+//
+// The amount of space at the end of flash to reserved. This must be a
+// multiple of 1024 bytes (making it aligned to a page boundary). This
+// reserved space is not erased when the application is updated, providing
+// non-volatile storage that can be used for parameters.
+//
+// Depends on: None
+// Exclusive of: None
+// Requires: None
+//
+//*****************************************************************************
+//#define FLASH_RSVD_SPACE 0x00000800
+
+//*****************************************************************************
+//
+// The number of words of stack space to reserve for the boot loader.
+//
+// Depends on: None
+// Exclusive of: None
+// Requires: None
+//
+//*****************************************************************************
+#define STACK_SIZE 64
+
+//*****************************************************************************
+//
+// The number of words in the data buffer used for receiving packets. This
+// value must be at least 3. If using autobauding on the UART, this must be at
+// least 20. The maximum usable value is 65 (larger values will result in
+// unused space in the buffer).
+//
+// Depends on: None
+// Exclusive of: None
+// Requires: None
+//
+//*****************************************************************************
+#define BUFFER_SIZE 20
+
+//*****************************************************************************
+//
+// Enables updates to the boot loader. Updating the boot loader is an unsafe
+// operation since it is not fully fault tolerant (losing power to the device
+// part way though could result in the boot loader no longer being present in
+// flash).
+//
+// Depends on: None
+// Exclusive of: None
+// Requires: None
+//
+//*****************************************************************************
+//#define ENABLE_BL_UPDATE
+
+//*****************************************************************************
+//
+// This definition will cause the the boot loader to erase the entire flash on
+// updates to the boot loader or to erase the entire application area when the
+// application is updated. This erases any unused sections in the flash before
+// the firmware is updated.
+//
+// Depends on: None
+// Exclusive of: None
+// Requires: None
+//
+//*****************************************************************************
+//#define FLASH_CODE_PROTECTION
+
+//*****************************************************************************
+//
+// Enables the call to decrypt the downloaded data before writing it into
+// flash. The decryption routine is empty in the reference boot loader source,
+// which simply provides a placeholder for adding an actual decrypter.
+//
+// Depends on: None
+// Exclusive of: None
+// Requires: None
+//
+//*****************************************************************************
+//#define ENABLE_DECRYPTION
+
+//*****************************************************************************
+//
+// Enables support for the MOSCFAIL handler in the NMI interrupt.
+// Note: Sandstorm or Fury devices do not provide the MOSCFAIL reset, so this
+// feature should not be enabled for these devices.
+//
+// Depends on: None
+// Exclusive of: None
+// Requires: None
+//
+//*****************************************************************************
+//#define ENABLE_MOSCFAIL_HANDLER
+
+//*****************************************************************************
+//
+// Enables the pin-based forced update check. When enabled, the boot loader
+// will go into update mode instead of calling the application if a pin is read
+// at a particular polarity, forcing an update operation. In either case, the
+// application is still able to return control to the boot loader in order to
+// start an update.
+//
+// Depends on: None
+// Exclusive of: None
+// Requires: FORCED_UPDATE_PERIPH, FORCED_UPDATE_PORT, FORCED_UPDATE_PIN,
+// FORCED_UPDATE_POLARITY
+//
+//*****************************************************************************
+//#define ENABLE_UPDATE_CHECK
+
+//*****************************************************************************
+//
+// The GPIO module to enable in order to check for a forced update. This will
+// be one of the SYSCTL_RCGC2_GPIOx values, where "x" is replaced with the port
+// name (such as B). The value of "x" should match the value of "x" for
+// FORCED_UPDATE_PORT.
+//
+// Depends on: ENABLE_UPDATE_CHECK
+// Exclusive of: None
+// Requries: None
+//
+//*****************************************************************************
+//#define FORCED_UPDATE_PERIPH SYSCTL_RCGC2_GPIOB
+
+//*****************************************************************************
+//
+// The GPIO port to check for a forced update. This will be one of the
+// GPIO_PORTx_BASE values, where "x" is replaced with the port name (such as
+// B). The value of "x" should match the value of "x" for
+// FORCED_UPDATE_PERIPH.
+//
+// Depends on: ENABLE_UPDATE_CHECK
+// Exclusive of: None
+// Requries: None
+//
+//*****************************************************************************
+//#define FORCED_UPDATE_PORT GPIO_PORTB_BASE
+
+//*****************************************************************************
+//
+// The pin to check for a forced update. This is a value between 0 and 7.
+//
+// Depends on: ENABLE_UPDATE_CHECK
+// Exclusive of: None
+// Requries: None
+//
+//*****************************************************************************
+//#define FORCED_UPDATE_PIN 4
+
+//*****************************************************************************
+//
+// The polarity of the GPIO pin that results in a forced update. This value
+// should be 0 if the pin should be low and 1 if the pin should be high.
+//
+// Depends on: ENABLE_UPDATE_CHECK
+// Exclusive of: None
+// Requries: None
+//
+//*****************************************************************************
+//#define FORCED_UPDATE_POLARITY 0
+
+//*****************************************************************************
+//
+// This enables a weak pull up for the GPIO pin used in a forced update. This
+// value should be 0 if the pin should be have an internal weak pull down and
+// 1 if the pin should have an interal weak pull up.
+// Only FORCED_UPDATE_WPU or FORCED_UPDATE_WPD or neither should be defined.
+//
+// Depends on: ENABLE_UPDATE_CHECK
+// Exclusive of: None
+// Requries: None
+//
+//*****************************************************************************
+//#define FORCED_UPDATE_WPU
+//#define FORCED_UPDATE_WPD
+
+//*****************************************************************************
+//
+// This enables the use of the GPIO_LOCK mechanism for configuration of
+// protected GPIO pins (for example JTAG pins). If this value is not defined,
+// the locking mechanism will not be used. The only legal values for this
+// feature are GPIO_LOCK_KEY for Fury devices and GPIO_LOCK_KEY_DD for all
+// other devices except Sandstorm devices, which do not support this feature.
+//
+// Depends on: ENABLE_UPDATE_CHECK
+// Exclusive of: None
+// Requries: None
+//
+//*****************************************************************************
+//#define FORCED_UPDATE_KEY GPIO_LOCK_KEY
+//#define FORCED_UPDATE_KEY GPIO_LOCK_KEY_DD
+
+//*****************************************************************************
+//
+// Selects the UART as the port for communicating with the boot loader.
+//
+// Depends on: None
+// Exclusive of: CAN_ENABLE_UPDATE, ENET_ENABLE_UPDATE, I2C_ENABLE_UPDATE,
+// SSI_ENABLE_UPDATE, USB_ENABLE_UPDATE
+// Requires: UART_AUTOBAUD or UART_FIXED_BAUDRATE
+//
+//*****************************************************************************
+//#define UART_ENABLE_UPDATE
+
+//*****************************************************************************
+//
+// Enables automatic baud rate detection. This can be used if the crystal
+// frequency is unknown, or if operation at different baud rates is desired.
+//
+// Depends on: UART_ENABLE_UPDATE
+// Exclusive of: UART_FIXED_BAUDRATE
+// Requires: None
+//
+//*****************************************************************************
+//#define UART_AUTOBAUD
+
+//*****************************************************************************
+//
+// Selects the baud rate to be used for the UART.
+//
+// Depends on: UART_ENABLE_UPDATE, CRYSTAL_FREQ
+// Exclusive of: UART_AUTOBAUD
+// Requires: None
+//
+//*****************************************************************************
+//#define UART_FIXED_BAUDRATE 115200
+
+//*****************************************************************************
+//
+// Selects the SSI port as the port for communicating with the boot loader.
+//
+// Depends on: None
+// Exclusive of: CAN_ENABLE_UPDATE, ENET_ENABLE_UPDATE, I2C_ENABLE_UPDATE,
+// UART_ENABLE_UPDATE, USB_ENABLE_UPDATE
+// Requires: None
+//
+//*****************************************************************************
+//#define SSI_ENABLE_UPDATE
+
+//*****************************************************************************
+//
+// Selects the I2C port as the port for communicating with the boot loader.
+//
+// Depends on: None
+// Exclusive of: CAN_ENABLE_UPDATE, ENET_ENABLE_UPDATE, SSI_ENABLE_UPDATE,
+// UART_ENABLE_UPDATE, USB_ENABLE_UPDATE
+// Requires: I2C_SLAVE_ADDR
+//
+//*****************************************************************************
+//#define I2C_ENABLE_UPDATE
+
+//*****************************************************************************
+//
+// Specifies the I2C address of the boot loader.
+//
+// Depends on: I2C_ENABLE_UPDATE
+// Exclusive of: None
+// Requires: None
+//
+//*****************************************************************************
+//#define I2C_SLAVE_ADDR 0x42
+
+//*****************************************************************************
+//
+// Selects Ethernet update via the BOOTP/TFTP protocol.
+//
+// Depends on: None
+// Exclusive of: CAN_ENABLE_UPDATE, I2C_ENABLE_UPDATE, SSI_ENABLE_UPDATE,
+// UART_ENABLE_UPDATE, USB_ENABLE_UPDATE
+// Requires: CRYSTAL_FREQ
+//
+//*****************************************************************************
+//#define ENET_ENABLE_UPDATE
+
+//*****************************************************************************
+//
+// Selects if the Ethernet LEDs should be enabled.
+//
+// Depends on: ENET_ENABLE_UPDATE
+// Exclusive of: None
+// Requires: None
+//
+//*****************************************************************************
+//#define ENET_ENABLE_LEDS
+
+//*****************************************************************************
+//
+// Selects the Ethernet MAC address. If not specified, the MAC address is
+// taken from the user registers.
+//
+// Depends on: ENET_ENABLE_UPDATE
+// Exclusive of: None
+// Requires: None
+//
+//*****************************************************************************
+//#define ENET_MAC_ADDR0 0x00
+//#define ENET_MAC_ADDR1 0x00
+//#define ENET_MAC_ADDR2 0x00
+//#define ENET_MAC_ADDR3 0x00
+//#define ENET_MAC_ADDR4 0x00
+//#define ENET_MAC_ADDR5 0x00
+
+//*****************************************************************************
+//
+// Sets the name of the BOOTP server to use. This can be used to request that
+// a particular BOOTP server respond to our request; the value will be either
+// the server's name, or a nickname used by that server. If not defined then
+// any BOOTP server is allowed to respond.
+//
+// Depends on: ENET_ENABLE_UPDATE
+// Exclusive of: None
+// Requires: None
+//
+//*****************************************************************************
+//#define ENET_BOOTP_SERVER "tiva"
+
+//*****************************************************************************
+//
+// Selects USB update via Device Firmware Update class.
+//
+// Depends on: None
+// Exclusive of: CAN_ENABLE_UPDATE, ENET_ENABLE_UPDATE, I2C_ENABLE_UPDATE,
+// SSI_ENABLE_UPDATE, UART_ENABLE_UPDATE,
+// Requires: CRYSTAL_FREQ, USB_VENDOR_ID, USB_PRODUCT_ID
+//
+//*****************************************************************************
+//#define USB_ENABLE_UPDATE
+
+//*****************************************************************************
+//
+// The USB vendor ID published by the DFU device. This value is the TI
+// Tiva vendor ID. Change this to the vendor ID you have been assigned by
+// USB-IF.
+//
+// Depends on: USB_ENABLE_UPDATE
+// Exclusive of: None
+// Requires: None
+//
+//*****************************************************************************
+//#define USB_VENDOR_ID 0x1cbe
+
+//*****************************************************************************
+//
+// The USB device ID published by the DFU device. If you are using your own
+// vendor ID, chose a device ID that is different from the ID you use in
+// non-update operation. If you have sublicensed TI's vendor ID, you must
+// use an assigned product ID here.
+//
+// Depends on: USB_ENABLE_UPDATE
+// Exclusive of: None
+// Requires: None
+//
+//*****************************************************************************
+//#define USB_PRODUCT_ID 0x00ff
+
+//*****************************************************************************
+//
+// Selects the BCD USB device release number published in the device
+// descriptor.
+//
+// Depends on: USB_ENABLE_UPDATE
+// Exclusive of: None
+// Requires: None
+//
+//*****************************************************************************
+//#define USB_DEVICE_ID 0x0001
+
+//*****************************************************************************
+//
+// Sets the maximum power consumption that the DFU device will report to the
+// USB host in the configuration descriptor. Units are milliamps.
+//
+// Depends on: USB_ENABLE_UPDATE
+// Exclusive of: None
+// Requires: None
+//
+//*****************************************************************************
+//#define USB_MAX_POWER 150
+
+//*****************************************************************************
+//
+// Determines whether the DFU device reports to the host that it is self
+// powered (defined as 0) or bus powered (defined as 1).
+//
+// Depends on: USB_ENABLE_UPDATE
+// Exclusive of: None
+// Requires: None
+//
+//*****************************************************************************
+//#define USB_BUS_POWERED 1
+
+//*****************************************************************************
+//
+// Specifies the GPIO peripheral associated with the USB host/device mux.
+//
+// Depends on: USB_ENABLE_UPDATE
+// Exclusive of: None
+// Requires: USB_MUX_PERIPH, USB_MUX_PORT, USB_MUX_PIN, USB_MUX_DEVICE
+//
+//*****************************************************************************
+//#define USB_HAS_MUX
+
+//*****************************************************************************
+//
+// Specifies the GPIO peripheral associated with the USB host/device mux.
+//
+// Depends on: USB_ENABLE_UPDATE, USB_HAS_MUX
+// Exclusive of: None
+// Requires: None
+//
+//*****************************************************************************
+//#define USB_MUX_PERIPH SYSCTL_RCGC2_GPIOH
+
+//*****************************************************************************
+//
+// Specifies the GPIO port associated with the USB host/device mux.
+//
+// Depends on: USB_ENABLE_UPDATE, USB_HAS_MUX
+// Exclusive of: None
+// Requires: None
+//
+//*****************************************************************************
+//#define USB_MUX_PORT GPIO_PORTH_BASE
+
+//*****************************************************************************
+//
+// Specifies the GPIO pin number used to switch the USB host/device mux. Valid
+// values are 0 through 7.
+//
+// Depends on: USB_ENABLE_UPDATE, USB_HAS_MUX
+// Exclusive of: None
+// Requires: None
+//
+//*****************************************************************************
+//#define USB_MUX_PIN 2
+
+//*****************************************************************************
+//
+// Specifies the state to set the GPIO pin to to select USB device mode via
+// the USB host/device mux. Valid values are 1 (high) or 0 (low).
+//
+// Depends on: USB_ENABLE_UPDATE, USB_HAS_MUX
+// Exclusive of: None
+// Requires: None
+//
+//*****************************************************************************
+//#define USB_MUX_DEVICE 1
+
+//*****************************************************************************
+//
+// Selects the CAN port as the port for communicating with the boot loader.
+//
+// Depends on: None
+// Exclusive of: ENET_ENABLE_UPDATE, I2C_ENABLE_UPDATE, SSI_ENABLE_UPDATE,
+// UART_ENABLE_UPDATE, USB_ENABLE_UPDATE
+// Requires: CAN_RX_PERIPH, CAN_RX_PORT, CAN_RX_PIN, CAN_TX_PERIPH,
+// CAN_TX_PORT, CAN_TX_PIN, CAN_BIT_RATE, CRYSTAL_FREQ.
+//
+//*****************************************************************************
+//#define CAN_ENABLE_UPDATE
+
+//*****************************************************************************
+//
+// Enables the UART to CAN bridging for use when the CAN port is selected for
+// communicating with the boot loader.
+//
+// Depends on: CAN_ENABLE_UPDATE
+// Exclusive of: None
+// Requires: None
+//
+//*****************************************************************************
+//#define CAN_UART_BRIDGE
+
+//*****************************************************************************
+//
+// Specifies the GPIO peripheral associated with CAN0 RX pin used by the boot
+// loader.
+//
+// Depends on: CAN_ENABLE_UPDATE
+// Exclusive of: None
+// Requires: None
+//
+//*****************************************************************************
+//#define CAN_RX_PERIPH SYSCTL_RCGC2_GPIOA
+
+//*****************************************************************************
+//
+// Specifies the GPIO port associated with CAN0 RX pin used by the boot loader.
+//
+// Depends on: CAN_ENABLE_UPDATE
+// Exclusive of: None
+// Requires: None
+//
+//*****************************************************************************
+//#define CAN_RX_PORT GPIO_PORTA_BASE
+
+//*****************************************************************************
+//
+// Specifies the GPIO pin number associated with CAN0 RX pin used by the boot
+// loader.
+//
+// Depends on: CAN_ENABLE_UPDATE
+// Exclusive of: None
+// Requires: None
+//
+//*****************************************************************************
+//#define CAN_RX_PIN 4
+
+//*****************************************************************************
+//
+// Specifies the GPIO peripheral associated with CAN0 TX pin used by the boot
+// loader.
+//
+// Depends on: CAN_ENABLE_UPDATE
+// Exclusive of: None
+// Requires: None
+//
+//*****************************************************************************
+//#define CAN_TX_PERIPH SYSCTL_RCGC2_GPIOA
+
+//*****************************************************************************
+//
+// Specifies the GPIO port associated with CAN0 TX pin used by the boot loader.
+//
+// Depends on: CAN_ENABLE_UPDATE
+// Exclusive of: None
+// Requires: None
+//
+//*****************************************************************************
+//#define CAN_TX_PORT GPIO_PORTA_BASE
+
+//*****************************************************************************
+//
+// Specifies the GPIO pin number associated with CAN0 TX pin used by the boot
+// loader.
+//
+// Depends on: CAN_ENABLE_UPDATE
+// Exclusive of: None
+// Requires: None
+//
+//*****************************************************************************
+//#define CAN_TX_PIN 5
+
+//*****************************************************************************
+//
+// Specifies the bit rate for CAN0 used by the boot loader.
+//
+// Depends on: CAN_ENABLE_UPDATE
+// Exclusive of: None
+// Requires: None
+//
+//*****************************************************************************
+//#define CAN_BIT_RATE 1000000
+
+//*****************************************************************************
+//
+// Boot loader hook functions.
+//
+// The following defines allow you to add application-specific function which
+// are called at various points during boot loader execution.
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// Performs application-specific low level hardware initialization on system
+// reset.
+//
+// If hooked, this function will be called immediately after the boot loader
+// code relocation completes. An application may perform any required low
+// hardware initialization during this function. Note that the system clock
+// has not been set when this function is called. Initialization that assumes
+// the system clock is set may be performed in the BL_INIT_FN_HOOK function
+// instead.
+//
+// void MyHwInitFunc(void);
+//
+//*****************************************************************************
+//#define BL_HW_INIT_FN_HOOK MyHwInitFunc
+
+//*****************************************************************************
+//
+// Performs application-specific initialization on system reset.
+//
+// If hooked, this function will be called immediately after the boot loader
+// sets the system clock. An application may perform any additional
+// initialization during this function.
+//
+// void MyInitFunc(void);
+//
+//*****************************************************************************
+//#define BL_INIT_FN_HOOK MyInitFunc
+
+//*****************************************************************************
+//
+// Performs application-specific reinitialization on boot loader entry via SVC.
+//
+// If hooked, this function will be called immediately after the boot loader
+// reinitializes the system clock when it is entered from an application
+// via the SVC mechanism rather than as a result of a system reset. An
+// application may perform any additional reinitialization in this function.
+//
+// void MyReinitFunc(void);
+//
+//*****************************************************************************
+//#define BL_REINIT_FN_HOOK MyReinitFunc
+
+//*****************************************************************************
+//
+// Informs an application that a download is starting.
+//
+// If hooked, this function will be called when a new firmware download is
+// about to start. The application may use this signal to initialize any
+// progress display.
+//
+// void MyStartFunc(void);
+//
+//*****************************************************************************
+//#define BL_START_FN_HOOK MyStartFunc
+
+//*****************************************************************************
+//
+// Informs an application of download progress.
+//
+// If hooked, this function will be called periodically during firmware
+// download. The application may use this to update its user interface.
+// When using a protocol which does not inform the client of the final size of
+// the download in advance (e.g. TFTP), the ulTotal parameter will be 0,
+// otherwise it indicates the expected size of the complete download.
+//
+// void MyProgressFunc(unsigned long ulCompleted, unsigned long ulTotal);
+//
+// where:
+//
+// - ulCompleted indicates the number of bytes already downloaded.
+// - ulTotal indicates the number of bytes expected or 0 if this is not known.
+//
+//*****************************************************************************
+//#define BL_PROGRESS_FN_HOOK MyProgressFunc
+
+//*****************************************************************************
+//
+// Informs an application that a download has completed.
+//
+// If hooked, this function will be called when a firmware download ends.
+// The application may use this signal to update its user interface. Typically
+// a system reset will occur shortly after this function returns as the boot
+// loader attempts to boot the new image.
+//
+// void MyEndFunc(void);
+//
+//*****************************************************************************
+//#define BL_END_FN_HOOK MyEndFunc
+
+//*****************************************************************************
+//
+// Allows an application to perform in-place data decryption during download.
+//
+// If hooked, this function will be called on receipt of any new block of
+// downloaded firmware image data. The application must decrypt this data
+// in place then return at which point the boot loader will write the data to
+// flash.
+//
+// void MyDecryptionFunc(unsigned char *pucBuffer, unsigned long ulSize);
+//
+// where:
+//
+// - pucBuffer points to the first byte of data to be decrypted.
+// - ulSize indicates the number of bytes of data at pucBuffer.
+//
+//*****************************************************************************
+//#define BL_DECRYPT_FN_HOOK MyDecryptionFunc
+
+//*****************************************************************************
+//
+// Allows an application to force a new firmware download.
+//
+// If hooked, this function will be called after a system reset (following
+// basic initialization and the initialization hook function) to give the
+// application an opportunity to force a new firmware download. Depending upon
+// the return code, the boot loader will either boot the existing firmware
+// image or wait for a new download to be started.
+//
+// Note that this hook takes precedence over ENABLE_UPDATE_CHECK settings. If
+// the hook function is defined, the basic GPIO check offered by
+// ENABLE_UPDATE_CHECK does not take place.
+//
+// unsigned long MyCheckUpdateFunc(void);
+//
+// where the return code is 0 if the boot loader should boot the existing
+// image (if found) or non-zero to indicate that the boot loader should retain
+// control and wait for a new firmware image to be downloaded.
+//
+//*****************************************************************************
+//#define BL_CHECK_UPDATE_FN_HOOK MyCheckUpdateFunc
+
+//*****************************************************************************
+//
+// Allows an application to replace the flash block erase function.
+//
+// If hooked, this function will be called whenever a block of flash is to
+// be erased. The function must erase the block and block until the operation
+// has completed. The size of the block which will be erased is defined by
+// FLASH_BLOCK_SIZE.
+//
+// void MyFlashEraseFunc(unsigned long ulBlockAddr);
+//
+// where:
+//
+// - ulBlockAddr is the address of the flash block to be erased.
+//
+//*****************************************************************************
+//#define BL_FLASH_ERASE_FN_HOOK MyFlashEraseFunc
+
+//*****************************************************************************
+//
+// Allows an application to replace the flash programming function.
+//
+// If hooked, this function will be called whenever a block of data is to be
+// be written to flash. The function must program the supplied data and block
+// until the operation has has completed.
+//
+// void MyFlashProgramFunc(unsigned long ulDstAddr,
+// unsigned char *pucSrcData,
+// unsigned long ulLength);
+//
+// where:
+//
+// - ulDstAddr is the address in flash at which the data is to be programmed.
+// This must be a multiple of 4.
+// - pucSrcData points to the first byte of the data to program.
+// - ulLength is the number of bytes of data to program. This must be a
+// multiple of 4.
+//
+//*****************************************************************************
+//#define BL_FLASH_PROGRAM_FN_HOOK MyFlashProgramFunc
+
+//*****************************************************************************
+//
+// Allows an application to replace the flash error clear function.
+//
+// If hooked, this function will be called before each flash erase or program
+// operation. The function must clear any flash error indicators and prepare
+// to detect access violations that may occur in a future erase or program
+// operation.
+//
+// void MyFlashClearErrorFunc(void);
+//
+//*****************************************************************************
+//#define BL_FLASH_CL_ERR_FN_HOOK MyFlashClearErrorFunc
+
+//*****************************************************************************
+//
+// Reports whether or not a flash access violation error has occurred.
+//
+// If hooked, this function will be called after flash erase or program
+// operations. The return code indicates to the caller whether or not
+// an access violation error has occurred since the last call to the function
+// defined by BL_FLASH_CL_ERR_FN_HOOK.
+//
+// unsigned long MyFlashErrorFunc(void);
+//
+// where the return code is 0 if no error has occurred or non-zero if an
+// error was detected.
+//
+//*****************************************************************************
+//#define BL_FLASH_ERROR_FN_HOOK MyFlashErrorFunc
+
+//*****************************************************************************
+//
+// Reports the total size of the device flash.
+//
+// If hooked, this function will be called to determine the size of the flash
+// device.
+//
+// unsigned long MyFlashSizeFunc(void);
+//
+// where the return code is the total number of bytes of flash supported by the
+// device. Note that this does not take into account any reserved space
+// defined via the FLASH_RSVD_SPACE value in this header file.
+//
+//*****************************************************************************
+//#define BL_FLASH_SIZE_FN_HOOK MyFlashSizeFunc
+
+//*****************************************************************************
+//
+// Reports the address of the first byte after the end of the device flash.
+//
+// If hooked, this function will be called to determine the address of the end
+// of valid flash.
+//
+// unsigned long MyFlashEndFunc(void);
+//
+// where the return code is the address of the first byte after the end of flash.
+// Note that this does not take into account any reserved space defined via
+// the FLASH_RSVD_SPACE value in this header file.
+//
+//*****************************************************************************
+//#define BL_FLASH_END_FN_HOOK MyFlashEndFunc
+
+//*****************************************************************************
+//
+// Checks whether the start address and size of an image are valid.
+//
+// If hooked, this function will be called whenever a new download is to be
+// started. It determines whether or not an image of a particular size may be
+// flashed at a given address. Valid addresses are:
+//
+// 1. APP_START_ADDRESS in all cases.
+// 2. 0x00000000 if ENABLE_BL_UPDATE is defined.
+// 3. The start of the reserved space if FLASH_RSVD_SPACE is defined.
+//
+// unsigned long MyFlashAddrCheckFunc(unsigned long ulAddr,
+// unsigned long ulSize);
+//
+// where:
+//
+// - ulAddr is the address in flash at which the image is to be programmed.
+// - ulSize is the total size of the image if known or 0 otherwise.
+//
+// The return code will be 0 if the address or size is invalid or a non-zero
+// value if valid.
+//
+//*****************************************************************************
+//#define BL_FLASH_AD_CHECK_FN_HOOK MyFlashAddrCheckFunc
+
+#endif // __BL_CONFIG_H__
diff --git a/boot_loader/bl_crc32.c b/boot_loader/bl_crc32.c
new file mode 100644
index 0000000..9413987
--- /dev/null
+++ b/boot_loader/bl_crc32.c
@@ -0,0 +1,267 @@
+//*****************************************************************************
+//
+// bl_crc32.c - CRC32 calculation functions used in the boot loader.
+//
+// Copyright (c) 2013-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
+//
+//*****************************************************************************
+#include <stdint.h>
+#include <stdbool.h>
+#include "inc/hw_types.h"
+#include "inc/hw_flash.h"
+#include "inc/hw_sysctl.h"
+#include "bl_config.h"
+#include "boot_loader/bl_crc32.h"
+
+//*****************************************************************************
+//
+// Storage for the CRC32 calculation lookup table.
+//
+//*****************************************************************************
+static uint32_t g_pui32CRC32Table[256];
+
+//*****************************************************************************
+//
+// Initialize the CRC32 calculation table for the polynomial used. We pick
+// the commonly used ANSI X 3.66 polymonial. This code was informed by an
+// example found at http://www.createwindow.com/programming/crc32/index.htm.
+//
+//*****************************************************************************
+static uint32_t
+Reflect(uint32_t ui32Ref, uint8_t ui8Ch)
+{
+ uint_fast32_t ui32Value;
+ int_fast16_t i16Loop;
+
+ //
+ // Clear our accumulator variable.
+ //
+ ui32Value = 0;
+
+ //
+ // Swap bit 0 for bit 7, bit 1 for bit 6, etc.
+ //
+ for(i16Loop = 1; i16Loop < (ui8Ch + 1); i16Loop++)
+ {
+ if(ui32Ref & 1)
+ {
+ ui32Value |= 1 << (ui8Ch - i16Loop);
+ }
+ ui32Ref >>= 1;
+ }
+
+ //
+ // Return the reflected value.
+ //
+ return(ui32Value);
+}
+
+//*****************************************************************************
+//
+// Initialize the lookup table used in calculating the CRC32 value.
+//
+//*****************************************************************************
+void
+InitCRC32Table(void)
+{
+ uint_fast32_t ui32Polynomial;
+ int_fast16_t i16Loop, i16Bit;
+
+ //
+ // This is the ANSI X 3.66 polynomial as required by the DFU
+ // specification.
+ //
+ ui32Polynomial = 0x04c11db7;
+
+ for(i16Loop = 0; i16Loop <= 0xFF; i16Loop++)
+ {
+ g_pui32CRC32Table[i16Loop]=Reflect(i16Loop, 8) << 24;
+ for (i16Bit = 0; i16Bit < 8; i16Bit++)
+ {
+ g_pui32CRC32Table[i16Loop] = ((g_pui32CRC32Table[i16Loop] << 1) ^
+ (g_pui32CRC32Table[i16Loop] &
+ ((uint32_t)1 << 31) ?
+ ui32Polynomial : 0));
+ }
+ g_pui32CRC32Table[i16Loop] = Reflect(g_pui32CRC32Table[i16Loop], 32);
+ }
+}
+
+//*****************************************************************************
+//
+// Calculate the CRC for the supplied block of data.
+//
+//*****************************************************************************
+uint32_t
+CalculateCRC32(uint8_t *pui8Data, uint32_t ui32Length, uint32_t ui32CRC)
+{
+ uint32_t ui32Count;
+ uint8_t *pui8Buffer;
+ uint8_t ui8Char;
+
+ //
+ // Get a pointer to the start of the data and the number of bytes to
+ // process.
+ //
+ pui8Buffer = pui8Data;
+ ui32Count = ui32Length;
+
+ //
+ // Perform the algorithm on each byte in the supplied buffer using the
+ // lookup table values calculated in InitCRC32Table().
+ //
+ while(ui32Count--)
+ {
+ ui8Char = *pui8Buffer++;
+ ui32CRC = (ui32CRC >> 8) ^ g_pui32CRC32Table[(ui32CRC & 0xFF) ^
+ ui8Char];
+ }
+
+ //
+ // Return the result.
+ //
+ return(ui32CRC);
+}
+
+//*****************************************************************************
+//
+//! Checks that the embedded CRC in the image matches the expected value.
+//!
+//! \param pui32Image points to the start of the firmware image in memory.
+//!
+//! This function finds the firmware image information header and verifies that
+//! the embedded CRC32 matches one calculated over the image.
+//!
+//! \return Returns \b CHECK_CRC_OK if the CRC calculated matches the value
+//! embedded in the image, \b CHECK_CRC_NO_HEADER if no image information
+//! header was found at the top of the vector table, \b CHECK_CRC_BAD_CRC if
+//! an embedded CRC was found but did not match the calculated value or \b
+//! CHECK_CRC_ZERO_LENGTH if the length field of the image information header
+//! contains 0 (likely indicating that the image had not been run through the
+//! binpack tool which inserts the length and CRC values into the header).
+//
+//*****************************************************************************
+uint32_t
+CheckImageCRC32(uint32_t *pui32Image)
+{
+ uint32_t ui32Loop, ui32FlashSize, ui32CRC;
+
+ //
+ // Determine the size of flash (giving an upper bound for the image
+ // size).
+ //
+ if(CLASS_IS_TM4C129)
+ {
+ //
+ // Get the flash size from the FLASH_PP register.
+ //
+ ui32FlashSize = ((2048 * ((HWREG(FLASH_PP) & FLASH_PP_SIZE_M) + 1)) -
+ APP_START_ADDRESS);
+ }
+ else
+ {
+ //
+ // Compute the size of the flash.
+ //
+ ui32FlashSize = (((HWREG(SYSCTL_DC0) & SYSCTL_DC0_FLASHSZ_M) << 11) +
+ 0x800 - APP_START_ADDRESS);
+ }
+
+ //
+ // Scan for the image information header marker bytes. Given that the
+ // largest possible vector table includes 16 system exceptions and 240
+ // IC-specific vectors, we only need to search 257 words into memory before
+ // giving up.
+ //
+ for(ui32Loop = 0; ui32Loop < 257; ui32Loop++)
+ {
+ //
+ // Have we found the header marker words?
+ //
+ if((pui32Image[ui32Loop] == 0xFF01FF02) &&
+ (pui32Image[ui32Loop + 1] == 0xFF03FF04))
+ {
+ //
+ // Yes. Check to see if the length field is 0xFFFFFFFF. This
+ // likely indicates that the image has not been processed by the
+ // binpack tool which adds the length and CRC information to the
+ // image header.
+ //
+ if(pui32Image[ui32Loop + 2] == 0xFFFFFFFF)
+ {
+ //
+ // The header reports an image size of 0 so we can't go on and
+ // check the CRC.
+ //
+ return(CHECK_CRC_NO_LENGTH);
+ }
+
+ //
+ // Extract the image length and ensure that it is sensible
+ // given the flash size. We assume the length is invalid if it
+ // is larger than the available flash size or smaller than the
+ // space taken up by the vector table and header we've already
+ // scanned through.
+ //
+ if((pui32Image[ui32Loop + 2] > ui32FlashSize) ||
+ (pui32Image[ui32Loop + 2] <
+ ((ui32Loop + 4) * sizeof(uint32_t))))
+ {
+ //
+ // The header reports an image size that is larger than the
+ // available flash so this is obviously incorrect. Fail the
+ // check.
+ //
+ return(CHECK_CRC_BAD_LENGTH);
+ }
+
+ //
+ // Calculate the CRC32 value for the image. Note that we skip the
+ // 4 bytes that hold the check CRC.
+ //
+ ui32CRC = CalculateCRC32((uint8_t *)pui32Image,
+ (ui32Loop + 3) * sizeof(uint32_t),
+ 0xffffffff);
+ ui32CRC = CalculateCRC32((uint8_t *)&pui32Image[ui32Loop + 4],
+ (pui32Image[ui32Loop + 2] -
+ ((ui32Loop + 4) * sizeof(uint32_t))),
+ ui32CRC);
+ ui32CRC ^= 0xffffffff;
+
+ //
+ // Determine whether the calculated CRC matches the value stored
+ // in the image information header.
+ //
+ if(ui32CRC == pui32Image[ui32Loop + 3])
+ {
+ return(CHECK_CRC_OK);
+ }
+ else
+ {
+ return(CHECK_CRC_BAD_CRC);
+ }
+ }
+ }
+
+ //
+ // If we drop out the loop, there was no image information header so
+ // fail the call.
+ //
+ return(CHECK_CRC_NO_HEADER);
+}
diff --git a/boot_loader/bl_crc32.h b/boot_loader/bl_crc32.h
new file mode 100644
index 0000000..ab8848d
--- /dev/null
+++ b/boot_loader/bl_crc32.h
@@ -0,0 +1,49 @@
+//*****************************************************************************
+//
+// bl_crc32.h - Public header for the boot loader CRC32 functions.
+//
+// Copyright (c) 2013-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
+//
+//*****************************************************************************
+
+#ifndef __BL_CRC32_H__
+#define __BL_CRC32_H__
+
+//*****************************************************************************
+//
+// Return codes generated by CheckImageCRC32().
+//
+//*****************************************************************************
+#define CHECK_CRC_OK 0
+#define CHECK_CRC_NO_HEADER 1
+#define CHECK_CRC_NO_LENGTH 2
+#define CHECK_CRC_BAD_LENGTH 3
+#define CHECK_CRC_BAD_CRC 4
+
+//*****************************************************************************
+//
+// Exported function prototypes.
+//
+//*****************************************************************************
+extern void InitCRC32Table(void);
+extern uint32_t CheckImageCRC32(uint32_t *pui32Image);
+extern uint32_t CalculateCRC32(uint8_t *pui8Data, uint32_t ui32Length,
+ uint32_t ui32CRC);
+
+#endif
diff --git a/boot_loader/bl_crystal.h b/boot_loader/bl_crystal.h
new file mode 100644
index 0000000..268d102
--- /dev/null
+++ b/boot_loader/bl_crystal.h
@@ -0,0 +1,79 @@
+//*****************************************************************************
+//
+// bl_crystal.h - Macros to convert a CRYSTAL_FREQ value into the appropriate
+// RCC XTAL field define.
+//
+// Copyright (c) 2010-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
+//
+//*****************************************************************************
+
+#ifndef __BL_CRYSTAL_H__
+#define __BL_CRYSTAL_H__
+
+//*****************************************************************************
+//
+// Convert the CRYSTAL_FREQ value into the corresponding SYSCTL_RCC_XTAL_???
+// value.
+//
+//*****************************************************************************
+#if CRYSTAL_FREQ == 3579545
+#define XTAL_VALUE SYSCTL_RCC_XTAL_3_57MHZ
+#elif CRYSTAL_FREQ == 3686400
+#define XTAL_VALUE SYSCTL_RCC_XTAL_3_68MHZ
+#elif CRYSTAL_FREQ == 4000000
+#define XTAL_VALUE SYSCTL_RCC_XTAL_4MHZ
+#elif CRYSTAL_FREQ == 4096000
+#define XTAL_VALUE SYSCTL_RCC_XTAL_4_09MHZ
+#elif CRYSTAL_FREQ == 4915200
+#define XTAL_VALUE SYSCTL_RCC_XTAL_4_91MHZ
+#elif CRYSTAL_FREQ == 5000000
+#define XTAL_VALUE SYSCTL_RCC_XTAL_5MHZ
+#elif CRYSTAL_FREQ == 5120000
+#define XTAL_VALUE SYSCTL_RCC_XTAL_5_12MHZ
+#elif CRYSTAL_FREQ == 6000000
+#define XTAL_VALUE SYSCTL_RCC_XTAL_6MHZ
+#elif CRYSTAL_FREQ == 6144000
+#define XTAL_VALUE SYSCTL_RCC_XTAL_6_14MHZ
+#elif CRYSTAL_FREQ == 7372800
+#define XTAL_VALUE SYSCTL_RCC_XTAL_7_37MHZ
+#elif CRYSTAL_FREQ == 8000000
+#define XTAL_VALUE SYSCTL_RCC_XTAL_8MHZ
+#elif CRYSTAL_FREQ == 8192000
+#define XTAL_VALUE SYSCTL_RCC_XTAL_8_19MHZ
+#elif CRYSTAL_FREQ == 10000000
+#define XTAL_VALUE SYSCTL_RCC_XTAL_10MHZ
+#elif CRYSTAL_FREQ == 12000000
+#define XTAL_VALUE SYSCTL_RCC_XTAL_12MHZ
+#elif CRYSTAL_FREQ == 12288000
+#define XTAL_VALUE SYSCTL_RCC_XTAL_12_2MHZ
+#elif CRYSTAL_FREQ == 13560000
+#define XTAL_VALUE SYSCTL_RCC_XTAL_13_5MHZ
+#elif CRYSTAL_FREQ == 14318180
+#define XTAL_VALUE SYSCTL_RCC_XTAL_14_3MHZ
+#elif CRYSTAL_FREQ == 16000000
+#define XTAL_VALUE SYSCTL_RCC_XTAL_16MHZ
+#elif CRYSTAL_FREQ == 16384000
+#define XTAL_VALUE SYSCTL_RCC_XTAL_16_3MHZ
+#elif CRYSTAL_FREQ == 25000000
+#define XTAL_VALUE SYSCTL_RCC_XTAL_25MHZ
+#else
+#error ERROR: Unknown CRYSTAL_FREQ value specified!
+#endif
+
+#endif // __BL_CRYSTAL_H__
diff --git a/boot_loader/bl_decrypt.c b/boot_loader/bl_decrypt.c
new file mode 100644
index 0000000..6db64da
--- /dev/null
+++ b/boot_loader/bl_decrypt.c
@@ -0,0 +1,64 @@
+//*****************************************************************************
+//
+// bl_decrypt.c - Code for performing an in-place decryption of the firmware
+// image as it is downloaded.
+//
+// Copyright (c) 2007-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
+//
+//*****************************************************************************
+
+#include <stdint.h>
+#include "bl_config.h"
+#include "boot_loader/bl_decrypt.h"
+
+//*****************************************************************************
+//
+//! \addtogroup bl_decrypt_api
+//! @{
+//
+//*****************************************************************************
+#if defined(ENABLE_DECRYPTION) || defined(DOXYGEN)
+
+//*****************************************************************************
+//
+//! Performs an in-place decryption of downloaded data.
+//!
+//! \param pui8Buffer is the buffer that holds the data to decrypt.
+//! \param ui32Size is the size, in bytes, of the buffer that was passed in via
+//! the \e pui8Buffer parameter.
+//!
+//! This function is a stub that could provide in-place decryption of the data
+//! that is being downloaded to the device.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+DecryptData(uint8_t *pui8Buffer, uint32_t ui32Size)
+{
+}
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
+#endif
+
diff --git a/boot_loader/bl_decrypt.h b/boot_loader/bl_decrypt.h
new file mode 100644
index 0000000..c8eed0c
--- /dev/null
+++ b/boot_loader/bl_decrypt.h
@@ -0,0 +1,35 @@
+//*****************************************************************************
+//
+// bl_decrypt.h - Definitions for the decryption function.
+//
+// Copyright (c) 2007-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
+//
+//*****************************************************************************
+
+#ifndef __BL_DECRYPT_H__
+#define __BL_DECRYPT_H__
+
+//*****************************************************************************
+//
+// Prototype for the decryption function.
+//
+//*****************************************************************************
+extern void DecryptData(uint8_t *pui8Buffer, uint32_t ui32Size);
+
+#endif // __BL_DECRYPT_H__
diff --git a/boot_loader/bl_emac.c b/boot_loader/bl_emac.c
new file mode 100644
index 0000000..c098da0
--- /dev/null
+++ b/boot_loader/bl_emac.c
@@ -0,0 +1,1914 @@
+//*****************************************************************************
+//
+// bl_emac.c - Functions to update via Ethernet.
+//
+// Copyright (c) 2013-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
+//
+//*****************************************************************************
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <string.h>
+#include "bl_config.h"
+#include "inc/hw_emac.h"
+#include "inc/hw_flash.h"
+#include "inc/hw_gpio.h"
+#include "inc/hw_memmap.h"
+#include "inc/hw_nvic.h"
+#include "inc/hw_sysctl.h"
+#include "inc/hw_types.h"
+#include "driverlib/gpio.h"
+#include "driverlib/pin_map.h"
+#include "driverlib/emac.h"
+#include "driverlib/sysctl.h"
+#include "boot_loader/bl_decrypt.h"
+#include "boot_loader/bl_flash.h"
+#include "boot_loader/bl_hooks.h"
+#include "driverlib/rom.h"
+//
+// Define ROM_SysCtlClockFreqSet() for snowflake RA0. Even though this function
+// is deprecated in RA0 ROM, the function operates correctly when
+// SYSCTL_MOSCCTL register is configured correctly prior to calling this
+// function.
+//
+#if defined(TARGET_IS_TM4C129_RA0)
+#define ROM_SysCtlClockFreqSet \
+ ((uint32_t (*)(uint32_t ui32Config, \
+ uint32_t ui32SysClock))ROM_SYSCTLTABLE[48])
+#endif
+
+//
+// Define MAP_GPIOPadConfigSet() for the Boot Loader for Snowflake.
+// This function fails in Snowflake for higher drive strengths, it will work
+// properly for the instances where it is used here in the boot loader.
+//
+#if defined(TARGET_IS_TM4C129_RA0) || \
+ defined(TARGET_IS_TM4C129_RA1)
+#define ROM_GPIOPadConfigSet \
+ ((void (*)(uint32_t ui32Port, \
+ uint8_t ui8Pins, \
+ uint32_t ui32Strength, \
+ uint32_t ui32PadType))ROM_GPIOTABLE[5])
+#endif
+
+#include "driverlib/rom_map.h"
+
+//*****************************************************************************
+//
+//! \addtogroup bl_emac_api
+//! @{
+//
+//*****************************************************************************
+
+#if defined(ENET_ENABLE_UPDATE) || defined(DOXYGEN)
+//*****************************************************************************
+//
+// Make sure that the crystal frequency is defined.
+//
+//*****************************************************************************
+#if !defined(CRYSTAL_FREQ)
+#error ERROR: CRYSTAL_FREQ must be defined for Ethernet update!
+#endif
+
+//*****************************************************************************
+//
+// Make sure that boot loader update is not enabled (it is not supported via
+// BOOTP given that there is no way to distinguish between a normal firmware
+// image and a boot loader update image).
+//
+//*****************************************************************************
+#if defined(ENABLE_BL_UPDATE)
+#error ERROR: Updating the boot loader is not supported over Ethernet!
+#endif
+
+//*****************************************************************************
+//
+// TFTP packets contain 512 bytes of data and a packet shorter than this
+// indicates the end of the transfer.
+//
+//*****************************************************************************
+#define TFTP_BLOCK_SIZE 512
+
+//*****************************************************************************
+//
+// uIP uses memset, so a simple one is provided here. This is not as efficient
+// as the one in the C library (from an execution time perspective), but it is
+// much smaller.
+//
+//*****************************************************************************
+void *
+my_memset(void *pvDest, int iChar, size_t i32Length)
+{
+ int8_t *pi8Buf = (int8_t *)pvDest;
+
+ //
+ // Fill the buffer with the given character.
+ //
+ while(i32Length--)
+ {
+ *pi8Buf++ = iChar;
+ }
+
+ //
+ // Return a pointer to the beginning of the buffer.
+ //
+ return(pvDest);
+}
+
+//*****************************************************************************
+//
+// uIP uses memcpy, so a simple one is provided here. This is not as efficient
+// as the one in the C library (from an execution time perspective), but it is
+// much smaller.
+//
+//*****************************************************************************
+void *
+my_memcpy(void *pvDest, const void *pvSrc, size_t i32Length)
+{
+ const int8_t *pi8Src = (const int8_t *)pvSrc;
+ int8_t *pi8Dest = (int8_t *)pvDest;
+
+ //
+ // Copy bytes from the source buffer to the destination buffer.
+ //
+ while(i32Length--)
+ {
+ *pi8Dest++ = *pi8Src++;
+ }
+
+ //
+ // Return a pointer to the beginning of the destination buffer.
+ //
+ return(pvDest);
+}
+
+//*****************************************************************************
+//
+// Directly include the uIP code if using Ethernet for the update. This allows
+// non-Ethernet boot loader builds to not have to supply the uip-conf.h file
+// that would otherwise be required.
+//
+//*****************************************************************************
+#define memcpy my_memcpy
+#define memset my_memset
+#undef htonl
+#undef ntohl
+#undef htons
+#undef ntohs
+#include "third_party/uip-1.0/uip/pt.h"
+#include "third_party/uip-1.0/uip/uip_arp.c"
+#undef BUF
+#include "third_party/uip-1.0/uip/uip.c"
+
+//*****************************************************************************
+//
+// A prototype for the function (in the startup code) for a predictable length
+// delay.
+//
+//*****************************************************************************
+extern void Delay(uint32_t ui32Count);
+
+//*****************************************************************************
+//
+// Defines for setting up the system clock.
+//
+//*****************************************************************************
+#define SYSTICKHZ 100
+#define SYSTICKMS (1000 / SYSTICKHZ)
+
+//*****************************************************************************
+//
+// UIP Timers (in ms)
+//
+//*****************************************************************************
+#define UIP_PERIODIC_TIMER_MS 50
+#define UIP_ARP_TIMER_MS 10000
+
+//*****************************************************************************
+//
+// This structure defines the fields in a BOOTP request/reply packet.
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ // The operation; 1 is a request, 2 is a reply.
+ //
+ uint8_t ui8Op;
+
+ //
+ // The hardware type; 1 is Ethernet.
+ //
+ uint8_t ui8HType;
+
+ //
+ // The hardware address length; for Ethernet this will be 6, the length of
+ // the MAC address.
+ //
+ uint8_t ui8HLen;
+
+ //
+ // Hop count, used by gateways for cross-gateway booting.
+ //
+ uint8_t ui8Hops;
+
+ //
+ // The transaction ID.
+ //
+ uint32_t ui32XID;
+
+ //
+ // The number of seconds elapsed since the client started trying to boot.
+ //
+ uint16_t ui16Secs;
+
+ //
+ // The BOOTP flags.
+ //
+ uint16_t ui16Flags;
+
+ //
+ // The client's IP address, if it knows it.
+ //
+ uint32_t ui32CIAddr;
+
+ //
+ // The client's IP address, as assigned by the BOOTP server.
+ //
+ uint32_t ui32YIAddr;
+
+ //
+ // The TFTP server's IP address.
+ //
+ uint32_t ui32SIAddr;
+
+ //
+ // The gateway IP address, if booting cross-gateway.
+ //
+ uint32_t ui32GIAddr;
+
+ //
+ // The hardware address; for Ethernet this is the MAC address.
+ //
+ uint8_t pui8CHAddr[16];
+
+ //
+ // The name, or nickname, of the server that should handle this BOOTP
+ // request.
+ //
+ char pcSName[64];
+
+ //
+ // The name of the boot file to be loaded via TFTP.
+ //
+ char pcFile[128];
+
+ //
+ // Optional vendor-specific area; not used for BOOTP.
+ //
+ uint8_t pui8Vend[64];
+}
+tBOOTPPacket;
+
+//*****************************************************************************
+//
+// The BOOTP commands.
+//
+//*****************************************************************************
+#define BOOTP_REQUEST 1
+#define BOOTP_REPLY 2
+
+//*****************************************************************************
+//
+// The TFTP commands.
+//
+//*****************************************************************************
+#define TFTP_RRQ 1
+#define TFTP_WRQ 2
+#define TFTP_DATA 3
+#define TFTP_ACK 4
+#define TFTP_ERROR 5
+
+//*****************************************************************************
+//
+// The UDP ports used by the BOOTP protocol.
+//
+//*****************************************************************************
+#define BOOTP_SERVER_PORT 67
+#define BOOTP_CLIENT_PORT 68
+
+//*****************************************************************************
+//
+// The UDP port for the TFTP server.
+//
+//*****************************************************************************
+#define TFTP_PORT 69
+
+//*****************************************************************************
+//
+// The MAC address of the Ethernet interface.
+//
+//*****************************************************************************
+#ifdef ENET_MAC_ADDR0
+static struct uip_eth_addr g_sMACAddr =
+{
+ {
+ ENET_MAC_ADDR0,
+ ENET_MAC_ADDR1,
+ ENET_MAC_ADDR2,
+ ENET_MAC_ADDR3,
+ ENET_MAC_ADDR4,
+ ENET_MAC_ADDR5
+ }
+};
+#else
+static struct uip_eth_addr g_sMACAddr;
+#endif
+
+//*****************************************************************************
+//
+// The number of SysTick interrupts since the start of the boot loader.
+//
+//*****************************************************************************
+static uint32_t g_ui32Ticks;
+
+//*****************************************************************************
+//
+// The seed for the random number generator.
+//
+//*****************************************************************************
+static uint32_t g_ui32RandomSeed;
+
+//*****************************************************************************
+//
+// The number of milliseconds since the last call to uip_udp_periodic().
+//
+//*****************************************************************************
+static volatile uint32_t g_ui32PeriodicTimer;
+
+//*****************************************************************************
+//
+// The number of milliseconds since the last call to uip_arp_timer().
+//
+//*****************************************************************************
+static volatile uint32_t g_ui32ARPTimer;
+
+//*****************************************************************************
+//
+// The transaction ID of the most recently sent out BOOTP request.
+//
+//*****************************************************************************
+static uint32_t g_ui32XID;
+
+//*****************************************************************************
+//
+// The state for the proto-thread that handles the BOOTP process.
+//
+//*****************************************************************************
+static struct pt g_sThread;
+
+//*****************************************************************************
+//
+// The amount of time to wait for a BOOTP reply before sending out a new BOOTP
+// request.
+//
+//*****************************************************************************
+static uint32_t g_ui32Delay;
+
+//*****************************************************************************
+//
+// The target time (relative to g_ui32Ticks) when the next timeout occurs.
+//
+//*****************************************************************************
+static uint32_t g_ui32Target;
+
+//*****************************************************************************
+//
+// The IP address of the TFTP server.
+//
+//*****************************************************************************
+static uip_ipaddr_t g_sServerAddr;
+
+//*****************************************************************************
+//
+// The name of the file to be read from the TFTP server.
+//
+//*****************************************************************************
+static char g_pcFilename[128];
+
+//*****************************************************************************
+//
+// The end of flash. If there is not a reserved block at the end of flash,
+// this is the real end of flash. If there is a reserved block, this is the
+// start of the reserved block (i.e. the virtual end of flash).
+//
+//*****************************************************************************
+static uint32_t g_ui32FlashEnd;
+
+//*****************************************************************************
+//
+// The current block being read from the TFTP server.
+//
+//*****************************************************************************
+static uint32_t g_ui32TFTPBlock;
+
+//*****************************************************************************
+//
+// The number of TFTP retries.
+//
+//*****************************************************************************
+static uint32_t g_ui32TFTPRetries;
+
+//*****************************************************************************
+//
+// The UDP socket used to communicate with the BOOTP and TFTP servers (in
+// sequence).
+//
+//*****************************************************************************
+struct uip_udp_conn *g_pConn;
+
+//*****************************************************************************
+//
+// The current link status.
+//
+//*****************************************************************************
+static uint32_t g_ui32Link;
+
+//*****************************************************************************
+//
+// Ethernet DMA descriptors.
+//
+// Although uIP uses a single buffer, the MAC hardware needs a minimum of
+// 3 receive descriptors to operate.
+//
+//*****************************************************************************
+#define NUM_TX_DESCRIPTORS 3
+#define NUM_RX_DESCRIPTORS 3
+tEMACDMADescriptor g_psRxDescriptor[NUM_TX_DESCRIPTORS];
+tEMACDMADescriptor g_psTxDescriptor[NUM_RX_DESCRIPTORS];
+uint32_t g_ui32RxDescIndex;
+uint32_t g_ui32TxDescIndex;
+
+//*****************************************************************************
+//
+// Transmit and receive buffers.
+//
+//*****************************************************************************
+#define RX_BUFFER_SIZE 1536
+#define TX_BUFFER_SIZE 1536
+uint8_t g_pui8RxBuffer[RX_BUFFER_SIZE];
+uint8_t g_pui8TxBuffer[TX_BUFFER_SIZE];
+
+//*****************************************************************************
+//
+//! Handles the SysTick interrupt.
+//!
+//! This function is called when the SysTick interrupt occurs. It simply
+//! keeps a running count of interrupts, used as a time basis for the BOOTP and
+//! TFTP protocols.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SysTickIntHandler(void)
+{
+ //
+ // Increment the tick count.
+ //
+ g_ui32Ticks++;
+ g_ui32PeriodicTimer += SYSTICKMS;
+ g_ui32ARPTimer += SYSTICKMS;
+}
+
+//*****************************************************************************
+//
+//! Computes a new random number.
+//!
+//! This function computes a new pseudo-random number, using a linear
+//! congruence random number generator. Note that if the entire 32-bits of the
+//! produced random number are not being used, the upper N bits should be used
+//! instead of the lower N bits as they are much more random (for example, use
+//! ``RandomNumber() >> 28'' instead of ``RandomNumber() & 15'').
+//!
+//! \return Returns a 32-bit pseudo-random number.
+//
+//*****************************************************************************
+static uint32_t
+RandomNumber(void)
+{
+ //
+ // Generate a new pseudo-random number with a linear congruence random
+ // number generator. This new random number becomes the seed for the next
+ // random number.
+ //
+ g_ui32RandomSeed = (g_ui32RandomSeed * 1664525) + 1013904223;
+
+ //
+ // Return the new random number.
+ //
+ return(g_ui32RandomSeed);
+}
+
+//*****************************************************************************
+//
+// Read a packet from the DMA receive buffer into the uIP packet buffer.
+//
+//*****************************************************************************
+static int32_t
+PacketReceive(uint8_t *pui8Buf, int32_t i32BufLen)
+{
+ int_fast32_t i32FrameLen, i32Loop;
+
+ //
+ // By default, we assume we got a bad frame.
+ //
+ i32FrameLen = 0;
+
+ //
+ // See if the receive descriptor contains a valid frame. Look for a
+ // descriptor error, indicating that the incoming packet was truncated or,
+ // if this is the last frame in a packet, the receive error bit.
+ //
+ if(!(g_psRxDescriptor[g_ui32RxDescIndex].ui32CtrlStatus &
+ DES0_RX_STAT_ERR))
+ {
+ //
+ // We have a valid frame so copy the content to the supplied buffer.
+ // First check that the "last descriptor" flag is set. We sized the
+ // receive buffer such that it can always hold a valid frame so this
+ // flag should never be clear at this point but...
+ //
+ if(g_psRxDescriptor[g_ui32RxDescIndex].ui32CtrlStatus &
+ DES0_RX_STAT_LAST_DESC)
+ {
+ i32FrameLen =
+ ((g_psRxDescriptor[g_ui32RxDescIndex].ui32CtrlStatus &
+ DES0_RX_STAT_FRAME_LENGTH_M) >>
+ DES0_RX_STAT_FRAME_LENGTH_S);
+
+ //
+ // Sanity check. This shouldn't be required since we sized the uIP
+ // buffer such that it's the same size as the DMA receive buffer
+ // but, just in case...
+ //
+ if(i32FrameLen > i32BufLen)
+ {
+ i32FrameLen = i32BufLen;
+ }
+
+ //
+ // Copy the data from the DMA receive buffer into the provided
+ // frame buffer.
+ //
+ for(i32Loop = 0; i32Loop < i32FrameLen; i32Loop++)
+ {
+ pui8Buf[i32Loop] = g_pui8RxBuffer[i32Loop];
+ }
+ }
+ }
+
+ //
+ // Move on to the next descriptor in the chain.
+ //
+ g_ui32RxDescIndex++;
+ if(g_ui32RxDescIndex == NUM_RX_DESCRIPTORS)
+ {
+ g_ui32RxDescIndex = 0;
+ }
+
+ //
+ // Mark the next descriptor in the ring as available for the receiver to
+ // write into.
+ //
+ g_psRxDescriptor[g_ui32RxDescIndex].ui32CtrlStatus = DES0_RX_CTRL_OWN;
+
+ //
+ // Return the Frame Length
+ //
+ return(i32FrameLen);
+}
+
+//*****************************************************************************
+//
+// Transmit a packet from the supplied buffer.
+//
+//*****************************************************************************
+static int32_t
+PacketTransmit(uint8_t *pui8Buf, int32_t i32BufLen)
+{
+ int_fast32_t i32Loop;
+
+ //
+ // Wait for the previous packet to be transmitted.
+ //
+ while(g_psTxDescriptor[g_ui32TxDescIndex].ui32CtrlStatus &
+ DES0_TX_CTRL_OWN)
+ {
+ }
+
+ //
+ // Check that we're not going to overflow the transmit buffer. This
+ // shouldn't be necessary since the uIP buffer is smaller than our DMA
+ // transmit buffer but, just in case...
+ //
+ if(i32BufLen > TX_BUFFER_SIZE)
+ {
+ i32BufLen = TX_BUFFER_SIZE;
+ }
+
+ //
+ // Copy the packet data into the transmit buffer.
+ //
+ for(i32Loop = 0; i32Loop < i32BufLen; i32Loop++)
+ {
+ g_pui8TxBuffer[i32Loop] = pui8Buf[i32Loop];
+ }
+
+ //
+ // Move to the next descriptor.
+ //
+ g_ui32TxDescIndex++;
+ if(g_ui32TxDescIndex == NUM_TX_DESCRIPTORS)
+ {
+ g_ui32TxDescIndex = 0;
+ }
+
+ //
+ // Fill in the packet size and tell the transmitter to start work.
+ //
+ g_psTxDescriptor[g_ui32TxDescIndex].ui32Count = (uint32_t)i32BufLen;
+ g_psTxDescriptor[g_ui32TxDescIndex].ui32CtrlStatus =
+ (DES0_TX_CTRL_LAST_SEG | DES0_TX_CTRL_FIRST_SEG |
+ DES0_TX_CTRL_INTERRUPT | DES0_TX_CTRL_IP_ALL_CKHSUMS |
+ DES0_TX_CTRL_CHAINED | DES0_TX_CTRL_OWN);
+
+ //
+ // Tell the DMA to reacquire the descriptor now that we've filled it in.
+ //
+ ROM_EMACTxDMAPollDemand(EMAC0_BASE);
+
+ //
+ // Return the number of bytes sent.
+ //
+ return(i32BufLen);
+}
+
+//*****************************************************************************
+//
+//! Constructs and sends a BOOTP request packet.
+//!
+//! This function constructs a BOOTP request packet and sends it as a broadcast
+//! message to the network.
+//!
+//! \return None.
+//
+//*****************************************************************************
+static void
+SendBOOTPRequest(void)
+{
+ uint8_t *pui8Packet = (uint8_t *)uip_appdata;
+ tBOOTPPacket *psBOOTP = (tBOOTPPacket *)uip_appdata;
+ uint32_t ui32Idx;
+
+ //
+ // Zero fill the BOOTP request packet.
+ //
+ for(ui32Idx = 0; ui32Idx < sizeof(tBOOTPPacket); ui32Idx++)
+ {
+ pui8Packet[ui32Idx] = 0;
+ }
+
+ //
+ // Construct a BOOTP request.
+ //
+ psBOOTP->ui8Op = BOOTP_REQUEST;
+
+ //
+ // Set the hardware type to Ethernet.
+ //
+ psBOOTP->ui8HType = 0x01;
+
+ //
+ // Set the hardware address length to 6.
+ //
+ psBOOTP->ui8HLen = 0x06;
+
+ //
+ // Choose a random number for the transaction ID.
+ //
+ psBOOTP->ui32XID = g_ui32XID = RandomNumber();
+
+ //
+ // Set the number of seconds since we started.
+ //
+ psBOOTP->ui16Secs = HTONS(g_ui32Ticks / SYSTICKHZ);
+
+ //
+ // Fill in the Ethernet MAC address.
+ //
+ for(ui32Idx = 0; ui32Idx < 6; ui32Idx++)
+ {
+ psBOOTP->pui8CHAddr[ui32Idx] = g_sMACAddr.addr[ui32Idx];
+ }
+
+ //
+ // Set the server name if defined.
+ //
+#ifdef ENET_BOOTP_SERVER
+ for(ui32Idx = 0;
+ (psBOOTP->pcSName[ui32Idx] = ENET_BOOTP_SERVER[ui32Idx]) != 0;
+ ui32Idx++)
+ {
+ }
+#endif
+
+ //
+ // Send the BOOTP request packet.
+ //
+ uip_udp_send(sizeof(tBOOTPPacket));
+}
+
+//*****************************************************************************
+//
+//! Parses a packet checking for a BOOTP reply message.
+//!
+//! This function parses a packet to determine if it is a BOOTP reply to our
+//! currently outstanding BOOTP request. If a valid reply is found, the
+//! appropriate information from the packet is extracted and saved.
+//!
+//! \return Returns 1 if a valid BOOTP reply message was found and 0 otherwise.
+//
+//*****************************************************************************
+static uint32_t
+ParseBOOTPReply(void)
+{
+ tBOOTPPacket *psBOOTP = (tBOOTPPacket *)uip_appdata;
+ uint32_t ui32Idx;
+
+ //
+ // See if this is a reply for our current BOOTP request.
+ //
+ if((psBOOTP->ui8Op != BOOTP_REPLY) ||
+ (psBOOTP->ui32XID != g_ui32XID) ||
+ (*(uint32_t *)psBOOTP->pui8CHAddr != *(uint32_t *)g_sMACAddr.addr) ||
+ (*(uint16_t *)(psBOOTP->pui8CHAddr + 4) !=
+ *(uint16_t *)(g_sMACAddr.addr + 4)))
+ {
+ return(0);
+ }
+
+ //
+ // Extract our IP address from the response.
+ //
+ *((uint32_t *)(void *)(&uip_hostaddr)) = psBOOTP->ui32YIAddr;
+
+ //
+ // Extract the server address from the response.
+ //
+ *((uint32_t *)(void *)(&g_sServerAddr)) = psBOOTP->ui32SIAddr;
+
+ //
+ // Save the boot file name.
+ //
+ for(ui32Idx = 0;
+ ((g_pcFilename[ui32Idx] = psBOOTP->pcFile[ui32Idx]) != 0) &&
+ (ui32Idx < (sizeof(g_pcFilename) - 1));
+ ui32Idx++)
+ {
+ }
+ g_pcFilename[ui32Idx] = 0;
+
+ //
+ // A valid BOOTP reply was found and decoded.
+ //
+ return(1);
+}
+
+
+//*****************************************************************************
+//
+//! Constructs and sends a TFTP error packet.
+//!
+//! This function constructs a TFTP read request packet (RRQ) and sends it to
+//! the server.
+//!
+//! \return None.
+//
+//*****************************************************************************
+static void
+SendTFTPError(uint16_t ui16Error, char *pcString)
+{
+ uint8_t *pui8Packet = (uint8_t *)uip_appdata;
+ int32_t i32Len;
+
+ pui8Packet[0] = (TFTP_ERROR >> 8) & 0xff;
+ pui8Packet[1] = TFTP_ERROR & 0xff;
+ pui8Packet[2] = (ui16Error >> 8) & 0xFF;
+ pui8Packet[3] = ui16Error & 0xFF;
+
+ //
+ // Get ready to copy the error string.
+ //
+ i32Len = 4;
+ pui8Packet += 4;
+
+ //
+ // Copy as much of the string as we can fit.
+ //
+ while((i32Len < (UIP_APPDATA_SIZE - 1)) && *pcString)
+ {
+ *pui8Packet++ = *pcString++;
+ i32Len++;
+ }
+
+ //
+ // Write the terminating 0.
+ //
+ *pui8Packet = (uint8_t)0;
+
+ //
+ // Send the error packet.
+ //
+ uip_udp_send(i32Len + 1);
+}
+
+//*****************************************************************************
+//
+//! Constructs and sends a TFTP read packet.
+//!
+//! This function constructs a TFTP read request packet (RRQ) and sends it to
+//! the server.
+//!
+//! \return None.
+//
+//*****************************************************************************
+static void
+SendTFTPGet(void)
+{
+ uint8_t *pui8Packet = (uint8_t *)uip_appdata;
+ uint32_t ui32Idx;
+ char *pcFilename;
+
+ //
+ // The TFTP RRQ packet should be sent to the TFTP server port.
+ //
+ g_pConn->rport = HTONS(TFTP_PORT);
+
+ //
+ // Set the TFTP packet opcode to RRQ.
+ //
+ pui8Packet[0] = (TFTP_RRQ >> 8) & 0xff;
+ pui8Packet[1] = TFTP_RRQ & 0xff;
+
+ //
+ // Copy the file name into the RRQ packet.
+ //
+ for(ui32Idx = 2, pcFilename = g_pcFilename;
+ (pui8Packet[ui32Idx++] = *pcFilename++) != 0; )
+ {
+ }
+
+ //
+ // Set the transfer mode to binary.
+ //
+ for(pcFilename = "octet"; (pui8Packet[ui32Idx++] = *pcFilename++) != 0; )
+ {
+ }
+
+ //
+ // Send the TFTP read packet.
+ //
+ uip_udp_send(ui32Idx);
+}
+
+//*****************************************************************************
+//
+//! Parses a packet checking for a TFTP data packet.
+//!
+//! This function parses a packet to determine if it is a TFTP data packet for
+//! out current TFTP transfer. If a valid packet is found, the contents of the
+//! packet are programmed into flash.
+//!
+//! \return Returns 1 if this packet was the last packet of the TFTP data
+//! transfer and 0 otherwise.
+//
+//*****************************************************************************
+static uint32_t
+ParseTFTPData(void)
+{
+ uint8_t *pui8Packet = (uint8_t *)uip_appdata;
+ uint32_t ui32FlashAddr;
+ uint32_t ui32Idx;
+
+ //
+ // See if this is a TFTP data packet.
+ //
+ if((pui8Packet[0] != ((TFTP_DATA >> 8) && 0xff)) ||
+ (pui8Packet[1] != (TFTP_DATA & 0xff)))
+ {
+ return(0);
+ }
+
+ //
+ // If the remote port on our connection is still the TFTP server port (i.e.
+ // this is the first data packet), then copy the transaction ID for the
+ // TFTP data connection into our connection. This will ensure that our
+ // response will be sent to the correct port.
+ //
+ if(g_pConn->rport == HTONS(TFTP_PORT))
+ {
+ g_pConn->rport =
+ ((struct uip_udpip_hdr *)&uip_buf[UIP_LLH_LEN])->srcport;
+ }
+
+ //
+ // See if this is the correct data packet.
+ //
+ if((pui8Packet[2] != ((g_ui32TFTPBlock >> 8) & 0xff)) ||
+ (pui8Packet[3] != (g_ui32TFTPBlock & 0xff)))
+ {
+ //
+ // Since the wrong data packet was sent, resend the ACK for it since
+ // we've already processed it.
+ //
+ pui8Packet[0] = (TFTP_ACK >> 8) & 0xff;
+ pui8Packet[1] = TFTP_ACK & 0xff;
+ uip_udp_send(4);
+
+ //
+ // Ignore this packet.
+ //
+ return(0);
+ }
+
+ //
+ // What address are we about to program to?
+ //
+ ui32FlashAddr =
+ ((g_ui32TFTPBlock - 1) * TFTP_BLOCK_SIZE) + APP_START_ADDRESS;
+
+ //
+ // Do not program this data into flash if it is beyond the end of flash.
+ //
+ if(ui32FlashAddr < g_ui32FlashEnd)
+ {
+ //
+ // If this is the first block and we have been provided with a start
+ // hook function, call it here to indicate that we are about to begin
+ // flashing a new image.
+ //
+#ifdef BL_START_FN_HOOK
+ if(g_ui32TFTPBlock == 1)
+ {
+ BL_START_FN_HOOK();
+ }
+#endif
+
+ //
+ // Clear any flash error indicator.
+ //
+ BL_FLASH_CL_ERR_FN_HOOK();
+
+ //
+ // If this is the first data packet and code protection is enabled,
+ // then erase the entire flash.
+ //
+#ifdef FLASH_CODE_PROTECTION
+ if(g_ui32TFTPBlock == 1)
+ {
+ //
+ // Loop through the pages in the flash, excluding the pages that
+ // contain the boot loader and the optional reserved space.
+ //
+ for(ui32Idx = APP_START_ADDRESS; ui32Idx < g_ui32FlashEnd;
+ ui32Idx += FLASH_PAGE_SIZE)
+ {
+ //
+ // Erase this block of the flash.
+ //
+ BL_FLASH_ERASE_FN_HOOK((ui32Idx);
+ }
+ }
+#else
+ //
+ // Flash code protection is not enabled, so see if the data in this
+ // packet will be programmed to the beginning of a flash block. We
+ // assume that the flash block size is always a multiple of 1KB so,
+ // since each TFTP packet is 512 bytes and that the start must always
+ // be on a flash page boundary, we can be sure that we will hit the
+ // start of each page as we receive packets.
+ //
+ if(!(ui32FlashAddr & (FLASH_PAGE_SIZE - 1)))
+ {
+ //
+ // Erase this block of the flash.
+ //
+ BL_FLASH_ERASE_FN_HOOK(ui32FlashAddr);
+ }
+#endif
+
+ //
+ // Decrypt the data if required.
+ //
+#ifdef BL_DECRYPT_FN_HOOK
+ BL_DECRYPT_FN_HOOK(pui8Packet + 4, uip_len - 4);
+#endif
+
+ //
+ // Program this block of data into flash.
+ //
+ BL_FLASH_PROGRAM_FN_HOOK(ui32FlashAddr, (pui8Packet + 4),
+ (uip_len - 4));
+
+ //
+ // If a progress reporting hook function has been provided, call it
+ // here. The TFTP protocol doesn't let us know how large the image is
+ // before it starts the transfer so we pass 0 as the ui32Total
+ // parameter to indicate this.
+ //
+#ifdef BL_PROGRESS_FN_HOOK
+ BL_PROGRESS_FN_HOOK(((ui32FlashAddr - APP_START_ADDRESS) +
+ (uip_len - 4)), 0);
+#endif
+ }
+
+ //
+ // Increment to the next block.
+ //
+ g_ui32TFTPBlock++;
+
+ //
+ // Save the packet length.
+ //
+ ui32Idx = uip_len;
+
+ //
+ // Did we see any error?
+ //
+ if(BL_FLASH_ERROR_FN_HOOK())
+ {
+ //
+ // Yes - send back an error packet.
+ //
+ SendTFTPError(2, "Error programming flash.");
+ }
+ else
+ {
+ //
+ // No errors reported so construct an ACK packet. The block number
+ // field is already correct, so it does not need to be set.
+ //
+ pui8Packet[0] = (TFTP_ACK >> 8) & 0xff;
+ pui8Packet[1] = TFTP_ACK & 0xff;
+
+ //
+ // Send the ACK packet to the TFTP server.
+ //
+ uip_udp_send(4);
+ }
+
+ //
+ // If the packet was shorter than TFTP_BLOCK_SIZE bytes then this was the
+ // last packet in the file.
+ //
+ if(ui32Idx != (TFTP_BLOCK_SIZE + 4))
+ {
+ //
+ // If an end signal hook function has been provided, call it here.
+ //
+#ifdef BL_END_FN_HOOK
+ BL_END_FN_HOOK();
+#endif
+ return(1);
+ }
+ //
+ // There is more data to be read.
+ //
+ return(0);
+}
+
+uint16_t
+LOCAL_EMACPHYRead(uint32_t ui32Base, uint8_t ui8PhyAddr, uint8_t ui8RegAddr)
+{
+
+ //
+ // Make sure the MII is idle.
+ //
+ while(HWREG(ui32Base + EMAC_O_MIIADDR) & EMAC_MIIADDR_MIIB)
+ {
+ }
+
+ //
+ // Tell the MAC to read the given PHY register.
+ //
+ HWREG(ui32Base + EMAC_O_MIIADDR) =
+ ((HWREG(ui32Base + EMAC_O_MIIADDR) & EMAC_MIIADDR_CR_M) |
+ (ui8RegAddr << EMAC_MIIADDR_MII_S) |
+ (ui8PhyAddr << EMAC_MIIADDR_PLA_S) | EMAC_MIIADDR_MIIB);
+
+ //
+ // Wait for the read to complete.
+ //
+ while(HWREG(ui32Base + EMAC_O_MIIADDR) & EMAC_MIIADDR_MIIB)
+ {
+ }
+
+ //
+ // Return the result.
+ //
+ return(HWREG(ui32Base + EMAC_O_MIIDATA) & EMAC_MIIDATA_DATA_M);
+}
+
+//*****************************************************************************
+//
+//! Handles the BOOTP process.
+//!
+//! This function contains the proto-thread for handling the BOOTP process. It
+//! first communicates with the BOOTP server to get its boot parameters (IP
+//! address, server address, and file name), then it communicates with the TFTP
+//! server on the specified server to read the firmware image file.
+//!
+//! \return None.
+//
+//*****************************************************************************
+#ifdef DOXYGEN
+char
+BOOTPThread(void)
+#else
+PT_THREAD(BOOTPThread(void))
+#endif
+{
+ //
+ // Begin the proto-thread.
+ //
+ PT_BEGIN(&g_sThread);
+
+wait_for_link:
+ PT_WAIT_UNTIL(&g_sThread,
+ (LOCAL_EMACPHYRead(EMAC0_BASE, 0, EPHY_BMSR) &
+ EPHY_BMSR_LINKSTAT) != 0);
+
+ //
+ // Reset the host address.
+ //
+ *((uint32_t *)(void *)(&uip_hostaddr)) = 0;
+
+ //
+ // Re-bind the UDP socket for sending requests to the BOOTP server.
+ //
+ uip_udp_remove(g_pConn);
+ *((uint32_t *)(void *)(&g_sServerAddr)) = 0xffffffff;
+ uip_udp_new(&g_sServerAddr, HTONS(BOOTP_SERVER_PORT));
+ uip_udp_bind(g_pConn, HTONS(BOOTP_CLIENT_PORT));
+
+ //
+ // Set the initial delay between BOOTP requests to 1 second.
+ //
+ g_ui32Delay = SYSTICKHZ;
+
+ //
+ // Loop forever. This loop is explicitly exited when a valid BOOTP reply
+ // is received.
+ //
+ while(1)
+ {
+ //
+ // Send a BOOTP request.
+ //
+ SendBOOTPRequest();
+
+ //
+ // Set the amount of time to wait for the BOOTP reply message.
+ //
+ g_ui32Target = g_ui32Ticks + g_ui32Delay;
+
+ //
+ // Wait until a packet is received or the timeout has occurred.
+ //
+wait_for_bootp_reply:
+ PT_WAIT_UNTIL(&g_sThread,
+ ((g_ui32Link = (LOCAL_EMACPHYRead(EMAC0_BASE, 0, EPHY_BMSR) &
+ EPHY_BMSR_LINKSTAT)) == 0) ||
+ uip_newdata() || (g_ui32Ticks > g_ui32Target));
+
+ //
+ // If the link has been lost, go back to waiting for a link.
+ //
+ if(g_ui32Link == 0)
+ {
+ goto wait_for_link;
+ }
+
+ //
+ // See if a packet has been received.
+ //
+ if(uip_newdata())
+ {
+ //
+ // Clear the new data flag so that this packet will only be
+ // examined one time.
+ //
+ uip_flags &= ~(UIP_NEWDATA);
+
+ //
+ // See if this is a BOOTP reply.
+ //
+ if(ParseBOOTPReply() == 1)
+ {
+ break;
+ }
+
+ //
+ // This was not a BOOTP reply packet, so go back to waiting.
+ //
+ goto wait_for_bootp_reply;
+ }
+
+ //
+ // If the delay between BOOTP requests is less than 60 seconds, double
+ // the delay time. This avoids constantly slamming the network with
+ // requests.
+ //
+ if(g_ui32Delay < (60 * SYSTICKHZ))
+ {
+ g_ui32Delay *= 2;
+ }
+ }
+
+ //
+ // Reconfigure the UDP socket to target the TFTP port on the server.
+ //
+ uip_ipaddr_copy(&g_pConn->ripaddr, g_sServerAddr);
+ uip_udp_bind(g_pConn, HTONS(13633));
+
+ //
+ // Send a TFTP read request.
+ //
+ SendTFTPGet();
+
+ //
+ // Since the first TFTP read request will result in an ARP request, delay
+ // for just a bit and then re-issue the TFTP read request.
+ //
+ PT_YIELD(&g_sThread);
+
+ //
+ // Resend the TFTP read request. If the ARP request has already been
+ // answered, this will go out as is and avoid the two second timeout below.
+ //
+ SendTFTPGet();
+
+ //
+ // Start the TFTP transfer from block one.
+ //
+ g_ui32TFTPBlock = 1;
+
+ //
+ // Set the number of TFTP retries to zero.
+ //
+ g_ui32TFTPRetries = 0;
+
+ //
+ // Loop forever. This loop is explicitly exited when the TFTP transfer has
+ // completed.
+ //
+ while(1)
+ {
+ //
+ // Set the amount of time to wait for the TFTP data packet.
+ //
+ g_ui32Target = g_ui32Ticks + (SYSTICKHZ * 4);
+
+ //
+ // Wait until a packet is received or the timeout has occurred.
+ //
+ PT_WAIT_UNTIL(&g_sThread,
+ ((g_ui32Link = (LOCAL_EMACPHYRead(EMAC0_BASE, 0, EPHY_BMSR) &
+ EPHY_BMSR_LINKSTAT)) == 0) ||
+ uip_newdata() || (g_ui32Ticks > g_ui32Target));
+
+ //
+ // If the link has been lost, go back to waiting for a link.
+ //
+ if(g_ui32Link == 0)
+ {
+ goto wait_for_link;
+ }
+
+ //
+ // See if a packet has been received.
+ //
+ if(uip_newdata())
+ {
+ //
+ // Clear the new data flag so that this packet will only be
+ // examined one time.
+ //
+ uip_flags &= ~(UIP_NEWDATA);
+
+ //
+ // See if this is a TFTP data packet.
+ //
+ if(ParseTFTPData() == 1)
+ {
+ break;
+ }
+ }
+ else if(g_ui32TFTPRetries < 3)
+ {
+ //
+ // The transfer timed out, so send a new TFTP read request.
+ //
+ SendTFTPGet();
+
+ //
+ // Start the TFTP transfer from block one.
+ //
+ g_ui32TFTPBlock = 1;
+
+ //
+ // Increment the count of TFTP retries.
+ //
+ g_ui32TFTPRetries++;
+ }
+ else
+ {
+ //
+ // The TFTP transfer failed after three retries, so start over.
+ //
+ goto wait_for_link;
+ }
+ }
+ //
+ // Wait for the last packet to be transmitted.
+ //
+ while(g_psTxDescriptor[g_ui32TxDescIndex].ui32CtrlStatus &
+ DES0_TX_CTRL_OWN)
+ {
+ }
+
+ //
+ // Wait for a bit to make sure that the final ACK packet is transmitted.
+ //
+ g_ui32Target = g_ui32Ticks + (SYSTICKHZ / 4);
+ while(g_ui32Ticks < g_ui32Target)
+ {
+ PT_YIELD(&g_sThread);
+ }
+
+ //
+ // Perform a software reset request. This will cause the microcontroller
+ // to reset; no further code will be executed.
+ //
+ HWREG(NVIC_APINT) = NVIC_APINT_VECTKEY | NVIC_APINT_SYSRESETREQ;
+
+ //
+ // The microcontroller should have reset, so this should never be reached.
+ // Just in case, loop forever.
+ //
+ while(1)
+ {
+ }
+
+ //
+ // End the proto-thread.
+ //
+ PT_END(&g_sThread);
+}
+
+static void
+LOCAL_EMACPHYConfigSet(uint32_t ui32Base, uint32_t ui32Config)
+{
+ //
+ // Write the Ethernet PHY configuration to the peripheral configuration
+ // register.
+ //
+ HWREG(ui32Base + EMAC_O_PC) = ui32Config;
+
+ //
+ // If using the internal PHY, reset it to ensure that new configuration is
+ // latched there.
+ //
+ if((ui32Config & EMAC_PHY_TYPE_MASK) == EMAC_PHY_TYPE_INTERNAL)
+ {
+ ROM_SysCtlPeripheralReset(SYSCTL_PERIPH_EPHY0);
+ while(!ROM_SysCtlPeripheralReady(SYSCTL_PERIPH_EPHY0))
+ {
+ //
+ // Wait for the PHY reset to complete.
+ //
+ }
+
+ //
+ // Delay a bit longer to ensure that the PHY reset has completed.
+ //
+ ROM_SysCtlDelay(1000);
+ }
+
+ //
+ // If using an external RMII PHY, we must set 2 bits in the Ethernet MAC
+ // Clock Configuration Register.
+ //
+ if((ui32Config & EMAC_PHY_TYPE_MASK) == EMAC_PHY_TYPE_EXTERNAL_RMII)
+ {
+ //
+ // Select and enable the external clock from the RMII PHY.
+ //
+ HWREG(EMAC0_BASE + EMAC_O_CC) |= EMAC_CC_CLKEN;
+ }
+ else
+ {
+ //
+ // Disable the external clock.
+ //
+ HWREG(EMAC0_BASE + EMAC_O_CC) &= ~EMAC_CC_CLKEN;
+ }
+
+ //
+ // Reset the MAC regardless of whether the PHY connection changed or not.
+ //
+ ROM_EMACReset(EMAC0_BASE);
+
+ ROM_SysCtlDelay(1000);
+}
+
+//*****************************************************************************
+//
+//! Reconfigures the Ethernet controller.
+//!
+//! \param ui32Clock is the system clock frequency.
+//!
+//! This function reconfigures the Ethernet controller, preparing it for use by
+//! the boot loader. This performs the steps common between the direct
+//! invocation of the boot loader and the application invocation of the boot
+//! loader.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+EnetReconfig(uint32_t ui32Clock)
+{
+ uip_ipaddr_t sAddr;
+ uint32_t ui32Loop;
+ uint32_t ui32User0, ui32User1;
+
+ //
+ // Configure for use with the internal PHY.
+ //
+ LOCAL_EMACPHYConfigSet(EMAC0_BASE,
+ (EMAC_PHY_TYPE_INTERNAL | EMAC_PHY_INT_MDIX_EN |
+ EMAC_PHY_AN_100B_T_FULL_DUPLEX));
+
+
+ //
+ // Reset the MAC.
+ //
+ ROM_EMACReset(EMAC0_BASE);
+
+ //
+ // Initialize the MAC and set the DMA mode.
+ //
+ ROM_EMACInit(EMAC0_BASE, ui32Clock,
+ EMAC_BCONFIG_MIXED_BURST | EMAC_BCONFIG_PRIORITY_FIXED, 4, 4, 0);
+
+ //
+ // Get the MAC address from the flash user registers. If it has not been
+ // programmed, then use the boot loader default MAC address.
+ //
+ ROM_FlashUserGet(&ui32User0, &ui32User1);
+ if((ui32User0 == 0xffffffff) || (ui32User1 == 0xffffffff))
+ {
+ //
+ // MAC address has not been programmed, use default.
+ //
+ g_sMACAddr.addr[0] = 0x00;
+ g_sMACAddr.addr[1] = 0x1a;
+ g_sMACAddr.addr[2] = 0xb6;
+ g_sMACAddr.addr[3] = 0x00;
+ g_sMACAddr.addr[4] = 0x64;
+ g_sMACAddr.addr[5] = 0x00;
+ }
+ else
+ {
+ g_sMACAddr.addr[0] = ui32User0 & 0xff;
+ g_sMACAddr.addr[1] = (ui32User0 >> 8) & 0xff;
+ g_sMACAddr.addr[2] = (ui32User0 >> 16) & 0xff;
+ g_sMACAddr.addr[3] = ui32User1 & 0xff;
+ g_sMACAddr.addr[4] = (ui32User1 >> 8) & 0xff;
+ g_sMACAddr.addr[5] = (ui32User1 >> 16) & 0xff;
+ }
+
+ //
+ // Set MAC configuration options.
+ //
+ ROM_EMACConfigSet(EMAC0_BASE,
+ (EMAC_CONFIG_FULL_DUPLEX | EMAC_CONFIG_CHECKSUM_OFFLOAD |
+ EMAC_CONFIG_7BYTE_PREAMBLE | EMAC_CONFIG_IF_GAP_96BITS |
+ EMAC_CONFIG_USE_MACADDR0 | EMAC_CONFIG_SA_FROM_DESCRIPTOR |
+ EMAC_CONFIG_BO_LIMIT_1024),
+ (EMAC_MODE_RX_STORE_FORWARD | EMAC_MODE_TX_STORE_FORWARD |
+ EMAC_MODE_TX_THRESHOLD_64_BYTES |
+ EMAC_MODE_RX_THRESHOLD_64_BYTES), 0);
+
+ //
+ // Initialize each of the transmit descriptors. Note that we leave the OWN
+ // bit clear here since we have not set up any transmissions yet.
+ //
+ for(ui32Loop = 0; ui32Loop < NUM_TX_DESCRIPTORS; ui32Loop++)
+ {
+ g_psTxDescriptor[ui32Loop].ui32Count =
+ (DES1_TX_CTRL_SADDR_INSERT |
+ (TX_BUFFER_SIZE << DES1_TX_CTRL_BUFF1_SIZE_S));
+ g_psTxDescriptor[ui32Loop].pvBuffer1 = g_pui8TxBuffer;
+ g_psTxDescriptor[ui32Loop].DES3.pLink =
+ (ui32Loop == (NUM_TX_DESCRIPTORS - 1)) ?
+ g_psTxDescriptor : &g_psTxDescriptor[ui32Loop + 1];
+ g_psTxDescriptor[ui32Loop].ui32CtrlStatus =
+ (DES0_TX_CTRL_LAST_SEG | DES0_TX_CTRL_FIRST_SEG |
+ DES0_TX_CTRL_INTERRUPT | DES0_TX_CTRL_CHAINED |
+ DES0_TX_CTRL_IP_ALL_CKHSUMS);
+ }
+
+ //
+ // Initialize each of the receive descriptors. We clear the OWN bit here
+ // to make sure that the receiver doesn't start writing anything
+ // immediately.
+ //
+ for(ui32Loop = 0; ui32Loop < NUM_RX_DESCRIPTORS; ui32Loop++)
+ {
+ g_psRxDescriptor[ui32Loop].ui32CtrlStatus = 0;
+ g_psRxDescriptor[ui32Loop].ui32Count =
+ (DES1_RX_CTRL_CHAINED |
+ (RX_BUFFER_SIZE << DES1_RX_CTRL_BUFF1_SIZE_S));
+ g_psRxDescriptor[ui32Loop].pvBuffer1 = g_pui8RxBuffer;
+ g_psRxDescriptor[ui32Loop].DES3.pLink =
+ (ui32Loop == (NUM_RX_DESCRIPTORS - 1)) ?
+ g_psRxDescriptor : &g_psRxDescriptor[ui32Loop + 1];
+ }
+
+ //
+ // Set the descriptor pointers in the hardware.
+ //
+ ROM_EMACRxDMADescriptorListSet(EMAC0_BASE, g_psRxDescriptor);
+ ROM_EMACTxDMADescriptorListSet(EMAC0_BASE, g_psTxDescriptor);
+
+ //
+ // Start from the beginning of both descriptor chains. We actually set
+ // the transmit descriptor index to the last descriptor in the chain
+ // since it will be incremented before use and this means the first
+ // transmission we perform will use the correct descriptor.
+ //
+ g_ui32RxDescIndex = 0;
+ g_ui32TxDescIndex = NUM_TX_DESCRIPTORS - 1;
+
+ //
+ // Program the MAC address.
+ //
+ ROM_EMACAddrSet(EMAC0_BASE, 0, g_sMACAddr.addr);
+
+ //
+ // Wait for the link to become active.
+ //
+ while((ROM_EMACPHYRead(EMAC0_BASE, 0, EPHY_BMSR) &
+ EPHY_BMSR_LINKSTAT) == 0)
+ {
+ }
+
+ //
+ // Set MAC filtering options. We receive all broadcast and multicast
+ // packets along with those addressed specifically for us.
+ //
+ ROM_EMACFrameFilterSet(EMAC0_BASE, (EMAC_FRMFILTER_SADDR |
+ EMAC_FRMFILTER_PASS_MULTICAST |
+ EMAC_FRMFILTER_PASS_NO_CTRL));
+
+ //
+ // Seed the random number generator from the MAC address.
+ //
+ g_ui32RandomSeed = *(uint32_t *)(g_sMACAddr.addr + 2);
+
+ //
+ // Initialize the uIP stack.
+ //
+ uip_init();
+ uip_arp_init();
+
+ //
+ // Set the MAC address.
+ //
+ uip_setethaddr(g_sMACAddr);
+
+ //
+ // Initialize the proto-thread used by the BOOTP protocol handler.
+ //
+ PT_INIT(&g_sThread);
+
+ //
+ // Create a UDP socket for sending requests to the BOOTP server. After the
+ // BOOTP portion of the protocol has been handled, this socket will be
+ // reused to communicate with the TFTP server.
+ //
+ *((uint32_t *)(void *)(&sAddr)) = 0xffffffff;
+ g_pConn = uip_udp_new(&sAddr, HTONS(BOOTP_SERVER_PORT));
+ uip_udp_bind(g_pConn, HTONS(BOOTP_CLIENT_PORT));
+
+ //
+ // Enable the Ethernet MAC transmitter and receiver.
+ //
+ ROM_EMACTxEnable(EMAC0_BASE);
+ ROM_EMACRxEnable(EMAC0_BASE);
+
+ //
+ // Mark the first receive descriptor as available to the DMA to start
+ // the receive processing.
+ //
+ g_psRxDescriptor[g_ui32RxDescIndex].ui32CtrlStatus |= DES0_RX_CTRL_OWN;
+
+ //
+ // Reset the counters that are incremented by SysTick.
+ //
+ g_ui32Ticks = 0;
+ g_ui32PeriodicTimer = 0;
+ g_ui32ARPTimer = 0;
+
+ //
+ // Setup SysTick.
+ //
+ HWREG(NVIC_ST_RELOAD) = (ui32Clock / SYSTICKHZ) - 1;
+ HWREG(NVIC_ST_CTRL) = (NVIC_ST_CTRL_CLK_SRC | NVIC_ST_CTRL_INTEN |
+ NVIC_ST_CTRL_ENABLE);
+}
+//*****************************************************************************
+//
+//! Configures the Ethernet controller.
+//!
+//! This function configures the Ethernet controller, preparing it for use by
+//! the boot loader.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+ConfigureEnet(void)
+{
+ //
+ // Make sure the main oscillator is enabled because this is required by
+ // the PHY. The system must have a 25MHz crystal attached to the OSC
+ // pins. The SYSCTL_MOSC_HIGHFREQ parameter is used when the crystal
+ // frequency is 10MHz or higher.
+ //
+ HWREG(SYSCTL_MOSCCTL) = SYSCTL_MOSC_HIGHFREQ;
+
+ //
+ // Delay while the main oscillator starts up.
+ //
+ Delay(5242880);
+
+ MAP_SysCtlClockFreqSet((SYSCTL_XTAL_25MHZ |
+ SYSCTL_OSC_MAIN |
+ SYSCTL_USE_PLL |
+ SYSCTL_CFG_VCO_480), 120000000);
+
+
+#ifdef ENET_ENABLE_LEDS
+ //
+ // PF1/PK4/PK6 are used for Ethernet LEDs.
+ //
+ ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);
+ ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOK);
+ ROM_GPIOPinConfigure(GPIO_PF1_EN0LED2);
+ ROM_GPIOPinConfigure(GPIO_PK4_EN0LED0);
+ ROM_GPIOPinConfigure(GPIO_PK6_EN0LED1);
+
+ //
+ // Make the pin(s) be peripheral controlled.
+ //
+ ROM_GPIODirModeSet(GPIO_PORTF_BASE, GPIO_PIN_1, GPIO_DIR_MODE_HW);
+ ROM_GPIODirModeSet(GPIO_PORTK_BASE, GPIO_PIN_4|GPIO_PIN_6, GPIO_DIR_MODE_HW);
+
+ //
+ // Set the pad(s) for standard push-pull operation.
+ //
+ ROM_GPIOPadConfigSet(GPIO_PORTF_BASE, GPIO_PIN_1, GPIO_STRENGTH_2MA, GPIO_PIN_TYPE_STD);
+ ROM_GPIOPadConfigSet(GPIO_PORTK_BASE, GPIO_PIN_4|GPIO_PIN_6, GPIO_STRENGTH_2MA, GPIO_PIN_TYPE_STD);
+#endif
+
+ //
+ // Enable and reset the Ethernet modules.
+ //
+ ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_EMAC0);
+ ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_EPHY0);
+ ROM_SysCtlPeripheralReset(SYSCTL_PERIPH_EMAC0);
+ ROM_SysCtlPeripheralReset(SYSCTL_PERIPH_EPHY0);
+
+ while(!ROM_SysCtlPeripheralReady(SYSCTL_PERIPH_EMAC0))
+ {
+ }
+
+}
+
+//*****************************************************************************
+//
+//! Starts the update process via BOOTP.
+//!
+//! This function starts the Ethernet firmware update process. The BOOTP
+//! (as defined by RFC951 at http://tools.ietf.org/html/rfc951) and TFTP (as
+//! defined by RFC1350 at http://tools.ietf.org/html/rfc1350) protocols are
+//! used to transfer the firmware image over Ethernet.
+//!
+//! \return Never returns.
+//
+//*****************************************************************************
+void
+UpdateBOOTP(void)
+{
+ //
+ // Get the size of flash.
+ //
+ g_ui32FlashEnd = ROM_SysCtlFlashSizeGet();
+#ifdef FLASH_RSVD_SPACE
+ g_ui32FlashEnd -= FLASH_RSVD_SPACE;
+#endif
+
+ //
+ // Perform the common Ethernet configuration. The frequency should
+ // match whatever the application sets the system clock.
+ //
+ EnetReconfig(120000000);
+
+ //
+ // Main Application Loop.
+ //
+ while(1)
+ {
+ uint32_t ui32Temp;
+
+ //
+ // See if there is a packet waiting to be read.
+ //
+ if(!(g_psRxDescriptor[g_ui32RxDescIndex].ui32CtrlStatus &
+ DES0_RX_CTRL_OWN))
+ {
+ //
+ // Read the packet from the Ethernet controller.
+ //
+ uip_len = PacketReceive(uip_buf, UIP_CONF_BUFFER_SIZE);
+
+ //
+ // See if this is an IP packet.
+ //
+ if((uip_len != 0) &&
+ (((struct uip_eth_hdr *)&uip_buf[0])->type ==
+ HTONS(UIP_ETHTYPE_IP)))
+ {
+ //
+ // Update the ARP tables based on this packet.
+ //
+ uip_arp_ipin();
+
+ //
+ // Process this packet.
+ //
+ uip_input();
+
+ //
+ // See if the processing of this packet resulted in a packet to be
+ // sent.
+ //
+ if(uip_len > 0)
+ {
+ //
+ // Update the ARP tables based on the packet to be sent.
+ //
+ uip_arp_out();
+
+ //
+ // Send the packet.
+ //
+ PacketTransmit(uip_buf, uip_len);
+
+ //
+ // Indicate that the packet has been sent.
+ //
+ uip_len = 0;
+ }
+ }
+
+ //
+ // See if this is an ARP packet.
+ //
+ else if((uip_len != 0) &&
+ (((struct uip_eth_hdr *)&uip_buf[0])->type ==
+ HTONS(UIP_ETHTYPE_ARP)))
+ {
+ //
+ // Process this packet.
+ //
+ uip_arp_arpin();
+
+ //
+ // See if the processing of this packet resulted in a packet to be
+ // sent.
+ //
+ if(uip_len > 0)
+ {
+ //
+ // Send the packet.
+ //
+ PacketTransmit(uip_buf, uip_len);
+
+ //
+ // Indicate that the packet has been sent.
+ //
+ uip_len = 0;
+ }
+ }
+ }
+
+ //
+ // See if the periodic timer has expired.
+ //
+ if(g_ui32PeriodicTimer > UIP_PERIODIC_TIMER_MS)
+ {
+ //
+ // Reset the periodic timer.
+ //
+ g_ui32PeriodicTimer = 0;
+
+ //
+ // Loop through the UDP connections.
+ //
+ for(ui32Temp = 0; ui32Temp < UIP_UDP_CONNS; ui32Temp++)
+ {
+ //
+ // Perform the periodic processing on this UDP connection.
+ //
+ uip_udp_periodic(ui32Temp);
+
+ //
+ // See if the periodic processing of this connection resulted in a
+ // packet to be sent.
+ //
+ if(uip_len > 0)
+ {
+ //
+ // Update the ARP tables based on the packet to be sent.
+ //
+ uip_arp_out();
+
+ //
+ // Send the packet.
+ //
+ PacketTransmit(uip_buf, uip_len);
+
+ //
+ // Indicate that the packet has been sent.
+ //
+ uip_len = 0;
+ }
+ }
+ }
+
+ //
+ // See if the ARP timer has expired.
+ //
+ if(g_ui32ARPTimer > UIP_ARP_TIMER_MS)
+ {
+ //
+ // Reset the ARP timer.
+ //
+ g_ui32ARPTimer = 0;
+
+ //
+ // Perform periodic processing on the ARP table.
+ //
+ uip_arp_timer();
+ }
+ }
+}
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
+#endif
diff --git a/boot_loader/bl_flash.c b/boot_loader/bl_flash.c
new file mode 100644
index 0000000..3bbb0ee
--- /dev/null
+++ b/boot_loader/bl_flash.c
@@ -0,0 +1,218 @@
+//*****************************************************************************
+//
+// bl_flash.c - Flash programming functions used by the boot loader.
+//
+// Copyright (c) 2006-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
+//
+//*****************************************************************************
+
+#include <stdint.h>
+#include "inc/hw_types.h"
+#include "inc/hw_flash.h"
+#include "inc/hw_sysctl.h"
+#include "inc/hw_memmap.h"
+#include "bl_config.h"
+#include "boot_loader/bl_flash.h"
+
+//*****************************************************************************
+//
+//! Erases a single 1KB block of internal flash.
+//!
+//! \param ui32Address is the address of the block of flash to erase.
+//!
+//! This function erases a single 1KB block of the internal flash, blocking
+//! until the erase has completed.
+//!
+//! \return None
+//
+//*****************************************************************************
+void
+BLInternalFlashErase(uint32_t ui32Address)
+{
+ //
+ // Erase this block of the flash.
+ //
+ HWREG(FLASH_FMA) = ui32Address;
+ HWREG(FLASH_FMC) = FLASH_FMC_WRKEY | FLASH_FMC_ERASE;
+
+ //
+ // Wait until the flash has been erased.
+ //
+ while(HWREG(FLASH_FMC) & FLASH_FMC_ERASE)
+ {
+ }
+}
+
+//*****************************************************************************
+//
+//! Programs a block of data at a given address in the internal flash.
+//!
+//! \param ui32DstAddr is the address of the first word to be programmed in
+//! flash.
+//! \param pui8SrcData is a pointer to the first byte to be programmed.
+//! \param ui32Length is the number of bytes to program. This must be a
+//! multiple of 4.
+//!
+//! This function writes a block of data to the internal flash at a given
+//! address. Since the flash is written a word at a time, the data must be a
+//! multiple of 4 bytes and the destination address, ui32DstAddr, must be on a
+//! word boundary.
+//!
+//! \return None
+//
+//*****************************************************************************
+void
+BLInternalFlashProgram(uint32_t ui32DstAddr, uint8_t *pui8SrcData,
+ uint32_t ui32Length)
+{
+ uint32_t ui32Loop;
+
+ for(ui32Loop = 0; ui32Loop < ui32Length; ui32Loop += 4)
+ {
+ //
+ // Program this word into flash.
+ //
+ HWREG(FLASH_FMA) = ui32DstAddr + ui32Loop;
+ HWREG(FLASH_FMD) = *(uint32_t *)(pui8SrcData + ui32Loop);
+ HWREG(FLASH_FMC) = FLASH_FMC_WRKEY | FLASH_FMC_WRITE;
+
+ //
+ // Wait until the flash has been programmed.
+ //
+ while(HWREG(FLASH_FMC) & FLASH_FMC_WRITE)
+ {
+ }
+ }
+}
+
+//*****************************************************************************
+//
+//! Returns the size of the internal flash in bytes.
+//!
+//! This function returns the total number of bytes of internal flash in the
+//! current part. No adjustment is made for any sections reserved via
+//! options defined in bl_config.h.
+//!
+//! \return Returns the total number of bytes of internal flash.
+//
+//*****************************************************************************
+uint32_t
+BLInternalFlashSizeGet(void)
+{
+ return(((HWREG(SYSCTL_DC0) & SYSCTL_DC0_FLASHSZ_M) + 1) << 11);
+}
+
+//*****************************************************************************
+//
+//! Checks whether a given start address is valid for a download.
+//!
+//! This function checks to determine whether the given address is a valid
+//! download image start address given the options defined in bl_config.h.
+//!
+//! \return Returns non-zero if the address is valid or 0 otherwise.
+//
+//*****************************************************************************
+uint32_t
+BLInternalFlashStartAddrCheck(uint32_t ui32Addr, uint32_t ui32ImgSize)
+{
+ uint32_t ui32FlashSize;
+
+ //
+ // Determine the size of the flash available on the part in use.
+ //
+ ui32FlashSize = ((HWREG(SYSCTL_DC0) & SYSCTL_DC0_FLASHSZ_M) + 1) << 11;
+
+ //
+ // If we are reserving space at the top of flash then this space is not
+ // available for application download but it is availble to be updated
+ // directly.
+ //
+#ifdef FLASH_RSVD_SPACE
+ if((ui32FlashSize - FLASH_RSVD_SPACE) != ui32Addr)
+ {
+ ui32FlashSize -= FLASH_RSVD_SPACE;
+ }
+#endif
+
+ //
+ // Is the address we were passed a valid start address? We allow:
+ //
+ // 1. Address 0 if configured to update the boot loader.
+ // 2. The start of the reserved block if parameter space is reserved (to
+ // allow a download of the parameter block contents).
+ // 3. The application start address specified in bl_config.h.
+ //
+ // The function fails if the address is not one of these, if the image
+ // size is larger than the available space or if the address is not word
+ // aligned.
+ //
+ if((
+#ifdef ENABLE_BL_UPDATE
+ (ui32Addr != 0) &&
+#endif
+#ifdef FLASH_RSVD_SPACE
+ (ui32Addr != (ui32FlashSize - FLASH_RSVD_SPACE)) &&
+#endif
+ (ui32Addr != APP_START_ADDRESS)) ||
+ ((ui32Addr + ui32ImgSize) > ui32FlashSize) || ((ui32Addr & 3) != 0))
+ {
+ return(0);
+ }
+ else
+ {
+ return(1);
+ }
+}
+
+//*****************************************************************************
+//
+//! Checks whether a flash access violation occurred.
+//!
+//! This function checks whether an access violation error occurred during
+//! the previous program or erase operation.
+//!
+//! \return Returns 0 if no error occurred or a non-zero value if an error was
+//! reported.
+//
+//*****************************************************************************
+void
+BLInternalFlashErrorClear(void)
+{
+ //
+ // Clear the flash controller access interrupt.
+ //
+ HWREG(FLASH_FCMISC) = FLASH_FCMISC_AMISC;
+}
+
+//*****************************************************************************
+//
+//! Checks whether a flash access violation occurred.
+//!
+//! This function checks whether an access violation error occurred since the
+//! last call to BLInternalFlashErrorClear().
+//!
+//! \return Returns 0 if no error occurred or a non-zero value if an error was
+//! reported.
+//
+//*****************************************************************************
+uint32_t
+BLInternalFlashErrorCheck(void)
+{
+ return(HWREG(FLASH_FCRIS) & FLASH_FCRIS_ARIS);
+}
diff --git a/boot_loader/bl_flash.h b/boot_loader/bl_flash.h
new file mode 100644
index 0000000..4a23f00
--- /dev/null
+++ b/boot_loader/bl_flash.h
@@ -0,0 +1,127 @@
+//*****************************************************************************
+//
+// bl_flash.h - Flash programming functions used by the boot loader.
+//
+// Copyright (c) 2006-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
+//
+//*****************************************************************************
+
+#ifndef __BL_FLASH_H__
+#define __BL_FLASH_H__
+
+#include "driverlib/rom.h"
+
+//*****************************************************************************
+//
+// Basic functions for erasing and programming internal flash.
+//
+//*****************************************************************************
+extern void BLInternalFlashErase(uint32_t ui32Address);
+extern void BLInternalFlashProgram(uint32_t ui32DstAddr, uint8_t *pui8SrcData,
+ uint32_t ui32Length);
+extern uint32_t BLInternalFlashSizeGet(void);
+extern uint32_t BLInternalFlashStartAddrCheck(uint32_t ui32Addr,
+ uint32_t ui32ImgSize);
+extern uint32_t BLInternalFlashErrorCheck(void);
+extern void BLInternalFlashErrorClear(void);
+
+//*****************************************************************************
+//
+// If the user has not specified which flash programming functions to use,
+// default to the basic, internal flash functions on Sandstorm, Fury and
+// DustDevil parts or the ROM-resident function for Tempest-class parts.
+//
+//*****************************************************************************
+#ifndef BL_FLASH_ERASE_FN_HOOK
+#define BL_FLASH_ERASE_FN_HOOK(ui32Address) \
+ { \
+ HWREG(FLASH_FMA) = (ui32Address); \
+ HWREG(FLASH_FMC) = FLASH_FMC_WRKEY | FLASH_FMC_ERASE; \
+ while(HWREG(FLASH_FMC) & FLASH_FMC_ERASE) \
+ { \
+ } \
+ }
+#else
+extern void BL_FLASH_ERASE_FN_HOOK(uint32_t ui32Address);
+#endif
+
+#ifndef BL_FLASH_PROGRAM_FN_HOOK
+#ifdef ROM_FlashProgram
+#define BL_FLASH_PROGRAM_FN_HOOK(ui32DstAddr, pui8SrcData, ui32Length) \
+ ROM_FlashProgram((uint32_t *)pui8SrcData, ui32DstAddr, \
+ (((ui32Length) + 3) & ~3))
+#else
+#define BL_FLASH_PROGRAM_FN_HOOK(ui32DstAddr, pui8SrcData, ui32Length) \
+ { \
+ uint32_t ui32FlashProgLoop; \
+ \
+ for(ui32FlashProgLoop = 0; ui32FlashProgLoop < (ui32Length); \
+ ui32FlashProgLoop += 4) \
+ { \
+ HWREG(FLASH_FMA) = (ui32DstAddr) + ui32FlashProgLoop; \
+ HWREG(FLASH_FMD) = *(uint32_t *)((pui8SrcData) + \
+ ui32FlashProgLoop); \
+ HWREG(FLASH_FMC) = FLASH_FMC_WRKEY | FLASH_FMC_WRITE; \
+ while(HWREG(FLASH_FMC) & FLASH_FMC_WRITE) \
+ { \
+ } \
+ } \
+ }
+#endif
+#else
+extern uint32_t BL_FLASH_PROGRAM_FN_HOOK(uint32_t ui32DstAddr,
+ uint8_t *pui8SrcData,
+ uint32_t ui32Length);
+#endif
+
+#ifndef BL_FLASH_CL_ERR_FN_HOOK
+#define BL_FLASH_CL_ERR_FN_HOOK() HWREG(FLASH_FCMISC) = FLASH_FCMISC_AMISC
+#else
+extern void BL_FLASH_CL_ERR_FN_HOOK(void);
+#endif
+
+#ifndef BL_FLASH_ERROR_FN_HOOK
+#define BL_FLASH_ERROR_FN_HOOK() (HWREG(FLASH_FCRIS) & FLASH_FCRIS_ARIS)
+#else
+extern uint32_t BL_FLASH_ERROR_FN_HOOK(void);
+#endif
+
+#ifndef BL_FLASH_SIZE_FN_HOOK
+#define BL_FLASH_SIZE_FN_HOOK() \
+ (((HWREG(SYSCTL_DC0) & SYSCTL_DC0_FLASHSZ_M) + 1) << 11)
+#else
+extern uint32_t BL_FLASH_SIZE_FN_HOOK(void);
+#endif
+
+#ifndef BL_FLASH_END_FN_HOOK
+#define BL_FLASH_END_FN_HOOK() \
+ (((HWREG(SYSCTL_DC0) & SYSCTL_DC0_FLASHSZ_M) + 1) << 11)
+#else
+extern uint32_t BL_FLASH_END_FN_HOOK(void);
+#endif
+
+#ifndef BL_FLASH_AD_CHECK_FN_HOOK
+#define BL_FLASH_AD_CHECK_FN_HOOK(ui32Addr, ui32Size) \
+ BLInternalFlashStartAddrCheck((ui32Addr), (ui32Size))
+#else
+extern uint32_t BL_FLASH_AD_CHECK_FN_HOOK(uint32_t ui32Address,
+ uint32_t ui32Length);
+#endif
+
+#endif // __BL_FLASH_H__
diff --git a/boot_loader/bl_hooks.h b/boot_loader/bl_hooks.h
new file mode 100644
index 0000000..1a174e3
--- /dev/null
+++ b/boot_loader/bl_hooks.h
@@ -0,0 +1,72 @@
+//*****************************************************************************
+//
+// bl_hooks.h - Definitions for the application-specific hook function.
+//
+// Copyright (c) 2009-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
+//
+//*****************************************************************************
+
+#ifndef __BL_HOOKS_H__
+#define __BL_HOOKS_H__
+
+//*****************************************************************************
+//
+// Prototypes for any application-specific hook functions that are defined in
+// bl_config.h. Note that the low level flash programming hooks are handled
+// in bl_flash.h to allow us to define macros for internal flash programming
+// in the normal case where no override functions are provided.
+//
+//*****************************************************************************
+#ifdef BL_HW_INIT_FN_HOOK
+extern void BL_HW_INIT_FN_HOOK(void);
+#endif
+#ifdef BL_INIT_FN_HOOK
+extern void BL_INIT_FN_HOOK(void);
+#endif
+#ifdef BL_REINIT_FN_HOOK
+extern void BL_REINIT_FN_HOOK(void);
+#endif
+#ifdef BL_START_FN_HOOK
+extern void BL_START_FN_HOOK(void);
+#endif
+#ifdef BL_PROGRESS_FN_HOOK
+extern void BL_PROGRESS_FN_HOOK(uint32_t ui32Completed, uint32_t ui32Total);
+#endif
+#ifdef BL_END_FN_HOOK
+extern void BL_END_FN_HOOK(void);
+#endif
+#ifdef BL_DECRYPT_FN_HOOK
+extern void BL_DECRYPT_FN_HOOK(uint8_t *pui8Buffer, uint32_t ui32Size);
+#endif
+#ifdef BL_CHECK_UPDATE_FN_HOOK
+extern uint32_t BL_CHECK_UPDATE_FN_HOOK(void);
+#endif
+
+//*****************************************************************************
+//
+// If ENABLE_DECRYPTION is defined but we don't have a hook function set for
+// decryption, default to the previous behavior which calls the stub function
+// DecryptData.
+//
+//*****************************************************************************
+#if (defined ENABLE_DECRYPTION) && !(defined BL_DECRYPT_FN_HOOK)
+#define BL_DECRYPT_FN_HOOK DecryptData
+#endif
+
+#endif // __BL_HOOKS_H__
diff --git a/boot_loader/bl_i2c.c b/boot_loader/bl_i2c.c
new file mode 100644
index 0000000..bc2b62c
--- /dev/null
+++ b/boot_loader/bl_i2c.c
@@ -0,0 +1,149 @@
+//*****************************************************************************
+//
+// bl_i2c.c - This file contains the function used to transfer data via the I2C
+// port.
+//
+// Copyright (c) 2006-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
+//
+//*****************************************************************************
+
+#include <stdint.h>
+#include "inc/hw_gpio.h"
+#include "inc/hw_i2c.h"
+#include "inc/hw_memmap.h"
+#include "inc/hw_sysctl.h"
+#include "inc/hw_types.h"
+#include "bl_config.h"
+#include "boot_loader/bl_i2c.h"
+
+//*****************************************************************************
+//
+//! \addtogroup bl_i2c_api
+//! @{
+//
+//*****************************************************************************
+#if defined(I2C_ENABLE_UPDATE) || defined(DOXYGEN)
+
+//*****************************************************************************
+//
+//! Sends data over the I2C port.
+//!
+//! \param pui8Data is the buffer containing the data to write out to the I2C
+//! port.
+//! \param ui32Size is the number of bytes provided in \e pui8Data buffer that
+//! will be written out to the I2C port.
+//!
+//! This function sends \e ui32Size bytes of data from the buffer pointed to by
+//! \e pui8Data via the I2C port. The function will wait till the I2C Slave
+//! port has been properly addressed by the I2C Master device before sending
+//! the first byte.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+I2CSend(const uint8_t *pui8Data, uint32_t ui32Size)
+{
+ //
+ // Transmit the number of bytes requested on the UART port.
+ //
+ while(ui32Size--)
+ {
+ //
+ // Wait for request to come in at slave.
+ //
+ while(!(HWREG(I2C0_BASE + I2C_O_SCSR) & I2C_SCSR_TREQ))
+ {
+ }
+
+ //
+ // Send out the next byte.
+ //
+ HWREG(I2C0_BASE + I2C_O_SDR) = *pui8Data++;
+ }
+}
+
+//*****************************************************************************
+//
+//! Waits until all data has been transmitted by the I2C port.
+//!
+//! This function waits until all data written to the I2C port has been read by
+//! the master.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+I2CFlush(void)
+{
+ //
+ // Wait until the I2C bus is no longer busy, meaning that the last byte has
+ // been sent.
+ //
+ while(HWREG(I2C0_BASE + I2C_O_MCS) & I2C_MCS_BUSBSY)
+ {
+ }
+}
+
+//*****************************************************************************
+//
+//! Receives data over the I2C port.
+//!
+//! \param pui8Data is the buffer to read data into from the I2C port.
+//! \param ui32Size is the number of bytes provided in the \e pui8Data buffer
+//! that should be written with data from the I2C port.
+//!
+//! This function reads back \e ui32Size bytes of data from the I2C port, into
+//! the buffer that is pointed to by \e pui8Data. This function will not
+//! return until \e ui32Size number of bytes have been received. This function
+//! will wait till the I2C Slave port has been properly addressed by the I2C
+//! Master before reading the first byte of data from the I2C port.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+I2CReceive(uint8_t *pui8Data, uint32_t ui32Size)
+{
+ //
+ // Send out the number of bytes requested.
+ //
+ while(ui32Size--)
+ {
+ //
+ // Wait until the slave has received the character.
+ //
+ while(!(HWREG(I2C0_BASE + I2C_O_SCSR) & I2C_SCSR_RREQ))
+ {
+ }
+
+ //
+ // Receive a byte from the I2C.
+ //
+ *pui8Data++ = HWREG(I2C0_BASE + I2C_O_SDR);
+ }
+}
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
+#endif
diff --git a/boot_loader/bl_i2c.h b/boot_loader/bl_i2c.h
new file mode 100644
index 0000000..4b7a01a
--- /dev/null
+++ b/boot_loader/bl_i2c.h
@@ -0,0 +1,70 @@
+//*****************************************************************************
+//
+// bl_i2c.h - Definitions for the I2C transport functions.
+//
+// Copyright (c) 2006-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
+//
+//*****************************************************************************
+
+#ifndef __BL_I2C_H__
+#define __BL_I2C_H__
+
+//*****************************************************************************
+//
+// This defines the I2C clock pin that is being used by the boot loader.
+//
+//*****************************************************************************
+#define I2C_CLK (1 << 2)
+
+//*****************************************************************************
+//
+// This defines the I2C data pin that is being used by the boot loader.
+//
+//*****************************************************************************
+#define I2C_DATA (1 << 3)
+
+//*****************************************************************************
+//
+// This defines the combination of pins used to implement the I2C port used by
+// the boot loader.
+//
+//*****************************************************************************
+#define I2C_PINS (I2C_CLK | I2C_DATA)
+
+//*****************************************************************************
+//
+// I2C Transport APIs
+//
+//*****************************************************************************
+extern void I2CSend(const uint8_t *pui8Data, uint32_t ui32Size);
+extern void I2CReceive(uint8_t *pui8Data, uint32_t ui32Size);
+extern void I2CFlush(void);
+
+//*****************************************************************************
+//
+// Define the transport functions if the I2C port is being used.
+//
+//*****************************************************************************
+#ifdef I2C_ENABLE_UPDATE
+#define SendData I2CSend
+#define FlushData I2CFlush
+#define ReceiveData I2CReceive
+#endif
+
+#endif // __BL_I2C_H__
diff --git a/boot_loader/bl_link.icf b/boot_loader/bl_link.icf
new file mode 100644
index 0000000..3e7af89
--- /dev/null
+++ b/boot_loader/bl_link.icf
@@ -0,0 +1,83 @@
+//*****************************************************************************
+//
+// bl_link.icf - Linker script for EW-ARM.
+//
+// Copyright (c) 2007-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
+//
+//*****************************************************************************
+
+//
+// Define a memory region that covers the entire 4 GB addressible space of the
+// processor.
+//
+define memory mem with size = 4G;
+
+//
+// Define a region for the on-chip flash.
+//
+define region FLASH = mem:[from 0x00000000 to 0x0000ffff];
+
+//
+// Define a region for the on-chip SRAM.
+//
+define region SRAM = mem:[from 0x20000000 to 0x2000ffff];
+
+//
+// Indicate that the sections containing the boot loader code should be
+// initialized by copying.
+//
+initialize manually with packing = none { section INTVEC };
+initialize manually with packing = none { section CODE };
+initialize manually with packing = none { section .text };
+initialize manually with packing = none { section .rodata };
+initialize manually with packing = none { section .data };
+
+keep { section INTVEC };
+keep { section INTVEC_init };
+
+//
+// Indicate that the noinit values should be left alone. This includes the
+// stack, which if initialized will destroy the return address from the
+// initialization code, causing the processor to branch to zero and fault.
+//
+do not initialize { section .noinit };
+
+//
+// Place the interrupt vectors at the start of flash/SRAM.
+//
+place at start of FLASH { readonly section INTVEC_init };
+place at start of SRAM { readwrite section INTVEC };
+
+//
+// Place the remainder of the read-only items into flash/SRAM.
+//
+place in FLASH { readonly section CODE_init };
+place in SRAM { readwrite section CODE };
+place in FLASH { readonly section .text_init };
+place in SRAM { readwrite section .text };
+place in FLASH { readonly section .rodata_init };
+place in SRAM { readwrite section .rodata };
+place in FLASH { readonly section .data_init };
+place in SRAM { readwrite section .data };
+place in FLASH { readonly };
+
+//
+// Place all read/write items into SRAM.
+//
+place in SRAM { readwrite };
diff --git a/boot_loader/bl_link.ld b/boot_loader/bl_link.ld
new file mode 100644
index 0000000..aae5f00
--- /dev/null
+++ b/boot_loader/bl_link.ld
@@ -0,0 +1,51 @@
+/******************************************************************************
+ *
+ * bl_link.ld - Scatter file for Gnu tools
+ *
+ * Copyright (c) 2007-2014 Texas Instruments Incorporated. All rights reserved.
+ * Software License Agreement
+ *
+ * Texas Instruments (TI) is supplying this software for use solely and
+ * exclusively on TI's microcontroller products. The software is owned by
+ * TI and/or its suppliers, and is protected under applicable copyright
+ * laws. You may not combine this software with "viral" open-source
+ * software in order to form a larger program.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+ * NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+ * NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+ * CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+ * DAMAGES, FOR ANY REASON WHATSOEVER.
+ *
+ * This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
+ *
+ *****************************************************************************/
+
+SECTIONS
+{
+ .text 0x20000000 : AT (0x00000000)
+ {
+ _text = .;
+ KEEP(*(.isr_vector))
+ *(.text*)
+ *(.rodata*)
+ _etext = .;
+ }
+
+ .data 0x20000000 + SIZEOF(.text) : AT (SIZEOF(.text))
+ {
+ _data = .;
+ *(.data*)
+ _edata = .;
+ }
+
+ .bss 0x20000000 + SIZEOF(.text) + SIZEOF(.data) :
+ AT (ADDR(.data) + SIZEOF(.data))
+ {
+ _bss = .;
+ *(.bss*)
+ *(COMMON)
+ _ebss = .;
+ }
+}
diff --git a/boot_loader/bl_link.sct b/boot_loader/bl_link.sct
new file mode 100644
index 0000000..fe22bd1
--- /dev/null
+++ b/boot_loader/bl_link.sct
@@ -0,0 +1,45 @@
+;******************************************************************************
+;
+; bl_link.sct - Scatter file for RV-MDK.
+;
+; Copyright (c) 2006-2014 Texas Instruments Incorporated. All rights reserved.
+; Software License Agreement
+;
+; Texas Instruments (TI) is supplying this software for use solely and
+; exclusively on TI's microcontroller products. The software is owned by
+; TI and/or its suppliers, and is protected under applicable copyright
+; laws. You may not combine this software with "viral" open-source
+; software in order to form a larger program.
+;
+; THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+; NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+; NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+; A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+; CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+; DAMAGES, FOR ANY REASON WHATSOEVER.
+;
+; This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
+;
+;******************************************************************************
+
+;
+; The contents of this application reside in flash.
+;
+FLASH 0x00000000 0x00010000
+{
+ ;
+ ; Place the vector table and reset handlers into flash.
+ ;
+ RESET 0x00000000 0x00010000
+ {
+ *.o (RESET, +First)
+ }
+
+ ;
+ ; Place everything else remaining into SRAM (RO, RW, and ZI)
+ ;
+ SRAM +0x20000000 0x00010000
+ {
+ * (+RO, +RW, +ZI)
+ }
+}
diff --git a/boot_loader/bl_link_ccs.cmd b/boot_loader/bl_link_ccs.cmd
new file mode 100644
index 0000000..0e09b6e
--- /dev/null
+++ b/boot_loader/bl_link_ccs.cmd
@@ -0,0 +1,63 @@
+/******************************************************************************
+ *
+ * bl_link_ccs.cmd - CCS linker configuration file for boot loader.
+ *
+ * Copyright (c) 2009-2014 Texas Instruments Incorporated. All rights reserved.
+ * Software License Agreement
+ *
+ * Texas Instruments (TI) is supplying this software for use solely and
+ * exclusively on TI's microcontroller products. The software is owned by
+ * TI and/or its suppliers, and is protected under applicable copyright
+ * laws. You may not combine this software with "viral" open-source
+ * software in order to form a larger program.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+ * NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+ * NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+ * CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+ * DAMAGES, FOR ANY REASON WHATSOEVER.
+ *
+ * This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
+ *
+ *****************************************************************************/
+
+--retain=Vectors
+
+/* The following command line options are set as part of the CCS project. */
+/* If you are building using the command line, or for some reason want to */
+/* define them here, you can uncomment and modify these lines as needed. */
+/* If you are using CCS for building, it is probably better to make any such */
+/* modifications in your CCS project and leave this file alone. */
+/* */
+/* --heap_size=0 */
+/* --stack_size=256 */
+/* --library=rtsv7M3_T_le_eabi.lib */
+
+/* System memory map */
+
+MEMORY
+{
+ FLASH (RX) : origin = 0x00000000, length = 0x00010000
+ SRAM (RWX) : origin = 0x20000000, length = 0x00010000
+}
+
+/* Section allocation in memory */
+
+SECTIONS
+{
+ GROUP
+ {
+ .intvecs
+ .text
+ .const
+ .data
+ } load = FLASH, run = 0x20000000, LOAD_START(init_load), RUN_START(init_run), SIZE(init_size)
+
+ GROUP
+ {
+ .bss
+ .stack
+ } run = SRAM, RUN_START(bss_run), RUN_END(bss_end), SIZE(bss_size), RUN_END(__STACK_TOP)
+
+}
diff --git a/boot_loader/bl_main.c b/boot_loader/bl_main.c
new file mode 100644
index 0000000..fbb7275
--- /dev/null
+++ b/boot_loader/bl_main.c
@@ -0,0 +1,913 @@
+//*****************************************************************************
+//
+// bl_main.c - The file holds the main control loop of the boot loader.
+//
+// Copyright (c) 2006-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
+//
+//*****************************************************************************
+
+#include <stdint.h>
+#include <stdbool.h>
+#include "inc/hw_gpio.h"
+#include "inc/hw_flash.h"
+#include "inc/hw_i2c.h"
+#include "inc/hw_memmap.h"
+#include "inc/hw_nvic.h"
+#include "inc/hw_ssi.h"
+#include "inc/hw_sysctl.h"
+#include "inc/hw_types.h"
+#include "inc/hw_uart.h"
+#include "bl_config.h"
+#include "boot_loader/bl_commands.h"
+#include "boot_loader/bl_decrypt.h"
+#include "boot_loader/bl_flash.h"
+#include "boot_loader/bl_hooks.h"
+#include "boot_loader/bl_i2c.h"
+#include "boot_loader/bl_packet.h"
+#include "boot_loader/bl_ssi.h"
+#include "boot_loader/bl_uart.h"
+#ifdef CHECK_CRC
+#include "boot_loader/bl_crc32.h"
+#endif
+
+//*****************************************************************************
+//
+// Make sure that the application start address falls on a flash page boundary
+//
+//*****************************************************************************
+#if (APP_START_ADDRESS & (FLASH_PAGE_SIZE - 1))
+#error ERROR: APP_START_ADDRESS must be a multiple of FLASH_PAGE_SIZE bytes!
+#endif
+
+//*****************************************************************************
+//
+// Make sure that the flash reserved space is a multiple of flash pages.
+//
+//*****************************************************************************
+#if (FLASH_RSVD_SPACE & (FLASH_PAGE_SIZE - 1))
+#error ERROR: FLASH_RSVD_SPACE must be a multiple of FLASH_PAGE_SIZE bytes!
+#endif
+
+//*****************************************************************************
+//
+//! \addtogroup bl_main_api
+//! @{
+//
+//*****************************************************************************
+#if defined(I2C_ENABLE_UPDATE) || defined(SSI_ENABLE_UPDATE) || \
+ defined(UART_ENABLE_UPDATE) || defined(DOXYGEN)
+
+//*****************************************************************************
+//
+// A prototype for the function (in the startup code) for calling the
+// application.
+//
+//*****************************************************************************
+extern void CallApplication(uint32_t ui32Base);
+
+//*****************************************************************************
+//
+// A prototype for the function (in the startup code) for a predictable length
+// delay.
+//
+//*****************************************************************************
+extern void Delay(uint32_t ui32Count);
+
+//*****************************************************************************
+//
+// Holds the current status of the last command that was issued to the boot
+// loader.
+//
+//*****************************************************************************
+uint8_t g_ui8Status;
+
+//*****************************************************************************
+//
+// This holds the current remaining size in bytes to be downloaded.
+//
+//*****************************************************************************
+uint32_t g_ui32TransferSize;
+
+//*****************************************************************************
+//
+// This holds the total size of the firmware image being downloaded (if the
+// protocol in use provides this).
+//
+//*****************************************************************************
+#if (defined BL_PROGRESS_FN_HOOK) || (defined CHECK_CRC)
+uint32_t g_ui32ImageSize;
+#endif
+
+//*****************************************************************************
+//
+// This holds the current address that is being written to during a download
+// command.
+//
+//*****************************************************************************
+uint32_t g_ui32TransferAddress;
+#ifdef CHECK_CRC
+uint32_t g_ui32ImageAddress;
+#endif
+
+//*****************************************************************************
+//
+// This is the data buffer used during transfers to the boot loader.
+//
+//*****************************************************************************
+uint32_t g_pui32DataBuffer[BUFFER_SIZE];
+
+//*****************************************************************************
+//
+// This is an specially aligned buffer pointer to g_pui32DataBuffer to make
+// copying to the buffer simpler. It must be offset to end on an address that
+// ends with 3.
+//
+//*****************************************************************************
+uint8_t *g_pui8DataBuffer;
+
+//*****************************************************************************
+//
+// Converts a word from big endian to little endian. This macro uses compiler-
+// specific constructs to perform an inline insertion of the "rev" instruction,
+// which performs the byte swap directly.
+//
+//*****************************************************************************
+#if defined(ewarm)
+#include <intrinsics.h>
+#define SwapWord(x) __REV(x)
+#endif
+#if defined(codered) || defined(gcc) || defined(sourcerygxx)
+#define SwapWord(x) __extension__ \
+ ({ \
+ register uint32_t __ret, __inp = x; \
+ __asm__("rev %0, %1" : "=r" (__ret) : "r" (__inp)); \
+ __ret; \
+ })
+#endif
+#if defined(rvmdk) || defined(__ARMCC_VERSION)
+#define SwapWord(x) __rev(x)
+#endif
+#if defined(ccs)
+uint32_t
+SwapWord(uint32_t x)
+{
+ __asm(" rev r0, r0\n"
+ " bx lr\n"); // need this to make sure r0 is returned
+ return(x + 1); // return makes compiler happy - ignored
+}
+#endif
+
+//*****************************************************************************
+//
+//! Configures the microcontroller.
+//!
+//! This function configures the peripherals and GPIOs of the microcontroller,
+//! preparing it for use by the boot loader. The interface that has been
+//! selected as the update port will be configured, and auto-baud will be
+//! performed if required.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+ConfigureDevice(void)
+{
+#ifdef UART_ENABLE_UPDATE
+ uint32_t ui32ProcRatio;
+#endif
+
+#ifdef CRYSTAL_FREQ
+ //
+ // Since the crystal frequency was specified, enable the main oscillator
+ // and clock the processor from it.
+ //
+ HWREG(SYSCTL_RCC) &= ~(SYSCTL_RCC_MOSCDIS);
+ Delay(524288);
+ HWREG(SYSCTL_RCC) = ((HWREG(SYSCTL_RCC) & ~(SYSCTL_RCC_OSCSRC_M)) |
+ SYSCTL_RCC_OSCSRC_MAIN);
+#endif
+
+#ifdef I2C_ENABLE_UPDATE
+ //
+ // Enable the clocks to the I2C and GPIO modules.
+ //
+ HWREG(SYSCTL_RCGC2) |= SYSCTL_RCGC2_GPIOB;
+ HWREG(SYSCTL_RCGC1) |= SYSCTL_RCGC1_I2C0;
+
+ //
+ // Configure the GPIO pins for hardware control, open drain with pull-up,
+ // and enable them.
+ //
+ HWREG(GPIO_PORTB_BASE + GPIO_O_AFSEL) |= (1 << 7) | I2C_PINS;
+ HWREG(GPIO_PORTB_BASE + GPIO_O_DEN) |= (1 << 7) | I2C_PINS;
+ HWREG(GPIO_PORTB_BASE + GPIO_O_ODR) |= I2C_PINS;
+
+ //
+ // Enable the I2C Slave Mode.
+ //
+ HWREG(I2C0_BASE + I2C_O_MCR) = I2C_MCR_MFE | I2C_MCR_SFE;
+
+ //
+ // Setup the I2C Slave Address.
+ //
+ HWREG(I2C0_BASE + I2C_O_SOAR) = I2C_SLAVE_ADDR;
+
+ //
+ // Enable the I2C Slave Device on the I2C bus.
+ //
+ HWREG(I2C0_BASE + I2C_O_SCSR) = I2C_SCSR_DA;
+#endif
+
+#ifdef SSI_ENABLE_UPDATE
+ //
+ // Enable the clocks to the SSI and GPIO modules.
+ //
+ HWREG(SYSCTL_RCGC2) |= SYSCTL_RCGC2_GPIOA;
+ HWREG(SYSCTL_RCGC1) |= SYSCTL_RCGC1_SSI0;
+
+ //
+ // Make the pin be peripheral controlled.
+ //
+ HWREG(GPIO_PORTA_BASE + GPIO_O_AFSEL) |= SSI_PINS;
+ HWREG(GPIO_PORTA_BASE + GPIO_O_DEN) |= SSI_PINS;
+
+ //
+ // Set the SSI protocol to Motorola with default clock high and data
+ // valid on the rising edge.
+ //
+ HWREG(SSI0_BASE + SSI_O_CR0) = (SSI_CR0_SPH | SSI_CR0_SPO |
+ (DATA_BITS_SSI - 1));
+
+ //
+ // Enable the SSI interface in slave mode.
+ //
+ HWREG(SSI0_BASE + SSI_O_CR1) = SSI_CR1_MS | SSI_CR1_SSE;
+#endif
+
+#ifdef UART_ENABLE_UPDATE
+ //
+ // Enable the the clocks to the UART and GPIO modules.
+ //
+ HWREG(SYSCTL_RCGC2) |= SYSCTL_RCGC2_GPIOA;
+ HWREG(SYSCTL_RCGC1) |= SYSCTL_RCGC1_UART0;
+
+ //
+ // Keep attempting to sync until we are successful.
+ //
+#ifdef UART_AUTOBAUD
+ while(UARTAutoBaud(&ui32ProcRatio) < 0)
+ {
+ }
+#else
+ ui32ProcRatio = UART_BAUD_RATIO(UART_FIXED_BAUDRATE);
+#endif
+
+ //
+ // Set GPIO A0 and A1 as UART pins.
+ //
+ HWREG(GPIO_PORTA_BASE + GPIO_O_AFSEL) |= UART_PINS;
+
+ //
+ // Set the pin type.
+ //
+ HWREG(GPIO_PORTA_BASE + GPIO_O_DEN) |= UART_PINS;
+
+ //
+ // Set the baud rate.
+ //
+ HWREG(UART0_BASE + UART_O_IBRD) = ui32ProcRatio >> 6;
+ HWREG(UART0_BASE + UART_O_FBRD) = ui32ProcRatio & UART_FBRD_DIVFRAC_M;
+
+ //
+ // Set data length, parity, and number of stop bits to 8-N-1.
+ //
+ HWREG(UART0_BASE + UART_O_LCRH) = UART_LCRH_WLEN_8 | UART_LCRH_FEN;
+
+ //
+ // Enable RX, TX, and the UART.
+ //
+ HWREG(UART0_BASE + UART_O_CTL) = (UART_CTL_UARTEN | UART_CTL_TXE |
+ UART_CTL_RXE);
+
+#ifdef UART_AUTOBAUD
+ //
+ // Need to ack in the UART case to hold it up while we get things set up.
+ //
+ AckPacket();
+#endif
+#endif
+}
+
+//*****************************************************************************
+//
+//! This function performs the update on the selected port.
+//!
+//! This function is called directly by the boot loader or it is called as a
+//! result of an update request from the application.
+//!
+//! \return Never returns.
+//
+//*****************************************************************************
+void
+Updater(void)
+{
+ uint32_t ui32Size, ui32Temp, ui32FlashSize;
+#ifdef CHECK_CRC
+ uint32_t ui32Retcode;
+#endif
+
+ //
+ // This ensures proper alignment of the global buffer so that the one byte
+ // size parameter used by the packetized format is easily skipped for data
+ // transfers.
+ //
+ g_pui8DataBuffer = ((uint8_t *)g_pui32DataBuffer) + 3;
+
+ //
+ // Insure that the COMMAND_SEND_DATA cannot be sent to erase the boot
+ // loader before the application is erased.
+ //
+ g_ui32TransferAddress = 0xffffffff;
+
+ //
+ // Read any data from the serial port in use.
+ //
+ while(1)
+ {
+ //
+ // Receive a packet from the port in use.
+ //
+ ui32Size = sizeof(g_pui32DataBuffer) - 3;
+ if(ReceivePacket(g_pui8DataBuffer, &ui32Size) != 0)
+ {
+ continue;
+ }
+
+ //
+ // The first byte of the data buffer has the command and determines
+ // the format of the rest of the bytes.
+ //
+ switch(g_pui8DataBuffer[0])
+ {
+ //
+ // This was a simple ping command.
+ //
+ case COMMAND_PING:
+ {
+ //
+ // This command always sets the status to COMMAND_RET_SUCCESS.
+ //
+ g_ui8Status = COMMAND_RET_SUCCESS;
+
+ //
+ // Just acknowledge that the command was received.
+ //
+ AckPacket();
+
+ //
+ // Go back and wait for a new command.
+ //
+ break;
+ }
+
+ //
+ // This command indicates the start of a download sequence.
+ //
+ case COMMAND_DOWNLOAD:
+ {
+ //
+ // Until determined otherwise, the command status is success.
+ //
+ g_ui8Status = COMMAND_RET_SUCCESS;
+
+ //
+ // A simple do/while(0) control loop to make error exits
+ // easier.
+ //
+ do
+ {
+ //
+ // See if a full packet was received.
+ //
+ if(ui32Size != 9)
+ {
+ //
+ // Indicate that an invalid command was received.
+ //
+ g_ui8Status = COMMAND_RET_INVALID_CMD;
+
+ //
+ // This packet has been handled.
+ //
+ break;
+ }
+
+ //
+ // Get the address and size from the command.
+ //
+ g_ui32TransferAddress = SwapWord(g_pui32DataBuffer[1]);
+ g_ui32TransferSize = SwapWord(g_pui32DataBuffer[2]);
+
+ //
+ // Depending upon the build options set, keep a copy of
+ // the original size and start address because we will need
+ // these later.
+ //
+#if (defined BL_PROGRESS_FN_HOOK) || (defined CHECK_CRC)
+ g_ui32ImageSize = g_ui32TransferSize;
+#endif
+#ifdef CHECK_CRC
+ g_ui32ImageAddress = g_ui32TransferAddress;
+#endif
+
+ //
+ // Check for a valid starting address and image size.
+ //
+ if(!BL_FLASH_AD_CHECK_FN_HOOK(g_ui32TransferAddress,
+ g_ui32TransferSize))
+ {
+ //
+ // Set the code to an error to indicate that the last
+ // command failed. This informs the updater program
+ // that the download command failed.
+ //
+ g_ui8Status = COMMAND_RET_INVALID_ADR;
+
+ //
+ // This packet has been handled.
+ //
+ break;
+ }
+
+
+ //
+ // Only erase the space that we need if we are not
+ // protecting the code, otherwise erase the entire flash.
+ //
+#ifdef FLASH_CODE_PROTECTION
+ ui32FlashSize = BL_FLASH_SIZE_FN_HOOK();
+#ifdef FLASH_RSVD_SPACE
+ if((ui32FlashSize - FLASH_RSVD_SPACE) !=
+ g_ui32TransferAddress)
+ {
+ ui32FlashSize -= FLASH_RSVD_SPACE;
+ }
+#endif
+#else
+ ui32FlashSize = g_ui32TransferAddress + g_ui32TransferSize;
+#endif
+
+ //
+ // Clear the flash access interrupt.
+ //
+ BL_FLASH_CL_ERR_FN_HOOK();
+
+ //
+ // Leave the boot loader present until we start getting an
+ // image.
+ //
+ for(ui32Temp = g_ui32TransferAddress;
+ ui32Temp < ui32FlashSize; ui32Temp += FLASH_PAGE_SIZE)
+ {
+ //
+ // Erase this block.
+ //
+ BL_FLASH_ERASE_FN_HOOK(ui32Temp);
+ }
+
+ //
+ // Return an error if an access violation occurred.
+ //
+ if(BL_FLASH_ERROR_FN_HOOK())
+ {
+ g_ui8Status = COMMAND_RET_FLASH_FAIL;
+ }
+ }
+ while(0);
+
+ //
+ // See if the command was successful.
+ //
+ if(g_ui8Status != COMMAND_RET_SUCCESS)
+ {
+ //
+ // Setting g_ui32TransferSize to zero makes
+ // COMMAND_SEND_DATA fail to accept any data.
+ //
+ g_ui32TransferSize = 0;
+ }
+
+ //
+ // Acknowledge that this command was received correctly. This
+ // does not indicate success, just that the command was
+ // received.
+ //
+ AckPacket();
+
+ //
+ // If we have a start notification hook function, call it
+ // now if everything is OK.
+ //
+#ifdef BL_START_FN_HOOK
+ if(g_ui32TransferSize)
+ {
+ BL_START_FN_HOOK();
+ }
+#endif
+
+ //
+ // Go back and wait for a new command.
+ //
+ break;
+ }
+
+ //
+ // This command indicates that control should be transferred to
+ // the specified address.
+ //
+ case COMMAND_RUN:
+ {
+ //
+ // Acknowledge that this command was received correctly. This
+ // does not indicate success, just that the command was
+ // received.
+ //
+ AckPacket();
+
+ //
+ // See if a full packet was received.
+ //
+ if(ui32Size != 5)
+ {
+ //
+ // Indicate that an invalid command was received.
+ //
+ g_ui8Status = COMMAND_RET_INVALID_CMD;
+
+ //
+ // This packet has been handled.
+ //
+ break;
+ }
+
+ //
+ // Get the address to which control should be transferred.
+ //
+ g_ui32TransferAddress = SwapWord(g_pui32DataBuffer[1]);
+
+ //
+ // This determines the size of the flash available on the
+ // device in use.
+ //
+ ui32FlashSize = BL_FLASH_SIZE_FN_HOOK();
+
+ //
+ // Test if the transfer address is valid for this device.
+ //
+ if(g_ui32TransferAddress >= ui32FlashSize)
+ {
+ //
+ // Indicate that an invalid address was specified.
+ //
+ g_ui8Status = COMMAND_RET_INVALID_ADR;
+
+ //
+ // This packet has been handled.
+ //
+ break;
+ }
+
+ //
+ // Make sure that the ACK packet has been sent.
+ //
+ FlushData();
+
+ //
+ // Reset and disable the peripherals used by the boot loader.
+ //
+#ifdef I2C_ENABLE_UPDATE
+ HWREG(SYSCTL_RCGC1) &= ~SYSCTL_RCGC1_I2C0;
+ HWREG(SYSCTL_SRCR1) = SYSCTL_SRCR1_I2C0;
+#endif
+#ifdef UART_ENABLE_UPDATE
+ HWREG(SYSCTL_RCGC1) &= ~SYSCTL_RCGC1_UART0;
+ HWREG(SYSCTL_SRCR1) = SYSCTL_SRCR1_UART0;
+#endif
+#ifdef SSI_ENABLE_UPDATE
+ HWREG(SYSCTL_RCGC1) &= ~SYSCTL_RCGC1_SSI0;
+ HWREG(SYSCTL_SRCR1) = SYSCTL_SRCR1_SSI0;
+#endif
+ HWREG(SYSCTL_SRCR1) = 0;
+
+ //
+ // Branch to the specified address. This should never return.
+ // If it does, very bad things will likely happen since it is
+ // likely that the copy of the boot loader in SRAM will have
+ // been overwritten.
+ //
+ ((void (*)(void))g_ui32TransferAddress)();
+
+ //
+ // In case this ever does return and the boot loader is still
+ // intact, simply reset the device.
+ //
+ HWREG(NVIC_APINT) = (NVIC_APINT_VECTKEY |
+ NVIC_APINT_SYSRESETREQ);
+
+ //
+ // The microcontroller should have reset, so this should
+ // never be reached. Just in case, loop forever.
+ //
+ while(1)
+ {
+ }
+ }
+
+ //
+ // This command just returns the status of the last command that
+ // was sent.
+ //
+ case COMMAND_GET_STATUS:
+ {
+ //
+ // Acknowledge that this command was received correctly. This
+ // does not indicate success, just that the command was
+ // received.
+ //
+ AckPacket();
+
+ //
+ // Return the status to the updater.
+ //
+ SendPacket(&g_ui8Status, 1);
+
+ //
+ // Go back and wait for a new command.
+ //
+ break;
+ }
+
+ //
+ // This command is sent to transfer data to the device following
+ // a download command.
+ //
+ case COMMAND_SEND_DATA:
+ {
+ //
+ // Until determined otherwise, the command status is success.
+ //
+ g_ui8Status = COMMAND_RET_SUCCESS;
+
+ //
+ // If this is overwriting the boot loader then the application
+ // has already been erased so now erase the boot loader.
+ //
+ if(g_ui32TransferAddress == 0)
+ {
+ //
+ // Clear the flash access interrupt.
+ //
+ BL_FLASH_CL_ERR_FN_HOOK();
+
+ //
+ // Erase the boot loader.
+ //
+ for(ui32Temp = 0; ui32Temp < APP_START_ADDRESS;
+ ui32Temp += FLASH_PAGE_SIZE)
+ {
+ //
+ // Erase this block.
+ //
+ BL_FLASH_ERASE_FN_HOOK(ui32Temp);
+ }
+
+ //
+ // Return an error if an access violation occurred.
+ //
+ if(BL_FLASH_ERROR_FN_HOOK())
+ {
+ //
+ // Setting g_ui32TransferSize to zero makes
+ // COMMAND_SEND_DATA fail to accept any more data.
+ //
+ g_ui32TransferSize = 0;
+
+ //
+ // Indicate that the flash erase failed.
+ //
+ g_ui8Status = COMMAND_RET_FLASH_FAIL;
+ }
+ }
+
+ //
+ // Take one byte off for the command.
+ //
+ ui32Size = ui32Size - 1;
+
+ //
+ // Check if there are any more bytes to receive.
+ //
+ if(g_ui32TransferSize >= ui32Size)
+ {
+ //
+ // If we have been provided with a decryption hook function
+ // call it here.
+ //
+#ifdef BL_DECRYPT_FN_HOOK
+ BL_DECRYPT_FN_HOOK(g_pui8DataBuffer + 1, ui32Size);
+#endif
+
+ //
+ // Write this block of data to the flash
+ //
+ BL_FLASH_PROGRAM_FN_HOOK(g_ui32TransferAddress,
+ (uint8_t *) &g_pui32DataBuffer[1],
+ ((ui32Size + 3) & ~3));
+
+ //
+ // Return an error if an access violation occurred.
+ //
+ if(BL_FLASH_ERROR_FN_HOOK())
+ {
+ //
+ // Indicate that the flash programming failed.
+ //
+ g_ui8Status = COMMAND_RET_FLASH_FAIL;
+ }
+ else
+ {
+ //
+ // Now update the address to program.
+ //
+ g_ui32TransferSize -= ui32Size;
+ g_ui32TransferAddress += ui32Size;
+
+ //
+ // If a progress hook function has been provided, call
+ // it here.
+ //
+#ifdef BL_PROGRESS_FN_HOOK
+ BL_PROGRESS_FN_HOOK(g_ui32ImageSize -
+ g_ui32TransferSize,
+ g_ui32ImageSize);
+#endif
+
+#ifdef CHECK_CRC
+ //
+ // If we've reached the end, check the CRC in the
+ // image to determine whether or not we report an error
+ // back to the host.
+ //
+ if(g_ui32TransferSize == 0)
+ {
+ InitCRC32Table();
+ ui32Retcode = CheckImageCRC32(
+ (uint32_t *)g_ui32ImageAddress);
+
+ //
+ // Was the CRC good? We consider the CRC good if
+ // the header is found and the embedded CRC matches
+ // the calculated value or, if ENFORCE_CRC is not
+ // defined, if the header exists but is unpopulated.
+ //
+#ifdef ENFORCE_CRC
+ if(ui32Retcode == CHECK_CRC_OK)
+#else
+ if((ui32Retcode == CHECK_CRC_OK) ||
+ (ui32Retcode == CHECK_CRC_NO_LENGTH))
+#endif
+ {
+ //
+ // The calculated CRC didn't match the expected
+ // value or the image didn't contain an embedded
+ // CRC.
+ //
+ g_ui8Status = COMMAND_RET_SUCCESS;
+ }
+ else
+ {
+ //
+ // The calculated CRC agreed with the embedded
+ // value.
+ //
+ g_ui8Status = COMMAND_RET_CRC_FAIL;
+ }
+ }
+#endif
+ }
+ }
+ else
+ {
+ //
+ // This indicates that too much data is being sent to the
+ // device.
+ //
+ g_ui8Status = COMMAND_RET_INVALID_ADR;
+ }
+
+ //
+ // Acknowledge that this command was received correctly. This
+ // does not indicate success, just that the command was
+ // received.
+ //
+ AckPacket();
+
+ //
+ // If we have an end notification hook function, and we've
+ // reached the end, call it now.
+ //
+#ifdef BL_END_FN_HOOK
+ if(g_ui32TransferSize == 0)
+ {
+ BL_END_FN_HOOK();
+ }
+#endif
+
+ //
+ // Go back and wait for a new command.
+ //
+ break;
+ }
+
+ //
+ // This command is used to reset the device.
+ //
+ case COMMAND_RESET:
+ {
+ //
+ // Send out a one-byte ACK to ensure the byte goes back to the
+ // host before we reset everything.
+ //
+ AckPacket();
+
+ //
+ // Make sure that the ACK packet has been sent.
+ //
+ FlushData();
+
+ //
+ // Perform a software reset request. This will cause the
+ // microcontroller to reset; no further code will be executed.
+ //
+ HWREG(NVIC_APINT) = (NVIC_APINT_VECTKEY |
+ NVIC_APINT_SYSRESETREQ);
+
+ //
+ // The microcontroller should have reset, so this should never
+ // be reached. Just in case, loop forever.
+ //
+ while(1)
+ {
+ }
+ }
+
+ //
+ // Just acknowledge the command and set the error to indicate that
+ // a bad command was sent.
+ //
+ default:
+ {
+ //
+ // Acknowledge that this command was received correctly. This
+ // does not indicate success, just that the command was
+ // received.
+ //
+ AckPacket();
+
+ //
+ // Indicate that a bad comand was sent.
+ //
+ g_ui8Status = COMMAND_RET_UNKNOWN_CMD;
+
+ //
+ // Go back and wait for a new command.
+ //
+ break;
+ }
+ }
+ }
+}
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
+#endif
diff --git a/boot_loader/bl_packet.c b/boot_loader/bl_packet.c
new file mode 100644
index 0000000..f54495c
--- /dev/null
+++ b/boot_loader/bl_packet.c
@@ -0,0 +1,295 @@
+//*****************************************************************************
+//
+// bl_packet.c - Packet handler functions used by the boot loader.
+//
+// Copyright (c) 2006-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
+//
+//*****************************************************************************
+
+#include <stdint.h>
+#include "bl_config.h"
+#include "boot_loader/bl_commands.h"
+#include "boot_loader/bl_i2c.h"
+#include "boot_loader/bl_packet.h"
+#include "boot_loader/bl_ssi.h"
+#include "boot_loader/bl_uart.h"
+
+//*****************************************************************************
+//
+//! \addtogroup bl_packet_api
+//! @{
+//
+//*****************************************************************************
+#if defined(I2C_ENABLE_UPDATE) || defined(SSI_ENABLE_UPDATE) || \
+ defined(UART_ENABLE_UPDATE) || defined(DOXYGEN)
+
+//*****************************************************************************
+//
+// The packet that is sent to acknowledge a received packet.
+//
+//*****************************************************************************
+static const uint8_t g_pui8ACK[2] = { 0, COMMAND_ACK };
+
+//*****************************************************************************
+//
+// The packet that is sent to not-acknowledge a received packet.
+//
+//*****************************************************************************
+static const uint8_t g_pui8NAK[2] = { 0, COMMAND_NAK };
+
+//*****************************************************************************
+//
+//! Calculates an 8-bit checksum
+//!
+//! \param pui8Data is a pointer to an array of 8-bit data of size ui32Size.
+//! \param ui32Size is the size of the array that will run through the checksum
+//! algorithm.
+//!
+//! This function simply calculates an 8-bit checksum on the data passed in.
+//!
+//! \return Returns the calculated checksum.
+//
+//*****************************************************************************
+uint32_t
+CheckSum(const uint8_t *pui8Data, uint32_t ui32Size)
+{
+ uint32_t ui32CheckSum;
+
+ //
+ // Initialize the checksum to zero.
+ //
+ ui32CheckSum = 0;
+
+ //
+ // Add up all the bytes, do not do anything for an overflow.
+ //
+ while(ui32Size--)
+ {
+ ui32CheckSum += *pui8Data++;
+ }
+
+ //
+ // Return the caculated check sum.
+ //
+ return(ui32CheckSum & 0xff);
+}
+
+//*****************************************************************************
+//
+//! Sends an Acknowledge packet.
+//!
+//! This function is called to acknowledge that a packet has been received by
+//! the microcontroller.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+AckPacket(void)
+{
+ //
+ // ACK/NAK packets are the only ones with no size.
+ //
+ SendData(g_pui8ACK, 2);
+}
+
+//*****************************************************************************
+//
+//! Sends a no-acknowledge packet.
+//!
+//! This function is called when an invalid packet has been received by the
+//! microcontroller, indicating that it should be retransmitted.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+NakPacket(void)
+{
+ //
+ // ACK/NAK packets are the only ones with no size.
+ //
+ SendData(g_pui8NAK, 2);
+}
+
+//*****************************************************************************
+//
+//! Receives a data packet.
+//!
+//! \param pui8Data is the location to store the data that is sent to the boot
+//! loader.
+//! \param pui32Size is the number of bytes returned in the pui8Data buffer
+//! that was provided.
+//!
+//! This function receives a packet of data from specified transfer function.
+//!
+//! \return Returns zero to indicate success while any non-zero value indicates
+//! a failure.
+//
+//*****************************************************************************
+int
+ReceivePacket(uint8_t *pui8Data, uint32_t *pui32Size)
+{
+ uint32_t ui32Size, ui32CheckSum;
+
+ //
+ // Wait for non-zero data before getting the first byte that holds the
+ // size of the packet we are receiving.
+ //
+ ui32Size = 0;
+ while(ui32Size == 0)
+ {
+ ReceiveData((uint8_t *)&ui32Size, 1);
+ }
+
+ //
+ // Subtract off the size and checksum bytes.
+ //
+ ui32Size -= 2;
+
+ //
+ // Receive the checksum followed by the actual data.
+ //
+ ReceiveData((uint8_t *)&ui32CheckSum, 1);
+
+ //
+ // If there is room in the buffer then receive the requested data.
+ //
+ if(*pui32Size >= ui32Size)
+ {
+ //
+ // Receive the actual data in the packet.
+ //
+ ReceiveData(pui8Data, ui32Size);
+
+ //
+ // Send a no acknowledge if the checksum does not match, otherwise send
+ // an acknowledge to the packet later.
+ //
+ if(CheckSum(pui8Data, ui32Size) != (ui32CheckSum & 0xff))
+ {
+ //
+ // Indicate tha the packet was not received correctly.
+ //
+ NakPacket();
+
+ //
+ // Packet was not received, there is no valid data in the buffer.
+ //
+ return(-1);
+ }
+ }
+ else
+ {
+ //
+ // If the caller allocated a buffer that was too small for the received
+ // data packet, receive it but don't fill the buffer.
+ // Then inform the caller that the packet was not received correctly.
+ //
+ while(ui32Size--)
+ {
+ ReceiveData(pui8Data, 1);
+ }
+
+ //
+ // Packet was not received, there is no valid data in the buffer.
+ //
+ return(-1);
+ }
+
+ //
+ // Make sure to return the number of bytes received.
+ //
+ *pui32Size = ui32Size;
+
+ //
+ // Packet was received successfully.
+ //
+ return(0);
+}
+
+//*****************************************************************************
+//
+//! Sends a data packet.
+//!
+//! \param pui8Data is the location of the data to be sent.
+//! \param ui32Size is the number of bytes to send.
+//!
+//! This function sends the data provided in the \e pui8Data parameter in the
+//! packet format used by the boot loader. The caller only needs to specify
+//! the buffer with the data that needs to be transferred. This function
+//! addresses all other packet formatting issues.
+//!
+//! \return Returns zero to indicate success while any non-zero value indicates
+//! a failure.
+//
+//*****************************************************************************
+int
+SendPacket(uint8_t *pui8Data, uint32_t ui32Size)
+{
+ uint32_t ui32Temp;
+
+ //
+ // Caculate the checksum to be sent out with the data.
+ //
+ ui32Temp = CheckSum(pui8Data, ui32Size);
+
+ //
+ // Need to include the size and checksum bytes in the packet.
+ //
+ ui32Size += 2;
+
+ //
+ // Send out the size followed by the data.
+ //
+ SendData((uint8_t *)&ui32Size, 1);
+ SendData((uint8_t *)&ui32Temp, 1);
+ SendData(pui8Data, ui32Size - 2);
+
+ //
+ // Wait for a non zero byte.
+ //
+ ui32Temp = 0;
+ while(ui32Temp == 0)
+ {
+ ReceiveData((uint8_t *)&ui32Temp, 1);
+ }
+
+ //
+ // Check if the byte was a valid ACK and return a negative value if it was
+ // not and aknowledge.
+ //
+ if(ui32Temp != COMMAND_ACK)
+ {
+ return(-1);
+ }
+
+ //
+ // This packet was sent and received successfully.
+ //
+ return(0);
+}
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
+#endif
diff --git a/boot_loader/bl_packet.h b/boot_loader/bl_packet.h
new file mode 100644
index 0000000..3c4f78d
--- /dev/null
+++ b/boot_loader/bl_packet.h
@@ -0,0 +1,37 @@
+//*****************************************************************************
+//
+// bl_packet.h - The global variables and definitions of the boot loader.
+//
+// Copyright (c) 2006-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
+//
+//*****************************************************************************
+
+#ifndef __BL_PACKET_H__
+#define __BL_PACKET_H__
+
+//*****************************************************************************
+//
+// Packet Handling APIs
+//
+//*****************************************************************************
+extern int ReceivePacket(uint8_t *pui8Data, uint32_t *pui32Size);
+extern int SendPacket(uint8_t *pui8Data, uint32_t ui32Size);
+extern void AckPacket(void);
+
+#endif // __BL_PACKET_H__
diff --git a/boot_loader/bl_ssi.c b/boot_loader/bl_ssi.c
new file mode 100644
index 0000000..ca10517
--- /dev/null
+++ b/boot_loader/bl_ssi.c
@@ -0,0 +1,161 @@
+//*****************************************************************************
+//
+// bl_ssi.c - Functions used to transfer data via the SSI port.
+//
+// Copyright (c) 2006-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
+//
+//*****************************************************************************
+
+#include <stdint.h>
+#include "inc/hw_gpio.h"
+#include "inc/hw_memmap.h"
+#include "inc/hw_ssi.h"
+#include "inc/hw_sysctl.h"
+#include "inc/hw_types.h"
+#include "bl_config.h"
+#include "boot_loader/bl_ssi.h"
+
+//*****************************************************************************
+//
+//! \addtogroup bl_ssi_api
+//! @{
+//
+//*****************************************************************************
+#if defined(SSI_ENABLE_UPDATE) || defined(DOXYGEN)
+
+//*****************************************************************************
+//
+//! Sends data via the SSI port in slave mode.
+//!
+//! \param pui8Data is the location of the data to send through the SSI port.
+//! \param ui32Size is the number of bytes of data to send.
+//!
+//! This function sends data through the SSI port in slave mode. This function
+//! will not return until all bytes are sent.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SSISend(const uint8_t *pui8Data, uint32_t ui32Size)
+{
+ //
+ // Send the requested number of bytes over the SSI port.
+ //
+ while(ui32Size--)
+ {
+ //
+ // Wait until there is space in the SSI FIFO.
+ //
+ while(!(HWREG(SSI0_BASE + SSI_O_SR) & SSI_SR_TNF))
+ {
+ }
+
+ //
+ // Write the next byte to the SSI port.
+ //
+ HWREG(SSI0_BASE + SSI_O_DR) = *pui8Data++;
+ }
+
+ //
+ // Empty the receive FIFO.
+ //
+ while(HWREG(SSI0_BASE + SSI_O_SR) & SSI_SR_RNE)
+ {
+ HWREG(SSI0_BASE + SSI_O_DR);
+ }
+}
+
+//*****************************************************************************
+//
+//! Waits until all data has been transmitted by the SSI port.
+//!
+//! This function waits until all data written to the SSI port has been read by
+//! the master.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SSIFlush(void)
+{
+ //
+ // Wait until the transmit FIFO is empty.
+ //
+ while(!(HWREG(SSI0_BASE + SSI_O_SR) & SSI_SR_TFE))
+ {
+ }
+
+ //
+ // Wait until the interface is not busy.
+ //
+ while(HWREG(SSI0_BASE + SSI_O_SR) & SSI_SR_BSY)
+ {
+ }
+}
+
+//*****************************************************************************
+//
+//! Receives data from the SSI port in slave mode.
+//!
+//! \param pui8Data is the location to store the data received from the SSI
+//! port.
+//! \param ui32Size is the number of bytes of data to receive.
+//!
+//! This function receives data from the SSI port in slave mode. The function
+//! will not return until \e ui32Size number of bytes have been received.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SSIReceive(uint8_t *pui8Data, uint32_t ui32Size)
+{
+ //
+ // Ensure that we are sending out zeros so that we don't confuse the host.
+ //
+ HWREG(SSI0_BASE + SSI_O_DR) = 0;
+
+ //
+ // Wait for the requested number of bytes.
+ //
+ while(ui32Size--)
+ {
+ //
+ // Wait until there is data in the FIFO.
+ //
+ while(!(HWREG(SSI0_BASE + SSI_O_SR) & SSI_SR_RNE))
+ {
+ }
+
+ //
+ // Read the next byte from the FIFO.
+ //
+ *pui8Data++ = HWREG(SSI0_BASE + SSI_O_DR);
+ HWREG(SSI0_BASE + SSI_O_DR) = 0;
+ }
+}
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
+#endif
diff --git a/boot_loader/bl_ssi.h b/boot_loader/bl_ssi.h
new file mode 100644
index 0000000..05ec3bb
--- /dev/null
+++ b/boot_loader/bl_ssi.h
@@ -0,0 +1,92 @@
+//*****************************************************************************
+//
+// bl_ssi.h - Definitions for the SSI transport functions.
+//
+// Copyright (c) 2006-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
+//
+//*****************************************************************************
+
+#ifndef __BL_SSI_H__
+#define __BL_SSI_H__
+
+//*****************************************************************************
+//
+// This is the number of bits per transfer for SSI. This is a constant and
+// cannot be changed without corresponding code changes.
+//
+//*****************************************************************************
+#define DATA_BITS_SSI 8
+
+//*****************************************************************************
+//
+// This defines the SSI chip select pin that is being used by the boot loader.
+//
+//*****************************************************************************
+#define SSI_CS (1 << 3)
+
+//*****************************************************************************
+//
+// This defines the SSI clock pin that is being used by the boot loader.
+//
+//*****************************************************************************
+#define SSI_CLK (1 << 2)
+
+//*****************************************************************************
+//
+// This defines the SSI transmit pin that is being used by the boot loader.
+//
+//*****************************************************************************
+#define SSI_TX (1 << 5)
+
+//*****************************************************************************
+//
+// This defines the SSI receive pin that is being used by the boot loader.
+//
+//*****************************************************************************
+#define SSI_RX (1 << 4)
+
+//*****************************************************************************
+//
+// This defines the combination of pins used to implement the SSI port used by
+// the boot loader.
+//
+//*****************************************************************************
+#define SSI_PINS (SSI_CLK | SSI_TX | SSI_RX | SSI_CS)
+
+//*****************************************************************************
+//
+// SSI Transport APIs
+//
+//*****************************************************************************
+extern void SSISend(const uint8_t *pui8Data, uint32_t ui32Size);
+extern void SSIReceive(uint8_t *pui8Data, uint32_t ui32Size);
+extern void SSIFlush(void);
+
+//*****************************************************************************
+//
+// Define the transport functions if the SSI port is being used.
+//
+//*****************************************************************************
+#ifdef SSI_ENABLE_UPDATE
+#define SendData SSISend
+#define FlushData SSIFlush
+#define ReceiveData SSIReceive
+#endif
+
+#endif // __BL_SSI_H__
diff --git a/boot_loader/bl_startup_ccs.s b/boot_loader/bl_startup_ccs.s
new file mode 100644
index 0000000..8bfa96b
--- /dev/null
+++ b/boot_loader/bl_startup_ccs.s
@@ -0,0 +1,645 @@
+;;*****************************************************************************
+;;
+;; bl_startup_ccs.s - Boot loader startup code for Code Composer Studio
+;;
+;; Copyright (c) 2009-2014 Texas Instruments Incorporated. All rights reserved.
+;; Software License Agreement
+;;
+;; Texas Instruments (TI) is supplying this software for use solely and
+;; exclusively on TI's microcontroller products. The software is owned by
+;; TI and/or its suppliers, and is protected under applicable copyright
+;; laws. You may not combine this software with "viral" open-source
+;; software in order to form a larger program.
+;;
+;; THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+;; NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+;; NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+;; A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+;; CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+;; DAMAGES, FOR ANY REASON WHATSOEVER.
+;;
+;; This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
+;;
+;;*****************************************************************************
+
+;;*****************************************************************************
+;;
+;; Include the boot loader configuration options.
+;;
+;;*****************************************************************************
+ .cdecls C, NOLIST, WARN
+ %{
+ #include "inc/hw_nvic.h"
+ #include "inc/hw_sysctl.h"
+ #include "bl_config.h"
+ %}
+
+;;*****************************************************************************
+;;
+;; Export symbols from this file that are used elsewhere
+;;
+;;*****************************************************************************
+ .global ResetISR, Delay, Vectors
+
+;;*****************************************************************************
+;;
+;; Create the stack and put it in a section
+;;
+;;*****************************************************************************
+ .global __stack
+__stack:.usect ".stack", STACK_SIZE * 4, 8
+
+;;*****************************************************************************
+;;
+;; Put the assembler into the correct configuration.
+;;
+;;*****************************************************************************
+ .thumb
+
+;;*****************************************************************************
+;;
+;; This portion of the file goes into interrupt vectors section
+;;
+;;*****************************************************************************
+ .sect ".intvecs"
+
+;;*****************************************************************************
+;;
+;; The minimal vector table for a Cortex-M3 processor.
+;;
+;;*****************************************************************************
+Vectors:
+ .ref __STACK_TOP
+ .word __STACK_TOP ;; Offset 00: Initial stack pointer
+ .word ResetISR - 0x20000000 ;; Offset 04: Reset handler
+ .word NmiSR - 0x20000000 ;; Offset 08: NMI handler
+ .word FaultISR - 0x20000000 ;; Offset 0C: Hard fault handler
+ .word IntDefaultHandler ;; Offset 10: MPU fault handler
+ .word IntDefaultHandler ;; Offset 14: Bus fault handler
+ .word IntDefaultHandler ;; Offset 18: Usage fault handler
+ .word 0 ;; Offset 1C: Reserved
+ .word 0 ;; Offset 20: Reserved
+ .word 0 ;; Offset 24: Reserved
+ .word 0 ;; Offset 28: Reserved
+ .word UpdateHandler - 0x20000000 ;; Offset 2C: SVCall handler
+ .word IntDefaultHandler ;; Offset 30: Debug monitor handler
+ .word 0 ;; Offset 34: Reserved
+ .word IntDefaultHandler ;; Offset 38: PendSV handler
+ .if $$defined(ENET_ENABLE_UPDATE)
+ .ref SysTickIntHandler
+ .word SysTickIntHandler ;; Offset 3C: SysTick handler
+ .else
+ .word IntDefaultHandler ;; Offset 3C: SysTick handler
+ .endif
+ .if $$defined(UART_ENABLE_UPDATE) & $$defined(UART_AUTOBAUD)
+ .ref GPIOIntHandler
+ .word GPIOIntHandler ;; Offset 40: GPIO port A handler
+ .else
+ .word IntDefaultHandler ;; Offset 40: GPIO port A handler
+ .endif
+ .if ($$defined(USB_ENABLE_UPDATE) | (APP_START_ADDRESS != VTABLE_START_ADDRESS))
+ .word IntDefaultHandler ;; Offset 44: GPIO Port B
+ .word IntDefaultHandler ;; Offset 48: GPIO Port C
+ .word IntDefaultHandler ;; Offset 4C: GPIO Port D
+ .word IntDefaultHandler ;; Offset 50: GPIO Port E
+ .word IntDefaultHandler ;; Offset 54: UART0 Rx and Tx
+ .word IntDefaultHandler ;; Offset 58: UART1 Rx and Tx
+ .word IntDefaultHandler ;; Offset 5C: SSI0 Rx and Tx
+ .word IntDefaultHandler ;; Offset 60: I2C0 Master and Slave
+ .word IntDefaultHandler ;; Offset 64: PWM Fault
+ .word IntDefaultHandler ;; Offset 68: PWM Generator 0
+ .word IntDefaultHandler ;; Offset 6C: PWM Generator 1
+ .word IntDefaultHandler ;; Offset 70: PWM Generator 2
+ .word IntDefaultHandler ;; Offset 74: Quadrature Encoder 0
+ .word IntDefaultHandler ;; Offset 78: ADC Sequence 0
+ .word IntDefaultHandler ;; Offset 7C: ADC Sequence 1
+ .word IntDefaultHandler ;; Offset 80: ADC Sequence 2
+ .word IntDefaultHandler ;; Offset 84: ADC Sequence 3
+ .word IntDefaultHandler ;; Offset 88: Watchdog timer
+ .word IntDefaultHandler ;; Offset 8C: Timer 0 subtimer A
+ .word IntDefaultHandler ;; Offset 90: Timer 0 subtimer B
+ .word IntDefaultHandler ;; Offset 94: Timer 1 subtimer A
+ .word IntDefaultHandler ;; Offset 98: Timer 1 subtimer B
+ .word IntDefaultHandler ;; Offset 9C: Timer 2 subtimer A
+ .word IntDefaultHandler ;; Offset A0: Timer 2 subtimer B
+ .word IntDefaultHandler ;; Offset A4: Analog Comparator 0
+ .word IntDefaultHandler ;; Offset A8: Analog Comparator 1
+ .word IntDefaultHandler ;; Offset AC: Analog Comparator 2
+ .word IntDefaultHandler ;; Offset B0: System Control
+ .word IntDefaultHandler ;; Offset B4: FLASH Control
+ .endif
+ .if ($$defined(USB_ENABLE_UPDATE) | (APP_START_ADDRESS != VTABLE_START_ADDRESS))
+ .word IntDefaultHandler ;; Offset B8: GPIO Port F
+ .word IntDefaultHandler ;; Offset BC: GPIO Port G
+ .word IntDefaultHandler ;; Offset C0: GPIO Port H
+ .word IntDefaultHandler ;; Offset C4: UART2 Rx and Tx
+ .word IntDefaultHandler ;; Offset C8: SSI1 Rx and Tx
+ .word IntDefaultHandler ;; Offset CC: Timer 3 subtimer A
+ .word IntDefaultHandler ;; Offset D0: Timer 3 subtimer B
+ .word IntDefaultHandler ;; Offset D4: I2C1 Master and Slave
+ .word IntDefaultHandler ;; Offset D8: Quadrature Encoder 1
+ .word IntDefaultHandler ;; Offset DC: CAN0
+ .word IntDefaultHandler ;; Offset E0: CAN1
+ .word IntDefaultHandler ;; Offset E4: CAN2
+ .word IntDefaultHandler ;; Offset E8: Ethernet
+ .word IntDefaultHandler ;; Offset EC: Hibernation module
+ .if $$defined(USB_ENABLE_UPDATE)
+ .ref USB0DeviceIntHandler
+ .word USB0DeviceIntHandler ;; Offset F0: USB 0 Controller
+ .else
+ .word IntDefaultHandler ;; Offset F0: USB 0 Controller
+ .endif
+ .endif
+
+;;*****************************************************************************
+;;
+;; This portion of the file goes into the text section.
+;;
+;;*****************************************************************************
+ .text
+
+;;*****************************************************************************
+;;
+;; Initialize the processor by copying the boot loader from flash to SRAM, zero
+;; filling the .bss section, and moving the vector table to the beginning of
+;; SRAM. The return address is modified to point to the SRAM copy of the boot
+;; loader instead of the flash copy, resulting in a branch to the copy now in
+;; SRAM.
+;;
+;;*****************************************************************************
+ .ref bss_run
+bss_start .word bss_run
+ .ref __STACK_TOP
+bss_end .word __STACK_TOP
+
+ .thumbfunc ProcessorInit
+ProcessorInit: .asmfunc
+ ;;
+ ;; Copy the code image from flash to SRAM.
+ ;;
+ movs r0, #0x0000
+ movs r1, #0x0000
+ movt r1, #0x2000
+ ldr r2, bss_start
+copy_loop:
+ ldr r3, [r0], #4
+ str r3, [r1], #4
+ cmp r1, r2
+ blt copy_loop
+
+ ;;
+ ;; Zero fill the .bss section.
+ ;;
+ movs r0, #0x0000
+ ldr r2, bss_end
+zero_loop:
+ str r0, [r1], #4
+ cmp r1, r2
+ blt zero_loop
+
+ ;;
+ ;; Set the vector table pointer to the beginning of SRAM.
+ ;;
+ movw r0, #(NVIC_VTABLE & 0xffff)
+ movt r0, #(NVIC_VTABLE >> 16)
+ movs r1, #0x0000
+ movt r1, #0x2000
+ str r1, [r0]
+
+ ;;
+ ;; Set the return address to the code just copied into SRAM.
+ ;;
+ orr lr, lr, #0x20000000
+
+ ;;
+ ;; Return to the caller.
+ ;;
+ bx lr
+ .endasmfunc
+
+;;*****************************************************************************
+;;
+;; The reset handler, which gets called when the processor starts.
+;;
+;;*****************************************************************************
+ .thumbfunc ResetISR
+ResetISR: .asmfunc
+ ;;
+ ;; Enable the floating-point unit. This must be done here in case any
+ ;; later C functions use floating point. Note that some toolchains will
+ ;; use the FPU registers for general workspace even if no explicit floating
+ ;; point data types are in use.
+ ;;
+ movw r0, #0xED88
+ movt r0, #0xE000
+ ldr r1, [r0]
+ orr r1, r1, #0x00F00000
+ str r1, [r0]
+
+ ;;
+ ;; Initialize the processor.
+ ;;
+ bl ProcessorInit
+
+ ;;
+ ;; Call the user-supplied low level hardware initialization function
+ ;; if provided.
+ ;;
+ .if $$defined(BL_HW_INIT_FN_HOOK)
+ .ref BL_HW_INIT_FN_HOOK
+ bl BL_HW_INIT_FN_HOOK
+ .endif
+
+ ;;
+ ;; See if an update should be performed.
+ ;;
+ .ref CheckForceUpdate
+ bl CheckForceUpdate
+ cbz r0, CallApplication
+
+ ;;
+ ;; Configure the microcontroller.
+ ;;
+ .thumbfunc EnterBootLoader
+EnterBootLoader:
+ .if $$defined(ENET_ENABLE_UPDATE)
+ .ref ConfigureEnet
+ bl ConfigureEnet
+ .elseif $$defined(CAN_ENABLE_UPDATE)
+ .ref ConfigureCAN
+ bl ConfigureCAN
+ .elseif $$defined(USB_ENABLE_UPDATE)
+ .ref ConfigureUSB
+ bl ConfigureUSB
+ .else
+ .ref ConfigureDevice
+ bl ConfigureDevice
+ .endif
+
+ ;;
+ ;; Call the user-supplied initialization function if provided.
+ ;;
+ .if $$defined(BL_INIT_FN_HOOK)
+ .ref BL_INIT_FN_HOOK
+ bl BL_INIT_FN_HOOK
+ .endif
+
+ ;;
+ ;; Branch to the update handler.
+ ;;
+ .if $$defined(ENET_ENABLE_UPDATE)
+ .ref UpdateBOOTP
+ b UpdateBOOTP
+ .elseif $$defined(CAN_ENABLE_UPDATE)
+ .ref UpdaterCAN
+ b UpdaterCAN
+ .elseif $$defined(USB_ENABLE_UPDATE)
+ .ref UpdaterUSB
+ b UpdaterUSB
+ .else
+ .ref Updater
+ b Updater
+ .endif
+ .endasmfunc
+
+ ;;
+ ;; This is a second symbol to allow starting the application from the boot
+ ;; loader the linker may not like the perceived jump.
+ ;;
+ .global StartApplication
+ .thumbfunc StartApplication
+StartApplication:
+ ;;
+ ;; Call the application via the reset handler in its vector table. Load
+ ;; the address of the application vector table.
+ ;;
+ .thumbfunc CallApplication
+CallApplication: .asmfunc
+ ;;
+ ;; Copy the application's vector table to the target address if necessary.
+ ;; Note that incorrect boot loader configuration could cause this to
+ ;; corrupt the code! Setting VTABLE_START_ADDRESS to 0x20000000 (the start
+ ;; of SRAM) is safe since this will use the same memory that the boot loader
+ ;; already uses for its vector table. Great care will have to be taken if
+ ;; other addresses are to be used.
+ ;;
+ .if (APP_START_ADDRESS != VTABLE_START_ADDRESS)
+ movw r0, #(VTABLE_START_ADDRESS & 0xffff)
+ .if (VTABLE_START_ADDRESS > 0xffff)
+ movt r0, #(VTABLE_START_ADDRESS >> 16)
+ .endif
+ movw r1, #(APP_START_ADDRESS & 0xffff)
+ .if (APP_START_ADDRESS > 0xffff)
+ movt r1, #(APP_START_ADDRESS >> 16)
+ .endif
+
+ ;;
+ ;; Calculate the end address of the vector table assuming that it has the
+ ;; maximum possible number of vectors. We don't know how many the app has
+ ;; populated so this is the safest approach though it may copy some non
+ ;; vector data if the app table is smaller than the maximum.
+ ;;
+ movw r2, #(70 * 4)
+ adds r2, r2, r0
+VectorCopyLoop:
+ ldr r3, [r1], #4
+ str r3, [r0], #4
+ cmp r0, r2
+ blt VectorCopyLoop
+ .endif
+
+ ;;
+ ;; Set the application's vector table start address. Typically this is the
+ ;; application start address but in some cases an application may relocate
+ ;; this so we can't assume that these two addresses are equal.
+ ;;
+ movw r0, #(VTABLE_START_ADDRESS & 0xffff)
+ .if (VTABLE_START_ADDRESS > 0xffff)
+ movt r0, #(VTABLE_START_ADDRESS >> 16)
+ .endif
+ movw r1, #(NVIC_VTABLE & 0xffff)
+ movt r1, #(NVIC_VTABLE >> 16)
+ str r0, [r1]
+
+ ;;
+ ;; Load the stack pointer from the application's vector table.
+ ;;
+ .if (APP_START_ADDRESS != VTABLE_START_ADDRESS)
+ movw r0, #(APP_START_ADDRESS & 0xffff)
+ .if (APP_START_ADDRESS > 0xffff)
+ movt r0, #(APP_START_ADDRESS >> 16)
+ .endif
+ .endif
+ ldr sp, [r0]
+
+ ;;
+ ;; Load the initial PC from the application's vector table and branch to
+ ;; the application's entry point.
+ ;;
+ ldr r0, [r0, #4]
+ bx r0
+ .endasmfunc
+
+;;*****************************************************************************
+;;
+;; The update handler, which gets called when the application would like to
+;; start an update.
+;;
+;;*****************************************************************************
+ .thumbfunc UpdateHandler
+UpdateHandler: .asmfunc
+ ;;
+ ;; Initialize the processor.
+ ;;
+ bl ProcessorInit
+
+ ;;
+ ;; Load the stack pointer from the vector table.
+ ;;
+ movs r0, #0x0000
+ ldr sp, [r0]
+
+ ;;
+ ;; Call the user-supplied low level hardware initialization function
+ ;; if provided.
+ ;;
+ .if $$defined(BL_HW_INIT_FN_HOOK)
+ bl BL_HW_INIT_FN_HOOK
+ .endif
+
+ ;;
+ ;; Call the user-supplied re-initialization function if provided.
+ ;;
+ .if $$defined(BL_REINIT_FN_HOOK)
+ .ref BL_REINIT_FN_HOOK
+ bl BL_REINIT_FN_HOOK
+ .endif
+
+ ;;
+ ;; Branch to the update handler.
+ ;;
+ .if $$defined(ENET_ENABLE_UPDATE)
+ b UpdateBOOTP
+ .elseif $$defined(CAN_ENABLE_UPDATE)
+ .ref AppUpdaterCAN
+ b AppUpdaterCAN
+ .elseif $$defined(USB_ENABLE_UPDATE)
+ .ref AppUpdaterUSB
+ b AppUpdaterUSB
+ .else
+ b Updater
+ .endif
+ .endasmfunc
+
+;;*****************************************************************************
+;;
+;; The NMI handler.
+;;
+;;*****************************************************************************
+ .thumbfunc NmiSR
+NmiSR: .asmfunc
+ .if $$defined(ENABLE_MOSCFAIL_HANDLER)
+ ;;
+ ;; Grab the fault frame from the stack (the stack will be cleared by the
+ ;; processor initialization that follows).
+ ;;
+ ldm sp, {r4-r11}
+ mov r12, lr
+
+ ;;
+ ;; Initialize the processor.
+ ;;
+ bl ProcessorInit
+
+ ;;
+ ;; Restore the stack frame.
+ ;;
+ mov lr, r12
+ stm sp, {r4-r11}
+
+ ;;
+ ;; Save the link register.
+ ;;
+ mov r9, lr
+
+ ;;
+ ;; Call the user-supplied low level hardware initialization function
+ ;; if provided.
+ ;;
+ .if $$defined(BL_HW_INIT_FN_HOOK)
+ bl BL_HW_INIT_FN_HOOK
+ .endif
+
+ ;;
+ ;; See if an update should be performed.
+ ;;
+ bl CheckForceUpdate
+ cbz r0, EnterApplication
+
+ ;;
+ ;; Clear the MOSCFAIL bit in RESC.
+ ;;
+ movw r0, #(SYSCTL_RESC & 0xffff)
+ movt r0, #(SYSCTL_RESC >> 16)
+ ldr r1, [r0]
+ bic r1, r1, #SYSCTL_RESC_MOSCFAIL
+ str r1, [r0]
+
+ ;;
+ ;; Fix up the PC on the stack so that the boot pin check is bypassed
+ ;; (since it has already been performed).
+ ;;
+ ldr r0, =EnterBootLoader
+ bic r0, #0x00000001
+ str r0, [sp, #0x18]
+
+ ;;
+ ;; Return from the NMI handler. This will then start execution of the
+ ;; boot loader.
+ ;;
+ bx r9
+
+ ;;
+ ;; Restore the link register.
+ ;;
+EnterApplication:
+ mov lr, r9
+
+ ;;
+ ;; Copy the application's vector table to the target address if necessary.
+ ;; Note that incorrect boot loader configuration could cause this to
+ ;; corrupt the code! Setting VTABLE_START_ADDRESS to 0x20000000 (the start
+ ;; of SRAM) is safe since this will use the same memory that the boot loader
+ ;; already uses for its vector table. Great care will have to be taken if
+ ;; other addresses are to be used.
+ ;;
+ .if (APP_START_ADDRESS != VTABLE_START_ADDRESS)
+ movw r0, #(VTABLE_START_ADDRESS & 0xffff)
+ .if (VTABLE_START_ADDRESS > 0xffff)
+ movt r0, #(VTABLE_START_ADDRESS >> 16)
+ .endif
+ movw r1, #(APP_START_ADDRESS & 0xffff)
+ .if (APP_START_ADDRESS > 0xffff)
+ movt r1, #(APP_START_ADDRESS >> 16)
+ .endif
+
+ ;;
+ ;; Calculate the end address of the vector table assuming that it has the
+ ;; maximum possible number of vectors. We don't know how many the app has
+ ;; populated so this is the safest approach though it may copy some non
+ ;; vector data if the app table is smaller than the maximum.
+ ;;
+ movw r2, #(70 * 4)
+ adds r2, r2, r0
+VectorCopyLoop2:
+ ldr r3, [r1], #4
+ str r3, [r0], #4
+ cmp r0, r2
+ blt VectorCopyLoop2
+ .endif
+
+ ;;
+ ;; Set the application's vector table start address. Typically this is the
+ ;; application start address but in some cases an application may relocate
+ ;; this so we can't assume that these two addresses are equal.
+ ;;
+ movw r0, #(VTABLE_START_ADDRESS & 0xffff)
+ .if (VTABLE_START_ADDRESS > 0xffff)
+ movt r0, #(VTABLE_START_ADDRESS >> 16)
+ .endif
+ movw r1, #(NVIC_VTABLE & 0xffff)
+ movt r1, #(NVIC_VTABLE >> 16)
+ str r0, [r1]
+
+ ;;
+ ;; Remove the NMI stack frame from the boot loader's stack.
+ ;;
+ ldmia sp, {r4-r11}
+
+ ;;
+ ;; Get the application's stack pointer.
+ ;;
+ .if (APP_START_ADDRESS != VTABLE_START_ADDRESS)
+ movw r0, #(APP_START_ADDRESS & 0xffff)
+ .if (APP_START_ADDRESS > 0xffff)
+ movt r0, #(APP_START_ADDRESS >> 16)
+ .endif
+ .endif
+ ldr sp, [r0, #0x00]
+
+ ;;
+ ;; Fix up the NMI stack frame's return address to be the reset handler of
+ ;; the application.
+ ;;
+ ldr r10, [r0, #0x04]
+ bic r10, #0x00000001
+
+ ;;
+ ;; Store the NMI stack frame onto the application's stack.
+ ;;
+ stmdb sp!, {r4-r11}
+
+ ;;
+ ;; Branch to the application's NMI handler.
+ ;;
+ ldr r0, [r0, #0x08]
+ bx r0
+ .else
+ ;;
+ ;; Loop forever since there is nothing that we can do about a NMI.
+ ;;
+ b NmiSR
+ .endif
+ .endasmfunc
+
+;;*****************************************************************************
+;;
+;; The hard fault handler.
+;;
+;;*****************************************************************************
+ .thumbfunc FaultISR
+FaultISR: .asmfunc
+ ;;
+ ;; Loop forever since there is nothing that we can do about a hard fault.
+ ;;
+ b FaultISR
+ .endasmfunc
+
+;;*****************************************************************************
+;;
+;; The default interrupt handler.
+;;
+;;*****************************************************************************
+ .thumbfunc IntDefaultHandler
+IntDefaultHandler: .asmfunc
+ ;;
+ ;; Loop forever since there is nothing that we can do about an unexpected
+ ;; interrupt.
+ ;;
+ b IntDefaultHandler
+ .endasmfunc
+
+;;*****************************************************************************
+;;
+;; Provides a small delay. The loop below takes 3 cycles/loop.
+;;
+;;*****************************************************************************
+; .globl Delay
+ .thumbfunc Delay
+Delay: .asmfunc
+ subs r0, #1
+ bne Delay
+ bx lr
+ .endasmfunc
+
+ .thumbfunc _c_int00
+ .global _c_int00
+_c_int00: .asmfunc
+ b ResetISR
+
+;;*****************************************************************************
+;;
+;; This is the end of the file.
+;;
+;;*****************************************************************************
+ .end
diff --git a/boot_loader/bl_startup_ewarm.S b/boot_loader/bl_startup_ewarm.S
new file mode 100644
index 0000000..2100b96
--- /dev/null
+++ b/boot_loader/bl_startup_ewarm.S
@@ -0,0 +1,612 @@
+//*****************************************************************************
+//
+// bl_startup_ewarm.S - Startup code for EWARM.
+//
+// Copyright (c) 2007-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// Include the assember definitions used to make this code compiler
+// independent.
+//
+//*****************************************************************************
+#include "inc/hw_nvic.h"
+#include "inc/hw_sysctl.h"
+#include "bl_config.h"
+
+//*****************************************************************************
+//
+// The stack gets placed into the zero-init section.
+//
+//*****************************************************************************
+ rseg .bss:DATA(2)
+
+//*****************************************************************************
+//
+// Allocate storage for the stack.
+//
+//*****************************************************************************
+ export g_pulStack
+g_pulStack ds8 STACK_SIZE * 4
+
+//*****************************************************************************
+//
+// This portion of the file goes into the vector section.
+//
+//*****************************************************************************
+ rseg INTVEC:CONST(2)
+
+//*****************************************************************************
+//
+// The minimal vector table for a Cortex-M3 processor.
+//
+//*****************************************************************************
+ export __vector_table
+__vector_table
+ dcd g_pulStack + (STACK_SIZE * 4) // Offset 00: Initial stack pointer
+ dcd ResetISR - 0x20000000 // Offset 04: Reset handler
+ dcd NmiSR - 0x20000000 // Offset 08: NMI handler
+ dcd FaultISR - 0x20000000 // Offset 0C: Hard fault handler
+ dcd IntDefaultHandler // Offset 10: MPU fault handler
+ dcd IntDefaultHandler // Offset 14: Bus fault handler
+ dcd IntDefaultHandler // Offset 18: Usage fault handler
+ dcd 0 // Offset 1C: Reserved
+ dcd 0 // Offset 20: Reserved
+ dcd 0 // Offset 24: Reserved
+ dcd 0 // Offset 28: Reserved
+ dcd UpdateHandler - 0x20000000 // Offset 2C: SVCall handler
+ dcd IntDefaultHandler // Offset 30: Debug monitor handler
+ dcd 0 // Offset 34: Reserved
+ dcd IntDefaultHandler // Offset 38: PendSV handler
+#if defined(ENET_ENABLE_UPDATE)
+ import SysTickIntHandler
+ dcd SysTickIntHandler // Offset 3C: SysTick handler
+#else
+ dcd IntDefaultHandler // Offset 3C: SysTick handler
+#endif
+#if defined(UART_ENABLE_UPDATE) && defined(UART_AUTOBAUD)
+ import GPIOIntHandler
+ dcd GPIOIntHandler // Offset 40: GPIO port A handler
+#else
+ dcd IntDefaultHandler // Offset 40: GPIO port A handler
+#endif
+#if (defined(USB_ENABLE_UPDATE) || \
+ (APP_START_ADDRESS != VTABLE_START_ADDRESS))
+ dcd IntDefaultHandler // Offset 44: GPIO Port B
+ dcd IntDefaultHandler // Offset 48: GPIO Port C
+ dcd IntDefaultHandler // Offset 4C: GPIO Port D
+ dcd IntDefaultHandler // Offset 50: GPIO Port E
+ dcd IntDefaultHandler // Offset 54: UART0 Rx and Tx
+ dcd IntDefaultHandler // Offset 58: UART1 Rx and Tx
+ dcd IntDefaultHandler // Offset 5C: SSI0 Rx and Tx
+ dcd IntDefaultHandler // Offset 60: I2C0 Master and Slave
+ dcd IntDefaultHandler // Offset 64: PWM Fault
+ dcd IntDefaultHandler // Offset 68: PWM Generator 0
+ dcd IntDefaultHandler // Offset 6C: PWM Generator 1
+ dcd IntDefaultHandler // Offset 70: PWM Generator 2
+ dcd IntDefaultHandler // Offset 74: Quadrature Encoder 0
+ dcd IntDefaultHandler // Offset 78: ADC Sequence 0
+ dcd IntDefaultHandler // Offset 7C: ADC Sequence 1
+ dcd IntDefaultHandler // Offset 80: ADC Sequence 2
+ dcd IntDefaultHandler // Offset 84: ADC Sequence 3
+ dcd IntDefaultHandler // Offset 88: Watchdog timer
+ dcd IntDefaultHandler // Offset 8C: Timer 0 subtimer A
+ dcd IntDefaultHandler // Offset 90: Timer 0 subtimer B
+ dcd IntDefaultHandler // Offset 94: Timer 1 subtimer A
+ dcd IntDefaultHandler // Offset 98: Timer 1 subtimer B
+ dcd IntDefaultHandler // Offset 9C: Timer 2 subtimer A
+ dcd IntDefaultHandler // Offset A0: Timer 2 subtimer B
+ dcd IntDefaultHandler // Offset A4: Analog Comparator 0
+ dcd IntDefaultHandler // Offset A8: Analog Comparator 1
+ dcd IntDefaultHandler // Offset AC: Analog Comparator 2
+ dcd IntDefaultHandler // Offset B0: System Control
+ dcd IntDefaultHandler // Offset B4: FLASH Control
+#endif
+#if (defined(USB_ENABLE_UPDATE) || (APP_START_ADDRESS != VTABLE_START_ADDRESS))
+ dcd IntDefaultHandler // Offset B8: GPIO Port F
+ dcd IntDefaultHandler // Offset BC: GPIO Port G
+ dcd IntDefaultHandler // Offset C0: GPIO Port H
+ dcd IntDefaultHandler // Offset C4: UART2 Rx and Tx
+ dcd IntDefaultHandler // Offset C8: SSI1 Rx and Tx
+ dcd IntDefaultHandler // Offset CC: Timer 3 subtimer A
+ dcd IntDefaultHandler // Offset D0: Timer 3 subtimer B
+ dcd IntDefaultHandler // Offset D4: I2C1 Master and Slave
+ dcd IntDefaultHandler // Offset D8: Quadrature Encoder 1
+ dcd IntDefaultHandler // Offset DC: CAN0
+ dcd IntDefaultHandler // Offset E0: CAN1
+ dcd IntDefaultHandler // Offset E4: CAN2
+ dcd IntDefaultHandler // Offset E8: Ethernet
+ dcd IntDefaultHandler // Offset EC: Hibernation module
+#if defined(USB_ENABLE_UPDATE)
+ import USB0DeviceIntHandler
+ dcd USB0DeviceIntHandler // Offset F0: USB 0 Controller
+#else
+ dcd IntDefaultHandler // Offset F0: USB 0 Controller
+#endif
+#endif
+
+//*****************************************************************************
+//
+// This portion of the file goes into the text section.
+//
+//*****************************************************************************
+ rseg CODE:CODE(2)
+ thumb
+
+//*****************************************************************************
+//
+// Initialize the processor by copying the boot loader from flash to SRAM, zero
+// filling the .bss section, and moving the vector table to the beginning of
+// SRAM. The return address is modified to point to the SRAM copy of the boot
+// loader instead of the flash copy, resulting in a branch to the copy now in
+// SRAM.
+//
+//*****************************************************************************
+ProcessorInit
+ //
+ // Copy the code image from flash to SRAM.
+ //
+ movs r0, #0x0000
+ movs r1, #0x0000
+ movt r1, #0x2000
+ ldr r2, =SFB(.bss)
+copy_loop
+ ldr r3, [r0], #4
+ str r3, [r1], #4
+ cmp r1, r2
+ blt copy_loop
+
+ //
+ // Zero fill the .bss section.
+ //
+ movs r0, #0x0000
+ ldr r2, =SFE(.bss)
+zero_loop
+ str r0, [r1], #4
+ cmp r1, r2
+ blt zero_loop
+
+ //
+ // Set the vector table pointer to the beginning of SRAM.
+ //
+ movw r0, #(NVIC_VTABLE & 0xffff)
+ movt r0, #(NVIC_VTABLE >> 16)
+ movs r1, #0x0000
+ movt r1, #0x2000
+ str r1, [r0]
+
+ //
+ // Set the return address to the code just copied into SRAM.
+ //
+ orr lr, lr, #0x20000000
+
+ //
+ // Return to the caller.
+ //
+ bx lr
+
+//*****************************************************************************
+//
+// The reset handler, which gets called when the processor starts.
+//
+//*****************************************************************************
+ export ResetISR
+ResetISR
+ //
+ // Enable the floating-point unit. This must be done here in case any
+ // later C functions use floating point. Note that some toolchains will
+ // use the FPU registers for general workspace even if no explicit floating
+ // point data types are in use.
+ //
+ movw r0, #0xED88
+ movt r0, #0xE000
+ ldr r1, [r0]
+ orr r1, r1, #0x00F00000
+ str r1, [r0]
+
+ //
+ // Initialize the processor.
+ //
+ bl ProcessorInit
+
+ //
+ // Call the user-supplied low level hardware initialization function
+ // if provided.
+ //
+#ifdef BL_HW_INIT_FN_HOOK
+ import BL_HW_INIT_FN_HOOK
+ bl BL_HW_INIT_FN_HOOK
+#endif
+
+ //
+ // See if an update should be performed.
+ //
+ import CheckForceUpdate
+ bl CheckForceUpdate
+ cbz r0, CallApplication
+
+ //
+ // Configure the microcontroller.
+ //
+EnterBootLoader
+#ifdef ENET_ENABLE_UPDATE
+ import ConfigureEnet
+ bl ConfigureEnet
+#elif defined(CAN_ENABLE_UPDATE)
+ import ConfigureCAN
+ bl ConfigureCAN
+#elif defined(USB_ENABLE_UPDATE)
+ import ConfigureUSB
+ bl ConfigureUSB
+#else
+ import ConfigureDevice
+ bl ConfigureDevice
+#endif
+
+ //
+ // Call the user-supplied initialization function if provided.
+ //
+#ifdef BL_INIT_FN_HOOK
+ import BL_INIT_FN_HOOK
+ bl BL_INIT_FN_HOOK
+#endif
+
+ //
+ // Branch to the update handler.
+ //
+#ifdef ENET_ENABLE_UPDATE
+ import UpdateBOOTP
+ b UpdateBOOTP
+#elif defined(CAN_ENABLE_UPDATE)
+ import UpdaterCAN
+ b UpdaterCAN
+#elif defined(USB_ENABLE_UPDATE)
+ import UpdaterUSB
+ b UpdaterUSB
+#else
+ import Updater
+ b Updater
+#endif
+
+ //
+ // This is a second symbol to allow starting the application from the boot
+ // loader the linker may not like the perceived jump.
+ //
+ export StartApplication
+StartApplication
+ //
+ // Call the application via the reset handler in its vector table. Load
+ // the address of the application's vector table first.
+ //
+CallApplication
+ //
+ // Copy the application's vector table to the target address if necessary.
+ // Note that incorrect boot loader configuration could cause this to
+ // corrupt the code! Setting VTABLE_START_ADDRESS to 0x20000000 (the start
+ // of SRAM) is safe since this will use the same memory that the boot loader
+ // already uses for its vector table. Great care will have to be taken if
+ // other addresses are to be used.
+ //
+#if (APP_START_ADDRESS != VTABLE_START_ADDRESS)
+ movw r0, #(VTABLE_START_ADDRESS & 0xffff)
+#if (VTABLE_START_ADDRESS > 0xffff)
+ movt r0, #(VTABLE_START_ADDRESS >> 16)
+#endif
+ movw r1, #(APP_START_ADDRESS & 0xffff)
+#if (APP_START_ADDRESS > 0xffff)
+ movt r1, #(APP_START_ADDRESS >> 16)
+#endif
+
+ //
+ // Calculate the end address of the vector table assuming that it has the
+ // maximum possible number of vectors. We don't know how many the app has
+ // populated so this is the safest approach though it may copy some non
+ // vector data if the app table is smaller than the maximum.
+ //
+ movw r2, #(70 * 4)
+ adds r2, r2, r0
+VectorCopyLoop
+ ldr r3, [r1], #4
+ str r3, [r0], #4
+ cmp r0, r2
+ blt VectorCopyLoop
+#endif
+
+ //
+ // Set the application's vector table start address. Typically this is the
+ // application start address but in some cases an application may relocate
+ // this so we can't assume that these two addresses are equal.
+ //
+ movw r0, #(VTABLE_START_ADDRESS & 0xffff)
+#if (VTABLE_START_ADDRESS > 0xffff)
+ movt r0, #(VTABLE_START_ADDRESS >> 16)
+#endif
+ movw r1, #(NVIC_VTABLE & 0xffff)
+ movt r1, #(NVIC_VTABLE >> 16)
+ str r0, [r1]
+
+ //
+ // Load the stack pointer from the application's vector table at the
+ // beginning of the image.
+ //
+#if (APP_START_ADDRESS != VTABLE_START_ADDRESS)
+ movw r0, #(APP_START_ADDRESS & 0xffff)
+#if (APP_START_ADDRESS > 0xffff)
+ movt r0, #(APP_START_ADDRESS >> 16)
+#endif
+#endif
+ ldr sp, [r0]
+
+ //
+ // Load the initial PC from the application's vector table and branch to
+ // the application's entry point.
+ //
+ ldr r0, [r0, #4]
+ bx r0
+
+//*****************************************************************************
+//
+// The update handler, which gets called when the application would like to
+// start an update.
+//
+//*****************************************************************************
+UpdateHandler
+ //
+ // Initialize the processor.
+ //
+ bl ProcessorInit
+
+ //
+ // Load the stack pointer from the vector table.
+ //
+ movs r0, #0x0000
+ ldr sp, [r0]
+
+ //
+ // Call the user-supplied low level hardware initialization function
+ // if provided.
+ //
+#ifdef BL_HW_INIT_FN_HOOK
+ bl BL_HW_INIT_FN_HOOK
+#endif
+
+ //
+ // Call the user-supplied re-initialization function if provided.
+ //
+#ifdef BL_REINIT_FN_HOOK
+ import BL_REINIT_FN_HOOK
+ bl BL_REINIT_FN_HOOK
+#endif
+
+ //
+ // Branch to the update handler.
+ //
+#ifdef ENET_ENABLE_UPDATE
+ b UpdateBOOTP
+#elif defined(CAN_ENABLE_UPDATE)
+ import AppUpdaterCAN
+ b AppUpdaterCAN
+#elif defined(USB_ENABLE_UPDATE)
+ import AppUpdaterUSB
+ b AppUpdaterUSB
+#else
+ b Updater
+#endif
+
+//*****************************************************************************
+//
+// The NMI handler.
+//
+//*****************************************************************************
+NmiSR
+#ifdef ENABLE_MOSCFAIL_HANDLER
+ //
+ // Grab the fault frame from the stack (the stack will be cleared by the
+ // processor initialization that follows).
+ //
+ ldm sp, {r4-r11}
+ mov r12, lr
+
+ //
+ // Initialize the processor.
+ //
+ bl ProcessorInit
+
+ //
+ // Restore the stack frame.
+ //
+ mov lr, r12
+ stm sp, {r4-r11}
+
+ //
+ // Save the link register.
+ //
+ mov r9, lr
+
+ //
+ // Call the user-supplied low level hardware initialization function
+ // if provided.
+ //
+#ifdef BL_HW_INIT_FN_HOOK
+ bl BL_HW_INIT_FN_HOOK
+#endif
+
+ //
+ // See if an update should be performed.
+ //
+ bl CheckForceUpdate
+ cbz r0, EnterApplication
+
+ //
+ // Clear the MOSCFAIL bit in RESC.
+ //
+ movw r0, #(SYSCTL_RESC & 0xffff)
+ movt r0, #(SYSCTL_RESC >> 16)
+ ldr r1, [r0]
+ bic r1, r1, #SYSCTL_RESC_MOSCFAIL
+ str r1, [r0]
+
+ //
+ // Fix up the PC on the stack so that the boot pin check is bypassed
+ // (since it has already been performed).
+ //
+ ldr r0, =EnterBootLoader
+ bic r0, #0x00000001
+ str r0, [sp, #0x18]
+
+ //
+ // Return from the NMI handler. This will then start execution of the
+ // boot loader.
+ //
+ bx r9
+
+ //
+ // Restore the link register.
+ //
+EnterApplication:
+ mov lr, r9
+
+ //
+ // Copy the application's vector table to the target address if necessary.
+ // Note that incorrect boot loader configuration could cause this to
+ // corrupt the code! Setting VTABLE_START_ADDRESS to 0x20000000 (the start
+ // of SRAM) is safe since this will use the same memory that the boot loader
+ // already uses for its vector table. Great care will have to be taken if
+ // other addresses are to be used.
+ //
+#if (APP_START_ADDRESS != VTABLE_START_ADDRESS)
+ movw r0, #(VTABLE_START_ADDRESS & 0xffff)
+#if (VTABLE_START_ADDRESS > 0xffff)
+ movt r0, #(VTABLE_START_ADDRESS >> 16)
+#endif
+ movw r1, #(APP_START_ADDRESS & 0xffff)
+#if (APP_START_ADDRESS > 0xffff)
+ movt r1, #(APP_START_ADDRESS >> 16)
+#endif
+
+ //
+ // Calculate the end address of the vector table assuming that it has the
+ // maximum possible number of vectors. We don't know how many the app has
+ // populated so this is the safest approach though it may copy some non
+ // vector data if the app table is smaller than the maximum.
+ //
+ movw r2, #(70 * 4)
+ adds r2, r2, r0
+VectorCopyLoop2:
+ ldr r3, [r1], #4
+ str r3, [r0], #4
+ cmp r0, r2
+ blt VectorCopyLoop2
+#endif
+
+ //
+ // Set the application's vector table start address. Typically this is the
+ // application start address but in some cases an application may relocate
+ // this so we can't assume that these two addresses are equal.
+ //
+ movw r0, #(VTABLE_START_ADDRESS & 0xffff)
+#if (VTABLE_START_ADDRESS > 0xffff)
+ movt r0, #(VTABLE_START_ADDRESS >> 16)
+#endif
+ movw r1, #(NVIC_VTABLE & 0xffff)
+ movt r1, #(NVIC_VTABLE >> 16)
+ str r0, [r1]
+
+ //
+ // Remove the NMI stack frame from the boot loader's stack.
+ //
+ ldmia sp, {r4-r11}
+
+ //
+ // Get the application's stack pointer.
+ //
+#if (APP_START_ADDRESS != VTABLE_START_ADDRESS)
+ movw r0, #(APP_START_ADDRESS & 0xffff)
+#if (APP_START_ADDRESS > 0xffff)
+ movt r0, #(APP_START_ADDRESS >> 16)
+#endif
+#endif
+ ldr sp, [r0, #0x00]
+
+ //
+ // Fix up the NMI stack frame's return address to be the reset handler of
+ // the application.
+ //
+ ldr r10, [r0, #0x04]
+ bic r10, #0x00000001
+
+ //
+ // Store the NMI stack frame onto the application's stack.
+ //
+ stmdb sp!, {r4-r11}
+
+ //
+ // Branch to the application's NMI handler.
+ //
+ ldr r0, [r0, #0x08]
+ bx r0
+#else
+ //
+ // Loop forever since there is nothing that we can do about a NMI.
+ //
+ b .
+#endif
+
+//*****************************************************************************
+//
+// The hard fault handler.
+//
+//*****************************************************************************
+FaultISR
+ //
+ // Loop forever since there is nothing that we can do about a hard fault.
+ //
+ b .
+
+//*****************************************************************************
+//
+// The default interrupt handler.
+//
+//*****************************************************************************
+IntDefaultHandler
+ //
+ // Loop forever since there is nothing that we can do about an unexpected
+ // interrupt.
+ //
+ b .
+
+//*****************************************************************************
+//
+// Provides a small delay. The loop below takes 3 cycles/loop.
+//
+//*****************************************************************************
+ export Delay
+Delay
+ subs r0, #1
+ bne Delay
+ bx lr
+
+//*****************************************************************************
+//
+// This is the end of the file.
+//
+//*****************************************************************************
+ end
diff --git a/boot_loader/bl_startup_gcc.S b/boot_loader/bl_startup_gcc.S
new file mode 100644
index 0000000..53f28d1
--- /dev/null
+++ b/boot_loader/bl_startup_gcc.S
@@ -0,0 +1,630 @@
+//*****************************************************************************
+//
+// bl_startup_gcc.S - Startup code for GNU.
+//
+// Copyright (c) 2007-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// Include the assember definitions used to make this code compiler
+// independent.
+//
+//*****************************************************************************
+#include "inc/hw_nvic.h"
+#include "inc/hw_sysctl.h"
+#include "bl_config.h"
+
+//*****************************************************************************
+//
+// Put the assembler into the correct configuration.
+//
+//*****************************************************************************
+ .syntax unified
+ .thumb
+
+//*****************************************************************************
+//
+// The stack gets placed into the zero-init section.
+//
+//*****************************************************************************
+ .bss
+
+//*****************************************************************************
+//
+// Allocate storage for the stack.
+//
+//*****************************************************************************
+g_pulStack:
+ .space STACK_SIZE * 4
+
+//*****************************************************************************
+//
+// This portion of the file goes into the text section.
+//
+//*****************************************************************************
+ .section .isr_vector
+
+//*****************************************************************************
+//
+// The minimal vector table for a Cortex-M3 processor.
+//
+//*****************************************************************************
+Vectors:
+ .word g_pulStack + (STACK_SIZE * 4) // Offset 00: Initial stack pointer
+ .word ResetISR - 0x20000000 // Offset 04: Reset handler
+ .word NmiSR - 0x20000000 // Offset 08: NMI handler
+ .word FaultISR - 0x20000000 // Offset 0C: Hard fault handler
+ .word IntDefaultHandler // Offset 10: MPU fault handler
+ .word IntDefaultHandler // Offset 14: Bus fault handler
+ .word IntDefaultHandler // Offset 18: Usage fault handler
+ .word 0 // Offset 1C: Reserved
+ .word 0 // Offset 20: Reserved
+ .word 0 // Offset 24: Reserved
+ .word 0 // Offset 28: Reserved
+ .word UpdateHandler - 0x20000000 // Offset 2C: SVCall handler
+ .word IntDefaultHandler // Offset 30: Debug monitor handler
+ .word 0 // Offset 34: Reserved
+ .word IntDefaultHandler // Offset 38: PendSV handler
+#if defined(ENET_ENABLE_UPDATE)
+ .extern SysTickIntHandler
+ .word SysTickIntHandler // Offset 3C: SysTick handler
+#else
+ .word IntDefaultHandler // Offset 3C: SysTick handler
+#endif
+#if defined(UART_ENABLE_UPDATE) && defined(UART_AUTOBAUD)
+ .extern GPIOIntHandler
+ .word GPIOIntHandler // Offset 40: GPIO port A handler
+#else
+ .word IntDefaultHandler // Offset 40: GPIO port A handler
+#endif
+#if (defined(USB_ENABLE_UPDATE) || \
+ (APP_START_ADDRESS != VTABLE_START_ADDRESS))
+ .word IntDefaultHandler // Offset 44: GPIO Port B
+ .word IntDefaultHandler // Offset 48: GPIO Port C
+ .word IntDefaultHandler // Offset 4C: GPIO Port D
+ .word IntDefaultHandler // Offset 50: GPIO Port E
+ .word IntDefaultHandler // Offset 54: UART0 Rx and Tx
+ .word IntDefaultHandler // Offset 58: UART1 Rx and Tx
+ .word IntDefaultHandler // Offset 5C: SSI0 Rx and Tx
+ .word IntDefaultHandler // Offset 60: I2C0 Master and Slave
+ .word IntDefaultHandler // Offset 64: PWM Fault
+ .word IntDefaultHandler // Offset 68: PWM Generator 0
+ .word IntDefaultHandler // Offset 6C: PWM Generator 1
+ .word IntDefaultHandler // Offset 70: PWM Generator 2
+ .word IntDefaultHandler // Offset 74: Quadrature Encoder 0
+ .word IntDefaultHandler // Offset 78: ADC Sequence 0
+ .word IntDefaultHandler // Offset 7C: ADC Sequence 1
+ .word IntDefaultHandler // Offset 80: ADC Sequence 2
+ .word IntDefaultHandler // Offset 84: ADC Sequence 3
+ .word IntDefaultHandler // Offset 88: Watchdog timer
+ .word IntDefaultHandler // Offset 8C: Timer 0 subtimer A
+ .word IntDefaultHandler // Offset 90: Timer 0 subtimer B
+ .word IntDefaultHandler // Offset 94: Timer 1 subtimer A
+ .word IntDefaultHandler // Offset 98: Timer 1 subtimer B
+ .word IntDefaultHandler // Offset 9C: Timer 2 subtimer A
+ .word IntDefaultHandler // Offset A0: Timer 2 subtimer B
+ .word IntDefaultHandler // Offset A4: Analog Comparator 0
+ .word IntDefaultHandler // Offset A8: Analog Comparator 1
+ .word IntDefaultHandler // Offset AC: Analog Comparator 2
+ .word IntDefaultHandler // Offset B0: System Control
+ .word IntDefaultHandler // Offset B4: FLASH Control
+#endif
+#if (defined(USB_ENABLE_UPDATE) || (APP_START_ADDRESS != VTABLE_START_ADDRESS))
+ .word IntDefaultHandler // Offset B8: GPIO Port F
+ .word IntDefaultHandler // Offset BC: GPIO Port G
+ .word IntDefaultHandler // Offset C0: GPIO Port H
+ .word IntDefaultHandler // Offset C4: UART2 Rx and Tx
+ .word IntDefaultHandler // Offset C8: SSI1 Rx and Tx
+ .word IntDefaultHandler // Offset CC: Timer 3 subtimer A
+ .word IntDefaultHandler // Offset D0: Timer 3 subtimer B
+ .word IntDefaultHandler // Offset D4: I2C1 Master and Slave
+ .word IntDefaultHandler // Offset D8: Quadrature Encoder 1
+ .word IntDefaultHandler // Offset DC: CAN0
+ .word IntDefaultHandler // Offset E0: CAN1
+ .word IntDefaultHandler // Offset E4: CAN2
+ .word IntDefaultHandler // Offset E8: Ethernet
+ .word IntDefaultHandler // Offset EC: Hibernation module
+#if defined(USB_ENABLE_UPDATE)
+ .extern USB0DeviceIntHandler
+ .word USB0DeviceIntHandler // Offset F0: USB 0 Controller
+#else
+ .word IntDefaultHandler // Offset F0: USB 0 Controller
+#endif
+#endif
+
+//*****************************************************************************
+//
+// This portion of the file goes into the text section.
+//
+//*****************************************************************************
+ .text
+
+//*****************************************************************************
+//
+// Initialize the processor by copying the boot loader from flash to SRAM, zero
+// filling the .bss section, and moving the vector table to the beginning of
+// SRAM. The return address is modified to point to the SRAM copy of the boot
+// loader instead of the flash copy, resulting in a branch to the copy now in
+// SRAM.
+//
+//*****************************************************************************
+ .thumb_func
+ProcessorInit:
+ //
+ // Copy the code image from flash to SRAM.
+ //
+ movs r0, #0x0000
+ movs r1, #0x0000
+ movt r1, #0x2000
+ .extern _bss
+ ldr r2, =_bss
+copy_loop:
+ ldr r3, [r0], #4
+ str r3, [r1], #4
+ cmp r1, r2
+ blt copy_loop
+
+ //
+ // Zero fill the .bss section.
+ //
+ movs r0, #0x0000
+ .extern _ebss
+ ldr r2, =_ebss
+zero_loop:
+ str r0, [r1], #4
+ cmp r1, r2
+ blt zero_loop
+
+ //
+ // Set the vector table pointer to the beginning of SRAM.
+ //
+ movw r0, #(NVIC_VTABLE & 0xffff)
+ movt r0, #(NVIC_VTABLE >> 16)
+ movs r1, #0x0000
+ movt r1, #0x2000
+ str r1, [r0]
+
+ //
+ // Set the return address to the code just copied into SRAM.
+ //
+ orr lr, lr, #0x20000000
+
+ //
+ // Return to the caller.
+ //
+ bx lr
+
+//*****************************************************************************
+//
+// The reset handler, which gets called when the processor starts.
+//
+//*****************************************************************************
+ .globl ResetISR
+ .thumb_func
+ResetISR:
+ //
+ // Enable the floating-point unit. This must be done here in case any
+ // later C functions use floating point. Note that some toolchains will
+ // use the FPU registers for general workspace even if no explicit floating
+ // point data types are in use.
+ //
+ movw r0, #0xED88
+ movt r0, #0xE000
+ ldr r1, [r0]
+ orr r1, r1, #0x00F00000
+ str r1, [r0]
+
+ //
+ // Initialize the processor.
+ //
+ bl ProcessorInit
+
+ //
+ // Call the user-supplied low level hardware initialization function
+ // if provided.
+ //
+#ifdef BL_HW_INIT_FN_HOOK
+ .extern BL_HW_INIT_FN_HOOK
+ bl BL_HW_INIT_FN_HOOK
+#endif
+
+ //
+ // See if an update should be performed.
+ //
+ .extern CheckForceUpdate
+ bl CheckForceUpdate
+ cbz r0, CallApplication
+
+ //
+ // Configure the microcontroller.
+ //
+ .thumb_func
+EnterBootLoader:
+#ifdef ENET_ENABLE_UPDATE
+ .extern ConfigureEnet
+ bl ConfigureEnet
+#elif defined(CAN_ENABLE_UPDATE)
+ .extern ConfigureCAN
+ bl ConfigureCAN
+#elif defined(USB_ENABLE_UPDATE)
+ .extern ConfigureUSB
+ bl ConfigureUSB
+#else
+ .extern ConfigureDevice
+ bl ConfigureDevice
+#endif
+
+ //
+ // Call the user-supplied initialization function if provided.
+ //
+#ifdef BL_INIT_FN_HOOK
+ .extern BL_INIT_FN_HOOK
+ bl BL_INIT_FN_HOOK
+#endif
+
+ //
+ // Branch to the update handler.
+ //
+#ifdef ENET_ENABLE_UPDATE
+ .extern UpdateBOOTP
+ b UpdateBOOTP
+#elif defined(CAN_ENABLE_UPDATE)
+ .extern UpdaterCAN
+ b UpdaterCAN
+#elif defined(USB_ENABLE_UPDATE)
+ .extern UpdaterUSB
+ b UpdaterUSB
+#else
+ .extern Updater
+ b Updater
+#endif
+
+ //
+ // This is a second symbol to allow starting the application from the boot
+ // loader the linker may not like the perceived jump.
+ //
+ .globl StartApplication
+ .thumb_func
+StartApplication:
+ //
+ // Call the application via the reset handler in its vector table. Load
+ // the address of the application vector table.
+ //
+ .thumb_func
+CallApplication:
+ //
+ // Copy the application's vector table to the target address if necessary.
+ // Note that incorrect boot loader configuration could cause this to
+ // corrupt the code! Setting VTABLE_START_ADDRESS to 0x20000000 (the start
+ // of SRAM) is safe since this will use the same memory that the boot loader
+ // already uses for its vector table. Great care will have to be taken if
+ // other addresses are to be used.
+ //
+#if (APP_START_ADDRESS != VTABLE_START_ADDRESS)
+ movw r0, #(VTABLE_START_ADDRESS & 0xffff)
+#if (VTABLE_START_ADDRESS > 0xffff)
+ movt r0, #(VTABLE_START_ADDRESS >> 16)
+#endif
+ movw r1, #(APP_START_ADDRESS & 0xffff)
+#if (APP_START_ADDRESS > 0xffff)
+ movt r1, #(APP_START_ADDRESS >> 16)
+#endif
+
+ //
+ // Calculate the end address of the vector table assuming that it has the
+ // maximum possible number of vectors. We don't know how many the app has
+ // populated so this is the safest approach though it may copy some non
+ // vector data if the app table is smaller than the maximum.
+ //
+ movw r2, #(70 * 4)
+ adds r2, r2, r0
+VectorCopyLoop:
+ ldr r3, [r1], #4
+ str r3, [r0], #4
+ cmp r0, r2
+ blt VectorCopyLoop
+#endif
+
+ //
+ // Set the application's vector table start address. Typically this is the
+ // application start address but in some cases an application may relocate
+ // this so we can't assume that these two addresses are equal.
+ //
+ movw r0, #(VTABLE_START_ADDRESS & 0xffff)
+#if (VTABLE_START_ADDRESS > 0xffff)
+ movt r0, #(VTABLE_START_ADDRESS >> 16)
+#endif
+ movw r1, #(NVIC_VTABLE & 0xffff)
+ movt r1, #(NVIC_VTABLE >> 16)
+ str r0, [r1]
+
+ //
+ // Load the stack pointer from the application's vector table.
+ //
+#if (APP_START_ADDRESS != VTABLE_START_ADDRESS)
+ movw r0, #(APP_START_ADDRESS & 0xffff)
+#if (APP_START_ADDRESS > 0xffff)
+ movt r0, #(APP_START_ADDRESS >> 16)
+#endif
+#endif
+ ldr sp, [r0]
+
+ //
+ // Load the initial PC from the application's vector table and branch to
+ // the application's entry point.
+ //
+ ldr r0, [r0, #4]
+ bx r0
+
+//*****************************************************************************
+//
+// The update handler, which gets called when the application would like to
+// start an update.
+//
+//*****************************************************************************
+ .thumb_func
+UpdateHandler:
+ //
+ // Initialize the processor.
+ //
+ bl ProcessorInit
+
+ //
+ // Load the stack pointer from the vector table.
+ //
+ movs r0, #0x0000
+ ldr sp, [r0]
+
+ //
+ // Call the user-supplied low level hardware initialization function
+ // if provided.
+ //
+#ifdef BL_HW_INIT_FN_HOOK
+ bl BL_HW_INIT_FN_HOOK
+#endif
+
+ //
+ // Call the user-supplied re-initialization function if provided.
+ //
+#ifdef BL_REINIT_FN_HOOK
+ .extern BL_REINIT_FN_HOOK
+ bl BL_REINIT_FN_HOOK
+#endif
+
+ //
+ // Branch to the update handler.
+ //
+#ifdef ENET_ENABLE_UPDATE
+ b UpdateBOOTP
+#elif defined(CAN_ENABLE_UPDATE)
+ .extern AppUpdaterCAN
+ b AppUpdaterCAN
+#elif defined(USB_ENABLE_UPDATE)
+ .extern AppUpdaterUSB
+ b AppUpdaterUSB
+#else
+ b Updater
+#endif
+
+//*****************************************************************************
+//
+// The NMI handler.
+//
+//*****************************************************************************
+ .thumb_func
+NmiSR:
+#ifdef ENABLE_MOSCFAIL_HANDLER
+ //
+ // Grab the fault frame from the stack (the stack will be cleared by the
+ // processor initialization that follows).
+ //
+ ldm sp, {r4-r11}
+ mov r12, lr
+
+ //
+ // Initialize the processor.
+ //
+ bl ProcessorInit
+
+ //
+ // Restore the stack frame.
+ //
+ mov lr, r12
+ stm sp, {r4-r11}
+
+ //
+ // Save the link register.
+ //
+ mov r9, lr
+
+ //
+ // Call the user-supplied low level hardware initialization function
+ // if provided.
+ //
+#ifdef BL_HW_INIT_FN_HOOK
+ bl BL_HW_INIT_FN_HOOK
+#endif
+
+ //
+ // See if an update should be performed.
+ //
+ bl CheckForceUpdate
+ cbz r0, EnterApplication
+
+ //
+ // Clear the MOSCFAIL bit in RESC.
+ //
+ movw r0, #(SYSCTL_RESC & 0xffff)
+ movt r0, #(SYSCTL_RESC >> 16)
+ ldr r1, [r0]
+ bic r1, r1, #SYSCTL_RESC_MOSCFAIL
+ str r1, [r0]
+
+ //
+ // Fix up the PC on the stack so that the boot pin check is bypassed
+ // (since it has already been performed).
+ //
+ ldr r0, =EnterBootLoader
+ bic r0, #0x00000001
+ str r0, [sp, #0x18]
+
+ //
+ // Return from the NMI handler. This will then start execution of the
+ // boot loader.
+ //
+ bx r9
+
+ //
+ // Restore the link register.
+ //
+ .thumb_func
+EnterApplication:
+ mov lr, r9
+
+ //
+ // Copy the application's vector table to the target address if necessary.
+ // Note that incorrect boot loader configuration could cause this to
+ // corrupt the code! Setting VTABLE_START_ADDRESS to 0x20000000 (the start
+ // of SRAM) is safe since this will use the same memory that the boot loader
+ // already uses for its vector table. Great care will have to be taken if
+ // other addresses are to be used.
+ //
+#if (APP_START_ADDRESS != VTABLE_START_ADDRESS)
+ movw r0, #(VTABLE_START_ADDRESS & 0xffff)
+#if (VTABLE_START_ADDRESS > 0xffff)
+ movt r0, #(VTABLE_START_ADDRESS >> 16)
+#endif
+ movw r1, #(APP_START_ADDRESS & 0xffff)
+#if (APP_START_ADDRESS > 0xffff)
+ movt r1, #(APP_START_ADDRESS >> 16)
+#endif
+
+ //
+ // Calculate the end address of the vector table assuming that it has the
+ // maximum possible number of vectors. We don't know how many the app has
+ // populated so this is the safest approach though it may copy some non
+ // vector data if the app table is smaller than the maximum.
+ //
+ movw r2, #(70 * 4)
+ adds r2, r2, r0
+VectorCopyLoop2:
+ ldr r3, [r1], #4
+ str r3, [r0], #4
+ cmp r0, r2
+ blt VectorCopyLoop2
+#endif
+
+ //
+ // Set the application's vector table start address. Typically this is the
+ // application start address but in some cases an application may relocate
+ // this so we can't assume that these two addresses are equal.
+ //
+ movw r0, #(VTABLE_START_ADDRESS & 0xffff)
+#if (VTABLE_START_ADDRESS > 0xffff)
+ movt r0, #(VTABLE_START_ADDRESS >> 16)
+#endif
+ movw r1, #(NVIC_VTABLE & 0xffff)
+ movt r1, #(NVIC_VTABLE >> 16)
+ str r0, [r1]
+
+ //
+ // Remove the NMI stack frame from the boot loader's stack.
+ //
+ ldmia sp, {r4-r11}
+
+ //
+ // Get the application's stack pointer.
+ //
+#if (APP_START_ADDRESS != VTABLE_START_ADDRESS)
+ movw r0, #(APP_START_ADDRESS & 0xffff)
+#if (APP_START_ADDRESS > 0xffff)
+ movt r0, #(APP_START_ADDRESS >> 16)
+#endif
+#endif
+ ldr sp, [r0, #0x00]
+
+ //
+ // Fix up the NMI stack frame's return address to be the reset handler of
+ // the application.
+ //
+ ldr r10, [r0, #0x04]
+ bic r10, #0x00000001
+
+ //
+ // Store the NMI stack frame onto the application's stack.
+ //
+ stmdb sp!, {r4-r11}
+
+ //
+ // Branch to the application's NMI handler.
+ //
+ ldr r0, [r0, #0x08]
+ bx r0
+#else
+ //
+ // Loop forever since there is nothing that we can do about a NMI.
+ //
+ b .
+#endif
+
+//*****************************************************************************
+//
+// The hard fault handler.
+//
+//*****************************************************************************
+ .thumb_func
+FaultISR:
+ //
+ // Loop forever since there is nothing that we can do about a hard fault.
+ //
+ b .
+
+//*****************************************************************************
+//
+// The default interrupt handler.
+//
+//*****************************************************************************
+ .thumb_func
+IntDefaultHandler:
+ //
+ // Loop forever since there is nothing that we can do about an unexpected
+ // interrupt.
+ //
+ b .
+
+//*****************************************************************************
+//
+// Provides a small delay. The loop below takes 3 cycles/loop.
+//
+//*****************************************************************************
+ .globl Delay
+ .thumb_func
+Delay:
+ subs r0, #1
+ bne Delay
+ bx lr
+
+//*****************************************************************************
+//
+// This is the end of the file.
+//
+//*****************************************************************************
+ .end
diff --git a/boot_loader/bl_startup_rvmdk.S b/boot_loader/bl_startup_rvmdk.S
new file mode 100644
index 0000000..435c325
--- /dev/null
+++ b/boot_loader/bl_startup_rvmdk.S
@@ -0,0 +1,653 @@
+;******************************************************************************
+;
+; bl_startup_rvmdk.S - Startup code for RV-MDK.
+;
+; Copyright (c) 2007-2014 Texas Instruments Incorporated. All rights reserved.
+; Software License Agreement
+;
+; Texas Instruments (TI) is supplying this software for use solely and
+; exclusively on TI's microcontroller products. The software is owned by
+; TI and/or its suppliers, and is protected under applicable copyright
+; laws. You may not combine this software with "viral" open-source
+; software in order to form a larger program.
+;
+; THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+; NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+; NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+; A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+; CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+; DAMAGES, FOR ANY REASON WHATSOEVER.
+;
+; This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
+;
+;******************************************************************************
+
+ include bl_config.inc
+
+;******************************************************************************
+;
+; A couple of defines that would normally be obtained from the appropriate C
+; header file, but must be manually provided here since the Keil compiler does
+; not have a mechanism for passing assembly source through the C preprocessor.
+;
+;******************************************************************************
+SYSCTL_RESC equ 0x400fe05c
+SYSCTL_RESC_MOSCFAIL equ 0x00010000
+NVIC_VTABLE equ 0xe000ed08
+
+;******************************************************************************
+;
+; Put the assembler into the correct configuration.
+;
+;******************************************************************************
+ thumb
+ require8
+ preserve8
+
+;******************************************************************************
+;
+; The stack gets placed into the zero-init section.
+;
+;******************************************************************************
+ area ||.bss||, noinit, align=2
+
+;******************************************************************************
+;
+; Allocate storage for the stack.
+;
+;******************************************************************************
+g_pulStack
+ space _STACK_SIZE * 4
+
+;******************************************************************************
+;
+; This portion of the file goes into the reset section.
+;
+;******************************************************************************
+ area RESET, code, readonly, align=3
+
+;******************************************************************************
+;
+; The minimal vector table for a Cortex-M3 processor.
+;
+;******************************************************************************
+ export __Vectors
+__Vectors
+ dcd g_pulStack + (_STACK_SIZE * 4) ; Offset 00: Initial stack pointer
+ dcd Reset_Handler ; Offset 04: Reset handler
+ dcd NmiSR ; Offset 08: NMI handler
+ dcd FaultISR ; Offset 0C: Hard fault handler
+ dcd IntDefaultHandler ; Offset 10: MPU fault handler
+ dcd IntDefaultHandler ; Offset 14: Bus fault handler
+ dcd IntDefaultHandler ; Offset 18: Usage fault handler
+ dcd 0 ; Offset 1C: Reserved
+ dcd 0 ; Offset 20: Reserved
+ dcd 0 ; Offset 24: Reserved
+ dcd 0 ; Offset 28: Reserved
+ dcd UpdateHandler ; Offset 2C: SVCall handler
+ dcd IntDefaultHandler ; Offset 30: Debug monitor handler
+ dcd 0 ; Offset 34: Reserved
+ dcd IntDefaultHandler ; Offset 38: PendSV handler
+ if :def:_ENET_ENABLE_UPDATE
+ import SysTickIntHandler
+ dcd SysTickIntHandler ; Offset 3C: SysTick handler
+ else
+ dcd IntDefaultHandler ; Offset 3C: SysTick handler
+ endif
+ if :def:_UART_ENABLE_UPDATE :land: :def:_UART_AUTOBAUD
+ import GPIOIntHandler
+ dcd GPIOIntHandler ; Offset 40: GPIO port A handler
+ else
+ dcd IntDefaultHandler ; Offset 40: GPIO port A handler
+ endif
+ if :def:_USB_ENABLE_UPDATE :lor: \
+ (_APP_START_ADDRESS != _VTABLE_START_ADDRESS)
+ dcd IntDefaultHandler ; Offset 44: GPIO Port B
+ dcd IntDefaultHandler ; Offset 48: GPIO Port C
+ dcd IntDefaultHandler ; Offset 4C: GPIO Port D
+ dcd IntDefaultHandler ; Offset 50: GPIO Port E
+ dcd IntDefaultHandler ; Offset 54: UART0 Rx and Tx
+ dcd IntDefaultHandler ; Offset 58: UART1 Rx and Tx
+ dcd IntDefaultHandler ; Offset 5C: SSI0 Rx and Tx
+ dcd IntDefaultHandler ; Offset 60: I2C0 Master and Slave
+ dcd IntDefaultHandler ; Offset 64: PWM Fault
+ dcd IntDefaultHandler ; Offset 68: PWM Generator 0
+ dcd IntDefaultHandler ; Offset 6C: PWM Generator 1
+ dcd IntDefaultHandler ; Offset 70: PWM Generator 2
+ dcd IntDefaultHandler ; Offset 74: Quadrature Encoder 0
+ dcd IntDefaultHandler ; Offset 78: ADC Sequence 0
+ dcd IntDefaultHandler ; Offset 7C: ADC Sequence 1
+ dcd IntDefaultHandler ; Offset 80: ADC Sequence 2
+ dcd IntDefaultHandler ; Offset 84: ADC Sequence 3
+ dcd IntDefaultHandler ; Offset 88: Watchdog timer
+ dcd IntDefaultHandler ; Offset 8C: Timer 0 subtimer A
+ dcd IntDefaultHandler ; Offset 90: Timer 0 subtimer B
+ dcd IntDefaultHandler ; Offset 94: Timer 1 subtimer A
+ dcd IntDefaultHandler ; Offset 98: Timer 1 subtimer B
+ dcd IntDefaultHandler ; Offset 9C: Timer 2 subtimer A
+ dcd IntDefaultHandler ; Offset A0: Timer 2 subtimer B
+ dcd IntDefaultHandler ; Offset A4: Analog Comparator 0
+ dcd IntDefaultHandler ; Offset A8: Analog Comparator 1
+ dcd IntDefaultHandler ; Offset AC: Analog Comparator 2
+ dcd IntDefaultHandler ; Offset B0: System Control
+ dcd IntDefaultHandler ; Offset B4: FLASH Control
+ endif
+ if :def:_USB_ENABLE_UPDATE :lor: \
+ (_APP_START_ADDRESS != _VTABLE_START_ADDRESS)
+ dcd IntDefaultHandler ; Offset B8: GPIO Port F
+ dcd IntDefaultHandler ; Offset BC: GPIO Port G
+ dcd IntDefaultHandler ; Offset C0: GPIO Port H
+ dcd IntDefaultHandler ; Offset C4: UART2 Rx and Tx
+ dcd IntDefaultHandler ; Offset C8: SSI1 Rx and Tx
+ dcd IntDefaultHandler ; Offset CC: Timer 3 subtimer A
+ dcd IntDefaultHandler ; Offset D0: Timer 3 subtimer B
+ dcd IntDefaultHandler ; Offset D4: I2C1 Master and Slave
+ dcd IntDefaultHandler ; Offset D8: Quadrature Encoder 1
+ dcd IntDefaultHandler ; Offset DC: CAN0
+ dcd IntDefaultHandler ; Offset E0: CAN1
+ dcd IntDefaultHandler ; Offset E4: CAN2
+ dcd IntDefaultHandler ; Offset E8: Ethernet
+ dcd IntDefaultHandler ; Offset EC: Hibernation module
+ if :def: _USB_ENABLE_UPDATE
+ import USB0DeviceIntHandler
+ dcd USB0DeviceIntHandler ; Offset F0: USB 0 Controller
+ else
+ dcd IntDefaultHandler ; Offset F0: USB 0 Controller
+ endif
+ endif
+
+;******************************************************************************
+;
+; Initialize the processor by copying the boot loader from flash to SRAM, zero
+; filling the .bss section, and moving the vector table to the beginning of
+; SRAM. The return address is modified to point to the SRAM copy of the boot
+; loader instead of the flash copy, resulting in a branch to the copy now in
+; SRAM.
+;
+;******************************************************************************
+ export ProcessorInit
+ProcessorInit
+ ;
+ ; Copy the code image from flash to SRAM.
+ ;
+ movs r0, #0x0000
+ movs r1, #0x0000
+ movt r1, #0x2000
+ import ||Image$$SRAM$$ZI$$Base||
+ ldr r2, =||Image$$SRAM$$ZI$$Base||
+copy_loop
+ ldr r3, [r0], #4
+ str r3, [r1], #4
+ cmp r1, r2
+ blt copy_loop
+
+ ;
+ ; Zero fill the .bss section.
+ ;
+ movs r0, #0x0000
+ import ||Image$$SRAM$$ZI$$Limit||
+ ldr r2, =||Image$$SRAM$$ZI$$Limit||
+zero_loop
+ str r0, [r1], #4
+ cmp r1, r2
+ blt zero_loop
+
+ ;
+ ; Set the vector table pointer to the beginning of SRAM.
+ ;
+ movw r0, #(NVIC_VTABLE & 0xffff)
+ movt r0, #(NVIC_VTABLE >> 16)
+ movs r1, #0x0000
+ movt r1, #0x2000
+ str r1, [r0]
+
+ ;
+ ; Return to the caller.
+ ;
+ bx lr
+
+;******************************************************************************
+;
+; The reset handler, which gets called when the processor starts.
+;
+;******************************************************************************
+ export Reset_Handler
+Reset_Handler
+
+ ;
+ ; Enable the floating-point unit. This must be done here in case any
+ ; later C functions use floating point. Note that some toolchains will
+ ; use the FPU registers for general workspace even if no explicit floating
+ ; point data types are in use.
+ ;
+ movw r0, #0xED88
+ movt r0, #0xE000
+ ldr r1, [r0]
+ orr r1, #0x00F00000
+ str r1, [r0]
+
+ ;
+ ; Initialize the processor.
+ ;
+ bl ProcessorInit
+
+ ;
+ ; Branch to the SRAM copy of the reset handler.
+ ;
+ ldr pc, =Reset_Handler_In_SRAM
+
+;******************************************************************************
+;
+; The NMI handler.
+;
+;******************************************************************************
+NmiSR
+ if :def:_ENABLE_MOSCFAIL_HANDLER
+ ;
+ ; Grab the fault frame from the stack (the stack will be cleared by the
+ ; processor initialization that follows).
+ ;
+ ldm sp, {r4-r11}
+ mov r12, lr
+
+ ;
+ ; Initialize the processor.
+ ;
+ bl ProcessorInit
+
+ ;
+ ; Branch to the SRAM copy of the NMI handler.
+ ;
+ ldr pc, =NmiSR_In_SRAM
+ else
+ ;
+ ; Loop forever since there is nothing that we can do about a NMI.
+ ;
+ b .
+ endif
+
+;******************************************************************************
+;
+; The hard fault handler.
+;
+;******************************************************************************
+FaultISR
+ ;
+ ; Loop forever since there is nothing that we can do about a hard fault.
+ ;
+ b .
+
+;******************************************************************************
+;
+; The update handler, which gets called when the application would like to
+; start an update.
+;
+;******************************************************************************
+UpdateHandler
+ ;
+ ; Initialize the processor.
+ ;
+ bl ProcessorInit
+
+ ;
+ ; Branch to the SRAM copy of the update handler.
+ ;
+ ldr pc, =UpdateHandler_In_SRAM
+
+;******************************************************************************
+;
+; This portion of the file goes into the text section.
+;
+;******************************************************************************
+ align 4
+ area ||.text||, code, readonly, align=2
+
+Reset_Handler_In_SRAM
+ ;
+ ; Call the user-supplied low level hardware initialization function
+ ; if provided.
+ ;
+ if :def:_BL_HW_INIT_FN_HOOK
+ import $_BL_HW_INIT_FN_HOOK
+ bl $_BL_HW_INIT_FN_HOOK
+ endif
+
+ ;
+ ; See if an update should be performed.
+ ;
+ import CheckForceUpdate
+ bl CheckForceUpdate
+ cbz r0, CallApplication
+
+ ;
+ ; Configure the microcontroller.
+ ;
+EnterBootLoader
+ if :def:_ENET_ENABLE_UPDATE
+ import ConfigureEnet
+ bl ConfigureEnet
+ elif :def:_CAN_ENABLE_UPDATE
+ import ConfigureCAN
+ bl ConfigureCAN
+ elif :def:_USB_ENABLE_UPDATE
+ import ConfigureUSB
+ bl ConfigureUSB
+ else
+ import ConfigureDevice
+ bl ConfigureDevice
+ endif
+
+ ;
+ ; Call the user-supplied initialization function if provided.
+ ;
+ if :def:_BL_INIT_FN_HOOK
+ import $_BL_INIT_FN_HOOK
+ bl $_BL_INIT_FN_HOOK
+ endif
+
+ ;
+ ; Branch to the update handler.
+ ;
+ if :def:_ENET_ENABLE_UPDATE
+ import UpdateBOOTP
+ b UpdateBOOTP
+ elif :def:_CAN_ENABLE_UPDATE
+ import UpdaterCAN
+ b UpdaterCAN
+ elif :def:_USB_ENABLE_UPDATE
+ import UpdaterUSB
+ b UpdaterUSB
+ else
+ import Updater
+ b Updater
+ endif
+
+ ;
+ ; This is a second symbol to allow starting the application from the boot
+ ; loader the linker may not like the perceived jump.
+ ;
+ export StartApplication
+StartApplication
+ ;
+ ; Call the application via the reset handler in its vector table. Load the
+ ; address of the application vector table.
+ ;
+CallApplication
+ ;
+ ; Copy the application's vector table to the target address if necessary.
+ ; Note that incorrect boot loader configuration could cause this to
+ ; corrupt the code! Setting VTABLE_START_ADDRESS to 0x20000000 (the start
+ ; of SRAM) is safe since this will use the same memory that the boot loader
+ ; already uses for its vector table. Great care will have to be taken if
+ ; other addresses are to be used.
+ ;
+ if (_APP_START_ADDRESS != _VTABLE_START_ADDRESS)
+ movw r0, #(_VTABLE_START_ADDRESS & 0xffff)
+ if (_VTABLE_START_ADDRESS > 0xffff)
+ movt r0, #(_VTABLE_START_ADDRESS >> 16)
+ endif
+ movw r1, #(_APP_START_ADDRESS & 0xffff)
+ if (_APP_START_ADDRESS > 0xffff)
+ movt r1, #(_APP_START_ADDRESS >> 16)
+ endif
+
+ ;
+ ; Calculate the end address of the vector table assuming that it has the
+ ; maximum possible number of vectors. We don't know how many the app has
+ ; populated so this is the safest approach though it may copy some non
+ ; vector data if the app table is smaller than the maximum.
+ ;
+ movw r2, #(70 * 4)
+ adds r2, r2, r0
+VectorCopyLoop
+ ldr r3, [r1], #4
+ str r3, [r0], #4
+ cmp r0, r2
+ blt VectorCopyLoop
+ endif
+
+ ;
+ ; Set the vector table address to the beginning of the application.
+ ;
+ movw r0, #(_VTABLE_START_ADDRESS & 0xffff)
+ if (_VTABLE_START_ADDRESS > 0xffff)
+ movt r0, #(_VTABLE_START_ADDRESS >> 16)
+ endif
+ movw r1, #(NVIC_VTABLE & 0xffff)
+ movt r1, #(NVIC_VTABLE >> 16)
+ str r0, [r1]
+
+ ;
+ ; Load the stack pointer from the application's vector table.
+ ;
+ if (_APP_START_ADDRESS != _VTABLE_START_ADDRESS)
+ movw r0, #(_APP_START_ADDRESS & 0xffff)
+ if (_APP_START_ADDRESS > 0xffff)
+ movt r0, #(_APP_START_ADDRESS >> 16)
+ endif
+ endif
+ ldr sp, [r0]
+
+ ;
+ ; Load the initial PC from the application's vector table and branch to
+ ; the application's entry point.
+ ;
+ ldr r0, [r0, #4]
+ bx r0
+
+;******************************************************************************
+;
+; The update handler, which gets called when the application would like to
+; start an update.
+;
+;******************************************************************************
+UpdateHandler_In_SRAM
+ ;
+ ; Load the stack pointer from the vector table.
+ ;
+ movs r0, #0x0000
+ ldr sp, [r0]
+
+ ;
+ ; Call the user-supplied low level hardware initialization function
+ ; if provided.
+ ;
+ if :def:_BL_HW_INIT_FN_HOOK
+ bl $_BL_HW_INIT_FN_HOOK
+ endif
+
+ ;
+ ; Call the user-supplied re-initialization function if provided.
+ ;
+ if :def:_BL_REINIT_FN_HOOK
+ import $_BL_REINIT_FN_HOOK
+ bl $_BL_REINIT_FN_HOOK
+ endif
+
+ ;
+ ; Branch to the update handler.
+ ;
+ if :def:_ENET_ENABLE_UPDATE
+ b UpdateBOOTP
+ elif :def:_CAN_ENABLE_UPDATE
+ import AppUpdaterCAN
+ b AppUpdaterCAN
+ elif :def:_USB_ENABLE_UPDATE
+ import AppUpdaterUSB
+ b AppUpdaterUSB
+ else
+ b Updater
+ endif
+
+;******************************************************************************
+;
+; The NMI handler.
+;
+;******************************************************************************
+ if :def:_ENABLE_MOSCFAIL_HANDLER
+NmiSR_In_SRAM
+ ;
+ ; Restore the stack frame.
+ ;
+ mov lr, r12
+ stm sp, {r4-r11}
+
+ ;
+ ; Save the link register.
+ ;
+ mov r9, lr
+
+ ;
+ ; Call the user-supplied low level hardware initialization function
+ ; if provided.
+ ;
+ if :def:_BL_HW_INIT_FN_HOOK
+ bl _BL_HW_INIT_FN_HOOK
+ endif
+
+ ;
+ ; See if an update should be performed.
+ ;
+ bl CheckForceUpdate
+ cbz r0, EnterApplication
+
+ ;
+ ; Clear the MOSCFAIL bit in RESC.
+ ;
+ movw r0, #(SYSCTL_RESC & 0xffff)
+ movt r0, #(SYSCTL_RESC >> 16)
+ ldr r1, [r0]
+ bic r1, r1, #SYSCTL_RESC_MOSCFAIL
+ str r1, [r0]
+
+ ;
+ ; Fix up the PC on the stack so that the boot pin check is bypassed
+ ; (since it has already been performed).
+ ;
+ ldr r0, =EnterBootLoader
+ bic r0, #0x00000001
+ str r0, [sp, #0x18]
+
+ ;
+ ; Return from the NMI handler. This will then start execution of the
+ ; boot loader.
+ ;
+ bx r9
+
+ ;
+ ; Restore the link register.
+ ;
+EnterApplication
+ mov lr, r9
+
+ ;
+ ; Copy the application's vector table to the target address if necessary.
+ ; Note that incorrect boot loader configuration could cause this to
+ ; corrupt the code! Setting VTABLE_START_ADDRESS to 0x20000000 (the start
+ ; of SRAM) is safe since this will use the same memory that the boot loader
+ ; already uses for its vector table. Great care will have to be taken if
+ ; other addresses are to be used.
+ ;
+ if (_APP_START_ADDRESS != _VTABLE_START_ADDRESS)
+ movw r0, #(_VTABLE_START_ADDRESS & 0xffff)
+ if (_VTABLE_START_ADDRESS > 0xffff)
+ movt r0, #(_VTABLE_START_ADDRESS >> 16)
+ endif
+ movw r1, #(_APP_START_ADDRESS & 0xffff)
+ if (_APP_START_ADDRESS > 0xffff)
+ movt r1, #(_APP_START_ADDRESS >> 16)
+ endif
+
+ ;
+ ; Calculate the end address of the vector table assuming that it has the
+ ; maximum possible number of vectors. We don't know how many the app has
+ ; populated so this is the safest approach though it may copy some non
+ ; vector data if the app table is smaller than the maximum.
+ ;
+ movw r2, #(70 * 4)
+ adds r2, r2, r0
+VectorCopyLoop2
+ ldr r3, [r1], #4
+ str r3, [r0], #4
+ cmp r0, r2
+ blt VectorCopyLoop2
+ endif
+
+ ;
+ ; Set the application's vector table start address. Typically this is the
+ ; application start address but in some cases an application may relocate
+ ; this so we can't assume that these two addresses are equal.
+ ;
+ movw r0, #(_VTABLE_START_ADDRESS & 0xffff)
+ if (_VTABLE_START_ADDRESS > 0xffff)
+ movt r0, #(_VTABLE_START_ADDRESS >> 16)
+ endif
+ movw r1, #(NVIC_VTABLE & 0xffff)
+ movt r1, #(NVIC_VTABLE >> 16)
+ str r0, [r1]
+
+ ;
+ ; Remove the NMI stack frame from the boot loader's stack.
+ ;
+ ldmia sp, {r4-r11}
+
+ ;
+ ; Get the application's stack pointer.
+ ;
+ if (_APP_START_ADDRESS != _VTABLE_START_ADDRESS)
+ movw r0, #(_APP_START_ADDRESS & 0xffff)
+ if (_APP_START_ADDRESS > 0xffff)
+ movt r0, #(_APP_START_ADDRESS >> 16)
+ endif
+ endif
+ ldr sp, [r0, #0x00]
+
+ ;
+ ; Fix up the NMI stack frame's return address to be the reset handler of
+ ; the application.
+ ;
+ ldr r10, [r0, #0x04]
+ bic r10, #0x00000001
+
+ ;
+ ; Store the NMI stack frame onto the application's stack.
+ ;
+ stmdb sp!, {r4-r11}
+
+ ;
+ ; Branch to the application's NMI handler.
+ ;
+ ldr r0, [r0, #0x08]
+ bx r0
+ endif
+
+;******************************************************************************
+;
+; The default interrupt handler.
+;
+;******************************************************************************
+IntDefaultHandler
+ ;
+ ; Loop forever since there is nothing that we can do about an unexpected
+ ; interrupt.
+ ;
+ b .
+
+;******************************************************************************
+;
+; Provides a small delay. The loop below takes 3 cycles/loop.
+;
+;******************************************************************************
+ export Delay
+Delay
+ subs r0, #1
+ bne Delay
+ bx lr
+
+;******************************************************************************
+;
+; This is the end of the file.
+;
+;******************************************************************************
+ align 4
+ end
diff --git a/boot_loader/bl_startup_sourcerygxx.S b/boot_loader/bl_startup_sourcerygxx.S
new file mode 100644
index 0000000..ded9231
--- /dev/null
+++ b/boot_loader/bl_startup_sourcerygxx.S
@@ -0,0 +1,630 @@
+//*****************************************************************************
+//
+// bl_startup_sourcerygxx.S - Startup code for Sourcery G++.
+//
+// Copyright (c) 2007-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// Include the assember definitions used to make this code compiler
+// independent.
+//
+//*****************************************************************************
+#include "inc/hw_nvic.h"
+#include "inc/hw_sysctl.h"
+#include "bl_config.h"
+
+//*****************************************************************************
+//
+// Put the assembler into the correct configuration.
+//
+//*****************************************************************************
+ .syntax unified
+ .thumb
+
+//*****************************************************************************
+//
+// The stack gets placed into the zero-init section.
+//
+//*****************************************************************************
+ .bss
+
+//*****************************************************************************
+//
+// Allocate storage for the stack.
+//
+//*****************************************************************************
+g_pulStack:
+ .space STACK_SIZE * 4
+
+//*****************************************************************************
+//
+// This portion of the file goes into the text section.
+//
+//*****************************************************************************
+ .section .isr_vector
+
+//*****************************************************************************
+//
+// The minimal vector table for a Cortex-M3 processor.
+//
+//*****************************************************************************
+Vectors:
+ .word g_pulStack + (STACK_SIZE * 4) // Offset 00: Initial stack pointer
+ .word ResetISR - 0x20000000 // Offset 04: Reset handler
+ .word NmiSR - 0x20000000 // Offset 08: NMI handler
+ .word FaultISR - 0x20000000 // Offset 0C: Hard fault handler
+ .word IntDefaultHandler // Offset 10: MPU fault handler
+ .word IntDefaultHandler // Offset 14: Bus fault handler
+ .word IntDefaultHandler // Offset 18: Usage fault handler
+ .word 0 // Offset 1C: Reserved
+ .word 0 // Offset 20: Reserved
+ .word 0 // Offset 24: Reserved
+ .word 0 // Offset 28: Reserved
+ .word UpdateHandler - 0x20000000 // Offset 2C: SVCall handler
+ .word IntDefaultHandler // Offset 30: Debug monitor handler
+ .word 0 // Offset 34: Reserved
+ .word IntDefaultHandler // Offset 38: PendSV handler
+#if defined(ENET_ENABLE_UPDATE)
+ .extern SysTickIntHandler
+ .word SysTickIntHandler // Offset 3C: SysTick handler
+#else
+ .word IntDefaultHandler // Offset 3C: SysTick handler
+#endif
+#if defined(UART_ENABLE_UPDATE) && defined(UART_AUTOBAUD)
+ .extern GPIOIntHandler
+ .word GPIOIntHandler // Offset 40: GPIO port A handler
+#else
+ .word IntDefaultHandler // Offset 40: GPIO port A handler
+#endif
+#if (defined(USB_ENABLE_UPDATE) || \
+ (APP_START_ADDRESS != VTABLE_START_ADDRESS))
+ .word IntDefaultHandler // Offset 44: GPIO Port B
+ .word IntDefaultHandler // Offset 48: GPIO Port C
+ .word IntDefaultHandler // Offset 4C: GPIO Port D
+ .word IntDefaultHandler // Offset 50: GPIO Port E
+ .word IntDefaultHandler // Offset 54: UART0 Rx and Tx
+ .word IntDefaultHandler // Offset 58: UART1 Rx and Tx
+ .word IntDefaultHandler // Offset 5C: SSI0 Rx and Tx
+ .word IntDefaultHandler // Offset 60: I2C0 Master and Slave
+ .word IntDefaultHandler // Offset 64: PWM Fault
+ .word IntDefaultHandler // Offset 68: PWM Generator 0
+ .word IntDefaultHandler // Offset 6C: PWM Generator 1
+ .word IntDefaultHandler // Offset 70: PWM Generator 2
+ .word IntDefaultHandler // Offset 74: Quadrature Encoder 0
+ .word IntDefaultHandler // Offset 78: ADC Sequence 0
+ .word IntDefaultHandler // Offset 7C: ADC Sequence 1
+ .word IntDefaultHandler // Offset 80: ADC Sequence 2
+ .word IntDefaultHandler // Offset 84: ADC Sequence 3
+ .word IntDefaultHandler // Offset 88: Watchdog timer
+ .word IntDefaultHandler // Offset 8C: Timer 0 subtimer A
+ .word IntDefaultHandler // Offset 90: Timer 0 subtimer B
+ .word IntDefaultHandler // Offset 94: Timer 1 subtimer A
+ .word IntDefaultHandler // Offset 98: Timer 1 subtimer B
+ .word IntDefaultHandler // Offset 9C: Timer 2 subtimer A
+ .word IntDefaultHandler // Offset A0: Timer 2 subtimer B
+ .word IntDefaultHandler // Offset A4: Analog Comparator 0
+ .word IntDefaultHandler // Offset A8: Analog Comparator 1
+ .word IntDefaultHandler // Offset AC: Analog Comparator 2
+ .word IntDefaultHandler // Offset B0: System Control
+ .word IntDefaultHandler // Offset B4: FLASH Control
+#endif
+#if (defined(USB_ENABLE_UPDATE) || (APP_START_ADDRESS != VTABLE_START_ADDRESS))
+ .word IntDefaultHandler // Offset B8: GPIO Port F
+ .word IntDefaultHandler // Offset BC: GPIO Port G
+ .word IntDefaultHandler // Offset C0: GPIO Port H
+ .word IntDefaultHandler // Offset C4: UART2 Rx and Tx
+ .word IntDefaultHandler // Offset C8: SSI1 Rx and Tx
+ .word IntDefaultHandler // Offset CC: Timer 3 subtimer A
+ .word IntDefaultHandler // Offset D0: Timer 3 subtimer B
+ .word IntDefaultHandler // Offset D4: I2C1 Master and Slave
+ .word IntDefaultHandler // Offset D8: Quadrature Encoder 1
+ .word IntDefaultHandler // Offset DC: CAN0
+ .word IntDefaultHandler // Offset E0: CAN1
+ .word IntDefaultHandler // Offset E4: CAN2
+ .word IntDefaultHandler // Offset E8: Ethernet
+ .word IntDefaultHandler // Offset EC: Hibernation module
+#if defined(USB_ENABLE_UPDATE)
+ .extern USB0DeviceIntHandler
+ .word USB0DeviceIntHandler // Offset F0: USB 0 Controller
+#else
+ .word IntDefaultHandler // Offset F0: USB 0 Controller
+#endif
+#endif
+
+//*****************************************************************************
+//
+// This portion of the file goes into the text section.
+//
+//*****************************************************************************
+ .text
+
+//*****************************************************************************
+//
+// Initialize the processor by copying the boot loader from flash to SRAM, zero
+// filling the .bss section, and moving the vector table to the beginning of
+// SRAM. The return address is modified to point to the SRAM copy of the boot
+// loader instead of the flash copy, resulting in a branch to the copy now in
+// SRAM.
+//
+//*****************************************************************************
+ .thumb_func
+ProcessorInit:
+ //
+ // Copy the code image from flash to SRAM.
+ //
+ movs r0, #0x0000
+ movs r1, #0x0000
+ movt r1, #0x2000
+ .extern _bss
+ ldr r2, =_bss
+copy_loop:
+ ldr r3, [r0], #4
+ str r3, [r1], #4
+ cmp r1, r2
+ blt copy_loop
+
+ //
+ // Zero fill the .bss section.
+ //
+ movs r0, #0x0000
+ .extern _ebss
+ ldr r2, =_ebss
+zero_loop:
+ str r0, [r1], #4
+ cmp r1, r2
+ blt zero_loop
+
+ //
+ // Set the vector table pointer to the beginning of SRAM.
+ //
+ movw r0, #(NVIC_VTABLE & 0xffff)
+ movt r0, #(NVIC_VTABLE >> 16)
+ movs r1, #0x0000
+ movt r1, #0x2000
+ str r1, [r0]
+
+ //
+ // Set the return address to the code just copied into SRAM.
+ //
+ orr lr, lr, #0x20000000
+
+ //
+ // Return to the caller.
+ //
+ bx lr
+
+//*****************************************************************************
+//
+// The reset handler, which gets called when the processor starts.
+//
+//*****************************************************************************
+ .globl ResetISR
+ .thumb_func
+ResetISR:
+ //
+ // Enable the floating-point unit. This must be done here in case any
+ // later C functions use floating point. Note that some toolchains will
+ // use the FPU registers for general workspace even if no explicit floating
+ // point data types are in use.
+ //
+ movw r0, #0xED88
+ movt r0, #0xE000
+ ldr r1, [r0]
+ orr r1, r1, #0x00F00000
+ str r1, [r0]
+
+ //
+ // Initialize the processor.
+ //
+ bl ProcessorInit
+
+ //
+ // Call the user-supplied low level hardware initialization function
+ // if provided.
+ //
+#ifdef BL_HW_INIT_FN_HOOK
+ .extern BL_HW_INIT_FN_HOOK
+ bl BL_HW_INIT_FN_HOOK
+#endif
+
+ //
+ // See if an update should be performed.
+ //
+ .extern CheckForceUpdate
+ bl CheckForceUpdate
+ cbz r0, CallApplication
+
+ //
+ // Configure the microcontroller.
+ //
+ .thumb_func
+EnterBootLoader:
+#ifdef ENET_ENABLE_UPDATE
+ .extern ConfigureEnet
+ bl ConfigureEnet
+#elif defined(CAN_ENABLE_UPDATE)
+ .extern ConfigureCAN
+ bl ConfigureCAN
+#elif defined(USB_ENABLE_UPDATE)
+ .extern ConfigureUSB
+ bl ConfigureUSB
+#else
+ .extern ConfigureDevice
+ bl ConfigureDevice
+#endif
+
+ //
+ // Call the user-supplied initialization function if provided.
+ //
+#ifdef BL_INIT_FN_HOOK
+ .extern BL_INIT_FN_HOOK
+ bl BL_INIT_FN_HOOK
+#endif
+
+ //
+ // Branch to the update handler.
+ //
+#ifdef ENET_ENABLE_UPDATE
+ .extern UpdateBOOTP
+ b UpdateBOOTP
+#elif defined(CAN_ENABLE_UPDATE)
+ .extern UpdaterCAN
+ b UpdaterCAN
+#elif defined(USB_ENABLE_UPDATE)
+ .extern UpdaterUSB
+ b UpdaterUSB
+#else
+ .extern Updater
+ b Updater
+#endif
+
+ //
+ // This is a second symbol to allow starting the application from the boot
+ // loader the linker may not like the perceived jump.
+ //
+ .globl StartApplication
+ .thumb_func
+StartApplication:
+ //
+ // Call the application via the reset handler in its vector table. Load
+ // the address of the application vector table.
+ //
+ .thumb_func
+CallApplication:
+ //
+ // Copy the application's vector table to the target address if necessary.
+ // Note that incorrect boot loader configuration could cause this to
+ // corrupt the code! Setting VTABLE_START_ADDRESS to 0x20000000 (the start
+ // of SRAM) is safe since this will use the same memory that the boot loader
+ // already uses for its vector table. Great care will have to be taken if
+ // other addresses are to be used.
+ //
+#if (APP_START_ADDRESS != VTABLE_START_ADDRESS)
+ movw r0, #(VTABLE_START_ADDRESS & 0xffff)
+#if (VTABLE_START_ADDRESS > 0xffff)
+ movt r0, #(VTABLE_START_ADDRESS >> 16)
+#endif
+ movw r1, #(APP_START_ADDRESS & 0xffff)
+#if (APP_START_ADDRESS > 0xffff)
+ movt r1, #(APP_START_ADDRESS >> 16)
+#endif
+
+ //
+ // Calculate the end address of the vector table assuming that it has the
+ // maximum possible number of vectors. We don't know how many the app has
+ // populated so this is the safest approach though it may copy some non
+ // vector data if the app table is smaller than the maximum.
+ //
+ movw r2, #(70 * 4)
+ adds r2, r2, r0
+VectorCopyLoop:
+ ldr r3, [r1], #4
+ str r3, [r0], #4
+ cmp r0, r2
+ blt VectorCopyLoop
+#endif
+
+ //
+ // Set the application's vector table start address. Typically this is the
+ // application start address but in some cases an application may relocate
+ // this so we can't assume that these two addresses are equal.
+ //
+ movw r0, #(VTABLE_START_ADDRESS & 0xffff)
+#if (VTABLE_START_ADDRESS > 0xffff)
+ movt r0, #(VTABLE_START_ADDRESS >> 16)
+#endif
+ movw r1, #(NVIC_VTABLE & 0xffff)
+ movt r1, #(NVIC_VTABLE >> 16)
+ str r0, [r1]
+
+ //
+ // Load the stack pointer from the application's vector table.
+ //
+#if (APP_START_ADDRESS != VTABLE_START_ADDRESS)
+ movw r0, #(APP_START_ADDRESS & 0xffff)
+#if (APP_START_ADDRESS > 0xffff)
+ movt r0, #(APP_START_ADDRESS >> 16)
+#endif
+#endif
+ ldr sp, [r0]
+
+ //
+ // Load the initial PC from the application's vector table and branch to
+ // the application's entry point.
+ //
+ ldr r0, [r0, #4]
+ bx r0
+
+//*****************************************************************************
+//
+// The update handler, which gets called when the application would like to
+// start an update.
+//
+//*****************************************************************************
+ .thumb_func
+UpdateHandler:
+ //
+ // Initialize the processor.
+ //
+ bl ProcessorInit
+
+ //
+ // Load the stack pointer from the vector table.
+ //
+ movs r0, #0x0000
+ ldr sp, [r0]
+
+ //
+ // Call the user-supplied low level hardware initialization function
+ // if provided.
+ //
+#ifdef BL_HW_INIT_FN_HOOK
+ bl BL_HW_INIT_FN_HOOK
+#endif
+
+ //
+ // Call the user-supplied re-initialization function if provided.
+ //
+#ifdef BL_REINIT_FN_HOOK
+ .extern BL_REINIT_FN_HOOK
+ bl BL_REINIT_FN_HOOK
+#endif
+
+ //
+ // Branch to the update handler.
+ //
+#ifdef ENET_ENABLE_UPDATE
+ b UpdateBOOTP
+#elif defined(CAN_ENABLE_UPDATE)
+ .extern AppUpdaterCAN
+ b AppUpdaterCAN
+#elif defined(USB_ENABLE_UPDATE)
+ .extern AppUpdaterUSB
+ b AppUpdaterUSB
+#else
+ b Updater
+#endif
+
+//*****************************************************************************
+//
+// The NMI handler.
+//
+//*****************************************************************************
+ .thumb_func
+NmiSR:
+#ifdef ENABLE_MOSCFAIL_HANDLER
+ //
+ // Grab the fault frame from the stack (the stack will be cleared by the
+ // processor initialization that follows).
+ //
+ ldm sp, {r4-r11}
+ mov r12, lr
+
+ //
+ // Initialize the processor.
+ //
+ bl ProcessorInit
+
+ //
+ // Restore the stack frame.
+ //
+ mov lr, r12
+ stm sp, {r4-r11}
+
+ //
+ // Save the link register.
+ //
+ mov r9, lr
+
+ //
+ // Call the user-supplied low level hardware initialization function
+ // if provided.
+ //
+#ifdef BL_HW_INIT_FN_HOOK
+ bl BL_HW_INIT_FN_HOOK
+#endif
+
+ //
+ // See if an update should be performed.
+ //
+ bl CheckForceUpdate
+ cbz r0, EnterApplication
+
+ //
+ // Clear the MOSCFAIL bit in RESC.
+ //
+ movw r0, #(SYSCTL_RESC & 0xffff)
+ movt r0, #(SYSCTL_RESC >> 16)
+ ldr r1, [r0]
+ bic r1, r1, #SYSCTL_RESC_MOSCFAIL
+ str r1, [r0]
+
+ //
+ // Fix up the PC on the stack so that the boot pin check is bypassed
+ // (since it has already been performed).
+ //
+ ldr r0, =EnterBootLoader
+ bic r0, #0x00000001
+ str r0, [sp, #0x18]
+
+ //
+ // Return from the NMI handler. This will then start execution of the
+ // boot loader.
+ //
+ bx r9
+
+ //
+ // Restore the link register.
+ //
+ .thumb_func
+EnterApplication:
+ mov lr, r9
+
+ //
+ // Copy the application's vector table to the target address if necessary.
+ // Note that incorrect boot loader configuration could cause this to
+ // corrupt the code! Setting VTABLE_START_ADDRESS to 0x20000000 (the start
+ // of SRAM) is safe since this will use the same memory that the boot loader
+ // already uses for its vector table. Great care will have to be taken if
+ // other addresses are to be used.
+ //
+#if (APP_START_ADDRESS != VTABLE_START_ADDRESS)
+ movw r0, #(VTABLE_START_ADDRESS & 0xffff)
+#if (VTABLE_START_ADDRESS > 0xffff)
+ movt r0, #(VTABLE_START_ADDRESS >> 16)
+#endif
+ movw r1, #(APP_START_ADDRESS & 0xffff)
+#if (APP_START_ADDRESS > 0xffff)
+ movt r1, #(APP_START_ADDRESS >> 16)
+#endif
+
+ //
+ // Calculate the end address of the vector table assuming that it has the
+ // maximum possible number of vectors. We don't know how many the app has
+ // populated so this is the safest approach though it may copy some non
+ // vector data if the app table is smaller than the maximum.
+ //
+ movw r2, #(70 * 4)
+ adds r2, r2, r0
+VectorCopyLoop2:
+ ldr r3, [r1], #4
+ str r3, [r0], #4
+ cmp r0, r2
+ blt VectorCopyLoop2
+#endif
+
+ //
+ // Set the application's vector table start address. Typically this is the
+ // application start address but in some cases an application may relocate
+ // this so we can't assume that these two addresses are equal.
+ //
+ movw r0, #(VTABLE_START_ADDRESS & 0xffff)
+#if (VTABLE_START_ADDRESS > 0xffff)
+ movt r0, #(VTABLE_START_ADDRESS >> 16)
+#endif
+ movw r1, #(NVIC_VTABLE & 0xffff)
+ movt r1, #(NVIC_VTABLE >> 16)
+ str r0, [r1]
+
+ //
+ // Remove the NMI stack frame from the boot loader's stack.
+ //
+ ldmia sp, {r4-r11}
+
+ //
+ // Get the application's stack pointer.
+ //
+#if (APP_START_ADDRESS != VTABLE_START_ADDRESS)
+ movw r0, #(APP_START_ADDRESS & 0xffff)
+#if (APP_START_ADDRESS > 0xffff)
+ movt r0, #(APP_START_ADDRESS >> 16)
+#endif
+#endif
+ ldr sp, [r0, #0x00]
+
+ //
+ // Fix up the NMI stack frame's return address to be the reset handler of
+ // the application.
+ //
+ ldr r10, [r0, #0x04]
+ bic r10, #0x00000001
+
+ //
+ // Store the NMI stack frame onto the application's stack.
+ //
+ stmdb sp!, {r4-r11}
+
+ //
+ // Branch to the application's NMI handler.
+ //
+ ldr r0, [r0, #0x08]
+ bx r0
+#else
+ //
+ // Loop forever since there is nothing that we can do about a NMI.
+ //
+ b .
+#endif
+
+//*****************************************************************************
+//
+// The hard fault handler.
+//
+//*****************************************************************************
+ .thumb_func
+FaultISR:
+ //
+ // Loop forever since there is nothing that we can do about a hard fault.
+ //
+ b .
+
+//*****************************************************************************
+//
+// The default interrupt handler.
+//
+//*****************************************************************************
+ .thumb_func
+IntDefaultHandler:
+ //
+ // Loop forever since there is nothing that we can do about an unexpected
+ // interrupt.
+ //
+ b .
+
+//*****************************************************************************
+//
+// Provides a small delay. The loop below takes 3 cycles/loop.
+//
+//*****************************************************************************
+ .globl Delay
+ .thumb_func
+Delay:
+ subs r0, #1
+ bne Delay
+ bx lr
+
+//*****************************************************************************
+//
+// This is the end of the file.
+//
+//*****************************************************************************
+ .end
diff --git a/boot_loader/bl_uart.c b/boot_loader/bl_uart.c
new file mode 100644
index 0000000..71df5c3
--- /dev/null
+++ b/boot_loader/bl_uart.c
@@ -0,0 +1,156 @@
+//*****************************************************************************
+//
+// bl_uart.c - Functions to transfer data via the UART port.
+//
+// Copyright (c) 2006-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
+//
+//*****************************************************************************
+
+#include <stdint.h>
+#include "inc/hw_gpio.h"
+#include "inc/hw_memmap.h"
+#include "inc/hw_sysctl.h"
+#include "inc/hw_types.h"
+#include "inc/hw_uart.h"
+#include "bl_config.h"
+#include "boot_loader/bl_uart.h"
+
+//*****************************************************************************
+//
+//! \addtogroup bl_uart_api
+//! @{
+//
+//*****************************************************************************
+#if defined(UART_ENABLE_UPDATE) || defined(DOXYGEN)
+
+//*****************************************************************************
+//
+//! Sends data over the UART port.
+//!
+//! \param pui8Data is the buffer containing the data to write out to the UART
+//! port.
+//! \param ui32Size is the number of bytes provided in \e pui8Data buffer that
+//! will be written out to the UART port.
+//!
+//! This function sends \e ui32Size bytes of data from the buffer pointed to by
+//! \e pui8Data via the UART port.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+UARTSend(const uint8_t *pui8Data, uint32_t ui32Size)
+{
+ //
+ // Transmit the number of bytes requested on the UART port.
+ //
+ while(ui32Size--)
+ {
+ //
+ // Make sure that the transmit FIFO is not full.
+ //
+ while((HWREG(UART0_BASE + UART_O_FR) & UART_FR_TXFF))
+ {
+ }
+
+ //
+ // Send out the next byte.
+ //
+ HWREG(UART0_BASE + UART_O_DR) = *pui8Data++;
+ }
+
+ //
+ // Wait until the UART is done transmitting.
+ //
+ UARTFlush();
+}
+
+//*****************************************************************************
+//
+//! Waits until all data has been transmitted by the UART port.
+//!
+//! This function waits until all data written to the UART port has been
+//! transmitted.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+UARTFlush(void)
+{
+ //
+ // Wait for the UART FIFO to empty and then wait for the shifter to get the
+ // bytes out the port.
+ //
+ while(!(HWREG(UART0_BASE + UART_O_FR) & UART_FR_TXFE))
+ {
+ }
+
+ //
+ // Wait for the FIFO to not be busy so that the shifter completes.
+ //
+ while((HWREG(UART0_BASE + UART_O_FR) & UART_FR_BUSY))
+ {
+ }
+}
+
+//*****************************************************************************
+//
+//! Receives data over the UART port.
+//!
+//! \param pui8Data is the buffer to read data into from the UART port.
+//! \param ui32Size is the number of bytes provided in the \e pui8Data buffer
+//! that should be written with data from the UART port.
+//!
+//! This function reads back \e ui32Size bytes of data from the UART port, into
+//! the buffer that is pointed to by \e pui8Data. This function will not
+//! return until \e ui32Size number of bytes have been received.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+UARTReceive(uint8_t *pui8Data, uint32_t ui32Size)
+{
+ //
+ // Send out the number of bytes requested.
+ //
+ while(ui32Size--)
+ {
+ //
+ // Wait for the FIFO to not be empty.
+ //
+ while((HWREG(UART0_BASE + UART_O_FR) & UART_FR_RXFE))
+ {
+ }
+
+ //
+ // Receive a byte from the UART.
+ //
+ *pui8Data++ = HWREG(UART0_BASE + UART_O_DR);
+ }
+}
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
+#endif
diff --git a/boot_loader/bl_uart.h b/boot_loader/bl_uart.h
new file mode 100644
index 0000000..8148995
--- /dev/null
+++ b/boot_loader/bl_uart.h
@@ -0,0 +1,81 @@
+//*****************************************************************************
+//
+// bl_uart.h - Definitions for the UART transport functions.
+//
+// Copyright (c) 2006-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
+//
+//*****************************************************************************
+
+#ifndef __BL_UART_H__
+#define __BL_UART_H__
+
+//*****************************************************************************
+//
+// This macro is used to generate a constant to represent the UART baud rate to
+// processor clock rate ratio. This prevents the need for run-time calculation
+// of the ratio of baud rate to processor clock rate ratio.
+//
+//*****************************************************************************
+#define UART_BAUD_RATIO(ui32Baud) \
+ ((((CRYSTAL_FREQ * 8) / ui32Baud) + 1) / 2)
+
+//*****************************************************************************
+//
+// This defines the UART receive pin that is being used by the boot loader.
+//
+//*****************************************************************************
+#define UART_RX (1 << 0)
+
+//*****************************************************************************
+//
+// This defines the UART transmit pin that is being used by the boot loader.
+//
+//*****************************************************************************
+#define UART_TX (1 << 1)
+
+//*****************************************************************************
+//
+// This defines the combination of pins used to implement the UART port used by
+// the boot loader.
+//
+//*****************************************************************************
+#define UART_PINS (UART_RX | UART_TX)
+
+//*****************************************************************************
+//
+// UART Transport APIs
+//
+//*****************************************************************************
+extern void UARTSend(const uint8_t *pui8Data, uint32_t ui32Size);
+extern void UARTReceive(uint8_t *pui8Data, uint32_t ui32Size);
+extern void UARTFlush(void);
+extern int UARTAutoBaud(uint32_t *pui32Ratio);
+
+//*****************************************************************************
+//
+// Define the transport functions if the UART is being used.
+//
+//*****************************************************************************
+#ifdef UART_ENABLE_UPDATE
+#define SendData UARTSend
+#define FlushData UARTFlush
+#define ReceiveData UARTReceive
+#endif
+
+#endif // __BL_UART_H__
diff --git a/boot_loader/bl_usb.c b/boot_loader/bl_usb.c
new file mode 100644
index 0000000..00ccd7a
--- /dev/null
+++ b/boot_loader/bl_usb.c
@@ -0,0 +1,2166 @@
+//*****************************************************************************
+//
+// bl_usb.c - Functions to transfer data via the USB port.
+//
+// Copyright (c) 2009-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
+//
+//*****************************************************************************
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "inc/hw_gpio.h"
+#include "inc/hw_memmap.h"
+#include "inc/hw_flash.h"
+#include "inc/hw_sysctl.h"
+#include "inc/hw_types.h"
+#include "inc/hw_nvic.h"
+#include "inc/hw_usb.h"
+#include "bl_config.h"
+#include "boot_loader/bl_crystal.h"
+#include "boot_loader/bl_flash.h"
+#include "boot_loader/bl_hooks.h"
+#include "boot_loader/bl_usbfuncs.h"
+#include "boot_loader/usbdfu.h"
+
+//*****************************************************************************
+//
+// DFU Notes:
+//
+// 1. This implementation is manifestation-tolerant and doesn't time out
+// waiting for a reset after a download completes. As a result, the detach
+// timeout in the DFU functional descriptor is set to the maximum possible
+// value representing a timeout of 65.536 seconds.
+//
+// 2. This implementation does not support the BUSY state. By skipping this
+// and remaining in DNLOAD_SYNC when we are waiting for a programming or
+// erase operation to complete, we save the overhead of having to support a
+// timeout mechanism. Host-side implementations don't seem to rely upon
+// the busy state so this does not appear to be a problem.
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+//! \addtogroup bl_usb_api
+//! @{
+//
+//*****************************************************************************
+#if defined(USB_ENABLE_UPDATE) || defined(DOXYGEN)
+
+//*****************************************************************************
+//
+// Make sure that the crystal frequency is defined.
+//
+//*****************************************************************************
+#if !defined(CRYSTAL_FREQ)
+#error ERROR: CRYSTAL_FREQ must be defined for USB update!
+#endif
+
+//*****************************************************************************
+//
+// Make sure that the crystal frequency is one of the ones that support USB
+// operation.
+//
+//*****************************************************************************
+#if CRYSTAL_FREQ != 4000000 && \
+ CRYSTAL_FREQ != 5000000 && \
+ CRYSTAL_FREQ != 6000000 && \
+ CRYSTAL_FREQ != 8000000 && \
+ CRYSTAL_FREQ != 10000000 && \
+ CRYSTAL_FREQ != 12000000 && \
+ CRYSTAL_FREQ != 16000000
+#error ERROR: Invalid CRYSTAL_FREQ specified for USB update!
+#endif
+
+//*****************************************************************************
+//
+// The DFU device information structure was developed assuming flash block
+// sizes in the 1KB to 32KB range but large external flash devices may have
+// 64KB or larger blocks. If the configuration options indicate a target
+// device with large pages, we fake the size at 32KB to keep the client happy.
+// The other option would be to redefine this field as an uint32_t but that
+// would break existing applications using the interface.
+//
+// For normal operation, this is unlikely to cause a problem since we will not
+// allow a flash operation to start anywhere other than at APP_START_ADDRESS
+// (which must fall on a real flash page boundary) or the start of the
+// reserved
+//
+//*****************************************************************************
+#if (FLASH_PAGE_SIZE > 0x10000)
+#define DFU_REPORTED_PAGE_SIZE 0x8000
+#else
+#define DFU_REPORTED_PAGE_SIZE FLASH_PAGE_SIZE
+#endif
+
+//*****************************************************************************
+//
+// This holds the total size of the firmware image being downloaded (which is
+// needed if we have a progress reporting hook function provided).
+//
+//*****************************************************************************
+#ifdef BL_PROGRESS_FN_HOOK
+uint32_t g_ui32ImageSize;
+#endif
+
+//*****************************************************************************
+//
+// The structure used to define a block of memory.
+//
+//*****************************************************************************
+typedef struct
+{
+ uint8_t *pui8Start;
+ uint32_t ui32Length;
+}
+tMemoryBlock;
+
+//*****************************************************************************
+//
+// The block of memory that is to be sent back in response to the next upload
+// request.
+//
+//*****************************************************************************
+tMemoryBlock g_sNextUpload;
+
+//*****************************************************************************
+//
+// The block of memory into which the next programming operation will write.
+//
+//*****************************************************************************
+volatile tMemoryBlock g_sNextDownload;
+
+//*****************************************************************************
+//
+// The block of flash to be erased.
+//
+//*****************************************************************************
+volatile tMemoryBlock g_sErase;
+
+//*****************************************************************************
+//
+// Information on the device we are running on. This will be returned to the
+// host after a download request containing command DFU_CMD_INFO.
+//
+//*****************************************************************************
+tDFUDeviceInfo g_sDFUDeviceInfo;
+
+//*****************************************************************************
+//
+// This variable keeps track of the last software-specific command received
+// from the host via a download request.
+//
+//*****************************************************************************
+uint8_t g_ui8LastCommand;
+
+//*****************************************************************************
+//
+// The current status of the DFU device as reported to the host in response to
+// USBD_DFU_REQUEST_GETSTATUS.
+//
+//*****************************************************************************
+tDFUGetStatusResponse g_sDFUStatus =
+{
+ 0, { 5, 0, 0 }, (uint8_t)STATE_IDLE, 0
+};
+
+//*****************************************************************************
+//
+// The structure sent in response to a valid USBD_DFU_REQUEST_TIVA.
+//
+//*****************************************************************************
+tDFUQueryTIVAProtocol g_sDFUProtocol =
+{
+ DFU_PROTOCOL_USBLIB_MARKER,
+ DFU_PROTOCOL_USBLIB_VERSION_1
+};
+
+//*****************************************************************************
+//
+// The current state of the device.
+//
+//*****************************************************************************
+volatile tDFUState g_eDFUState = STATE_IDLE;
+
+//*****************************************************************************
+//
+// The current status of the device.
+//
+//*****************************************************************************
+volatile tDFUStatus g_eDFUStatus = STATUS_OK;
+
+//*****************************************************************************
+//
+// The buffer used to hold download data from the host prior to writing it to
+// flash or image data in the process of being uploaded to the host.
+//
+//*****************************************************************************
+uint8_t g_pui8DFUBuffer[DFU_TRANSFER_SIZE];
+
+//*****************************************************************************
+//
+// The start of the image data within g_pui8DFUBuffer.
+//
+//*****************************************************************************
+uint8_t *g_pui8DFUWrite;
+
+//*****************************************************************************
+//
+// The number of bytes of valid data in the DFU buffer.
+//
+//*****************************************************************************
+volatile uint16_t g_ui16DFUBufferUsed;
+
+//*****************************************************************************
+//
+// Flags used to indicate that the main thread is being asked to do something.
+//
+//*****************************************************************************
+volatile uint32_t g_ui32CommandFlags;
+#define CMD_FLAG_ERASE 0
+#define CMD_FLAG_WRITE 1
+#define CMD_FLAG_RESET 2
+
+//*****************************************************************************
+//
+// This global determines whether or not we add a DFU header to any uploaded
+// image data. If true, the binary image is sent without the header. If false
+// the header is included. This is a DFU requirement since uploaded images
+// must be able to be downloaded again and hence must have the header in place
+// so that the destination address is available.
+//
+//*****************************************************************************
+bool g_bUploadBinary = false;
+
+//*****************************************************************************
+//
+// If the upload format includes the header, we need to be able to suppress
+// this when replying to TIVA-specific commands such as CMD_DFU_INFO. This
+// global determines whether we need to suppress the header that would
+// otherwise be send in response to the first USBD_DFU_REQUEST_UPLOAD received
+// while in STATE_IDLE.
+//
+//*****************************************************************************
+bool g_bSuppressUploadHeader = false;
+
+//*****************************************************************************
+//
+// A flag we use to indicate when the device has been enumerated.
+//
+//*****************************************************************************
+bool g_bAddressSet = false;
+
+//*****************************************************************************
+//
+// The languages supported by this device.
+//
+//*****************************************************************************
+const uint8_t g_pui8LangDescriptor[] =
+{
+ 4,
+ USB_DTYPE_STRING,
+ USBShort(USB_LANG_EN_US)
+};
+
+//*****************************************************************************
+//
+// The jump table used to implement request handling in the DFU state machine.
+//
+//*****************************************************************************
+typedef void (* tHandleRequests)(tUSBRequest *psUSBRequest);
+
+extern void HandleRequestIdle(tUSBRequest *psUSBRequest);
+extern void HandleRequestDnloadSync(tUSBRequest *psUSBRequest);
+extern void HandleRequestDnloadIdle(tUSBRequest *psUSBRequest);
+extern void HandleRequestManifestSync(tUSBRequest *psUSBRequest);
+extern void HandleRequestUploadIdle(tUSBRequest *psUSBRequest);
+extern void HandleRequestError(tUSBRequest *psUSBRequest);
+
+tHandleRequests g_pfnRequestHandlers[] =
+{
+ 0, // STATE_APP_IDLE
+ 0, // STATE_APP_DETACH
+ HandleRequestIdle, // STATE_IDLE
+ HandleRequestDnloadSync, // STATE_DNLOAD_SYNC
+ HandleRequestDnloadSync, // STATE_DNBUSY
+ HandleRequestDnloadIdle, // STATE_DNLOAD_IDLE
+ HandleRequestManifestSync, // STATE_MANIFEST_SYNC
+ 0, // STATE_MANIFEST
+ 0, // STATE_MANIFEST_WAIT_RESET
+ HandleRequestUploadIdle, // STATE_UPLOAD_IDLE
+ HandleRequestError // STATE_ERROR
+};
+
+//*****************************************************************************
+//
+// The manufacturer string.
+//
+//*****************************************************************************
+const uint8_t g_pui8ManufacturerString[] =
+{
+ (17 + 1) * 2,
+ USB_DTYPE_STRING,
+ 'T', 0, 'e', 0, 'x', 0, 'a', 0, 's', 0, ' ', 0, 'I', 0, 'n', 0,
+ 's', 0, 't', 0, 'r', 0, 'u', 0, 'm', 0, 'e', 0, 'n', 0, 't', 0,
+ 's', 0
+};
+
+//*****************************************************************************
+//
+// The product string.
+//
+//*****************************************************************************
+const uint8_t g_pui8ProductString[] =
+{
+ (23 + 1) * 2,
+ USB_DTYPE_STRING,
+ 'D', 0, 'e', 0, 'v', 0, 'i', 0, 'c', 0, 'e', 0, ' ', 0, 'F', 0, 'i', 0,
+ 'r', 0, 'm', 0, 'w', 0, 'a', 0, 'r', 0, 'e', 0, ' ', 0, 'U', 0, 'p', 0,
+ 'g', 0, 'r', 0, 'a', 0, 'd', 0, 'e', 0
+};
+
+//*****************************************************************************
+//
+// The serial number string.
+//
+//*****************************************************************************
+const uint8_t g_pui8SerialNumberString[] =
+{
+ (3 + 1) * 2,
+ USB_DTYPE_STRING,
+ '0', 0, '.', 0, '1', 0
+};
+
+//*****************************************************************************
+//
+// The descriptor string table.
+//
+//*****************************************************************************
+const uint8_t *const g_ppui8StringDescriptors[] =
+{
+ g_pui8LangDescriptor,
+ g_pui8ManufacturerString,
+ g_pui8ProductString,
+ g_pui8SerialNumberString
+};
+
+//*****************************************************************************
+//
+// DFU Device Descriptor.
+//
+//*****************************************************************************
+const uint8_t g_pui8DFUDeviceDescriptor[] =
+{
+ 18, // Size of this structure.
+ USB_DTYPE_DEVICE, // Type of this structure.
+ USBShort(0x110), // USB version 1.1 (if we say 2.0, hosts assume
+ // high-speed - see USB 2.0 spec 9.2.6.6)
+ USB_CLASS_VEND_SPECIFIC, // USB Device Class
+ 0, // USB Device Sub-class
+ 0, // USB Device protocol
+ 64, // Maximum packet size for default pipe.
+ USBShort(USB_VENDOR_ID), // Vendor ID (VID).
+ USBShort(USB_PRODUCT_ID), // Product ID (PID).
+ USBShort(USB_DEVICE_ID), // Device Release Number BCD.
+ 1, // Manufacturer string identifier.
+ 2, // Product string identifier.
+ 3, // Product serial number.
+ 1 // Number of configurations.
+};
+
+//*****************************************************************************
+//
+// DFU device configuration descriptor.
+//
+//*****************************************************************************
+const uint8_t g_pui8DFUConfigDescriptor[] =
+{
+ //
+ // Configuration descriptor header.
+ //
+ 9, // Size of the configuration descriptor.
+ USB_DTYPE_CONFIGURATION, // Type of this descriptor.
+ USBShort(27), // The total size of this full structure.
+ 1, // The number of interfaces in this
+ // configuration.
+ 1, // The unique value for this configuration.
+ 0, // The string identifier that describes this
+ // configuration.
+#if USB_BUS_POWERED
+ USB_CONF_ATTR_BUS_PWR, // Bus Powered
+#else
+ USB_CONF_ATTR_SELF_PWR, // Self Powered
+#endif
+ (USB_MAX_POWER / 2), // The maximum power in 2mA increments.
+
+ //
+ // Interface descriptor.
+ //
+ 9, // Length of this descriptor.
+ USB_DTYPE_INTERFACE, // This is an interface descriptor.
+ 0, // Interface number .
+ 0, // Alternate setting number.
+ 0, // Number of endpoints (only endpoint 0 used)
+ USB_CLASS_APP_SPECIFIC, // Application specific interface class
+ USB_DFU_SUBCLASS, // Device Firmware Upgrade subclass
+ USB_DFU_PROTOCOL, // DFU protocol
+ 0, // No interface description string present.
+
+ //
+ // Device Firmware Upgrade functional descriptor.
+ //
+ 9, // Length of this descriptor.
+ 0x21, // DFU Functional descriptor type
+ (DFU_ATTR_CAN_DOWNLOAD | // DFU attributes.
+ DFU_ATTR_CAN_UPLOAD |
+ DFU_ATTR_MANIFEST_TOLERANT),
+ USBShort(0xFFFF), // Detach timeout (set to maximum).
+ USBShort(DFU_TRANSFER_SIZE),// Transfer size 1KB.
+ USBShort(0x0110) // DFU Version 1.1
+};
+
+//*****************************************************************************
+//
+// The USB device interrupt handler.
+//
+// This function is called to process USB interrupts when in device mode.
+// This handler will branch the interrupt off to the appropriate application or
+// stack handlers depending on the current status of the USB controller.
+//
+// \return None.
+//
+//*****************************************************************************
+void
+USB0DeviceIntHandler(void)
+{
+ uint32_t ui32TxStatus, ui32GenStatus;
+
+ //
+ // Get the current full USB interrupt status.
+ //
+ ui32TxStatus = HWREGH(USB0_BASE + USB_O_TXIS);
+ ui32GenStatus = HWREGB(USB0_BASE + USB_O_IS);
+
+ //
+ // Received a reset from the host.
+ //
+ if(ui32GenStatus & USB_IS_RESET)
+ {
+ USBDeviceEnumResetHandler();
+ }
+
+ //
+ // USB device was disconnected.
+ //
+ if(ui32GenStatus & USB_IS_DISCON)
+ {
+ HandleDisconnect();
+ }
+
+ //
+ // Handle end point 0 interrupts.
+ //
+ if(ui32TxStatus & USB_TXIE_EP0)
+ {
+ USBDeviceEnumHandler();
+ }
+}
+
+//*****************************************************************************
+//
+// A prototype for the function (in the startup code) for a predictable length
+// delay.
+//
+//*****************************************************************************
+extern void Delay(uint32_t ui32Count);
+
+//*****************************************************************************
+//
+// Send the current state or status structure back to the host. This function
+// also acknowledges the request which causes us to send back this data.
+//
+//*****************************************************************************
+void
+SendDFUStatus(void)
+{
+ //
+ // Acknowledge the original request.
+ //
+ USBDevEndpoint0DataAck(false);
+
+ //
+ // Copy the current state into the status structure we will return.
+ //
+ g_sDFUStatus.bState = (uint8_t)g_eDFUState;
+ g_sDFUStatus.bStatus = (uint8_t)g_eDFUStatus;
+
+ //
+ // Send the status structure back to the host.
+ //
+ USBBLSendDataEP0((uint8_t *)&g_sDFUStatus, sizeof(tDFUGetStatusResponse));
+}
+
+//*****************************************************************************
+//
+// Send the next block of upload data back to the host assuming data remains
+// to be sent.
+//
+// \param ui16Length is the requested amount of data.
+// \param bAppendHeader is \b true to append a tDFUDownloadProgHeader at the
+// start of the uploaded data or \b false if no header is required.
+//
+// Returns \b true if a full packet containing DFU_TRANSFER_SIZE bytes
+// was sent and data remains to be sent following this transaction, or \b
+// false if no more data remains to be sent following this transaction.
+//
+//*****************************************************************************
+bool
+SendUploadData(uint16_t ui16Length, bool bAppendHeader)
+{
+ uint16_t ui16ToSend;
+ uint32_t ui32Available;
+
+ //
+ // Acknowledge the original request.
+ //
+ USBDevEndpoint0DataAck(false);
+
+ //
+ // How much data is available to be sent?
+ //
+ ui32Available = (g_sNextUpload.ui32Length +
+ (bAppendHeader ? sizeof(tDFUDownloadProgHeader) : 0));
+
+ //
+ // How much data can we send? This is the smallest of the maximum transfer
+ // size, the requested length or the available data.
+ //
+ ui16ToSend =
+ (ui16Length > DFU_TRANSFER_SIZE) ? DFU_TRANSFER_SIZE : ui16Length;
+ ui16ToSend =
+ ((uint32_t)ui16ToSend > ui32Available) ? ui32Available : ui16ToSend;
+
+ //
+ // If we have been asked to send a header, we need to copy some of the data
+ // into a buffer and send from there. If we don't do this, we run the risk
+ // of sending a long packet prematurely and ending the upload before it is
+ // complete.
+ //
+ if(bAppendHeader)
+ {
+ tDFUDownloadProgHeader *psHdr;
+ uint8_t *pui8From;
+ uint8_t *pui8To;
+ uint32_t ui32Loop;
+
+ //
+ // We are appending a header so write the header information into a
+ // buffer then copy the first chunk of data from its original position
+ // into the same buffer.
+ //
+ psHdr = (tDFUDownloadProgHeader *)g_pui8DFUBuffer;
+
+ //
+ // Build the header.
+ //
+ psHdr->ui8Command = DFU_CMD_PROG;
+ psHdr->ui8Reserved = 0;
+ psHdr->ui16StartAddr = ((uint32_t)(g_sNextUpload.pui8Start) / 1024);
+ psHdr->ui32Length = g_sNextUpload.ui32Length;
+
+ //
+ // Copy the remainder of the first transfer's data from its original
+ // position.
+ //
+ pui8From = g_sNextUpload.pui8Start;
+ pui8To = (uint8_t *)(psHdr + 1);
+ for(ui32Loop = (ui16ToSend - sizeof(tDFUDownloadProgHeader)); ui32Loop;
+ ui32Loop--)
+ {
+ *pui8To++ = *pui8From++;
+ }
+
+ //
+ // Send the data.
+ //
+ USBBLSendDataEP0((uint8_t *)psHdr, ui16ToSend);
+
+ //
+ // Update our upload pointer and length.
+ //
+ g_sNextUpload.pui8Start += ui16ToSend - sizeof(tDFUDownloadProgHeader);
+ g_sNextUpload.ui32Length -=
+ ui16ToSend - sizeof(tDFUDownloadProgHeader);
+ }
+ else
+ {
+ //
+ // We are not sending a header so send the requested upload data back
+ // to the host directly from its original position.
+ //
+ USBBLSendDataEP0(g_sNextUpload.pui8Start, ui16ToSend);
+
+ //
+ // Update our upload pointer and length.
+ //
+ g_sNextUpload.pui8Start += ui16ToSend;
+ g_sNextUpload.ui32Length -= ui16ToSend;
+ }
+
+ //
+ // We return true if we sent a full packet (containing the maximum transfer
+ // size bytes) or false to indicate that a long packet was sent or no more
+ // data remains.
+ //
+ return(((ui16ToSend == DFU_TRANSFER_SIZE) && g_sNextUpload.ui32Length) ?
+ true : false);
+}
+
+//*****************************************************************************
+//
+// Send the current state back to the host.
+//
+//*****************************************************************************
+void
+SendDFUState(void)
+{
+ //
+ // Acknowledge the original request.
+ //
+ USBDevEndpoint0DataAck(false);
+
+ //
+ // Update the status structure with the current state.
+ //
+ g_sDFUStatus.bState = (uint8_t)g_eDFUState;
+
+ //
+ // Send the state from the status structure back to the host.
+ //
+ USBBLSendDataEP0((uint8_t *)&g_sDFUStatus.bState, 1);
+}
+
+//*****************************************************************************
+//
+//! Handle USB requests sent to the DFU device.
+//!
+//! \param psUSBRequest is a pointer to the USB request that the device has
+//! been sent.
+//!
+//! This function is called to handle all non-standard requests received
+//! by the device. This will include all the DFU endpoint 0 commands along
+//! with the TIVA-specific request we use to query whether the device
+//! supports our flavor of the DFU binary format. Incoming DFU requests are
+//! processed by request handlers specific to the particular state of the DFU
+//! connection. This state machine implementation is chosen to keep the
+//! software as close as possible to the USB DFU class documentation.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+HandleRequests(tUSBRequest *psUSBRequest)
+{
+ //
+ // This request is used by the host to determine whether the connected
+ // device supports the TIVA protocol extensions to DFU (our
+ // DFU_CMD_xxxx command headers passed alongside DNLOAD requests). We
+ // check the parameters and, if they are as expected, we respond with
+ // a 4 byte structure providing a marker and the protocol version
+ // number.
+ //
+ if(psUSBRequest->bRequest == USBD_DFU_REQUEST_TIVA)
+ {
+ //
+ // Check that the request parameters are all as expected. We are
+ // using the wValue value merely as a way of making it less likely
+ // that we respond to another vendor's device-specific request.
+ //
+ if((psUSBRequest->wLength == sizeof(tDFUQueryTIVAProtocol)) &&
+ (psUSBRequest->wValue == REQUEST_TIVA_VALUE))
+ {
+ //
+ // Acknowledge the original request.
+ //
+ USBDevEndpoint0DataAck(false);
+
+ //
+ // Send the status structure back to the host.
+ //
+ USBBLSendDataEP0((uint8_t *)&g_sDFUProtocol,
+ sizeof(tDFUQueryTIVAProtocol));
+ }
+ else
+ {
+ //
+ // The request parameters were not as expected so we assume
+ // that this is not our request and stall the endpoint to
+ // indicate an error.
+ //
+ USBBLStallEP0();
+ }
+
+ return;
+ }
+
+ //
+ // Pass the request to the relevant handler depending upon our current
+ // state. If no handler is configured, we stall the endpoint since this
+ // implies that requests can't be handled in this state.
+ //
+ if(g_pfnRequestHandlers[g_eDFUState])
+ {
+ //
+ // Dispatch the request to the relevant handler depending upon the
+ // current state.
+ //
+ (g_pfnRequestHandlers[g_eDFUState])(psUSBRequest);
+ }
+ else
+ {
+ USBBLStallEP0();
+ }
+}
+
+//*****************************************************************************
+//
+// Handle all incoming DFU requests while in state STATE_IDLE.
+//
+//*****************************************************************************
+void
+HandleRequestIdle(tUSBRequest *psUSBRequest)
+{
+ switch(psUSBRequest->bRequest)
+ {
+ //
+ // This is a download request. We need to request the transaction
+ // payload unless this is a zero length request in which case we mark
+ // the error by stalling the endpoint.
+ //
+ case USBD_DFU_REQUEST_DNLOAD:
+ {
+ if(psUSBRequest->wLength)
+ {
+ USBBLRequestDataEP0(g_pui8DFUBuffer, psUSBRequest->wLength);
+ }
+ else
+ {
+ USBBLStallEP0();
+ return;
+ }
+ break;
+ }
+
+ //
+ // This is an upload request. We send back a block of data
+ // corresponding to the current upload pointer as held in
+ // g_sNextUpload.
+ //
+ case USBD_DFU_REQUEST_UPLOAD:
+ {
+ //
+ // If we have any upload data to send, send it. Make sure we append
+ // a header if required.
+ //
+ if(SendUploadData(psUSBRequest->wLength,
+ g_bSuppressUploadHeader ? false :
+ !g_bUploadBinary))
+ {
+ //
+ // We sent a full (max packet size) frame to the host so
+ // transition to UPLOAD_IDLE state since we expect another
+ // upload request to continue the process.
+ //
+ g_eDFUState = STATE_UPLOAD_IDLE;
+ }
+
+ //
+ // Clear the flag we use to suppress sending the DFU header.
+ //
+ g_bSuppressUploadHeader = false;
+
+ return;
+ }
+
+ //
+ // Return the current device status structure.
+ //
+ case USBD_DFU_REQUEST_GETSTATUS:
+ {
+ SendDFUStatus();
+ return;
+ }
+
+ //
+ // Return the current device state.
+ //
+ case USBD_DFU_REQUEST_GETSTATE:
+ {
+ SendDFUState();
+ return;
+ }
+
+ //
+ // Ignore the ABORT request. This returns us to IDLE state but we're
+ // there already.
+ //
+ case USBD_DFU_REQUEST_ABORT:
+ {
+ break;
+ }
+
+ //
+ // All other requests are illegal in this state so signal the error
+ // by stalling the endpoint.
+ //
+ case USBD_DFU_REQUEST_CLRSTATUS:
+ case USBD_DFU_REQUEST_DETACH:
+ default:
+ {
+ USBBLStallEP0();
+ return;
+ }
+ }
+
+ //
+ // If we drop out of the switch, we need to ACK the received request.
+ //
+ USBDevEndpoint0DataAck(false);
+}
+
+//*****************************************************************************
+//
+// Handle all incoming DFU requests while in state STATE_DNLOAD_SYNC or
+// STATE_DNBUSY.
+//
+//*****************************************************************************
+void
+HandleRequestDnloadSync(tUSBRequest *psUSBRequest)
+{
+ //
+ // In this state, we have received a block of the download and are waiting
+ // for a USBD_DFU_REQUEST_GETSTATUS which will trigger a return
+ // to STATE_DNLOAD_IDLE assuming we have finished programming the block.
+ // If the last command we received was not DFU_CMD_PROG, we transition
+ // directly from this state back to STATE_IDLE once the last operation has
+ // completed since we need to be able to accept a new command.
+ //
+ switch(psUSBRequest->bRequest)
+ {
+ //
+ // The host is requesting the current device status. Return this and
+ // revert to STATE_IDLE.
+ //
+ case USBD_DFU_REQUEST_GETSTATUS:
+ {
+ //
+ // Are we finished processing whatever the last flash-operation
+ // was? Note that we don't support DNLOAD_BUSY state in this
+ // implementation, we merely continue to report DNLOAD_SYNC state
+ // until we are finished with the command.
+ //
+ if(!g_ui32CommandFlags)
+ {
+ //
+ // If we are in the middle of a programming operation,
+ // transition back to DNLOAD_IDLE state to wait for the
+ // next block. If not, go back to idle since we expect a
+ // new command.
+ //
+ g_eDFUState = ((g_ui8LastCommand == DFU_CMD_PROG) ?
+ STATE_DNLOAD_IDLE : STATE_IDLE);
+ }
+
+ //
+ // Send the latest status back to the host.
+ //
+ SendDFUStatus();
+
+ //
+ // Return here since we've already ACKed the request.
+ //
+ return;
+ }
+
+ //
+ // The host is requesting the current device state.
+ //
+ case USBD_DFU_REQUEST_GETSTATE:
+ {
+ //
+ // Are we currently in DNLOAD_SYNC state?
+ //
+ if(g_eDFUState == STATE_DNLOAD_SYNC)
+ {
+ //
+ // Yes - send back the state.
+ //
+ SendDFUState();
+ }
+ else
+ {
+ //
+ // In STATE_BUSY, we can't respond to any requests so stall
+ // the endpoint.
+ //
+ USBBLStallEP0();
+ }
+
+ //
+ // Return here since the incoming request has already been either
+ // ACKed or stalled by the processing above.
+ //
+ return;
+ }
+
+ //
+ // Any other request is ignored and causes us to stall the control
+ // endpoint and remain in STATE_ERROR.
+ //
+ default:
+ {
+ USBBLStallEP0();
+ return;
+ }
+ }
+}
+
+//*****************************************************************************
+//
+// Handle all incoming DFU requests while in state STATE_DNLOAD_IDLE.
+//
+//*****************************************************************************
+void
+HandleRequestDnloadIdle(tUSBRequest *psUSBRequest)
+{
+ switch(psUSBRequest->bRequest)
+ {
+ //
+ // This is a download request. We need to request the transaction
+ // payload unless this is a zero length request in which case we mark
+ // the error by stalling the endpoint.
+ //
+ case USBD_DFU_REQUEST_DNLOAD:
+ {
+ //
+ // Are we being passed data to program?
+ //
+ if(psUSBRequest->wLength)
+ {
+ //
+ // Yes - request the data.
+ //
+ USBBLRequestDataEP0(g_pui8DFUBuffer, psUSBRequest->wLength);
+ }
+ else
+ {
+ //
+ // No - this is the signal that a download operation is
+ // complete. Do we agree?
+ //
+ if(g_sNextDownload.ui32Length)
+ {
+ //
+ // We think there should still be some data to be received
+ // so mark this as an error.
+ //
+ g_eDFUState = STATE_ERROR;
+ g_eDFUStatus = STATUS_ERR_NOTDONE;
+ }
+ else
+ {
+ //
+ // We agree that the download has completed. Enter state
+ // STATE_MANIFEST_SYNC.
+ //
+ g_eDFUState = STATE_MANIFEST_SYNC;
+ }
+ }
+ break;
+ }
+
+ //
+ // Return the current device status structure.
+ //
+ case USBD_DFU_REQUEST_GETSTATUS:
+ {
+ SendDFUStatus();
+ return;
+ }
+
+ //
+ // Return the current device state.
+ //
+ case USBD_DFU_REQUEST_GETSTATE:
+ {
+ SendDFUState();
+ return;
+ }
+
+ //
+ // An ABORT request causes us to abort the current transfer and
+ // return the the idle state regardless of the state of the previous
+ // programming operation.
+ //
+ case USBD_DFU_REQUEST_ABORT:
+ {
+ //
+ // Default to downloading the main code image.
+ //
+ g_sNextDownload.pui8Start =
+ (uint8_t *)g_sDFUDeviceInfo.ui32AppStartAddr;
+ g_sNextDownload.ui32Length = (g_sDFUDeviceInfo.ui32FlashTop -
+ g_sDFUDeviceInfo.ui32AppStartAddr);
+ g_eDFUState = STATE_IDLE;
+ break;
+ }
+
+ //
+ // All other requests are illegal in this state so signal the error
+ // by stalling the endpoint.
+ //
+ case USBD_DFU_REQUEST_CLRSTATUS:
+ case USBD_DFU_REQUEST_DETACH:
+ case USBD_DFU_REQUEST_UPLOAD:
+ default:
+ {
+ USBBLStallEP0();
+ return;
+ }
+ }
+
+ //
+ // If we drop out of the switch, we need to ACK the received request.
+ //
+ USBDevEndpoint0DataAck(false);
+}
+
+//*****************************************************************************
+//
+// Handle all incoming DFU requests while in state STATE_MANIFEST_SYNC.
+//
+//*****************************************************************************
+void
+HandleRequestManifestSync(tUSBRequest *psUSBRequest)
+{
+ //
+ // In this state, we have received the last block of a download and are
+ // waiting for a USBD_DFU_REQUEST_GETSTATUS which will trigger a return
+ // to STATE_IDLE.
+ //
+ switch(psUSBRequest->bRequest)
+ {
+ //
+ // The host is requesting the current device status. Return this and
+ // revert to STATE_IDLE.
+ //
+ case USBD_DFU_REQUEST_GETSTATUS:
+ {
+ g_eDFUState = STATE_IDLE;
+ SendDFUStatus();
+ break;
+ }
+
+ //
+ // The host is requesting the current device state.
+ //
+ case USBD_DFU_REQUEST_GETSTATE:
+ {
+ SendDFUState();
+ break;
+ }
+
+ //
+ // Any other request is ignored and causes us to stall the control
+ // endpoint and remain in STATE_MANIFEST_SYNC.
+ //
+ default:
+ {
+ USBBLStallEP0();
+ break;
+ }
+ }
+}
+
+//*****************************************************************************
+//
+// Handle all incoming DFU requests while in state STATE_UPLOAD_IDLE.
+//
+//*****************************************************************************
+void
+HandleRequestUploadIdle(tUSBRequest *psUSBRequest)
+{
+ //
+ // In this state, we have already received the first upload request. What
+ // are we being asked to do now?
+ //
+ switch(psUSBRequest->bRequest)
+ {
+ //
+ // The host is requesting more upload data.
+ //
+ case USBD_DFU_REQUEST_UPLOAD:
+ {
+ //
+ // See if there is any more data to transfer and, if there is,
+ // send it back to the host.
+ //
+ if(!SendUploadData(psUSBRequest->wLength, false))
+ {
+ //
+ // We sent less than a full packet of data so the transfer is
+ // complete. Revert to idle state and ensure that we reset
+ // our upload pointer and size to the default flash region.
+ //
+ g_eDFUState = STATE_IDLE;
+ g_sNextUpload.pui8Start =
+ (uint8_t *)g_sDFUDeviceInfo.ui32AppStartAddr;
+ g_sNextUpload.ui32Length = (g_sDFUDeviceInfo.ui32FlashTop -
+ g_sDFUDeviceInfo.ui32AppStartAddr);
+ }
+ break;
+ }
+
+ //
+ // The host is requesting the current device status.
+ //
+ case USBD_DFU_REQUEST_GETSTATUS:
+ {
+ SendDFUStatus();
+ break;
+ }
+
+ //
+ // The host is requesting the current device state.
+ //
+ case USBD_DFU_REQUEST_GETSTATE:
+ {
+ SendDFUState();
+ break;
+ }
+
+ //
+ // The host is requesting that we abort the current upload.
+ //
+ case USBD_DFU_REQUEST_ABORT:
+ {
+ //
+ // Default to sending the main application image for the next
+ // upload.
+ //
+ g_sNextUpload.pui8Start =
+ (uint8_t *)g_sDFUDeviceInfo.ui32AppStartAddr;
+ g_sNextUpload.ui32Length = (g_sDFUDeviceInfo.ui32FlashTop -
+ g_sDFUDeviceInfo.ui32AppStartAddr);
+ g_eDFUState = STATE_IDLE;
+ break;
+ }
+
+ //
+ // Any other request is ignored and causes us to stall the control
+ // endpoint and remain in STATE_ERROR.
+ //
+ default:
+ {
+ USBBLStallEP0();
+ break;
+ }
+ }
+}
+
+//*****************************************************************************
+//
+// Handle all incoming DFU requests while in state STATE_ERROR.
+//
+//*****************************************************************************
+void
+HandleRequestError(tUSBRequest *psUSBRequest)
+{
+ //
+ // In this state, we respond to state and status requests and also to
+ // USBD_DFU_REQUEST_CLRSTATUS which clears the previous error condition.
+ //
+ switch(psUSBRequest->bRequest)
+ {
+ //
+ // The host is requesting the current device status.
+ //
+ case USBD_DFU_REQUEST_GETSTATUS:
+ {
+ SendDFUStatus();
+ break;
+ }
+
+ //
+ // The host is requesting the current device state.
+ //
+ case USBD_DFU_REQUEST_GETSTATE:
+ {
+ SendDFUState();
+ break;
+ }
+
+ //
+ // The host is asking us to clear our previous error condition and
+ // revert to idle state in preparation to receive new commands.
+ //
+ case USBD_DFU_REQUEST_CLRSTATUS:
+ {
+ g_eDFUState = STATE_IDLE;
+ g_eDFUStatus = STATUS_OK;
+ USBDevEndpoint0DataAck(false);
+ break;
+ }
+
+ //
+ // Any other request is ignored and causes us to stall the control
+ // endpoint and remain in STATE_ERROR.
+ //
+ default:
+ {
+ USBBLStallEP0();
+ break;
+ }
+ }
+}
+
+//*****************************************************************************
+//
+// Handle cases where the host sets a new USB configuration.
+//
+//*****************************************************************************
+void
+HandleConfigChange(uint32_t ui32Info)
+{
+ //
+ // Revert to idle state.
+ //
+ g_eDFUState = STATE_IDLE;
+ g_eDFUStatus = STATUS_OK;
+}
+
+//*****************************************************************************
+//
+// Setting the device address indicates that we are now connected to the host
+// and can expect some DFU communication so we use this opportunity to clean
+// out our state just in case we were not idle last time the host disconnected.
+//
+//*****************************************************************************
+void
+HandleSetAddress(void)
+{
+ g_eDFUState = STATE_IDLE;
+ g_eDFUStatus = STATUS_OK;
+ g_bAddressSet = true;
+
+ //
+ // Default the download address to the app start address and valid length
+ // to the whole of the programmable flash area.
+ //
+ g_sNextDownload.pui8Start =
+ (uint8_t *)g_sDFUDeviceInfo.ui32AppStartAddr;
+ g_sNextDownload.ui32Length = (g_sDFUDeviceInfo.ui32FlashTop -
+ g_sDFUDeviceInfo.ui32AppStartAddr);
+
+ //
+ // Default the upload address to the app start address and valid length
+ // to the whole of the programmable flash area.
+ //
+ g_sNextUpload.pui8Start =
+ (uint8_t *)g_sDFUDeviceInfo.ui32AppStartAddr;
+ g_sNextUpload.ui32Length = (g_sDFUDeviceInfo.ui32FlashTop -
+ g_sDFUDeviceInfo.ui32AppStartAddr);
+}
+
+//*****************************************************************************
+//
+// Check that a range of addresses passed is within the region of flash that
+// the boot loader is allowed to access.
+//
+// Returns true if the address range is accessible or false otherwise.
+//
+//*****************************************************************************
+bool
+FlashRangeCheck(uint32_t ui32Start, uint32_t ui32Length)
+{
+#ifdef ENABLE_BL_UPDATE
+ if((ui32Length <=
+ (g_sDFUDeviceInfo.ui32FlashTop - g_sDFUDeviceInfo.ui32AppStartAddr)) &&
+ ((ui32Start + ui32Length) <= g_sDFUDeviceInfo.ui32FlashTop))
+#else
+ if((ui32Start >= g_sDFUDeviceInfo.ui32AppStartAddr) &&
+ (ui32Length <=
+ (g_sDFUDeviceInfo.ui32FlashTop - g_sDFUDeviceInfo.ui32AppStartAddr)) &&
+ ((ui32Start + ui32Length) <= g_sDFUDeviceInfo.ui32FlashTop))
+#endif
+ {
+ //
+ // The block passed lies wholly within the flash address range of
+ // this device.
+ //
+ return(true);
+ }
+ else
+ {
+ //
+ // We were passed an address that is out of range so set the
+ // appropriate status code.
+ //
+ g_eDFUStatus = STATUS_ERR_ADDRESS;
+ return(false);
+ }
+}
+
+//*****************************************************************************
+//
+//! Process TIVA-specific commands passed via DFU download requests.
+//!
+//! \param psCmd is a pointer to the first byte of the \b DFU_DNLOAD payload
+//! that is expected to hold a command.
+//! \param ui32Size is the number of bytes of data pointed to by \e psCmd.
+//! This function is called when a DFU download command is received while in
+//! \b STATE_IDLE. New downloads are assumed to contain a prefix structure
+//! containing one of several TIVA-specific commands and this function
+//! is responsible for parsing the download data and processing whichever
+//! command is contained within it.
+//!
+//! \return Returns \b true on success or \b false on failure.
+//
+//*****************************************************************************
+bool
+ProcessDFUDnloadCommand(tDFUDownloadHeader *psCmd, uint32_t ui32Size)
+{
+ //
+ // Make sure we got enough data to contain a valid command header.
+ //
+ if(ui32Size < sizeof(tDFUDownloadHeader))
+ {
+ return(false);
+ }
+
+ //
+ // Remember the command that we have been passed since we will need thi
+ // to determine which state to transition to on exit from STATE_DNLOAD_SYNC.
+ //
+ g_ui8LastCommand = psCmd->ui8Command;
+
+ //
+ // Which command have we been passed?
+ //
+ switch(psCmd->ui8Command)
+ {
+ //
+ // We are being asked to start a programming operation.
+ //
+ case DFU_CMD_PROG:
+ {
+ tDFUDownloadProgHeader *psHdr;
+
+ //
+ // Extract the address and size from the command header.
+ //
+ psHdr = (tDFUDownloadProgHeader *)psCmd;
+
+ //
+ // Is the passed address range valid?
+ //
+ if(BL_FLASH_AD_CHECK_FN_HOOK(psHdr->ui16StartAddr * 1024,
+ psHdr->ui32Length))
+ {
+ //
+ // Yes - remember the range passed so that we will write the
+ // passed data to the correct place.
+ //
+ g_sNextDownload.pui8Start =
+ (uint8_t *)(psHdr->ui16StartAddr * 1024);
+ g_sNextDownload.ui32Length = psHdr->ui32Length;
+
+ //
+ // If we have been provided with a progress reporting hook
+ // function, remember the total length of the image so that
+ // we can report this later.
+ //
+#ifdef BL_PROGRESS_FN_HOOK
+ g_ui32ImageSize = psHdr->ui32Length;
+#endif
+
+ //
+ // Also set the upload address and size to match this download
+ // so that, by default, the host will get back what it just
+ // wrote if it performs an upload without an intermediate
+ // DFU_CMD_READ to set the address and size.
+ //
+ g_sNextUpload.pui8Start =
+ (uint8_t *)(psHdr->ui16StartAddr * 1024);
+ g_sNextUpload.ui32Length = psHdr->ui32Length;
+
+ //
+ // Also remember that we have data in this packet to write.
+ //
+ g_pui8DFUWrite = (uint8_t *)(psHdr + 1);
+ g_ui16DFUBufferUsed = ui32Size - sizeof(tDFUDownloadHeader);
+
+ //
+ // If a start signal hook function has been provided, call it
+ // here since we are about to start a new download.
+ //
+#ifdef BL_START_FN_HOOK
+ BL_START_FN_HOOK();
+#endif
+
+ //
+ // If FLASH_CODE_PROTECTION is defined in bl_config.h we
+ // erase the whole application area at this point before we
+ // start to flash the new image.
+ //
+#ifdef FLASH_CODE_PROTECTION
+ g_sErase.pui8Start =
+ (uint8_t *)g_sDFUDeviceInfo.ui32AppStartAddr;
+
+ g_sErase.ui32Length = (g_sDFUDeviceInfo.ui32FlashTop -
+ g_sDFUDeviceInfo.ui32AppStartAddr);
+ HWREGBITW(&g_ui32CommandFlags, CMD_FLAG_ERASE) = 1;
+#endif
+
+ //
+ // Tell the main thread to write the data we just received it.
+ //
+ HWREGBITW(&g_ui32CommandFlags, CMD_FLAG_WRITE) = 1;
+ }
+ else
+ {
+ //
+ // The flash range was invalid so switch to error state.
+ //
+ return(false);
+ }
+ break;
+ }
+
+ //
+ // We are being passed the position and size of a block of flash to
+ // return in a following upload operation.
+ //
+ case DFU_CMD_READ:
+ {
+ tDFUDownloadReadCheckHeader *psHdr;
+
+ //
+ // Extract the address and size from the command header.
+ //
+ psHdr = (tDFUDownloadReadCheckHeader *)psCmd;
+
+ //
+ // Is the passed address range valid?
+ //
+ if(FlashRangeCheck(psHdr->ui16StartAddr * 1024, psHdr->ui32Length))
+ {
+ //
+ // Yes - remember the range passed so that we will return
+ // this block of flash on the next upload request.
+ //
+ g_sNextUpload.pui8Start =
+ (uint8_t *)(psHdr->ui16StartAddr * 1024);
+ g_sNextUpload.ui32Length = psHdr->ui32Length;
+ }
+ else
+ {
+ //
+ // The flash range was invalid so switch to error state.
+ //
+ return(false);
+ }
+ break;
+ }
+
+ //
+ // We are being passed the position and size of a block of flash which
+ // we will check to ensure that it is erased.
+ //
+ case DFU_CMD_CHECK:
+ {
+ tDFUDownloadReadCheckHeader *psHdr;
+ uint32_t *pui32Check;
+ uint32_t ui32Loop;
+
+ //
+ // Extract the address and size from the command header.
+ //
+ psHdr = (tDFUDownloadReadCheckHeader *)psCmd;
+
+ //
+ // Make sure the range we have been passed is within the area of
+ // flash that we are allowed to look at.
+ //
+ if(FlashRangeCheck(psHdr->ui16StartAddr * 1024, psHdr->ui32Length))
+ {
+ //
+ // The range is valid so perform the check here.
+ //
+ pui32Check = (uint32_t *)(psHdr->ui16StartAddr * 1024);
+
+ //
+ // Check each word in the range to ensure that it is erased. If
+ // not, set the error status and return.
+ //
+ for(ui32Loop = 0; ui32Loop < (psHdr->ui32Length / 4);
+ ui32Loop++)
+ {
+ if(*pui32Check != 0xFFFFFFFF)
+ {
+ g_eDFUStatus = STATUS_ERR_CHECK_ERASED;
+ return(false);
+ }
+ pui32Check++;
+ }
+
+ //
+ // If we get here, the check passed so set the status to
+ // indicate this.
+ //
+ g_eDFUStatus = STATUS_OK;
+ }
+ else
+ {
+ //
+ // The flash range was invalid so switch to error state.
+ //
+ return(false);
+ }
+ break;
+ }
+
+ //
+ // We are being asked to erase a block of flash.
+ //
+ case DFU_CMD_ERASE:
+ {
+ tDFUDownloadEraseHeader *psHdr;
+
+ //
+ // Extract the address and size from the command header.
+ //
+ psHdr = (tDFUDownloadEraseHeader *)psCmd;
+
+ //
+ // Make sure the range we have been passed is within the area of
+ // flash that we are allowed to look at.
+ //
+ if(FlashRangeCheck((uint32_t)psHdr->ui16StartAddr * 1024,
+ ((uint32_t)psHdr->ui16NumBlocks *
+ DFU_REPORTED_PAGE_SIZE )))
+ {
+ //
+ // The range is valid so tell the main loop to erase the
+ // block.
+ //
+ g_sErase.pui8Start = (uint8_t *)
+ ((uint32_t)psHdr->ui16StartAddr * 1024);
+ g_sErase.ui32Length = ((uint32_t)psHdr->ui16NumBlocks *
+ DFU_REPORTED_PAGE_SIZE);
+ HWREGBITW(&g_ui32CommandFlags, CMD_FLAG_ERASE) = 1;
+ }
+ else
+ {
+ //
+ // The flash range was invalid so switch to error state.
+ //
+ return(false);
+ }
+ break;
+ }
+
+ //
+ // We are being asked to send back device information on the next
+ // upload request.
+ //
+ case DFU_CMD_INFO:
+ {
+ //
+ // Register that we need to send the device info structure on the
+ // next upload request.
+ //
+ g_sNextUpload.pui8Start = (uint8_t *)&g_sDFUDeviceInfo;
+ g_sNextUpload.ui32Length = sizeof(tDFUDeviceInfo);
+
+ //
+ // Make sure we don't append the DFU_CMD_PROG header when we send
+ // back the data.
+ //
+ g_bSuppressUploadHeader = true;
+ break;
+ }
+
+ //
+ // We are being asked to set the format of uploaded images.
+ //
+ case DFU_CMD_BIN:
+ {
+ tDFUDownloadBinHeader *psHdr;
+
+ //
+ // Extract the required format the command header.
+ //
+ psHdr = (tDFUDownloadBinHeader *)psCmd;
+
+ //
+ // Set the global format appropriately.
+ //
+ g_bUploadBinary = psHdr->bBinary ? true : false;
+ break;
+ }
+
+ //
+ // We are being asked to prepare to reset the board and, as a result,
+ // run the main application image.
+ //
+ case DFU_CMD_RESET:
+ {
+ //
+ // Tell the main thread that it's time to go bye-bye...
+ //
+ HWREGBITW(&g_ui32CommandFlags, CMD_FLAG_RESET) = 1;
+
+ break;
+ }
+
+ //
+ // We have been passed an unrecognized command identifier so report an
+ // error.
+ //
+ default:
+ {
+ g_eDFUStatus = STATUS_ERR_VENDOR;
+ return(false);
+ }
+ }
+
+ return(true);
+}
+
+//*****************************************************************************
+//
+// This callback function is called when data is received for the DATA phase
+// of an EP0 OUT transaction. This data will either be a block of download
+// data (if we are in STATE_DNLOAD_IDLE) or a new command (if we are in
+// STATE_IDLE).
+//
+//*****************************************************************************
+void
+HandleEP0Data(uint32_t ui32Size)
+{
+ bool bRetcode;
+
+ if(g_eDFUState == STATE_IDLE)
+ {
+ //
+ // This must be a new DFU download command header so parse it and
+ // determine what to do next.
+ //
+ bRetcode =
+ ProcessDFUDnloadCommand((tDFUDownloadHeader *)g_pui8DFUBuffer,
+ ui32Size);
+
+ //
+ // Did we receive a recognized and valid command?
+ //
+ if(!bRetcode)
+ {
+ //
+ // No - set the error state. The status is set within the
+ // ProcessDFUDnloadCommand() function.
+ //
+ g_eDFUState = STATE_ERROR;
+ return;
+ }
+ }
+ else
+ {
+ //
+ // If we are not in STATE_IDLE, this must be a block of data for an
+ // ongoing download so signal the main thread to write it to flash.
+ //
+ g_ui16DFUBufferUsed = (uint16_t)ui32Size;
+ g_pui8DFUWrite = g_pui8DFUBuffer;
+
+ //
+ // Tell the main thread to write the new data.
+ //
+ HWREGBITW(&g_ui32CommandFlags, CMD_FLAG_WRITE) = 1;
+ }
+
+ //
+ // Move to STATE_DNLOAD_SYNC since we now expect USBD_DFU_REQUEST_GETSTATUS
+ // before the next USBD_DFU_REQUEST_DNLOAD.
+ //
+ g_eDFUState = STATE_DNLOAD_SYNC;
+}
+
+//*****************************************************************************
+//
+// Handle bus resets
+//
+// This function is called if the USB controller detects a reset condition on
+// the bus. If we are not in the process of downloading a new image, we use
+// this as a signal to reboot and run the main application image.
+//
+//*****************************************************************************
+void
+HandleReset(void)
+{
+ //
+ // Are we currently in the middle of a download operation?
+ //
+ if((g_eDFUState != STATE_DNLOAD_IDLE) &&
+ (g_eDFUState != STATE_DNLOAD_SYNC) && (g_eDFUState != STATE_IDLE))
+ {
+ //
+ // No - tell the main thread that it should reboot the system assuming
+ // that we are already configured. If we don't check that we are
+ // already configured, this will cause a reset during initial
+ // enumeration and that wouldn't be very helpful.
+ //
+ if(g_bAddressSet)
+ {
+ HWREGBITW(&g_ui32CommandFlags, CMD_FLAG_RESET) = 1;
+ }
+ }
+}
+
+//*****************************************************************************
+//
+// Handle cases where the USB host disconnects.
+//
+//*****************************************************************************
+void
+HandleDisconnect(void)
+{
+ //
+ // For error resilience, it may be desireable to note if the host
+ // disconnects and, if partway through a main image download, clear the
+ // first block of the flash to ensure that the image is not considered
+ // valid on the next boot. For now, however, we merely wait for the host
+ // to connect again, remaining in DFU mode.
+ //
+
+ //
+ // Remember that we are waiting for enumeration.
+ //
+ g_bAddressSet = false;
+}
+
+//*****************************************************************************
+//
+// Erase a single block of flash
+//
+// This function erases a single, 1KB block of flash, returning once the
+// operation has completed.
+//
+// \return None.
+//
+//*****************************************************************************
+static void
+EraseFlashBlock(uint32_t ui32Addr)
+{
+ BL_FLASH_ERASE_FN_HOOK(ui32Addr);
+}
+
+//*****************************************************************************
+//
+//! This is the main routine for handling updating over USB.
+//!
+//! This function forms the main loop of the USB DFU updater. It polls for
+//! commands sent from the USB request handlers and is responsible for
+//! erasing flash blocks, programming data into erased blocks and resetting
+//! the device.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+UpdaterUSB(void)
+{
+ uint32_t ui32Idx, ui32Start, ui32Temp;
+ uint16_t ui16Used;
+#ifndef FLASH_CODE_PROTECTION
+ uint32_t ui32End;
+#endif
+
+ //
+ // Loop forever waiting for the USB interrupt handlers to tell us to do
+ // something.
+ //
+ while(1)
+ {
+ while(g_ui32CommandFlags == 0)
+ {
+ //
+ // Wait for something to do.
+ //
+ }
+
+ //
+ // Are we being asked to perform a system reset?
+ //
+ if(HWREGBITW(&g_ui32CommandFlags, CMD_FLAG_RESET))
+ {
+ //
+ // Time to go bye-bye... This will cause the microcontroller
+ // to reset; no further code will be executed.
+ //
+ HWREG(NVIC_APINT) = NVIC_APINT_VECTKEY | NVIC_APINT_SYSRESETREQ;
+
+ //
+ // The microcontroller should have reset, so this should never be
+ // reached. Just in case, loop forever.
+ //
+ while(1)
+ {
+ }
+ }
+
+ //
+ // Are we being asked to erase a range of blocks in flash?
+ //
+ if(HWREGBITW(&g_ui32CommandFlags, CMD_FLAG_ERASE))
+ {
+ //
+ // Loop through the pages in the block of flash we have been asked
+ // to erase and clear each one.
+ //
+ ui32Temp = g_sErase.ui32Length;
+ for(ui32Idx = (uint32_t)g_sErase.pui8Start;
+ ui32Idx < (uint32_t)(g_sErase.pui8Start + ui32Temp);
+ ui32Idx += FLASH_PAGE_SIZE)
+ {
+ EraseFlashBlock(ui32Idx);
+ }
+
+ //
+ // Clear the command flag to indicate that we are done.
+ //
+ HWREGBITW(&g_ui32CommandFlags, CMD_FLAG_ERASE) = 0;
+ }
+
+ //
+ // Are we being asked to program a block of flash?
+ //
+ if(HWREGBITW(&g_ui32CommandFlags, CMD_FLAG_WRITE))
+ {
+ //
+ // Decrypt the data if required.
+ //
+#ifdef BL_DECRYPT_FN_HOOK
+ BL_DECRYPT_FN_HOOK(g_pui8DFUWrite, g_ui16DFUBufferUsed);
+#endif
+
+ //
+ // Where will the new block be written?
+ //
+ ui32Start = (uint32_t)(g_sNextDownload.pui8Start);
+
+#ifndef FLASH_CODE_PROTECTION
+ //
+ // What is the address of the last byte we will write in this
+ // block of data? We copy g_ui16DFUBufferUsed to prevent warnings
+ // about "undefined order of volatile accesses" from some
+ // compilers.
+ //
+ ui16Used = g_ui16DFUBufferUsed;
+
+ ui32End = (uint32_t)g_sNextDownload.pui8Start + ui16Used - 1;
+
+ //
+ // Are we writing data at the start of a new flash block? If so,
+ // we need to erase the content of the block first.
+ //
+ if((ui32Start & (FLASH_PAGE_SIZE - 1)) == 0)
+ {
+ //
+ // We are writing to the start of a block so erase it.
+ //
+ EraseFlashBlock(ui32Start & ~(FLASH_PAGE_SIZE - 1));
+ }
+ else
+ {
+ //
+ // Will this block of data straddle two flash blocks? If so,
+ // we need to erase the following block.
+ //
+ if((ui32Start & ~(FLASH_PAGE_SIZE - 1)) !=
+ (ui32End & ~(FLASH_PAGE_SIZE - 1)))
+ {
+ EraseFlashBlock(ui32End & ~(FLASH_PAGE_SIZE - 1));
+ }
+ }
+#endif
+
+ //
+ // Write the new block of data to the flash
+ //
+ BL_FLASH_PROGRAM_FN_HOOK(ui32Start, g_pui8DFUWrite, ui16Used);
+
+ //
+ // Update our position and remaining size.
+ //
+ g_sNextDownload.pui8Start += ui16Used;
+ g_sNextDownload.ui32Length -= ui16Used;
+
+ //
+ // Clear the command flag to indicate that we are done.
+ //
+ HWREGBITW(&g_ui32CommandFlags, CMD_FLAG_WRITE) = 0;
+
+ //
+ // If a progress hook function has been provided, call
+ // it here.
+ //
+#ifdef BL_PROGRESS_FN_HOOK
+ BL_PROGRESS_FN_HOOK(g_ui32ImageSize - g_sNextDownload.ui32Length,
+ g_ui32ImageSize);
+#endif
+
+ //
+ // If we just finished the download and an end signal hook function
+ // has been provided, call it too.
+ //
+#ifdef BL_END_FN_HOOK
+ if(g_sNextDownload.ui32Length == 0)
+ {
+ BL_END_FN_HOOK();
+ }
+#endif
+ }
+ }
+}
+
+//*****************************************************************************
+//
+//! Configure the USB controller and place the DFU device on the bus.
+//!
+//! This function configures the USB controller for DFU device operation,
+//! initializes the state machines required to control the firmware update and
+//! places the device on the bus in preparation for requests from the host. It
+//! is assumed that the main system clock has been configured at this point.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+ConfigureUSBInterface(void)
+{
+ uint32_t ui32FlashSize;
+
+ //
+ // Initialize our device information structure.
+ //
+ ui32FlashSize = BL_FLASH_SIZE_FN_HOOK();
+
+ g_sDFUDeviceInfo.ui16FlashBlockSize = DFU_REPORTED_PAGE_SIZE;
+ g_sDFUDeviceInfo.ui16NumFlashBlocks =
+ ui32FlashSize / DFU_REPORTED_PAGE_SIZE;
+ g_sDFUDeviceInfo.ui32ClassInfo = HWREG(SYSCTL_DID0);
+ g_sDFUDeviceInfo.ui32PartInfo = HWREG(SYSCTL_DID1);
+ g_sDFUDeviceInfo.ui32AppStartAddr = APP_START_ADDRESS;
+#ifdef FLASH_RSVD_SPACE
+ g_sDFUDeviceInfo.ui32FlashTop = ui32FlashSize - FLASH_RSVD_SPACE;
+#else
+ g_sDFUDeviceInfo.ui32FlashTop = ui32FlashSize;
+#endif
+
+ //
+ // Publish our DFU device descriptors and place the device on the bus.
+ //
+ USBBLInit();
+}
+
+#if (defined USB_HAS_MUX) || (defined DOXYGEN)
+//*****************************************************************************
+//
+//! Configures and set the mux selecting USB device-mode operation.
+//!
+//! On target boards which use a multiplexer to switch between USB host and
+//! device operation, this function is used to configure the relevant GPIO
+//! pin and drive it such that the mux selects USB device-mode operation.
+//! If \b USB_HAS_MUX is not defined in bl_config.h, this function is compiled
+//! out.
+//!
+//! \return None.
+//
+//*****************************************************************************
+static void
+SetUSBMux(void)
+{
+ //
+ // Enable the GPIO peripheral that contains the mux control pin.
+ //
+ HWREG(SYSCTL_RCGC2) |= USB_MUX_PERIPH;
+
+ //
+ // Delay a very short period before we access the newly-enabled peripheral.
+ //
+ Delay(1);
+
+ //
+ // Make the pin be an output.
+ //
+ HWREG(USB_MUX_PORT + GPIO_O_DIR) |= (1 << USB_MUX_PIN);
+ HWREG(USB_MUX_PORT + GPIO_O_AFSEL) &= ~(1 << USB_MUX_PIN);
+
+ //
+ // Set the output drive strength to 2mA.
+ //
+ HWREG(USB_MUX_PORT + GPIO_O_DR2R) |= (1 << USB_MUX_PIN);
+ HWREG(USB_MUX_PORT + GPIO_O_DR4R) &= ~(1 << USB_MUX_PIN);
+ HWREG(USB_MUX_PORT + GPIO_O_DR8R) &= ~(1 << USB_MUX_PIN);
+ HWREG(USB_MUX_PORT + GPIO_O_SLR) &= ~(1 << USB_MUX_PIN);
+
+ //
+ // Set the pin type to a normal, GPIO output.
+ //
+ HWREG(USB_MUX_PORT + GPIO_O_ODR) &= ~(1 << USB_MUX_PIN);
+ HWREG(USB_MUX_PORT + GPIO_O_PUR) &= ~(1 << USB_MUX_PIN);
+ HWREG(USB_MUX_PORT + GPIO_O_PDR) &= ~(1 << USB_MUX_PIN);
+ HWREG(USB_MUX_PORT + GPIO_O_DEN) |= (1 << USB_MUX_PIN);
+
+ //
+ // Clear this pin's bit in the analog mode select register.
+ //
+ HWREG(USB_MUX_PORT + GPIO_O_AMSEL) &= ~(1 << USB_MUX_PIN);
+
+ //
+ // Write the pin to the appropriate level to select USB device mode.
+ //
+ HWREG(USB_MUX_PORT + (GPIO_O_DATA + ((1 << USB_MUX_PIN) << 2))) =
+ (USB_MUX_DEVICE ? (1 << USB_MUX_PIN) : 0);
+}
+#endif
+
+//*****************************************************************************
+//
+//! Generic configuration is handled in this function.
+//!
+//! This function is called by the start up code to perform any configuration
+//! necessary before calling the update routine. It is responsible for setting
+//! the system clock to the expected rate and setting flash programming
+//! parameters prior to calling ConfigureUSBInterface() to set up the USB
+//! hardware and place the DFU device on the bus.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+ConfigureUSB(void)
+{
+ //
+ // Enable the main oscillator.
+ //
+ HWREG(SYSCTL_RCC) &= ~(SYSCTL_RCC_MOSCDIS);
+
+ //
+ // Delay while the main oscillator starts up.
+ //
+ Delay(524288);
+
+ //
+ // Set the crystal frequency, switch to the main oscillator, and enable the
+ // PLL.
+ //
+ HWREG(SYSCTL_RCC) = ((HWREG(SYSCTL_RCC) &
+ ~(SYSCTL_RCC_PWRDN | SYSCTL_RCC_XTAL_M |
+ SYSCTL_RCC_OSCSRC_M)) |
+ XTAL_VALUE | SYSCTL_RCC_OSCSRC_MAIN);
+
+ //
+ // Delay while the PLL locks.
+ //
+ Delay(524288);
+
+ //
+ // Disable the PLL bypass so that the part is clocked from the PLL, and set
+ // sysdiv to 8. This yields a system clock of 25MHz.
+ //
+ HWREG(SYSCTL_RCC) = ((HWREG(SYSCTL_RCC) & ~(SYSCTL_RCC_BYPASS |
+ SYSCTL_RCC_SYSDIV_M)) |
+ ((8 - 1) << SYSCTL_RCC_SYSDIV_S) |
+ SYSCTL_RCC_USESYSDIV);
+
+ //
+ // If the target device has a mux to allow selection of USB host or
+ // device mode, make sure this is set to device mode.
+ //
+#ifdef USB_HAS_MUX
+ SetUSBMux();
+#endif
+
+ //
+ // Configure the USB interface and put the device on the bus.
+ //
+ ConfigureUSBInterface();
+}
+
+//*****************************************************************************
+//
+//! This is the application entry point to the USB updater.
+//!
+//! This function should only be entered from a running application and not
+//! when running the boot loader with no application present. If the
+//! calling application supports any USB device function, it must remove
+//! itself from the USB bus prior to calling this function. This function
+//! assumes that the calling application has already configured the system
+//! clock to run from the PLL.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+AppUpdaterUSB(void)
+{
+ //
+ // Set sysdiv to 8. This yields a system clock of 25MHz.
+ //
+ HWREG(SYSCTL_RCC) = ((HWREG(SYSCTL_RCC) & ~(SYSCTL_RCC_SYSDIV_M)) |
+ ((8 - 1) << SYSCTL_RCC_SYSDIV_S));
+
+ //
+ // If the target device has a mux to allow selection of USB host or
+ // device mode, make sure this is set to device mode.
+ //
+#ifdef USB_HAS_MUX
+ SetUSBMux();
+#endif
+
+ //
+ // Configure the USB interface and put the device on the bus.
+ //
+ ConfigureUSBInterface();
+
+ //
+ // Call the main update routine.
+ //
+ UpdaterUSB();
+}
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
+#endif
diff --git a/boot_loader/bl_usbfuncs.c b/boot_loader/bl_usbfuncs.c
new file mode 100644
index 0000000..552fabc
--- /dev/null
+++ b/boot_loader/bl_usbfuncs.c
@@ -0,0 +1,1915 @@
+//*****************************************************************************
+//
+// bl_usbfuncs.c - The subset of USB library functions required by the USB DFU
+// boot loader.
+//
+// Copyright (c) 2008-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
+//
+//*****************************************************************************
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "inc/hw_types.h"
+#include "inc/hw_memmap.h"
+#include "inc/hw_usb.h"
+#include "inc/hw_sysctl.h"
+#include "inc/hw_nvic.h"
+#include "inc/hw_ints.h"
+#include "inc/hw_gpio.h"
+#include "bl_config.h"
+#include "boot_loader/bl_usbfuncs.h"
+
+//*****************************************************************************
+//
+//! \addtogroup bl_usb_api
+//! @{
+//
+//*****************************************************************************
+#if defined(USB_ENABLE_UPDATE) || defined(DOXYGEN)
+
+//*****************************************************************************
+//
+// Local functions prototypes.
+//
+//*****************************************************************************
+static void USBDGetStatus(tUSBRequest *pUSBRequest);
+static void USBDClearFeature(tUSBRequest *pUSBRequest);
+static void USBDSetFeature(tUSBRequest *pUSBRequest);
+static void USBDSetAddress(tUSBRequest *pUSBRequest);
+static void USBDGetDescriptor(tUSBRequest *pUSBRequest);
+static void USBDSetDescriptor(tUSBRequest *pUSBRequest);
+static void USBDGetConfiguration(tUSBRequest *pUSBRequest);
+static void USBDSetConfiguration(tUSBRequest *pUSBRequest);
+static void USBDGetInterface(tUSBRequest *pUSBRequest);
+static void USBDSetInterface(tUSBRequest *pUSBRequest);
+static void USBDEP0StateTx(void);
+static int32_t USBDStringIndexFromRequest(uint16_t ui16Lang,
+ uint16_t ui16Index);
+
+//*****************************************************************************
+//
+// This structure holds the full state for the device enumeration.
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ // The devices current address, this also has a change pending bit in the
+ // MSB of this value specified by DEV_ADDR_PENDING.
+ //
+ volatile uint32_t ui32DevAddress;
+
+ //
+ // This holds the current active configuration for this device.
+ //
+ uint32_t ui32Configuration;
+
+ //
+ // This holds the current alternate interface for this device. We only have
+ // 1 interface so only need to hold 1 setting.
+ //
+ uint8_t ui8AltSetting;
+
+ //
+ // This is the pointer to the current data being sent out or received
+ // on endpoint zero.
+ //
+ uint8_t *pui8EP0Data;
+
+ //
+ // This is the number of bytes that remain to be sent from or received
+ // into the g_sUSBDeviceState.pui8EP0Data data buffer.
+ //
+ volatile uint32_t ui32EP0DataRemain;
+
+ //
+ // The amount of data being sent/received due to a custom request.
+ //
+ uint32_t ui32OUTDataSize;
+
+ //
+ // Holds the current device status.
+ //
+ uint8_t ui8Status;
+
+ //
+ // This flag indicates whether or not remote wakeup signalling is in
+ // progress.
+ //
+ bool bRemoteWakeup;
+
+ //
+ // During remote wakeup signalling, this counter is used to track the
+ // number of milliseconds since the signalling was initiated.
+ //
+ uint8_t ui8RemoteWakeupCount;
+}
+tDeviceState;
+
+//*****************************************************************************
+//
+// The states for endpoint zero during enumeration.
+//
+//*****************************************************************************
+typedef enum
+{
+ //
+ // The USB device is waiting on a request from the host controller on
+ // endpoint zero.
+ //
+ USB_STATE_IDLE,
+
+ //
+ // The USB device is sending data back to the host due to an IN request.
+ //
+ USB_STATE_TX,
+
+ //
+ // The USB device is receiving data from the host due to an OUT
+ // request from the host.
+ //
+ USB_STATE_RX,
+
+ //
+ // The USB device has completed the IN or OUT request and is now waiting
+ // for the host to acknowledge the end of the IN/OUT transaction. This
+ // is the status phase for a USB control transaction.
+ //
+ USB_STATE_STATUS,
+
+ //
+ // This endpoint has signaled a stall condition and is waiting for the
+ // stall to be acknowledged by the host controller.
+ //
+ USB_STATE_STALL
+}
+tEP0State;
+
+//*****************************************************************************
+//
+// Define the max packet size for endpoint zero.
+//
+//*****************************************************************************
+#define EP0_MAX_PACKET_SIZE 64
+
+//*****************************************************************************
+//
+// This is a flag used with g_sUSBDeviceState.ui32DevAddress to indicate that a
+// device address change is pending.
+//
+//*****************************************************************************
+#define DEV_ADDR_PENDING 0x80000000
+
+//*****************************************************************************
+//
+// This label defines the default configuration number to use after a bus
+// reset.
+//
+//*****************************************************************************
+#define DEFAULT_CONFIG_ID 1
+
+//*****************************************************************************
+//
+// This label defines the number of milliseconds that the remote wakeup signal
+// must remain asserted before removing it. Section 7.1.7.7 of the USB 2.0 spec
+// states that "the remote wakeup device must hold the resume signaling for at
+// least 1ms but for no more than 15ms" so 10mS seems a reasonable choice.
+//
+//*****************************************************************************
+#define REMOTE_WAKEUP_PULSE_MS 10
+
+//*****************************************************************************
+//
+// This label defines the number of milliseconds between the point where we
+// assert the remote wakeup signal and calling the client back to tell it that
+// bus operation has been resumed. This value is based on the timings provided
+// in section 7.1.7.7 of the USB 2.0 specification which indicates that the host
+// (which takes over resume signalling when the device's initial signal is
+// detected) must hold the resume signalling for at least 20mS.
+//
+//*****************************************************************************
+#define REMOTE_WAKEUP_READY_MS 20
+
+//*****************************************************************************
+//
+// The buffer for reading data coming into EP0
+//
+//*****************************************************************************
+static uint8_t g_pui8DataBufferIn[EP0_MAX_PACKET_SIZE];
+
+//*****************************************************************************
+//
+// This global holds the current state information for the USB device.
+//
+//*****************************************************************************
+static volatile tDeviceState g_sUSBDeviceState;
+
+//*****************************************************************************
+//
+// This global holds the current state of endpoint zero.
+//
+//*****************************************************************************
+static volatile tEP0State g_eUSBDEP0State = USB_STATE_IDLE;
+
+//*****************************************************************************
+//
+// Function table to handle standard requests.
+//
+//*****************************************************************************
+static const tStdRequest g_ppfnUSBDStdRequests[] =
+{
+ USBDGetStatus,
+ USBDClearFeature,
+ 0,
+ USBDSetFeature,
+ 0,
+ USBDSetAddress,
+ USBDGetDescriptor,
+ USBDSetDescriptor,
+ USBDGetConfiguration,
+ USBDSetConfiguration,
+ USBDGetInterface,
+ USBDSetInterface,
+};
+
+//*****************************************************************************
+//
+// Amount to shift the RX interrupt sources by in the flags used in the
+// interrupt calls.
+//
+//*****************************************************************************
+#define USB_INT_RX_SHIFT 8
+
+//*****************************************************************************
+//
+// Amount to shift the status interrupt sources by in the flags used in the
+// interrupt calls.
+//
+//*****************************************************************************
+#define USB_INT_STATUS_SHIFT 24
+
+//*****************************************************************************
+//
+// Amount to shift the RX endpoint status sources by in the flags used in the
+// calls.
+//
+//*****************************************************************************
+#define USB_RX_EPSTATUS_SHIFT 16
+
+//*****************************************************************************
+//
+// Converts from an endpoint specifier to the offset of the endpoint's
+// control/status registers.
+//
+//*****************************************************************************
+#define EP_OFFSET(Endpoint) (Endpoint - 0x10)
+
+//*****************************************************************************
+//
+// Retrieves data from endpoint 0's FIFO.
+//
+// \param pui8Data is a pointer to the data area used to return the data from
+// the FIFO.
+// \param pui32Size is initially the size of the buffer passed into this call
+// via the \e pui8Data parameter. It will be set to the amount of data
+// returned in the buffer.
+//
+// This function will return the data from the FIFO for endpoint 0.
+// The \e pui32Size parameter should indicate the size of the buffer passed in
+// the \e pui32Data parameter. The data in the \e pui32Size parameter will be
+// changed to match the amount of data returned in the \e pui8Data parameter.
+// If a zero byte packet was received this call will not return a error but
+// will instead just return a zero in the \e pui32Size parameter. The only
+// error case occurs when there is no data packet available.
+//
+// \return This call will return 0, or -1 if no packet was received.
+//
+//*****************************************************************************
+int32_t
+USBEndpoint0DataGet(uint8_t *pui8Data, uint32_t *pui32Size)
+{
+ uint32_t ui32ByteCount;
+
+ //
+ // Don't allow reading of data if the RxPktRdy bit is not set.
+ //
+ if((HWREGH(USB0_BASE + USB_O_CSRL0) & USB_CSRL0_RXRDY) == 0)
+ {
+ //
+ // Can't read the data because none is available.
+ //
+ *pui32Size = 0;
+
+ //
+ // Return a failure since there is no data to read.
+ //
+ return(-1);
+ }
+
+ //
+ // Get the byte count in the FIFO.
+ //
+ ui32ByteCount = HWREGH(USB0_BASE + USB_O_COUNT0 + USB_EP_0);
+
+ //
+ // Determine how many bytes we will actually copy.
+ //
+ ui32ByteCount = (ui32ByteCount < *pui32Size) ? ui32ByteCount : *pui32Size;
+
+ //
+ // Return the number of bytes we are going to read.
+ //
+ *pui32Size = ui32ByteCount;
+
+ //
+ // Read the data out of the FIFO.
+ //
+ for(; ui32ByteCount > 0; ui32ByteCount--)
+ {
+ //
+ // Read a byte at a time from the FIFO.
+ //
+ *pui8Data++ = HWREGB(USB0_BASE + USB_O_FIFO0 + (USB_EP_0 >> 2));
+ }
+
+ //
+ // Success.
+ //
+ return(0);
+}
+
+//*****************************************************************************
+//
+// Acknowledge that data was read from endpoint 0's FIFO.
+//
+// \param bIsLastPacket indicates if this is the last packet.
+//
+// This function acknowledges that the data was read from the endpoint 0's
+// FIFO. The \e bIsLastPacket parameter is set to a \b true value if this is
+// the last in a series of data packets. This call can be used if processing
+// is required between reading the data and acknowledging that the data has
+// been read.
+//
+// \return None.
+//
+//*****************************************************************************
+void
+USBDevEndpoint0DataAck(bool bIsLastPacket)
+{
+ //
+ // Clear RxPktRdy, and optionally DataEnd, on endpoint zero.
+ //
+ HWREGB(USB0_BASE + USB_O_CSRL0) =
+ USB_CSRL0_RXRDYC | (bIsLastPacket ? USB_CSRL0_DATAEND : 0);
+
+}
+
+//*****************************************************************************
+//
+// Puts data into endpoint 0's FIFO.
+//
+// \param pui8Data is a pointer to the data area used as the source for the
+// data to put into the FIFO.
+// \param ui32Size is the amount of data to put into the FIFO.
+//
+// This function will put the data from the \e pui8Data parameter into the FIFO
+// for endpoint 0. If a packet is already pending for transmission then
+// this call will not put any of the data into the FIFO and will return -1.
+//
+// \return This call will return 0 on success, or -1 to indicate that the FIFO
+// is in use and cannot be written.
+//
+//*****************************************************************************
+int32_t
+USBEndpoint0DataPut(uint8_t *pui8Data, uint32_t ui32Size)
+{
+ //
+ // Don't allow transmit of data if the TxPktRdy bit is already set.
+ //
+ if(HWREGB(USB0_BASE + USB_O_CSRL0 + USB_EP_0) & USB_CSRL0_TXRDY)
+ {
+ return(-1);
+ }
+
+ //
+ // Write the data to the FIFO.
+ //
+ for(; ui32Size > 0; ui32Size--)
+ {
+ HWREGB(USB0_BASE + USB_O_FIFO0 + (USB_EP_0 >> 2)) = *pui8Data++;
+ }
+
+ //
+ // Success.
+ //
+ return(0);
+}
+
+//*****************************************************************************
+//
+// Starts the transfer of data from endpoint 0's FIFO.
+//
+// \param ui32TransType is set to indicate what type of data is being sent.
+//
+// This function will start the transfer of data from the FIFO for
+// endpoint 0. This is necessary if the \b USB_EP_AUTO_SET bit was not enabled
+// for the endpoint. Setting the \e ui32TransType parameter will allow the
+// appropriate signaling on the USB bus for the type of transaction being
+// requested. The \e ui32TransType parameter should be one of the following:
+//
+// - USB_TRANS_OUT for OUT transaction on any endpoint in host mode.
+// - USB_TRANS_IN for IN transaction on any endpoint in device mode.
+// - USB_TRANS_IN_LAST for the last IN transactions on endpoint zero in a
+// sequence of IN transactions.
+// - USB_TRANS_SETUP for setup transactions on endpoint zero.
+// - USB_TRANS_STATUS for status results on endpoint zero.
+//
+// \return This call will return 0 on success, or -1 if a transmission is
+// already in progress.
+//
+//*****************************************************************************
+int32_t
+USBEndpoint0DataSend(uint32_t ui32TransType)
+{
+ //
+ // Don't allow transmit of data if the TxPktRdy bit is already set.
+ //
+ if(HWREGB(USB0_BASE + USB_O_CSRL0 + USB_EP_0) & USB_CSRL0_TXRDY)
+ {
+ return(-1);
+ }
+
+ //
+ // Set TxPktRdy in order to send the data.
+ //
+ HWREGB(USB0_BASE + USB_O_CSRL0 + USB_EP_0) = ui32TransType & 0xff;
+
+ //
+ // Success.
+ //
+ return(0);
+}
+
+#if defined(USB_VBUS_CONFIG) || defined(USB_ID_CONFIG) || \
+ defined(USB_DP_CONFIG) || defined(USB_DM_CONFIG) || defined(DOXYGEN)
+//*****************************************************************************
+//
+//! Initialize the pins used by USB functions.
+//!
+//! This function configures the pins for USB functions depending on defines
+//! from the bl_config.h file.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+USBConfigurePins(void)
+{
+ //
+ // Enable the clocks to the GPIOs.
+ //
+ HWREG(SYSCTL_RCGCGPIO) |= (0x0
+#if defined(USB_VBUS_CONFIG)
+ | USB_VBUS_PERIPH
+#endif
+#if defined(USB_ID_CONFIG)
+ | USB_ID_PERIPH
+#endif
+#if defined(USB_DP_CONFIG)
+ | USB_DP_PERIPH
+#endif
+#if defined(USB_DM_CONFIG)
+ | USB_DM_PERIPH
+#endif
+ );
+
+ //
+ // Setup the pins based on bl_config.h
+ //
+#if defined(USB_VBUS_CONFIG)
+ //
+ // Set the VBUS pin to be an analog input.
+ //
+ HWREG(USB_VBUS_PORT + GPIO_O_DIR) &= ~(1 << USB_VBUS_PIN);
+ HWREG(USB_VBUS_PORT + GPIO_O_AMSEL) |= (1 << USB_VBUS_PIN);
+#endif
+
+#if defined(USB_ID_CONFIG)
+ //
+ // Set the ID pin to be an analog input.
+ //
+ HWREG(USB_ID_PORT + GPIO_O_DIR) &= ~(1 << USB_ID_PIN);
+ HWREG(USB_ID_PORT + GPIO_O_AMSEL) |= (1 << USB_ID_PIN);
+#endif
+
+#if defined(USB_DP_CONFIG)
+ //
+ // Set the DP pin to be an analog input.
+ //
+ HWREG(USB_DP_PORT + GPIO_O_DIR) &= ~(1 << USB_DP_PIN);
+ HWREG(USB_DP_PORT + GPIO_O_AMSEL) |= (1 << USB_DP_PIN);
+#endif
+
+#if defined(USB_DM_CONFIG)
+ //
+ // Set the DM pin to be an analog input.
+ //
+ HWREG(USB_DM_PORT + GPIO_O_DIR) &= ~(1 << USB_DM_PIN);
+ HWREG(USB_DM_PORT + GPIO_O_AMSEL) |= (1 << USB_DM_PIN);
+#endif
+
+}
+#endif
+
+//*****************************************************************************
+//
+//! Initialize the boot loader USB functions.
+//!
+//! This function initializes the boot loader USB functions and places the DFU
+//! device onto the USB bus.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+USBBLInit(void)
+{
+ //
+ // Configure the USB Pins based on the bl_config.h settings.
+ //
+#if defined(USB_VBUS_CONFIG) || defined(USB_ID_CONFIG) || \
+ defined(USB_DP_CONFIG) || defined(USB_DM_CONFIG)
+ USBConfigurePins();
+#endif
+
+ //
+ // Initialize a couple of fields in the device state structure.
+ //
+ g_sUSBDeviceState.ui32Configuration = DEFAULT_CONFIG_ID;
+
+ //
+ // Enable the USB controller.
+ //
+ HWREG(SYSCTL_RCGC2) |= 0x10000;
+
+ //
+ // Turn on USB Phy clock.
+ //
+ HWREG(SYSCTL_RCC2) &= ~SYSCTL_RCC2_USBPWRDN;
+
+ //
+ // Clear any pending interrupts.
+ //
+ HWREGH(USB0_BASE + USB_O_TXIS);
+ HWREGB(USB0_BASE + USB_O_IS);
+
+ //
+ // Enable USB Interrupts.
+ //
+ HWREGH(USB0_BASE + USB_O_TXIE) = USB_TXIS_EP0;
+ HWREGB(USB0_BASE + USB_O_IE) = (USB_IS_DISCON | USB_IS_RESET);
+
+ //
+ // Default to the state where remote wakeup is disabled.
+ //
+ g_sUSBDeviceState.ui8Status = 0;
+ g_sUSBDeviceState.bRemoteWakeup = false;
+
+ //
+ // Determine the self- or bus-powered state based on bl_config.h setting.
+ //
+#if USB_BUS_POWERED
+ g_sUSBDeviceState.ui8Status &= ~USB_STATUS_SELF_PWR;
+#else
+ g_sUSBDeviceState.ui8Status |= USB_STATUS_SELF_PWR;
+#endif
+
+ //
+ // Attach the device using the soft connect.
+ //
+ HWREGB(USB0_BASE + USB_O_POWER) |= USB_POWER_SOFTCONN;
+
+ //
+ // Enable the USB interrupt.
+ //
+ HWREG(NVIC_EN1) = 1 << (INT_USB0 - 48);
+}
+
+//*****************************************************************************
+//
+// This function starts the request for data from the host on endpoint zero.
+//
+// \param pui8Data is a pointer to the buffer to fill with data from the USB
+// host.
+// \param ui32Size is the size of the buffer or data to return from the USB
+// host.
+//
+// This function handles retrieving data from the host when a custom command
+// has been issued on endpoint zero. When the requested data is received,
+// the function HandleEP0Data() will be called.
+//
+// \return None.
+//
+//*****************************************************************************
+void
+USBBLRequestDataEP0(uint8_t *pui8Data, uint32_t ui32Size)
+{
+ //
+ // Enter the RX state on end point 0.
+ //
+ g_eUSBDEP0State = USB_STATE_RX;
+
+ //
+ // Save the pointer to the data.
+ //
+ g_sUSBDeviceState.pui8EP0Data = pui8Data;
+
+ //
+ // Location to save the current number of bytes received.
+ //
+ g_sUSBDeviceState.ui32OUTDataSize = ui32Size;
+
+ //
+ // Bytes remaining to be received.
+ //
+ g_sUSBDeviceState.ui32EP0DataRemain = ui32Size;
+}
+
+//*****************************************************************************
+//
+//! This function requests transfer of data to the host on endpoint zero.
+//!
+//! \param pui8Data is a pointer to the buffer to send via endpoint zero.
+//! \param ui32Size is the amount of data to send in bytes.
+//!
+//! This function handles sending data to the host when a custom command is
+//! issued or non-standard descriptor has been requested on endpoint zero.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+USBBLSendDataEP0(uint8_t *pui8Data, uint32_t ui32Size)
+{
+ //
+ // Return the externally provided device descriptor.
+ //
+ g_sUSBDeviceState.pui8EP0Data = pui8Data;
+
+ //
+ // The size of the device descriptor is in the first byte.
+ //
+ g_sUSBDeviceState.ui32EP0DataRemain = ui32Size;
+
+ //
+ // Save the total size of the data sent.
+ //
+ g_sUSBDeviceState.ui32OUTDataSize = ui32Size;
+
+ //
+ // Now in the transmit data state.
+ //
+ USBDEP0StateTx();
+}
+
+//*****************************************************************************
+//
+//! This function generates a stall condition on endpoint zero.
+//!
+//! This function is typically called to signal an error condition to the host
+//! when an unsupported request is received by the device. It should be
+//! called from within the callback itself (in interrupt context) and not
+//! deferred until later since it affects the operation of the endpoint zero
+//! state machine.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+USBBLStallEP0(void)
+{
+ //
+ // Perform a stall on endpoint zero.
+ //
+ HWREGB(USB0_BASE + USB_O_CSRL0) |= (USB_CSRL0_STALL | USB_CSRL0_RXRDYC);
+
+ //
+ // Enter the stalled state.
+ //
+ g_eUSBDEP0State = USB_STATE_STALL;
+}
+
+//*****************************************************************************
+//
+// This internal function reads a request data packet and dispatches it to
+// either a standard request handler or the registered device request
+// callback depending upon the request type.
+//
+// \return None.
+//
+//*****************************************************************************
+static void
+USBDReadAndDispatchRequest(void)
+{
+ uint32_t ui32Size;
+ tUSBRequest *pRequest;
+
+ //
+ // Cast the buffer to a request structure.
+ //
+ pRequest = (tUSBRequest *)g_pui8DataBufferIn;
+
+ //
+ // Set the buffer size.
+ //
+ ui32Size = EP0_MAX_PACKET_SIZE;
+
+ //
+ // Get the data from the USB controller end point 0.
+ //
+ USBEndpoint0DataGet(g_pui8DataBufferIn, &ui32Size);
+
+ if(!ui32Size)
+ {
+ return;
+ }
+
+ //
+ // See if this is a standard request or not.
+ //
+ if((pRequest->bmRequestType & USB_RTYPE_TYPE_M) != USB_RTYPE_STANDARD)
+ {
+ //
+ // Pass this non-standard request on to the DFU handler
+ //
+ HandleRequests(pRequest);
+ }
+ else
+ {
+ //
+ // Assure that the jump table is not out of bounds.
+ //
+ if((pRequest->bRequest <
+ (sizeof(g_ppfnUSBDStdRequests) / sizeof(tStdRequest))) &&
+ (g_ppfnUSBDStdRequests[pRequest->bRequest] != 0))
+ {
+ //
+ // Jump table to the appropriate handler.
+ //
+ g_ppfnUSBDStdRequests[pRequest->bRequest](pRequest);
+ }
+ else
+ {
+ //
+ // If there is no handler then stall this request.
+ //
+ USBBLStallEP0();
+ }
+ }
+}
+
+//*****************************************************************************
+//
+// This is the low level interrupt handler for endpoint zero.
+//
+// This function handles all interrupts on endpoint zero in order to maintain
+// the state needed for the control endpoint on endpoint zero. In order to
+// successfully enumerate and handle all USB standard requests, all requests
+// on endpoint zero must pass through this function. The endpoint has the
+// following states: \b USB_STATE_IDLE, \b USB_STATE_TX, \b USB_STATE_RX,
+// \b USB_STATE_STALL, and \b USB_STATE_STATUS. In the \b USB_STATE_IDLE
+// state the USB controller has not received the start of a request, and once
+// it does receive the data for the request it will either enter the
+// \b USB_STATE_TX, \b USB_STATE_RX, or \b USB_STATE_STALL depending on the
+// command. If the controller enters the \b USB_STATE_TX or \b USB_STATE_RX
+// then once all data has been sent or received, it must pass through the
+// \b USB_STATE_STATUS state to allow the host to acknowledge completion of
+// the request. The \b USB_STATE_STALL is entered from \b USB_STATE_IDLE in
+// the event that the USB request was not valid. Both the \b USB_STATE_STALL
+// and \b USB_STATE_STATUS are transitional states that return to the
+// \b USB_STATE_IDLE state.
+//
+// \return None.
+//
+// USB_STATE_IDLE -*--> USB_STATE_TX -*-> USB_STATE_STATUS -*->USB_STATE_IDLE
+// | | |
+// |--> USB_STATE_RX - |
+// | |
+// |--> USB_STATE_STALL ---------->---------
+//
+// ----------------------------------------------------------------
+// | Current State | State 0 | State 1 |
+// | --------------------|-------------------|----------------------
+// | USB_STATE_IDLE | USB_STATE_TX/RX | USB_STATE_STALL |
+// | USB_STATE_TX | USB_STATE_STATUS | |
+// | USB_STATE_RX | USB_STATE_STATUS | |
+// | USB_STATE_STATUS | USB_STATE_IDLE | |
+// | USB_STATE_STALL | USB_STATE_IDLE | |
+// ----------------------------------------------------------------
+//
+//*****************************************************************************
+void
+USBDeviceEnumHandler(void)
+{
+ uint32_t ui32EPStatus;
+
+ //
+ // Get the TX portion of the endpoint status.
+ //
+ ui32EPStatus = HWREGH(USB0_BASE + EP_OFFSET(USB_EP_0) + USB_O_TXCSRL1);
+
+ //
+ // Get the RX portion of the endpoint status.
+ //
+ ui32EPStatus |=
+ ((HWREGH(USB0_BASE + EP_OFFSET(USB_EP_0) + USB_O_RXCSRL1)) <<
+ USB_RX_EPSTATUS_SHIFT);
+
+ //
+ // What state are we currently in?
+ //
+ switch(g_eUSBDEP0State)
+ {
+ //
+ // Handle the status state, this is a transitory state from
+ // USB_STATE_TX or USB_STATE_RX back to USB_STATE_IDLE.
+ //
+ case USB_STATE_STATUS:
+ {
+ //
+ // Just go back to the idle state.
+ //
+ g_eUSBDEP0State = USB_STATE_IDLE;
+
+ //
+ // If there is a pending address change then set the address.
+ //
+ if(g_sUSBDeviceState.ui32DevAddress & DEV_ADDR_PENDING)
+ {
+ //
+ // Clear the pending address change and set the address.
+ //
+ g_sUSBDeviceState.ui32DevAddress &= ~DEV_ADDR_PENDING;
+ HWREGB(USB0_BASE + USB_O_FADDR) =
+ (uint8_t)g_sUSBDeviceState.ui32DevAddress;
+ }
+
+ //
+ // If a new packet is already pending, we need to read it
+ // and handle whatever request it contains.
+ //
+ if(ui32EPStatus & USB_DEV_EP0_OUT_PKTRDY)
+ {
+ //
+ // Process the newly arrived packet.
+ //
+ USBDReadAndDispatchRequest();
+ }
+ break;
+ }
+
+ //
+ // In the IDLE state the code is waiting to receive data from the host.
+ //
+ case USB_STATE_IDLE:
+ {
+ //
+ // Is there a packet waiting for us?
+ //
+ if(ui32EPStatus & USB_DEV_EP0_OUT_PKTRDY)
+ {
+ //
+ // Yes - process it.
+ //
+ USBDReadAndDispatchRequest();
+ }
+ break;
+ }
+
+ //
+ // Data is still being sent to the host so handle this in the
+ // EP0StateTx() function.
+ //
+ case USB_STATE_TX:
+ {
+ USBDEP0StateTx();
+ break;
+ }
+
+ //
+ // Handle the receive state for commands that are receiving data on
+ // endpoint zero.
+ //
+ case USB_STATE_RX:
+ {
+ uint32_t ui32DataSize;
+
+ //
+ // Set the number of bytes to get out of this next packet.
+ //
+ if(g_sUSBDeviceState.ui32EP0DataRemain > EP0_MAX_PACKET_SIZE)
+ {
+ //
+ // Don't send more than EP0_MAX_PACKET_SIZE bytes.
+ //
+ ui32DataSize = EP0_MAX_PACKET_SIZE;
+ }
+ else
+ {
+ //
+ // There was space so send the remaining bytes.
+ //
+ ui32DataSize = g_sUSBDeviceState.ui32EP0DataRemain;
+ }
+
+ //
+ // Get the data from the USB controller end point 0.
+ //
+ USBEndpoint0DataGet(g_sUSBDeviceState.pui8EP0Data, &ui32DataSize);
+
+ //
+ // If there we not more that EP0_MAX_PACKET_SIZE or more bytes
+ // remaining then this transfer is complete. If there were exactly
+ // EP0_MAX_PACKET_SIZE remaining then there still needs to be
+ // null packet sent before this is complete.
+ //
+ if(g_sUSBDeviceState.ui32EP0DataRemain < EP0_MAX_PACKET_SIZE)
+ {
+ //
+ // Need to ack the data on end point 0 in this case
+ // without setting data end.
+ //
+ USBDevEndpoint0DataAck(true);
+
+ //
+ // Return to the idle state.
+ //
+ g_eUSBDEP0State = USB_STATE_IDLE;
+
+ //
+ // If there is a receive callback then call it.
+ //
+ if(g_sUSBDeviceState.ui32OUTDataSize != 0)
+ {
+ //
+ // Call the receive handler to handle the data
+ // that was received.
+ //
+ HandleEP0Data(g_sUSBDeviceState.ui32OUTDataSize);
+
+ //
+ // Indicate that there is no longer any data being waited
+ // on.
+ //
+ g_sUSBDeviceState.ui32OUTDataSize = 0;
+ }
+ }
+ else
+ {
+ //
+ // Need to ack the data on end point 0 in this case
+ // without setting data end.
+ //
+ USBDevEndpoint0DataAck(false);
+ }
+
+ //
+ // Advance the pointer.
+ //
+ g_sUSBDeviceState.pui8EP0Data += ui32DataSize;
+
+ //
+ // Decrement the number of bytes that are being waited on.
+ //
+ g_sUSBDeviceState.ui32EP0DataRemain -= ui32DataSize;
+
+ break;
+ }
+ //
+ // The device stalled endpoint zero so check if the stall needs to be
+ // cleared once it has been successfully sent.
+ //
+ case USB_STATE_STALL:
+ {
+ //
+ // If we sent a stall then acknowledge this interrupt.
+ //
+ if(ui32EPStatus & USB_DEV_EP0_SENT_STALL)
+ {
+ //
+ // Clear the stall condition.
+ //
+ HWREGB(USB0_BASE + USB_O_CSRL0) &= ~(USB_DEV_EP0_SENT_STALL);
+
+ //
+ // Reset the global end point 0 state to IDLE.
+ //
+ g_eUSBDEP0State = USB_STATE_IDLE;
+
+ }
+ break;
+ }
+ //
+ // Halt on an unknown state, but only in DEBUG mode builds.
+ //
+ default:
+ {
+#ifdef DEBUG
+ while(1);
+#endif
+ break;
+ }
+ }
+}
+
+//*****************************************************************************
+//
+// This function handles bus reset notifications.
+//
+// This function is called from the low level USB interrupt handler whenever
+// a bus reset is detected. It performs tidy-up as required and resets the
+// configuration back to defaults in preparation for descriptor queries from
+// the host.
+//
+// \return None.
+//
+//*****************************************************************************
+void
+USBDeviceEnumResetHandler(void)
+{
+ //
+ // Disable remote wakeup signalling (as per USB 2.0 spec 9.1.1.6).
+ //
+ g_sUSBDeviceState.ui8Status &= ~USB_STATUS_REMOTE_WAKE;
+ g_sUSBDeviceState.bRemoteWakeup = false;
+
+ //
+ // Call the device dependent code to indicate a bus reset has occurred.
+ //
+ HandleReset();
+
+ //
+ // Reset the default configuration identifier and alternate function
+ // selections.
+ //
+ g_sUSBDeviceState.ui32Configuration = DEFAULT_CONFIG_ID;
+ g_sUSBDeviceState.ui8AltSetting = 0;
+}
+
+//*****************************************************************************
+//
+// This function handles the GET_STATUS standard USB request.
+//
+// \param pUSBRequest holds the request type and endpoint number if endpoint
+// status is requested.
+//
+// This function handles responses to a Get Status request from the host
+// controller. A status request can be for the device, an interface or an
+// endpoint. If any other type of request is made this function will cause
+// a stall condition to indicate that the command is not supported. The
+// \e pUSBRequest structure holds the type of the request in the
+// bmRequestType field. If the type indicates that this is a request for an
+// endpoint's status, then the wIndex field holds the endpoint number.
+//
+// \return None.
+//
+//*****************************************************************************
+static void
+USBDGetStatus(tUSBRequest *pUSBRequest)
+{
+ uint16_t ui16Data;
+
+ //
+ // Determine what type of status was requested.
+ //
+ switch(pUSBRequest->bmRequestType & USB_RTYPE_RECIPIENT_M)
+ {
+ //
+ // This was a Device Status request.
+ //
+ case USB_RTYPE_DEVICE:
+ {
+ //
+ // Return the current status for the device.
+ //
+ ui16Data = g_sUSBDeviceState.ui8Status;
+
+ break;
+ }
+
+ //
+ // This was a Interface status request.
+ //
+ case USB_RTYPE_INTERFACE:
+ {
+ //
+ // Interface status always returns 0.
+ //
+ ui16Data = 0;
+
+ break;
+ }
+
+ //
+ // This was an unknown request or a request for an endpoint (of which
+ // we have none) so set a stall.
+ //
+ case USB_RTYPE_ENDPOINT:
+ default:
+ {
+ //
+ // Anything else causes a stall condition to indicate that the
+ // command was not supported.
+ //
+ USBBLStallEP0();
+ return;
+ }
+ }
+
+ //
+ // Send the two byte status response.
+ //
+ g_sUSBDeviceState.ui32EP0DataRemain = 2;
+ g_sUSBDeviceState.pui8EP0Data = (uint8_t *)&ui16Data;
+
+ //
+ // Send the response.
+ //
+ USBDEP0StateTx();
+}
+
+//*****************************************************************************
+//
+// This function handles the CLEAR_FEATURE standard USB request.
+//
+// \param pUSBRequest holds the options for the Clear Feature USB request.
+//
+// This function handles device or endpoint clear feature requests. The
+// \e pUSBRequest structure holds the type of the request in the bmRequestType
+// field and the feature is held in the wValue field. For device, the only
+// clearable feature is the Remote Wake feature. This device request
+// should only be made if the descriptor indicates that Remote Wake is
+// implemented by the device. For endpoint requests the only clearable
+// feature is the ability to clear a halt on a given endpoint. If any other
+// requests are made, then the device will stall the request to indicate to
+// the host that the command was not supported.
+//
+// \return None.
+//
+//*****************************************************************************
+static void
+USBDClearFeature(tUSBRequest *pUSBRequest)
+{
+ //
+ // Determine what type of status was requested.
+ //
+ switch(pUSBRequest->bmRequestType & USB_RTYPE_RECIPIENT_M)
+ {
+ //
+ // This is a clear feature request at the device level.
+ //
+ case USB_RTYPE_DEVICE:
+ {
+ //
+ // Only remote wake is clearable by this function.
+ //
+ if(USB_FEATURE_REMOTE_WAKE & pUSBRequest->wValue)
+ {
+ //
+ // Clear the remote wake up state.
+ //
+ g_sUSBDeviceState.ui8Status &= ~USB_STATUS_REMOTE_WAKE;
+
+ //
+ // Need to ack the data on end point 0.
+ //
+ USBDevEndpoint0DataAck(true);
+ }
+ else
+ {
+ USBBLStallEP0();
+ }
+ break;
+ }
+
+ //
+ // This is an unknown request or one destined for an invalid endpoint.
+ //
+ case USB_RTYPE_ENDPOINT:
+ default:
+ {
+ USBBLStallEP0();
+ return;
+ }
+ }
+}
+
+//*****************************************************************************
+//
+// This function handles the SET_FEATURE standard USB request.
+//
+// \param pUSBRequest holds the feature in the wValue field of the USB
+// request.
+//
+// This function handles device or endpoint set feature requests. The
+// \e pUSBRequest structure holds the type of the request in the bmRequestType
+// field and the feature is held in the wValue field. For device, the only
+// settable feature is the Remote Wake feature. This device request
+// should only be made if the descriptor indicates that Remote Wake is
+// implemented by the device. For endpoint requests the only settable feature
+// is the ability to issue a halt on a given endpoint. If any other requests
+// are made, then the device will stall the request to indicate to the host
+// that the command was not supported.
+//
+// \return None.
+//
+//*****************************************************************************
+static void
+USBDSetFeature(tUSBRequest *pUSBRequest)
+{
+ //
+ // Determine what type of status was requested.
+ //
+ switch(pUSBRequest->bmRequestType & USB_RTYPE_RECIPIENT_M)
+ {
+ //
+ // This is a set feature request at the device level.
+ //
+ case USB_RTYPE_DEVICE:
+ {
+ //
+ // Only remote wake is setable by this function.
+ //
+ if(USB_FEATURE_REMOTE_WAKE & pUSBRequest->wValue)
+ {
+ //
+ // Set the remote wakeup state.
+ //
+ g_sUSBDeviceState.ui8Status |= USB_STATUS_REMOTE_WAKE;
+
+ //
+ // Need to ack the data on end point 0.
+ //
+ USBDevEndpoint0DataAck(true);
+ }
+ else
+ {
+ USBBLStallEP0();
+ }
+ break;
+ }
+
+ //
+ // This is an unknown request or one destined for an invalid endpoint.
+ //
+ case USB_RTYPE_ENDPOINT:
+ default:
+ {
+ USBBLStallEP0();
+ return;
+ }
+ }
+}
+
+//*****************************************************************************
+//
+// This function handles the SET_ADDRESS standard USB request.
+//
+// \param pUSBRequest holds the new address to use in the wValue field of the
+// USB request.
+//
+// This function is called to handle the change of address request from the
+// host controller. This can only start the sequence as the host must
+// acknowledge that the device has changed address. Thus this function sets
+// the address change as pending until the status phase of the request has
+// been completed successfully. This prevents the devices address from
+// changing and not properly responding to the status phase.
+//
+// \return None.
+//
+//*****************************************************************************
+static void
+USBDSetAddress(tUSBRequest *pUSBRequest)
+{
+ //
+ // The data needs to be acknowledged on end point 0 without setting data
+ // end because there is no data coming.
+ //
+ USBDevEndpoint0DataAck(true);
+
+ //
+ // Save the device address as we cannot change address until the status
+ // phase is complete.
+ //
+ g_sUSBDeviceState.ui32DevAddress = pUSBRequest->wValue | DEV_ADDR_PENDING;
+
+ //
+ // Transition directly to the status state since there is no data phase
+ // for this request.
+ //
+ g_eUSBDEP0State = USB_STATE_STATUS;
+
+ //
+ // Clear the DFU status just in case we were in an error state last time
+ // the device was accessed and we were unplugged and replugged (for a self-
+ // powered implementation, of course).
+ //
+ HandleSetAddress();
+}
+
+//*****************************************************************************
+//
+// This function handles the GET_DESCRIPTOR standard USB request.
+//
+// \param pUSBRequest holds the data for this request.
+//
+// This function will return all configured standard USB descriptors to the
+// host - device, config and string descriptors. Any request for a descriptor
+// which is not available will result in endpoint 0 being stalled.
+//
+// \return None.
+//
+//*****************************************************************************
+static void
+USBDGetDescriptor(tUSBRequest *pUSBRequest)
+{
+ uint32_t ui32Stall;
+
+ //
+ // Default to no stall.
+ //
+ ui32Stall = 0;
+
+ //
+ // Which descriptor are we being asked for?
+ //
+ switch(pUSBRequest->wValue >> 8)
+ {
+ //
+ // This request was for a device descriptor.
+ //
+ case USB_DTYPE_DEVICE:
+ {
+ //
+ // Return the externally provided device descriptor.
+ //
+ g_sUSBDeviceState.pui8EP0Data =
+ (uint8_t *)g_pui8DFUDeviceDescriptor;
+
+ //
+ // The size of the device descriptor is in the first byte.
+ //
+ g_sUSBDeviceState.ui32EP0DataRemain =
+ g_pui8DFUDeviceDescriptor[0];
+ break;
+ }
+
+ //
+ // This request was for a configuration descriptor.
+ //
+ case USB_DTYPE_CONFIGURATION:
+ {
+ uint8_t ui8Index;
+
+ //
+ // Which configuration are we being asked for?
+ //
+ ui8Index = (uint8_t)(pUSBRequest->wValue & 0xFF);
+
+ //
+ // Is this valid?
+ //
+ if(ui8Index != 0)
+ {
+ //
+ // This is an invalid configuration index. Stall EP0 to
+ // indicate a request error.
+ //
+ USBBLStallEP0();
+ g_sUSBDeviceState.pui8EP0Data = 0;
+ g_sUSBDeviceState.ui32EP0DataRemain = 0;
+ }
+ else
+ {
+ //
+ // Start by sending data from the beginning of the first
+ // descriptor.
+ //
+
+ g_sUSBDeviceState.pui8EP0Data =
+ (uint8_t *)g_pui8DFUConfigDescriptor;
+
+ //
+ // Get the size of the config descriptor (remembering that in
+ // this case, we only have a single section)
+ //
+ g_sUSBDeviceState.ui32EP0DataRemain =
+ *(uint16_t *)&(g_pui8DFUConfigDescriptor[2]);
+ }
+ break;
+ }
+
+ //
+ // This request was for a string descriptor.
+ //
+ case USB_DTYPE_STRING:
+ {
+ int32_t i32Index;
+
+ //
+ // Determine the correct descriptor index based on the requested
+ // language ID and index.
+ //
+ i32Index = USBDStringIndexFromRequest(pUSBRequest->wIndex,
+ pUSBRequest->wValue & 0xFF);
+
+ //
+ // If the mapping function returned -1 then stall the request to
+ // indicate that the request was not valid.
+ //
+ if(i32Index == -1)
+ {
+ USBBLStallEP0();
+ break;
+ }
+
+ //
+ // Return the externally specified configuration descriptor.
+ //
+ g_sUSBDeviceState.pui8EP0Data =
+ (uint8_t *)g_ppui8StringDescriptors[i32Index];
+
+ //
+ // The total size of a string descriptor is in byte 0.
+ //
+ g_sUSBDeviceState.ui32EP0DataRemain =
+ g_ppui8StringDescriptors[i32Index][0];
+
+ break;
+ }
+
+ //
+ // Any other request is not handled by the default enumeration handler
+ // so see if it needs to be passed on to another handler.
+ //
+ default:
+ {
+ //
+ // All other requests are not handled.
+ //
+ USBBLStallEP0();
+ ui32Stall = 1;
+ break;
+ }
+ }
+
+ //
+ // If there was no stall, ACK the data and see if data needs to be sent.
+ //
+ if(ui32Stall == 0)
+ {
+ //
+ // Need to ack the data on end point 0 in this case without
+ // setting data end.
+ //
+ USBDevEndpoint0DataAck(false);
+
+ //
+ // If this request has data to send, then send it.
+ //
+ if(g_sUSBDeviceState.pui8EP0Data)
+ {
+ //
+ // If there is more data to send than is requested then just
+ // send the requested amount of data.
+ //
+ if(g_sUSBDeviceState.ui32EP0DataRemain > pUSBRequest->wLength)
+ {
+ g_sUSBDeviceState.ui32EP0DataRemain = pUSBRequest->wLength;
+ }
+
+ //
+ // Now in the transmit data state. Be careful to call the correct
+ // function since we need to handle the config descriptor
+ // differently from the others.
+ //
+ USBDEP0StateTx();
+ }
+ }
+}
+
+//*****************************************************************************
+//
+// This function determines which string descriptor to send to satisfy a
+// request for a given index and language.
+//
+// \param ui16Lang is the requested string language ID.
+// \param ui16Index is the requested string descriptor index.
+//
+// When a string descriptor is requested, the host provides a language ID and
+// index to identify the string ("give me string number 5 in French"). This
+// function maps these two parameters to an index within our device's string
+// descriptor array which is arranged as multiple groups of strings with
+// one group for each language advertised via string descriptor 0.
+//
+// We assume that there are an equal number of strings per language and
+// that the first descriptor is the language descriptor and use this fact to
+// perform the mapping.
+//
+// \return The index of the string descriptor to return or -1 if the string
+// could not be found.
+//
+//*****************************************************************************
+static int32_t
+USBDStringIndexFromRequest(uint16_t ui16Lang, uint16_t ui16Index)
+{
+ tString0Descriptor *pLang;
+ uint32_t ui32NumLangs;
+ uint32_t ui32NumStringsPerLang;
+ uint32_t ui32Loop;
+
+ //
+ // First look for the trivial case where descriptor 0 is being
+ // requested. This is the special case since descriptor 0 contains the
+ // language codes supported by the device.
+ //
+ if(ui16Index == 0)
+ {
+ return(0);
+ }
+
+ //
+ // How many languages does this device support? This is determined by
+ // looking at the length of the first descriptor in the string table,
+ // subtracting 2 for the header and dividing by two (the size of each
+ // language code).
+ //
+ ui32NumLangs = (g_ppui8StringDescriptors[0][0] - 2) / 2;
+
+ //
+ // We assume that the table includes the same number of strings for each
+ // supported language. We know the number of entries in the string table,
+ // so how many are there for each language? This may seem an odd way to
+ // do this (why not just have the application tell us in the device info
+ // structure?) but it's needed since we didn't want to change the API
+ // after the first release which did not support multiple languages.
+ //
+ ui32NumStringsPerLang = ((NUM_STRING_DESCRIPTORS - 1) / ui32NumLangs);
+
+ //
+ // Just to be sure, make sure that the calculation indicates an equal
+ // number of strings per language. We expect the string table to contain
+ // (1 + (strings_per_language * languages)) entries.
+ //
+ if((1 + (ui32NumStringsPerLang * ui32NumLangs)) != NUM_STRING_DESCRIPTORS)
+ {
+ return(-1);
+ }
+
+ //
+ // Now determine which language we are looking for. It is assumed that
+ // the order of the groups of strings per language in the table is the
+ // same as the order of the language IDs listed in the first descriptor.
+ //
+ pLang = (tString0Descriptor *)(g_ppui8StringDescriptors[0]);
+
+ //
+ // Look through the supported languages looking for the one we were asked
+ // for.
+ //
+ for(ui32Loop = 0; ui32Loop < ui32NumLangs; ui32Loop++)
+ {
+ //
+ // Have we found the requested language?
+ //
+ if(pLang->wLANGID[ui32Loop] == ui16Lang)
+ {
+ //
+ // Yes - calculate the index of the descriptor to send.
+ //
+ return((ui32NumStringsPerLang * ui32Loop) + ui16Index);
+ }
+ }
+
+ //
+ // If we drop out of the loop, the requested language was not found so
+ // return -1 to indicate the error.
+ //
+ return(-1);
+}
+
+//*****************************************************************************
+//
+// This function handles the SET_DESCRIPTOR standard USB request.
+//
+// \param pUSBRequest holds the data for this request.
+//
+// This function currently is not supported and will respond with a Stall
+// to indicate that this command is not supported by the device.
+//
+// \return None.
+//
+//*****************************************************************************
+static void
+USBDSetDescriptor(tUSBRequest *pUSBRequest)
+{
+ //
+ // This function is not handled by default.
+ //
+ USBBLStallEP0();
+}
+
+//*****************************************************************************
+//
+// This function handles the GET_CONFIGURATION standard USB request.
+//
+// \param pUSBRequest holds the data for this request.
+//
+// This function responds to a host request to return the current
+// configuration of the USB device. The function will send the configuration
+// response to the host and return. This value will either be 0 or the last
+// value received from a call to SetConfiguration().
+//
+// \return None.
+//
+//*****************************************************************************
+static void
+USBDGetConfiguration(tUSBRequest *pUSBRequest)
+{
+ uint8_t ui8Value;
+
+ //
+ // If we still have an address pending then the device is still not
+ // configured.
+ //
+ if(g_sUSBDeviceState.ui32DevAddress & DEV_ADDR_PENDING)
+ {
+ ui8Value = 0;
+ }
+ else
+ {
+ ui8Value = (uint8_t)g_sUSBDeviceState.ui32Configuration;
+ }
+
+ g_sUSBDeviceState.ui32EP0DataRemain = 1;
+ g_sUSBDeviceState.pui8EP0Data = &ui8Value;
+
+ //
+ // Send the single byte response.
+ //
+ USBDEP0StateTx();
+}
+
+//*****************************************************************************
+//
+// This function handles the SET_CONFIGURATION standard USB request.
+//
+// \param pUSBRequest holds the data for this request.
+//
+// This function responds to a host request to change the current
+// configuration of the USB device. The actual configuration number is taken
+// from the structure passed in via \e pUSBRequest.
+//
+// \return None.
+//
+//*****************************************************************************
+static void
+USBDSetConfiguration(tUSBRequest *pUSBRequest)
+{
+ //
+ // Cannot set the configuration to one that does not exist so check the
+ // enumeration structure to see how many valid configurations are present.
+ //
+ if(pUSBRequest->wValue > 1)
+ {
+ //
+ // The passed configuration number is not valid. Stall the endpoint to
+ // signal the error to the host.
+ //
+ USBBLStallEP0();
+ }
+ else
+ {
+ //
+ // Need to ack the data on end point 0.
+ //
+ USBDevEndpoint0DataAck(true);
+
+ //
+ // Save the configuration.
+ //
+ g_sUSBDeviceState.ui32Configuration = pUSBRequest->wValue;
+
+ //
+ // If passed a configuration other than 0 (which tells us that we are
+ // not currently configured), configure the endpoints (other than EP0)
+ // appropriately.
+ //
+ if(g_sUSBDeviceState.ui32Configuration)
+ {
+ //
+ // Set the power state
+ //
+#if USB_BUS_POWERED
+ g_sUSBDeviceState.ui8Status &= ~USB_STATUS_SELF_PWR;
+#else
+ g_sUSBDeviceState.ui8Status |= USB_STATUS_SELF_PWR;
+#endif
+ }
+
+ //
+ // Do whatever needs to be done as a result of the config change.
+ //
+ HandleConfigChange(g_sUSBDeviceState.ui32Configuration);
+ }
+}
+
+//*****************************************************************************
+//
+// This function handles the GET_INTERFACE standard USB request.
+//
+// \param pUSBRequest holds the data for this request.
+//
+// This function is called when the host controller request the current
+// interface that is in use by the device. This simply returns the value set
+// by the last call to SetInterface().
+//
+// \return None.
+//
+//*****************************************************************************
+static void
+USBDGetInterface(tUSBRequest *pUSBRequest)
+{
+ uint8_t ui8Value;
+
+ //
+ // If we still have an address pending then the device is still not
+ // configured.
+ //
+ if(g_sUSBDeviceState.ui32DevAddress & DEV_ADDR_PENDING)
+ {
+ ui8Value = 0;
+ }
+ else
+ {
+ //
+ // Is the interface number valid?
+ //
+ if(pUSBRequest->wIndex == 0)
+ {
+ //
+ // Read the current alternate setting for the required interface.
+ //
+ ui8Value = g_sUSBDeviceState.ui8AltSetting;
+ }
+ else
+ {
+ //
+ // An invalid interface number was specified.
+ //
+ USBBLStallEP0();
+ return;
+ }
+ }
+
+ //
+ // Send the single byte response.
+ //
+ g_sUSBDeviceState.ui32EP0DataRemain = 1;
+ g_sUSBDeviceState.pui8EP0Data = &ui8Value;
+
+ //
+ // Send the single byte response.
+ //
+ USBDEP0StateTx();
+}
+
+//*****************************************************************************
+//
+// This function handles the SET_INTERFACE standard USB request.
+//
+// \param pUSBRequest holds the data for this request.
+//
+// The DFU device supports a single interface with no alternate settings so
+// this handler is hardcoded assuming this configuration.
+//
+// \return None.
+//
+//*****************************************************************************
+static void
+USBDSetInterface(tUSBRequest *pUSBRequest)
+{
+ if((pUSBRequest->wIndex == 0) && (pUSBRequest->wValue == 0))
+ {
+ //
+ // We were passed a valid interface number so acknowledge the request.
+ //
+ USBDevEndpoint0DataAck(true);
+ }
+ else
+ {
+ //
+ // The values passed were not valid so stall endpoint 0.
+ //
+ USBBLStallEP0();
+ }
+}
+
+//*****************************************************************************
+//
+// This internal function handles sending data on endpoint zero.
+//
+// \return None.
+//
+//*****************************************************************************
+static void
+USBDEP0StateTx(void)
+{
+ uint32_t ui32NumBytes;
+ uint8_t *pui8Data;
+
+ //
+ // In the TX state on endpoint zero.
+ //
+ g_eUSBDEP0State = USB_STATE_TX;
+
+ //
+ // Set the number of bytes to send this iteration.
+ //
+ ui32NumBytes = g_sUSBDeviceState.ui32EP0DataRemain;
+
+ //
+ // Limit individual transfers to 64 bytes.
+ //
+ if(ui32NumBytes > EP0_MAX_PACKET_SIZE)
+ {
+ ui32NumBytes = EP0_MAX_PACKET_SIZE;
+ }
+
+ //
+ // Save the pointer so that it can be passed to the USBEndpointDataPut()
+ // function.
+ //
+ pui8Data = g_sUSBDeviceState.pui8EP0Data;
+
+ //
+ // Advance the data pointer and counter to the next data to be sent.
+ //
+ g_sUSBDeviceState.ui32EP0DataRemain -= ui32NumBytes;
+ g_sUSBDeviceState.pui8EP0Data += ui32NumBytes;
+
+ //
+ // Put the data in the correct FIFO.
+ //
+ USBEndpoint0DataPut(pui8Data, ui32NumBytes);
+
+ //
+ // If this is exactly 64 then don't set the last packet yet.
+ //
+ if(ui32NumBytes == EP0_MAX_PACKET_SIZE)
+ {
+ //
+ // There is more data to send or exactly 64 bytes were sent, this
+ // means that there is either more data coming or a null packet needs
+ // to be sent to complete the transaction.
+ //
+ USBEndpoint0DataSend(USB_TRANS_IN);
+ }
+ else
+ {
+ //
+ // Now go to the status state and wait for the transmit to complete.
+ //
+ g_eUSBDEP0State = USB_STATE_STATUS;
+
+ //
+ // Send the last bit of data.
+ //
+ USBEndpoint0DataSend(USB_TRANS_IN_LAST);
+ g_sUSBDeviceState.ui32OUTDataSize = 0;
+ }
+}
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
+#endif // USB_ENABLE_UPDATE
diff --git a/boot_loader/bl_usbfuncs.h b/boot_loader/bl_usbfuncs.h
new file mode 100644
index 0000000..7c3868c
--- /dev/null
+++ b/boot_loader/bl_usbfuncs.h
@@ -0,0 +1,505 @@
+//*****************************************************************************
+//
+// bl_usbfuncs.h - Prototypes for the subset of USB library functions used in
+// the USB DFU boot loader.
+//
+// Copyright (c) 2008-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
+//
+//*****************************************************************************
+
+#ifndef __BL_USBFUNCS_H__
+#define __BL_USBFUNCS_H__
+
+//*****************************************************************************
+//
+//! \addtogroup bl_usb_api
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// If building with a C++ compiler, make all of the definitions in this header
+// have a C binding.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+//*****************************************************************************
+//
+// The following macro allows compiler-independent syntax to be used to
+// define packed structures. A typical structure definition using these
+// macros will look similar to the following example:
+//
+// #ifdef ewarm
+// #pragma pack(1)
+// #endif
+//
+// typedef struct _PackedStructName
+// {
+// uint32_t ui32FirstField;
+// int8_t i8CharMember;
+// uint16_t ui16Short;
+// }
+// PACKED tPackedStructName;
+//
+// #ifdef ewarm
+// #pragma pack()
+// #endif
+//
+// The conditional blocks related to ewarm include the #pragma pack() lines
+// only if the IAR Embedded Workbench compiler is being used. Unfortunately,
+// it is not possible to emit a #pragma from within a macro definition so this
+// must be done explicitly.
+//
+//*****************************************************************************
+#if defined(ccs) || \
+ defined(codered) || \
+ defined(gcc) || \
+ defined(rvmdk) || \
+ defined(__ARMCC_VERSION) || \
+ defined(sourcerygxx)
+#define PACKED __attribute__ ((packed))
+#elif defined(ewarm)
+#define PACKED
+#else
+#error Unrecognized COMPILER!
+#endif
+
+//*****************************************************************************
+//
+// Standard USB descriptor types. These values are passed in the upper bytes
+// of tUSBRequest.wValue on USBREQ_GET_DESCRIPTOR and also appear in the
+// bDescriptorType field of standard USB descriptors.
+//
+//*****************************************************************************
+#define USB_DTYPE_DEVICE 1
+#define USB_DTYPE_CONFIGURATION 2
+#define USB_DTYPE_STRING 3
+#define USB_DTYPE_INTERFACE 4
+#define USB_DTYPE_ENDPOINT 5
+#define USB_DTYPE_DEVICE_QUAL 6
+#define USB_DTYPE_OSPEED_CONF 7
+#define USB_DTYPE_INTERFACE_PWR 8
+
+#define USBShort(ui16Value) (ui16Value & 0xff), (ui16Value >> 8)
+
+#define USB_LANG_EN_US 0x0409 // English (United States)
+
+#define USB_EP_DEV_IN 0x00002000 // Device IN endpoint
+#define USB_EP_DEV_OUT 0x00001000 // Device OUT endpoint
+
+//*****************************************************************************
+//
+// All structures defined in this section of the header require byte packing of
+// fields. This is usually accomplished using the PACKED macro but, for IAR
+// Embedded Workbench, this requires a pragma.
+//
+//*****************************************************************************
+#ifdef ewarm
+#pragma pack(1)
+#endif
+
+//*****************************************************************************
+//
+// Definitions related to standard USB device requests (sections 9.3 & 9.4)
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+//! The standard USB request header as defined in section 9.3 of the USB 2.0
+//! specification.
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ //! Determines the type and direction of the request.
+ //
+ uint8_t bmRequestType;
+
+ //
+ //! Identifies the specific request being made.
+ //
+ uint8_t bRequest;
+
+ //
+ //! Word-sized field that varies according to the request.
+ //
+ uint16_t wValue;
+
+ //
+ //! Word-sized field that varies according to the request; typically used
+ //! to pass an index or offset.
+ //
+ uint16_t wIndex;
+
+ //
+ //! The number of bytes to transfer if there is a data stage to the
+ //! request.
+ //
+ uint16_t wLength;
+}
+PACKED tUSBRequest;
+
+//*****************************************************************************
+//
+// The following defines are used with the bmRequestType member of tUSBRequest.
+//
+// Request types have 3 bit fields:
+// 4:0 - Is the recipient type.
+// 6:5 - Is the request type.
+// 7 - Is the direction of the request.
+//
+//*****************************************************************************
+#define USB_RTYPE_DIR_IN 0x80
+#define USB_RTYPE_DIR_OUT 0x00
+
+#define USB_RTYPE_TYPE_M 0x60
+#define USB_RTYPE_VENDOR 0x40
+#define USB_RTYPE_CLASS 0x20
+#define USB_RTYPE_STANDARD 0x00
+
+#define USB_RTYPE_RECIPIENT_M 0x1f
+#define USB_RTYPE_OTHER 0x03
+#define USB_RTYPE_ENDPOINT 0x02
+#define USB_RTYPE_INTERFACE 0x01
+#define USB_RTYPE_DEVICE 0x00
+
+//*****************************************************************************
+//
+// Standard USB requests IDs used in the bRequest field of tUSBRequest.
+//
+//*****************************************************************************
+#define USBREQ_GET_STATUS 0x00
+#define USBREQ_CLEAR_FEATURE 0x01
+#define USBREQ_SET_FEATURE 0x03
+#define USBREQ_SET_ADDRESS 0x05
+#define USBREQ_GET_DESCRIPTOR 0x06
+#define USBREQ_SET_DESCRIPTOR 0x07
+#define USBREQ_GET_CONFIG 0x08
+#define USBREQ_SET_CONFIG 0x09
+#define USBREQ_GET_INTERFACE 0x0a
+#define USBREQ_SET_INTERFACE 0x0b
+#define USBREQ_SYNC_FRAME 0x0c
+
+//*****************************************************************************
+//
+// Data returned from a USBREQ_GET_STATUS request to a device.
+//
+//*****************************************************************************
+#define USB_STATUS_SELF_PWR 0x0001 // Currently self powered.
+#define USB_STATUS_BUS_PWR 0x0000 // Currently bus-powered.
+#define USB_STATUS_PWR_M 0x0001 // Mask for power mode.
+#define USB_STATUS_REMOTE_WAKE 0x0002 // Remote wake-up is currently enabled.
+
+
+//*****************************************************************************
+//
+//! This structure describes the USB configuration descriptor as defined in
+//! USB 2.0 specification section 9.6.3. This structure also applies to the
+//! USB other speed configuration descriptor defined in section 9.6.4.
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ //! The length of this descriptor in bytes. All configuration descriptors
+ //! are 9 bytes long.
+ //
+ uint8_t bLength;
+
+ //
+ //! The type of the descriptor. For a configuration descriptor, this will
+ //! be USB_DTYPE_CONFIGURATION (2).
+ //
+ uint8_t bDescriptorType;
+
+ //
+ //! The total length of data returned for this configuration. This
+ //! includes the combined length of all descriptors (configuration,
+ //! interface, endpoint and class- or vendor-specific) returned for this
+ //! configuration.
+ //
+ uint16_t wTotalLength;
+
+ //
+ //! The number of interface supported by this configuration.
+ //
+ uint8_t bNumInterfaces;
+
+ //
+ //! The value used as an argument to the SetConfiguration standard request
+ //! to select this configuration.
+ //
+ uint8_t bConfigurationValue;
+
+ //
+ //! The index of a string descriptor describing this configuration.
+ //
+ uint8_t iConfiguration;
+
+ //
+ //! Attributes of this configuration.
+ //
+ uint8_t bmAttributes;
+
+ //
+ //! The maximum power consumption of the USB device from the bus in this
+ //! configuration when the device is fully operational. This is expressed
+ //! in units of 2mA so, for example, 100 represents 200mA.
+ //
+ uint8_t bMaxPower;
+}
+PACKED tConfigDescriptor;
+
+//*****************************************************************************
+//
+// Flags used in constructing the value assigned to the field
+// tConfigDescriptor.bmAttributes. Note that bit 7 is reserved and must be set
+// to 1.
+//
+//*****************************************************************************
+#define USB_CONF_ATTR_PWR_M 0xC0
+
+#define USB_CONF_ATTR_SELF_PWR 0xC0
+#define USB_CONF_ATTR_BUS_PWR 0x80
+#define USB_CONF_ATTR_RWAKE 0xA0
+
+//*****************************************************************************
+//
+// Feature Selectors (tUSBRequest.wValue) passed on USBREQ_CLEAR_FEATURE and
+// USBREQ_SET_FEATURE.
+//
+//*****************************************************************************
+#define USB_FEATURE_EP_HALT 0x0000 // Endpoint halt feature.
+#define USB_FEATURE_REMOTE_WAKE 0x0001 // Remote wake feature, device only.
+#define USB_FEATURE_TEST_MODE 0x0002 // Test mode
+
+//*****************************************************************************
+//
+//! This structure describes the USB string descriptor for index 0 as defined
+//! in USB 2.0 specification section 9.6.7. Note that the number of language
+//! IDs is variable and can be determined by examining bLength. The number of
+//! language IDs present in the descriptor is given by ((bLength - 2) / 2).
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ //! The length of this descriptor in bytes. This value will vary
+ //! depending upon the number of language codes provided in the descriptor.
+ //
+ uint8_t bLength;
+
+ //
+ //! The type of the descriptor. For a string descriptor, this will be
+ //! USB_DTYPE_STRING (3).
+ //
+ uint8_t bDescriptorType;
+
+ //
+ //! The language code (LANGID) for the first supported language. Note that
+ //! this descriptor may support multiple languages, in which case, the
+ //! number of elements in the wLANGID array will increase and bLength will
+ //! be updated accordingly.
+ //
+ uint16_t wLANGID[1];
+}
+PACKED tString0Descriptor;
+
+//*****************************************************************************
+//
+//! This structure describes the USB string descriptor for all string indexes
+//! other than 0 as defined in USB 2.0 specification section 9.6.7.
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ //! The length of this descriptor in bytes. This value will be 2 greater
+ //! than the number of bytes comprising the UNICODE string that the
+ //! descriptor contains.
+ //
+ uint8_t bLength;
+
+ //
+ //! The type of the descriptor. For a string descriptor, this will be
+ //! USB_DTYPE_STRING (3).
+ //
+ uint8_t bDescriptorType;
+
+ //
+ //! The first byte of the UNICODE string. This string is not NULL
+ //! terminated. Its length (in bytes) can be computed by subtracting 2
+ //! from the value in the bLength field.
+ //
+ uint8_t bString;
+}
+PACKED tStringDescriptor;
+
+//*****************************************************************************
+//
+// Return to default packing when using the IAR Embedded Workbench compiler.
+//
+//*****************************************************************************
+#ifdef ewarm
+#pragma pack()
+#endif
+
+//*****************************************************************************
+//
+// Some standard USB class definitions.
+//
+//*****************************************************************************
+#define USB_CLASS_APP_SPECIFIC 0xfe
+#define USB_CLASS_VEND_SPECIFIC 0xff
+
+//*****************************************************************************
+//
+// The following are values that are returned from USBEndpointStatus(). The
+// USB_HOST_* values are used when the USB controller is in host mode and the
+// USB_DEV_* values are used when the USB controller is in device mode.
+//
+//*****************************************************************************
+#define USB_DEV_RX_SENT_STALL 0x00400000 // Stall was sent on this endpoint
+#define USB_DEV_RX_DATA_ERROR 0x00080000 // CRC error on the data
+#define USB_DEV_RX_OVERRUN 0x00040000 // OUT packet was not loaded due to
+ // a full FIFO
+#define USB_DEV_RX_FIFO_FULL 0x00020000 // RX FIFO full
+#define USB_DEV_RX_PKT_RDY 0x00010000 // Data packet ready
+#define USB_DEV_TX_NOT_COMP 0x00000080 // Large packet split up, more data
+ // to come
+#define USB_DEV_TX_SENT_STALL 0x00000020 // Stall was sent on this endpoint
+#define USB_DEV_TX_UNDERRUN 0x00000004 // IN received with no data ready
+#define USB_DEV_TX_FIFO_NE 0x00000002 // The TX FIFO is not empty
+#define USB_DEV_TX_TXPKTRDY 0x00000001 // Transmit still being transmitted
+#define USB_DEV_EP0_SETUP_END 0x00000010 // Control transaction ended before
+ // Data End seen
+#define USB_DEV_EP0_SENT_STALL 0x00000004 // Stall was sent on this endpoint
+#define USB_DEV_EP0_IN_PKTPEND 0x00000002 // Transmit data packet pending
+#define USB_DEV_EP0_OUT_PKTRDY 0x00000001 // Receive data packet ready
+
+//*****************************************************************************
+//
+// This value specifies the maximum size of transfers on endpoint 0 as 64
+// bytes. This value is fixed in hardware as the FIFO size for endpoint 0.
+//
+//*****************************************************************************
+#define MAX_PACKET_SIZE_EP0 64
+
+//*****************************************************************************
+//
+// These values are used to indicate which endpoint to access.
+//
+//*****************************************************************************
+#define USB_EP_0 0x00000000 // Endpoint 0
+#define NUM_USB_EP 4 // Number of supported endpoints
+
+//*****************************************************************************
+//
+// These macros allow conversion between 0-based endpoint indices and the
+// USB_EP_x values required when calling various USB APIs.
+//
+//*****************************************************************************
+#define INDEX_TO_USB_EP(x) ((x) << 4)
+#define USB_EP_TO_INDEX(x) ((x) >> 4)
+
+//*****************************************************************************
+//
+// The following are values that can be passed to USBEndpointDataSend() as the
+// ui32TransType parameter.
+//
+//*****************************************************************************
+#define USB_TRANS_OUT 0x00000102 // Normal OUT transaction
+#define USB_TRANS_IN 0x00000102 // Normal IN transaction
+#define USB_TRANS_IN_LAST 0x0000010a // Final IN transaction (for
+ // endpoint 0 in device mode)
+#define USB_TRANS_SETUP 0x0000110a // Setup transaction (for endpoint
+ // 0)
+#define USB_TRANS_STATUS 0x00000142 // Status transaction (for endpoint
+ // 0)
+
+//*****************************************************************************
+//
+// Function prototype for any standard USB request.
+//
+//*****************************************************************************
+typedef void (* tStdRequest)(tUSBRequest *psUSBRequest);
+
+//*****************************************************************************
+//
+// Data structures defined in bl_usb.c but referenced elsewhere.
+//
+//*****************************************************************************
+extern const uint8_t g_pui8DFUConfigDescriptor[];
+extern const uint8_t g_pui8DFUDeviceDescriptor[];
+extern const uint8_t * const g_ppui8StringDescriptors[];
+
+#define NUM_STRING_DESCRIPTORS 4
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// Prototypes of the various USB handler functions.
+//
+//*****************************************************************************
+extern void HandleRequests(tUSBRequest *psUSBRequest);
+extern void HandleConfigChange(uint32_t ui32Info);
+extern void HandleEP0Data(uint32_t ui32Info);
+extern void HandleReset(void);
+extern void HandleDisconnect(void);
+extern void HandleSetAddress(void);
+
+//*****************************************************************************
+//
+// Prototypes for the APIs.
+//
+//*****************************************************************************
+extern void USBDevEndpoint0DataAck(bool bIsLastPacket);
+extern int32_t USBEndpoint0DataGet(uint8_t *pui8Data, uint32_t *pui32Size);
+extern int32_t USBEndpoint0DataPut(uint8_t *pui8Data, uint32_t ui32Size);
+extern int32_t USBEndpoint0DataSend(uint32_t ui32TransType);
+extern void USBBLInit(void);
+extern void USBBLStallEP0(void);
+extern void USBBLRequestDataEP0(uint8_t *pui8Data, uint32_t ui32Size);
+extern void USBBLSendDataEP0(uint8_t *pui8Data, uint32_t ui32Size);
+extern void USBDeviceEnumHandler(void);
+extern void USBDeviceEnumResetHandler(void);
+
+//*****************************************************************************
+//
+// Mark the end of the C bindings section for C++ compilers.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __BL_USBFUNCS_H__
diff --git a/boot_loader/readme.txt b/boot_loader/readme.txt
new file mode 100644
index 0000000..6c37d28
--- /dev/null
+++ b/boot_loader/readme.txt
@@ -0,0 +1,28 @@
+Boot Loader
+
+The boot loader is a small piece of code that can be programmed at the
+beginning of flash to act as an application loader as well as an update
+mechanism for an application running on a Tiva microcontroller, utilizing
+either UART0, I2C0, SSI0, Ethernet or USB. The capabilities of the boot loader
+are configured via the bl_config.h include file (which is located in the
+application directory, not in the boot loader source directory).
+
+-------------------------------------------------------------------------------
+
+Copyright (c) 2007-2014 Texas Instruments Incorporated. All rights reserved.
+Software License Agreement
+
+Texas Instruments (TI) is supplying this software for use solely and
+exclusively on TI's microcontroller products. The software is owned by
+TI and/or its suppliers, and is protected under applicable copyright
+laws. You may not combine this software with "viral" open-source
+software in order to form a larger program.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+DAMAGES, FOR ANY REASON WHATSOEVER.
+
+This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
diff --git a/boot_loader/uip-conf.h b/boot_loader/uip-conf.h
new file mode 100644
index 0000000..5c1d770
--- /dev/null
+++ b/boot_loader/uip-conf.h
@@ -0,0 +1,108 @@
+//*****************************************************************************
+//
+// uip-conf.h - uIP configuration for the boot loader.
+//
+// Copyright (c) 2007-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
+//
+//*****************************************************************************
+
+#ifndef __UIP_CONF_H__
+#define __UIP_CONF_H__
+
+//*****************************************************************************
+//
+// This typedef defines the 8-bit type used throughout uIP.
+//
+//*****************************************************************************
+typedef uint8_t u8_t;
+
+//*****************************************************************************
+//
+// This typedef defines the 16-bit type used throughout uIP.
+//
+//*****************************************************************************
+typedef uint16_t u16_t;
+
+//*****************************************************************************
+//
+// This typedef defines the dataype used for keeping statistics in uIP.
+//
+//*****************************************************************************
+typedef uint16_t uip_stats_t;
+
+//*****************************************************************************
+//
+// Turn off TCP support.
+//
+//*****************************************************************************
+#define UIP_CONF_TCP 0
+
+//*****************************************************************************
+//
+// Turn on UDP support.
+//
+//*****************************************************************************
+#define UIP_CONF_UDP 1
+
+//*****************************************************************************
+//
+// Only support a single UDP connection.
+//
+//*****************************************************************************
+#define UIP_CONF_UDP_CONNS 1
+
+//*****************************************************************************
+//
+// Only support a single entry in the ARP table.
+//
+//*****************************************************************************
+#define UIP_CONF_ARPTAB_SIZE 1
+
+//*****************************************************************************
+//
+// Set the size of the uIP packet data buffer.
+//
+//*****************************************************************************
+#define UIP_CONF_BUFFER_SIZE 1600//700
+
+//*****************************************************************************
+//
+// Enable UDP broadcast support.
+//
+//*****************************************************************************
+#define UIP_CONF_BROADCAST 1
+
+//*****************************************************************************
+//
+// Define a data type for the UDP application state. This is not used, but
+// must be defined for uIP.
+//
+//*****************************************************************************
+typedef uint32_t uip_udp_appstate_t;
+
+//*****************************************************************************
+//
+// The name of the function to be called when UDP packets arrive, or when the
+// UDP periodic timer expires.
+//
+//*****************************************************************************
+extern char BOOTPThread(void);
+#define UIP_UDP_APPCALL BOOTPThread
+
+#endif // __UIP_CONF_H__
diff --git a/boot_loader/usbdfu.h b/boot_loader/usbdfu.h
new file mode 100644
index 0000000..3ae00e1
--- /dev/null
+++ b/boot_loader/usbdfu.h
@@ -0,0 +1,420 @@
+//*****************************************************************************
+//
+// usbdfu.h - Definitions related to the USB Device Firmware Upgrade class.
+//
+// Copyright (c) 2008-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
+//
+//*****************************************************************************
+
+#ifndef __USBDFU_H__
+#define __USBDFU_H__
+
+//*****************************************************************************
+//
+// DFU attributes as published in the functional descriptor.
+//
+//*****************************************************************************
+#define DFU_ATTR_WILL_DETACH 0x08
+#define DFU_ATTR_MANIFEST_TOLERANT \
+ 0x04
+#define DFU_ATTR_CAN_UPLOAD 0x02
+#define DFU_ATTR_CAN_DOWNLOAD 0x01
+
+//*****************************************************************************
+//
+// The states that the DFU device can be in. These values are reported to
+// the host in response to a USBD_DFU_REQUEST_GETSTATE request.
+//
+//*****************************************************************************
+typedef enum
+{
+ STATE_APP_IDLE = 0,
+ STATE_APP_DETACH,
+ STATE_IDLE,
+ STATE_DNLOAD_SYNC,
+ STATE_DNBUSY,
+ STATE_DNLOAD_IDLE,
+ STATE_MANIFEST_SYNC,
+ STATE_MANIFEST,
+ STATE_MANIFEST_WAIT_RESET,
+ STATE_UPLOAD_IDLE,
+ STATE_ERROR
+}
+tDFUState;
+
+//*****************************************************************************
+//
+// The current error status of the DFU device. These values are reported to
+// the host in response to a USBD_DFU_REQUEST_GETSTATUS request.
+//
+//*****************************************************************************
+typedef enum
+{
+ STATUS_OK = 0,
+ STATUS_ERR_TARGET,
+ STATUS_ERR_FILE,
+ STATUS_ERR_WRITE,
+ STATUS_ERR_ERASE,
+ STATUS_ERR_CHECK_ERASED,
+ STATUS_ERR_PROG,
+ STATUS_ERR_VERIFY,
+ STATUS_ERR_ADDRESS,
+ STATUS_ERR_NOTDONE,
+ STATUS_ERR_FIRMWARE,
+ STATUS_ERR_VENDOR,
+ STATUS_ERR_USBR,
+ STATUS_ERR_POR,
+ STATUS_ERR_UNKNOWN,
+ STATUS_ERR_STALLEDPKT
+}
+tDFUStatus;
+
+//*****************************************************************************
+//
+// The descriptor type for the DFU functional descriptor.
+//
+//*****************************************************************************
+#define USB_DFU_FUNC_DESCRIPTOR_TYPE 0x21
+
+//*****************************************************************************
+//
+// The subclass identifier for DFU as reported to the host in the
+// bInterfaceSubClass field of the DFU interface descriptor.
+//
+//*****************************************************************************
+#define USB_DFU_SUBCLASS 0x01
+
+//*****************************************************************************
+//
+// The protocol identifier for DFU as reported to the host in the
+// bInterfaceProtocol field of the DFU interface descriptor.
+//
+//*****************************************************************************
+#define USB_DFU_PROTOCOL 0x02
+#define USB_DFU_RUNTIME_PROTOCOL 0x01
+
+//*****************************************************************************
+//
+// DFU class-specific request identifiers.
+//
+//*****************************************************************************
+#define USBD_DFU_REQUEST_DETACH 0
+#define USBD_DFU_REQUEST_DNLOAD 1
+#define USBD_DFU_REQUEST_UPLOAD 2
+#define USBD_DFU_REQUEST_GETSTATUS 3
+#define USBD_DFU_REQUEST_CLRSTATUS 4
+#define USBD_DFU_REQUEST_GETSTATE 5
+#define USBD_DFU_REQUEST_ABORT 6
+
+//*****************************************************************************
+//
+// Request 1KB blocks from the host. This value is published in the USB
+// functional descriptor.
+//
+//*****************************************************************************
+#define DFU_TRANSFER_SIZE 1024
+
+//*****************************************************************************
+//
+// TIVA-specific request identifier. This is used to determine whether
+// the target device supports our DFU command protocol. It is expected that
+// a device not supporting our extensions will stall this request. This
+// request is only supported while the DFU device is in STATE_IDLE.
+//
+// An IN request containing the following parameters will result in the device
+// sending back a tDFUQueryTIVAProtocol structure indicating that
+// TIVA extensions are supported. The actual values in wValue and wIndex
+// have no meaning other than to act as markers in the unlikely event that
+// another DFU device also chooses to use request ID 0x42 for some other
+// purpose.
+//
+// wValue - 0x23(REQUEST_TIVA_VALUE)
+// wIndex - Interface number
+// wLength - sizeof(tDFUQueryTIVAProtocol)
+//
+//*****************************************************************************
+#define USBD_DFU_REQUEST_TIVA 0x42
+#define REQUEST_TIVA_VALUE 0x23
+
+#define DFU_PROTOCOL_USBLIB_MARKER \
+ 0x4C4D
+#define DFU_PROTOCOL_USBLIB_VERSION_1 \
+ 0x0001
+
+#ifdef ewarm
+#pragma pack(1)
+#endif
+
+//*****************************************************************************
+//
+// The structure sent to the host when a valid USBD_DFU_REQUEST_TIVA is
+// received while the DFU device is in idle state.
+//
+//*****************************************************************************
+typedef struct
+{
+ uint16_t ui16Marker; // DFU_PROTOCOL_USBLIB_MARKER
+ uint16_t ui16Version; // DFU_PROTOCOL_USBLIB_VERSION_1
+}
+PACKED tDFUQueryTIVAProtocol;
+
+//*****************************************************************************
+//
+// Structure sent to the host in response to USBD_DFU_REQUEST_GETSTATUS.
+//
+//*****************************************************************************
+typedef struct
+{
+ uint8_t bStatus;
+ uint8_t bwPollTimeout[3];
+ uint8_t bState;
+ uint8_t iString;
+}
+PACKED tDFUGetStatusResponse;
+
+//*****************************************************************************
+//
+// Firmware Download Commands
+//
+// The data passed on a USBD_DFU_REQUEST_DNLOAD request is comprised of a
+// header which instructs the boot loader how to interpret the block and
+// block-specific data. The following definitions relate to the download
+// block headers.
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// Supported command identifiers
+//
+//*****************************************************************************
+#define DFU_CMD_PROG 0x01
+#define DFU_CMD_READ 0x02
+#define DFU_CMD_CHECK 0x03
+#define DFU_CMD_ERASE 0x04
+#define DFU_CMD_INFO 0x05
+#define DFU_CMD_BIN 0x06
+#define DFU_CMD_RESET 0x07
+
+//*****************************************************************************
+//
+// Generic download command header.
+//
+//*****************************************************************************
+typedef struct
+{
+ uint8_t ui8Command; // Command identifier.
+ uint8_t pui8Data[7]; // Command-specific data elements.
+}
+PACKED tDFUDownloadHeader;
+
+//*****************************************************************************
+//
+// Header for the DFU_CMD_PROG command.
+//
+// This command is used to program a section of the flash with the binary data
+// which immediately follows the header. The start address of the data is
+// expressed as a 1KB block number so 0 would represent the bottom of flash
+// (which, incidentally, the USB boot loader will not let you program) and 0x10
+// would represent address 16KB or 16384 (0x4000). The ui32Length field
+// contains the total number of bytes of data in the following programming
+// operation. The DFU device will not look for any command header on following
+// USBD_DFU_REQUEST_DNLOAD requests until the operation is completed or
+// aborted.
+//
+// By using this protocol, the DFU_CMD_PROG command header may be used as a
+// simple header on the binary files to be sent to the DFU device for
+// programming. If we enforce the requirement that the DFU_CMD_PROG header is
+// applied to each USBD_DFU_REQUEST_DNLOAD (one per block), this means that the
+// host-side DFU application must be aware of the underlying protocol and
+// insert these headers dynamically during programming operations. This could
+// be handled by post processing the binary to insert the headers at the
+// appropriate points but this would then tie the binary structure to the
+// chosen transfer size and break the operation if the transfer size were to
+// change in the future.
+//
+//*****************************************************************************
+typedef struct
+{
+ uint8_t ui8Command; // DFU_CMD_PROG
+ uint8_t ui8Reserved; // Reserved - set to 0x00.
+ uint16_t ui16StartAddr; // Block start address / 1024
+ uint32_t ui32Length; // Total length, in bytes, of following data
+ // for the complete download operation.
+}
+PACKED tDFUDownloadProgHeader;
+
+//*****************************************************************************
+//
+// Header for the DFU_CMD_READ and DFU_CMD_CHECK commands.
+//
+// This command may be used to set the address range whose content will be
+// returned on subsequent USBD_DFU_REQUEST_UPLOAD requests from the host.
+//
+// To read back a the contents of a region of flash, the host should send
+// USBD_DFU_REQUEST_DNLOAD with ui8Command DFU_CMD_READ, ui16StartAddr set to
+// the 1KB block start address and ui32Length set to the number of bytes to
+// read. The host should then send one or more USBD_DFU_REQUEST_UPLOAD
+// requests to receive the current flash contents from the configured
+// addresses. Data returned will include an 8 byte DFU_CMD_PROG prefix
+// structure unless the prefix has been disabled by sending a DFU_CMD_BIN
+// command with the bBinary parameter set to 1.
+//
+// To check that a region of flash is erased, the DFU_CMD_CHECK command should
+// be sent with ui16StartAddr and ui32Length set to describe the region to
+// check. The host should then send a USBD_DFU_REQUEST_GETSTATUS. If the
+// erase check was successful, the returned bStatus value will be STATUS_OK,
+// otherwise it will be STATUS_ERR_CHECK_ERASED. Note that ui32Length passed
+// must be a multiple of 4. If this is not the case, the value will be
+// truncated before the check is performed.
+//
+//*****************************************************************************
+typedef struct
+{
+ uint8_t ui8Command; // DFU_CMD_READ or DFU_CMD_CHECK
+ uint8_t ui8Reserved; // Reserved - write to 0
+ uint16_t ui16StartAddr; // Block start address / 1024
+ uint32_t ui32Length; // The number of bytes of data to read back or
+ // check.
+}
+PACKED tDFUDownloadReadCheckHeader;
+
+//*****************************************************************************
+//
+// Header for the DFU_CMD_ERASE command.
+//
+// This command may be used to erase a number of flash blocks. The address of
+// the first block to be erased is passed in ui16StartAddr with ui16NumBlocks
+// containing the number of blocks to be erased from this address. The block
+// size of the device may be determined using the DFU_CMD_INFO command.
+//
+//*****************************************************************************
+typedef struct
+{
+ uint8_t ui8Command; // DFU_CMD_ERASE
+ uint8_t ui8Reserved; // Reserved - set to 0
+ uint16_t ui16StartAddr; // Block start address / 1024
+ uint16_t ui16NumBlocks; // The number of blocks to erase
+ uint8_t pui8Reserved2[2]; // Reserved - set to 0
+}
+PACKED tDFUDownloadEraseHeader;
+
+//*****************************************************************************
+//
+// Header for the DFU_CMD_INFO command.
+//
+// This command may be used to query information about the connected device.
+// After sending the command, the information is returned on the next
+// USBD_DFU_REQUEST_UPLOAD request.
+//
+//*****************************************************************************
+typedef struct
+{
+ uint8_t ui8Command; // DFU_CMD_INFO
+ uint8_t pui8Reserved[7]; // Reserved - set to 0
+}
+PACKED tDFUDownloadInfoHeader;
+
+//*****************************************************************************
+//
+// Header for the DFU_CMD_BIN command.
+//
+// This command may be used to set the format of uploaded data. By default,
+// images read using USBD_DFU_REQUEST_UPLOAD are formatted with the appropriate
+// header to allow the same image to be flashed back to the device and have it
+// located at the address from which it originated. This is a requirement of
+// the DFU class specification (section 6.2 "the uploaded image must be
+// usable in a subsequent download") but may not be helpful in some cases where
+// the application wishes to receive only the binary image from flash. To
+// instruct the DFU device to omit the position and size header, send this
+// command with the bBinary field set to \b true prior to issuing a
+// USBD_DFU_REQUEST_UPLOAD for image data. The format choice remains in effect
+// until the command is sent once again with bBinary set to \b false.
+//
+// Note that the format choice affects only image data sent and not responses
+// read via USBD_DFU_REQUEST_UPLOAD following software-specific commands such
+// as DFU_CMD_INFO.
+//
+//*****************************************************************************
+typedef struct
+{
+ uint8_t ui8Command; // DFU_CMD_BIN
+ uint8_t bBinary; // Set to true to omit image header or false
+ // to include it (the default)
+ uint8_t pui8Reserved[6]; // Reserved - set to 0
+}
+PACKED tDFUDownloadBinHeader;
+
+//*****************************************************************************
+//
+// The DFU_CMD_RESET command uses a tDFUDownloadHeader structure since
+// only the ui8Command field is important. This command causes an immediate
+// reset of the the target board.
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+//! Payload returned in response to the DFU_CMD_INFO command.
+//!
+//! This is structure is returned in response to the first
+//! USBD_DFU_REQUEST_UPLOAD request following a DFU_CMD_INFO command.
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ //! The size of a flash block in bytes.
+ //
+ uint16_t ui16FlashBlockSize;
+
+ //
+ //! The number of blocks of flash in the device. Total flash size is
+ //! ui16NumFlashBlocks * ui16FlashBlockSize.
+ //
+ uint16_t ui16NumFlashBlocks;
+
+ //
+ //! Information on the part number, family, version and package as read
+ //! from SYSCTL register DID1.
+ //
+ uint32_t ui32PartInfo;
+
+ //
+ //! Information on the part class and revision as read from SYSCTL DID0.
+ //
+ uint32_t ui32ClassInfo;
+
+ //
+ //! Address 1 byte above the highest location the boot loader can access.
+ //
+ uint32_t ui32FlashTop;
+
+ //
+ //! Lowest address the boot loader can write or erase.
+ //
+ uint32_t ui32AppStartAddr;
+}
+PACKED tDFUDeviceInfo;
+
+#ifdef ewarm
+#pragma pack()
+#endif
+
+#endif // __USBDFU_H__
diff --git a/nfclib/debug.h b/nfclib/debug.h
new file mode 100644
index 0000000..ad0b20c
--- /dev/null
+++ b/nfclib/debug.h
@@ -0,0 +1,74 @@
+//*****************************************************************************
+//
+// debug.h - macro for debug output to terminal.
+//
+// Copyright (c) 2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
+//
+//*****************************************************************************
+
+#ifndef __DEBUG_H__
+#define __DEBUG_H__
+
+//*****************************************************************************
+//
+// Debugging Macros from debug.h in NFCLib. These provide extra debug support.
+// comment out the undef's if you want to use them.
+//
+// DEBUG_PRINTF enables UART messages
+// DEBUG enables ASSERT statements for line / file specific information.
+//
+//*****************************************************************************
+//#define DEBUG_PRINT
+//#define DEBUG
+
+#ifdef DEBUG_PRINT
+#include "utils/uartstdio.h"
+#define DebugPrintf(...) UARTprintf(__VA_ARGS__)
+#else
+#define DebugPrintf(...)
+#endif
+
+//*****************************************************************************
+//
+// Prototype for the function that is called when an invalid argument is passed
+// to an API. This is only used when doing a DEBUG build.
+//
+//*****************************************************************************
+extern void __error__(char *pcFilename, uint32_t ui32Line);
+
+//*****************************************************************************
+//
+// The ASSERT macro, which does the actual assertion checking. Typically, this
+// will be for procedure arguments.
+//
+//*****************************************************************************
+#ifdef DEBUG
+#define ASSERT(expr) do \
+ { \
+ if(!(expr)) \
+ { \
+ __error__(__FILE__, __LINE__); \
+ } \
+ } \
+ while(0)
+#else
+#define ASSERT(expr)
+#endif
+
+#endif //__DEBUG_H__
diff --git a/nfclib/directmode.c b/nfclib/directmode.c
new file mode 100644
index 0000000..4aef39e
--- /dev/null
+++ b/nfclib/directmode.c
@@ -0,0 +1,1059 @@
+//*****************************************************************************
+//
+// directmode.h - Direct mode communications.
+//
+// Copyright (c) 2010-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
+//
+//*****************************************************************************
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "inc/hw_timer.h"
+#include "inc/hw_gpio.h"
+#include "inc/hw_memmap.h"
+#include "inc/hw_types.h"
+#include "driverlib/gpio.h"
+#include "driverlib/timer.h"
+#include "driverlib/sysctl.h"
+#include "driverlib/ssi.h"
+#include "driverlib/interrupt.h"
+#include "ssitrf79x0.h"
+#include "trf79x0_hw.h"
+#include "directmode.h"
+#include "trf79x0.h"
+#include "iso14443a.h"
+
+#if defined(rvmdk)
+#define inline __inline
+#endif
+
+//*****************************************************************************
+//
+// Direct mode 0 implementation for ISO 14443 A.
+//
+// This file implements transmission of raw ISO 14443-2 modulation type A
+// formatted bit streams at ~106kbit/s on the TRF79x0 in direct mode 0.
+// The functionality will generate and receive the correct SOF and EOF markers
+// but everything else (parity and CRC) is the responsibility of the calling
+// code. iso14443.c has functions ISO14443ACalculateParity()/
+// ISO14443ACheckParity()/ ISO14443ACalculateCRC()/ ISO14443ACheckCRC() for
+// this purpose. Since it transmits and receives raw bit streams it can also
+// be used for MIFARE Classic communication which needs incorrect parity bits.
+//
+// The implementation uses one timer (TIMER 0) for timing, so this can not
+// be used by anything else, or at least must be set up again before each
+// use, with DirectModeInit().
+//
+// DirectModeEnable() and DirectModeDisable() keep track of state and will
+// not re-enable the mode if it was already active. DirectModeIsEnabled()
+// can be used to query the state. While direct mode is active no other
+// functionality on the TRF79x0 should be accessed and its IRQ is disabled.
+//
+// \note DirectModeDisable() implements a workaround for an apparent bug in
+// the TRF7960 which will perform a soft reset of the TRF7960. In order to
+// not leave the chip in an entirely unexpected state it will then call
+// ISO14443ASetupRegisters() to prepare the chip for ISO 14443 A operation
+// (which is most likely what you'll be using together with this code). If
+// you do not want ISO 14443 A operation you need to restore the necessary
+// settings yourself.
+//
+//*****************************************************************************
+
+//
+// Keep track whether direct mode is enabled.
+//
+static int g_iDirectModeEnabled = 0;
+
+//
+// Receive timeout. This is a loop count, not as reliable as SysCtlDelay(),
+// but not really critical.
+//
+#define DIRECTMODE_RECEIVE_TIMEOUT 30000
+
+//
+// Use timer 0 for direct mode timing.
+//
+#define DIRECTMODE_TIMER_PORT TIMER0_BASE
+#define DIRECTMODE_TIMER_SYSCTL SYSCTL_PERIPH_TIMER0
+
+//*****************************************************************************
+//
+// The macros below do exactly the same as GPIOPinWrite() and GPIOPinRead()
+// from gpio.c and TimerIntStatus() and TimerIntClear() from timer.c, just
+// without the function call and with compile time argument optimization.
+//
+//*****************************************************************************
+#define GPIOPinWrite(ulPort, ucPins, ucVal) \
+ (HWREG((ulPort) + (GPIO_O_DATA + ((ucPins) << 2))) = (ucVal))
+
+#define GPIOPinRead(ulPort, ucPins) \
+ (HWREG((ulPort) + (GPIO_O_DATA + ((ucPins) << 2))))
+
+#define TimerIntStatus(ulBase, bMasked) \
+ ((bMasked) ? HWREG((ulBase) + TIMER_O_MIS) : \
+ HWREG((ulBase) + TIMER_O_RIS))
+
+//*****************************************************************************
+//
+// Shortcut to mimic TimerIntClear() function in DriverLib without the call
+// overhead.
+//
+//*****************************************************************************
+#define TimerIntClear(ulBase, ulIntFlags) \
+ HWREG((ulBase) + TIMER_O_ICR) = (ulIntFlags)
+
+//*****************************************************************************
+//
+// Set timer value.
+// This function is missing from the StellarisWare timer API, so here it is
+// as a macro
+//
+//*****************************************************************************
+#define TimerValueSet(ulBase, ulTimer, ulValue) \
+ HWREG((ulBase) + ((ulTimer)==TIMER_A ? TIMER_O_TAV : TIMER_O_TBV)) = \
+ (ulValue)
+
+//*****************************************************************************
+//
+// This macro enables modulation/disables the field.
+//
+//*****************************************************************************
+#define MODOn() \
+ GPIOPinWrite(TRF79X0_MOD_BASE, TRF79X0_MOD_PIN, \
+ TRF79X0_MOD_PIN)
+
+//*****************************************************************************
+//
+// This macro disables modulation/enables the field.
+//
+//*****************************************************************************
+#define MODOff() \
+ GPIOPinWrite(TRF79X0_MOD_BASE, TRF79X0_MOD_PIN, 0)
+
+//*****************************************************************************
+//
+// Waits for the next one-eighth bit interval, depends on timer B being set up
+// for one-eighth bit intervals.
+//
+//*****************************************************************************
+#define WaitEighthBit() \
+{ \
+ while(!(TimerIntStatus(DIRECTMODE_TIMER_PORT, 0) & TIMER_TIMB_TIMEOUT)) \
+ { \
+ }; \
+ \
+ TimerIntClear(DIRECTMODE_TIMER_PORT, TIMER_TIMB_TIMEOUT); \
+}
+
+//*****************************************************************************
+//
+// Waits for the next quarter bit interval, depends on timer A being set up
+// for quarter bit intervals.
+//
+//*****************************************************************************
+#define WaitQuarterBit() \
+{ \
+ while(!(TimerIntStatus(DIRECTMODE_TIMER_PORT, 0) & TIMER_TIMA_TIMEOUT)) \
+ { \
+ } \
+ TimerIntClear(DIRECTMODE_TIMER_PORT, TIMER_TIMA_TIMEOUT); \
+}
+
+//*****************************************************************************
+//
+// Modulation sequences, names from ISO 14443-2.
+//
+// All these sequences end at 0.75 bit period and start
+// somewhere before 1 bit period. This way they can be freely combined
+// for an overall rate of one sequence per bit period, and give less than
+// 0.25 bit periods for computation.
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// X: pulse after half-bit.
+//
+// - Wait 1/4 bit period for previous sequence to get to the start of this bit.
+// - Wait 1/4 bit period.
+// - Wait 1/4 bit period to get to 1/2 bit period.
+// - Set MOD bit active.
+// - Wait 1/4 bit period to get to 3/4 bit period.
+// - Set MOD bit inactive.
+//
+//*****************************************************************************
+#define SequenceX() \
+ WaitQuarterBit(); \
+ WaitQuarterBit(); \
+ WaitQuarterBit(); \
+ MODOn(); \
+ WaitQuarterBit(); \
+ MODOff();
+
+//*****************************************************************************
+//
+// Y: This sequence just waits out a full bit period with no other toggle.
+//
+// - Wait 1/4 bit period for previous sequence to get to the start of this bit.
+// - Wait 1/4 bit period.
+// - Wait 1/4 bit period to get to 1/2 bit period.
+// - Wait 1/4 bit period to get to 3/4 bit period.
+//
+//*****************************************************************************
+#define SequenceY() \
+ WaitQuarterBit(); \
+ WaitQuarterBit(); \
+ WaitQuarterBit(); \
+ WaitQuarterBit();
+
+//*****************************************************************************
+//
+// Z: Mode pulse at start of bit period.
+//
+// - Wait 1/4 bit period for previous sequence to get to the start of this bit.
+// - Set MOD bit active.
+// - Wait 1/4 bit period.
+// - Set MOD bit inactive.
+// - Wait 1/4 bit period to get to 1/2 bit period.
+// - Wait 1/4 bit period to get to 3/4 bit period.
+//
+//*****************************************************************************
+#define SequenceZ() \
+ WaitQuarterBit(); \
+ MODOn(); \
+ WaitQuarterBit(); \
+ MODOff(); \
+ WaitQuarterBit(); \
+ WaitQuarterBit();
+
+//*****************************************************************************
+//
+// Set up timers and GPIO port for direct mode operation.
+//
+// This sets up GPTM 0 timer A for quarter bit periods (used in sending)
+// and timer B for one-eighth bit periods (used in receiving).
+//
+//*****************************************************************************
+void
+DirectModeInit(void)
+{
+ //
+ // Enable GPIO port A for bit-banging receive.
+ //
+ SysCtlPeripheralEnable(TRF79X0_RX_PERIPH);
+ SysCtlPeripheralEnable(TRF79X0_EN_PERIPH);
+ SysCtlPeripheralEnable(TRF79X0_MOD_PERIPH);
+ SysCtlPeripheralEnable(TRF79X0_IRQ_PERIPH);
+
+ //
+ // Enable and configure timer in periodic up mode
+ //
+ SysCtlPeripheralEnable(DIRECTMODE_TIMER_SYSCTL);
+ TimerConfigure(DIRECTMODE_TIMER_PORT,
+ TIMER_CFG_SPLIT_PAIR | TIMER_CFG_A_PERIODIC_UP |
+ TIMER_CFG_B_PERIODIC_UP);
+
+ //
+ // Configure timer max value for an fc/32 = 13.56MHz/32 = quarter bit
+ // at ~106kHz. This means that the timer must count up to
+ // SysClk/(13.56MHz/32) = (32*SysClk)/13.56MHz. This comes down to 117.99
+ // at 50MHz. The error at 50MHz is negligible, but at other frequencies or
+ // in the general case a fractional logic might be needed.
+ // Note that the argument for TimerLoadSet is actually the desired divisor
+ // minus 1. 117.99 would round to 118, so the argument must be 117.
+ // However since integer calculation is truncating and not rounding this is
+ // directly the result of the division. Should a different frequency be
+ // used where the result of the division is not also the rounded result of
+ // the division minus 1 then proper rounding logic must be added.
+ //
+ TimerLoadSet(DIRECTMODE_TIMER_PORT, TIMER_A,
+ ((SysCtlClockGet() * 32) / 13560000));
+
+ //
+ // Configure Timer B for fc/16 = one eighth bit at ~106kHz. Same
+ // considerations as above apply.
+ //
+ TimerLoadSet(DIRECTMODE_TIMER_PORT, TIMER_B,
+ ((SysCtlClockGet() * 16) / 13560000));
+}
+
+//*****************************************************************************
+//
+// Dual use send code for direct mode. Can either accept an opaque bit stream
+// ( (iMode && DIRECT_MODE_SEND_MASK) == DIRECT_MODE_SEND_OPAQUE ) or
+// structured bytes with parity (... DIRECT_MODE_SEND_PARITY), e.q. as
+// parity_data_t. In the first case uiBytes gives the number of opaque 8
+// bit units to send (e.g. sizeof(*pvBuffer) == uiBytes + (uiBits > 0 ?
+// 1 : 0) ), in the second case it's the number of logical bytes (since each
+// logical byte is encoded as a 16bit word the buffer size must be twice as
+// big). In both cases uiBits gives the number of least significant bits
+// that should additionally be sent.
+//
+//*****************************************************************************
+static inline void
+DirectModeSend(int iMode, void const *pvBuffer, unsigned int uiBytes,
+ unsigned int uiBits)
+{
+ //
+ // We'll keep the current pointer as an 8-bit value and the current byte as
+ // an 16-bit value in any case. In parity mode we'll arrange the pointer
+ // movement and uiCurrentByte assignment specially.
+ //
+ unsigned char const *pucCurrent;
+ unsigned short usPos, usCurrentByte;
+ unsigned char ucLastBit, ucCurrentBit, ucBitsRemain;
+
+ //
+ // Initialize the byte and bit position.
+ //
+ usPos = 0;
+ ucLastBit = 0;
+
+ iMode = iMode & DIRECT_MODE_SEND_MASK;
+
+ //
+ // Create a byte pointer to use with the rest of this function.
+ //
+ pucCurrent = pvBuffer;
+
+ //
+ // Set the MOD pin inactive.
+ //
+ MODOff();
+
+ //
+ // Start the timer.
+ //
+ TimerEnable(DIRECTMODE_TIMER_PORT, TIMER_A);
+
+ //
+ // SOF.
+ //
+ SequenceZ();
+
+ while(usPos++ < uiBytes)
+ {
+ //
+ // Prepare the bit counter and value for this byte for either
+ // 8 bits per byte or 9 bits per 16 bit word.
+ //
+ if(iMode == DIRECT_MODE_SEND_OPAQUE)
+ {
+ ucBitsRemain = 8;
+ usCurrentByte = *pucCurrent;
+ }
+ else
+ {
+ ucBitsRemain = 9;
+ usCurrentByte = pucCurrent[0] | (pucCurrent[1] << 8);
+ }
+
+ //
+ // Send the bits of this byte.
+ //
+ do
+ {
+ ucCurrentBit = usCurrentByte & 0x1;
+
+ if(ucCurrentBit)
+ {
+ //
+ // Transfer a 1 Bit.
+ //
+ SequenceX();
+ }
+ else
+ {
+ //
+ // Transfer a 0-Bit, encoded differently depending on if this
+ // was the last bit.
+ //
+ if(ucLastBit)
+ {
+ SequenceY();
+ }
+ else
+ {
+ SequenceZ();
+ }
+ }
+
+ //
+ // Shift to next bit.
+ //
+ usCurrentByte >>= 1;
+
+ ucLastBit = ucCurrentBit;
+ }
+ while(--ucBitsRemain > 0);
+
+ //
+ // Increment the data pointer by either a byte or one 16 bit word.
+ //
+ pucCurrent += (iMode == DIRECT_MODE_SEND_OPAQUE) ? 1 : 2;
+ }
+
+ //
+ // This is the same as above for the possibly remaining fractional byte.
+ //
+ if(uiBits > 0)
+ {
+ ucBitsRemain = uiBits;
+ usCurrentByte = *pucCurrent;
+
+ //
+ // If sending parity then or in the parity.
+ //
+ if(iMode == DIRECT_MODE_SEND_PARITY)
+ {
+ usCurrentByte |= pucCurrent[-1] << 8;
+ }
+
+ do
+ {
+ ucCurrentBit = usCurrentByte & 0x1;
+
+ //
+ // Transfer a 1 Bit.
+ //
+ if(ucCurrentBit)
+ {
+ SequenceX();
+ }
+ else
+ {
+ //
+ // Transfer a 0-Bit, encoded differently depending on if this
+ // was the last bit.
+ //
+ if(ucLastBit)
+ {
+ SequenceY();
+ }
+ else
+ {
+ SequenceZ();
+ }
+ }
+
+ //
+ // Shift to next bit.
+ //
+ usCurrentByte >>= 1;
+ ucLastBit = ucCurrentBit;
+ }
+ while(--ucBitsRemain > 0);
+ }
+
+ //
+ // EOF is either a 0 or a Y.
+ //
+ if(ucLastBit)
+ {
+ SequenceY();
+ }
+ else
+ {
+ SequenceZ();
+ }
+
+ SequenceY();
+
+ //
+ // Disable the timer and return.
+ //
+ TimerDisable(DIRECTMODE_TIMER_PORT, TIMER_A);
+}
+
+//*****************************************************************************
+//
+// Dual-use receive code for direct mode 0. Similar to the send code can
+// either output an opaque bitstream (DIRECT_MODE_RECV_OPAQUE), or bytes with
+// associated parity bits (DIRECT_MODE_RECV_PARITY).
+//
+//*****************************************************************************
+static void
+DirectModeReceive(int iMode, void *pvBuffer, unsigned int *puiBytes,
+ unsigned int *puiBits)
+{
+ unsigned int uiMaxBytes, uiCountBytes, uiCountBits;
+ int iCurrentBitVal, iLastBitVal, iCount, iHaveSOF;
+ unsigned char *pucCurrent;
+ unsigned int uiCurrentByte;
+ unsigned int uiBitsRemain;
+ int iTimeout;
+
+ //
+ // Signal description: The input on MISO will start out low
+ // and then change to the sub carrier data stream which is either
+ // high, or high-low-high with a frequency of 848kHz. Exactly one
+ // half bit will be all high and one half bit will be alternating.
+ //
+
+ // Reception methodology: Use the IRQ logic as an edge detector.
+ // Configure the GPIO pin for edge triggered interrupts (the interrupt
+ // will not actually be enabled, so no handler will be called). Clear
+ // the interrupt before each sampling interval and check its unmasked
+ // status afterwards.
+ //
+ // The reception may not be perfectly aligned to the bit clock, in that
+ // case the edges will dominate the high signal, e.g. even if there is
+ // just one edge in a sampling period the complete period will read as
+ // "edges present". Look for changes in the sampling result to decode the
+ // manchester encoded stream: there will be a change in the middle of each
+ // bit (and the direction of that change signifies the bit value) and there
+ // might be change at the start/end of a bit. One bit is 8 sampling
+ // periods, so expected is a change every 8 periods. If a change occurs
+ // after 4 periods this is at the start/end of a bit and should be ignored
+ // (and the counter kept incrementing). When keeping in mind that the
+ // subcarier edges may dominate the steady signal that means that there
+ // must have been at least 7 periods since a recognized edge to recognize a
+ // subcarrier-steady edge as a data edge, or 6 periods since a recognized
+ // edge to recognize a steady-subcarrier edge as a data edge.
+ //
+
+ //
+ // Pointer to the next storage location.
+ //
+ pucCurrent = pvBuffer;
+
+ //
+ // Currently sampled data unit (either 8 or 9 bits).
+ //
+ uiCurrentByte = 0;
+
+ //
+ // Set up edge detection.
+ //
+ GPIOIntTypeSet(TRF79X0_RX_BASE, TRF79X0_RX_PIN, GPIO_BOTH_EDGES);
+
+ //
+ // Make sure that data parameters are correct before using them.
+ //
+ if((pvBuffer == NULL) || (puiBytes == NULL) || (*puiBytes == 0))
+ {
+ return;
+ }
+
+ //
+ // Maximal number of bytes to receive, and count of bytes and count of bits
+ // received so far.
+ //
+ uiMaxBytes = *puiBytes;
+ uiCountBytes = 0;
+ uiCountBits = 0;
+
+ //
+ // iCurrentBitVal contains the sampling result for the most recently ended
+ // sampling interval, while iLastBitVal is for the interval before that.
+ // Edges are detected by having iCurrentBitVal != iLastBitVal.
+ //
+ iCurrentBitVal = 0;
+ iLastBitVal = 0;
+
+ //
+ // iCount contains the number of quarter bit intervals since the last
+ // recognized data edge. It is initialized with a half bit period
+ // at the start to immediately detect the data edge in the middle of
+ // the SOF bit, and afterwards incremented for each sampling period and
+ // reset to 0 when a data edge is detected. When an edge is ignored count
+ // will also be set to exactly a half bit period in order to guarantee
+ // that the next edge will be detected as a data edge.
+ //
+ iCount = 4;
+
+ iMode = iMode & DIRECT_MODE_RECV_MASK;
+
+ //
+ // Initialized the number of bits left in the data unit.
+ //
+ if(iMode == DIRECT_MODE_RECV_OPAQUE)
+ {
+ uiBitsRemain = 8;
+ }
+ else
+ {
+ uiBitsRemain = 9;
+ }
+
+ //
+ // Ignore the first bit which is a start-of-frame indicator.
+ //
+ iHaveSOF = 0;
+
+ //
+ // The signal starts out low, so wait for the rising edge.
+ //
+ GPIOIntClear(TRF79X0_RX_BASE, TRF79X0_RX_PIN);
+ {
+ //
+ // Initialize the timeout.
+ //
+ iTimeout = DIRECTMODE_RECEIVE_TIMEOUT;
+
+ while(!(GPIOIntStatus(TRF79X0_RX_BASE, 0) &
+ TRF79X0_RX_PIN) && (iTimeout-- > 0))
+ {
+ }
+ }
+
+ //
+ // Set the timer to 0 and start it.
+ //
+ TimerValueSet(DIRECTMODE_TIMER_PORT, TIMER_B, 0);
+ TimerEnable(DIRECTMODE_TIMER_PORT, TIMER_B);
+
+ //
+ // Reset edge detector.
+ //
+ GPIOIntClear(TRF79X0_RX_BASE, TRF79X0_RX_PIN);
+
+ do
+ {
+ //
+ // Wait until the end of the current sampling interval.
+ //
+ WaitEighthBit();
+
+ //
+ // Copy over the sampling result to be processed, reset edge detector.
+ //
+ iCurrentBitVal = (GPIOIntStatus(TRF79X0_RX_BASE, 0) &
+ TRF79X0_RX_PIN);
+
+ GPIOIntClear(TRF79X0_RX_BASE, TRF79X0_RX_PIN);
+
+ //
+ // Check for a change in bit polarity.
+ //
+ if(iLastBitVal != iCurrentBitVal)
+ {
+ if(iLastBitVal)
+ {
+ //
+ // may be overly long.
+ //
+ if(iCount <= 6)
+ {
+ //
+ // ignore, but force iCount to sane value.
+ //
+ iCount = 4;
+ }
+ else
+ {
+ if(iHaveSOF)
+ {
+ //
+ // This edge is a 1 bit, add it to the current data
+ // unit.
+ //
+ uiBitsRemain--;
+
+ uiCurrentByte |= 1 << uiCountBits;
+
+ uiCountBits++;
+ }
+ else
+ {
+ iHaveSOF = 1;
+ }
+
+ //
+ // Reset iCount.
+ //
+ iCount = 0;
+ }
+ }
+ else
+ {
+ //
+ // may be overly short
+ //
+ if(iCount <= 5)
+ {
+ //
+ // ignore, but force iCount to sane value.
+ //
+ iCount = 4;
+ }
+ else
+ {
+ if(iHaveSOF)
+ {
+ //
+ // This edge is a 0 bit, add it to the current data
+ // unit.
+ //
+ uiBitsRemain--;
+ uiCountBits++;
+ }
+ else
+ {
+ iHaveSOF = 1;
+ }
+
+ //
+ // Reset iCount.
+ //
+ iCount = 0;
+ }
+ }
+ }
+
+ //
+ // Increment number of one eighth bit periods since last recognized
+ // edge.
+ //
+ iCount++;
+ iLastBitVal = iCurrentBitVal;
+
+ if(uiBitsRemain == 0)
+ {
+ //
+ // Store received data unit, advance pointer.
+ //
+ if(iMode == DIRECT_MODE_RECV_OPAQUE)
+ {
+ uiBitsRemain = 8;
+ *pucCurrent = uiCurrentByte;
+ pucCurrent += 1;
+ }
+ else
+ {
+ uiBitsRemain = 9;
+ pucCurrent[0] = uiCurrentByte & 0xff;
+ pucCurrent[1] = uiCurrentByte >> 8;
+ pucCurrent += 2;
+ }
+
+ //
+ // Clear temporary store.
+ //
+ uiCurrentByte = 0;
+ uiCountBits = 0;
+
+ //
+ // Increment counter, abort when the receive buffer is full.
+ //
+ uiCountBytes++;
+ if((uiCountBytes + 1) >= uiMaxBytes)
+ {
+ break;
+ }
+ }
+
+ //
+ // More than 2 bit periods (16 eighth bit periods) since the last edge
+ // signify a time out, end of reception.
+ //
+ }
+ while(iCount < 16);
+
+ //
+ // Stop timer.
+ //
+ TimerDisable(DIRECTMODE_TIMER_PORT, TIMER_B);
+
+ //
+ // Store length.
+ //
+ *puiBytes = uiCountBytes;
+
+ if(puiBits != NULL)
+ {
+ if(uiCountBits > 0)
+ {
+ //
+ // Store incomplete byte.
+ //
+ if(iMode == DIRECT_MODE_RECV_OPAQUE)
+ {
+ *pucCurrent = uiCurrentByte;
+ }
+ else
+ {
+ pucCurrent[0] = uiCurrentByte & 0xff;
+ pucCurrent[1] = uiCurrentByte >> 8;
+ }
+ }
+
+ //
+ // Store length of incomplete byte.
+ //
+ *puiBits = uiCountBits;
+ }
+}
+
+//*****************************************************************************
+//
+// Transmits and receives an ISO 14443-2 type A frame in direct mode 0.
+//
+// \param iMode is a flag field to specify the format of the input and output
+// parameters. Should be a combination of (either \b DIRECT_MODE_SEND_OPAQUE
+// or \b DIRECT_MODE_SEND_PARITY) and (either \b DIRECT_MODE_RECV_OPAQUE or
+// \b DIRECT_MODE_RECV_PARITY). See discussion below.
+// \param pvSendBuf is the data buffer to send.
+// \param uiSendBytes determines the number of full data units to be sent (8
+// or 9 bits each). For a discussion of data unit sizes see below.
+// \param uiSendBits determines how many bits from an additional, fractional
+// data unit should be sent. Setting this to a value other than 0 means that
+// \e pvSendBuf has space for an \e uiSendBytes + 1 data units.
+// \param pvRecvBuf is the data buffer for receiving.
+// \param puiRecvBytes inputs the space available in \e pvRecvBuf (in logical
+// data units) and outputs the number of full data units actually received
+// \param puiRecvBits outputs the number of additional bits received after the
+// last full data unit indicated in \e puiRecvBytes
+//
+// Both input and output can be in one of two formats: OPAQUE and PARITY.
+//
+// - \b OPAQUE specifies an opaque bit stream, where each byte in the input
+// corresponds to 8 bits sent on the radio interface and 8 bits received on
+// the radio interface correspond to 1 byte in the output.
+// - \b PARITY has for each byte in the input/output an associated parity bit.
+// These are stored as a 16 bit word: the payload byte is in the lower 8 bits
+// and the parity bit is the least significant bit of the higher byte.
+//
+// The principal data unit size for OPAQUE is 8 bits, and the principal data
+// unit size for PARITY is 9 bits (stored as a 16 bit word). All inputs
+// and outputs are in terms of data units, which means that the actual storage
+// size, in bytes, for PARITY mode is twice the number of data units.
+//
+// In both modes additional bits can be sent or received after the last
+// full data unit. PARITY mode is best suited for ISO 14443 operation
+// since it conveniently associates each byte with its parity bit, and
+// allows for direct access to the payload byte of each data unit through
+// simple masking, and not requiring shifts and masks over two bytes.
+//
+// Direct mode needs to have been enabled with DirectModeEnable() (with
+// argument \e iMode = 0) before calling this function. This function will
+// disable the master processor interrupt while it is running.
+//
+//*****************************************************************************
+void
+DirectModeTransceive(int iMode, void const *pvSendBuf, unsigned int uiSendBytes,
+ unsigned int uiSendBits, void *pvRecvBuf,
+ unsigned int *puiRecvBytes, unsigned int *puiRecvBits)
+{
+ int iDisabled;
+
+ //
+ // Disable interrupts.
+ //
+ iDisabled = IntMasterDisable();
+
+ //
+ // Send and receive
+ //
+ DirectModeSend(iMode, pvSendBuf, uiSendBytes, uiSendBits);
+ DirectModeReceive(iMode, pvRecvBuf, puiRecvBytes, puiRecvBits);
+
+ //
+ // Enable interrupts if necessary.
+ //
+ if(iDisabled == 0)
+ {
+ IntMasterEnable();
+ }
+}
+
+//*****************************************************************************
+//
+// Starts direct mode.
+//
+// \param iMode is the direct mode to enable and must be 0 for now.
+//
+// This function sets the desired direct mode type on the TRF79x0 and then
+// enables direct mode. This also has the effect of disabling the
+// TRF79x0 IRQ. No TRF79x0 operation can be performed while direct mode is
+// active (and none should be attempted).
+// The function sets an internal flag and does nothing if direct mode has
+// already been enabled by this function and not been disabled with
+// DirectModeDisable().
+//
+//*****************************************************************************
+void
+DirectModeEnable(unsigned int iMode)
+{
+ unsigned char pucRegs[3];
+
+ //
+ // Check to see if direct mode is already enabled, and if so, do nothing
+ //
+ if(g_iDirectModeEnabled)
+ {
+ return;
+ }
+
+ //
+ // Read chip status control and ISO registers.
+ //
+ TRF79x0ReadRegisterContinuous(TRF79X0_CHIP_STATUS_CTRL_REG, pucRegs, 2);
+
+ //
+ // Set direct mode type to bitstream.
+ //
+ if(iMode)
+ {
+ pucRegs[TRF79X0_ISO_CONTROL_REG] |= TRF79X0_ISO_CONTROL_DIR_MODE;
+
+ }
+ else
+ {
+ pucRegs[TRF79X0_ISO_CONTROL_REG] &= ~TRF79X0_ISO_CONTROL_DIR_MODE;
+ }
+
+ //
+ // Enable direct mode in saved registers.
+ //
+ pucRegs[0] |= TRF79X0_STATUS_CTRL_DIRECT;
+
+ //
+ // Write direct mode type to TRF79x0.
+ //
+ TRF79x0WriteRegister(TRF79X0_ISO_CONTROL_REG, pucRegs[1]);
+
+ //
+ // Clear pucRegs[2]
+ //
+ pucRegs[2] = 0;
+
+ //
+ // Start direct mode
+ // This write will not finish (which would end direct mode) but instead
+ // must be finished with TRF79x0DirectModeDisable(). Also the IRQ handler
+ // has been deactivated while the chip select is asserted since it can't
+ // use the SPI anyway.
+ //
+ SSITRF79x0WriteContinuousStart(TRF79X0_CHIP_STATUS_CTRL_REG);
+ SSITRF79x0WriteContinuousData(pucRegs, 1);
+
+ //
+ // Delay 8 dummy clock cycles
+ //
+ SSITRF79x0DummyWrite(&pucRegs[2], 1);
+
+ //
+ // Set up GPIO configuration: Use the input (normally MISO) as a GPIO to
+ // bit-bang the reception of the sub-carrier signal
+ //
+ GPIOPinTypeGPIOInput(TRF79X0_RX_BASE, TRF79X0_RX_PIN);
+
+ //
+ // Set flag
+ //
+ g_iDirectModeEnabled = 1;
+}
+
+//*****************************************************************************
+//
+// Stops direct mode.
+//
+// This stops the direct mode and releases the communication interface.
+// It checks an internal flag and does nothing if direct mode has not been
+// enabled with DirectModeEnable() or has been disabled with
+// DirectModeDisable() before.
+//
+// \note There seems to be a bug in the TRF7960 which makes the chip unusable
+// for some time after exiting direct mode due to the MISO line not
+// working properly. Currently the required workaround is to send a
+// \b TRF79X0_SOFT_INIT_CMD command and then reinitialize the chip, with
+// ISO14443ASetupRegisters(). This is done by this function, so you'll
+// find the TRF79x0 configured for ISO 14443-A even if it wasn't before.
+//
+//*****************************************************************************
+void
+DirectModeDisable(void)
+{
+ int iDisabled;
+
+ //
+ // Check to see if direct mode is enabled, and if not, do nothing.
+ //
+ if(!g_iDirectModeEnabled)
+ {
+ return;
+ }
+
+ //
+ // Kludge: We want to prevent the IRQ handler from going off
+ // before we have reinitialized the interface. The call to
+ // SSITRF79x0WriteContinuousStop(), and by extension all the
+ // calls to TRF79x0DirectCommand or TRF79x0Read*, will enable the
+ // IRQ, so we disable the processor IRQ for the time being.
+ //
+ iDisabled = IntMasterDisable();
+
+ //
+ // Restore SSI pin settings.
+ //
+ GPIOPinTypeSSI(TRF79X0_RX_BASE, TRF79X0_RX_PIN);
+
+ //
+ // Disable direct mode.
+ //
+ SSITRF79x0WriteContinuousStop();
+
+ //
+ // For good measure: Discard bytes from FIFO.
+ //
+ TRF79x0DirectCommand(TRF79X0_RESET_FIFO_CMD);
+
+ //
+ // Clear flag.
+ //
+ g_iDirectModeEnabled = 0;
+
+ //
+ // Re-enable processor IRQ if necessary.
+ //
+ if(iDisabled == 0)
+ {
+ IntMasterEnable();
+ }
+
+ //
+ // Enable TRF IRQ.
+ //
+ TRF79x0InterruptEnable();
+
+ //
+ // This code should be removed if a better solution is found since
+ // the direct mode code should not directly depend on ISO 14443-A
+ // and there might, hypothetically, be other protocols that the user
+ // might want to use.
+ //
+ TRF79x0DirectCommand(TRF79X0_SOFT_INIT_CMD);
+ ISO14443ASetupRegisters();
+ ISO14443APowerOn();
+}
+
+//*****************************************************************************
+//
+// Queries whether direct mode is enabled.
+//
+// \return A non-zero value indicates that direct mode is enabled and a zero
+// value indicates that direct mode is disabled.
+//
+//*****************************************************************************
+int
+DirectModeIsEnabled(void)
+{
+ return(g_iDirectModeEnabled);
+}
diff --git a/nfclib/directmode.h b/nfclib/directmode.h
new file mode 100644
index 0000000..6124859
--- /dev/null
+++ b/nfclib/directmode.h
@@ -0,0 +1,78 @@
+//*****************************************************************************
+//
+// directmode.h - Direct mode communications.
+//
+// Copyright (c) 2010-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
+//
+//*****************************************************************************
+
+#ifndef __DIRECTMODE_H__
+#define __DIRECTMODE_H__
+
+//*****************************************************************************
+//
+// Define NULL, if not already defined.
+//
+//*****************************************************************************
+#ifndef NULL
+#define NULL ((void *)0)
+#endif
+
+//
+// Input to DirectModeTransceive is an opaque stream of bits, grouped as 8
+// bits into one byte. LSBit should be sent first.
+//
+#define DIRECT_MODE_SEND_OPAQUE 0
+
+//
+// Input to DirectModeTransceive is an array of bytes with associated parity
+// bit, stored as 16 bit words. The lower 8 bits in each word are the byte
+// (LSBit should be sent first), the lowest bit of the upper 8 bits is the
+// parity bit. The remaining 7 bits are ignored.
+//
+//
+#define DIRECT_MODE_SEND_PARITY 1
+
+//
+// Output from DirectModeTransceive should be an opaque bit stream, grouped as
+// 8 bits into one byte, LSBit was received first.
+//
+#define DIRECT_MODE_RECV_OPAQUE 0
+
+//
+// Output from DirectModeTransceive should be an array of bytes with
+// associated parity bit.
+//
+#define DIRECT_MODE_RECV_PARITY 2
+
+#define DIRECT_MODE_SEND_MASK 1
+#define DIRECT_MODE_RECV_MASK 2
+
+extern void DirectModeInit(void);
+extern void DirectModeTransceive(int iMode, void const *pvSendBuf,
+ unsigned int iSendBytes,
+ unsigned int iSendBits, void *pvRecvBuf,
+ unsigned int *piRecvBytes,
+ unsigned int *piRecvBits);
+
+extern void DirectModeEnable(unsigned int iMode);
+extern void DirectModeDisable(void);
+extern int DirectModeIsEnabled(void);
+
+#endif
diff --git a/nfclib/iso14443-4.c b/nfclib/iso14443-4.c
new file mode 100644
index 0000000..4bb39af
--- /dev/null
+++ b/nfclib/iso14443-4.c
@@ -0,0 +1,164 @@
+//*****************************************************************************
+//
+// iso14443-4.c - ISO 14443-4 implementation.
+//
+//
+// Copyright (c) 2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
+//
+//*****************************************************************************
+
+#include <string.h>
+
+#include "inc/hw_types.h"
+#include "driverlib/sysctl.h"
+#include "trf7960.h"
+
+//*****************************************************************************
+//
+// Transceive ISO 14443-4 RATS command.
+//
+//*****************************************************************************
+int
+ISO14443RATS(unsigned char ucFSDI, unsigned char ucCID, unsigned char *pucATS)
+{
+ unsigned char pucResponse[16];
+ unsigned int uiRxSize;
+ unsigned char pucRATS[2];
+ int i;
+
+ uiRxSize = sizeof(pucResponse);
+
+ //
+ // RATS command.
+ //
+ pucRATS[0] = 0xE0;
+ pucRATS[1] = (ucFSDI << 4) || ucCID;
+
+ //
+ // Transmit RATS, receive ATS.
+ //
+ TRF7960Transceive(pucRATS, sizeof(pucRATS), 0, pucResponse, &uiRxSize, NULL,
+ TRF7960_TRANSCEIVE_CRC);
+
+ if(uiRxSize >= 3)
+ {
+ //
+ // Valid ATS received, return it as an char buffer. Was transmitted LSByte first.
+ // pucResponse[0] is the length of the transmitted ATS, including TL byte, NOT including
+ // two CRC bytes
+ //
+ for(i = 0; i < pucResponse[0]; i++)
+ pucATS[i] = pucResponse[i];
+
+ return(uiRxSize);
+ }
+ else
+ {
+ return(0);
+ }
+}
+
+//*****************************************************************************
+//
+// Transceive ISO 14443-4 PPS command.
+// ucCID must between 0~14, ucDRI & ucDSI must between 0~3
+//
+//*****************************************************************************
+int
+ISO14443PPS(unsigned char ucCID, unsigned char ucDRI, unsigned char ucDSI)
+{
+ unsigned char pucResponse[3];
+ unsigned int uiRxSize;
+ unsigned char pucPPS[3];
+
+ uiRxSize = sizeof(pucResponse);
+
+ //
+ // PPS command.
+ //
+ pucPPS[0] = (0xD << 4) | ucCID;
+ pucPPS[1] = 0x11; // PPS1 is transmitted
+ pucPPS[2] = (ucDSI << 2) | ucDRI;
+
+ //
+ // Transmit PPS, receive PPS response.
+ //
+ TRF7960Transceive(pucPPS, sizeof(pucPPS), 0, pucResponse, &uiRxSize, NULL,
+ TRF7960_TRANSCEIVE_CRC);
+
+ //
+ // check if receive the first byte of the response is PPSS
+ //
+ if(pucResponse[0] == pucPPS[0])
+ return(1);
+ else
+ {
+ //
+ // Not valid response
+ //
+ return(0);
+ }
+}
+
+//*****************************************************************************
+//
+// Transceive ISO 14443-4 DESELECT command.
+// ucCID must between 0~14, ucDRI & ucDSI must between 0~3
+//
+//*****************************************************************************
+int
+ISO14443DESELECT(unsigned char ucCID)
+{
+ unsigned char pucResponse[2];
+ unsigned int uiRxSize;
+ unsigned char pucDESELECT[2];
+
+ uiRxSize = sizeof(pucResponse);
+
+ pucResponse[0] = 0;
+ pucResponse[1] = 0;
+
+ //
+ // DESELECT command.
+ //
+ pucDESELECT[0] = 0xCA; // S-block with DESELECT set and CID following
+ pucDESELECT[1] = ucCID & 0x0F;
+
+ //
+ // Transmit DESELECT, receive DESELECT response.
+ //
+ TRF7960Transceive(pucDESELECT, sizeof(pucDESELECT), 0, pucResponse, &uiRxSize, NULL,
+ TRF7960_TRANSCEIVE_CRC);
+
+ //
+ // check if receive the first byte of the response is DESELECT
+ // check if the second byte contains the same CID
+ //
+ if(pucResponse[0] == pucDESELECT[0])
+ {
+ return(1);
+ }
+ else
+ {
+ //
+ // Not valid response
+ //
+ return(0);
+ }
+}
diff --git a/nfclib/iso14443-4.h b/nfclib/iso14443-4.h
new file mode 100644
index 0000000..b2f9b8b
--- /dev/null
+++ b/nfclib/iso14443-4.h
@@ -0,0 +1,33 @@
+//*****************************************************************************
+//
+// iso14443a.h - ISO 14443A implementation.
+//
+//
+// Copyright (c) 2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
+//
+//*****************************************************************************
+
+#ifndef __ISO14443-4_H__
+#define __ISO14443-4_H__
+
+extern int ISO14443RATS(unsigned char ucFSDI, unsigned char ucCID, unsigned char *pucATS);
+extern int ISO14443PPS(unsigned char ucCID, unsigned char ucDRI, unsigned char ucDSI);
+extern int ISO14443DESELECT(unsigned char ucCID);
+
+#endif
diff --git a/nfclib/iso14443a.c b/nfclib/iso14443a.c
new file mode 100644
index 0000000..10cd6b2
--- /dev/null
+++ b/nfclib/iso14443a.c
@@ -0,0 +1,1141 @@
+//*****************************************************************************
+//
+// iso14443a.c - ISO 14443A implementation.
+//
+// Copyright (c) 2010-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
+//
+//*****************************************************************************
+
+#include <string.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include "inc/hw_types.h"
+#include "driverlib/sysctl.h"
+#include "trf79x0.h"
+#include "iso14443a.h"
+
+//*****************************************************************************
+//
+// Global anti-collision state for use by ISO14443ASelectFirst() and
+// ISO14443ASelectNext().
+//
+//*****************************************************************************
+static struct ISO14443AAnticolState g_sAnticolState;
+
+//*****************************************************************************
+//
+// ISO14443-A Anti-collision implementation, iterative depth-first tree search
+// with optional backtracking.
+//
+// Usage:
+// In ISO 14443 A there are two types of resting states for cards: IDLE and
+// HALT. A card enters IDLE state after powering up and performing all the
+// necessary internal initialization. The specification states that the card
+// must be in IDLE state and ready to accept commands 5ms after being put into
+// an unmodulated (e.g. no commands sent) field of the necessary strength.
+//
+// This pause is guaranteed by ISO14443APowerOn().
+//
+// During the selection and anti-collision phase cards will be in intermediary
+// states (READY and READY*) but then always return to the original state
+// (IDLE and HALT).
+//
+// After a card has been selected by any of the ISO14443ASelect* functions
+// of this module it can be sent to the HALT state with ISO14443AHalt(),
+// and must be sent to HALT (or deactivated in another way) before calling
+// another ISO14443ASelect* function.
+//
+// Cards in the IDLE state react to both WUPA and REQA commands, cards in
+// HALT state react only to WUPA commands. Cards in HALT state can not
+// return to IDLE state except through completely powering off the card
+// and powering it up again, but the specification makes no claims as to how
+// long the field must be off in order for the card to power off and this time
+// will vary between card types.
+//
+// The ISO14443ASelectFirst/Next functions take one parameter (\e ucCmd) that
+// must be \b ISO14443A_REQA or \b ISO14443A_WUPA to specify which wake up
+// method to use. ISO14443ASelect will always use WUPA.
+//
+// This leads to two main usage protocols:
+// <h3>A: Detect only new cards</h3> <ul>
+// <li> Keep field enabled at all times
+// <li> Use ISO14443ASelectFirst() with ISO14443A_REQA to find new cards that
+// entered the field. Note: Ensure a pause of 5ms before each call to
+// ISO14443ASelectFirst(), e.g. with ISO14443APowerOn().
+// <li> If a card was found by SelectFirst, operate on that card and
+// deactivate it with ISO14443AHalt(). Note: all successful calls to any
+// ISO14443ASelect* function should always be paired with a call to
+// ISO14443AHalt() before the next call to any ISO14443ASelect* function.
+// <li> Repeatedly call ISO14443ASelectFirst() with \b ISO14443A_REQA in a
+// loop. It will only find new cards and not relist the cards that were
+// already handled and halted
+// </ul>
+// Pseudo C: <pre>
+// while(1) {
+// ISO14443APowerOn();
+// if(ISO14443ASelectFirst(ISO14443A_REQA, ...)) {
+//
+// <i>Do something with the card</i>
+//
+// ISO14443AHalt();
+// }
+//
+// <i>Do NOT power off the field</i>
+// }
+// </pre>
+//
+// <h3>B: List all cards in the field</h3> <ul>
+// <li> Optionally disable the field or do other things, but enable the
+// field at least for 5ms (e.g. with ISO14443APowerOn())
+// <li> Call ISO14443ASelectFirst() with \b ISO14443A_WUPA to find the first
+// card, handle it, call ISO14443AHalt(). If at least one card was
+// found, use ISO14443ASelectNext() with \b ISO14443A_WUPA in a loop to
+// find more cards, handle them and call ISO14443AHalt() on them.
+// <li> You may disable the field and restart the procedure at any time with
+// ISO14443APowerOn() and ISO14443ASelectFirst(). It will always list
+// all cards in the field, not only new cards.
+// </ul>
+// Pseudo C: <pre>
+// while(1) {
+// ISO14443APowerOn();
+// if(ISO14443ASelectFirst(ISO14443A_WUPA, ...)) {
+// do {
+//
+// <i>Do something with the card</i>
+//
+// ISO14443AHalt();
+// } while(ISO14443ASelectNext(ISO14443A_WUPA, ...));
+// }
+//
+// <i>You may power off the field here</i>
+// }
+// </pre>
+//
+// In both cases ISO14443ASelect() can be used at any time (after halting a
+// previously selected card) to select a card by known UID.
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// This structure stores the UID that we're currently working on.
+//
+//*****************************************************************************
+struct ISO14443AAnticolState
+{
+ //
+ // This field stores the raw responses that the anti-collision is actually
+ // performed over, e.g. 3 times 5 bytes. Same goes for \e ucCollisions.
+ // Before returning the UID to the calling code this must be cleaned,
+ // that is remove cascade tag and BCC.
+ //
+ unsigned char ucUID[15];
+ //
+ // Stores the collision positions discovered so far. It is a bit field
+ // with the same indices as \e ucUID.
+ //
+ unsigned char ucCollisions[15];
+ //
+ // Stores the number of bits that we've successfully received or
+ // disambiguated. Note: Real count for the \e ucUID field of this
+ // structure, not NVB format. For example 8 means 1 byte and 0 bits, 40
+ // means full cascade level 1, 41 means full cascade level 1 plus 1 bit in
+ // cascade level 2.
+ //
+ unsigned int iBitPos;
+};
+
+//*****************************************************************************
+//
+// Set up registers for ISO 14443 A 106Kbit/s operation. This function must
+// be called after initializing the TRF79x0 (for example with TRF79x0Init()
+// or TRF79x0DirectCommand() with argument \b TRF79X0_SOFT_INIT_CMD) and before
+// calling any of the other ISO14443A functions.
+//
+//*****************************************************************************
+void
+ISO14443ASetupRegisters(void)
+{
+ //
+ // Set the ISO format to ISO1443A 106Kbps.
+ //
+ TRF79x0WriteRegister(TRF79X0_ISO_CONTROL_REG,
+ TRF79X0_ISO_CONTROL_14443A_106K);
+
+ //
+ // Set the TX pulse to 106ns (0x20 * 73.7ns).
+ //
+ TRF79x0WriteRegister(TRF79X0_TX_PULSE_LENGTH_CTRL_REG, 0x20);
+
+ //
+ // Set the RX No response wait time to 529us (0xe * 37.76us).
+ //
+ TRF79x0WriteRegister(TRF79X0_RX_NO_RESPONSE_WAIT_REG, 0x0e);
+
+ //
+ // Set the RX wait time to 66us (7 * 9.44us).
+ //
+ TRF79x0WriteRegister(TRF79X0_RX_WAIT_TIME_REG, 0x07);
+
+ //
+ // Set the SYSCLK to 6.78MHz and the Modulation Depth to OOK.
+ //
+ TRF79x0WriteRegister(TRF79X0_MODULATOR_CONTROL_REG,
+ (TRF79X0_MOD_CTRL_SYS_CLK_6_78MHZ |
+ TRF79X0_MOD_CTRL_MOD_OOK_100));
+
+ //
+ // Configure the Special Settings Register.
+ //
+ TRF79x0WriteRegister(TRF79X0_RX_SPECIAL_SETTINGS_REG,
+ (TRF79x0ReadRegister(TRF79X0_RX_SPECIAL_SETTINGS_REG) & 0x0f) |
+ TRF79X0_RX_SP_SET_M848);
+
+ //
+ // Configure the Test Settings Register.
+ //
+ TRF79x0WriteRegister(TRF79X0_TEST_SETTING1_REG, 0x20);
+
+ //
+ // Set the regulator voltage to be automatic.
+ //
+ TRF79x0WriteRegister(TRF79X0_REGULATOR_CONTROL_REG,
+ TRF79X0_REGULATOR_CTRL_AUTO_REG);
+}
+
+//*****************************************************************************
+//
+// Power on the field and wait for a time that is long enough to guarantee
+// that all cards in the field will be initialized.
+//
+//*****************************************************************************
+void
+ISO14443APowerOn(void)
+{
+ unsigned char ucReg;
+
+ //
+ // Enable RF field and receiver.
+ //
+ ucReg = TRF79x0ReadRegister(TRF79X0_CHIP_STATUS_CTRL_REG);
+ TRF79x0WriteRegister(TRF79X0_CHIP_STATUS_CTRL_REG,
+ ucReg | TRF79X0_STATUS_CTRL_RF_ON);
+
+ //
+ // Wait 5ms (as per ISO 14443-3 clause 5).
+ //
+ SysCtlDelay(((SysCtlClockGet() / 3) * 5) / 1000);
+}
+
+//*****************************************************************************
+//
+// Power off the field and wait for some time.
+//
+//*****************************************************************************
+void
+ISO14443APowerOff(void)
+{
+ unsigned char ucReg;
+
+ //
+ // Disable RF field and receiver.
+ //
+ ucReg = TRF79x0ReadRegister(TRF79X0_CHIP_STATUS_CTRL_REG);
+
+ TRF79x0WriteRegister(TRF79X0_CHIP_STATUS_CTRL_REG,
+ ucReg & ~TRF79X0_STATUS_CTRL_RF_ON);
+
+ //
+ // Wait 5ms.
+ //
+ SysCtlDelay(((SysCtlClockGet() / 3) * 5) / 1000);
+}
+
+//*****************************************************************************
+//
+// Transmit a HLTA command that should HALT the currently selected card. You
+// should always call this function after a successful call to either
+// ISO14443ASelect(), ISO14443ASelectFirst() or ISO14443ASelectNext() and
+// before any other call to any of those functions.
+//
+//*****************************************************************************
+void
+ISO14443AHalt(void)
+{
+ //
+ // HLTA command.
+ //
+ const unsigned char pucHLTA[2] = {0x50, 0x00};
+
+ TRF79x0Transceive(pucHLTA, sizeof(pucHLTA), 0, NULL, NULL, NULL,
+ TRF79X0_TRANSCEIVE_CRC);
+}
+
+//*****************************************************************************
+//
+// Transceive ISO 14443-A REQA type command.
+//
+// \param ucCmd is the command, either \b ISO14443A_REQA or \b ISO14443A_WUPA
+// \param piATQA is a pointer to an integer to store the received ATQA and
+// will be set to -1 if a collision occurred.
+//
+// \return true if at least one card responded that is capable of bit-frame
+// anti-collision (e.g. no collision and one of the lower 5 bits of response
+// set, or collision within the first 5 bits, or collision not in the first
+// 5 bits but at least one of the first 5 bits is a 1-bit) and false
+// otherwise.
+//
+// \note User code usually does not need to call this function since it is
+// implicitly called in ISO14443ASelect(), ISO14443ASelectFirst() or
+// ISO14443ASelectNext().
+//
+//*****************************************************************************
+int
+ISO14443AREQA(unsigned char ucCmd, int *piATQA)
+{
+ unsigned char pucResponse[2];
+ unsigned int uiRxSize;
+ int iColPos;
+
+ uiRxSize = sizeof(pucResponse);
+
+ //
+ // Transmit WUPA/REQA, receive ATQA.
+ //
+ TRF79x0Transceive(&ucCmd, 0, 7, pucResponse, &uiRxSize, 0,
+ TRF79X0_TRANSCEIVE_NO_CRC);
+
+ if(uiRxSize == 2)
+ {
+ //
+ // Valid ATQA received, return it as an integer. Was transmitted
+ // LSByte first.
+ //
+ if(piATQA != NULL)
+ {
+ *piATQA = pucResponse[0] | (pucResponse[1] << 8);
+ }
+
+ //
+ // Return true if one of the lower 5 bits was set.
+ //
+ return((pucResponse[0] & 0x1F) != 0);
+ }
+ else
+ {
+ //
+ // No valid ATQA received.
+ //
+ if(piATQA != NULL)
+ {
+ *piATQA = -1;
+ }
+
+ if(uiRxSize == 0)
+ {
+ //
+ // No response at all -> no card with bit-frame anti-collision.
+ //
+ return(0);
+ }
+ else
+ {
+ //
+ // Probably some collision.
+ //
+ iColPos = TRF79x0GetCollisionPosition();
+
+ if(iColPos > 5)
+ {
+ //
+ // Collision not within the first 5 bits, return true if one of
+ // the lower 5 bits was set.
+ //
+ return((pucResponse[0] & 0x1F) != 0);
+ }
+ else if(iColPos > 0 && iColPos <= 5)
+ {
+ //
+ // Collision within the first 5 bits, so at least one of them
+ // was 1.
+ //
+ return(1);
+ }
+ else
+ {
+ //
+ // No collision, but only 1 byte sent? That card's not right.
+ //
+ return(0);
+ }
+ }
+ }
+}
+
+//*****************************************************************************
+//
+// Find one card through the anti-collision procedure with given \e psState.
+//
+// \param psState is the anti-collision state to start from. If this state
+// already specifies a full UID then it will be selected, otherwise
+// anti-collision will be tried to complete that starting state, with no
+// backtracking.
+// \param pucUID is an output buffer to write the selected UID and may be
+// \b NULL in which case the UID will not be returned.
+// \param puiUIDSize inputs the available space in bytes in \e pucUID and
+// returns with the actual length that has been stored there.
+// \param pucSAK is an output parameter that stores the received SAK value.
+// May be \b NULL in which case the SAK will not be returned
+//
+// This is a depth first search in a binary tree over the UID space. On each
+// attempt we can learn up to 4 bytes of the UID of the card(s) currently in
+// the field. If the UIDs of two cards differ we will learn that too and get
+// the collision position: the position of the bit where the UID of at least
+// two cards differs. We will mark this position in the appropriate field in
+// the structure ISO14443AnticolState and then branch first in the direction of
+// 0 and increase iBitPos to include this bit.
+//
+// \return This function returns 1 if a card was selected and 0 otherwise.
+//
+//*****************************************************************************
+static int
+ISO14443ADoAnticol(struct ISO14443AAnticolState *psState, unsigned char *pucUID,
+ unsigned int *puiUIDSize, unsigned char *pucSAK)
+{
+ int iCascadeLevel, iPos;
+ unsigned char pucCmd[7], pucResponse[5];
+ unsigned int uiRxSize;
+ int iIdx, iMaskPosition, iCollPosition, iValidBits, iMaxLength, iNVB;
+
+ iCascadeLevel = 1;
+
+ while(iCascadeLevel < 4)
+ {
+ //
+ // Already known bits for this cascade level, e.g. not including
+ // the possible 5 bytes * 8 bits/byte for the lower levels.
+ //
+ iValidBits = psState->iBitPos - (iCascadeLevel - 1) * 5 * 8;
+
+ //
+ // Clamp to a full cascade level.
+ //
+ if(iValidBits > 40)
+ {
+ iValidBits = 40;
+ }
+
+ //
+ // NVB format: bytes.
+ //
+ iNVB = (iValidBits / 8) << 4;
+
+ //
+ // NVB format: bits.
+ //
+ iNVB |= (iValidBits % 8);
+
+ //
+ // Also count the command byte and the NVB byte itself.
+ //
+ iNVB += 0x20;
+
+ //
+ // Prepare command for this level: ANTICOLLISION if less than a full 5
+ // bytes for the current cascade level, SELECT otherwise.
+ //
+ switch (iCascadeLevel)
+ {
+ case 1:
+ {
+ pucCmd[0] = 0x93;
+ break;
+ }
+ case 2:
+ {
+ pucCmd[0] = 0x95;
+ break;
+ }
+ case 3:
+ {
+ pucCmd[0] = 0x97;
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+
+ pucCmd[1] = iNVB;
+
+ //
+ // Copy over known bytes (number of bits for this level divided by 8,
+ // rounded up).
+ //
+ memcpy(pucCmd + 2, psState->ucUID + (iCascadeLevel - 1) * 5,
+ (iValidBits + 7) / 8);
+
+ //
+ // Enforce a small delay of ~600us before each anti-collision frame.
+ //
+ SysCtlDelay(((SysCtlClockGet() / 3) * 6) / 10000);
+
+ //
+ // Maximal expected response length.
+ //
+ uiRxSize = 5;
+
+ if(iNVB != 0x70)
+ {
+ //
+ // Anti-collision command.
+ //
+ TRF79x0Transceive(pucCmd, pucCmd[1] >> 4, pucCmd[1] & 0xf,
+ pucResponse, &uiRxSize, NULL,
+ TRF79X0_TRANSCEIVE_NO_CRC);
+
+ if(uiRxSize == 0)
+ {
+ return(0);
+ }
+
+ iCollPosition = TRF79x0GetCollisionPosition();
+
+ if(iCollPosition < 0)
+ {
+ //
+ // No collision occurred, add full response data to known bits.
+ //
+ iCollPosition = 40;
+ }
+ else
+ {
+ //
+ // Collision occurred, only add the part that was received
+ // correctly.
+ //
+ // TF7960 Collision position register is in NVB format,
+ // convert to straight bit position. This will be the number
+ // of bits that were the same in all responding cards.
+ //
+ iCollPosition -= 0x20;
+ iCollPosition = ((iCollPosition >> 4) * 8) + (iCollPosition & 0xf);
+ }
+
+ //
+ // Bounds check the results and return 0 if it was invalid.
+ //
+ if(iCollPosition < 0 || iCollPosition > 40)
+ {
+ return(0);
+ }
+
+ //
+ // Mask out the invalid bits in the last byte of the response, if
+ // any.
+ //
+ // Graphic:
+ // UID bytes: | first || second || third || fourth || fifth |
+ // | iValidBits |
+ // | iCollPosition |
+ // In this graphic the first byte is fully valid. The second byte
+ // was sent partially invalid, but should have been masked on a
+ // previous run. The third byte is received partially invalid and
+ // needs to be masked. Response will only contain the second and
+ // third byte (although both are received properly byte-aligned).
+ //
+ //
+ // This many bits in response are valid or at least compatible
+ // with the UID.
+ //
+ iMaskPosition = iCollPosition - (iValidBits / 8) * 8;
+
+ if(iMaskPosition % 8)
+ {
+ //
+ // Need to construct a mask for iMaskPosition%8 bits and
+ // apply it at iMaskPosition/8.
+ //
+ pucResponse[iMaskPosition / 8] &= ~((~0) << (iMaskPosition % 8));
+ }
+
+ //
+ // Merge in up to iMaskPosition/8 (rounded up) byte into response
+ // at index iBitPos/8 (rounded down).
+ //
+ for(iIdx = 0; iIdx < (iMaskPosition + 7) / 8; iIdx++)
+ {
+ psState->ucUID[(psState->iBitPos / 8) + iIdx] |=
+ pucResponse[iIdx];
+ }
+
+ psState->iBitPos += iCollPosition - iValidBits;
+
+ //
+ // Only within this cascade level:
+ //
+ if(psState->iBitPos % 40 != 0)
+ {
+ //
+ // Mark backtracking point.
+ //
+ psState->ucCollisions[psState->iBitPos / 8] |=
+ 1 << (psState->iBitPos % 8);
+
+ //
+ // Walk into the 0 direction.
+ //
+ psState->iBitPos += 1;
+ }
+ }
+ else
+ {
+ //
+ // Select command.
+ //
+ TRF79x0Transceive(pucCmd, pucCmd[1] >> 4, pucCmd[1] & 0xf,
+ pucResponse, &uiRxSize, NULL,
+ TRF79X0_TRANSCEIVE_CRC);
+
+ if(uiRxSize == 1)
+ {
+ //
+ // SAK received.
+ //
+ if(pucResponse[0] & 0x04)
+ {
+ //
+ // UID not complete, increase cascade level.
+ //
+ iCascadeLevel++;
+
+ if(iCascadeLevel > 3)
+ {
+ break;
+ }
+ }
+ else
+ {
+ //
+ // UID complete, return.
+ //
+ break;
+ }
+ }
+ else
+ {
+ //
+ // Some error, card not selected.
+ //
+ memset(psState->ucUID, 0, sizeof(psState->ucUID));
+ psState->iBitPos = 0;
+ break;
+ }
+ }
+ }
+
+ //
+ // Some error, not fully selected.
+ //
+ if(((psState->iBitPos % 40) != 0) || (psState->iBitPos == 0))
+ {
+ return(0);
+ }
+
+ //
+ // Fully selected a card. pucResponse[0] should be from the last
+ // transaction, of a SELECT command, and therefore contain the SAK
+ //
+ if(pucSAK != NULL)
+ {
+ *pucSAK = pucResponse[0];
+ }
+
+ //
+ // If requested, return the UID, without cascade tag and BCC.
+ //
+ if(pucUID != NULL && puiUIDSize != NULL)
+ {
+ iMaxLength = *puiUIDSize;
+ iPos = 0;
+ *puiUIDSize = 0;
+
+ //
+ // From the 5 bytes in each cascade level the 3 middle bytes need to be
+ // copied for each level except for the last, where the first 4 bytes
+ // need to be copied.
+ //
+ for(iPos = 0; iPos < psState->iBitPos / 8; iPos += 5)
+ {
+ if(iPos + 5 < psState->iBitPos / 8)
+ {
+ //
+ // Not the last cascade level.
+ //
+ if(*puiUIDSize + 3 > iMaxLength)
+ {
+ //
+ // Not enough space
+ //
+ *puiUIDSize = 0;
+ break;
+ }
+
+ //
+ // Copy 3 bytes (e.g. don't copy cascade tag and BCC).
+ //
+ memcpy(pucUID + *puiUIDSize, psState->ucUID + iPos + 1, 3);
+
+ *puiUIDSize += 3;
+ }
+ else
+ {
+ //
+ // Last cascade level.
+ //
+ if(*puiUIDSize + 4 > iMaxLength)
+ {
+ //
+ // Not enough space.
+ //
+ *puiUIDSize = 0;
+
+ break;
+ }
+
+ //
+ // Copy 4 bytes (e.g. don't copy BCC).
+ //
+ memcpy(pucUID + *puiUIDSize, psState->ucUID + iPos, 4);
+
+ *puiUIDSize += 4;
+ }
+ }
+ }
+ return(1);
+}
+
+//*****************************************************************************
+//
+// Selects the first (or only) card and returns its UID, UID length and
+// SAK bytes.
+//
+// \param ucCmd must be ISO14443A_REQA or ISO14443A_WUPA.
+// \param pucUID will store UID of the card that was selected. May be NULL
+// in which case the UID will not be returned.
+// \param puiUIDSize must be initialized with the length of the buffer in
+// \e pucUID and will return the number of bytes actually stored.
+// \param pucSAK will store the SAK byte of the card that was selected and may
+// be NULL in which case the SAK byte will not be returned.
+//
+// The function call initializes and updates a static internal state that
+// marks the position in the anti-collision procedure. ISO14443ASelectNext()
+// can be used to continue with the anti-collision from that starting point.
+//
+// \note You should call ISO14443AHalt() if this function returned true and
+// you are done operating on the card.
+//
+// \return Function returns 1 if a card was selected, 0 otherwise.
+//
+//*****************************************************************************
+int
+ISO14443ASelectFirst(unsigned char ucCmd, unsigned char *pucUID,
+ unsigned int *puiUIDSize, unsigned char *pucSAK)
+{
+ //
+ // Initialize/clear static state.
+ //
+ memset(&g_sAnticolState, 0, sizeof(g_sAnticolState));
+
+ //
+ // Wake up all or only new tags.
+ //
+ if(ISO14443AREQA(ucCmd, NULL) == 0)
+ {
+ //
+ // No tag with support for bit frame anti-collision found.
+ //
+ return(0);
+ }
+
+ return(ISO14443ADoAnticol(&g_sAnticolState, pucUID, puiUIDSize, pucSAK));
+}
+
+//*****************************************************************************
+//
+// Selects the next card and returns its UID, UID length and SAK bytes.
+//
+// \param ucCmd must be ISO14443A_REQA or ISO14443A_WUPA.
+// \param UID will store UID of the card that was selected and may be NULL
+// in which case the UID will not be returned.
+// \param puiUIDSize must be initialized with the length of the buffer in
+// \e UID and will return the number of bytes actually stored.
+// \param pucSAK will store the SAK byte of the card that was selected and may
+// be NULL in which case the SAK byte will not be returned.
+//
+// Uses the state that was initialized by ISO14443SelectFirst() and tries
+// to find more cards in the field.
+//
+// \note You should call ISO14443AHalt() if this function returned true and
+// you are done operating on the card.
+//
+// \return This function returns 1 if a card was selected and 0 otherwise.
+//
+//*****************************************************************************
+int
+ISO14443ASelectNext(unsigned char ucCmd, unsigned char *pucUID,
+ unsigned int *puiUIDSize, unsigned char *pucSAK)
+{
+ //
+ // Backtrack through static state: starting at iBitPos and going reverse,
+ // find the first bit that's set in collisions, walk into the 1 direction,
+ // clear the collision indicator and set iBitPos to that position.
+ //
+ while(--g_sAnticolState.iBitPos > 0)
+ {
+ //
+ // Clear UID bit at this position to clean the state.
+ //
+ g_sAnticolState.ucUID[g_sAnticolState.iBitPos / 8] &=
+ ~(1 << (g_sAnticolState.iBitPos % 8));
+
+ if(g_sAnticolState.ucCollisions[g_sAnticolState.iBitPos / 8] &
+ (1 << (g_sAnticolState.iBitPos % 8)))
+ {
+ //
+ // This is our new starting point, set UID bit to walk into the
+ // 1 direction.
+ //
+ g_sAnticolState.ucUID[g_sAnticolState.iBitPos / 8] |=
+ 1 << (g_sAnticolState.iBitPos % 8);
+
+ //
+ // Remove backtracking marker.
+ //
+ g_sAnticolState.ucCollisions[g_sAnticolState.iBitPos / 8] &=
+ ~(1 << (g_sAnticolState.iBitPos % 8));
+
+ //
+ // Increment bit position to account for the bit that we just
+ // added, then break loop to perform anti-collision with the new
+ // partial UID.
+ //
+ g_sAnticolState.iBitPos++;
+
+ break;
+ }
+
+ //
+ // Not a backtracking point, go further back.
+ //
+ }
+
+ //
+ // No further backtracking points -> no other cards.
+ //
+ if(g_sAnticolState.iBitPos <= 0)
+ {
+ return(0);
+ }
+
+ //
+ // Wake up all or only new tags.
+ //
+ if(!ISO14443AREQA(ucCmd, NULL))
+ {
+ //
+ // No tag with support for bit frame anti-collision found.
+ //
+ return(0);
+ }
+
+ return(ISO14443ADoAnticol(&g_sAnticolState, pucUID, puiUIDSize, pucSAK));
+}
+
+//*****************************************************************************
+//
+// Selects a card with given UID and return its SAK byte.
+//
+// \param pucUID must point to the UID of the card that should be selected and
+// may not be NULL.
+// \param uiUIDSize must be the length in bytes of the UID stored in \e pucUID.
+// \param pucSAK will store the SAK byte of the card that was selected. May be
+// \b NULL in which case the SAK byte will not be returned.
+//
+// \note You should call ISO14443AHalt() if this function returned true and
+// you are done operating on the card.
+//
+// \return This function will return 1 if a card was selected and 0 otherwise.
+//
+//*****************************************************************************
+int
+ISO14443ASelect(unsigned char const *pucUID, unsigned int uiUIDSize,
+ unsigned char *pucSAK)
+{
+ int iIdx, iPos;
+ struct ISO14443AAnticolState sState;
+
+ //
+ // Check if the given UID size is supported.
+ //
+ if((uiUIDSize != 4) && (uiUIDSize != 7) && (uiUIDSize != 10))
+ {
+ return(0);
+ }
+
+ //
+ // Prepare a state for the given UID.
+ //
+ sState.iBitPos = 0;
+
+ for(iPos = 0; iPos < uiUIDSize;)
+ {
+ //
+ // Check if this is the final cascade level.
+ //
+ if(iPos + 4 < uiUIDSize)
+ {
+ //
+ // If this was not the final cascade level then add a cascade tag.
+ //
+ sState.ucUID[sState.iBitPos / 8] = 0x88;
+
+ //
+ // Copy three bytes of UID.
+ //
+ memcpy(sState.ucUID + (sState.iBitPos / 8) + 1, pucUID + iPos, 3);
+
+ //
+ // Increment position in UID.
+ //
+ iPos += 3;
+ }
+ else
+ {
+ //
+ // For the final cascade level just copy four bytes of UID.
+ //
+ memcpy(sState.ucUID + (sState.iBitPos / 8), pucUID + iPos, 4);
+
+ //
+ // Increment position in UID.
+ //
+ iPos += 4;
+ }
+
+ //
+ // Calculate BCC.
+ //
+ sState.ucUID[sState.iBitPos / 8 + 4] = 0;
+
+ for(iIdx = 0; iIdx < 4; iIdx++)
+ {
+ sState.ucUID[sState.iBitPos / 8 + 4] ^=
+ sState.ucUID[sState.iBitPos / 8 + iIdx];
+ }
+
+ //
+ // Increment position in state.
+ //
+ sState.iBitPos += 40;
+ }
+
+ //
+ // Always wake up all cards.
+ //
+ if(!ISO14443AREQA(ISO14443A_WUPA, NULL))
+ {
+ //
+ // No tag with support for bit frame anti-collision found.
+ //
+ return(0);
+ }
+
+ return(ISO14443ADoAnticol(&sState, NULL, NULL, pucSAK));
+}
+
+//*****************************************************************************
+//
+// Helper functions for ISO 14443-A frames to be sent or received in Direct
+// Mode.
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// Calculates odd parity for one byte.
+//
+//*****************************************************************************
+static unsigned char
+ParityByte(unsigned char ucByte)
+{
+ ucByte ^= ucByte >> 1;
+ ucByte ^= ucByte >> 1;
+ ucByte ^= ucByte >> 1;
+ ucByte ^= ucByte >> 1;
+ ucByte ^= ucByte >> 1;
+ ucByte ^= ucByte >> 1;
+ ucByte ^= ucByte >> 1;
+ return((ucByte & 1) ^ 1);
+}
+
+//*****************************************************************************
+//
+// Checks that data has correct (odd) parity
+//
+// \param pusData is the data buffer to check and must store 16 bits per one
+// logical byte: the lower 8 bits are the data byte, the LSBit in the upper
+// byte is the parity.
+// \param lSize is the number of logical bytes/16 bit words in \e pusData.
+//
+// \return This function returns 1 if the parity was correct and 0 otherwise.
+//
+//*****************************************************************************
+int
+ISO14443ACheckParity(const unsigned short * const pusData, const long lSize)
+{
+ int iFailed, iIdx;
+
+ iFailed = 0;
+
+ for(iIdx = 0; iIdx < lSize; iIdx++)
+ {
+ iFailed |= (pusData[iIdx] >> 8) ^ ParityByte(pusData[iIdx] & 0xff);
+ }
+
+ return(!iFailed);
+}
+
+//*****************************************************************************
+//
+// Sets data to correct (odd) parity
+//
+// \param pusData is the data buffer to update and must store 16 bits per one
+// logical byte: the lower 8 bits are the data byte, the LSBit in the upper
+// byte is the parity.
+// \param lSize is the number of logical bytes/16 bit words in \e data
+//
+//*****************************************************************************
+void
+ISO14443ACalculateParity(unsigned short * const pusData, const long lSize)
+{
+ int iIdx;
+
+ for(iIdx = 0; iIdx < lSize; iIdx++)
+ {
+ pusData[iIdx] = (pusData[iIdx] & 0xff) |
+ (ParityByte(pusData[iIdx] & 0xff) << 8);
+ }
+}
+
+//*****************************************************************************
+//
+// Calculate CRC-A and return it.
+//
+//*****************************************************************************
+static unsigned short
+CalculateCRC(const unsigned short * const pusData, const long lSize)
+{
+ unsigned short usCrc;
+ int iIdx, iBit;
+ unsigned char ucByte, ucBit;
+
+ usCrc = 0x6363;
+
+ for(iIdx = 0; iIdx < lSize; iIdx++)
+ {
+ ucByte = pusData[iIdx] & 0xff;
+
+ for(iBit = 0; iBit < 8; iBit++)
+ {
+ ucBit = (usCrc ^ ucByte) & 1;
+
+ ucByte >>= 1;
+ usCrc >>= 1;
+
+ if(ucBit)
+ {
+ usCrc ^= 0x8408;
+ }
+ }
+ }
+ return(usCrc);
+}
+
+//*****************************************************************************
+//
+// Check that data has correct CRC in last two bytes.
+//
+// \param pusData is the data buffer to check and must store 16 bits per one
+// logical byte: the lower 8 bits are the data byte, the LSBit in the upper
+// byte is the parity.
+// \param lSize is the number of logical bytes/16 bit words in \e pusData.
+// Must be at least 2, since the CRC consists of two bytes.
+//
+// \return This function returns 1 if the CRC was correct and 0 otherwise.
+//
+//*****************************************************************************
+int
+ISO14443ACheckCRC(const unsigned short * const pusData, const long lSize)
+{
+ unsigned short usCrc;
+
+ if(lSize < 2)
+ {
+ return(0);
+ }
+
+ usCrc = CalculateCRC(pusData, lSize - 2);
+
+ if(((usCrc & 0xff) == (pusData[lSize - 2] & 0xff)) &&
+ (((usCrc >> 8) & 0xff) == (pusData[lSize - 1] & 0xff)))
+ {
+ return(1);
+ }
+ return(0);
+}
+
+//*****************************************************************************
+//
+// Appends correct CRC to the data
+//
+// \param pusData is the data buffer to update and must store 16 bits per one
+// logical byte: the lower 8 bits are the data byte, the LSBit in the upper
+// byte is the parity.
+// \param lSize is the number of logical bytes/16 bit words in \e pusData. The
+// buffer in \e pusData must have room for an additional two logical bytes.
+//
+// \return This function returns the new length to correctly append the CRC.
+//
+//*****************************************************************************
+long
+ISO14443ACalculateCRC(unsigned short * const pusData, const long lSize)
+{
+ unsigned short usCrc;
+
+ usCrc = CalculateCRC(pusData, lSize);
+
+ pusData[lSize] = usCrc & 0xff;
+ pusData[lSize + 1] = (usCrc >> 8) & 0xff;
+
+ ISO14443ACalculateParity(pusData + lSize, 2);
+
+ return(lSize + 2);
+}
diff --git a/nfclib/iso14443a.h b/nfclib/iso14443a.h
new file mode 100644
index 0000000..274ada7
--- /dev/null
+++ b/nfclib/iso14443a.h
@@ -0,0 +1,65 @@
+//*****************************************************************************
+//
+// iso14443a.h - ISO 14443A implementation.
+//
+// Copyright (c) 2010-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
+//
+//*****************************************************************************
+
+#ifndef __ISO14443A_H__
+#define __ISO14443A_H__
+
+//
+// REQA command, which wakes cards from IDLE state and puts them into READY
+// state. One of the two possible parameters for \e ucCmd in
+// ISO14443ASelectFirst() and ISO14443ASelectNext().
+//
+#define ISO14443A_REQA 0x26
+//
+// WUPA command, which wakes cards from IDLE or HALT state and puts them
+// into READY or READY* state. One of the two possible parameters for
+// \e ucCmd in ISO14443ASelectFirst() and ISO14443ASelectNext().
+//
+#define ISO14443A_WUPA 0x52
+
+extern void ISO14443ASetupRegisters(void);
+extern void ISO14443APowerOn(void);
+extern void ISO14443APowerOff(void);
+extern void ISO14443AHalt(void);
+extern int ISO14443AREQA(unsigned char ucCmd, int *piATQA);
+extern int ISO14443ASelect(unsigned char const *pucUID,
+ unsigned int uiUIDLength, unsigned char *pucSAK);
+extern int ISO14443ASelectFirst(unsigned char ucCmd, unsigned char *pucUID,
+ unsigned int *puiUIDLength,
+ unsigned char *pucSAK);
+extern int ISO14443ASelectNext(unsigned char ucCmd, unsigned char *pucUID,
+ unsigned int *puiUIDLength,
+ unsigned char *pucSAK);
+extern int ISO14443ACheckParity(const unsigned short * const pusData,
+ const long lLen);
+extern void ISO14443ACalculateParity(unsigned short * const pusData,
+ const long lLen);
+extern int ISO14443ACheckCRC(const unsigned short * const pusData,
+ const long lLen);
+extern long ISO14443ACalculateCRC(unsigned short * const pusData, const long lSize);
+
+extern int ISO14443RATS(unsigned char ucFSDI, unsigned char ucCID, unsigned char *pucATS);
+extern int ISO14443PPS(unsigned char ucCID, unsigned char ucDRI, unsigned char ucDSI);
+extern int ISO14443DESELECT(unsigned char ucCID);
+#endif
diff --git a/nfclib/iso14443b.c b/nfclib/iso14443b.c
new file mode 100644
index 0000000..a7cd7fb
--- /dev/null
+++ b/nfclib/iso14443b.c
@@ -0,0 +1,339 @@
+//*****************************************************************************
+//
+// iso14443B.c - ISO 14443B implementation.
+//
+// Copyright (c) 2010-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+//*****************************************************************************
+
+#include <string.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include "inc/hw_types.h"
+#include "driverlib/sysctl.h"
+#include "trf79x0.h"
+#include "iso14443b.h"
+
+//*****************************************************************************
+//
+// Set up registers for ISO 14443 B 106Kbit/s operation. This function must
+// be called after initializing the TRF79x0 (for example with TRF79x0Init()
+// or TRF79x0Command() with argument \b TRF79X0_SOFT_INIT_CMD) and before
+// calling any of the other ISO14443B functions.
+//
+//*****************************************************************************
+void
+ISO14443BSetupRegisters(void)
+{
+ //
+ // Set the ISO format to ISO1443B 106Kbps.
+ //
+ TRF79x0WriteRegister(TRF79X0_ISO_CONTROL_REG,
+ TRF79X0_ISO_CONTROL_14443B_106K);
+
+ //
+ // Set the TX pulse to 106ns (0x20 * 73.7ns).
+ //
+ TRF79x0WriteRegister(TRF79X0_TX_PULSE_LENGTH_CTRL_REG, 0x20);
+
+ //
+ // Set the RX No response wait time to 529us (0xe * 37.76us).
+ //
+ TRF79x0WriteRegister(TRF79X0_RX_NO_RESPONSE_WAIT_REG, 0x0e);
+
+ //
+ // Set the RX wait time to 66us (7 * 9.44us).
+ //
+ TRF79x0WriteRegister(TRF79X0_RX_WAIT_TIME_REG, 0x07);
+
+ //
+ // Set the SYSCLK to 6.78MHz and the Modulation 10% ASK.
+ //
+ TRF79x0WriteRegister(TRF79X0_MODULATOR_CONTROL_REG, TRF79X0_MOD_CTRL_SYS_CLK_6_78MHZ);
+
+ //
+ // Configure the Special Settings Register.
+ //
+ TRF79x0WriteRegister(TRF79X0_RX_SPECIAL_SETTINGS_REG,
+ (TRF79x0ReadRegister(TRF79X0_RX_SPECIAL_SETTINGS_REG) & 0x0f) |
+ TRF79X0_RX_SP_SET_M848);
+
+ //
+ // Configure the Test Settings Register.
+ //
+ TRF79x0WriteRegister(TRF79X0_TEST_SETTING1_REG, 0x20);
+
+
+ //
+ // Set the regulator voltage to be automatic.
+ //
+ TRF79x0WriteRegister(TRF79X0_REGULATOR_CONTROL_REG,
+ TRF79X0_REGULATOR_CTRL_AUTO_REG);
+}
+
+//*****************************************************************************
+//
+// Power on the field and wait for a time that is long enough to guarantee
+// that all cards in the field will be initialized.
+//
+//*****************************************************************************
+void
+ISO14443BPowerOn(void)
+{
+ unsigned char ucReg;
+
+ //
+ // Enable RF field and receiver.
+ //
+ ucReg = TRF79x0ReadRegister(TRF79X0_CHIP_STATUS_CTRL_REG);
+ TRF79x0WriteRegister(TRF79X0_CHIP_STATUS_CTRL_REG,
+ ucReg | TRF79X0_STATUS_CTRL_RF_ON);
+
+ //
+ // Wait 5ms (as per ISO 14443-3 clause 5).
+ //
+ SysCtlDelay(((SysCtlClockGet() / 3) * 5) / 1000);
+}
+
+//*****************************************************************************
+//
+// Power off the field and wait for some time.
+//
+//*****************************************************************************
+void
+ISO14443BPowerOff(void)
+{
+ unsigned char ucReg;
+
+ //
+ // Disable RF field and receiver.
+ //
+ ucReg = TRF79x0ReadRegister(TRF79X0_CHIP_STATUS_CTRL_REG);
+
+ TRF79x0WriteRegister(TRF79X0_CHIP_STATUS_CTRL_REG,
+ ucReg & ~TRF79X0_STATUS_CTRL_RF_ON);
+
+ //
+ // Wait 5ms.
+ //
+ SysCtlDelay(((SysCtlClockGet() / 3) * 5) / 1000);
+}
+
+int
+ISO14443BHalt(unsigned char *pucPUPI)
+{
+ unsigned char ucResponse;
+ unsigned int uiRxSize;
+
+ //
+ // HLTA command.
+ //
+ unsigned char pucHLTA[5];
+
+ pucHLTA[0] = 0x50;
+ pucHLTA[1] = pucPUPI[0];
+ pucHLTA[2] = pucPUPI[1];
+ pucHLTA[3] = pucPUPI[2];
+ pucHLTA[4] = pucPUPI[3];
+
+ TRF79x0Transceive(pucHLTA, sizeof(pucHLTA), 0, &ucResponse, &uiRxSize, NULL,
+ TRF79X0_TRANSCEIVE_CRC);
+
+ //
+ // Valid answer to HLTB received.
+ if((uiRxSize == 1) && (ucResponse == 0))
+ return(uiRxSize);
+ else
+ return(0);
+}
+
+//*****************************************************************************
+//
+// Transceive ISO 14443-B SlotMARKER command.
+//
+// \param ucSlot is the slot number for the following operations, must between 1~15
+//
+//*****************************************************************************
+void
+ISO14443BSlotMARKER(unsigned char ucSlot)
+{
+ unsigned char ucAPn;
+
+ ucAPn = (ucSlot << 4) | 0x05;
+
+ TRF79x0Transceive(&ucAPn, 1, 0, 0, 0, 0, TRF79X0_TRANSCEIVE_CRC);
+// TRF79x0Send(&ucAPn, 1, 0, TRF79X0_TRANSCEIVE_TX_CRC);
+}
+
+//*****************************************************************************
+//
+// Transceive ISO 14443-B REQB type command.
+//
+// \param ucCmd is the command, either \b ISO14443B_REQB or \b ISO14443B_WUPB
+// \param ucAFI is the application family identifier
+// \param ucN is the number of the time slot that was used in anticollision process,
+// must between 0 ~ 4
+// \param piATQB is a pointer to an integer to store the received ATQB and
+// will be set to -1 if a collision occurred.
+//
+// \return true if at least one card responded and false
+// otherwise.
+//
+// \note User code usually does not need to call this function since it is
+// implicitly called in ISO14443BSelect(), ISO14443bSelectFirst() or
+// ISO14443BSelectNext().
+//
+//*****************************************************************************
+int
+ISO14443BREQB(unsigned char ucCmd, unsigned char ucAFI, unsigned char ucN,
+ unsigned char *pucATQB, unsigned int *puiATQBSize)
+{
+ unsigned char pucREQB[3];
+ unsigned char pucResponse[12];
+ unsigned int uiRxSize;
+ int i, slotTotal, slot;
+
+ switch(ucN)
+ {
+ case 0: slotTotal = 1; break;
+ case 1: slotTotal = 2; break;
+ case 2: slotTotal = 4; break;
+ case 3: slotTotal = 8; break;
+ case 4: slotTotal = 16; break;
+ default: slotTotal = 1; break;
+ }
+
+ uiRxSize = sizeof(pucResponse);
+ pucResponse[0] = 0;
+
+ //
+ // Transmit WUPB/REQB, receive ATQB.
+ //
+ pucREQB[0] = 0x05;
+ pucREQB[1] = ucAFI;
+ pucREQB[2] = ucCmd | ucN;
+
+ //
+ // the first byte of ATQB is 0x50
+ //
+ TRF79x0Transceive(pucREQB, sizeof(pucREQB), 0, pucResponse, &uiRxSize, 0,
+ TRF79X0_TRANSCEIVE_CRC);
+
+ //
+ // check if needing to scan slot
+ //
+ slot = 1;
+ while((pucResponse[0] != 0x50) && (slot < slotTotal))
+ {
+ uiRxSize = 12;
+ pucResponse[0] = 0;
+
+ TRF79x0IRQClearCauses(TRF79X0_WAIT_RXEND);
+ //
+ // the order of the two function must not reversed, because the TRF79x0ReceiveAgain() called
+ // TRF79x0Command(TRF79X0_RESET_FIFO_CMD); to reset receive FIFO
+ // the most important action TRF79x0ReceiveAgain() done is to set g_sRXState.uiMaxLength as uiRxSize
+ // in order to enable the TRF7970A interrupt to continue receive data
+ //
+ ISO14443BSlotMARKER(slot++);
+ TRF79x0ReceiveAgain(pucResponse, &uiRxSize);
+ };
+
+ //
+ // Valid ATQB received. Was transmitted LSByte first.
+ //
+ if(pucResponse[0] == 0x50)
+ {
+ if(pucATQB != NULL)
+ {
+ for(i = 0; i < uiRxSize; i++)
+ pucATQB[i] = pucResponse[i];
+ }
+ *puiATQBSize = uiRxSize;
+
+ //
+ // Return true
+ //
+ return(1);
+ }
+ else
+ {
+ //
+ // No response at all
+ //
+ return(0);
+ }
+}
+
+//*****************************************************************************
+//
+// Transceive ISO 14443-3 ATTRIB command.
+// EOF_SOF indicate the PCD capability to support suppression of the EOF and/or SOF
+// from PICC to PCD, which may reduce communication overhead.
+// The suppression of EOF and/or SOF is optional for the PICC.
+// SOF/EOF suppression applies only for communications at fc / 128 (~ 106 kbit/s).
+// For bit rates higher than fc / 128 (~ 106 kbit/s) the PICC shall always provide SOF and EOF
+// EOF_SOF set 0 indicate SOF&EOF required.
+//
+// ucTR1 & ucTR0 must between 0~2
+//
+//*****************************************************************************
+int
+ISO14443BATTRIB(unsigned char *pucPUPI, unsigned char ucTR0, unsigned char ucTR1, unsigned char ucEOF_SOF,
+ unsigned char ucMaxFrameSize, unsigned char ucBitRateD2C, unsigned char ucBitRateC2D,
+ unsigned char ucProtocolType, unsigned char ucCID, unsigned char *A2ATTRIB)
+{
+ unsigned char pucResponse[3];
+ unsigned int uiRxSize;
+ unsigned char pucATTRIB[9];
+
+ uiRxSize = sizeof(pucResponse);
+
+ //
+ // ATTRIB command.
+ //
+ pucATTRIB[0] = 0x1D;
+ pucATTRIB[1] = pucPUPI[0];
+ pucATTRIB[2] = pucPUPI[1];
+ pucATTRIB[3] = pucPUPI[2];
+ pucATTRIB[4] = pucPUPI[3];
+ pucATTRIB[5] = (ucTR0 << 6) | (ucTR1 << 4) | (ucEOF_SOF << 3) | (ucEOF_SOF << 2);
+ pucATTRIB[6] = (ucBitRateC2D << 6) | (ucBitRateD2C << 4) | ucMaxFrameSize;
+ pucATTRIB[7] = ucProtocolType & 0x0F;
+ pucATTRIB[8] = ucCID & 0x0F;
+
+ //
+ // Transmit ATTRIB without higher layer INF, receive answer to ATTRIB command without higher layer response
+ //
+ TRF79x0Transceive(pucATTRIB, sizeof(pucATTRIB), 0, pucResponse, &uiRxSize, NULL,
+ TRF79X0_TRANSCEIVE_CRC);
+
+ if(uiRxSize == 1 )
+ {
+ //
+ // Valid answer to ATTRIB command received, return it as an char, uiRxSize NOT including two CRC bytes
+ //
+ if(A2ATTRIB != NULL)
+ *A2ATTRIB = pucResponse[0];
+
+ return(uiRxSize);
+ }
+ else
+ {
+ return(0);
+ }
+}
diff --git a/nfclib/iso14443b.h b/nfclib/iso14443b.h
new file mode 100644
index 0000000..16b2e3c
--- /dev/null
+++ b/nfclib/iso14443b.h
@@ -0,0 +1,51 @@
+//*****************************************************************************
+//
+// iso14443b.h - ISO 14443B implementation.
+//
+// Copyright (c) 2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
+//
+//*****************************************************************************
+
+#ifndef __ISO14443B_H__
+#define __ISO14443B_H__
+
+//
+// REQB command, which wakes cards from IDLE state and puts them into READY
+// state. One of the two possible parameters for \e ucCmd in
+// ISO14443BSelectFirst() and ISO14443BSelectNext().
+//
+#define ISO14443B_REQB 0x00
+//
+// WUPB command, which wakes cards from IDLE or HALT state and puts them
+// into READY or READY* state. One of the two possible parameters for
+// \e ucCmd in ISO14443BSelectFirst() and ISO14443BSelectNext().
+//
+#define ISO14443B_WUPB 0x08
+
+extern void ISO14443BSetupRegisters(void);
+extern void ISO14443BPowerOn(void);
+extern void ISO14443BPowerOff(void);
+extern int ISO14443BHalt(unsigned char *pucPUPI);
+extern int ISO14443BREQB(unsigned char ucCmd, unsigned char ucAFI, unsigned char ucN,
+ unsigned char *pucATQB, unsigned int *puiATQBSize );
+extern int ISO14443BATTRIB(unsigned char *pucPUPI, unsigned char ucTR0, unsigned char ucTR1, unsigned char ucEOF_SOF,
+ unsigned char ucMaxFrameSize, unsigned char ucBitRateD2C, unsigned char ucBitRateC2D,
+ unsigned char ucProtocolType, unsigned char ucCID, unsigned char *A2ATTRIB);
+
+#endif
diff --git a/nfclib/iso15693.c b/nfclib/iso15693.c
new file mode 100644
index 0000000..dc32578
--- /dev/null
+++ b/nfclib/iso15693.c
@@ -0,0 +1,694 @@
+//*****************************************************************************
+//
+// iso15693.c - The top level API used to communicate with ISO15063 cards.
+//
+// Copyright (c) 2010-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+//*****************************************************************************
+
+#include <string.h>
+#include "inc/hw_memmap.h"
+#include "inc/hw_types.h"
+#include "driverlib/sysctl.h"
+#include "trf79x0.h"
+#include "nfclib/iso15693.h"
+
+extern struct
+{
+ //
+ // The actual string of bytes in the UID.
+ //
+ unsigned char pucUID[UID_SIZE];
+
+ //
+ // The number of valid bytes in the pucUID variable.
+ //
+ unsigned long ulUIDSize;
+
+ //
+ // The ASCII string that is used to display the UID on the screen.
+ //
+ char pcUIDStr[CARD_LABEL_SIZE];
+
+ unsigned char ucSlot;
+}g_sCard_15693[16];
+
+//*****************************************************************************
+//
+// Command/Response and transmit/receive buffer.
+//
+//*****************************************************************************
+static unsigned char g_pucCmd[16];
+
+//*****************************************************************************
+//
+// The value that is written to the block if the "Erase" button is pressed.
+// This will invalidate the block.
+//
+//*****************************************************************************
+static const unsigned char g_pucValueEmpty[] =
+{
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+static unsigned char ucCardFound = 0;
+
+//*****************************************************************************
+//
+// Set up registers for ISO 15693 operation. This function must
+// be called after initializing the TRF79x0 (for example with TRF79x0Init()
+// or TRF79x0Command() with argument \b TRF79X0_SOFT_INIT_CMD) and before
+// calling any of the other ISO15963 functions.
+//
+//*****************************************************************************
+void
+ISO15693SetupRegisters(void)
+{
+ // actually, we can just use the default setting
+#if 0
+ //
+ // Set the TX pulse to 9.44us (0x80 * 73.7ns).
+ //
+ TRF79x0WriteRegister(TRF79X0_TX_PULSE_LENGTH_CTRL_REG, 0x80);
+
+ //
+ // Set the RX No response wait time to 529us (0xe * 37.76us).
+ //
+ TRF79x0WriteRegister(TRF79X0_RX_NO_RESPONSE_WAIT_REG, 0x0e);
+
+ //
+ // Set the RX wait time to 293us (0x20 * 9.44us).
+ //
+ TRF79x0WriteRegister(TRF79X0_RX_WAIT_TIME_REG, 0x20);
+
+ //
+ // Configure the Special Settings Register.
+ //
+ TRF79x0WriteRegister(TRF79X0_RX_SPECIAL_SETTINGS_REG,
+ (TRF79x0ReadRegister(TRF79X0_RX_SPECIAL_SETTINGS_REG) & 0x0f) |
+ TRF79X0_RX_SP_SET_C424);
+
+ //
+ // Configure the Test Settings Register.
+ //
+ TRF79x0WriteRegister(TRF79X0_TEST_SETTING1_REG, 0x20);
+#endif
+
+ //
+ // Set the SYSCLK to 6.78MHz and the Modulation Depth to OOK.
+ //
+ TRF79x0WriteRegister(TRF79X0_MODULATOR_CONTROL_REG,
+ (TRF79X0_MOD_CTRL_SYS_CLK_6_78MHZ |
+ TRF79X0_MOD_CTRL_MOD_ASK_10));
+
+ //
+ // Set the regulator voltage to be automatic.
+ //
+ TRF79x0WriteRegister(TRF79X0_REGULATOR_CONTROL_REG,
+ TRF79X0_REGULATOR_CTRL_AUTO_REG);
+
+ //
+ // Set the regulator voltage to be automatic.
+ //
+ TRF79x0WriteRegister(TRF79X0_CHIP_STATUS_CTRL_REG,
+ TRF79X0_STATUS_CTRL_RF_ON | TRF79X0_STATUS_CTRL_RF_PWR_FULL
+ | TRF79X0_STATUS_CTRL_5V_OPERATION);
+
+ //
+ // Set the ISO format to ISO15693 high bit rate, 26.48 kbps, one subcarrier, 1 out of 4
+ //
+ TRF79x0WriteRegister(TRF79X0_ISO_CONTROL_REG,
+ TRF79X0_ISO_CONTROL_15693_HIGH_1SUB_1OUT4);
+}
+
+//*****************************************************************************
+//
+//! Initializes the ISO15693 utility functions.
+//!
+//! This function prepares the ISO1593 utility functions so that they are
+//! prepared for the remaining ISO1593 calls. This function must be called once
+//! before calling any other ISO1593 functions.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+ISO15693Init(void)
+{
+ //
+ // Initialize RFID hardware.
+ //
+ TRF79x0Init();
+
+ //
+ // Set up ISO 15693 operation.
+ //
+ ISO15693SetupRegisters();
+}
+
+void
+ISO15693NextSlot(void)
+{
+ TRF79x0Command(TRF79X0_STOP_DECODERS_CMD);
+ TRF79x0Command(TRF79X0_RUN_DECODERS_CMD);
+ TRF79x0Command(TRF79X0_RESET_FIFO_CMD);
+ TRF79x0Command(TRF79X0_TRANSMIT_NEXT_SLOT_CMD);
+}
+
+//
+// \ucSubCarrier,
+// 0 A single sub-carrier frequency shall be used by the VICC
+// 1 Two sub-carriers shall be used by the VICC
+// \ucDataRate
+// 0 Low data rate shall be used
+// 1 High data rate shall be used
+// \ucNbSlots
+// 0 16 slots
+// 1 1 slot
+//
+int
+ISO15693InventoryAFI(unsigned char ucSubCarrier, unsigned char ucDataRate,
+ unsigned char ucAfi, unsigned char ucNbSlots,
+ unsigned char *pucMask, unsigned char ucMaskLen)
+{
+ unsigned char pucResponse[10];
+ unsigned int uiRxSize, i, slot;
+
+ uiRxSize = 10;
+
+ //
+ // Prepare Inventory command.
+ //
+ // b5 AFI_flag
+ // 0 AFI Field is not present
+ // 1 AFI Field is present
+ g_pucCmd[0] = (ucNbSlots << 5) | (0x1 << 4) | (0x1 << 2) | (ucDataRate << 1) | ucSubCarrier;
+ g_pucCmd[1] = 0x01; // Command Code = 0x01 ---> Inventory
+ g_pucCmd[2] = ucAfi;
+ g_pucCmd[3] = ucMaskLen;
+
+ //
+ // Transmit Inventory, receive response
+ //
+ TRF79x0Transceive(g_pucCmd, 4, 0, pucResponse, &uiRxSize, 0, TRF79X0_TRANSCEIVE_CRC);
+
+ //
+ // check if needing to scan slot
+ //
+ slot = 1;
+ while((uiRxSize != 10) && (slot < 16))
+ {
+ uiRxSize = sizeof(pucResponse);
+
+ TRF79x0IRQClearCauses(TRF79X0_WAIT_RXEND);
+ //
+ // the order of the two function must not reversed, because the TRF79x0ReceiveAgain() called
+ // TRF79x0Command(TRF79X0_RESET_FIFO_CMD); to reset receive FIFO
+ // the most important action TRF79x0ReceiveAgain() done is to set g_sRXState.uiMaxLength as uiRxSize
+ // in order to enable the TRF7970A interrupt to continue receive data
+ //
+ ISO15693NextSlot();
+ TRF79x0ReceiveAgain(pucResponse, &uiRxSize);
+ slot++;
+ };
+
+ if(uiRxSize == 10 )
+ {
+ //
+ // Valid answer to Inventory command received, return it as an char, uiRxSize NOT including two CRC bytes
+ // the first 2 byte in pucResponse is Flags & DSFI, the last 8 bytes is UID
+ //
+ if(pucMask != NULL)
+ {
+ for(i = 0; i < 8; i++)
+ pucMask[i] = pucResponse[2 + i];
+ }
+ return(uiRxSize);
+ }
+ else
+ {
+ return(0);
+ }
+}
+
+
+//
+// \ucSubCarrier,
+// 0 A single sub-carrier frequency shall be used by the VICC
+// 1 Two sub-carriers shall be used by the VICC
+// \ucDataRate
+// 0 Low data rate shall be used
+// 1 High data rate shall be used
+// \ucNbSlots
+// 0 16 slots
+// 1 1 slot
+//
+int
+ISO15693Inventory(unsigned char ucSubCarrier, unsigned char ucDataRate,
+ unsigned char ucNbSlots, unsigned char *pucMask, unsigned char ucMaskLen)
+{
+ unsigned char pucResponse[10];
+ unsigned char uiRxSize, i, slot;
+
+ uiRxSize = sizeof(pucResponse);
+
+ //
+ // Prepare Inventory command.
+ //
+ // b5 AFI_flag
+ // 0 AFI Field is not present
+ // 1 AFI Field is present
+ g_pucCmd[0] = (ucNbSlots << 5) | (0x1 << 2) | (ucDataRate << 1) | ucSubCarrier;
+ g_pucCmd[1] = 0x01; // Command Code = 0x01 ---> Inventory
+ g_pucCmd[3] = ucMaskLen;
+
+ //
+ // Transmit Inventory, receive response
+ //
+ TRF79x0Transceive(g_pucCmd, 3, 0, pucResponse, &uiRxSize, 0, TRF79X0_TRANSCEIVE_CRC);
+
+ //
+ // check if needing to scan slot
+ //
+ slot = 1;
+ while((uiRxSize != 10) && (slot < 16))
+ {
+ uiRxSize = sizeof(pucResponse);
+
+ TRF79x0IRQClearCauses(TRF79X0_WAIT_RXEND);
+ //
+ // the order of the two function must not reversed, because the TRF79x0ReceiveAgain() called
+ // TRF79x0Command(TRF79X0_RESET_FIFO_CMD); to reset receive FIFO
+ // the most important action TRF79x0ReceiveAgain() done is to set g_sRXState.uiMaxLength as uiRxSize
+ // in order to enable the TRF7970A interrupt to continue receive data
+ //
+ ISO15693NextSlot();
+ TRF79x0ReceiveAgain(pucResponse, &uiRxSize);
+ slot++;
+ };
+
+ if(uiRxSize == 10 )
+ {
+ //
+ // Valid answer to Inventory command received, return it as an char, uiRxSize NOT including two CRC bytes
+ //
+ if(pucMask != NULL)
+ {
+ for(i = 0; i < uiRxSize; i++)
+ pucMask[i] = pucResponse[i];
+ }
+ return(uiRxSize);
+ }
+ else
+ {
+ return(0);
+ }
+}
+
+int
+ISO15693Anticollision16Slots(unsigned char ucSubCarrier, unsigned char ucDataRate,
+ unsigned char *pucMask, unsigned char ucMaskLen)
+{
+ unsigned char pucResponse[10], ucMaskNew[8];
+ unsigned int uiRxSize, uiTxSize, i, slot = 0;
+ unsigned int uiFlagCollision = 0, uiSlotCollision = 0;
+
+ uiRxSize = sizeof(pucResponse);
+
+ //
+ // Prepare Inventory command.
+ //
+ // b5 AFI_flag
+ // 0 AFI Field is not present
+ // 1 AFI Field is present
+ g_pucCmd[0] = (0x1 << 2) | (ucDataRate << 1) | ucSubCarrier;
+ g_pucCmd[1] = 0x01; // Command Code = 0x01 ---> Inventory
+ g_pucCmd[2] = ucMaskLen;
+
+ uiTxSize = 3 + (((ucMaskLen >> 2) + 1) >> 1);
+
+ if(uiTxSize > 3)
+ {
+ for(i = 0; i < (uiTxSize - 3); i++)
+ g_pucCmd[3 + i] = pucMask[i];
+ }
+
+ //
+ // Transmit Inventory, receive response
+ //
+ TRF79x0Transceive(g_pucCmd, uiTxSize, 0, pucResponse, &uiRxSize, 0, TRF79X0_TRANSCEIVE_CRC);
+
+ //
+ // check if needing to scan slot
+ //
+ while(slot < 16)
+ {
+ if(TRF79x0IsCollision() == 1)
+ {
+ uiFlagCollision = 1;
+ uiSlotCollision = slot -1;
+ }
+ else if(uiRxSize == 10)
+ {
+ for(i = 0; i < 8; i++)
+ g_sCard_15693[ucCardFound + 1].pucUID[i] = pucResponse[2 + i];
+ g_sCard_15693[ucCardFound + 1].ucSlot = slot;
+ ucCardFound++;
+ }
+
+ uiRxSize = sizeof(pucResponse);
+
+ TRF79x0IRQClearCauses(TRF79X0_WAIT_RXEND);
+
+ //
+ // the order of the two function must not reversed, because the TRF79x0ReceiveAgain() called
+ // TRF79x0Command(TRF79X0_RESET_FIFO_CMD); to reset receive FIFO
+ // the most important action TRF79x0ReceiveAgain() done is to set g_sRXState.uiMaxLength as uiRxSize
+ // in order to enable the TRF7970A interrupt to continue receive data
+ //
+ ISO15693NextSlot();
+ TRF79x0ReceiveAgain(pucResponse, &uiRxSize);
+ slot++;
+ };
+
+ //
+ // only do ones cascade
+ // TODO: NEED refer to the msp430 version to make more cascade anticollision function
+ //
+ if(uiFlagCollision && (ucMaskLen < 4))
+ {
+ uiFlagCollision = 0;
+ ucMaskNew[0] = uiSlotCollision;
+ ISO15693Anticollision16Slots(0, 1, &ucMaskNew[0], ucMaskLen + 4);
+ }
+
+ if(ucCardFound)
+ {
+ ucCardFound = 0;
+ return(1);
+ }
+ else
+ {
+ return(0);
+ }
+}
+
+int
+ISO15693StayQuiet(unsigned char *pucUID)
+{
+ int i;
+
+ //
+ // Prepare Stay Quiet command.
+ //
+ // b6 Address_flag the bit sequence start from b1 not b0!
+ // 1 Request is addressed. UID field is included. It shall be executed only
+ // by the VICC whose UID matches the UID specified in the request.
+ g_pucCmd[0] = (1 << 5) | (1 << 1);
+ // Command Code = 0x02 ---> Stay Quiet
+ g_pucCmd[1] = 0x02;
+ for(i = 0; i < 8; i++)
+ g_pucCmd[2 + i] = pucUID[i];
+
+ //
+ // Transmit Stay Quiet command, receive response
+ //
+ TRF79x0Transceive(g_pucCmd, 10, 0, 0, 0, 0, TRF79X0_TRANSCEIVE_TX_CRC);
+}
+
+//*****************************************************************************
+//
+// ! Reads a single block data from the selected card.
+// !
+// ! \param uiBlock is the address of the block to read.
+// ! \param pucBuf is the output buffer to store the raw block contents into.
+// ! This buffer must be able to store at least 32 bytes.
+// !
+// ! This function reads a ISO15693 block and returns the full contents
+// ! of the block with no interpretation of the bytes. The function will
+// ! return the number of valid bytes stored in the \e pucBuf parameter.
+// !
+//
+//*****************************************************************************
+int
+BlockReadSingleUID(unsigned char *pucUID, unsigned int uiBlock, unsigned char *pucBuf)
+{
+ unsigned char pucCmd[11];
+ unsigned int uiRxBytes;
+ unsigned int uiRxBits;
+ int i;
+
+ //
+ // Reading 32 bytes and 0 bits.
+ //
+ uiRxBytes = 32;
+ uiRxBits = 0;
+
+ //
+ // Prepare Read Single Block command.
+ //
+ // b6 Address_flag the bit sequence start from b1 not b0!
+ // 1 Request is addressed. UID field is included. It shall be executed only
+ // by the VICC whose UID matches the UID specified in the request.
+ // b7 Option_flag
+ // 1 Meaning is defined by the command description
+ pucCmd[0] = (1 << 6) |(1 << 5) | (1 << 1);
+ // Command Code = 0x20 ---> Read Single Block
+ pucCmd[1] = 0x20;
+ for(i = 0; i < 8; i++)
+ pucCmd[2 + i] = pucUID[i];
+ pucCmd[10] = uiBlock;
+
+ //
+ // Transmit Read Single Block, receive response
+ //
+ TRF79x0Transceive(pucCmd, sizeof(pucCmd), 0, pucBuf, &uiRxBytes, &uiRxBits, TRF79X0_TRANSCEIVE_CRC);
+ if(uiRxBytes == 0)
+ {
+ return(0);
+ }
+
+ return(uiRxBytes);
+}
+
+int
+BlockReadSingle(unsigned int uiBlock, unsigned char *pucBuf)
+{
+ unsigned char pucCmd[3];
+ unsigned int uiRxBytes;
+ unsigned int uiRxBits;
+ int i;
+
+ //
+ // Reading 32 bytes and 0 bits.
+ //
+ uiRxBytes = 32;
+ uiRxBits = 0;
+
+ //
+ // Prepare Read Single Block command.
+ //
+ // b7 Option_flag
+ // 1 Meaning is defined by the command description
+ pucCmd[0] = (1 << 6) | (1 << 1);
+ // Command Code = 0x20 ---> Read Single Block
+ pucCmd[1] = 0x20;
+ pucCmd[2] = uiBlock;
+
+ //
+ // Transmit Read Single Block, receive response
+ //
+ TRF79x0Transceive(pucCmd, sizeof(pucCmd), 0, pucBuf, &uiRxBytes, &uiRxBits, TRF79X0_TRANSCEIVE_CRC);
+ if(uiRxBytes == 0)
+ {
+ return(0);
+ }
+
+ return(uiRxBytes);
+}
+//*****************************************************************************
+//
+// ! Write a single block data to the selected card.
+// !
+// ! \param uiBlock is the address of the block to write.
+// ! \param pucBuf is the input buffer to store the raw block contents into.
+// ! This buffer must be able to store at least 32 bytes.
+// !
+// ! This function write a ISO15693 block
+// !
+//
+//*****************************************************************************
+int
+BlockWriteSingleUID(unsigned char *pucUID, unsigned int uiBlock, unsigned char ucValueLen, unsigned char *pucBuf)
+{
+ unsigned char pucCmd[43];
+ unsigned char pucResponse[2];
+ unsigned int uiRxBytes;
+ int i;
+
+ //
+ // transmit bytes as most
+ //
+ uiRxBytes = 2;
+
+ //
+ // Prepare Write Single Block command.
+ //
+ // b6 Address_flag the bit sequence start from b1 not b0!
+ // 1 Request is addressed. UID field is included. It shall be executed only
+ // by the VICC whose UID matches the UID specified in the request.
+
+ // b7 Option_flag must be set for Write & Lock command
+ // 1 Meaning is defined by the command description
+ pucCmd[0] = (1 << 6) | (1 << 5) | (1 << 1);
+ // Command Code = 0x21 ---> Write Single Block
+ pucCmd[1] = 0x21;
+ for(i = 0; i < 8; i++)
+ pucCmd[2 + i] = pucUID[i];
+ pucCmd[10] = uiBlock;
+ for(i = 0; i < ucValueLen; i++)
+ pucCmd[11 + i] = pucBuf[i];
+
+ //
+ // Transmit Read Single Block, receive response
+ //
+ TRF79x0TransceiveISO15693(pucCmd, 11 + ucValueLen, 0, pucResponse, &uiRxBytes, 0, TRF79X0_TRANSCEIVE_CRC);
+ if(uiRxBytes == 0)
+ {
+ return(0);
+ }
+
+ return(uiRxBytes);
+}
+
+int
+BlockWriteSingle(unsigned int uiBlock, unsigned char ucValueLen, unsigned char *pucBuf)
+{
+ unsigned char pucCmd[7];
+ unsigned char pucResponse[2];
+ unsigned int uiRxBytes;
+ int i;
+
+ //
+ // transmit bytes as most
+ //
+ uiRxBytes = 2;
+
+ //
+ // Prepare Write Single Block command.
+ //
+ // b6 Address_flag the bit sequence start from b1 not b0!
+ // 1 Request is addressed. UID field is included. It shall be executed only
+ // by the VICC whose UID matches the UID specified in the request.
+
+ // b7 Option_flag must be set for Write & Lock command
+ // 1 Meaning is defined by the command description
+ pucCmd[0] = (1 << 6) | (1 << 1);
+ // Command Code = 0x21 ---> Write Single Block
+ pucCmd[1] = 0x21;
+ pucCmd[2] = uiBlock;
+ for(i = 0; i < ucValueLen; i++)
+ pucCmd[3 + i] = pucBuf[i];
+
+ //
+ // Transmit Read Single Block, receive response
+ //
+ TRF79x0TransceiveISO15693(pucCmd, 3 + ucValueLen, 0, pucResponse, &uiRxBytes, 0, TRF79X0_TRANSCEIVE_CRC);
+ if(uiRxBytes == 0)
+ {
+ return(0);
+ }
+
+ return(uiRxBytes);
+}
+
+int
+BlockLockSingleUID(unsigned char *pucUID, unsigned int uiBlock, unsigned char *pucResponse)
+{
+ unsigned char pucCmd[11];
+ unsigned int uiRxBytes;
+ unsigned int uiRxBits;
+ int i;
+
+ //
+ // Reading 32 bytes and 0 bits.
+ //
+ uiRxBytes = 2;
+ uiRxBits = 0;
+
+ //
+ // Prepare Read Single Block command.
+ //
+ // b6 Address_flag the bit sequence start from b1 not b0!
+ // 1 Request is addressed. UID field is included. It shall be executed only
+ // by the VICC whose UID matches the UID specified in the request.
+ // b7 Option_flag must be set for Write & Lock command
+ // 1 Meaning is defined by the command description
+ pucCmd[0] = (1 << 6) | (1 << 5) | (1 << 1);
+ // Command Code = 0x22 ---> Lock Single Block
+ pucCmd[1] = 0x22;
+ for(i = 0; i < 8; i++)
+ pucCmd[2 + i] = pucUID[i];
+ pucCmd[10] = uiBlock;
+
+ //
+ // Transmit Read Single Block, receive response
+ //
+ TRF79x0TransceiveISO15693(pucCmd, sizeof(pucCmd), 0, pucResponse, &uiRxBytes, &uiRxBits, TRF79X0_TRANSCEIVE_CRC);
+ if(uiRxBytes == 0)
+ {
+ return(0);
+ }
+
+ return(uiRxBytes);
+}
+
+int
+BlockLockSingle(unsigned int uiBlock, unsigned char *pucResponse)
+{
+ unsigned char pucCmd[3];
+ unsigned int uiRxBytes;
+ unsigned int uiRxBits;
+ int i;
+
+ //
+ // Reading 32 bytes and 0 bits.
+ //
+ uiRxBytes = 2;
+ uiRxBits = 0;
+
+ //
+ // Prepare Read Single Block command.
+ //
+
+ pucCmd[0] = (1 << 6) | (1 << 1);
+ // Command Code = 0x22 ---> Lock Single Block
+ pucCmd[1] = 0x22;
+ pucCmd[2] = uiBlock;
+
+ //
+ // Transmit Read Single Block, receive response
+ //
+ TRF79x0TransceiveISO15693(pucCmd, sizeof(pucCmd), 0, pucResponse, &uiRxBytes, &uiRxBits, TRF79X0_TRANSCEIVE_CRC);
+ if(uiRxBytes == 0)
+ {
+ return(0);
+ }
+
+ return(uiRxBytes);
+}
diff --git a/nfclib/iso15693.h b/nfclib/iso15693.h
new file mode 100644
index 0000000..574b199
--- /dev/null
+++ b/nfclib/iso15693.h
@@ -0,0 +1,62 @@
+//*****************************************************************************
+//
+// iso15693.h - The top level API used to communicate with MIFARE cards.
+//
+// Copyright (c) 2010-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+//*****************************************************************************
+
+#ifndef __ISO15693_H__
+#define __ISO15693_H__
+
+//*****************************************************************************
+//
+// The maximum size in bytes of a card's UID in ASCII.
+//
+//*****************************************************************************
+#define UID_SIZE 8
+
+
+//*****************************************************************************
+//
+// The size in card label string for the card's UID. Two characters per byte
+// and a spot for a null terminator.
+//
+//*****************************************************************************
+#define CARD_LABEL_SIZE (6 + (UID_SIZE * 2) + 1)
+
+extern void ISO15693Init(void);
+extern int ISO15693InventoryAFI(unsigned char ucSubCarrier, unsigned char ucDataRate,
+ unsigned char ucAfi, unsigned char ucNbSlots,
+ unsigned char *pucMask, unsigned char ucMaskLen);
+extern int ISO15693Inventory(unsigned char ucSubCarrier, unsigned char ucDataRate,
+ unsigned char ucNbSlots, unsigned char *pucMask, unsigned char ucMaskLen);
+extern int ISO15693Anticollision16Slots(unsigned char ucSubCarrier, unsigned char ucDataRate,
+ unsigned char *pucMask, unsigned char ucMaskLen);
+
+extern int BlockReadSingleUID(unsigned char *pucUID, unsigned int uiBlock, unsigned char *pucBuf);
+extern int BlockWriteSingleUID(unsigned char *pucUID, unsigned int uiBlock, unsigned char ucValueLen, unsigned char *pucBuf);
+extern int BlockLockSingleUID(unsigned char *pucUID, unsigned int uiBlock, unsigned char *pucResponse);
+
+extern int BlockReadSingle(unsigned int uiBlock, unsigned char *pucBuf);
+extern int BlockWriteSingle(unsigned int uiBlock, unsigned char ucValueLen, unsigned char *pucBuf);
+extern int BlockLockSingle(unsigned int uiBlock, unsigned char *pucResponse);
+
+extern int ISO15693StayQuiet(unsigned char *pucUID);
+
+#endif
+
diff --git a/nfclib/llcp.c b/nfclib/llcp.c
new file mode 100644
index 0000000..9a878ea
--- /dev/null
+++ b/nfclib/llcp.c
@@ -0,0 +1,1051 @@
+//*****************************************************************************
+//
+// llcp.c - Logic Link Control Protocol : used to send packets via NPP or SNEP
+// NPP: NDEF Push Protocol
+// SNEP: Simple NDEF Exchange protocol
+// NOTE: currently only SNEP is Supported
+//
+// Copyright (c) 2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
+//
+//*****************************************************************************
+#include <stdbool.h>
+#include <stdint.h>
+#include <string.h>
+#include "utils/uartstdio.h"
+#include "nfclib/llcp.h"
+#include "nfclib/snep.h"
+
+//*****************************************************************************
+//
+//! \addtogroup nfc_llcp_api NFC LLCP API Functions
+//! @{
+//! Logical Link Control Protocol is the NFC transport layer used to open and
+//! close a virtual link used to transfer NDEFs between two devices in
+//! peer-to-peer mode via the Simple NDEF Exchange Protocol.
+//! For more information on LLCP, please read the Logical Link Control Protocol
+//! Specification Version 1.1.
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// The next PDU to be sent to the destination device - updated based on
+// incoming packets or by LLCPSetNextPDU().
+//
+//*****************************************************************************
+tLLCPPduPtype g_eNextPduQueue = LLCP_SYMM_PDU;
+
+//*****************************************************************************
+//
+// Connection Status
+//
+//*****************************************************************************
+tLLCPConnectionStatus g_eLLCPConnectionStatus = LLCP_CONNECTION_IDLE;
+
+//*****************************************************************************
+//
+// Destination Service Access Point Address
+//
+//*****************************************************************************
+uint8_t g_ui8dsapValue;
+
+//*****************************************************************************
+//
+// Source Service Access Point Address
+//
+//*****************************************************************************
+uint8_t g_ui8ssapValue;
+
+//*****************************************************************************
+//
+// Service Name - SNEP by default
+//
+//*****************************************************************************
+tServiceName g_eCurrentServiceEnabled = SNEP_SERVICE;
+
+//*****************************************************************************
+//
+// Acknowledged packets
+//
+//*****************************************************************************
+uint8_t g_ui8NSNR = 0x00;
+
+//*****************************************************************************
+//
+// Disconnected Mode Reason
+//
+//*****************************************************************************
+tDisconnectModeReason g_eDMReason;
+
+//*****************************************************************************
+//
+// LLCP Link Time Out
+//
+//*****************************************************************************
+uint16_t g_ui16LLCPlto = 0x00;
+
+//*****************************************************************************
+//
+// LLCP MIUX of the initiator / target communicating with the TRF7970A.
+// 248 by default.
+//
+//*****************************************************************************
+uint8_t g_ui8LLCPmiu = 248;
+
+//*****************************************************************************
+//
+//! Initializes the Logical Link Control Protocol layer.
+//!
+//! This function must be called prior to any other function offer by the LLCP
+//! driver. This function initializes the acknowledge packets, the current
+//! service enabled, and the next PDU for the LLCP_stateMachine(), and also
+//! initializes the SNEP layer with SNEP_init().
+//!
+//! \return None
+//!
+//
+//*****************************************************************************
+void LLCP_init(void)
+{
+ //
+ // Reset NS and NR
+ //
+ g_ui8NSNR = 0x00;
+ g_ui8LLCPmiu = 128;
+ g_eLLCPConnectionStatus = LLCP_CONNECTION_IDLE;
+ g_eCurrentServiceEnabled = SNEP_SERVICE;
+ g_eNextPduQueue = LLCP_SYMM_PDU;
+ SNEP_init();
+ SNEP_setMaxPayload(g_ui8LLCPmiu);
+}
+
+//*****************************************************************************
+//
+//! Gets link timeout
+//!
+//! This function returns the Link Timeout, which may be modified if the
+//! LLCP_processTLV() function processes a LLCP_LTO TLV.
+//!
+//! \return \e \b g_ui16LLCPlto the link timeout.
+//
+//*****************************************************************************
+uint16_t LLCP_getLinkTimeOut(void)
+{
+ return g_ui16LLCPlto;
+}
+
+//*****************************************************************************
+//
+//! Adds a LLCP parameter to the LLCP PDU with the Type Length
+//! Value (TLV) format.
+//!
+//! \param eLLCPparam is the LLCP type that will be added.
+//! \param pui8TLVBufferPtr is the pointer where the TLV is written
+//!
+//! The \e \b eLLCPparam parameter can be any of the following:
+//!
+//! - \b LLCP_VERSION - Version Number
+//! - \b LLCP_MIUX - Maximum Information Unit Extension
+//! - \b LLCP_WKS - Well-Known Service List
+//! - \b LLCP_LTO - Link Timeout
+//! - \b LLCP_RW - Receive Window Size
+//! - \b LLCP_SN - Service Name
+//! - \b LLCP_OPT - Option
+//! - \b LLCP_SDREQ - Service Discovery Request
+//! - \b LLCP_SDRES - Service Discovery Response
+//! - \b LLCP_ERROR - Reserved (used ro return length of 0)
+//!
+//! This function is used to add a LLCP Parameter to the LLCP PDU to include
+//! more information about the LLCP layer. This function must be called inside
+//! LLCP_sendCONNECT(), LLCP_sendCC(), NFCDEP_sendATR_REQ() and
+//! NFCDEP_sendATR_RES().
+//!
+//! \return ui8PacketLength Length of the LLCP Parameter added to the LLCP.
+//
+//*****************************************************************************
+uint8_t LLCP_addTLV(tLLCPParamaeter eLLCPparam, uint8_t * pui8TLVBufferPtr)
+{
+ uint8_t ui8PacketLength = 0;
+
+ switch(eLLCPparam)
+ {
+ case LLCP_VERSION:
+ // Type
+ pui8TLVBufferPtr[0] = (uint8_t) LLCP_VERSION;
+ // Length
+ pui8TLVBufferPtr[1] = 0x01;
+ // Value
+ pui8TLVBufferPtr[2] = 0x11; // Version 1.1
+ break;
+ case LLCP_MIUX:
+ // Type
+ pui8TLVBufferPtr[0] = (uint8_t) LLCP_MIUX;
+ // Length
+ pui8TLVBufferPtr[1] = 0x02;
+ // Value
+ // 128 + MIUX (120) = MIU (248)
+ pui8TLVBufferPtr[2] = (LLCP_MIUX_SIZE >> 8) & 0xFF; // MIUX 15:8
+ pui8TLVBufferPtr[3] = (uint8_t) LLCP_MIUX_SIZE; // MIUX 7:0
+ break;
+ case LLCP_WKS:
+ // Type
+ pui8TLVBufferPtr[0] = (uint8_t) LLCP_WKS;
+ // Length
+ pui8TLVBufferPtr[1] = 0x02;
+ // Value
+ pui8TLVBufferPtr[2] = 0x00;
+ pui8TLVBufferPtr[3] = 0x03;
+ break;
+ case LLCP_LTO:
+ // Type
+ pui8TLVBufferPtr[0] = (uint8_t) LLCP_LTO;
+ // Length
+ pui8TLVBufferPtr[1] = 0x01;
+ // Value
+ pui8TLVBufferPtr[2] = 0x64; // (100 (0x64) * 10 mS = 1000 mS timeout, Figure 22, LLP)
+ break;
+ case LLCP_RW:
+ // Type
+ pui8TLVBufferPtr[0] = (uint8_t) LLCP_RW;
+ // Length
+ pui8TLVBufferPtr[1] = 0x01;
+ // Value
+ // Section 5.6.2.2 LLP
+ // A receive window size of zero indicates that the local LLC will not
+ // accept I PDUs on that data link connection. A receive window size of
+ // one indicates that the local LLC will acknowledge every I PDU before
+ // accepting additional I PDUs.
+ //
+ pui8TLVBufferPtr[2] = 0x04;
+ break;
+ case LLCP_SN:
+ // Type
+ pui8TLVBufferPtr[0] = (uint8_t) LLCP_SN;
+ if(g_eCurrentServiceEnabled == NPP_SERVICE)
+ {
+ // Length
+ pui8TLVBufferPtr[1] = 0x0F;
+ // Value
+ pui8TLVBufferPtr[2] = 'c';
+ pui8TLVBufferPtr[3] = 'o';
+ pui8TLVBufferPtr[4] = 'm';
+ pui8TLVBufferPtr[5] = '.';
+ pui8TLVBufferPtr[6] = 'a';
+ pui8TLVBufferPtr[7] = 'n';
+ pui8TLVBufferPtr[8] = 'd';
+ pui8TLVBufferPtr[9] = 'r';
+ pui8TLVBufferPtr[10] = 'o';
+ pui8TLVBufferPtr[11] = 'i';
+ pui8TLVBufferPtr[12] = 'd';
+ pui8TLVBufferPtr[13] = '.';
+ pui8TLVBufferPtr[14] = 'n';
+ pui8TLVBufferPtr[15] = 'p';
+ pui8TLVBufferPtr[16] = 'p';
+ }
+ else if(g_eCurrentServiceEnabled == SNEP_SERVICE)
+ {
+ // Length
+ pui8TLVBufferPtr[1] = 0x0F;
+ // Value
+ pui8TLVBufferPtr[2] = 'u';
+ pui8TLVBufferPtr[3] = 'r';
+ pui8TLVBufferPtr[4] = 'n';
+ pui8TLVBufferPtr[5] = ':';
+ pui8TLVBufferPtr[6] = 'n';
+ pui8TLVBufferPtr[7] = 'f';
+ pui8TLVBufferPtr[8] = 'c';
+ pui8TLVBufferPtr[9] = ':';
+ pui8TLVBufferPtr[10] = 's';
+ pui8TLVBufferPtr[11] = 'n';
+ pui8TLVBufferPtr[12] = ':';
+ pui8TLVBufferPtr[13] = 's';
+ pui8TLVBufferPtr[14] = 'n';
+ pui8TLVBufferPtr[15] = 'e';
+ pui8TLVBufferPtr[16] = 'p';
+
+ }
+ break;
+ case LLCP_OPT:
+ // Type
+ pui8TLVBufferPtr[0] = (uint8_t) LLCP_OPT;
+ // Length
+ pui8TLVBufferPtr[1] = 0x01;
+ // Value
+ pui8TLVBufferPtr[2] = 0x03; // (Class 3) (Table 7, LLP)
+ break;
+ case LLCP_SDREQ:
+ break;
+ case LLCP_SDRES:
+ break;
+ default:
+ pui8TLVBufferPtr[0] = LLCP_ERROR;
+ break;
+ }
+
+ if(pui8TLVBufferPtr[0] == LLCP_ERROR)
+ ui8PacketLength = 0x00;
+ else
+ ui8PacketLength = pui8TLVBufferPtr[1] + 2;
+
+ return ui8PacketLength;
+}
+
+//*****************************************************************************
+//
+//! Processes the LLCP Parameter TLV.
+//!
+//! \param pui8TLVBufferPtr is the pointer to the Type value of the TLV.
+//!
+//! This function processes the LLCP Parameters included in the ATR_RES. This
+//! function must be called inside the NFCDEP_processReceivedData(), to
+//! initialize the g_ui8LLCPmiu and g_ui16LLCPlto if they are included as part
+//! of ATR_RES.
+//!
+//! \return None
+//
+//*****************************************************************************
+void LLCP_processTLV(uint8_t * pui8TLVBufferPtr)
+{
+ uint16_t ui16Miu;
+ switch(pui8TLVBufferPtr[0])
+ {
+ case LLCP_VERSION:
+ break;
+ case LLCP_MIUX:
+ // MIU = 128 + MIUX
+ ui16Miu = (pui8TLVBufferPtr[2] << 8)+pui8TLVBufferPtr[3]+128;
+ // Check if the received MIU is less than 248, the modify the current MIU to it
+ if(ui16Miu < 248)
+ {
+ // Modify MIU to be less
+ g_ui8LLCPmiu = (uint8_t) ui16Miu;
+
+ }
+ else
+ {
+ // Maximum supported MIU is 248
+ g_ui8LLCPmiu = 248;
+ }
+
+ SNEP_setMaxPayload(g_ui8LLCPmiu);
+ break;
+ case LLCP_WKS:
+ break;
+ case LLCP_LTO:
+ g_ui16LLCPlto = pui8TLVBufferPtr[2] * 10;
+ break;
+ case LLCP_RW:
+ break;
+ case LLCP_SN:
+ break;
+ case LLCP_OPT:
+ break;
+ case LLCP_SDREQ:
+ break;
+ case LLCP_SDRES:
+ break;
+ default:
+ break;
+ }
+}
+
+//*****************************************************************************
+//
+//! Prepares the LLCP packet to be transmitted.
+//!
+//! \param pui8PduBufferPtr is the start pointer to add the LLCP PDU.
+//!
+//! This function is used to add the LLCP portion of the DEP_REQ / DEP_RES PDU.
+//! This function must be called inside NFCDEP_sendDEP_REQ() and
+//! NFCDEP_sendDEP_RES(). It currently does not support sending the following
+//! PDUs : LLCP_PAX_PDU, LLCP_AGF_PDU, LLCP_UI_PDU, LLCP_FRMR_PDU, LLCP_SNL_PDU,
+//! LLCP_RNR_PDU, and LLCP_RESERVED_PDU.
+//!
+//! \return ui8PacketLength is the length of the LLCP PDU added to the
+//! pui8PduBufferPtr.
+//
+//*****************************************************************************
+uint8_t LLCP_stateMachine(uint8_t * pui8PduBufferPtr)
+{
+ uint8_t ui8PacketLength=0;
+
+ switch(g_eNextPduQueue)
+ {
+ case LLCP_SYMM_PDU:
+ {
+ //UARTprintf("TX: SYMM\n");
+ ui8PacketLength = LLCP_sendSYMM(pui8PduBufferPtr);
+ break;
+ }
+ case LLCP_PAX_PDU:
+ {
+ break;
+ }
+ case LLCP_AGF_PDU:
+ {
+ break;
+ }
+ case LLCP_UI_PDU:
+ {
+ break;
+ }
+ case LLCP_CONNECT_PDU:
+ {
+ //UARTprintf("TX: CONNECT\n");
+ ui8PacketLength = LLCP_sendCONNECT(pui8PduBufferPtr);
+ g_eNextPduQueue = LLCP_SYMM_PDU;
+ break;
+ }
+ case LLCP_DISC_PDU:
+ {
+ if(g_eCurrentServiceEnabled == HANDOVER_SERVICE)
+ {
+ g_eCurrentServiceEnabled = SNEP_SERVICE;
+ }
+ //UARTprintf("TX: DISC\n");
+ ui8PacketLength = LLCP_sendDISC(pui8PduBufferPtr);
+ break;
+ }
+ case LLCP_CC_PDU:
+ {
+ //UARTprintf("TX: CC\n");
+ ui8PacketLength = LLCP_sendCC(pui8PduBufferPtr);
+ break;
+ }
+ case LLCP_DM_PDU:
+ {
+ //UARTprintf("TX: DM\n");
+ g_eLLCPConnectionStatus = LLCP_CONNECTION_IDLE;
+ ui8PacketLength = LLCP_sendDM(pui8PduBufferPtr,g_eDMReason);
+ g_eNextPduQueue = LLCP_SYMM_PDU;
+ break;
+ }
+ case LLCP_FRMR_PDU:
+ {
+ break;
+ }
+ case LLCP_SNL_PDU:
+ {
+ break;
+ }
+ case LLCP_I_PDU:
+ {
+ //UARTprintf("TX: I\n");
+ ui8PacketLength = LLCP_sendI(pui8PduBufferPtr);
+ break;
+ }
+ case LLCP_RR_PDU:
+ {
+ //UARTprintf("TX: RR\n");
+ if(g_eCurrentServiceEnabled == HANDOVER_SERVICE)
+ {
+ g_eLLCPConnectionStatus = LLCP_CONNECTION_IDLE;
+ }
+ ui8PacketLength = LLCP_sendRR(pui8PduBufferPtr);
+ break;
+ }
+ case LLCP_RNR_PDU:
+ {
+ break;
+ }
+ case LLCP_RESERVED_PDU:
+ {
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+
+ return ui8PacketLength;
+}
+
+//*****************************************************************************
+//
+//! Processes LLCP Data Received.
+//!
+//! \param pui8RxBuffer is the start pointer of the LLCP data received.
+//! \param ui8PduLength is the length of the LLCP PDU received.
+//!
+//! This function is used to handle the LLCP portion of the DEP_REQ / DEP_RES PDU.
+//! This function must be called inside NFCDEP_processReceivedRequest() and
+//! NFCDEP_processReceivedData().It currently does not support to handle the
+//! following PDUs : LLCP_PAX_PDU, LLCP_AGF_PDU, LLCP_UI_PDU, LLCP_FRMR_PDU,
+//! LLCP_SNL_PDU, LLCP_RNR_PDU, and LLCP_RESERVED_PDU.
+//!
+//! \return \b eLLCPStatus is the boolean status if the command was processed
+//! (1) or not (0).
+//
+//*****************************************************************************
+tStatus LLCP_processReceivedData(uint8_t * pui8RxBuffer, uint8_t ui8PduLength)
+{
+ tLLCPPduPtype ePduType;
+ tStatus eLLCPStatus = STATUS_SUCCESS;
+ tSNEPConnectionStatus eSnepProtocolStatus;
+
+ ePduType = (tLLCPPduPtype) ( ((pui8RxBuffer[0] & 0x03) << 2) +
+ ((pui8RxBuffer[1] & 0xC0) >> 6));
+
+ switch(ePduType)
+ {
+ case LLCP_SYMM_PDU:
+ if(g_eCurrentServiceEnabled == SNEP_SERVICE)
+ {
+ eSnepProtocolStatus = SNEP_getProtocolStatus();
+ if((g_eNextPduQueue == LLCP_CONNECT_PDU) ||
+ (g_eNextPduQueue == LLCP_I_PDU))
+ {
+ //
+ // Do no modify the next PDU
+ //
+ }
+ else if(eSnepProtocolStatus == SNEP_CONNECTION_SEND_COMPLETE)
+ {
+ SNEP_setProtocolStatus(SNEP_CONNECTION_IDLE);
+ //UARTprintf("RX: SYMM ");
+ g_eNextPduQueue = LLCP_DISC_PDU;
+ }
+ else if((eSnepProtocolStatus ==
+ SNEP_CONNECTION_RECEIVED_FIRST_PACKET) ||
+ (eSnepProtocolStatus ==
+ SNEP_CONNECTION_RECEIVE_COMPLETE) ||
+ (eSnepProtocolStatus ==
+ SNEP_CONNECTION_EXCESS_SIZE) ||
+ (eSnepProtocolStatus ==
+ SNEP_CONNECTION_SENDING_N_FRAGMENTS))
+ {
+ //UARTprintf("RX: SYMM ");
+ g_eNextPduQueue = LLCP_I_PDU;
+ }
+ else
+ {
+ if(g_eLLCPConnectionStatus != LLCP_CONNECTION_IDLE)
+ {
+ g_eNextPduQueue = LLCP_SYMM_PDU;
+ }
+ }
+ }
+ else if(g_eCurrentServiceEnabled == HANDOVER_SERVICE)
+ {
+ if(g_eLLCPConnectionStatus == LLCP_CONNECTION_IDLE)
+ {
+ g_eNextPduQueue = LLCP_DISC_PDU;
+ }
+ else
+ g_eNextPduQueue = LLCP_SYMM_PDU;
+ }
+ else
+ {
+ if(g_eLLCPConnectionStatus != LLCP_CONNECTION_IDLE)
+ {
+ //UARTprintf("RX: SYMM ");
+ g_eNextPduQueue = LLCP_SYMM_PDU;
+ }
+ }
+ break;
+ case LLCP_PAX_PDU:
+ // Not Supported
+ break;
+ case LLCP_AGF_PDU:
+ // Not Supported
+ break;
+ case LLCP_UI_PDU:
+ // Not Supported
+ break;
+ case LLCP_CONNECT_PDU:
+ g_ui8dsapValue = (pui8RxBuffer[1] & 0x3F);
+
+ // Check Service Name TLV
+ if(pui8RxBuffer[2] == 0x06)
+ {
+ if (pui8RxBuffer[3] == 0x0F && pui8RxBuffer[4] == 'u'
+ && pui8RxBuffer[5] == 'r' && pui8RxBuffer[6] == 'n'
+ && pui8RxBuffer[7] == ':' && pui8RxBuffer[8] == 'n'
+ && pui8RxBuffer[9] == 'f' && pui8RxBuffer[10] == 'c'
+ && pui8RxBuffer[11] == ':' && pui8RxBuffer[12] == 's'
+ && pui8RxBuffer[13] == 'n' && pui8RxBuffer[14] == ':'
+ && pui8RxBuffer[15] == 's' && pui8RxBuffer[16] == 'n'
+ && pui8RxBuffer[17] == 'e' && pui8RxBuffer[18] == 'p')
+ {
+ // SNEP
+ g_eCurrentServiceEnabled = SNEP_SERVICE;
+ }
+ else if (pui8RxBuffer[3] == 0x0F && pui8RxBuffer[4] == 'c'
+ && pui8RxBuffer[5] == 'o' && pui8RxBuffer[6] == 'm'
+ && pui8RxBuffer[7] == '.' && pui8RxBuffer[8] == 'a'
+ && pui8RxBuffer[9] == 'n' && pui8RxBuffer[10] == 'd'
+ && pui8RxBuffer[11] == 'r' && pui8RxBuffer[12] == 'o'
+ && pui8RxBuffer[13] == 'i' && pui8RxBuffer[14] == 'd'
+ && pui8RxBuffer[15] == '.' && pui8RxBuffer[16] == 'n'
+ && pui8RxBuffer[17] == 'p' && pui8RxBuffer[18] == 'p')
+ {
+ // NPP
+ g_eCurrentServiceEnabled = NPP_SERVICE;
+ }
+ else if (pui8RxBuffer[3] == 0x13 && pui8RxBuffer[4] == 'u'
+ && pui8RxBuffer[5] == 'r' && pui8RxBuffer[6] == 'n'
+ && pui8RxBuffer[7] == ':' && pui8RxBuffer[8] == 'n'
+ && pui8RxBuffer[9] == 'f' && pui8RxBuffer[10] == 'c'
+ && pui8RxBuffer[11] == ':' && pui8RxBuffer[12] == 's'
+ && pui8RxBuffer[13] == 'n' && pui8RxBuffer[14] == ':'
+ && pui8RxBuffer[15] == 'h' && pui8RxBuffer[16] == 'a'
+ && pui8RxBuffer[17] == 'n' && pui8RxBuffer[18] == 'd'
+ && pui8RxBuffer[19] == 'o' && pui8RxBuffer[20] == 'v'
+ && pui8RxBuffer[21] == 'e' && pui8RxBuffer[22] == 'r')
+ {
+ // Handover
+ g_eCurrentServiceEnabled = HANDOVER_SERVICE;
+ }
+ else if(ui8PduLength == 2)
+ {
+ // SNEP
+ g_eCurrentServiceEnabled = SNEP_SERVICE;
+ }
+ else
+ {
+ // // Debug Incoming Request
+ // while(1);
+ // Ignore the command
+ g_eNextPduQueue = LLCP_SYMM_PDU;
+ break;
+ }
+ }
+ else
+ g_eCurrentServiceEnabled = SNEP_SERVICE;
+
+ g_eNextPduQueue = LLCP_CC_PDU;
+ break;
+ case LLCP_DISC_PDU:
+ //UARTprintf("RX: DISC ");
+ g_eDMReason = DM_REASON_LLCP_RECEIVED_DISC_PDU;
+ g_eNextPduQueue = LLCP_DM_PDU;
+ break;
+ case LLCP_CC_PDU:
+ //UARTprintf("RX: CC ");
+ g_ui8dsapValue = (pui8RxBuffer[1] & 0x3F);
+ g_eNextPduQueue = LLCP_I_PDU;
+ break;
+ case LLCP_DM_PDU:
+ //UARTprintf("RX: DM ");
+ g_eLLCPConnectionStatus = LLCP_CONNECTION_IDLE;
+ // Reset the snep communication
+ g_eNextPduQueue = LLCP_SYMM_PDU;
+ break;
+ case LLCP_FRMR_PDU:
+ //UARTprintf("RX: FRMR ");
+ break;
+ case LLCP_SNL_PDU:
+ //UARTprintf("RX: SNL ");
+ break;
+ case LLCP_I_PDU:
+ //UARTprintf("RX: I ");
+ if(g_eCurrentServiceEnabled == SNEP_SERVICE)
+ SNEP_processReceivedData(&pui8RxBuffer[3],ui8PduLength-3);
+ else if(g_eCurrentServiceEnabled == NPP_SERVICE)
+ {
+ // Not Supported
+ }
+ else if(g_eCurrentServiceEnabled == HANDOVER_SERVICE)
+ {
+ // Not Supported
+ }
+ if(g_eLLCPConnectionStatus == LLCP_CONNECTION_ESTABLISHED)
+ {
+ g_eLLCPConnectionStatus = LLCP_CONNECTION_RECEIVING;
+ }
+ g_eNextPduQueue = LLCP_RR_PDU;
+ break;
+ case LLCP_RR_PDU:
+ //UARTprintf("RX: RR \n");
+ g_eNextPduQueue = LLCP_SYMM_PDU;
+ eSnepProtocolStatus = SNEP_getProtocolStatus();
+ if(g_eLLCPConnectionStatus == LLCP_CONNECTION_SENDING)
+ {
+ if(
+ (eSnepProtocolStatus ==
+ SNEP_CONNECTION_WAITING_FOR_CONTINUE) ||
+ (eSnepProtocolStatus ==
+ SNEP_CONNECTION_WAITING_FOR_SUCCESS))
+ {
+ g_eNextPduQueue = LLCP_SYMM_PDU;
+ }
+ else if(eSnepProtocolStatus ==
+ SNEP_CONNECTION_SENDING_N_FRAGMENTS)
+ {
+ g_eNextPduQueue = LLCP_I_PDU;
+ }
+ else if(eSnepProtocolStatus == SNEP_CONNECTION_SEND_COMPLETE)
+ {
+ g_eNextPduQueue = LLCP_DISC_PDU;
+ }
+ }
+ else
+ {
+ //
+ // Used for debugging
+ //
+ g_eNextPduQueue = LLCP_SYMM_PDU;
+ }
+ break;
+ case LLCP_RNR_PDU:
+ //UARTprintf("RX: RNR ");
+ break;
+ case LLCP_RESERVED_PDU:
+ //UARTprintf("RX: RESERVED ");
+ break;
+ default:
+ //UARTprintf("RX: UNKNOWN LLCP ");
+ eLLCPStatus = STATUS_FAIL;
+ break;
+ }
+
+ return eLLCPStatus;
+}
+
+//*****************************************************************************
+//
+//! Set next PDU, return SUCCESS or FAIL
+//!
+//! \param eNextPdu is the LLCP PDU to set next.
+//!
+//! The \e eNextPdu parameter can be any of the following:
+//!
+//! - \b LLCP_SYMM_PDU - See LLCP standard document section 4.3.1
+//! - \b LLCP_PAX_PDU - See LLCP standard document section 4.3.2
+//! - \b LLCP_AGF_PDU - See LLCP standard document section 4.3.3
+//! - \b LLCP_UI_PDU - See LLCP standard document section 4.3.4
+//! - \b LLCP_CONNECT_PDU - See LLCP standard document section 4.3.5
+//! - \b LLCP_DISC_PDU - See LLCP standard document section 4.3.6
+//! - \b LLCP_CC_PDU - See LLCP standard document section 4.3.7
+//! - \b LLCP_DM_PDU - See LLCP standard document section 4.3.8
+//! - \b LLCP_FRMR_PDU - See LLCP standard document section 4.3.9
+//! - \b LLCP_SNL_PDU - See LLCP standard document section 4.3.10
+//! - \b LLCP_I_PDU - See LLCP standard document section 4.3.11
+//! - \b LLCP_RR_PDU - See LLCP standard document section 4.3.12
+//! - \b LLCP_RNR_PDU - See LLCP standard document section 4.3.13
+//! - \b LLCP_RESERVED_PDU - See LLCP standard document section 4.3.14
+//! - \b LLCP_ERROR_PDU - Unknown PDU
+//!
+//! This function is used to modify the next LLCP PDU. For example
+//! when we need to set the next PDU to be LLCP_CONNECT_PDU, to initiate
+//! a transfer. For more information please see the LLCP document from the
+//! NFC Forum.
+//!
+//! \return eSetNextPduStatus SUCCESS if g_eNextPduQueue was modified, else
+//! return FAIL
+//
+//*****************************************************************************
+tStatus LLCP_setNextPDU(tLLCPPduPtype eNextPdu)
+{
+ tStatus eSetNextPduStatus;
+ if(g_eLLCPConnectionStatus == LLCP_CONNECTION_IDLE ||
+ g_eLLCPConnectionStatus == LLCP_CONNECTION_ESTABLISHED)
+ {
+ g_eNextPduQueue = eNextPdu;
+ if(eNextPdu == LLCP_CONNECT_PDU)
+ g_eCurrentServiceEnabled = SNEP_SERVICE;
+ eSetNextPduStatus = STATUS_SUCCESS;
+ }
+ else
+ {
+ eSetNextPduStatus = STATUS_FAIL;
+ }
+ return eSetNextPduStatus;
+}
+
+//*****************************************************************************
+//
+//! Send SYMM message
+//!
+//! \param pui8PduBufferPtr is the start pointer to store the SYMM PDU.
+//!
+//! This function adds a SYMM PDU starting at pui8PduBufferPtr.For more
+//! details on this PDU read LLCP V1.1 Section 4.3.1.
+//!
+//! \return ui8IndexTemp is the length of the SYMM PDU.
+//
+//*****************************************************************************
+uint8_t LLCP_sendSYMM(uint8_t * pui8PduBufferPtr)
+{
+ uint8_t ui8IndexTemp = 0;
+ // DSAP (6 bits) PTYPE (4 bits) SSAP (6 bits)
+ pui8PduBufferPtr[ui8IndexTemp++] = ( (LLCP_SYMM_PDU & 0xFC) >> 2);
+ pui8PduBufferPtr[ui8IndexTemp++] = ( (LLCP_SYMM_PDU & 0x03) << 6);
+ return ui8IndexTemp;
+}
+
+//*****************************************************************************
+//
+//! Send CONNECT message
+//!
+//! \param pui8PduBufferPtr is the start pointer to store the CONNECT PDU.
+//!
+//! This function adds a CONNECT PDU starting at pui8PduBufferPtr.For more
+//! details on this PDU read LLCP V1.1 Section 4.3.5.
+//!
+//! \return ui8IndexTemp is the length of the CONNECT PDU.
+//
+//*****************************************************************************
+uint8_t LLCP_sendCONNECT(uint8_t * pui8PduBufferPtr)
+{
+ uint8_t ui8IndexTemp = 0;
+
+ g_eCurrentServiceEnabled = SNEP_SERVICE;
+
+ //
+ // Reset NR and NS
+ //
+ g_ui8NSNR = 0x00;
+
+ g_eLLCPConnectionStatus = LLCP_CONNECTION_SENDING;
+
+ g_ui8ssapValue = LLCP_SSAP_CONNECT_SEND;
+ g_ui8dsapValue = DSAP_SERVICE_DISCOVERY_PROTOCOL;
+
+ // DSAP (6 bits) PTYPE (4 bits) SSAP (6 bits)
+ pui8PduBufferPtr[ui8IndexTemp++] = (g_ui8dsapValue << 2) |
+ ( (LLCP_CONNECT_PDU & 0xFC) >> 2);
+ pui8PduBufferPtr[ui8IndexTemp++] = ( (LLCP_CONNECT_PDU & 0x03) << 6) |
+ g_ui8ssapValue;
+
+ //
+ // TLV Fields
+ //
+ ui8IndexTemp = ui8IndexTemp +
+ LLCP_addTLV(LLCP_SN, &pui8PduBufferPtr[ui8IndexTemp]);
+ ui8IndexTemp = ui8IndexTemp +
+ LLCP_addTLV(LLCP_MIUX, &pui8PduBufferPtr[ui8IndexTemp]);
+ ui8IndexTemp = ui8IndexTemp +
+ LLCP_addTLV(LLCP_RW, &pui8PduBufferPtr[ui8IndexTemp]);
+
+ return ui8IndexTemp;
+}
+
+//*****************************************************************************
+//
+//! Send DISC message
+//!
+//! \param pui8PduBufferPtr is the start pointer to store the DISC PDU.
+//!
+//! This function adds a DISC PDU starting at pui8PduBufferPtr.For more details
+//! on this PDU read LLCP V1.1 Section 4.3.6.
+//!
+//! \return ui8IndexTemp is the length of the DISC PDU.
+//
+//*****************************************************************************
+uint8_t LLCP_sendDISC(uint8_t * pui8PduBufferPtr)
+{
+ uint8_t ui8IndexTemp = 0;
+
+ //
+ // DSAP (6 bits) PTYPE (4 bits) SSAP (6 bits)
+ //
+ pui8PduBufferPtr[ui8IndexTemp++] = (g_ui8dsapValue << 2) |
+ ( (LLCP_DISC_PDU & 0xFC) >> 2);
+ pui8PduBufferPtr[ui8IndexTemp++] = ( (LLCP_DISC_PDU & 0x03) << 6) |
+ g_ui8ssapValue;
+
+ return ui8IndexTemp;
+}
+
+//*****************************************************************************
+//
+//! Send CC message
+//!
+//! \param pui8PduBufferPtr is the start pointer to store the CC PDU.
+//!
+//! This function adds a CC PDU starting at pui8PduBufferPtr. For more details
+//! on this PDU, read LLCP V1.1 Section 4.3.7.
+//!
+//! \return \b ui8IndexTemp is the length of the CC PDU.
+//
+//*****************************************************************************
+uint8_t LLCP_sendCC(uint8_t * pui8PduBufferPtr)
+{
+ uint8_t ui8IndexTemp = 0;
+
+ g_eLLCPConnectionStatus = LLCP_CONNECTION_ESTABLISHED;
+
+ //
+ // Reset NR and NS
+ //
+ g_ui8NSNR = 0x00;
+
+ g_ui8ssapValue = LLCP_SSAP_CONNECT_RECEIVED;
+
+ // DSAP (6 bits) PTYPE (4 bits) SSAP (6 bits)
+ pui8PduBufferPtr[ui8IndexTemp++] = (g_ui8dsapValue << 2) |
+ ( (LLCP_CC_PDU & 0xFC) >> 2);
+ pui8PduBufferPtr[ui8IndexTemp++] = ( (LLCP_CC_PDU & 0x03) << 6) |
+ g_ui8ssapValue;
+
+ //
+ // TLV Fields
+ //
+ ui8IndexTemp = ui8IndexTemp +
+ LLCP_addTLV(LLCP_MIUX, &pui8PduBufferPtr[ui8IndexTemp]);
+ ui8IndexTemp = ui8IndexTemp +
+ LLCP_addTLV(LLCP_RW, &pui8PduBufferPtr[ui8IndexTemp]);
+
+ return ui8IndexTemp;
+}
+
+//*****************************************************************************
+//
+//! Send DM message
+//!
+//! \param pui8PduBufferPtr is the start pointer to store the DM PDU.
+//! \param eDmReason is the enumeration of the disconnection reason.
+//!
+//! The \e eDmReason parameter can be any of the following:
+//!
+//! - \b DM_REASON_LLCP_RECEIVED_DISC_PDU
+//! - \b DM_REASON_LLCP_RECEIVED_CONNECTION_ORIENTED_PDU
+//! - \b DM_REASON_LLCP_RECEIVED_CONNECT_PDU_NO_SERVICE
+//! - \b DM_REASON_LLCP_PROCESSED_CONNECT_PDU_REQ_REJECTED
+//! - \b DM_REASON_LLCP_PERMNANTLY_NOT_ACCEPT_CONNECT_WITH_SAME_SSAP
+//! - \b DM_REASON_LLCP_PERMNANTLY_NOT_ACCEPT_CONNECT_WITH_ANY_SSAP
+//! - \b DM_REASON_LLCP_TEMMPORARILY_NOT_ACCEPT_PDU_WITH_SAME_SSSAPT
+//! - \b DM_REASON_LLCP_TEMMPORARILY_NOT_ACCEPT_PDU_WITH_ANY_SSSAPT
+//!
+//! This function adds a DM PDU starting at pui8PduBufferPtr with a dm_reason.
+//! For more details on this PDU read LLCP V1.1 Section 4.3.8.
+//!
+//! \return ui8IndexTemp is the length of the DM PDU.
+//
+//*****************************************************************************
+uint8_t LLCP_sendDM(uint8_t * pui8PduBufferPtr,tDisconnectModeReason eDmReason)
+{
+ uint8_t ui8IndexTemp = 0;
+
+ // DSAP (6 bits) PTYPE (4 bits) SSAP (6 bits)
+ pui8PduBufferPtr[ui8IndexTemp++] = (g_ui8dsapValue << 2) |
+ ( (LLCP_DM_PDU & 0xFC) >> 2);
+ pui8PduBufferPtr[ui8IndexTemp++] = ( (LLCP_DM_PDU & 0x03) << 6) |
+ g_ui8ssapValue;
+
+ pui8PduBufferPtr[ui8IndexTemp++] = (uint8_t) eDmReason;
+
+ return ui8IndexTemp;
+}
+
+//*****************************************************************************
+//
+//! Send I message
+//!
+//! \param pui8PduBufferPtr is the start pointer to store the I PDU.
+//!
+//! This function adds a I PDU starting at pui8PduBufferPtr.For more details
+//! on this PDU read LLCP V1.1 Section 4.3.10.
+//!
+//! \return ui8IndexTemp is the length of the I PDU.
+//
+//*****************************************************************************
+uint8_t LLCP_sendI(uint8_t * pui8PduBufferPtr)
+{
+ uint8_t ui8IndexTemp = 0;
+ tSNEPConnectionStatus eSnepProtocolStatus;
+
+ // DSAP (6 bits) PTYPE (4 bits) SSAP (6 bits)
+ pui8PduBufferPtr[ui8IndexTemp++] = (g_ui8dsapValue << 2) | ( (LLCP_I_PDU & 0xFC) >> 2);
+ pui8PduBufferPtr[ui8IndexTemp++] = ( (LLCP_I_PDU & 0x03) << 6) | g_ui8ssapValue;
+
+ pui8PduBufferPtr[ui8IndexTemp++] = g_ui8NSNR;
+
+ g_ui8NSNR = (g_ui8NSNR & 0x0F) | (((g_ui8NSNR >> 4) + 0x01) << 4); // Increment N(S)
+
+ if(g_eLLCPConnectionStatus == LLCP_CONNECTION_ESTABLISHED)
+ {
+ g_eLLCPConnectionStatus = LLCP_CONNECTION_SENDING;
+ }
+ if(g_eCurrentServiceEnabled == SNEP_SERVICE)
+ {
+ if(g_eLLCPConnectionStatus == LLCP_CONNECTION_SENDING)
+ {
+ ui8IndexTemp = ui8IndexTemp +
+ SNEP_sendRequest(&pui8PduBufferPtr[ui8IndexTemp],SNEP_REQUEST_PUT);
+ }
+ else if(g_eLLCPConnectionStatus == LLCP_CONNECTION_RECEIVING)
+ {
+ eSnepProtocolStatus = SNEP_getProtocolStatus();
+ if(eSnepProtocolStatus == SNEP_CONNECTION_RECEIVED_FIRST_PACKET)
+ {
+ ui8IndexTemp = ui8IndexTemp +
+ SNEP_sendResponse(&pui8PduBufferPtr[ui8IndexTemp],
+ SNEP_RESPONSE_CONTINUE);
+ }
+ else if(eSnepProtocolStatus == SNEP_CONNECTION_RECEIVE_COMPLETE)
+ {
+ ui8IndexTemp = ui8IndexTemp +
+ SNEP_sendResponse(&pui8PduBufferPtr[ui8IndexTemp],
+ SNEP_RESPONSE_SUCCESS);
+ }
+ else if(eSnepProtocolStatus == SNEP_CONNECTION_EXCESS_SIZE)
+ {
+ ui8IndexTemp = ui8IndexTemp +
+ SNEP_sendResponse(&pui8PduBufferPtr[ui8IndexTemp],
+ SNEP_RESPONSE_REJECT);
+ }
+ }
+ }
+ else if(g_eCurrentServiceEnabled == NPP_SERVICE)
+ {
+ // RFU
+ }
+
+ return ui8IndexTemp;
+}
+
+//*****************************************************************************
+//
+//! Send RR message
+//!
+//! \param pui8PduBufferPtr is the start pointer to store the RR PDU.
+//!
+//! This function adds a RR PDU starting at pui8PduBufferPtr.For more details
+//! on this PDU read LLCP V1.1 Section 4.3.11.
+//!
+//! \return ui8IndexTemp is the length of the RR PDU.
+//
+//*****************************************************************************
+uint8_t LLCP_sendRR(uint8_t * pui8PduBufferPtr)
+{
+ uint8_t ui8IndexTemp = 0;
+
+ // DSAP (6 bits) PTYPE (4 bits) SSAP (6 bits)
+ pui8PduBufferPtr[ui8IndexTemp++] = (g_ui8dsapValue << 2) | \
+ ((LLCP_RR_PDU & 0xFC) >> 2);
+ pui8PduBufferPtr[ui8IndexTemp++] = ( (LLCP_RR_PDU & 0x03) << 6) | \
+ g_ui8ssapValue;
+
+ // Increment N(R)
+ g_ui8NSNR = (g_ui8NSNR & 0xF0) | ((g_ui8NSNR + 0x01) & 0x0F);
+
+ pui8PduBufferPtr[ui8IndexTemp++] = (g_ui8NSNR & 0x0F);
+
+ return ui8IndexTemp;
+}
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
diff --git a/nfclib/llcp.h b/nfclib/llcp.h
new file mode 100644
index 0000000..7e419e0
--- /dev/null
+++ b/nfclib/llcp.h
@@ -0,0 +1,248 @@
+//*****************************************************************************
+//
+// llcp.h - Logic Link Control Protocol header file
+//
+// Copyright (c) 2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
+//
+//*****************************************************************************
+#ifndef __NFC_LLCP_H__
+#define __NFC_LLCP_H__
+
+#include "types.h"
+
+//*****************************************************************************
+//
+//! \addtogroup nfc_llcp_api NFC LLCP API Functions
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// List of Commands
+//
+//*****************************************************************************
+
+//
+// ! LLCP Magic Number is constant 0x46666D
+//
+#define LLCP_MAGIC_NUMBER_HIGH 0x46
+#define LLCP_MAGIC_NUMBER_MIDDLE 0x66
+#define LLCP_MAGIC_NUMBER_LOW 0x6D
+
+//*****************************************************************************
+//
+// Service in local service Environment and is NOT advertised by local SDP
+//
+//*****************************************************************************
+
+//
+//! Source Service Access Point when sending
+//
+#define LLCP_SSAP_CONNECT_SEND 0x20
+
+//
+//! Source Service Access Point when receiving
+//
+#define LLCP_SSAP_CONNECT_RECEIVED 0x04
+
+//
+//! Destination Service Access Point for discovery
+//
+#define DSAP_SERVICE_DISCOVERY_PROTOCOL 0x01
+
+//
+//! The LLCP_MIU is the maximum information unit supported by the LLCP layer.
+//! This information unit may be included in each LLCP packet depending on the
+//! PDU type. The minimum must be 128.
+//
+#define LLCP_MIU 248
+
+//
+//! The LLCP_MIUX_SIZE is the value for the LLCP_MIUX TLV used in LLCP_addTLV().
+//
+#define LLCP_MIUX_SIZE (LLCP_MIU - 128)
+
+//*****************************************************************************
+//
+//! LLCP Parameter Enumerations.
+//
+//*****************************************************************************
+typedef enum
+{
+ //! See LLCP V1.1 Section 4.5.1
+ LLCP_VERSION = 0x01,
+ //! See LLCP V1.1 Section 4.5.2
+ LLCP_MIUX = 0x02,
+ //! See LLCP V1.1 Section 4.5.3
+ LLCP_WKS = 0x03,
+ //! See LLCP V1.1 Section 4.5.4
+ LLCP_LTO = 0x04,
+ //! See LLCP V1.1 Section 4.5.5
+ LLCP_RW = 0x05,
+ //! See LLCP V1.1 Section 4.5.6
+ LLCP_SN = 0x06,
+ //! See LLCP V1.1 Section 4.5.7
+ LLCP_OPT = 0x07,
+ //! See LLCP V1.1 Section 4.5.8
+ LLCP_SDREQ = 0x08,
+ //! See LLCP V1.1 Section 4.5.9
+ LLCP_SDRES = 0x09,
+ LLCP_ERROR
+}tLLCPParamaeter;
+
+//*****************************************************************************
+//
+//! PDU Type Enumerations.
+//
+//*****************************************************************************
+typedef enum
+{
+ //! See LLCP V1.1 Section 4.3.1
+ LLCP_SYMM_PDU = 0x00,
+ //! See LLCP V1.1 Section 4.3.2
+ LLCP_PAX_PDU= 0x01,
+ //! See LLCP V1.1 Section 4.3.3
+ LLCP_AGF_PDU= 0x02,
+ //! See LLCP V1.1 Section 4.3.4
+ LLCP_UI_PDU = 0x03,
+ //! See LLCP V1.1 Section 4.3.5
+ LLCP_CONNECT_PDU = 0x04,
+ //! See LLCP V1.1 Section 4.3.6
+ LLCP_DISC_PDU = 0x05,
+ //! See LLCP V1.1 Section 4.3.7
+ LLCP_CC_PDU = 0x06,
+ //! See LLCP V1.1 Section 4.3.8
+ LLCP_DM_PDU = 0x07,
+ //! See LLCP V1.1 Section 4.3.9
+ LLCP_FRMR_PDU = 0x08,
+ //! See LLCP V1.1 Section 4.3.10
+ LLCP_SNL_PDU = 0x09,
+ //! See LLCP V1.1 Section 4.3.11
+ LLCP_I_PDU = 0x0C,
+ //! See LLCP V1.1 Section 4.3.12
+ LLCP_RR_PDU = 0x0D,
+ //! See LLCP V1.1 Section 4.3.13
+ LLCP_RNR_PDU = 0x0E,
+ //! See LLCP V1.1 Section 4.3.14
+ LLCP_RESERVED_PDU = 0x0F
+}tLLCPPduPtype;
+
+//*****************************************************************************
+//
+//! LLCP Connection Status Enumeration.
+//
+//*****************************************************************************
+typedef enum
+{
+ //! No Tx/Rx ongoing.
+ LLCP_CONNECTION_IDLE = 0x00,
+
+ //! When a virtual link is created either when we send a CONNECT PDU and
+ //! receive a CC PDU, or when we receive a CONNECT PDU and respond a CC PDU.
+ LLCP_CONNECTION_ESTABLISHED,
+
+ //! When sending data via SNEP
+ LLCP_CONNECTION_SENDING,
+
+ //! When receiving data via SNEP
+ LLCP_CONNECTION_RECEIVING
+
+}tLLCPConnectionStatus;
+
+//*****************************************************************************
+//
+//! Service Name Enumerations - Only support SNEP_SERVICE
+//
+//*****************************************************************************
+typedef enum
+{
+ NPP_SERVICE = 0,
+ SNEP_SERVICE,
+ HANDOVER_SERVICE
+}tServiceName;
+
+
+//*****************************************************************************
+//
+//! Disconnected Mode Reasons Enumerations.
+//
+//*****************************************************************************
+typedef enum
+{
+ //! See LLCP Section 4.3.8.
+ DM_REASON_LLCP_RECEIVED_DISC_PDU = 0x00,
+
+ //! See LLCP Section 4.3.8.
+ DM_REASON_LLCP_RECEIVED_CONNECTION_ORIENTED_PDU = 0x01,
+
+ //! See LLCP Section 4.3.8.
+ DM_REASON_LLCP_RECEIVED_CONNECT_PDU_NO_SERVICE = 0x02,
+
+ //! See LLCP Section 4.3.8.
+ DM_REASON_LLCP_PROCESSED_CONNECT_PDU_REQ_REJECTED = 0x03,
+
+ //! See LLCP Section 4.3.8.
+ DM_REASON_LLCP_PERMNANTLY_NOT_ACCEPT_CONNECT_WITH_SAME_SSAP = 0x10,
+
+ //! See LLCP Section 4.3.8.
+ DM_REASON_LLCP_PERMNANTLY_NOT_ACCEPT_CONNECT_WITH_ANY_SSAP = 0x11,
+
+ //! See LLCP Section 4.3.8.
+ DM_REASON_LLCP_TEMMPORARILY_NOT_ACCEPT_PDU_WITH_SAME_SSSAPT = 0x20,
+
+ //! See LLCP Section 4.3.8.
+ DM_REASON_LLCP_TEMMPORARILY_NOT_ACCEPT_PDU_WITH_ANY_SSSAPT = 0x21
+}tDisconnectModeReason;
+
+
+
+//*****************************************************************************
+//
+// Function Prototypes
+//
+//*****************************************************************************
+void LLCP_init(void);
+
+uint8_t LLCP_stateMachine(uint8_t * pui8PduBufferPtr);
+
+tStatus LLCP_processReceivedData(uint8_t * pui8RxBuffer, uint8_t ui8PduLength);
+
+uint16_t LLCP_getLinkTimeOut(void);
+uint8_t LLCP_addTLV(tLLCPParamaeter eLLCPparam, uint8_t * pui8TLVBufferPtr);
+void LLCP_processTLV(uint8_t * pui8TLVBufferPtr);
+
+tStatus LLCP_setNextPDU(tLLCPPduPtype eNextPdu);
+void LLCP_setConnectionStatus(tLLCPConnectionStatus eConnectionState);
+
+uint8_t LLCP_sendSYMM(uint8_t * pui8PduBufferPtr);
+uint8_t LLCP_sendCONNECT(uint8_t * pui8PduBufferPtr);
+uint8_t LLCP_sendDISC(uint8_t * pui8PduBufferPtr);
+uint8_t LLCP_sendCC(uint8_t * pui8PduBufferPtr);
+uint8_t LLCP_sendDM(uint8_t * pui8PduBufferPtr,tDisconnectModeReason eDmReason);
+uint8_t LLCP_sendI(uint8_t * pui8PduBufferPtr);
+uint8_t LLCP_sendRR(uint8_t * pui8PduBufferPtr);
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
+
+#endif //__NFC_LLCP_H__
diff --git a/nfclib/nfc.c b/nfclib/nfc.c
new file mode 100644
index 0000000..30bc104
--- /dev/null
+++ b/nfclib/nfc.c
@@ -0,0 +1,241 @@
+//*****************************************************************************
+//
+// nfc.c - NFC implementation.
+//
+// Copyright (c) 2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
+//
+//*****************************************************************************
+
+#include <string.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include "inc/hw_types.h"
+#include "driverlib/sysctl.h"
+#include "trf79x0.h"
+#include "iso14443b.h"
+
+unsigned char g_ucNFCID[11] = "\x80\x12\x34\x56"; //NFC ID (PUPI = 80123456)
+
+//*****************************************************************************
+//
+// Set up registers for ISO 14443 B 106Kbit/s operation. This function must
+// be called after initializing the TRF79x0 (for example with TRF79x0Init()
+// or TRF79x0DirectCommand() with argument \b TRF79X0_SOFT_INIT_CMD) and before
+// calling any of the other ISO14443B functions.
+//
+//*****************************************************************************
+void
+NfcTagType4BSetupRegisters(void)
+{
+ TRF79x0DirectCommand(TRF79X0_SOFT_INIT_CMD);
+ TRF79x0DirectCommand(TRF79X0_IDLE_CMD);
+
+ //
+ // TODO:check why have to set as this?
+ //
+ TRF79x0WriteRegister(TRF79X0_MODULATOR_CONTROL_REG,
+ TRF79X0_MOD_CTRL_MOD_OOK_100);
+
+ //
+ // Set the ISO format to NFC Card Emulation, Type B
+ //
+ TRF79x0WriteRegister(TRF79X0_ISO_CONTROL_REG, 0x25);
+
+ //
+ // Set the regulator voltage to be automatic.
+ //
+ TRF79x0WriteRegister(TRF79X0_REGULATOR_CONTROL_REG,
+ TRF79X0_REGULATOR_CTRL_VRS_2_8V);
+
+ //
+ // RX Special Settings for ISO14443B
+ //
+ TRF79x0WriteRegister(TRF79X0_RX_SPECIAL_SETTINGS_REG, 0x3C);
+
+ //
+ // Set the Target Detection Level to Max; use SDD
+ //
+// TRF79x0WriteRegister(TRF79X0_NFC_TARGET_LEVEL_REG, 0x27);
+ TRF79x0WriteRegister(TRF79X0_NFC_TARGET_LEVEL_REG, 0x07);
+
+ //
+ // Set the NFCID to be sent during SDD
+ //
+ TRF79x0WriteRegisterContinuous(TRF79X0_NFC_ID_REG, g_ucNFCID, 4);
+
+ TRF79x0WriteRegister(TRF79X0_NFC_LO_FIELD_LEVEL_REG, 0x03);
+
+ //
+ // ISO14443B TX Options
+ //
+ TRF79x0WriteRegister(TRF79X0_ISO14443B_OPTIONS_REG, 0x00);
+
+ TRF79x0WriteRegister(TRF79X0_CHIP_STATUS_CTRL_REG, 0x21);
+
+ TRF79x0ResetFifoCommand();
+ TRF79x0DirectCommand(TRF79X0_STOP_DECODERS_CMD);
+ TRF79x0DirectCommand(TRF79X0_RUN_DECODERS_CMD);
+}
+
+//*****************************************************************************
+//
+// Set up registers for ISO 14443 A 106Kbit/s operation. This function must
+// be called after initializing the TRF79x0 (for example with TRF79x0Init()
+// or TRF79x0DirectCommand() with argument \b TRF79X0_SOFT_INIT_CMD) and before
+// calling any of the other ISO14443B functions.
+//
+//*****************************************************************************
+void
+NfcTagType4ASetupRegisters(void)
+{
+ unsigned char Data[11] = "\x08\x12\x34\x56";
+
+ //Examples of start byte of Type A UID Values and MFGs seen by Nexus S.
+ //These are just a few found by using the TagInfo app
+ //0x01, 0x05, 0x07, 0x09, 0x19 = Infineon
+ //0x02, 0x03, 0x04, 0x06, 0x0A = NXP
+ //0x08 = Unknown, considered to be for random ID
+ //0x1C, 0xC2, 0x3E, 0x80 = NXP
+
+ TRF79x0DirectCommand(TRF79X0_SOFT_INIT_CMD);
+ TRF79x0DirectCommand(TRF79X0_IDLE_CMD);
+
+ //
+ // TODO:check why have to set as this?
+ //
+ TRF79x0WriteRegister(TRF79X0_MODULATOR_CONTROL_REG,
+ TRF79X0_MOD_CTRL_MOD_OOK_100);
+
+ //
+ // Set the ISO format to NFC Card Emulation, Type A
+ //
+ TRF79x0WriteRegister(TRF79X0_ISO_CONTROL_REG, 0x24);
+
+ //
+ // Set the regulator voltage to be automatic.
+ //
+ TRF79x0WriteRegister(TRF79X0_REGULATOR_CONTROL_REG,
+ TRF79X0_REGULATOR_CTRL_AUTO_REG);
+
+ //
+ // RX Special Settings for ISO14443A
+ //
+ TRF79x0WriteRegister(TRF79X0_RX_SPECIAL_SETTINGS_REG, 0x30);
+
+ //
+ // Set the Target Detection Level to Max; use SDD
+ //
+ TRF79x0WriteRegister(TRF79X0_NFC_TARGET_LEVEL_REG, 0x27);
+
+ //
+ // Set the NFCID to be sent during SDD
+ //
+ TRF79x0WriteRegisterContinuous(TRF79X0_NFC_ID_REG, Data, 4);
+
+ TRF79x0WriteRegister(TRF79X0_NFC_LO_FIELD_LEVEL_REG, 0x83);
+
+ // SDD need this
+ TRF79x0WriteRegister(TRF79X0_ISO14443B_OPTIONS_REG, 0x01);
+
+ //
+ // ISO14443B TX Options
+ //
+// TRF79x0WriteRegister(TRF79X0_ISO14443B_OPTIONS_REG, 0x01);
+ TRF79x0WriteRegister(TRF79X0_ISO14443A_OPTIONS_REG, 0x00);
+
+// //
+// // Set the TX pulse to 106ns (0x20 * 73.7ns).
+// //
+// TRF79x0WriteRegister(TRF79X0_TX_PULSE_LENGTH_CTRL_REG, 0x20);
+//
+// //
+// // Set the RX No response wait time to 529us (0xe * 37.76us).
+// //
+// TRF79x0WriteRegister(TRF79X0_RX_NO_RESPONSE_WAIT_REG, 0x0e);
+//
+// //
+// // Set the RX wait time to 66us (7 * 9.44us).
+// //
+// TRF79x0WriteRegister(TRF79X0_RX_WAIT_TIME_REG, 0x07);
+ TRF79x0WriteRegister(TRF79X0_TEST_SETTING1_REG, 0x40);
+
+ TRF79x0WriteRegister(TRF79X0_CHIP_STATUS_CTRL_REG, 0x21);
+
+ TRF79x0ResetFifoCommand();
+ TRF79x0DirectCommand(TRF79X0_STOP_DECODERS_CMD);
+ TRF79x0DirectCommand(TRF79X0_RUN_DECODERS_CMD);
+
+ //
+ // Delay 5ms before initializing the TRF79x0.
+ //
+ SysCtlDelay((SysCtlClockGet()/3000) * 2);
+}
+
+//*****************************************************************************
+//
+//
+//
+//*****************************************************************************
+int
+ISO14443BATQB(unsigned char *pucPUPI,unsigned char ucAFI, unsigned char ucBitRate,
+ unsigned char ucMaxFrameSize, unsigned char ucProtocolType,
+ unsigned char ucFWI, unsigned char ucADC, unsigned char ucFO)
+{
+ unsigned char pucATQB[12];
+
+//
+// // Protocol Info Bytes
+// buffer[10] = 0x80; // Date Rate Capability ( Only Support 106 kbps)
+// // Max Frame/Protocol type (128 bytes / PICC compliant to -4)
+// buffer[11] = 0x71;
+// // (FWI/ADC/FO) ( FWT = 77.3mSec, ADC = coded according to AFI, CID supported)
+// buffer[12] = 0x85;
+
+ //
+ // ATQB response.
+ //
+ pucATQB[0] = 0x50;
+ pucATQB[1] = pucPUPI[0];
+ pucATQB[2] = pucPUPI[1];
+ pucATQB[3] = pucPUPI[2];
+ pucATQB[4] = pucPUPI[3];
+ pucATQB[5] = ucAFI;
+ pucATQB[6] = 0xE2; // CRC_B
+ pucATQB[7] = 0xAF; // CRC_B
+ pucATQB[8] = 0x11; // # of applications (1)
+ pucATQB[9] = ucBitRate;
+ pucATQB[10] = (ucMaxFrameSize << 4) | ucProtocolType;
+ pucATQB[11] = (ucFWI << 4) | (ucADC << 2) | ucFO;
+
+ //
+ // Transmit w/o receive
+ //
+ TRF79x0Transceive(pucATQB, sizeof(pucATQB), 0, 0, 0, 0, TRF79X0_TRANSCEIVE_TX_CRC);
+
+ //
+ // Return true
+ //
+ return(1);
+}
+
+//*****************************************************************************
+//
+// NFC P2P Functions
+//
+//*****************************************************************************
diff --git a/nfclib/nfc.h b/nfclib/nfc.h
new file mode 100644
index 0000000..6f349ce
--- /dev/null
+++ b/nfclib/nfc.h
@@ -0,0 +1,42 @@
+//*****************************************************************************
+//
+// nfc.h - NFC implementation.
+//
+// Copyright (c) 2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
+//
+//*****************************************************************************
+
+#ifndef __NFC_H__
+#define __NFC_H__
+
+//*****************************************************************************
+//
+// General NFC Function Prototypes
+//
+//*****************************************************************************
+extern unsigned char g_ucNFCID[4];
+
+extern void NfcTagType4BSetupRegisters(void);
+extern void NfcTagType4ASetupRegisters(void);
+extern int ISO14443BATQB(unsigned char *pucPUPI,unsigned char ucAFI,
+ unsigned char ucBitRate,unsigned char ucMaxFrameSize,
+ unsigned char ucProtocolType,unsigned char ucFWI,
+ unsigned char ucADC, unsigned char ucFO);
+
+#endif //__NFC_H__
diff --git a/nfclib/nfc_dep.c b/nfclib/nfc_dep.c
new file mode 100644
index 0000000..3c30910
--- /dev/null
+++ b/nfclib/nfc_dep.c
@@ -0,0 +1,597 @@
+//*****************************************************************************
+//
+// nfc_dep.c - used to send packets of P2P
+//
+// Copyright (c) 2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
+//
+//*****************************************************************************
+#include <stdbool.h>
+#include <stdint.h>
+#include <string.h>
+#include "nfclib/nfc_dep.h"
+#include "nfclib/llcp.h"
+#include "nfclib/trf79x0.h"
+
+//*****************************************************************************
+//
+// Globals
+//
+//*****************************************************************************
+
+uint8_t g_pui8NFCID3t[10] = {0x01, 0xFE, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09};
+
+uint8_t g_ui8NfcDepPni = 0x00;
+
+uint8_t g_ui8RtoxTransportData;
+
+tPDUBlock tNextPduType = INFORMATION_PDU;
+
+uint8_t * g_pui8DEPBufferPtr;
+
+//*****************************************************************************
+//
+// NFCDEP_SendATR_REQ -
+//
+//*****************************************************************************
+void NFCDEP_SendATR_REQ(uint8_t * pui8NFCID2_Ptr)
+{
+ uint8_t ui8Counter = 0;
+ uint8_t ui8Offset = 0;
+
+ //
+ // Length
+ //
+ g_pui8DEPBufferPtr[0] = 0x25;
+
+ //
+ // Command
+ //
+ g_pui8DEPBufferPtr[1] = (uint8_t) ((ATR_REQ_CMD & 0xFF00) >> 8);
+ g_pui8DEPBufferPtr[2] = (uint8_t) (ATR_REQ_CMD & 0x00FF);
+
+ //
+ // NFCID3i
+ //
+ for(ui8Counter=0;ui8Counter<8;ui8Counter++)
+ {
+ g_pui8DEPBufferPtr[3+ui8Counter] = pui8NFCID2_Ptr[ui8Counter];
+ }
+ g_pui8DEPBufferPtr[11] = 0x00;
+ g_pui8DEPBufferPtr[12] = 0x00;
+
+ g_pui8DEPBufferPtr[13] = DIDi;
+ g_pui8DEPBufferPtr[14] = BSi;
+ g_pui8DEPBufferPtr[15] = BRi;
+ g_pui8DEPBufferPtr[16] = PPi; // Max Payload 64 bytes
+
+ //
+ // LLCP Magic Number
+ //
+ g_pui8DEPBufferPtr[17] = LLCP_MAGIC_NUMBER_HIGH;
+ g_pui8DEPBufferPtr[18] = LLCP_MAGIC_NUMBER_MIDDLE;
+ g_pui8DEPBufferPtr[19] = LLCP_MAGIC_NUMBER_LOW;
+
+ ui8Offset = 20;
+ ui8Offset = ui8Offset + LLCP_addTLV(LLCP_VERSION,
+ &g_pui8DEPBufferPtr[ui8Offset]);
+ ui8Offset = ui8Offset + LLCP_addTLV(LLCP_MIUX,&g_pui8DEPBufferPtr[ui8Offset]);
+ ui8Offset = ui8Offset + LLCP_addTLV(LLCP_WKS,&g_pui8DEPBufferPtr[ui8Offset]);
+ ui8Offset = ui8Offset + LLCP_addTLV(LLCP_LTO,&g_pui8DEPBufferPtr[ui8Offset]);
+ ui8Offset = ui8Offset + LLCP_addTLV(LLCP_OPT,&g_pui8DEPBufferPtr[ui8Offset]);
+
+ TRF79x0WriteFIFO(g_pui8DEPBufferPtr,CRC_BIT_ENABLE,ui8Offset);
+}
+
+//*****************************************************************************
+//
+// NFCDEP_SendPSL_REQ -
+//
+//*****************************************************************************
+void NFCDEP_SendPSL_REQ(void)
+{
+ uint8_t ui8Offset = 1;
+
+ //
+ // Command
+ //
+ g_pui8DEPBufferPtr[ui8Offset++] = (uint8_t) ((PSL_REQ_CMD & 0xFF00) >> 8);
+ g_pui8DEPBufferPtr[ui8Offset++] = (uint8_t) (PSL_REQ_CMD & 0x00FF);
+
+ //
+ // DID
+ //
+ g_pui8DEPBufferPtr[ui8Offset++] = 0x00;
+
+ //
+ // BRS -
+ // B5 B4 B3 (DSI) Initiator to Target
+ // B2 B1 B0 (DRI) Target to Initiator
+ // 0 0 0 106kbaud
+ // 0 0 1 212kbaud
+ // 0 1 0 424kbaud (default)
+ // 0 1 1 848kbaud
+ //
+ g_pui8DEPBufferPtr[ui8Offset++] = 0x12;
+
+ //
+ // FSL
+ // B1-B0 Max Payload Size (11b: Max payload size is 254 bytes)
+ //
+ g_pui8DEPBufferPtr[ui8Offset++] = 0x03;
+
+ //
+ // Length
+ //
+ g_pui8DEPBufferPtr[0] = ui8Offset;
+
+ TRF79x0WriteFIFO(g_pui8DEPBufferPtr,CRC_BIT_ENABLE,ui8Offset);
+}
+
+//*****************************************************************************
+//
+// NFCDEP_SendATR_RES -
+//
+//*****************************************************************************
+void NFCDEP_SendATR_RES(void)
+{
+ uint8_t ui8Counter = 0;
+ uint8_t ui8Offset = 1;
+
+ //
+ // Command
+ //
+ g_pui8DEPBufferPtr[ui8Offset++] = (uint8_t) ((ATR_RES_CMD & 0xFF00) >> 8);
+ g_pui8DEPBufferPtr[ui8Offset++] = (uint8_t) (ATR_RES_CMD & 0x00FF);
+
+ //
+ // NFCID3t
+ //
+ for(ui8Counter=0;ui8Counter<10;ui8Counter++)
+ {
+ g_pui8DEPBufferPtr[ui8Offset++] = g_pui8NFCID3t[ui8Counter];
+ }
+
+ g_pui8DEPBufferPtr[ui8Offset++] = DIDt;
+ g_pui8DEPBufferPtr[ui8Offset++] = BSt;
+ g_pui8DEPBufferPtr[ui8Offset++] = BRt;
+ g_pui8DEPBufferPtr[ui8Offset++] = TO;
+ g_pui8DEPBufferPtr[ui8Offset++] = PPt; // Max Payload 64 bytes
+
+ //
+ // LLCP Magic Number
+ //
+ g_pui8DEPBufferPtr[ui8Offset++] = LLCP_MAGIC_NUMBER_HIGH;
+ g_pui8DEPBufferPtr[ui8Offset++] = LLCP_MAGIC_NUMBER_MIDDLE;
+ g_pui8DEPBufferPtr[ui8Offset++] = LLCP_MAGIC_NUMBER_LOW;
+
+ ui8Offset = ui8Offset + LLCP_addTLV(LLCP_VERSION,
+ &g_pui8DEPBufferPtr[ui8Offset]);
+ ui8Offset = ui8Offset + LLCP_addTLV(LLCP_MIUX,&g_pui8DEPBufferPtr[ui8Offset]);
+ ui8Offset = ui8Offset + LLCP_addTLV(LLCP_WKS,&g_pui8DEPBufferPtr[ui8Offset]);
+ ui8Offset = ui8Offset + LLCP_addTLV(LLCP_LTO,&g_pui8DEPBufferPtr[ui8Offset]);
+ ui8Offset = ui8Offset + LLCP_addTLV(LLCP_OPT,&g_pui8DEPBufferPtr[ui8Offset]);
+
+ //
+ // Length
+ //
+ g_pui8DEPBufferPtr[0] = ui8Offset;
+
+ TRF79x0WriteFIFO(g_pui8DEPBufferPtr,CRC_BIT_ENABLE,ui8Offset);
+}
+
+//*****************************************************************************
+//
+// NFCDEP_SendRSL_RES -
+//
+//*****************************************************************************
+void NFCDEP_SendRSL_RES(void)
+{
+ uint8_t ui8Offset = 1;
+
+ //
+ // Command
+ //
+ g_pui8DEPBufferPtr[ui8Offset++] = (uint8_t) ((RSL_RES_CMD & 0xFF00) >> 8);
+ g_pui8DEPBufferPtr[ui8Offset++] = (uint8_t) (RSL_RES_CMD & 0x00FF);
+
+ //
+ // Length
+ //
+ g_pui8DEPBufferPtr[0] = ui8Offset;
+
+ TRF79x0WriteFIFO(g_pui8DEPBufferPtr,CRC_BIT_ENABLE,ui8Offset);
+}
+
+//*****************************************************************************
+//
+// NFCDEP_SendPSL_RES -
+//
+//*****************************************************************************
+void NFCDEP_SendPSL_RES(uint8_t did_value)
+{
+ uint8_t ui8Offset = 1;
+
+ //
+ // Command
+ //
+ g_pui8DEPBufferPtr[ui8Offset++] = (uint8_t) ((PSL_RES_CMD & 0xFF00) >> 8);
+ g_pui8DEPBufferPtr[ui8Offset++] = (uint8_t) (PSL_RES_CMD & 0x00FF);
+
+ g_pui8DEPBufferPtr[ui8Offset++] = 0x00;
+
+ //
+ // Length
+ //
+ g_pui8DEPBufferPtr[0] = ui8Offset;
+
+ TRF79x0WriteFIFO(g_pui8DEPBufferPtr,CRC_BIT_ENABLE,ui8Offset);
+}
+
+//*****************************************************************************
+//
+// NFCDEP_ProcessReceivedRequest -
+//
+//*****************************************************************************
+tStatus NFCDEP_ProcessReceivedRequest(uint8_t * pui8RxBuffer , \
+ uint8_t * pui8NFCID2_Ptr,
+ bool bActiveResponse)
+{
+ volatile uint8_t ui8CommandLength;
+ uint16_t ui16Command;
+ tStatus eNfcDepStatus = STATUS_SUCCESS;
+ uint8_t ui8PFBValue;
+ uint8_t ui8Counter;
+
+ ui8CommandLength = pui8RxBuffer[0];
+ ui16Command = pui8RxBuffer[2] + (pui8RxBuffer[1] << 8);
+
+ ui8PFBValue = pui8RxBuffer[3];
+
+ // Check if chaining is enabled
+ if((ui8PFBValue & 0xF0) == 0x00)
+ {
+ tNextPduType = INFORMATION_PDU;
+ }
+ else if((ui8PFBValue & 0xF0) == 0x10)
+ {
+ tNextPduType = ACK_PDU;
+ }
+ else if((ui8PFBValue & 0xF0) == 0x90)
+ {
+ tNextPduType = RTOX_REQ_PDU;
+ }
+ else if((ui8PFBValue & 0xF0) == 0x80)
+ {
+ tNextPduType = ATN_PDU;
+ }
+
+
+ if(ui16Command == ATR_REQ_CMD)
+ {
+ if((pui8NFCID2_Ptr[0] == pui8RxBuffer[3] && \
+ pui8NFCID2_Ptr[1] == pui8RxBuffer[4] && \
+ pui8NFCID2_Ptr[2] == pui8RxBuffer[5] && \
+ pui8NFCID2_Ptr[3] == pui8RxBuffer[6] && \
+ pui8NFCID2_Ptr[4] == pui8RxBuffer[7] && \
+ pui8NFCID2_Ptr[5] == pui8RxBuffer[8] && \
+ pui8NFCID2_Ptr[6] == pui8RxBuffer[9] && \
+ pui8NFCID2_Ptr[7] == pui8RxBuffer[10]) || bActiveResponse == true)
+ {
+ ui8Counter = 0;
+ while(ui8CommandLength > (ui8Counter+20))
+ {
+ //
+ // Process the TLV - pass the starting address of the TLV
+ //
+ LLCP_processTLV(&pui8RxBuffer[ui8Counter+20]);
+
+ //
+ // Increment ui8Counter by the length+ 2 (type and length) of
+ // the current TLV
+ //
+ ui8Counter = ui8Counter+ pui8RxBuffer[ui8Counter+21] + 2;
+ }
+ NFCDEP_SendATR_RES();
+ // Reset the PNI
+ g_ui8NfcDepPni = 0x00;
+ //UARTprintf("CMD : D400\n");
+ }
+ else
+ eNfcDepStatus = STATUS_FAIL;
+ }
+ else if(ui16Command == PSL_REQ_CMD)
+ {
+ // Check if the DSI (Bits 5-3) == 010b => 424kbaud (Init. to Target)
+ // if the DRI (2-0) == 010b => 424kbaud (Target to Initiator)
+ if(((pui8RxBuffer[4] & 0x38) == 0x10) && \
+ ((pui8RxBuffer[4] & 0x07) == 0x02))
+ {
+ NFCDEP_SendPSL_RES(pui8RxBuffer[3]);
+ TRF79x0SetMode(P2P_PASSIVE_TARGET_MODE,FREQ_424_KBPS);
+ }
+
+ }
+ else if(ui16Command == DEP_REQ_CMD)
+ {
+ //
+ // LLCP Packet Handler
+ //
+ if(tNextPduType == INFORMATION_PDU)
+ {
+ LLCP_processReceivedData(&pui8RxBuffer[4], (ui8CommandLength-4));
+ }
+
+ NFCDEP_SendDEP_RES();
+ }
+ else if(ui16Command == DSL_REQ_CMD)
+ {
+ //
+ // Debug
+ //
+ while(1);
+ }
+ else if(ui16Command == RSL_REQ_CMD)
+ {
+ //UARTprintf("CMD : D40A\n");
+ if(ui8CommandLength == 0x03)
+ NFCDEP_SendRSL_RES();
+ }
+ else
+ {
+ eNfcDepStatus = STATUS_FAIL;
+
+ }
+ return eNfcDepStatus;
+}
+
+//*****************************************************************************
+//
+// NFCDEP_ProcessReceivedData -
+//
+//*****************************************************************************
+tStatus NFCDEP_ProcessReceivedData(uint8_t * pui8RxBuffer)
+{
+ volatile uint8_t ui8CommandLength;
+ uint16_t ui16Command;
+ uint8_t ui8Counter;
+ tStatus eNfcDepStatus = STATUS_SUCCESS;
+ uint8_t ui8PFBValue;
+
+ ui8CommandLength = pui8RxBuffer[0];
+ ui16Command = pui8RxBuffer[2] + (pui8RxBuffer[1] << 8);
+
+ if(ui16Command == ATR_RES_CMD)
+ {
+ //
+ // Store the g_pui8NFCID3t
+ //
+ for(ui8Counter = 0; ui8Counter < 10; ui8Counter++)
+ {
+ g_pui8NFCID3t[ui8Counter] = pui8RxBuffer[3+ui8Counter];
+ }
+ //
+ // LLCP Decoding - RFU
+ //
+ if(pui8RxBuffer[18] == LLCP_MAGIC_NUMBER_HIGH && \
+ pui8RxBuffer[19] == LLCP_MAGIC_NUMBER_MIDDLE && \
+ pui8RxBuffer[20] == LLCP_MAGIC_NUMBER_LOW)
+ {
+ ui8Counter = 0;
+ while(ui8CommandLength > (ui8Counter+21))
+ {
+ //
+ // Process the TLV - pass the starting address of the TLV
+ //
+ LLCP_processTLV(&pui8RxBuffer[ui8Counter+21]);
+
+ //
+ // Increment ui8Counter by the length+ 2 (type and length) of
+ // the current TLV
+ //
+ ui8Counter = ui8Counter+ pui8RxBuffer[ui8Counter+22] + 2;
+ }
+ //
+ // Set the next PDU for LLCP - SYMM PDU
+ //
+ LLCP_setNextPDU(LLCP_SYMM_PDU);
+
+ //
+ // Reset the PNI
+ //
+ g_ui8NfcDepPni = 0x00;
+ tNextPduType = INFORMATION_PDU;
+ }
+ else
+ {
+ eNfcDepStatus = STATUS_FAIL;
+ }
+ }
+ else if(ui16Command == PSL_RES_CMD)
+ {
+ //
+ // Check if DID is correct
+ //
+ if(pui8RxBuffer[3] != 0x00)
+ eNfcDepStatus = STATUS_FAIL;
+
+ }
+ else if(ui16Command == DEP_RES_CMD)
+ {
+ ui8PFBValue = pui8RxBuffer[3];
+
+ if((ui8PFBValue & 0xF0) == 0x00)
+ {
+ tNextPduType = INFORMATION_PDU;
+ }
+ else if((ui8PFBValue & 0xF0) == 0x10)
+ {
+ //
+ // Check if chaining is enabled
+ //
+ tNextPduType = ACK_PDU;
+ }
+ else if((ui8PFBValue & 0xF0) == 0x90)
+ {
+ tNextPduType = RTOX_REQ_PDU;
+ g_ui8RtoxTransportData = (0x3F & pui8RxBuffer[4]);
+ }
+
+ if(tNextPduType == INFORMATION_PDU)
+ //
+ // LLCP Packet Handler
+ //
+ eNfcDepStatus = LLCP_processReceivedData(&pui8RxBuffer[4],
+ (ui8CommandLength-4));
+
+ }
+ else if(ui16Command == DSL_RES_CMD)
+ {
+
+ }
+ else if(ui16Command == RSL_RES_CMD)
+ {
+
+ }
+ else
+ {
+ eNfcDepStatus = STATUS_FAIL;
+ }
+
+ return eNfcDepStatus;
+}
+
+//*****************************************************************************
+//
+// NFCDEP_SendDEP_REQ - Send DEP_REQ to TRF79x0
+//
+//*****************************************************************************
+void NFCDEP_SendDEP_REQ(uint8_t * pui8RxBuffer)
+{
+ uint8_t ui8TotalLength = 0;
+
+ if(tNextPduType == INFORMATION_PDU)
+ {
+ //
+ // Total = 1 byte Length + 2 bytes Command + 1 byte PFB + n PDU
+ //
+ ui8TotalLength = 4 + LLCP_stateMachine(&g_pui8DEPBufferPtr[4]);
+
+ //
+ // PFB Byte
+ //
+ g_pui8DEPBufferPtr[3] = ((tNextPduType | (g_ui8NfcDepPni++)) & 0x03);
+ }
+ else if(tNextPduType == RTOX_REQ_PDU)
+ {
+ //
+ // PFB Byte
+ //
+ g_pui8DEPBufferPtr[3] = (tNextPduType);
+
+ g_pui8DEPBufferPtr[4] = g_ui8RtoxTransportData;
+ ui8TotalLength = 5;
+ }
+ else if(tNextPduType == ACK_PDU)
+ {
+ //
+ // PFB Byte
+ //
+ g_pui8DEPBufferPtr[3] = ((tNextPduType | (g_ui8NfcDepPni++)) & 0x03);
+
+ ui8TotalLength = 4;
+ }
+
+ //
+ // Length
+ //
+ g_pui8DEPBufferPtr[0] = ui8TotalLength;
+
+ //
+ // Command
+ //
+ g_pui8DEPBufferPtr[1] = (uint8_t) ((DEP_REQ_CMD & 0xFF00) >> 8);
+ g_pui8DEPBufferPtr[2] = (uint8_t) (DEP_REQ_CMD & 0x00FF);
+
+ TRF79x0WriteFIFO(g_pui8DEPBufferPtr,CRC_BIT_ENABLE,ui8TotalLength);
+
+ if(tNextPduType == RTOX_REQ_PDU)
+ if(TRF79x0IRQHandler(((2<<g_ui8RtoxTransportData)/3)) ==
+ IRQ_STATUS_RX_COMPLETE)
+ {
+ NFCDEP_ProcessReceivedData(pui8RxBuffer);
+ NFCDEP_SendDEP_REQ(pui8RxBuffer);
+ }
+}
+
+//*****************************************************************************
+//
+// NFCDEP_SendDEP_RES -Send DEP_RES to TRF79x0
+//
+//*****************************************************************************
+void NFCDEP_SendDEP_RES(void)
+{
+ uint8_t ui8TotalLength = 0;
+
+ if(tNextPduType == INFORMATION_PDU)
+ {
+ //
+ // PFB Byte
+ //
+ g_pui8DEPBufferPtr[3] = ((tNextPduType | (g_ui8NfcDepPni++)) & 0x03);
+
+ //
+ // Total = 1 byte Length + 2 bytes Command + 1 byte PFB + n PDU
+ //
+ ui8TotalLength = 4 + LLCP_stateMachine(&g_pui8DEPBufferPtr[4]);
+ }
+ else if(tNextPduType == ATN_PDU)
+ {
+ //
+ // PFB Byte
+ //
+ g_pui8DEPBufferPtr[3] = (tNextPduType);
+
+ ui8TotalLength = 4;
+ }
+
+ //
+ // Length
+ //
+ g_pui8DEPBufferPtr[0] = ui8TotalLength;
+
+ //
+ // Command
+ //
+ g_pui8DEPBufferPtr[1] = (uint8_t) ((DEP_RES_CMD & 0xFF00) >> 8);
+ g_pui8DEPBufferPtr[2] = (uint8_t) (DEP_RES_CMD & 0x00FF);
+
+ TRF79x0WriteFIFO(g_pui8DEPBufferPtr,CRC_BIT_ENABLE,ui8TotalLength);
+}
+
+//*****************************************************************************
+//
+// NFCDEP_SetBufferPtr - set global buffer pointer to input pointer value
+//
+//*****************************************************************************
+void NFCDEP_SetBufferPtr(uint8_t * buffer_ptr)
+{
+ g_pui8DEPBufferPtr = buffer_ptr;
+}
+
diff --git a/nfclib/nfc_dep.h b/nfclib/nfc_dep.h
new file mode 100644
index 0000000..4581ebe
--- /dev/null
+++ b/nfclib/nfc_dep.h
@@ -0,0 +1,109 @@
+//*****************************************************************************
+//
+// nfc_dep.h - Defines for sending packets of P2P
+//
+// Copyright (c) 2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
+//
+//*****************************************************************************
+#ifndef __NFC_DEP_H__
+#define __NFC_DEP_H__
+#include "types.h"
+
+//*****************************************************************************
+//
+// List of Commands
+//
+//*****************************************************************************
+// REQUESTS //
+#define ATR_REQ_CMD 0xD400
+#define PSL_REQ_CMD 0xD404
+#define DEP_REQ_CMD 0xD406
+#define DSL_REQ_CMD 0xD408
+#define RSL_REQ_CMD 0xD40A
+
+// RESPONSES //
+#define ATR_RES_CMD 0xD501
+#define PSL_RES_CMD 0xD505
+#define DEP_RES_CMD 0xD507
+#define DSL_RES_CMD 0xD509
+#define RSL_RES_CMD 0xD50B
+
+
+#define DIDi 0x00
+#define BSi 0x00
+#define BRi 0x00
+//*****************************************************************************
+//
+// Initiator Maximum payload size + General bytes available (BIT1)
+// B6 B5 - '00' Max Payload 64 bytes
+// B6 B5 - '01' Max Payload 128 bytes
+// B6 B5 - '10' Max Payload 192 bytes
+// B6 B5 - '11' Max Payload 254 bytes (default)
+//
+//*****************************************************************************
+#define PPi 0x32
+
+#define DIDt 0x00
+#define BSt 0x00
+#define BRt 0x00
+#define TO 0x07
+//*****************************************************************************
+//
+// Target Maximum payload size + General bytes available (BIT1)
+// B6 B5 - '00' Max Payload 64 bytes
+// B6 B5 - '01' Max Payload 128 bytes
+// B6 B5 - '10' Max Payload 192 bytes
+// B6 B5 - '11' Max Payload 254 bytes (default)
+//
+//*****************************************************************************
+#define PPt 0x32
+
+//*****************************************************************************
+//
+//
+//
+//*****************************************************************************
+typedef enum
+{
+ ACK_PDU = 0x40,
+ INFORMATION_PDU = 0x00,
+ NACK_PDU = 0x50,
+ ATN_PDU = 0x80,
+ RTOX_REQ_PDU = 0x90,
+
+}tPDUBlock;
+
+//*****************************************************************************
+//
+// Function Prototypes
+//
+//*****************************************************************************
+void NFCDEP_SendATR_REQ(uint8_t * pui8NFCID2_Ptr);
+void NFCDEP_SendPSL_REQ(void);
+void NFCDEP_SendATR_RES(void);
+void NFCDEP_SendRSL_RES(void);
+void NFCDEP_SendPSL_RES(uint8_t did_value);
+
+tStatus NFCDEP_ProcessReceivedRequest(uint8_t * rx_buffer ,uint8_t * pui8NFCID2_Ptr, bool bActiveResponse);
+tStatus NFCDEP_ProcessReceivedData(uint8_t * rx_buffer);
+void NFCDEP_SendDEP_REQ(uint8_t * rx_buffer);
+void NFCDEP_SendDEP_RES(void);
+void NFCDEP_SetBufferPtr(uint8_t * buffer_ptr);
+
+#endif //__NFC_DEP_H__
diff --git a/nfclib/nfc_f.c b/nfclib/nfc_f.c
new file mode 100644
index 0000000..c27ef22
--- /dev/null
+++ b/nfclib/nfc_f.c
@@ -0,0 +1,166 @@
+//*****************************************************************************
+//
+// nfc_f.c - contains implementation of NFC Type F (Felica) protocol
+//
+// Copyright (c) 2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
+//
+//*****************************************************************************
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "nfclib/nfc_f.h"
+#include "nfclib/trf79x0.h"
+
+//*****************************************************************************
+//
+// NFC ID for TYPE F cards
+//
+//*****************************************************************************
+uint8_t g_ui8NFCID2[8] = {0x01 , 0xFE, 0x88 , 0x77, 0x66 , 0x55, 0x44 , 0x33};
+
+//*****************************************************************************
+//
+// Pointer to buffer
+//
+//*****************************************************************************
+uint8_t * g_pui8NFC_F_BufferPtr;
+
+//*****************************************************************************
+//
+// Sens SENSF_REQ (request)
+//
+//*****************************************************************************
+void NFCTypeF_SendSENSF_REQ(void)
+{
+ uint8_t ui8NFC_F_Packet[6];
+ //
+ // Length
+ //
+ ui8NFC_F_Packet[0] = 0x06;
+ //
+ // Command
+ //
+ ui8NFC_F_Packet[1] = SENSF_REQ_CMD;
+
+ ui8NFC_F_Packet[2] = 0xFF; // System Code (SC) 7:0
+ ui8NFC_F_Packet[3] = 0xFF; // System Code (SC) 15:8
+
+ ui8NFC_F_Packet[4] = 0x00; // Request Code (RC)
+
+ ui8NFC_F_Packet[5] = 0x03; // Time Slot Number (TSN) (DP, Table 42, 4 time slots)
+ TRF79x0WriteFIFO(ui8NFC_F_Packet,CRC_BIT_ENABLE,6);
+}
+
+//*****************************************************************************
+//
+// Send SENSF_RES (response)
+//
+//*****************************************************************************
+void NFCTypeF_SendSENSF_RES(void)
+{
+ uint8_t ui8NFC_F_Packet[18];
+ uint8_t ui8Offset = 0;
+ uint8_t ui8Counter = 0;
+ //
+ // Length
+ //
+ ui8NFC_F_Packet[ui8Offset++] = 0x12;
+ //
+ // Command
+ //
+ ui8NFC_F_Packet[ui8Offset++] = SENSF_RES_CMD;
+
+ for(ui8Counter = 0; ui8Counter < 8; ui8Counter++)
+ {
+ ui8NFC_F_Packet[ui8Offset++] = g_ui8NFCID2[ui8Counter];
+ }
+
+ // PAD 0
+ ui8NFC_F_Packet[ui8Offset++] = 0xC0;
+ ui8NFC_F_Packet[ui8Offset++] = 0xC1;
+ // PAD 1
+ ui8NFC_F_Packet[ui8Offset++] = 0xC2;
+ ui8NFC_F_Packet[ui8Offset++] = 0xC3;
+ ui8NFC_F_Packet[ui8Offset++] = 0xC4;
+ // MRTI CHECK
+ ui8NFC_F_Packet[ui8Offset++] = 0xC5;
+ // MRTI UPDATE
+ ui8NFC_F_Packet[ui8Offset++] = 0xC6;
+ // PAD2
+ ui8NFC_F_Packet[ui8Offset++] = 0xC7;
+
+ TRF79x0WriteFIFO(ui8NFC_F_Packet,CRC_BIT_ENABLE,ui8Offset);
+}
+//*****************************************************************************
+//
+// Process data received in buffer
+//
+//*****************************************************************************
+tStatus NFCTypeF_ProcessReceivedData(uint8_t * pui8RxBuffer)
+{
+ volatile uint8_t ui8CommandLength;
+ uint8_t ui8Command;
+ uint8_t ui8Counter;
+ tStatus eNFCFStatus = STATUS_SUCCESS;
+
+ ui8CommandLength = pui8RxBuffer[0];
+ ui8Command = pui8RxBuffer[1];
+
+// //UARTprintf("NFC_F CMD: %d \n",ui8Command);
+
+ if(ui8Command == SENSF_RES_CMD)
+ {
+ //
+ // Store the g_ui8NFCID2
+ //
+ for(ui8Counter = 0; ui8Counter < 8; ui8Counter++)
+ {
+ g_ui8NFCID2[ui8Counter] = pui8RxBuffer[2+ui8Counter];
+ }
+ }
+ else if(ui8Command == SENSF_REQ_CMD && ui8CommandLength == 0x06 )
+ {
+ if(pui8RxBuffer[2] == 0xFF && pui8RxBuffer[3] == 0xFF)
+ {
+ // Valid SENSF_REQ received - thus send a SENSF Response
+ NFCTypeF_SendSENSF_RES();
+ }
+ else
+ eNFCFStatus = STATUS_FAIL;
+ }
+ else
+ {
+ eNFCFStatus = STATUS_FAIL;
+ }
+ return eNFCFStatus;
+}
+
+//*****************************************************************************
+//
+// Return the NFCID
+//
+//*****************************************************************************
+uint8_t * NFCTypeF_GetNFCID2(void)
+{
+ return g_ui8NFCID2;
+}
+
+
+
+
diff --git a/nfclib/nfc_f.h b/nfclib/nfc_f.h
new file mode 100644
index 0000000..9292731
--- /dev/null
+++ b/nfclib/nfc_f.h
@@ -0,0 +1,48 @@
+//*****************************************************************************
+//
+// nfc_f.h - Type F (Felica) NFC Header
+//
+// Copyright (c) 2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
+//
+//*****************************************************************************
+#ifndef __NFC_F_H__
+#define __NFC_F_H__
+
+#include "types.h"
+
+//*****************************************************************************
+//
+// List of Commands
+//
+//*****************************************************************************
+#define SENSF_REQ_CMD 0x00
+#define SENSF_RES_CMD 0x01
+
+//*****************************************************************************
+//
+// Function Prototypes
+//
+//*****************************************************************************
+void NFCTypeF_SendSENSF_REQ(void);
+void NFCTypeF_SendSENSF_RES(void);
+tStatus NFCTypeF_ProcessReceivedData(uint8_t * pui8RxBuffer);
+uint8_t * NFCTypeF_GetNFCID2(void);
+void NFCTypeF_SetBufferPtr(uint8_t * buffer_ptr);
+
+#endif //__NFC_F_H__
diff --git a/nfclib/nfc_p2p.c b/nfclib/nfc_p2p.c
new file mode 100644
index 0000000..7f1638a
--- /dev/null
+++ b/nfclib/nfc_p2p.c
@@ -0,0 +1,1993 @@
+//*****************************************************************************
+//
+// nfc_p2p.c - contains implementation of p2p over NFC
+//
+// Copyright (c) 2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
+//
+//*****************************************************************************
+#include <stdbool.h>
+#include <stdint.h>
+#include "nfclib/nfc_p2p.h"
+#include "nfclib/nfc_f.h"
+#include "nfclib/nfc_dep.h"
+#include "nfclib/llcp.h"
+#include "nfclib/snep.h"
+#include "nfclib/debug.h"
+
+//*****************************************************************************
+//! \addtogroup nfc_p2p_api NFC P2P API Functions
+//! @{
+//! This module implements the encoding and decoding of NFC P2P messages
+//! and records.
+//!
+//! It is assumed that users of this module have a functional knowledge of NFC
+//! P2P messages and record types as defined by the NFC specification at
+//! <a href="http://www.nfc-forum.org/specs/spec_list/">
+//! http://www.nfc-forum.org/specs/spec_list</a> .
+//!
+//! The functions in this module assume that the NFCP2P_proccessStateMachine()
+//! is being called every 77ms or less as defined by the Digital
+//! Protocol Technical Specification requirement 197. Before any of the
+//! functions in this module are called, TRF79x0Init() and NFCP2P_init() must be
+//! called to initialize the transceiver and the NFCP2P state machine.
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// Globals
+//
+//*****************************************************************************
+
+//
+// Global pointer to recieve data, used by NFCP2PStateMachine().
+//
+uint8_t *g_ui8RxDataPtr;
+
+//
+// Flag to keep track of when to transmit data. Used by NFCP2PStateMachine().
+//
+bool g_bTxDataAvailable = false;
+
+//
+// Timout value aquired from lower level in NFC Stack, used by
+// NFCP2PStateMachine()
+//
+uint16_t g_ui16TargetTimeout = 0;
+
+//*****************************************************************************
+//
+// State used by NFCP2PStateMachine.
+//
+// Options are:
+// - NFC_P2P_PROTOCOL_ACTIVATION
+// - NFC_P2P_PARAMETER_SELECTION
+// - NFC_P2P_DATA_EXCHANGE_PROTOCOL
+// - NFC_P2P_DEACTIVATION
+//
+//*****************************************************************************
+tNFCP2PState g_eNFCP2PState = NFC_P2P_PROTOCOL_ACTIVATION;
+
+//*****************************************************************************
+//
+// Global for what mode the TRF79x0 operates in.
+//
+// Options are:
+// - BOARD_INIT
+// - P2P_INITATIOR_MODE
+// - P2P_PASSIVE_TARGET_MODE
+// - P2P_ACTIVE_TARGET_MODE
+// - CARD_EMULATION_TYPE_A
+// - CARD_EMULATION_TYPE_B
+//
+//*****************************************************************************
+tTRF79x0TRFMode g_eP2PMode;
+
+//*****************************************************************************
+//
+// Global for TRF79x0 operating frequency.
+//
+// Options are:
+// - FREQ_STAND_BY
+// - FREQ_106_KBPS
+// - FREQ_212_KBPS
+// - FREQ_424_KBPS
+//
+//*****************************************************************************
+tTRF79x0Frequency g_eP2PFrequency;
+
+//*****************************************************************************
+//! Initialize the variables used by the NFC Stack.
+//!
+//! \param eMode is the mode which to initialize the TRF79x0
+//! \param eFrequency is the frequency which to initialize the TRF79x0
+//!
+//! This function must be called before any other NFCP2P function is called.
+//! It can be called at any point to change the mode or frequency of the
+//! TRF79x0 transceiver. This function initializes either the initiator or the
+//! target mode.
+//!
+//! The \e eMode parameter can be any of the following:
+//!
+//! - \b BOARD_INIT - Initial Mode.
+//! - \b P2P_INITATIOR_MODE - P2P Initiator Mode.
+//! - \b P2P_PASSIVE_TARGET_MODE - P2P Passive Target Mode.
+//! - \b P2P_ACTIVE_TARGET_MODE - P2P Active Target Mode.
+//! - \b CARD_EMULATION_TYPE_A - Card Emulation for Type A cards.
+//! - \b CARD_EMULATION_TYPE_B - Card Emulation for Type B cards.
+//!
+//! The \e eFrequency parameter can be any of the following:
+//!
+//! - \b FREQ_STAND_BY - Used for Board Initialization.
+//! - \b FREQ_106_KBPS - Frequency of 106 kB per second.
+//! - \b FREQ_212_KBPS - Frequency of 212 kB per second.
+//! - \b FREQ_424_KBPS - Frequency of 424 kB per second.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+NFCP2P_init(tTRF79x0TRFMode eMode,tTRF79x0Frequency eFrequency)
+{
+ //
+ // Reset Default Values
+ //
+ g_eNFCP2PState = NFC_P2P_PROTOCOL_ACTIVATION;
+ g_eP2PMode = eMode;
+ g_eP2PFrequency = eFrequency;
+ g_bTxDataAvailable = false;
+ g_ui16TargetTimeout = 0;
+
+ //
+ // Store the nfc_buffer ptr in g_ui8RxDataPtr
+ //
+ g_ui8RxDataPtr = TRF79x0GetNFCBuffer();
+
+ //
+ // Initialize NFC DEP Global Pointer to use the g_ui8RxDataPtr pointer -
+ // the pointer is used to send responses/commands to the other Peer to
+ // Peer device. This implementation allows to reduce the RAM consumption.
+ //
+ NFCDEP_SetBufferPtr(g_ui8RxDataPtr);
+}
+
+//*****************************************************************************
+//
+//!
+//! Processes low level stack.
+//!
+//! \return This function returns the current NFCP2P state.
+//!
+//! The \e \b tNFCP2PState return parameter can be any of the following
+//! - \b NFC_P2P_PROTOCOL_ACTIVATION - Polling/Listening for SENSF_REQ / SENSF_RES.
+//! - \b NFC_P2P_PARAMETER_SELECTION - Setting the NFCIDs and bit rate
+//! - \b NFC_P2P_DATA_EXCHANGE_PROTOCOL - Data exchange using the LLCP layer
+//! - \b NFC_P2P_DEACTIVATION - Technology deactivation.
+//!
+//! This function must be executed every 77 ms or less as
+//! defined by requirement 197 inside the Digital Protocol Technical
+//! Specification. When the g_eP2PMode is set to P2P_INITATIOR_MODE, this
+//! function sends a SENSF_REQ to check if there is a Target in the field,
+//! while blocking the main application. If there is no target in the field,
+//! it exits. When the g_eP2PMode is set to P2P_PASSIVE_TARGET_MODE, this
+//! function waits for command for 495 ms, while blocking the main
+//! application. If no commands are received or if any errors occurred, this
+//! function exits. Once a technology is activated for either
+//! P2P_INITATIOR_MODE or P2P_PASSIVE_TARGET_MODE, the main application can use
+//! g_eNFCP2PState when equal to NFC_P2P_DATA_EXCHANGE_PROTOCOL, to then call
+//! NFCP2P_sendPacket() to send data from the TRF7970A to a target/initiator.
+//! Furthermore when g_eNFCP2PState is NFC_P2P_DATA_EXCHANGE_PROTOCOL,
+//! the main application must check the receive state with the function
+//! NFCP2P_getReceiveState() each time NFCP2P_proccessStateMachine() is
+//! executed to ensure it handles the data as it is received.
+//!
+//! \return g_eNFCP2PState, which is the current P2P state.
+//
+//*****************************************************************************
+tNFCP2PState
+NFCP2P_proccessStateMachine(void)
+{
+ uint8_t *pui8NFCID2_Ptr=0;
+
+ tTRF79x0IRQFlag eIRQStatus = IRQ_STATUS_IDLE;
+
+ switch(g_eNFCP2PState)
+ {
+ case NFC_P2P_PROTOCOL_ACTIVATION:
+ {
+ if (g_eP2PMode == P2P_INITATIOR_MODE)
+ {
+ //
+ // Initialize the TRF7970A Registers for P2P Initiator Mode -
+ // in the case there is an external field enabled, the function
+ // will return STATUS_FAIL, the TRF7970 field will be disabled,
+ // and the program should switch to Target Mode.
+ //
+ if(TRF79x0Init2(P2P_INITATIOR_MODE, g_eP2PFrequency) ==
+ STATUS_FAIL)
+ break;
+
+ //
+ // Send SENSF_REQ
+ //
+ NFCTypeF_SendSENSF_REQ();
+
+ //
+ // Check if IRQ is triggered - timeout of 20 mS
+ //
+ if(TRF79x0IRQHandler(20) == IRQ_STATUS_RX_COMPLETE)
+ {
+ //
+ // Process the received data - check for valid SENSF_RES
+ //
+ if (NFCTypeF_ProcessReceivedData(g_ui8RxDataPtr) ==
+ STATUS_SUCCESS)
+ {
+ g_eNFCP2PState = NFC_P2P_PARAMETER_SELECTION;
+ #ifdef DEBUG_PRINT
+ //UARTprintf("\nInitiator Activated \n");
+ //UARTprintf("Exit PROT ACT \n");
+ #endif
+
+ break;
+ }
+ else
+ {
+ TRF79x0DisableTransmitter();
+ break;
+ }
+ }
+ else
+ {
+ TRF79x0DisableTransmitter();
+ break;
+ }
+
+ }
+ else if (g_eP2PMode == P2P_PASSIVE_TARGET_MODE)
+ {
+ TRF79x0Init2(P2P_PASSIVE_TARGET_MODE, g_eP2PFrequency);
+
+ //
+ // Poll the IRQ flag for 495 mS.
+ //
+ while(eIRQStatus != IRQ_STATUS_TIME_OUT)
+ {
+ eIRQStatus = TRF79x0IRQHandler(495);
+
+ //
+ // Process the received data - check for valid SENSF_REQ
+ //
+ if((eIRQStatus == IRQ_STATUS_RX_COMPLETE) &&
+ (NFCTypeF_ProcessReceivedData(g_ui8RxDataPtr) ==
+ STATUS_SUCCESS))
+ {
+ g_eNFCP2PState = NFC_P2P_PARAMETER_SELECTION;
+ break;
+ #ifdef DEBUG_PRINT
+ //UARTprintf("\nTarget Activated \n");
+ //UARTprintf("Exit PROT ACT \n");
+ #endif
+
+ }
+ }
+ break;
+
+ }
+ else if (g_eP2PMode == P2P_ACTIVE_TARGET_MODE)
+ {
+ TRF79x0Init2(P2P_ACTIVE_TARGET_MODE, g_eP2PFrequency);
+
+ //
+ // Poll the IRQ flag for 495 mS.
+ //
+ while(eIRQStatus != IRQ_STATUS_TIME_OUT)
+ {
+ eIRQStatus = TRF79x0IRQHandler(495);
+
+ //
+ // Process the received data - check for valid ATR_REQ
+ //
+ if((eIRQStatus == IRQ_STATUS_RX_COMPLETE) &&
+ (NFCDEP_ProcessReceivedRequest(g_ui8RxDataPtr,0,true) ==
+ STATUS_SUCCESS))
+ {
+ g_eNFCP2PState = NFC_P2P_DATA_EXCHANGE_PROTOCOL;
+ break;
+ #ifdef DEBUG_PRINT
+ //UARTprintf("\nTarget Activated \n");
+ //UARTprintf("Exit PROT ACT \n");
+ #endif
+
+
+ }
+ }
+ break;
+ }
+ }
+ case NFC_P2P_PARAMETER_SELECTION:
+ {
+ //
+ // Reset the LLCP Parameters
+ //
+ LLCP_init();
+ if (g_eP2PMode == P2P_INITATIOR_MODE)
+ {
+ pui8NFCID2_Ptr = NFCTypeF_GetNFCID2();
+ NFCDEP_SendATR_REQ(pui8NFCID2_Ptr);
+ //
+ // Check if IRQ is triggered - timeout of 100 mS
+ //
+ if (TRF79x0IRQHandler(1000) == IRQ_STATUS_RX_COMPLETE)
+ {
+ //
+ // Process the received data - check for valid ATR_RES
+ //
+ if (NFCDEP_ProcessReceivedData(g_ui8RxDataPtr)
+ == STATUS_SUCCESS)
+ {
+ //
+ // If Current Frequency is 212 request to go to a higher
+ // baud rate
+ //
+ if(g_eP2PFrequency == FREQ_212_KBPS)
+ {
+ NFCDEP_SendPSL_REQ();
+
+ if (TRF79x0IRQHandler(1000) ==
+ IRQ_STATUS_RX_COMPLETE)
+ {
+ if (NFCDEP_ProcessReceivedData(g_ui8RxDataPtr)==
+ STATUS_SUCCESS)
+ {
+ //
+ // If the function returns successful then
+ // the returned DID was correct.
+ //
+ TRF79x0SetMode(g_eP2PMode,FREQ_424_KBPS);
+ }
+ }
+ else
+ {
+ #ifdef DEBUG_PRINT
+ //UARTprintf("\nMCU Timed Out\n");
+ //UARTprintf("Exit PARAM SEL\n");
+ #endif
+ g_eNFCP2PState = NFC_P2P_PROTOCOL_ACTIVATION;
+ TRF79x0DisableTransmitter();
+ break;
+ }
+ }
+
+ g_eNFCP2PState = NFC_P2P_DATA_EXCHANGE_PROTOCOL;
+ #ifdef DEBUG_PRINT
+ //UARTprintf("Exit P2P PARM SEL\n");
+ #endif
+
+ g_ui16TargetTimeout = LLCP_getLinkTimeOut();
+
+ #ifdef DEBUG_PRINT
+ //UARTprintf("Time out is: %d",g_ui16TargetTimeout);
+ #endif
+ }
+ else
+ {
+ g_eNFCP2PState = NFC_P2P_PROTOCOL_ACTIVATION;
+ TRF79x0DisableTransmitter();
+ break;
+ }
+ }
+ else
+ {
+ #ifdef DEBUG_PRINT
+ //UARTprintf("\nMCU Timed Out\n");
+ //UARTprintf("Exit PARAM SEL\n");
+ #endif
+ g_eNFCP2PState = NFC_P2P_PROTOCOL_ACTIVATION;
+ TRF79x0DisableTransmitter();
+ break;
+ }
+ }
+ else if (g_eP2PMode == P2P_PASSIVE_TARGET_MODE)
+ {
+ //
+ // Check if IRQ is triggered - timeout of 100 mS
+ //
+ if (TRF79x0IRQHandler(1000) == IRQ_STATUS_RX_COMPLETE)
+ {
+ pui8NFCID2_Ptr = NFCTypeF_GetNFCID2();
+ //
+ // Process the received data - check for valid ATR_REQ
+ //
+ if (NFCDEP_ProcessReceivedRequest(g_ui8RxDataPtr,
+ pui8NFCID2_Ptr,false)
+ == STATUS_SUCCESS)
+ {
+ g_eNFCP2PState = NFC_P2P_DATA_EXCHANGE_PROTOCOL;
+ #ifdef DEBUG_PRINT
+ //UARTprintf("Exit P2P PARM SEL\n");
+ #endif
+ }
+ else
+ {
+ g_eNFCP2PState = NFC_P2P_PROTOCOL_ACTIVATION;
+ #ifdef DEBUG_PRINT
+ //UARTprintf("\nMCU Invalid ATR REQ\n");
+ //UARTprintf("Exit P2P PARM SEL\n");
+ #endif
+ break;
+ }
+ }
+ else
+ {
+ g_eNFCP2PState = NFC_P2P_PROTOCOL_ACTIVATION;
+ #ifdef DEBUG_PRINT
+ //UARTprintf("\nMCU Timed Out\n");
+ //UARTprintf("Exit PARAM SEL\n");
+ #endif
+ break;
+ //TRF79x0DisableTransmitter();
+ }
+ }
+ else if (g_eP2PMode == P2P_ACTIVE_TARGET_MODE)
+ {
+ //TODO
+ break;
+ }
+ }
+ case NFC_P2P_DATA_EXCHANGE_PROTOCOL:
+ {
+ if (g_eP2PMode == P2P_INITATIOR_MODE)
+ {
+ NFCDEP_SendDEP_REQ(g_ui8RxDataPtr);
+ //
+ // Check if IRQ is triggered - timeout of 100 mS
+ //
+ if (TRF79x0IRQHandler(g_ui16TargetTimeout) ==
+ IRQ_STATUS_RX_COMPLETE)
+ {
+ //
+ // Process the received data - check for valid DEP_RES
+ //
+ if (NFCDEP_ProcessReceivedData(g_ui8RxDataPtr) ==
+ STATUS_FAIL)
+ {
+ //DebugPrintf("Exit DATA EXCHANGE\n");
+ g_eNFCP2PState = NFC_P2P_PROTOCOL_ACTIVATION;
+ break;
+ }
+
+ //
+ // Check if there is data to send to the Target.
+ //
+ if (g_bTxDataAvailable == true)
+ {
+ //
+ // Set the Connect PDU as the next command to the Target
+ //
+ if (LLCP_setNextPDU(LLCP_CONNECT_PDU) == STATUS_SUCCESS)
+ {
+ //
+ // If there was no ongoing connection, then clear
+ // the g_data_available flag
+ //
+ g_bTxDataAvailable = false;
+ }
+ }
+ }
+ else
+ {
+ #ifdef DEBUG_PRINT
+ //UARTprintf("\nMCU Timed Out \n");
+ //UARTprintf("Exit DATA EXCHANGE\n");
+ #endif
+ g_eNFCP2PState = NFC_P2P_PROTOCOL_ACTIVATION;
+ TRF79x0DisableTransmitter();
+ break;
+ }
+ }
+ else if ((g_eP2PMode == P2P_PASSIVE_TARGET_MODE) ||
+ (g_eP2PMode == P2P_ACTIVE_TARGET_MODE))
+ {
+ //
+ // Check if IRQ is triggered - timeout of 100 mS
+ //
+ eIRQStatus = IRQ_STATUS_IDLE;
+ while((eIRQStatus == IRQ_STATUS_IDLE) ||
+ (eIRQStatus == IRQ_STATUS_RF_FIELD_CHANGE) )
+ {
+ eIRQStatus = TRF79x0IRQHandler(1000);
+ }
+
+ if (eIRQStatus == IRQ_STATUS_RX_COMPLETE)
+ {
+ //
+ // Check if there is data to send to the Target.
+ //
+ if (g_bTxDataAvailable == true)
+ {
+ //
+ // Set the Connect PDU as the next command to the Target
+ //
+ if (LLCP_setNextPDU(LLCP_CONNECT_PDU) == STATUS_SUCCESS)
+ {
+ //
+ // If there was no ongoing connection, then clear
+ //the g_data_available flag
+ //
+ g_bTxDataAvailable = false;
+ }
+ }
+
+ //
+ // Process the received data - check for valid DEP_REQ
+ //
+ if (NFCDEP_ProcessReceivedRequest(g_ui8RxDataPtr,
+ pui8NFCID2_Ptr,false)
+ == STATUS_FAIL)
+ {
+ g_eNFCP2PState = NFC_P2P_PROTOCOL_ACTIVATION;
+ #ifdef DEBUG_PRINT
+ //UARTprintf("Exit DATA EXCHANGE\n");
+ #endif
+ break;
+ }
+ }
+ else if (eIRQStatus
+ == (IRQ_STATUS_RX_COMPLETE | IRQ_STATUS_FIFO_HIGH_OR_LOW))
+ {
+ // Wait to receive the complete payload
+ }
+ else
+ {
+ g_eNFCP2PState = NFC_P2P_PROTOCOL_ACTIVATION;
+ #ifdef DEBUG_PRINT
+ //UARTprintf("\nMCU Timed Out \n");
+ //UARTprintf("Exit DATA EXCHANGE\n");
+ #endif
+
+ break;
+ }
+ }
+ else if (g_eP2PMode == P2P_ACTIVE_TARGET_MODE)
+ {
+ //TODO
+ break;
+ }
+ }
+ case NFC_P2P_DEACTIVATION:
+ {
+ break;
+ }
+ }
+
+ return g_eNFCP2PState;
+
+}
+
+//*****************************************************************************
+//
+//! Sends a raw buffer of data to the SNEP stack to be transmitted.
+//!
+//! \param pui8DataPtr is a pointer to the raw data to be sent.
+//! \param ui32DataLength is the length of the raw data.
+//!
+//! This function is used to send a data stream over NFC. The buffer resulting
+//! from a call to NFCP2P_NDEFMessageEncoder() should be fed to this function.
+//!
+//! \return Status of sent packet.
+//!
+//! The \e \b tStatus parameter can be any of the following:
+//!
+//! - \b STATUS_FAIL - The function exited with a failure.
+//! - \b STATUS_SUCCESS - The function ended in succes.
+//
+//*****************************************************************************
+tStatus
+NFCP2P_sendPacket(uint8_t *pui8DataPtr, uint32_t ui32DataLength)
+{
+ g_bTxDataAvailable = true;
+ return SNEP_setupPacket(pui8DataPtr,ui32DataLength);
+}
+
+//*****************************************************************************
+//
+//! NFCP2P_getReceiveState - Gets the receive state from the low level SNEP
+//! stack.
+//!
+//! Description: This function is used to get the receive payload status
+//! from the SNEP layer.
+//!
+//! \return This function returns the receive state.
+//
+//*****************************************************************************
+sNFCP2PRxStatus
+NFCP2P_getReceiveState(void)
+{
+ sNFCP2PRxStatus eReceiveStatus;
+
+ SNEP_getReceiveStatus(&eReceiveStatus.eDataReceivedStatus,
+ &eReceiveStatus.ui8DataReceivedLength,
+ &eReceiveStatus.pui8RxDataPtr);
+
+ return eReceiveStatus;
+}
+
+//*****************************************************************************
+//
+//! Encodes NFC Message meta-data and payload information.
+//!
+//! \param sNDEFDataToSend is a sNDEFMessageData structure filled out with the
+//! NDEF message to send.
+//! \param pui8Buffer is a pointer to the buffer where the raw encoded data will
+//! be stored
+//! \param ui16BufferMaxLength is the maximum number of bytes the buffer
+//! can hold. This parameter is used to prevent writing past the end of the
+//! buffer.
+//! \param pui32BufferLength is a pointer to an integer that is filled with
+//! the length of the raw data encoded to the \b pui8Buffer.
+//!
+//! This function takes a filled sNDEFMessageData structure and encodes it to
+//! the provided buffer. The length, in bytes, of the data encoded to the buffer
+//! is stored into the integer pointer provided.
+//!
+//! \return This function returns \b STATUS_SUCCESS (1) or \b STATUS_FAIL (0).
+//!
+//
+// Note: for an explanation of the fields please see the Programmers Note in
+// nfc_p2p.h
+//*****************************************************************************
+bool
+NFCP2P_NDEFMessageEncoder(sNDEFMessageData sNDEFDataToSend,
+ uint8_t *pui8Buffer,
+ uint16_t ui16BufferMaxLength,
+ uint32_t *pui32BufferLength)
+{
+ uint32_t ui32HeaderSize = 0;
+ uint32_t x;
+ sNDEFMessageData sMessage = sNDEFDataToSend;
+
+ //
+ // Check Arguements, ASSERT / return STATUS_FAIL as appropriate
+ //
+ ASSERT(ui16BufferMaxLength > 0);
+ ASSERT(pui8Buffer != 0);
+ ASSERT(sNDEFDataToSend.ui8TypeLength > 0);
+ ASSERT(sNDEFDataToSend.ui32PayloadLength > 0);
+ ASSERT(sNDEFDataToSend.pui8PayloadPtr != 0);
+ ASSERT(sNDEFDataToSend.ui32PayloadLength < ui16BufferMaxLength);
+ if(
+ (ui16BufferMaxLength == 0) ||
+ (pui8Buffer == 0) ||
+ (sNDEFDataToSend.ui8TypeLength == 0) ||
+ (sNDEFDataToSend.ui32PayloadLength == 0 ) ||
+ (sNDEFDataToSend.pui8PayloadPtr == 0) ||
+ (sNDEFDataToSend.ui32PayloadLength > ui16BufferMaxLength)
+ )
+ {
+ DebugPrintf(" ERR: NDEFMessageEncoder: Invalid Input\n");
+ return STATUS_FAIL;
+ }
+ if(ui16BufferMaxLength < 25)
+ {
+ DebugPrintf("Warning: NDEFMessageEncoder : You need a bigger buffer\n");
+ }
+
+ //
+ // Fill STATUS_BYTE field
+ //
+ pui8Buffer[ui32HeaderSize] = (
+ NDEF_STATUSBYTE_SET_MB(sMessage.sStatusByte.MB) |
+ NDEF_STATUSBYTE_SET_ME(sMessage.sStatusByte.ME) |
+ NDEF_STATUSBYTE_SET_CF(sMessage.sStatusByte.CF) |
+ NDEF_STATUSBYTE_SET_SR(sMessage.sStatusByte.SR) |
+ NDEF_STATUSBYTE_SET_IL(sMessage.sStatusByte.IL) |
+ NDEF_STATUSBYTE_SET_TNF(sMessage.sStatusByte.TNF)
+ );
+ ui32HeaderSize++;
+
+ //
+ // Fill TYPE_LENGTH field
+ //
+ pui8Buffer[ui32HeaderSize] = sMessage.ui8TypeLength;
+ ui32HeaderSize++;
+
+ //
+ // Fill PAYLOAD_LENGTH field.
+ // based on StatusByte.SR field. May truncate if improperly set.
+ //
+ switch(sMessage.sStatusByte.SR)
+ {
+ //
+ // PAYLOAD_LENGTH is 1 byte long
+ //
+ case NDEF_STATUSBYTE_SR_1BYTEPAYLOADSIZE:
+ {
+ pui8Buffer[ui32HeaderSize] = (sMessage.ui32PayloadLength & 0xFF);
+ ui32HeaderSize++;
+ break;
+ }
+
+ //
+ // PAYLOAD_LENGTH is 4 bytes long, inverted order (NFC Standard)
+ //
+ case NDEF_STATUSBYTE_SR_4BYTEPAYLOADSIZE:
+ {
+ pui8Buffer[ui32HeaderSize+0] = ((sMessage.ui32PayloadLength >> 3*8)
+ & 0xFF);
+ pui8Buffer[ui32HeaderSize+1] = ((sMessage.ui32PayloadLength >> 2*8)
+ & 0xFF);
+ pui8Buffer[ui32HeaderSize+2] = ((sMessage.ui32PayloadLength >> 1*8)
+ & 0xFF);
+ pui8Buffer[ui32HeaderSize+3] = ((sMessage.ui32PayloadLength >> 0*8)
+ & 0xFF);
+ ui32HeaderSize = ui32HeaderSize + 4;
+ break;
+ }
+
+ //
+ // default case, should never get here, if you do its an error
+ //
+ default:
+ {
+ DebugPrintf("ERR: NFC Header Encoder fn PAYLOAD_LENGTH field\n");
+ return STATUS_FAIL;
+ break;
+ }
+ }
+
+ //
+ // Fill ID_LENGTH field.
+ // depends on Statusbyte.IL, if IL not set but data given in ui8IDLength
+ // the data will be ignored.
+ //
+ switch(sMessage.sStatusByte.IL)
+ {
+ //
+ // No ID_LENGTH field included
+ //
+ case NDEF_STATUSBYTE_IL_IDLENGTHABSENT:
+ {
+ // do nothing
+ break;
+ }
+
+ //
+ // ID_LENGTH field present, fill data, incriment buffer pointer
+ //
+ case NDEF_STATUSBYTE_IL_IDLENGTHPRESENT:
+ {
+ pui8Buffer[ui32HeaderSize] = sMessage.ui8IDLength;
+ ui32HeaderSize++;
+ break;
+ }
+
+ //
+ // default case, should never get here, if you do its an error.
+ //
+ default:
+ {
+ DebugPrintf("ERR: NFC Header Encoder fn ID_LENGTH field\n");
+ return STATUS_FAIL;
+ break;
+ }
+ }
+
+ //
+ // Fill TYPE field. If TYPE_LENGTH > NDEF_TYPE_MAXSIZE then TYPE will be
+ // truncated to MAXSIZE
+ //
+ if(0 == sMessage.ui8TypeLength)
+ {
+ //
+ // do nothing
+ // TYPE_LENGTH = 0, so there is nothing to put in the TYPE field
+ //
+ }
+ else
+ {
+ for(x = 0;(x < sMessage.ui8TypeLength) && (x < NDEF_TYPE_MAXSIZE); x++)
+ {
+ pui8Buffer[ui32HeaderSize] = sMessage.pui8Type[x];
+ ui32HeaderSize++;
+ }
+ }
+
+ //
+ // Fill ID field. If ID_LENGTH > NDEF_ID_MAXSIZE then ID will be truncated
+ // to MAXSIZE.
+ //
+ switch(sMessage.sStatusByte.IL)
+ {
+ //
+ // StatusByte.IL says no ID_LENGTH field, thus no ID field.
+ //
+ case NDEF_STATUSBYTE_IL_IDLENGTHABSENT:{
+ //do nothing.
+ break;
+ }
+
+ //
+ // StatusByte.IL says ID_LENGTH Exists, so add the ID.
+ //
+ case NDEF_STATUSBYTE_IL_IDLENGTHPRESENT:
+ {
+ if(0 == sMessage.ui8IDLength)
+ {
+ //
+ // Do nothing. ID_LENGTH = 0 so there is no ID to add.
+ //
+ }
+ else
+ {
+ for(x = 0;(x < sMessage.ui8IDLength) && (x < NDEF_ID_MAXSIZE);
+ x++)
+ {
+ pui8Buffer[ui32HeaderSize] = sMessage.pui8ID[x];
+ ui32HeaderSize++;
+ }
+ }
+ break;
+ }
+ }
+
+ //
+ // Make sure we wont overflow the buffer with the payload in the next step.
+ //
+ if((ui32HeaderSize + sMessage.ui32PayloadLength) > ui16BufferMaxLength)
+ {
+ ASSERT(0);
+ DebugPrintf("ERR:NDEFMessageEncoder: BufferOverflow Payload too big\n");
+ return STATUS_FAIL;
+ }
+
+ //
+ // Fill PAYLOAD buffer.
+ //
+ if(sMessage.sStatusByte.SR == NDEF_STATUSBYTE_SR_1BYTEPAYLOADSIZE)
+ {
+ //
+ // 1 byte PAYLOAD_LENGTH.
+ //
+ for(x = 0;x < (sMessage.ui32PayloadLength & 0xFF);x++)
+ {
+ pui8Buffer[ui32HeaderSize] = sMessage.pui8PayloadPtr[x];
+ ui32HeaderSize++;
+ }
+ }
+ else
+ {
+ //
+ // 4 byte PAYLOAD_LENGTH.
+ // (treat Payload length as a 32bit number)
+ //
+ for(x = 0;x < sMessage.ui32PayloadLength; x++)
+ {
+ pui8Buffer[ui32HeaderSize] = sMessage.pui8PayloadPtr[x];
+ ui32HeaderSize++;
+ }
+ }
+
+ //
+ // Fill BufferLength variable.
+ //
+ *pui32BufferLength = ui32HeaderSize;
+
+
+ return STATUS_SUCCESS;
+
+}
+
+//*****************************************************************************
+//
+//! Decodes NFC Message meta-data and payload information.
+//!
+//! \param psNDEFDataDecoded is a pointer to the sNDEFMessageData structure to
+//! be filled.
+//! \param pui8Buffer is a pointer to the raw NFC data buffer from which to
+//! decode the data.
+//! \param ui16BufferMaxLength is the maximum number of bytes the buffer
+//! can hold. This parameter is used to prevent reading past the end of the
+//! buffer.
+//!
+//! This function takes in a buffer of raw NFC data and fills up an
+//! sNDEFMessageData structure. This function is the first step to decoding an
+//! NFC Message. The next step is to decode the Message Payload, which is the record.
+//! The decoded sNDEFMessageData structure has a field named \b pui8Type. The
+//! \b pui8Type field defines the record type and therefore indicates which
+//! RecordDecoder function to use on the Message Payload.
+//!
+//! \return This function returns \b STATUS_SUCCESS (1) or \b STATUS_FAIL (0).
+//
+// Note: local variables are used to break out fields from the header for
+// clarity. ui32HeaderSize is used to keep track of how large the header
+// is in bytes. It is used to computer the size of the payload at the end.
+// (length of Buffer - HeaderSize = Payload length)
+//
+//*****************************************************************************
+bool
+NFCP2P_NDEFMessageDecoder(sNDEFMessageData *psNDEFDataDecoded,
+ uint8_t *pui8Buffer,
+ uint16_t ui16BufferMaxLength)
+{
+ sNDEFMessageData *psMessage;
+ uint8_t ui8StatusByte,ui8TypeLength,ui8IDLength;
+ uint8_t *pui8PayloadPtr;
+ uint32_t ui32HeaderSize = 0;
+ uint32_t ui32PayloadLength=0;
+ uint32_t x;
+
+ //
+ // Check Input for Validity
+ //
+ ASSERT(pui8Buffer != 0);
+ ASSERT(ui16BufferMaxLength > 0);
+
+ //
+ // Minimum length of header is 5 bytes.
+ //
+ if(ui16BufferMaxLength <= 5)
+ {
+ DebugPrintf("ERR: NDEFMessageDecoder: Invalid Input\n");
+ return STATUS_FAIL;
+ }
+
+ psMessage = psNDEFDataDecoded;
+
+ //
+ // Load Status Byte into NDEF Structure.
+ //
+ ui8StatusByte = pui8Buffer[ui32HeaderSize];
+ psMessage->sStatusByte.MB = NDEF_STATUSBYTE_GET_MB(ui8StatusByte);
+ psMessage->sStatusByte.ME = NDEF_STATUSBYTE_GET_ME(ui8StatusByte);
+ psMessage->sStatusByte.CF = NDEF_STATUSBYTE_GET_CF(ui8StatusByte);
+ psMessage->sStatusByte.SR = NDEF_STATUSBYTE_GET_SR(ui8StatusByte);
+ psMessage->sStatusByte.IL = NDEF_STATUSBYTE_GET_IL(ui8StatusByte);
+ psMessage->sStatusByte.TNF = NDEF_STATUSBYTE_GET_TNF(ui8StatusByte);
+
+ //
+ // Increment size of header (+1 for the size of the Status Byte).
+ //
+ ui32HeaderSize++;
+
+ //
+ // Load TypeLength byte into NDEF Structure.
+ //
+ ui8TypeLength = pui8Buffer[ui32HeaderSize];
+ psMessage->ui8TypeLength = ui8TypeLength;
+
+ //
+ // Increment size of header (+1 for the size of the Status Byte).
+ //
+ ui32HeaderSize++;
+
+ //
+ // Determine the payload size based upon the SR field in the header.
+ //
+ switch (psMessage->sStatusByte.SR)
+ {
+ //
+ // Short Record (PAYLOAD_LENGTH field is 1 byte).
+ //
+ case NDEF_STATUSBYTE_SR_1BYTEPAYLOADSIZE:
+ {
+ ui32PayloadLength = pui8Buffer[ui32HeaderSize];
+
+ //
+ // Validate Data
+ //
+ if((ui32HeaderSize + ui32PayloadLength) > ui16BufferMaxLength)
+ {
+ ASSERT(0);
+ DebugPrintf(
+ "ERR: NFCP2P_NDEFMessageDecoder: ui32PayloadLength > ui16BufferMaxLength\n");
+ DebugPrintf("\tYou Need a bigger buffer to hold this message.\n");
+ return STATUS_FAIL;
+ }
+ else
+ {
+ //
+ // Set Payload Length
+ //
+ psMessage->ui32PayloadLength = ui32PayloadLength;
+ ui32HeaderSize++;
+ }
+ break;
+ }
+
+ //
+ // Normal Record (PAYLOAD_LENGTH field is 4 bytes).
+ //
+ case NDEF_STATUSBYTE_SR_4BYTEPAYLOADSIZE:
+ {
+ ui32PayloadLength =
+ (
+ (pui8Buffer[ui32HeaderSize + 3] << 0*8) |
+ (pui8Buffer[ui32HeaderSize + 2] << 1*8) |
+ (pui8Buffer[ui32HeaderSize + 1] << 2*8) |
+ (pui8Buffer[ui32HeaderSize + 0] << 3*8)
+ );
+
+ //
+ // Validate Data
+ //
+ if((ui32HeaderSize + ui32PayloadLength) > ui16BufferMaxLength)
+ {
+ ASSERT(0);
+ DebugPrintf(
+ "ERR: NFCP2P_NDEFMessageDecoder: ui32PayloadLength > ui16BufferMaxLength\n");
+ DebugPrintf("\tYou Need a bigger buffer to hold this message.\n");
+ return STATUS_FAIL;
+ }
+ else
+ {
+ //
+ // Set Payload Length
+ //
+ psMessage->ui32PayloadLength = ui32PayloadLength;
+ ui32HeaderSize = ui32HeaderSize + 4;
+ }
+ break;
+ }
+
+ //
+ // This should never happen. return error.
+ //
+ default:
+ {
+ DebugPrintf("NDEFMessageDecoder: ERR decoding SR bit \n");
+ ASSERT(0);
+ return STATUS_FAIL;
+ break;
+ }
+ }
+
+ //
+ // Load ID_LENGTH field, if it exists. Depends on StatusByte.IL.
+ //
+ switch (psMessage->sStatusByte.IL)
+ {
+ //
+ // ID_LENGTH field exists. Load it to the NDEF structure.
+ //
+ case NDEF_STATUSBYTE_IL_IDLENGTHPRESENT:
+ {
+ ui8IDLength = pui8Buffer[ui32HeaderSize];
+ psMessage->ui8IDLength = ui8IDLength;
+ ui32HeaderSize++;
+ break;
+ }
+
+ //
+ // ID_LENGTH field does not exist and thus the ID field doesnt exists.
+ // Load 0 to NDEF structure to express this
+ //
+ case NDEF_STATUSBYTE_IL_IDLENGTHABSENT:
+ {
+ psMessage->ui8IDLength = 0;
+ break;
+ }
+
+ //
+ // This should never happen. return error.
+ //
+ default:
+ {
+ DebugPrintf(
+ "ERR: Invalid ID_LENGTH field Detected in NDEFMessageDecoder\n");
+ ASSERT(0);
+ return STATUS_FAIL;
+ break;
+ }
+ }
+
+ //
+ // Load TYPE field based on length in TYPE_LENGTH field
+ //
+ // If TYPE_LENGTH value is larger than NDEF_TYPE_MAXSIZE truncate to MAXSIZE
+ // and adjust index in buffer to end of TYPE so as to not lose data / skew
+ // pointer.
+ //
+ if(psMessage->ui8TypeLength > NDEF_TYPE_MAXSIZE)
+ {
+ #ifdef DEBUG_PRINT
+ ASSERT(0);
+ UARTprintf("ERR: MessageDecode: TYPE > NDEF_TYPE_MAXSIZE, truncating to %d bytes\n",
+ NDEF_TYPE_MAXSIZE);
+ UARTprintf(" Orig Type = ");
+ for(x = 0;x < psMessage->ui8TypeLength;x++)
+ {
+ UARTprintf("%c",pui8Buffer[ui32HeaderSize + x]);
+ }
+ UARTprintf("\n");
+ #endif
+
+ //
+ // Copy across truncated TYPE
+ //
+ for(x = 0;x < NDEF_TYPE_MAXSIZE;x++)
+ {
+ psMessage->pui8Type[x] = pui8Buffer[ui32HeaderSize];
+ ui32HeaderSize++;
+ }
+
+ //
+ // Adjust index appropriately.
+ //
+ ui32HeaderSize = ui32HeaderSize +
+ (psMessage->ui8TypeLength - NDEF_TYPE_MAXSIZE);
+ psMessage->ui8TypeLength = NDEF_TYPE_MAXSIZE;
+ }
+ else
+ {
+ //
+ // No problem
+ // Load Type field into NDEF structure
+ //
+ for(x = 0;x < psMessage->ui8TypeLength;x++)
+ {
+ psMessage->pui8Type[x] = pui8Buffer[ui32HeaderSize];
+ ui32HeaderSize++;
+ }
+ }
+
+ //
+ // Load ID field into NDEF structure. Depends on length in ID_LENGTH field.
+ // if ID field is > NDEF_ID_MAXSIZE truncate to MAXSIZE
+ //
+ if(psMessage->ui8IDLength > NDEF_ID_MAXSIZE)
+ {
+ #ifdef DEBUG_PRINT
+ ASSERT(0);
+ UARTprintf("ERR: ID_LENGTH > NDEF_ID_MAXSIZE, trucating to %d bytes\n",
+ NDEF_ID_MAXSIZE);
+ UARTprintf(" Orig ID = ");
+ for(x = 0;x < psMessage->ui8IDLength;x++)
+ {
+ UARTprintf("%c",pui8Buffer[ui32HeaderSize + x]);
+ }
+ UARTprintf("\n");
+ #endif
+
+ //
+ // Copy across truncated ID
+ //
+ for(x = 0;x < NDEF_ID_MAXSIZE;x++)
+ {
+ psMessage->pui8ID[x] = pui8Buffer[ui32HeaderSize];
+ ui32HeaderSize++;
+ }
+
+ //
+ // adjust index appropriately
+ //
+ ui32HeaderSize = ui32HeaderSize + (psMessage->ui8IDLength -
+ NDEF_ID_MAXSIZE);
+ psMessage->ui8IDLength = NDEF_ID_MAXSIZE;
+ }
+ else
+ {
+ //
+ // No problem
+ // Load ID field into NDEF structure
+ //
+ for(x = 0;x < psMessage->ui8IDLength;x++)
+ {
+ psMessage->pui8ID[x] = pui8Buffer[ui32HeaderSize];
+ ui32HeaderSize++;
+ }
+ }
+
+ //
+ // Error Check
+ // Check to make sure we didnt overrun the buffer / read beyond its bounds.
+ //
+ if((ui32HeaderSize + psMessage->ui32PayloadLength) > ui16BufferMaxLength)
+ {
+ ASSERT(0);
+ DebugPrintf("ERR: NDEFMessageDecode: Buffer OverRun / OverRead\n");
+
+ //
+ // Clear all data out of datastrucutre, dont return invalid data.
+ //
+ psMessage->ui32PayloadLength=0;
+ psMessage->pui8PayloadPtr=0;
+
+ return STATUS_FAIL;
+ }
+
+ //
+ // Calculate Payload Pointer (payload is located after the header)
+ //
+ pui8PayloadPtr = pui8Buffer + ui32HeaderSize;
+
+ //
+ // Set the Message Payload Pointer
+ //
+ psMessage->pui8PayloadPtr = pui8PayloadPtr;
+
+ return STATUS_SUCCESS;
+}
+
+//*****************************************************************************
+//
+//! Encode NDEF Text Records.
+//!
+//! \param sTextRecord is the Text Record Structure to be encoded.
+//! \param pui8Buffer is a pointer to the buffer to fill with the raw NFC data.
+//! \param ui16BufferMaxLength is the maximum number of bytes the buffer
+//! can hold. This parameter is used to prevent writing past the end of the
+//! buffer.
+//! \param pui32BufferLength is a pointer to the integer to hold the length of
+//! the raw NFC data buffer.
+//!
+//! This function takes a TextRecord structure and encodes it into a provided
+//! buffer in the raw NFC data format. The length of the data stored in the
+//! buffer is stored in \e ui32BufferLength.
+//!
+//! \return This function returns \b STATUS_SUCCESS (1) or \b STATUS_FAIL (0).
+//
+//*****************************************************************************
+bool
+NFCP2P_NDEFTextRecordEncoder(sNDEFTextRecord sTextRecord,
+ uint8_t *pui8Buffer,
+ uint16_t ui16BufferMaxLength,
+ uint32_t *pui32BufferLength)
+{
+ uint8_t x;
+ uint32_t ui32RecordIndex = 0;
+
+ //
+ // Validate Input
+ //
+ ASSERT(pui8Buffer != 0);
+ ASSERT(ui16BufferMaxLength > 0);
+ ASSERT(pui32BufferLength != 0);
+ ASSERT(sTextRecord.pui8Text != 0);
+ ASSERT(sTextRecord.ui32TextLength > 0);
+ ASSERT(sTextRecord.ui32TextLength < ui16BufferMaxLength);
+ if( (pui8Buffer == 0) ||
+ (ui16BufferMaxLength == 0) ||
+ (pui32BufferLength == 0) ||
+ (sTextRecord.pui8Text == 0) ||
+ (sTextRecord.ui32TextLength == 0) ||
+ (sTextRecord.ui32TextLength > ui16BufferMaxLength))
+ {
+ DebugPrintf("ERR: NDEFTextRecordEncoder: Invalid Input\n");
+ return STATUS_FAIL;
+ }
+
+ //
+ // Fill StatusByte in buffer
+ //
+ pui8Buffer[ui32RecordIndex] =
+ (
+ NDEF_TEXTRECORD_STATUSBYTE_SET_UTF(sTextRecord.sStatusByte.bUTFcode) |
+ NDEF_TEXTRECORD_STATUSBYTE_SET_RFU(sTextRecord.sStatusByte.bRFU ) |
+ NDEF_TEXTRECORD_STATUSBYTE_SET_LENGTHLANGCODE(
+ sTextRecord.sStatusByte.ui5LengthLangCode)
+ );
+ ui32RecordIndex++;
+
+ //
+ // Validate LanguageCode Length
+ //
+ if(sTextRecord.sStatusByte.ui5LengthLangCode >
+ NDEF_TEXTRECORD_LANGUAGECODE_MAXSIZE)
+ {
+ ASSERT(0);
+ DebugPrintf("Err: TextRecordEncoder: ui5LengthLanguageCode > ");
+ DebugPrintf("NDEF_TEXTRECORD_LANGUAGECODE_MAXSIZE\n");
+ DebugPrintf("\t Truncating from %d to MaxSize of %d.\n",
+ sTextRecord.sStatusByte.ui5LengthLangCode,
+ NDEF_TEXTRECORD_LANGUAGECODE_MAXSIZE);
+ }
+
+ //
+ // Fill LanguageCode in buffer
+ //
+ for(x = 0;x < sTextRecord.sStatusByte.ui5LengthLangCode;x++)
+ {
+ pui8Buffer[ui32RecordIndex] = sTextRecord.pui8LanguageCode[x];
+ ui32RecordIndex++;
+ }
+
+ //
+ // Error Check
+ //
+ if((ui32RecordIndex + sTextRecord.ui32TextLength) > ui16BufferMaxLength)
+ {
+ ASSERT(0);
+ DebugPrintf("ERR: NDEFTextRecordEncode: Buffer Overflow Immenant\n");
+ return STATUS_FAIL;
+ }
+
+ //
+ // Fill Text in buffer
+ //
+ for(x = 0;x < sTextRecord.ui32TextLength;x++)
+ {
+ pui8Buffer[ui32RecordIndex] = sTextRecord.pui8Text[x];
+ ui32RecordIndex++;
+ }
+
+ //
+ // Set buffer length
+ //
+ *pui32BufferLength = ui32RecordIndex;
+
+ return STATUS_SUCCESS;
+}
+
+//*****************************************************************************
+//
+//! Decode NDEF Text Records.
+//!
+//! \param psTextDataDecoded is a pointer to the TextRecord structure to decode
+//! the data into.
+//! \param pui8Buffer is a pointer to the raw NFC data buffer to be decoded.
+//! \param ui32BufferLength is the length of the raw NFC data buffer.
+//!
+//! This function takes a raw NFC data buffer and decodes the data into a Text
+//! record data structure. It is assumed that the raw data buffer contains a
+//! text record.
+//!
+//! \return This function returns \b STATUS_SUCCESS (1) or \b STATUS_FAIL (0).
+//
+//*****************************************************************************
+bool
+NFCP2P_NDEFTextRecordDecoder(sNDEFTextRecord *psTextDataDecoded,
+ uint8_t *pui8Buffer,
+ uint32_t ui32BufferLength)
+{
+ sNDEFTextRecord *psTextRecord;
+ uint8_t ui8StatusByte, ui8LengthLangCode, x = 0;
+ uint32_t ui32RecordIndex = 0;
+
+ //
+ // Validate Input
+ //
+ ASSERT(pui8Buffer != 0);
+ ASSERT(psTextDataDecoded != 0);
+ if(
+ (pui8Buffer == 0) ||
+ (psTextDataDecoded == 0)
+ )
+ {
+ DebugPrintf("ERR: TextRecordDecoder: Invalid Input\n");
+ return STATUS_FAIL;
+ }
+
+ //
+ // Initialize (done to insure 0 as sentinel in language Code)
+ //
+ psTextRecord = psTextDataDecoded;
+ for(x = 0;x < NDEF_TEXTRECORD_LANGUAGECODE_MAXSIZE;x++)
+ {
+ psTextRecord->pui8LanguageCode[x] = 0;
+ }
+ psTextRecord->ui32TextLength = 0;
+
+ //
+ // Load STATUSBYTE field
+ //
+ ui8StatusByte = pui8Buffer[ui32RecordIndex];
+ psTextRecord->sStatusByte.bUTFcode =
+ NDEF_TEXTRECORD_STATUSBYTE_GET_UTF(ui8StatusByte);
+ psTextRecord->sStatusByte.bRFU =
+ NDEF_TEXTRECORD_STATUSBYTE_GET_RFU(ui8StatusByte);
+ ui8LengthLangCode =
+ NDEF_TEXTRECORD_STATUSBYTE_GET_LENGTHLANGCODE(ui8StatusByte);
+ psTextRecord->sStatusByte.ui5LengthLangCode = ui8LengthLangCode;
+ ui32RecordIndex++;
+
+ //
+ // The StatusByte.RFU should always be 0, if this is not the case return
+ // failure
+ //
+ if(psTextRecord->sStatusByte.bRFU != 0)
+ {
+ ASSERT(0);
+ DebugPrintf("Err: NDEF TextRecord Decoder: StatusByte.RFU !=0\n");
+ return STATUS_FAIL;
+ }
+
+ //
+ // LengthLangCode must be > 0
+ //
+ if(ui8LengthLangCode <= 0)
+ {
+ ASSERT(0);
+ DebugPrintf("ERR: NDEFTextRecordDecoder: LengthLangCode <= 0\n");
+ return STATUS_FAIL;
+
+ }
+
+ //
+ // Load LANGUAGE_CODE field
+ //
+ for(x = 0;x < ui8LengthLangCode;x++)
+ {
+ //
+ // If space left in LanguageCode field put character in, otherwise
+ // truncate. (dont copy across, but do incriment through raw buffer)
+ //
+ if(x < NDEF_TEXTRECORD_LANGUAGECODE_MAXSIZE)
+ {
+ psTextRecord->pui8LanguageCode[x] = pui8Buffer[ui32RecordIndex];
+ ui32RecordIndex++;
+ }
+ else
+ {
+ ui32RecordIndex++;
+ }
+ }
+
+ //
+ // Validate Data
+ //
+ if(ui8LengthLangCode > NDEF_TEXTRECORD_LANGUAGECODE_MAXSIZE)
+ {
+ DebugPrintf("ERR: TextRecordDecoder: LengthLangCode > ");
+ DebugPrintf("NDEF_TEXTRECORD_LANGUAGECODE_MAXSIZE, truncating %d to %d",
+ ui8LengthLangCode,NDEF_TEXTRECORD_LANGUAGECODE_MAXSIZE);
+ DebugPrintf("\n");
+ psTextRecord->sStatusByte.ui5LengthLangCode =
+ NDEF_TEXTRECORD_LANGUAGECODE_MAXSIZE;
+ }
+
+ //
+ // Load pointer to Text
+ //
+ psTextRecord->pui8Text = pui8Buffer + ui32RecordIndex;
+
+ //
+ // Validate Data - make sure we dont overrun the buffer
+ //
+ if(ui32RecordIndex > ui32BufferLength)
+ {
+ ASSERT(0);
+ DebugPrintf("ERR: TextRecordDecoder: Text Length longer than payload.");
+ DebugPrintf("\n");
+ return STATUS_FAIL;
+ }
+ else
+ {
+ //
+ // Calculate Length of Text
+ // Length of text = Length of Record - RecordIndex to this point.
+ //
+ psTextRecord->ui32TextLength = ui32BufferLength-ui32RecordIndex;
+ }
+
+ return STATUS_SUCCESS;
+}
+
+//*****************************************************************************
+//
+//! Encode NDEF URI Records.
+//!
+//! \param sURIRecord is the URI Record Structure to be encoded.
+//! \param pui8Buffer is a pointer to the buffer to fill with the raw NFC data.
+//! \param ui16BufferMaxLength is the maximum number of bytes the buffer
+//! can hold. This parameter is used to prevent writing past the end of the
+//! buffer.
+//! \param pui32BufferLength is a pointer to the integer to hold the length of
+//! the raw NFC data buffer.
+//!
+//! This function takes a URI Record structure and encodes it into a provided
+//! buffer in a raw NFC data format. The length of the data stored in the buffer
+//! is stored in \e \b pui32BufferLength.
+//!
+//! \return This function returns \b STATUS_SUCCESS (1) or \b STATUS_FAIL (0).
+//
+//*****************************************************************************
+bool
+NFCP2P_NDEFURIRecordEncoder(sNDEFURIRecord sURIRecord,
+ uint8_t *pui8Buffer,
+ uint16_t ui16BufferMaxLength,
+ uint32_t *pui32BufferLength)
+{
+ uint32_t ui32RecordIndex = 0;
+ uint8_t x = 0;
+
+ //
+ // Validate Input
+ //
+ ASSERT(pui8Buffer != 0);
+ ASSERT(ui16BufferMaxLength !=0);
+ ASSERT((sURIRecord.ui32URILength +1) < ui16BufferMaxLength);
+ if(
+ (pui8Buffer == 0) ||
+ (ui16BufferMaxLength ==0) ||
+ ((sURIRecord.ui32URILength +1) > ui16BufferMaxLength)
+ )
+ {
+ ASSERT(0);
+ DebugPrintf("ERR: URIRecordEncoder: Invalid Input\n");
+ return STATUS_FAIL;
+ }
+
+ //
+ // Fill IDCode field in buffer
+ //
+ pui8Buffer[ui32RecordIndex] = sURIRecord.eIDCode;
+ ui32RecordIndex++;
+
+ //
+ // Fill UTF8 string into buffer
+ //
+ for(x = 0;x < sURIRecord.ui32URILength;x++)
+ {
+ pui8Buffer[ui32RecordIndex] = sURIRecord.puiUTF8String[x];
+ ui32RecordIndex++;
+ }
+
+ //
+ // Set Buffer Length
+ //
+ *pui32BufferLength = ui32RecordIndex;
+
+ return STATUS_SUCCESS;
+
+}
+
+//*****************************************************************************
+//
+//! Decode NDEF URI Records.
+//!
+//! \param sURIRecord is a pointer to the URIRecord structure into which to
+//! decode the data.
+//! \param pui8Buffer is a pointer to the raw NFC data buffer to be decoded.
+//! \param ui32BufferLength is the length of the raw NFC data buffer.
+//!
+//! This function takes a raw NFC data buffer and decodes the data into a URI
+//! record data structure. It is assumed that the raw data buffer contains a
+//! URI record.
+//!
+//! \return This function returns \b STATUS_SUCCESS (1) or \b STATUS_FAIL (0).
+//
+//*****************************************************************************
+bool
+NFCP2P_NDEFURIRecordDecoder(sNDEFURIRecord *sURIRecord,
+ uint8_t *pui8Buffer,
+ uint32_t ui32BufferLength)
+{
+ uint32_t ui32RecordIndex = 0;
+
+ //
+ // Validate Input
+ //
+ ASSERT(pui8Buffer != 0);
+ ASSERT(sURIRecord != 0);
+ if(
+ (pui8Buffer == 0) ||
+ (sURIRecord == 0)
+ )
+ {
+ DebugPrintf("ERR: URIRecordDecoder: Invalid Input\n");
+ return STATUS_FAIL;
+ }
+
+ //
+ // Load eIDCode field into struct
+ // error check that the ID code is valid.
+ //
+ if(pui8Buffer[ui32RecordIndex] >= NDEF_URIRECORD_IDCODE_RFU)
+ {
+ //
+ // IDCode not recognized, skip it.
+ // (can add codes in nfc_p2p.h eNDEF_URIRecord_IDCode enumeration)
+ //
+ DebugPrintf("ERR: URI Record Decoder: URI ID Code Not Recognized: 0x%x\n"
+ ,pui8Buffer[ui32RecordIndex]);
+ sURIRecord->eIDCode = RFU;
+ ui32RecordIndex++;
+ //return STATUS_FAIL;
+ }
+ else
+ {
+ //
+ // ID Code is Valid, set it.
+ //
+ sURIRecord->eIDCode = pui8Buffer[ui32RecordIndex];
+ ui32RecordIndex++;
+ }
+
+ //
+ // Load UTF8 String Pointer into struct
+ //
+ sURIRecord->puiUTF8String = pui8Buffer + ui32RecordIndex;
+
+ //
+ // Load URI string Length into struct
+ //
+ sURIRecord->ui32URILength = ui32BufferLength-ui32RecordIndex;
+
+ return STATUS_SUCCESS;
+}
+
+//*****************************************************************************
+//
+//! Encode NDEF SmartPoster Records.
+//!
+//! \param sSmartPoster is the SmartPoster Record Structure to be encoded.
+//! \param pui8Buffer is a pointer to the buffer to fill with the raw NFC data.
+//! \param ui16BufferMaxLength is the maximum number of bytes the buffer
+//! can hold. This parameter is used to prevent writing past the end of the
+//! buffer.
+//! \param pui32BufferLength is a pointer to the integer to hold the length of
+//! the raw NFC data buffer.
+//!
+//! This function takes a SmartPoster record structure and encodes it into a
+//! provided buffer in a raw NFC data format. The length of the data stored in
+//! the buffer is stored in \e \b pui32BufferLength.
+//!
+//! \note It is assumed that all smart poster messages have a Text record and a
+//! URI record.
+//!
+//! \return This function returns \b STATUS_SUCCESS (1) or \b STATUS_FAIL (0).
+//
+// Note: This function works by first encoding the Record, then the Header.
+// The Header comes before the Record. Thus space is allocated in the
+// buffer for the Header before the buffer is passed to the encoder. The
+// extra space will be taken care of by the Header encoder function
+// (aka NDEFMessageEncoder).
+//
+//
+//*****************************************************************************
+bool
+NFCP2P_NDEFSmartPosterRecordEncoder(sNDEFSmartPosterRecord sSmartPoster,
+ uint8_t *pui8Buffer,
+ uint16_t ui16BufferMaxLength,
+ uint32_t *pui32BufferLength)
+{
+ //
+ // RECORD_OFFSET is the max size of the header. The magic number 7 comes
+ // from the size of the Statusbyte[1]+PayloadLength[4]+IDLength[1]+
+ // TypeLength[1]. This is done to ensure that there is space
+ // left in the buffer for the header while the record is encoding.
+ //
+ #define RECORD_OFFSET (NDEF_TYPE_MAXSIZE+NDEF_ID_MAXSIZE+7)
+
+ bool bStatus = STATUS_SUCCESS;
+
+ uint32_t ui32TotalLength = 0;
+ uint32_t ui32RecordLength = 0;
+
+ uint8_t *pui8CurrHeaderPt = pui8Buffer;
+ uint8_t *pui8CurrRecordPt = pui8CurrHeaderPt + RECORD_OFFSET;
+
+ //
+ // Validate Data
+ //
+ ASSERT(ui16BufferMaxLength != 0);
+ ASSERT(pui8Buffer != 0);
+
+ //
+ // Encode TextMessage, Update Payload Ptr and Payload Length in Header,
+ // Encode TextHeader (included TextPayload)
+ //
+ bStatus = NFCP2P_NDEFTextRecordEncoder(sSmartPoster.sTextPayload,
+ pui8CurrRecordPt,
+ (ui16BufferMaxLength -
+ (pui8CurrRecordPt - pui8Buffer)),
+ &ui32RecordLength);
+ sSmartPoster.sTextHeader.ui32PayloadLength = ui32RecordLength;
+ sSmartPoster.sTextHeader.pui8PayloadPtr = pui8CurrRecordPt;
+ if(STATUS_FAIL == bStatus)
+ {
+ DebugPrintf(" ERR: SmartPoster TextRecord Encode FAIL.\n");
+ return bStatus;
+ }
+
+ bStatus = NFCP2P_NDEFMessageEncoder(sSmartPoster.sTextHeader,
+ pui8CurrHeaderPt,
+ (ui16BufferMaxLength -
+ (pui8CurrHeaderPt - pui8Buffer)),
+ &ui32RecordLength);
+ pui8CurrHeaderPt = pui8CurrHeaderPt + ui32RecordLength;
+ pui8CurrRecordPt = pui8CurrHeaderPt + RECORD_OFFSET;
+ if(STATUS_FAIL == bStatus)
+ {
+ DebugPrintf(" ERR: SmartPoster TextRecord Header Encode FAIL.\n");
+ return bStatus;
+ }
+ ui32TotalLength += ui32RecordLength;
+
+ //
+ // Encode URIMessage, Update Payload Ptr and Payload Length in Header,
+ // Encode URIHeader (included URIPayload)
+ //
+ bStatus = NFCP2P_NDEFURIRecordEncoder(sSmartPoster.sURIPayload,
+ pui8CurrRecordPt,
+ (ui16BufferMaxLength -
+ (pui8CurrRecordPt - pui8Buffer)),
+ &ui32RecordLength);
+ sSmartPoster.sURIHeader.ui32PayloadLength = ui32RecordLength;
+ sSmartPoster.sURIHeader.pui8PayloadPtr = pui8CurrRecordPt;
+ if(STATUS_FAIL == bStatus)
+ {
+ DebugPrintf(" ERR: SmartPoster URIRecord Encode FAIL.\n");
+ return bStatus;
+ }
+ bStatus = NFCP2P_NDEFMessageEncoder(sSmartPoster.sURIHeader,
+ pui8CurrHeaderPt,
+ (ui16BufferMaxLength -
+ (pui8CurrHeaderPt - pui8Buffer)),
+ &ui32RecordLength);
+ pui8CurrHeaderPt = pui8CurrHeaderPt + ui32RecordLength;
+ pui8CurrRecordPt = pui8CurrHeaderPt + RECORD_OFFSET;
+ ui32TotalLength += ui32RecordLength;
+ if(STATUS_FAIL == bStatus)
+ {
+ DebugPrintf(" ERR: SmartPoster URIRecord Header Encode FAIL.\n");
+ return bStatus;
+ }
+
+ //
+ // Encode ActionMessage, Update Payload Ptr and Payload Length in Header,
+ // Encode ActionHeader (included ActionPayload)
+ //
+ if(sSmartPoster.bActionExists)
+ {
+ //
+ // The Action Record has no Encoder / Decoder because it is just 1 byte
+ // of data. So it is hard coded into the Smart Poster Encoder / Decoder
+ //
+ pui8CurrRecordPt[0] = sSmartPoster.sActionPayload.eAction;
+ sSmartPoster.sActionHeader.ui32PayloadLength = 1;
+ sSmartPoster.sActionHeader.pui8PayloadPtr = pui8CurrRecordPt;
+ bStatus = NFCP2P_NDEFMessageEncoder(sSmartPoster.sActionHeader,
+ pui8CurrHeaderPt,
+ (ui16BufferMaxLength -
+ (pui8CurrHeaderPt - pui8Buffer)),
+ &ui32RecordLength);
+ pui8CurrHeaderPt = pui8CurrHeaderPt + ui32RecordLength;
+ pui8CurrRecordPt = pui8CurrHeaderPt + RECORD_OFFSET;
+ ui32TotalLength += ui32RecordLength;
+ if(STATUS_FAIL == bStatus)
+ {
+ DebugPrintf(" ERR: SmartPoster ActionRecord Encode FAIL.\n");
+ return bStatus;
+ }
+ }
+
+ //
+ // Check for buffer overflow. This should be caught in the lower level
+ // encode functions, but just to be safe we check for it here as well.
+ //
+ if(ui32TotalLength > ui16BufferMaxLength)
+ {
+ DebugPrintf(" ERR: SmartPosterRecordEncoder : Buffer Overflow.\n");
+ return STATUS_FAIL;
+ }
+
+ //
+ // Return Buffer Length
+ //
+ *pui32BufferLength = ui32TotalLength;
+
+ return STATUS_SUCCESS;
+}
+
+//*****************************************************************************
+//
+//! Decode NDEF SmartPoster Records.
+//!
+//! \param sSmartPoster is a pointer to the SmartPosterRecord structure into
+//! which to decode the data.
+//! \param pui8Buffer is a pointer to the raw NFC data buffer to be decoded.
+//! \param ui16BufferMaxLength is the maximum number of bytes the buffer
+//! can hold. This parameter is used to prevent reading past the end of the
+//! buffer.
+//! \param ui32BufferLength is the length of the raw NFC data buffer.
+//!
+//! This function takes a raw NFC data buffer and decodes the data into a
+//! SmartPoster record data structure. It is assumed that the raw data buffer
+//! contains a SmartPoster record.
+//!
+//! \return This function returns \b STATUS_SUCCESS (1) or \b STATUS_FAIL (0).
+//!
+//! \note Currently only Title, Action and URI records are supported.
+//! Other records are skipped and ignored.
+//
+//*****************************************************************************
+bool
+NFCP2P_NDEFSmartPosterRecordDecoder(sNDEFSmartPosterRecord *sSmartPoster,
+ uint8_t *pui8Buffer,
+ uint16_t ui16BufferMaxLength,
+ uint32_t ui32BufferLength)
+{
+ sNDEFMessageData sCurrentHeader; //temp Header Info
+ uint32_t ui32RecordIndex = 0;
+ uint8_t *pui8CurrHeaderPt;
+ uint8_t x = 0;
+ bool bCheck = STATUS_SUCCESS;
+ uint64_t TypeID = 0;
+
+ //
+ // Initialize
+ //
+ sSmartPoster->bActionExists = false;
+
+ //
+ // Process through Payload for Smart Poster.
+ // Assume first header at pui8Buffer[0]
+ // Process and fill
+ //
+ while(ui32RecordIndex < ui32BufferLength)
+ {
+ //
+ // Pointer to Header
+ //
+ pui8CurrHeaderPt = pui8Buffer+ui32RecordIndex;
+
+ //
+ // Decode Current Header, in this case the
+ //
+ bCheck = NFCP2P_NDEFMessageDecoder(&sCurrentHeader,
+ pui8CurrHeaderPt,
+ (ui16BufferMaxLength -
+ (pui8CurrHeaderPt - pui8Buffer))
+ );
+ if(STATUS_FAIL == bCheck)
+ {
+ DebugPrintf("ERR: SPDecoder: SP NDEFMessageDecoder Failed\n");
+ return STATUS_FAIL;
+ }
+ //
+ // Check for buffer read overrun. This would be caused by bad data.
+ // This goes off when you try to read past the end of the buffer.
+ //
+ if((sCurrentHeader.ui32PayloadLength +
+ (sCurrentHeader.pui8PayloadPtr - pui8Buffer))
+ > ui16BufferMaxLength)
+ {
+ DebugPrintf("ERR: SPDecoder: BufferRead Overrun. Bad Data.");
+ return STATUS_FAIL;
+ }
+
+ //
+ // Calculate Record Type
+ //
+ for(x = 0,TypeID = 0;x < sCurrentHeader.ui8TypeLength;x++)
+ {
+ TypeID = (TypeID << 8) + sCurrentHeader.pui8Type[x];
+ }
+
+ //
+ // Decode Header into appropriate part of SmartPoster struct
+ // Call decoder function for each header type
+ //
+ switch(TypeID)
+ {
+ //
+ // Text Record
+ //
+ case NDEF_TYPE_TEXT:
+ {
+ bCheck = NFCP2P_NDEFMessageDecoder(&sSmartPoster->sTextHeader,
+ pui8CurrHeaderPt,
+ (ui16BufferMaxLength -
+ (pui8CurrHeaderPt - pui8Buffer))
+ );
+ if(STATUS_FAIL == bCheck)
+ {
+ DebugPrintf(
+ " ERR: SPDecoder: Text NDEFMessageDecoder Failed\n");
+ return STATUS_FAIL;
+ }
+ bCheck = NFCP2P_NDEFTextRecordDecoder(
+ &sSmartPoster->sTextPayload,
+ sSmartPoster->sTextHeader.pui8PayloadPtr,
+ sSmartPoster->sTextHeader.ui32PayloadLength
+ );
+ if(STATUS_FAIL == bCheck)
+ {
+ DebugPrintf(
+ " ERR: SPDecoder: NDEFTextRecordDecoder Failed\n");
+ return STATUS_FAIL;
+ }
+ break;
+ }
+
+ //
+ // URI Record
+ //
+ case NDEF_TYPE_URI:
+ {
+ bCheck = NFCP2P_NDEFMessageDecoder(&sSmartPoster->sURIHeader,
+ pui8CurrHeaderPt,
+ (ui16BufferMaxLength -
+ (pui8CurrHeaderPt - pui8Buffer))
+ );
+ if(STATUS_FAIL == bCheck)
+ {
+ DebugPrintf(
+ " ERR: SPDecoder: URI NDEFMessageDecoder Failed\n");
+ return STATUS_FAIL;
+ }
+ bCheck = NFCP2P_NDEFURIRecordDecoder(
+ &sSmartPoster->sURIPayload,
+ sSmartPoster->sURIHeader.pui8PayloadPtr,
+ sSmartPoster->sURIHeader.ui32PayloadLength
+ );
+ if(STATUS_FAIL == bCheck)
+ {
+ DebugPrintf(\
+ " ERR: SPDecoder: NDEFURIMessageDecoder Failed\n");
+ return STATUS_FAIL;
+ }
+ break;
+ }
+
+ //
+ // Action Record (built in type to SmartPoster, no need for external
+ // functions)
+ //
+ case NDEF_TYPE_ACTION:
+ {
+ sSmartPoster->bActionExists = true;
+ bCheck = NFCP2P_NDEFMessageDecoder(&sSmartPoster->sActionHeader,
+ pui8CurrHeaderPt,
+ (ui16BufferMaxLength -
+ (pui8CurrHeaderPt - pui8Buffer))
+ );
+ if(STATUS_FAIL == bCheck)
+ {
+ DebugPrintf(
+ " ERR: SPDecoder: Action NDEFMessageDecoder Failed\n");
+ return STATUS_FAIL;
+ }
+ sSmartPoster->sActionPayload.eAction =
+ sSmartPoster->sActionHeader.pui8PayloadPtr[0];
+ break;
+ }
+
+ //
+ // Other record type, not supported, so skip it.
+ //
+ default:
+ {
+ DebugPrintf("NDEFSmartPosterDecode: Record Not recognized: 0x%x\n"
+ ,TypeID);
+ break;
+ }
+ }
+
+ //
+ // Incriment ui32RecordIndex
+ // (sCurrentHeader.pui8PayloadPtr-pui8CurrHeaderPt) = size of header
+ // when added to payload length this gives the total record size
+ //
+ ui32RecordIndex += (sCurrentHeader.pui8PayloadPtr-pui8CurrHeaderPt)
+ + sCurrentHeader.ui32PayloadLength;
+ }
+
+ return STATUS_SUCCESS;
+}
+
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
diff --git a/nfclib/nfc_p2p.h b/nfclib/nfc_p2p.h
new file mode 100644
index 0000000..d0a7136
--- /dev/null
+++ b/nfclib/nfc_p2p.h
@@ -0,0 +1,1536 @@
+//*****************************************************************************
+//
+// nfc_p2p.h - contains P2P State Machine NDEF P2P Record Type Structures
+//
+// Copyright (c) 2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
+//
+//*****************************************************************************
+#ifndef __NFC_P2P_H__
+#define __NFC_P2P_H__
+
+//*****************************************************************************
+//
+//! \addtogroup nfc_p2p_api
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// NFC Protocol Headers
+//
+//*****************************************************************************
+#include "nfc_f.h"
+#include "nfc_dep.h"
+#include "llcp.h"
+#include "snep.h"
+
+//*****************************************************************************
+//
+// TRF7970 Header
+//
+//*****************************************************************************
+#include "trf79x0.h"
+
+//*****************************************************************************
+//
+//! Enumeration for 4 possible states for NFC P2P State Machine.
+//
+//*****************************************************************************
+typedef enum {
+ //
+ //! Polling/Listening for SENSF_REQ / SENSF_RES.
+ //
+ NFC_P2P_PROTOCOL_ACTIVATION = 0,
+
+ //
+ //! Setting the NFCIDs and bit rate
+ //
+ NFC_P2P_PARAMETER_SELECTION,
+
+ //
+ //! Data exchange using the LLCP layer
+ //
+ NFC_P2P_DATA_EXCHANGE_PROTOCOL,
+
+ //
+ //! Technology deactivation
+ //
+ NFC_P2P_DEACTIVATION
+
+} tNFCP2PState;
+
+//*****************************************************************************
+//
+//! This structure defines the status of the received payload.
+//
+//*****************************************************************************
+typedef struct{
+
+ //
+ //! SNEP RX Packet Status
+ //
+ tPacketStatus eDataReceivedStatus;
+
+ //
+ //! SNEP Number of bytes received
+ //
+ uint8_t ui8DataReceivedLength;
+
+ //
+ //! Pointer to data received
+ //
+ uint8_t *pui8RxDataPtr;
+
+}sNFCP2PRxStatus;
+
+//*****************************************************************************
+//
+// Programmers Note: NDEF message layout
+//
+// The fields in an NDEF header are as follows:
+// ______________________________
+// | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0| Notes:
+// |------------------------------|
+// | MB| ME| CF| SR| IL| TNF | NDEF StatusByte
+// |------------------------------|
+// | TYPE_LENGTH | 1 byte, hex value
+// |------------------------------|
+// | PAYLOAD_LENGTH | 1 or 4 bytes (determined by SR) (LSB first)
+// |------------------------------|
+// | ID_LENGTH | 0 or 1 bytes (determined by IL)
+// |------------------------------|
+// | TYPE | 2 or 5 bytes (determined by TYPE_LENGTH)
+// |------------------------------|
+// | ID | 0 or 1 byte (determined by IL & ID_LENGTH)
+// |------------------------------|
+// | PAYLOAD | X bytes (determined by PAYLOAD_LENGTH)
+// |------------------------------|
+// NDEF messages NDEF messages can be considered as two parts:
+// The Header (everything except the last field), and the Payload.
+//
+// **********
+// HEADER
+// **********
+// The Header encompases Everything in the above diagram except the PAYLOAD
+// The Header can vary in length from 5-13 bytes.
+// The PAYLOAD_LENGTH, ID_LENGTH, ID, and TYPE fields can all very in length.
+//
+// Field Name | Length Depends On | Length
+// ------------------------------------------------
+// PAYLOAD LENGTH | SR | SR = 1 => 1 byte , SR = 0 => 4 bytes
+// ID_LENGTH | IL | IL = 0 (if IL = 0 Both ID_LENGTH and
+// ID fields are excluded.
+// If IL = 1 then ID_LENGTH
+// exists. If ID_LENGTH = 0x0
+// then the ID field is
+// not included)
+// TYPE | TYPE_LENGTH | 2-5 bytes (hex value of TYPE_LENGTH)
+// (In special cases there can be
+// a TYPE_LENGTH of 0, in which
+// case there is no TYPE field.)
+//
+// Note: PAYLOAD_LENGTH only gives the length of the PAYLOAD in its message.
+// The PAYLOAD_LENGTH does NOT give the length of the record across
+// multiple messages..
+//
+// ***********
+// PAYLOAD
+// ***********
+// The Payload can have a wide range of formats depending on the TNF and TYPE
+// specified. (IE a TNF of 0x01 aka WELL_KNOWN_TYPE and a TYPE of 'T' would
+// indicate a plain text payload, which has its own syntax). The user can even
+// implement their own PAYLOAD type, providing handlers are provided on both the
+// sending and receiving devices.
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// NDEF message header definitions
+// SET macros are used to set the bit (encoder)
+// GET macros are used to read the bit (decoder)
+//
+//*****************************************************************************
+
+//
+//! This macro is used to set the MB field in the StatusByte of the NFC message header by
+//! shifting a bit into position. This define should be ORed together with other StatusByte
+//! Fields.
+//!
+//! \param ui8x is the binary value to be shifted into place
+//!
+//! \b Example: Set the MB field in a StatusByte
+//!
+//! <tt>sNDEFMessage.sStatusByte = sNDEFMessage.sStatusByte |
+//! NDEF_STATUSBYTE_SET_MB(0x1) </tt>
+//!
+//! \b Example: Clear the MB field in a StatusByte
+//!
+//! <tt>sNDEFMessage.sStatusByte = sNDEFMessage.sStatusByte &
+//! NDEF_STATUSBYTE_SET_MB(0x0) </tt>
+//!
+//
+#define NDEF_STATUSBYTE_SET_MB(ui8x) ((ui8x & 0x01) << 7)
+
+//
+//! This macro is used to set the ME field in the StatusByte of the NFC message
+//! header by shifting a bit into position. This define should be ORed together
+//! with other StatusByte Fields.
+//!
+//! \param ui8x is the binary value to be shifted into place
+//!
+//! \b Example: Set the ME field in a StatusByte
+//!
+//! <tt>sNDEFMessage.sStatusByte = sNDEFMessage.sStatusByte |
+//! NDEF_STATUSBYTE_SET_ME(0x1) </tt>
+//!
+//! \b Example: Clear the ME field in a StatusByte
+//!
+//! <tt>sNDEFMessage.sStatusByte = sNDEFMessage.sStatusByte &
+//! NDEF_STATUSBYTE_SET_ME(0x0) </tt>
+//!
+//
+#define NDEF_STATUSBYTE_SET_ME(ui8x) ((ui8x & 0x01) << 6)
+
+//
+//! This Macro is used to set the CF field in the StatusByte of the NFC message
+//! header by shifting a bit into position. This define should be ORed together
+//! with other StatusByte Fields.
+//!
+//! \param ui8x is the binary value to be shifted into place
+//!
+//! \b Example: Set the CF field in a StatusByte
+//!
+//! <tt>sNDEFMessage.sStatusByte = sNDEFMessage.sStatusByte |
+//! NDEF_STATUSBYTE_SET_CF(0x1) </tt>
+//!
+//! \b Example: Clear the CF field in a StatusByte
+//!
+//! <tt>sNDEFMessage.sStatusByte = sNDEFMessage.sStatusByte &
+//! NDEF_STATUSBYTE_SET_CF(0x0) </tt>
+//!
+//
+#define NDEF_STATUSBYTE_SET_CF(ui8x) ((ui8x & 0x01) << 5)
+
+//
+//! This macro is used to set the SR field in the StatusByte of the NFC message
+//! header by shifting a bit into position. This define should be ORed together
+//! with other StatusByte Fields.
+//!
+//! \param ui8x is the binary value to be shifted into place
+//!
+//! \b Example: Set the SR field in a StatusByte
+//!
+//! <tt>sNDEFMessage.sStatusByte = sNDEFMessage.sStatusByte |
+//! NDEF_STATUSBYTE_SET_SR(0x1) </tt>
+//!
+//! \b Example: Clear the SR field in a StatusByte
+//!
+//! <tt>sNDEFMessage.sStatusByte = sNDEFMessage.sStatusByte &
+//! NDEF_STATUSBYTE_SET_SR(0x0) </tt>
+//!
+//
+#define NDEF_STATUSBYTE_SET_SR(ui8x) ((ui8x & 0x01) << 4)
+
+//
+//! This macro is used to set the IL field in the StatusByte of the NFC message header by
+//! shifting a bit into position. This define should be ORed together with other StatusByte
+//! Fields.
+//!
+//! \param ui8x is the binary value to be shifted into place
+//!
+//! \b Example: Set the IL field in a StatusByte
+//!
+//! <tt>sNDEFMessage.sStatusByte = sNDEFMessage.sStatusByte |
+//! NDEF_STATUSBYTE_SET_IL(0x1) </tt>
+//!
+//! \b Example: Clear the IL field in a StatusByte
+//!
+//! <tt>sNDEFMessage.sStatusByte = sNDEFMessage.sStatusByte &
+//! NDEF_STATUSBYTE_SET_IL(0x0) </tt>
+//!
+//
+#define NDEF_STATUSBYTE_SET_IL(ui8x) ((ui8x & 0x01) << 3)
+
+//
+//! This macro is used to set the TNF field in the StatusByte of the NFC message
+//! header by shifting a bit into position. This define should be ORed together
+//! with other StatusByte Fields.
+//!
+//! \param ui8x is the 3-bit value to be shifted into place
+//!
+//! \b Example: Set the TNF field to Well Known Type in a StatusByte
+//!
+//! <tt>NsNDEFMessage.sStatusByte = sNDEFMessage.sStatusByte |
+//! NDEF_STATUSBYTE_SET_TNF(0x1) </tt>
+//!
+//! \b Example: Set the TNF field to Unknown Type in a StatusByte
+//!
+//! <tt>sNDEFMessage.sStatusByte = sNDEFMessage.sStatusByte &
+//! NDEF_STATUSBYTE_SET_TNF(0x5) </tt>
+//!
+//
+#define NDEF_STATUSBYTE_SET_TNF(ui8x) ((ui8x & 0x07) << 0)
+
+//
+//! Macro used to get the MB field value from the StatusByte of the NFC message
+//! header.
+//!
+//! \param ui8x is the 8-bit StatusByte
+//!
+//! \b Example: Get the MB field from the StatusByte into variable x
+//!
+//! <tt>x = NDEF_STATUSBYTE_GET_MB(sNDEFMessageData.sStatusByte) </tt>
+//!
+//
+#define NDEF_STATUSBYTE_GET_MB(ui8x) ((ui8x >> 7) & 0x01)
+
+//
+//! Macro used to get the ME field value from the StatusByte of the NFC message
+//! header.
+//!
+//! \param ui8x is the 8-bit StatusByte
+//!
+//! \b Example: Get the ME field from the StatusByte into variable x
+//!
+//! <tt>x = NDEF_STATUSBYTE_GET_ME(sNDEFMessageData.sStatusByte) </tt>
+//!
+//
+#define NDEF_STATUSBYTE_GET_ME(ui8x) ((ui8x >> 6) & 0x01)
+
+//
+//! Macro used to get the CF field value from the StatusByte of the NFC message
+//! header.
+//!
+//! \param ui8x is the 8-bit StatusByte
+//!
+//! \b Example: Get the CF field from the StatusByte into variable x
+//!
+//! <tt>x = NDEF_STATUSBYTE_GET_CF(sNDEFMessageData.sStatusByte) </tt>
+//!
+//
+#define NDEF_STATUSBYTE_GET_CF(ui8x) ((ui8x >> 5) & 0x01)
+
+//
+//! Macro used to get the SR field value from the StatusByte of the NFC message
+//! header.
+//!
+//! \param ui8x is the 8-bit StatusByte
+//!
+//! \b Example: Get the SR field from the StatusByte into variable x
+//!
+//! <tt>x = NDEF_STATUSBYTE_GET_SR(sNDEFMessageData.sStatusByte) </tt>
+//!
+//
+#define NDEF_STATUSBYTE_GET_SR(ui8x) ((ui8x >> 4) & 0x01)
+
+//
+//! Macro used to get the IL field value from the StatusByte of the NFC message
+//! header.
+//!
+//! \param ui8x is the 8-bit StatusByte
+//!
+//! \b Example: Get the IL field from the StatusByte into variable x
+//!
+//! <tt>x = NDEF_STATUSBYTE_GET_IL(sNDEFMessageData.sStatusByte) </tt>
+//!
+//
+#define NDEF_STATUSBYTE_GET_IL(ui8x) ((ui8x >> 3) & 0x01)
+
+//
+//! Macro used to get the TNF field value from the StatusByte of the NFC message
+//! header.
+//!
+//! \param ui8x is the 8-bit StatusByte
+//!
+//! \b Example: Get the TNF field from the StatusByte into variable x
+//!
+//! <tt>x = NDEF_STATUSBYTE_GET_TNF(sNDEFMessageData.sStatusByte) </tt>
+//!
+//
+#define NDEF_STATUSBYTE_GET_TNF(ui8x) ((ui8x >> 0) & 0x07)
+
+//*****************************************************************************
+//
+// Defines to check Header StatusByte field meaning. Some cases left out
+// because they are irrelevant (ie only care when MB is 1 or not 1, dont care
+// about 0)
+//
+//*****************************************************************************
+
+//
+//! Flag used to check the MB field in the StatusByte. If MB is set then this is
+//! the first Record.
+//!
+//! \b Example: Check for Message Begin flag
+//!
+//! <tt>if(NDEF_STATUSBYTE_GET_MB(ui8StatusByte) ==
+//! NDEF_STATUSBYTE_MB_FIRSTBYTE){} </tt>
+//
+#define NDEF_STATUSBYTE_MB_FIRSTBYTE 1
+
+//
+//! Flag used to check the ME field in the StatusByte. If ME is set, then this
+//! is the last Record.
+//!
+//! \b Example: Check for Message End flag
+//!
+//! <tt>if(NDEF_STATUSBYTE_GET_ME(ui8StatusByte) == NDEF_STATUSBYTE_ME_LASTBYTE)
+//! {} </tt>
+//
+#define NDEF_STATUSBYTE_ME_LASTBYTE 1
+
+//
+//! Flag used to check the CF field in the StatusByte. If CF is set, then the
+//! message is a chunked message spread out across multiple transactions.
+//!
+//! \b Example: Check for Chunked Flag
+//!
+//! <tt>if(NDEF_STATUSBYTE_GET_CF(ui8StatusByte) == NDEF_STATUSBYTE_CF_CHUNK)
+//! {} </tt>
+//
+#define NDEF_STATUSBYTE_CF_CHUNK 1
+
+//
+//! Flag used to check the SR field in the StatusByte. If SR is set, then
+//! the message is a short record with a payload length field of 1 byte instead
+//! of 4 bytes.
+//!
+//! \b Example: Check the Short Record flag
+//!
+//! <tt>if(NDEF_STATUSBYTE_GET_SR(ui8StatusByte) ==
+//! NDEF_STATUSBYTE_SR_1BYTEPAYLOADSIZE){} </tt>
+//
+#define NDEF_STATUSBYTE_SR_1BYTEPAYLOADSIZE 1
+
+//
+//! Flag used to check the SR field in the StatusByte. If SR is not set, then
+//! the message is a normal record with a payload length field of 4 bytes
+//! instead of 1 byte.
+//!
+//! \b Example: Check the Short Record flag
+//!
+//! <tt>if(NDEF_STATUSBYTE_GET_SR(ui8StatusByte) ==
+//! NDEF_STATUSBYTE_SR_4BYTEPAYLOADSIZE){} </tt>
+//
+#define NDEF_STATUSBYTE_SR_4BYTEPAYLOADSIZE 0
+
+//
+//! Flag used to check the IL field in the StatusByte. If IL is set, then the ID
+//! and IDLength fields are present in the message.
+//!
+//! \b Example: Check for the presence of the ID Length and ID name field
+//!
+//! <tt>if(NDEF_STATUSBYTE_GET_IL(ui8StatusByte) ==
+//! NDEF_STATUSBYTE_IL_IDLENGTHPRESENT) {} </tt>
+//
+#define NDEF_STATUSBYTE_IL_IDLENGTHPRESENT 1
+
+//
+//! Flag used to check the IL field in the StatusByte. If IL is not set, then
+//! there is no ID or IDLength fields included in the message.
+//!
+//! \b Example: Check for the presence of the ID Length and ID name field
+//!
+//! <tt>if(NDEF_STATUSBYTE_GET_IL(ui8StatusByte) ==
+//! NDEF_STATUSBYTE_IL_IDLENGTHABSENT) {} </tt>
+//
+#define NDEF_STATUSBYTE_IL_IDLENGTHABSENT 0
+
+//*****************************************************************************
+//
+// Defines to set maximum field lengths in bytes
+//
+//*****************************************************************************
+
+//
+//! Maximum size of Type field in StatusByte. This define is used to declare the
+//! length of the buffer in the structure and thus can be changed to allow
+//! larger Type names.
+//!
+//! \b Example: Copy the Type from raw buffer to structure using
+//! NDEF_TYPE_MAXSIZE to prevent overflowing buffer in the
+//! structure
+//!
+//! <tt>
+//! \verbatim
+//! //
+//! // Assume that TypeLength is already decoded from the raw buffer and is
+//! // stored in sNDEFMessageData.ui8TypeLength. Assume ui8RawBuffer is a
+//! // pointer to the beginning of the Type field in the raw data stream.
+//! //
+//! int x = 0;
+//! for(x = 0; (x<NDEF_TYPE_MAXSIZE) & (x<sNDEFMessageData.ui8TypeLength); x++)
+//! {
+//! sNDEFMessageData.pui8Type[x]=ui8RawBuffer[x];
+//! }
+//! \endverbatim
+//! </tt>
+//
+#define NDEF_TYPE_MAXSIZE 10 // can be changed
+
+//
+//! Maximum size of the ID field in StatusByte, which can be modified to support
+//! larger ID names.
+//!
+//! \b Example: Copy the ID from the raw buffer to the structure using
+//! NDEF_ID_MAXSIZE to prevent overflowing buffer in the structure
+//!
+//! <tt>
+//! \verbatim
+//! //
+//! // Assume IDLength already decoded from the raw buffer is stored in
+//! // sNDEFMessageData.ui8IDLength. Assume ui8RawBuffer is a pointer to
+//! // the beginning of the ID field in the raw data stream.
+//! //
+//! int x = 0;
+//! for(x = 0; (x<NDEF_ID_MAXSIZE) & (x<sNDEFMessageData.ui8IDLength); x++)
+//! {
+//! sNDEFMessageData.pui8pui8ID[x] = ui8RawBuffer[x];
+//! }
+//! \endverbatim
+//! </tt>
+//
+#define NDEF_ID_MAXSIZE 10 // can be changed
+
+//*****************************************************************************
+//
+// Defines to check NDEF ID type
+//
+//*****************************************************************************
+
+//
+//! NFC Message TypeID hex representation for TEXT records.
+//! 0x54 == 'T' in UTF-8
+//!
+//! \b Example: Check if tag type is TEXT
+//!
+//! <tt>
+//! \verbatim
+//! //
+//! // Assume the Tag Type has already decoded into sNDEFMessageData.pui8Type
+//! //
+//! if(sNDEFMessageData.pui8Type == NDEF_TYPE_TEXT)
+//! {
+//! // The Tag is a TEXT record, handle it appropriately
+//! }
+//! \endverbatim
+//! </tt>
+//
+#define NDEF_TYPE_TEXT 0x54 // 'T' in UTF-8
+
+//
+//! NFC Message TypeID hex representation for URI records.
+//! 0x55 == 'U' in UTF-8
+//!
+//! \b Example: Check if tag type is URI
+//!
+//! <tt>
+//! \verbatim
+//! //
+//! // Assume the Tag Type has already decoded into sNDEFMessageData.pui8Type
+//! //
+//! if(sNDEFMessageData.pui8Type == NDEF_TYPE_URI)
+//! {
+//! // The Tag is a URI record, handle it appropriately
+//! }
+//! \endverbatim
+//! </tt>
+//
+#define NDEF_TYPE_URI 0x55 // 'U' in UTF-8
+
+//
+//! NFC Message TypeID hex representation for SMARTPOSTER records.
+//! 0x5370 == "Sp" in UTF-8
+//!
+//! \b Example: Check if tag type is SMARTPOSTER
+//!
+//! <tt>
+//! \verbatim
+//! //
+//! // Assume the Tag Type has already decoded into sNDEFMessageData.pui8Type
+//! //
+//! if(sNDEFMessageData.pui8Type == NDEF_TYPE_SMARTPOSTER)
+//! {
+//! // The Tag is a SMARTPOSTER record, handle it appropriately
+//! }
+//! \endverbatim
+//! </tt>
+//
+#define NDEF_TYPE_SMARTPOSTER 0x5370 //"Sp" in UTF-8
+
+//
+//! NFC Message TypeID hex representation for SIGNATURE records.
+//! 0x536967 == "Sig" in UTF-8
+//!
+//! \b Example: Check if tag type is SIGNATURE
+//!
+//! <tt>
+//! \verbatim
+//! //
+//! // Assume the Tag Type has already decoded into sNDEFMessageData.pui8Type
+//! //
+//! if(sNDEFMessageData.pui8Type == NDEF_TYPE_SIGNATURE)
+//! {
+//! // The Tag is a SIGNATURE record, handle it appropriately
+//! }
+//! \endverbatim
+//! </tt>
+//
+#define NDEF_TYPE_SIGNATURE 0x536967 //"Sig" in UTF-8
+
+//
+//! NFC Message TypeID hex representation for SIZE records.
+//! 0x73 == 's' in UTF-8
+//!
+//! \b Example: Check if tag type is SIZE
+//!
+//! <tt>
+//! \verbatim
+//! //
+//! // Assume the Tag Type has already decoded into sNDEFMessageData.pui8Type
+//! //
+//! if(sNDEFMessageData.pui8Type == NDEF_TYPE_SIZE)
+//! {
+//! // The Tag is a SIZE record. Handle it appropriately
+//! }
+//! \endverbatim
+//! </tt>
+//
+#define NDEF_TYPE_SIZE 0x73 // 's' in UTF-8
+
+//
+//! NFC Message TypeID hex representation for ACTION records.
+//! 0x616374 == "act" in UTF-8
+//!
+//! \b Example: Check if tag type is ACTION
+//!
+//! <tt>
+//! \verbatim
+//! //
+//! // Assume the Tag Type has already decoded into sNDEFMessageData.pui8Type
+//! //
+//! if(sNDEFMessageData.pui8Type == NDEF_TYPE_ACTION)
+//! {
+//! // The Tag is a ACTION record, handle it appropriately
+//! }
+//! \endverbatim
+//! </tt>
+//
+#define NDEF_TYPE_ACTION 0x616374 //"act" in UTF-8
+
+
+
+//*****************************************************************************
+//
+//! Enumeration for Type Name Format (TNF) field in NDEF header StatusByte.
+//! TNF values are 3 bits. Most records are of the Well Known Type format
+//! (0x01).
+//
+// TNF = Type Name Format: 3bit field, indicates structure of TYPE field
+// Acceptable Values are:
+// 0x00 Empty
+// 0x01 NFC Forum well-known type [NFC RTD]
+// NDEF Record Type Description Full URI Reference
+// 'Sp' Smart Poster urn:nfc:wkt:Sp
+// 'T' Text urn:nfc:wkt:T
+// 'U' URI urn:nfc:wkt:U
+// 'Hr' Handover Request urn:nfc:wkt:Hr
+// 'Hs' Handover Select urn:nfc:wkt:Hs
+// 'Hc' Handover Carrier urn:nfc:wkt:Hc
+// 'Sig' Signature urn:nfc:wkt:Sig
+// 0x02 Media-type as defined in RFC 2046 [RFC 2046]
+// 0x03 Absolute URI as defined in RFC 3986 [RFC 3986]
+// 0x04 NFC Forum external type [NFC RTD]
+// 0x05 Unknown
+// 0x06 Unchanged (used with single message across multiple chunks)
+// 0x07 Reserved
+//
+//*****************************************************************************
+typedef enum
+{
+ //
+ //! Empty Format
+ //
+ TNF_EMPTY = 0x00,
+
+ //
+ //! NFC Forum Well Known Type [NFC RTD]
+ //
+ TNF_WELLKNOWNTYPE = 0x01,
+
+ //
+ //! Media-type as defined in RFC 2046 [RFC 2046]
+ //
+ TNF_MEDIA_TYPE = 0x02,
+
+ //
+ //! Absolute URI as defined in RFC 3986 [RFC 3986]
+ //
+ TNF_ABSOLUTE_URI = 0x03,
+
+ //
+ //! NFC Forum external type [NFC RTD]
+ //
+ TNF_EXTERNAL_TYPE = 0x04,
+
+ //
+ //! Unknown
+ //
+ TNF_UNKNOWN = 0x05,
+
+ //
+ //! Unchanged (used with single message across multiple chunks)
+ //
+ TNF_UNCHANGED = 0x06,
+
+ //
+ //! Reserved
+ //
+ TNF_RESERVED = 0x07
+} tTNF;
+
+//*****************************************************************************
+//
+//! NFC NDEF message header StatusByte structure. Included in this structure
+//! are fields for Message Begin (MB), Message End (ME), Chunk Flag (CF), Short
+//! Record (SR), IDLength (IL) and Type Name Format (TNF). The purpose of this
+//! structure is to make the fields readily available for message processing.
+// ______________________________
+// | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0|
+// |------------------------------|
+// | MB| ME| CF| SR| IL| TNF |
+// |------------------------------|
+//
+// MB = Message Begin : marks start of NDEF message
+// ME = Message End : marks end of NDEF message
+// CF = Chunk Flag : indicate first or middle record chunk of chunked payload
+// SR = Short Record : if == 1 PAYLOAD_LENGTH is 1 byte, else it is 4 bytes
+// IL = ID Length : indicate presence of ID_LENGTH byte
+// (1 =included, 0 = not)
+// TNF = Type Name Format: 3bit field, indicates structure of TYPE field
+//
+// Note: for a record that only takes up 1 NDEF message both the MB and ME
+// fields would be set on the same message. It is likely that the SR
+// field would be set as well to save space, but not required.
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ //! Message Begin flag
+ //
+ bool MB;
+
+ //
+ //! Message End flag
+ //
+ bool ME;
+
+ //
+ //! Chunk Flag
+ //
+ bool CF;
+
+ //
+ //! Short Record flag
+ //
+ bool SR;
+
+ //
+ //! ID Length flag
+ //
+ bool IL;
+
+ //
+ //! Type Name Field. An enumeration specifying the general tag type.
+ //
+ tTNF TNF;
+
+} sNDEFStatusByte;
+
+//*****************************************************************************
+//
+//! Structure to hold NDEF Message header data. The message header encapsulates
+//! and contains metadata about the payload message. This structure is used
+//! with the NFCP2P_NDEFMessageEncoder and NFCP2P_NDEFMessageDecoder functions.
+//! For detailed information on the NDEF message header data, please see the NFC
+//! specification.
+//
+// NDEF Record Layout
+// _________________
+// | StatusByte | 1 byte
+// |-----------------|
+// | TYPE_LENGTH | 1 byte, hex value
+// |---------------- |
+// | PAYLOAD_LENGTH | 1 or 4 bytes
+// |---------------- |
+// | ID_LENGTH | 0 or 1 bytes
+// |---------------- |
+// | TYPE | 2 or 5 bytes
+// |---------------- |
+// | ID | 0 or 1 byte
+// |---------------- |
+// | |
+// | PAYLOAD | Multiple Bytes
+// | |
+// |-----------------|
+//
+// Note: The Type and ID field lengths are arbitrarily set and can be expanded
+// if desired. The PayloadLength field is set to the standard maximum.
+// The Payload is set as a pointer into the received buffer.
+//
+//*****************************************************************************
+typedef struct
+{
+
+ //
+ //! Metadata about the message
+ //
+ sNDEFStatusByte sStatusByte;
+
+ //
+ //! Length of the Type field in bytes
+ //
+ uint8_t ui8TypeLength;
+
+ //
+ //! Length of the payload in bytes
+ //
+ uint32_t ui32PayloadLength;
+
+ //
+ //! Length of ID field in bytes. Optional field
+ //
+ uint8_t ui8IDLength;
+
+ //
+ //! Contains message type
+ //
+ uint8_t pui8Type[NDEF_TYPE_MAXSIZE];
+
+ //
+ //! Contains message ID. Optional field
+ //
+ uint8_t pui8ID[NDEF_ID_MAXSIZE];
+
+ //
+ //! Pointer to the encoded payload buffer
+ //
+ uint8_t *pui8PayloadPtr;
+
+} sNDEFMessageData;
+
+//*****************************************************************************
+//
+// General defines used to interpret data / set limits on buffer sizes
+//
+//*****************************************************************************
+//
+//! Check text record bit in the StatusByte to determine if text record is UTF8
+//! format.
+//!
+//! \b Example: Check Text Record for UTF8 format
+//!
+//! <tt> if(sNDEFTextRecord.bUTFcode == NDEF_TEXTRECORD_STATUSBYTE_UTF8){}</tt>
+//
+#define NDEF_TEXTRECORD_STATUSBYTE_UTF8 0 // DO NOT CHANGE
+
+//
+//! Check text record bit in the StatusByte to determine if text record is UTF16
+//! format.
+//!
+//! \b Example: Check Text Record for UTF16 format
+//!
+//! <tt> if(sNDEFTextRecord.bUTFcode == NDEF_TEXTRECORD_STATUSBYTE_UTF16){}</tt>
+//
+#define NDEF_TEXTRECORD_STATUSBYTE_UTF16 1 // DO NOT CHANGE
+
+//
+//! Define the size of the Text Record Language Code Buffer. This can be changed
+//! by the user to fit larger language codes that may develop in the future.
+//! Current language codes are 2 or 5 bits, but users can use larger sizes
+//! if they are adopted in the future.
+//
+#define NDEF_TEXTRECORD_LANGUAGECODE_MAXSIZE 5 // can be changed
+
+//*****************************************************************************
+//
+// Set Values into Raw StatusByte by | together
+//
+//*****************************************************************************
+
+//
+//! Set UTF bit field in TextRecord StatusByte field. This define should be ORed
+//! together with other StatusByte fields and set into StatusByte.
+//!
+//! \param ui8x is the 8-bit StatusByte
+//!
+//! \b Example: Set UTF bit field to UTF8
+//!
+//! <tt> ui8StatusByte = (NDEF_TEXTRECORD_STATUSBYTE_SET_UTF(
+//! NDEF_TEXTRECORD_STATUSBYTE_UTF8) |
+//! NDEF_TEXTRECORD_STATUSBYTE_SET_LENGTHLANGCODE(...))
+//! </tt>
+//!
+//
+#define NDEF_TEXTRECORD_STATUSBYTE_SET_UTF(ui8x) ((ui8x & 0x01) << 7)
+
+//
+//! Set the RFU bit field in the TextRecord StatusByte field. Should be ORed
+//! together with other StatusByte fields and set into StatusByte. The RFU field
+//! is reserved for future use by the NFC specification and should not be used
+//! by normal applications.
+//!
+//! \param ui8x is the 8-bit StatusByte
+//!
+//! <tt> ui8StatusByte = (NDEF_TEXTRECORD_STATUSBYTE_SET_RFU(0)|
+//! (NDEF_TEXTRECORD_STATUSBYTE_SET_LENGTHLANGCODE(...)))
+//! </tt>
+//!
+//
+#define NDEF_TEXTRECORD_STATUSBYTE_SET_RFU(ui8x) ((ui8x & 0x01) << 6)
+
+//
+//! Set the Language Code Length field in the TextRecord StatusByte field.
+//! This define should be ORed together with other StatusByte fields and set
+//! into StatusByte.
+//!
+//! \param ui8x is the 8-bit StatusByte
+//!
+//! <tt> ui8StatusByte = (NDEF_TEXTRECORD_STATUSBYTE_SET_LENGTHLANGCODE(5) |
+//! NDEF_TEXTRECORD_STATUSBYTE_SET_LENGTHLANGCODE(...))
+//! </tt>
+//!
+//
+#define NDEF_TEXTRECORD_STATUSBYTE_SET_LENGTHLANGCODE(ui8x) ((ui8x & 0x3F) << 0)
+
+//*****************************************************************************
+//
+// Get values from Raw StatusByte
+//
+//*****************************************************************************
+
+//
+//! This macro extracts the UTF bit value from the raw StatusByte.
+//!
+//! \param ui8x is the 8-bit StatusByte
+//!
+//! \b Example: Fill the UTF boolean value in the data structure from the raw
+//! buffer byte
+//!
+//! <tt> sNDEFTextRecord.bUTFcode = NDEF_TEXTRECORD_STATUSBYTE_GET_UTF(
+//! ui8StatusByte)
+//! </tt>
+//!
+//
+#define NDEF_TEXTRECORD_STATUSBYTE_GET_UTF(ui8x) ((ui8x >> 7) & 0x01)
+
+//
+//! This macro extracts the RFU bit value from raw StatusByte. According to the
+//! NFC specification, this value must be zero.
+//!
+//! \param ui8x is the 8-bit StatusByte
+//!
+//! \b Example: Fill the RFU boolean value in the data structure from the raw
+//! buffer byte
+//!
+//! <tt> sNDEFTextRecord.bRFU = NDEF_TEXTRECORD_STATUSBYTE_GET_RFU(
+//! ui8StatusByte)
+//! </tt>
+//!
+//
+#define NDEF_TEXTRECORD_STATUSBYTE_GET_RFU(ui8x) ((ui8x >> 6) & 0x01)
+
+//
+//! This macro extracts the Language Code Length field from the raw StatusByte.
+//!
+//! \param ui8x is the 8-bit StatusByte
+//!
+//! \b Example: Fill the Language Code Length field in the data structure from
+//! the raw buffer byte
+//!
+//! <tt>
+//! sNDEFTextRecord.ui5LengthLangCode =
+//! NDEF_TEXTRECORD_STATUSBYTE_GET_LENGTHLANGCODE(ui8StatusByte)
+//! </tt>
+//!
+//
+#define NDEF_TEXTRECORD_STATUSBYTE_GET_LENGTHLANGCODE(ui8x) ((ui8x >> 0) & 0x3F)
+
+//*****************************************************************************
+//
+//! This structure defines the text record status byte.
+//! bUTFcode determines if the Text Record is encoded with UTF8 (0) or
+//! UTF16 (1). bRFU is reserved for future use by the NFC specification.
+//! ui5LengthLangCode holds the length of the language code. Currently
+//! language code lengths are either 2 or 5 bytes.
+// ______________________________
+// | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0|
+// |------------------------------|
+// |UTF|RFU| Length of Lang Code | = StatusByte
+// |------------------------------|
+//
+// UTF = UTF8 or UTF16 text string formatting (0 = UTF8, 1 = UTF16)
+// RFU = 0, no exceptions, its reserved for future use
+// LenLangCode = 6 bytes to determine the Length of Language Code (next field)
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ //! Flag for UTF Code. 0 = UTF8, 1 = UTF16
+ //
+ bool bUTFcode;
+
+ //
+ //! Reserved for future use by NFC specification
+ //
+ bool bRFU;
+
+ //
+ //! Length of Text Record language code
+ //
+ uint8_t ui5LengthLangCode;
+
+} sNDEFTextRecordStatusByte;
+
+//*****************************************************************************
+//
+//! This structure defines the text record. sStatusByte contains the length of
+//! the language code and the formatting for the Text (UTF8/UTF16).
+//! pui8LanguageCode is a buffer that contains the language code; the buffer
+//! size can be changed at compile time by modifying the
+//! NDEF_TEXTRECORD_LANGUAGECODE_MAXSIZE define. pui8Text is a pointer to the
+//! text payload of the Text Record. These three fields are defined in the
+//! NFC specification. In addition, ui32TextLength has been added for
+//! convenience to keep track of the Text buffer length. For example, a
+//! text record with the Text "hello world" would have a StatusByte of 0x02
+//! (UTF = 0 (UTF8), LenLangCode = 0x2), a Language Code of "en"
+//! (for English, note that it is 2 bytes long just as the ui5LengthLangCode
+//! field of the Text Record StatusByte denoted), pui8Text points to
+//! a buffer holding "hello world", and ui32TextLength has a value of 11,
+//! which is the number of chars in "hello world".
+//
+// NDEF message Text Record Payload Layout
+// _________________
+// | StatusByte | = 1 byte
+// |-----------------|
+// | Language Code | = 2-5 bytes
+// |-----------------|
+// | |
+// | Text | = Multiple Bytes
+// | |
+// |-----------------|
+//
+// Note: the contents of a text record are freeform plain text in either
+// UTF8 or UTF16 format.
+//
+// Note: the TextRecordLength is used in lieu of a terminiating sentinel on
+// the puiText buffer.
+//
+//*****************************************************************************
+typedef struct
+{
+
+ //
+ //! Structure to hold StatusByte information
+ //
+ sNDEFTextRecordStatusByte sStatusByte;
+
+ //
+ //! Buffer that holds the Language Code
+ //
+ uint8_t pui8LanguageCode[NDEF_TEXTRECORD_LANGUAGECODE_MAXSIZE];
+
+ //
+ //! Pointer to the Text Buffer
+ //
+ uint8_t *pui8Text;
+
+ //
+ //! Length of text in Text Buffer
+ //
+ uint32_t ui32TextLength;
+
+} sNDEFTextRecord;
+
+//*****************************************************************************
+//
+//! Define used to mark end of well-defined URI Record ID Codes. Any code
+//! greater than this value is not defined by the NFC specification.
+//!
+//! \b Example: Check if ID Code of Tag is known defined value
+//!
+//! <tt>
+//! \verbatim
+//! if(sNDEFURIRecord.eIDCode < NDEF_URIRECORD_IDCODE_RFU)
+//! {
+//! //process tag
+//! }
+//! \endverbatim
+//! </tt>
+//
+//*****************************************************************************
+#define NDEF_URIRECORD_IDCODE_RFU 0x24
+
+//*****************************************************************************
+//
+//! Enumeration of all possible URI Record ID Codes defined by the NFC
+//! specification.
+//! For the complete list, please see the enumeration definition in nfc_p2p.h.
+//! Defined values range from 0x00 (no prepending) to 0x23 ('urn:nfc:').
+//! Values 0x24 and above are reserved for future use.
+//
+// Acceptable Prepending values are:
+// 0x00 N/A. No prepending is done
+// 0x01 http://www.
+// 0x02 https://www.
+// 0x03 http://
+// 0x04 https://
+// 0x05 tel:
+// 0x06 mailto:
+// 0x07 ftp://anonymous:anonymous@
+// 0x08 ftp://ftp.
+// 0x09 ftps://
+// 0x0A sftp://
+// 0x0B smb://
+// 0x0C nfs://
+// 0x0D ftp://
+// 0x0E dav://
+// 0x0F news:
+// 0x10 telnet://
+// 0x11 imap:
+// 0x12 rtsp://
+// 0x13 urn:
+// 0x14 pop:
+// 0x15 sip:
+// 0x16 sips:
+// 0x17 tftp:
+// 0x18 btspp://
+// 0x19 btl2cap://
+// 0x1A btgoep://
+// 0x1B tcpobex://
+// 0x1C irdaobex://
+// 0x1D file://
+// 0x1E urn:epc:id:
+// 0x1F urn:epc:tag:
+// 0x20 urn:epc:pat:
+// 0x21 urn:epc:raw:
+// 0x22 urn:epc:
+// 0x23 urn:nfc:
+//
+// 0x24-0xFF RFU Reserved for Future Use, Not Valid Inputs
+//
+//*****************************************************************************
+typedef enum
+{
+
+ //
+ //! Nothing is prepended to puiUTF8String
+ //
+ unabridged = 0x00,
+
+ //
+ //! 'http://www.' is prepended to puiUTF8String
+ //
+ http_www = 0x01,
+
+ //
+ //! 'https://www.' is prepended to puiUTF8String
+ //
+ https_www = 0x02,
+
+ //
+ //! 'http://' is prepended to puiUTF8String
+ //
+ http = 0x03,
+
+ //
+ //! 'https://' is prepended to puiUTF8String
+ //
+ https = 0x04,
+
+ //
+ //! 'tel:' is prepended to puiUTF8String
+ //
+ tel = 0x05,
+
+ //
+ //! 'mailto:' is prepended to puiUTF8String
+ //
+ mailto = 0x06,
+
+ //
+ //! 'ftp://anonymous:anonymous@' is prepended to puiUTF8String
+ //
+ ftp_anonymous = 0x07,
+
+ //
+ //! 'ftp://ftp.' is prepended to puiUTF8String
+ //
+ ftp_ftp = 0x08,
+
+ //
+ //! 'ftps://' is prepended to puiUTF8String
+ //
+ ftps = 0x09,
+
+ //
+ //! 'sftp://' is prepended to puiUTF8String
+ //
+ sftp = 0x0A,
+
+ //
+ //! 'smb://' is prepended to puiUTF8String
+ //
+ smb = 0x0B,
+
+ //
+ //! 'nfs://' is prepended to puiUTF8String
+ //
+ nfs = 0x0C,
+
+ //
+ //! 'ftp://' is prepended to puiUTF8String
+ //
+ ftp = 0x0D,
+
+ //
+ //! 'dav://' is prepended to puiUTF8String
+ //
+ dav = 0x0E,
+
+ //
+ //! 'news:' is prepended to puiUTF8String
+ //
+ news = 0x0F,
+
+ //
+ //! 'telnet://' is prepended to puiUTF8String
+ //
+ telnet = 0x10,
+
+ //
+ //! 'imap:' is prepended to puiUTF8String
+ //
+ imap = 0x11,
+
+ //
+ //! 'rtsp://' is prepended to puiUTF8String
+ //
+ rtsp = 0x12,
+
+ //
+ //! 'urn:' is prepended to puiUTF8String
+ //
+ urn = 0x13,
+
+ //
+ //! 'pop:' is prepended to puiUTF8String
+ //
+ pop = 0x14,
+
+ //
+ //! 'sip:' is prepended to puiUTF8String
+ //
+ sip = 0x15,
+
+ //
+ //! 'sips:' is prepended to puiUTF8String
+ //
+ sips = 0x16,
+
+ //
+ //! 'tftp:' is prepended to puiUTF8String
+ //
+ tftp = 0x17,
+
+ //
+ //! 'btspp://' is prepended to puiUTF8String
+ //
+ btspp = 0x18,
+
+ //
+ //! 'btl2cap://' is prepended to puiUTF8String
+ //
+ btl2cap = 0x19,
+
+ //
+ //! 'btgoep://' is prepended to puiUTF8String
+ //
+ btgoep = 0x1A,
+
+ //
+ //! 'tcpobex://' is prepended to puiUTF8String
+ //
+ tcpobex = 0x1B,
+
+ //
+ //! 'irdaobex://' is prepended to puiUTF8String
+ //
+ irdaobex = 0x1C,
+
+ //
+ //! 'file://' is prepended to puiUTF8String
+ //
+ file = 0x1D,
+
+ //
+ //! 'urn:epc:id:' is prepended to puiUTF8String
+ //
+ urn_epc_id = 0x1E,
+
+ //
+ //! 'urn:epc:tag:' is prepended to puiUTF8String
+ //
+ urn_epc_tag = 0x1F,
+
+ //
+ //! 'urn:epc:pat:' is prepended to puiUTF8String
+ //
+ urn_epc_pat = 0x20,
+
+ //
+ //! 'urn:epc:raw:' is prepended to puiUTF8String
+ //
+ urn_epc_raw = 0x21,
+
+ //
+ //! 'urn:epc:' is prepended to puiUTF8String
+ //
+ urn_epc = 0x22,
+
+ //
+ //! 'urn:nfc:' is prepended to puiUTF8String
+ //
+ urn_nfc = 0x23,
+
+ //
+ //! Values equal to and above this are reserved for future use (RFU)
+ //
+ RFU = 0x24
+
+} eNDEF_URIRecord_IDCode;
+
+//*****************************************************************************
+//
+//! This structure defines the URI record type. The URI Record Type has two
+//! fields; the ID code and the UTF8 URI string. The IDCode is used to
+//! determine the URI type. For example, IDcode of 0x06 is 'mailto:'
+//! and usually triggers an email event. IDcode 0x01 is 'http://www.' and
+//! usually triggers a webpage to open. The IDcode values are prepended to
+//! the UTF8 string. ui32URILength is used to determine the length of the
+//! puiUTF8String buffer. For example, to direct a user to 'http://www.ti.com'
+//! the IDcode is 0x01, the UTF8 string is 'ti.com', and the ui32URILength is
+//! 0x6.
+//
+// NDEF message URI Record Payload Layout
+// _________________
+// | ID Code | 1 byte
+// |-----------------|
+// | |
+// | UTF8 String | Multiple Bytes
+// | |
+// |-----------------|
+//
+// The URI string is multiple bytes of UTF8 format text with a possible
+// prepended value depending on the ID Code
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ //! Enumeration of all possible ID codes
+ //
+ eNDEF_URIRecord_IDCode eIDCode;
+
+ //
+ //! Buffer that holds the URI character string
+ //
+ uint8_t *puiUTF8String;
+
+ //
+ //! Length of URI Character String
+ //
+ uint32_t ui32URILength;
+
+} sNDEFURIRecord;
+
+//*****************************************************************************
+//
+//! Enumeration of the three actions that can be associated with an Action
+//! Record.
+//
+//*****************************************************************************
+typedef enum
+{
+
+ //
+ //! Do Action on Record
+ //
+ DO_ACTION = 0x00,
+
+ //
+ //! Save Record for Later
+ //
+ SAVE_FOR_LATER = 0x01,
+
+ //
+ //! Open Record for Editing
+ //
+ OPEN_FOR_EDITING = 0x02
+
+} tAction;
+
+//*****************************************************************************
+//
+//! This structure defines an Action Record
+//
+//*****************************************************************************
+typedef struct
+{
+
+ //
+ //! Action Record type enumeration
+ //
+ tAction eAction;
+
+} sNDEFActionRecord;
+
+//*****************************************************************************
+//
+//! This structure defines the SmartPoster record type.
+//! The SmartPoster Record is essentially
+//! a URI Record with other records included for metadata. Thus
+//! the SmartPoster must include at least a URI Record and may also include a
+//! Text Record for a Title record, an Action record to do actions on the URI,
+//! an Icon Record with a small icon, a Size record that holds the size of the
+//! externally referenced entity, and a Type record that denotes the type of the
+//! externally referenced entity. It should be noted that while the SmartPoster
+//! specification can include all these records, this library only provides
+//! support for Title, URI and Action records. All other records are ignored
+//! by the default handler.
+//
+// NDEF message SmartPoster Record Payload consists of multiple fully wrapped
+// NDEF records. The basic layout is a URI record with subsequent records as
+// metadata on size, type, icon, title, and action associated with record.
+//
+// The possible record types are :
+// Title Record : multiple possible in different languages (Text Record)
+// URI Record : 1 and only 1, core of Smart Poster record
+// Action Record : how to treat the URI (Do, Save for later, Open for edit)
+// Icon Record : MIME type image record [optional]
+// Size Record : size of external referenced entity (web link) [optional]
+// Type Record : MIME type of external referenced entity [optional
+//
+//
+// Note: Currently only Title,URI, and Action records are supported.
+// Image, Type and size records are not implemented.
+//
+//*****************************************************************************
+typedef struct
+{
+
+ //
+ //! message header for Text Record
+ //
+ sNDEFMessageData sTextHeader;
+
+ //
+ //! Text Record payload structure
+ //
+ sNDEFTextRecord sTextPayload;
+
+ //
+ //! message header for URI Record
+ //
+ sNDEFMessageData sURIHeader;
+
+ //
+ //! URI Record payload strucutre
+ //
+ sNDEFURIRecord sURIPayload;
+
+ //
+ //! Flag to signal if Action Record is part of Smart Poster
+ //
+ bool bActionExists;
+
+ //
+ //! message header for Action Record
+ //
+ sNDEFMessageData sActionHeader;
+
+ //
+ //! Action Record payload strucutre
+ //
+ sNDEFActionRecord sActionPayload;
+
+} sNDEFSmartPosterRecord;
+
+//*****************************************************************************
+//
+// Function Prototypes
+//
+//*****************************************************************************
+void NFCP2P_init(tTRF79x0TRFMode eMode,tTRF79x0Frequency eFrequency);
+tNFCP2PState NFCP2P_proccessStateMachine(void);
+tStatus NFCP2P_sendPacket(uint8_t *pui8DataPtr, uint32_t ui32DataLength);
+sNFCP2PRxStatus NFCP2P_getReceiveState(void);
+
+bool NFCP2P_NDEFMessageEncoder(sNDEFMessageData sNDEFDataToSend,
+ uint8_t *pui8Buffer,
+ uint16_t ui16BufferMaxLength,
+ uint32_t *pui32BufferLength);
+bool NFCP2P_NDEFMessageDecoder(sNDEFMessageData *psNDEFDataDecoded,
+ uint8_t *pui8Buffer,
+ uint16_t ui16BufferMaxLength);
+bool NFCP2P_NDEFTextRecordEncoder(sNDEFTextRecord sTextRecord,
+ uint8_t *pui8Buffer,
+ uint16_t ui16BufferMaxLength,
+ uint32_t *ui32BufferLength);
+bool NFCP2P_NDEFTextRecordDecoder(sNDEFTextRecord *sTextRecord,
+ uint8_t *pui8Buffer,
+ uint32_t ui32BufferLength);
+bool NFCP2P_NDEFURIRecordEncoder(sNDEFURIRecord sURIRecord,
+ uint8_t *pui8Buffer,
+ uint16_t ui16BufferMaxLength,
+ uint32_t *ui32BufferLength);
+bool NFCP2P_NDEFURIRecordDecoder(sNDEFURIRecord *sURIRecord,
+ uint8_t *pui8Buffer,
+ uint32_t ui32BufferLength);
+bool NFCP2P_NDEFSmartPosterRecordEncoder(sNDEFSmartPosterRecord sSmartPoster,
+ uint8_t *pui8Buffer,
+ uint16_t ui16BufferMaxLength,
+ uint32_t *ui32BufferLength);
+bool NFCP2P_NDEFSmartPosterRecordDecoder(sNDEFSmartPosterRecord *sSmartPoster,
+ uint8_t *pui8Buffer,
+ uint16_t ui16BufferMaxLength,
+ uint32_t ui32BufferLength);
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
+
+#endif //__NFC_P2P_H__
diff --git a/nfclib/snep.c b/nfclib/snep.c
new file mode 100644
index 0000000..dc0bd95
--- /dev/null
+++ b/nfclib/snep.c
@@ -0,0 +1,760 @@
+//*****************************************************************************
+//
+// snep.c - implementation of Simple NDEF Exchange Protocol, uses LLCP
+//
+// Copyright (c) 2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
+//
+//*****************************************************************************
+#include <stdbool.h>
+#include <stdint.h>
+#include <string.h>
+#include "nfclib/snep.h"
+#include "nfclib/debug.h"
+
+//*****************************************************************************
+//
+//! \addtogroup nfc_snep_api NFC SNEP API Functions
+//! @{
+//! Simple NDEF Exchange Protocol is an application protocol used by the LLCP
+//! layer to send / receive NDEFs between two NFC Forum Devices operating
+//! in Peer-to-Peer Mode (1 Target and 1 Initiator). For more information
+//! on SNEP, please read the NFC Simple NDEF Exchange Protocol Specification
+//! Version 1.0.
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// Stores the length of the Tx/Rx packet.
+//
+//****************************************************************************
+uint32_t g_ui32SNEPPacketLength;
+
+//*****************************************************************************
+//
+// g_pui8SNEPTxPacketPtr points to the first location of the data to be
+// transferred
+//
+//*****************************************************************************
+uint8_t * g_pui8SNEPTxPacketPtr;
+uint8_t * g_pui8SNEPRxPacketPtr;
+
+//*****************************************************************************
+//
+// Stores the remaining rx byte count
+//
+//*****************************************************************************
+uint32_t g_ui32SNEPRemainingRxPayloadBytes = 0;
+
+//*****************************************************************************
+//
+// Stores the bytes received in the current I-PDU transaction
+//
+//*****************************************************************************
+uint8_t g_ui8SNEPReceivedBytes = 0;
+
+//*****************************************************************************
+//
+// Stores the status of the incoming packet
+//
+//*****************************************************************************
+tPacketStatus g_eRxPacketStatus = RECEIVED_NO_FRAGMENT;
+
+//*****************************************************************************
+//
+// Stores the status of the SNEP communication
+//
+//*****************************************************************************
+tSNEPConnectionStatus g_eSNEPConnectionStatus = SNEP_CONNECTION_IDLE;
+//*****************************************************************************
+//
+// Stores the maximum size of each SNEP packet.
+//
+//*****************************************************************************
+uint8_t g_ui8MaxPayload = SNEP_MAX_BUFFER;
+
+//*****************************************************************************
+//
+// Stores the index of the current transaction
+//
+//*****************************************************************************
+uint32_t g_ui32TxIndex = 0;
+
+//*****************************************************************************
+//
+//! Initialize the Simple NDEF Exchange Protocol driver.
+//!
+//! This function must be called prior to any other function offered by the
+//! SNEP driver. This function initializes the SNEP status, Tx/Rx packet length
+//! and maximum payload size. This function must be called by the LLCP_init().
+//!
+//! \return None.
+//
+//*****************************************************************************
+void SNEP_init(void)
+{
+ g_eSNEPConnectionStatus = SNEP_CONNECTION_IDLE;
+ g_eRxPacketStatus = RECEIVED_NO_FRAGMENT;
+ g_ui32SNEPRemainingRxPayloadBytes = 0;
+ g_ui8SNEPReceivedBytes = 0;
+ g_ui8MaxPayload = SNEP_MAX_BUFFER;
+ g_ui32TxIndex = 0;
+}
+
+//*****************************************************************************
+//
+//! Set the Maximum size of each fragment.
+//!
+//! \param ui8MaxPayload is the maximum size of each fragment.
+//!
+//! This function must be called inside LLCP_processTLV() to define the maxium
+//! size of each fragment based on the Maximum Information Unit (MIU) supported
+//! by the target/initiator.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void SNEP_setMaxPayload(uint8_t ui8MaxPayload)
+{
+ if(ui8MaxPayload <= SNEP_MAX_BUFFER)
+ {
+ g_ui8MaxPayload = ui8MaxPayload;
+ if(g_ui8MaxPayload == 0x80)
+ {
+ ui8MaxPayload = 0;
+ }
+ }
+}
+
+//*****************************************************************************
+//
+//! Set the global SNEP Packet Pointer and Length
+//!
+//! \param pui8PacketPtr is the pointer to the first payload to be transmitted.
+//! \param ui32PacketLength is the length of the total packet.
+//!
+//! This function must be called by the main application to initialize the
+//! packet to be sent to the SNEP server.
+//!
+//! \return This function returns \b STATUS_SUCCESS (1) if the packet was
+//! queued, else it returns \b STATUS_FAIL (0).
+//
+//*****************************************************************************
+tStatus SNEP_setupPacket(uint8_t * pui8PacketPtr, uint32_t ui32PacketLength)
+{
+ tStatus ePacketSetupStatus;
+
+ if(g_eSNEPConnectionStatus == SNEP_CONNECTION_IDLE )
+ {
+ g_pui8SNEPTxPacketPtr = pui8PacketPtr;
+ // Reset TX Index
+ g_ui32TxIndex = 0;
+ g_ui32SNEPPacketLength = ui32PacketLength;
+ g_eSNEPConnectionStatus = SNEP_CONNECTION_IDLE;
+
+ ePacketSetupStatus = STATUS_SUCCESS;
+ }
+ else
+ ePacketSetupStatus = STATUS_FAIL;
+
+ return ePacketSetupStatus;
+}
+
+
+//*****************************************************************************
+//
+//! Sends request to the server.
+//!
+//! \param pui8DataPtr is the start pointer where the request is written.
+//! \param eRequestCmd is the request command to be sent.
+//!
+//! The \e eRequestCmd parameter can be any of the following:
+//!
+//! - \b SNEP_REQUEST_CONTINUE - Send remaining fragments
+//! - \b SNEP_REQUEST_GET - Return an NDEF message
+//! - \b SNEP_REQUEST_PUT - Accept an NDEF message
+//! - \b SNEP_REQUEST_REJECT - Do not send remaining fragments
+//!
+//! This function sends an SNEP request from the SNEP client to an SNEP server.
+//! It must be called from the LLCP_sendI() function.
+//!
+//! \return \b ui8offset, which is the length of the request written starting at
+//! \b pui8DataPtr.
+//
+//*****************************************************************************
+uint8_t SNEP_sendRequest(uint8_t * pui8DataPtr, tSNEPCommands eRequestCmd)
+{
+ uint8_t ui8PacketLength;
+ uint8_t ui8offset = 0;
+ static uint8_t * pui8SNEPPacketPtr;
+ volatile uint8_t ui8counter;
+
+ switch(eRequestCmd)
+ {
+ case SNEP_REQUEST_CONTINUE:
+ {
+ if(g_eSNEPConnectionStatus == SNEP_CONNECTION_IDLE)
+ break;
+ }
+ case SNEP_REQUEST_GET:
+ {
+ break;
+ }
+ case SNEP_REQUEST_PUT:
+ {
+ if(g_eSNEPConnectionStatus == SNEP_CONNECTION_IDLE)
+ {
+ //
+ // Set sneP_packet_ptr to first address
+ //
+ pui8SNEPPacketPtr = g_pui8SNEPTxPacketPtr;
+
+ //
+ // SNEP Protocol Version
+ //
+ pui8DataPtr[ui8offset++] = SNEP_VERSION;
+
+ //
+ // Request Field
+ //
+ pui8DataPtr[ui8offset++] = (uint8_t) SNEP_REQUEST_PUT;
+
+ //
+ // Length (4 bytes)
+ //
+ pui8DataPtr[ui8offset++] =
+ (uint8_t) ((g_ui32SNEPPacketLength & 0xFF000000) >> 24);
+ pui8DataPtr[ui8offset++] =
+ (uint8_t) ((g_ui32SNEPPacketLength & 0x00FF0000) >> 16);
+ pui8DataPtr[ui8offset++] =
+ (uint8_t) ((g_ui32SNEPPacketLength & 0x0000FF00) >> 8);
+ pui8DataPtr[ui8offset++] =
+ (uint8_t) (g_ui32SNEPPacketLength & 0x000000FF);
+
+ //
+ // The PUT Request has 6 bytes of overhead (Version (1) Request
+ // Field (1) Length (4)).
+ //
+ if( g_ui32SNEPPacketLength > (g_ui8MaxPayload - 6))
+ {
+ //
+ // Remaining bytes = Total Length - (SNEP_MAX_BUFFER - 13)
+ //
+ g_ui32SNEPPacketLength = g_ui32SNEPPacketLength -
+ (g_ui8MaxPayload - 6);
+ ui8PacketLength = (g_ui8MaxPayload - 6);
+
+ //
+ // Change connection status to waiting for continue
+ //
+ g_eSNEPConnectionStatus =
+ SNEP_CONNECTION_WAITING_FOR_CONTINUE;
+ }
+ else
+ {
+ ui8PacketLength = g_ui32SNEPPacketLength;
+ g_ui32SNEPPacketLength = 0;
+
+ //
+ // Change connection status to waiting for success
+ //
+ g_eSNEPConnectionStatus =
+ SNEP_CONNECTION_WAITING_FOR_SUCCESS;
+ }
+
+ //
+ // Copy the snep_packet buffer into the pui8DataPtr
+ //
+ for(ui8counter = 0; ui8counter < ui8PacketLength; ui8counter++)
+ {
+ pui8DataPtr[ui8offset++] = pui8SNEPPacketPtr[g_ui32TxIndex++];
+
+ }
+ }
+ else if(g_eSNEPConnectionStatus ==
+ SNEP_CONNECTION_SENDING_N_FRAGMENTS)
+ {
+ if( g_ui32SNEPPacketLength > g_ui8MaxPayload)
+ {
+ //
+ // Remaining bytes = Total Length - SNEP_MAX_BUFFER
+ //
+ g_ui32SNEPPacketLength = g_ui32SNEPPacketLength -
+ g_ui8MaxPayload;
+ ui8PacketLength = g_ui8MaxPayload;
+ }
+ else
+ {
+ ui8PacketLength = g_ui32SNEPPacketLength;
+ //
+ // Remaining bytes = 0
+ //
+ g_ui32SNEPPacketLength = 0;
+ g_eSNEPConnectionStatus = SNEP_CONNECTION_WAITING_FOR_SUCCESS;
+ }
+
+ //
+ // Copy the snep_packet buffer into the pui8DataPtr
+ //
+ for(ui8counter = 0; ui8counter < ui8PacketLength; ui8counter++)
+ {
+ pui8DataPtr[ui8offset++] = pui8SNEPPacketPtr[g_ui32TxIndex++];
+ }
+
+ }
+ break;
+ }
+ case SNEP_REQUEST_REJECT:
+ {
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+
+ return ui8offset;
+}
+
+//*****************************************************************************
+//
+//! Sends response to the client.
+//!
+//! \param pui8DataPtr is the start pointer where the response is written.
+//! \param eResponseCmd is the response command to be sent.
+//!
+//! The \e eResponseCmd parameter can be any of the following:
+//!
+//! - \b SNEP_RESPONSE_CONTINUE - Continue send remaining fragments
+//! - \b SNEP_RESPONSE_SUCCESS - Operation succeeded
+//! - \b SNEP_RESPONSE_NOT_FOUND - Resource not found
+//! - \b SNEP_RESPONSE_EXCESS_DATA - Resource exceeds data size limit
+//! - \b SNEP_RESPONSE_BAD_REQUEST - Malformed request not understood
+//! - \b SNEP_RESPONSE_NOT_IMPLEMENTED - Unsupported functionality requested
+//! - \b SNEP_RESPONSE_UNSUPPORTED_VER - Unsupported protocol version
+//! - \b SNEP_RESPONSE_REJECT - Do not send remaining fragments
+//!
+//! This function sends an SNEP response from the SNEP server to an SNEP client.
+//! It must be called from the LLCP_sendI() function.
+//!
+//! \return \b ui8offset is the length of the response written starting at
+//! \b pui8DataPtr.
+//
+//*****************************************************************************
+uint8_t SNEP_sendResponse(uint8_t * pui8DataPtr, tSNEPCommands eResponseCmd)
+{
+ uint8_t ui8offset = 0;
+
+ switch(eResponseCmd)
+ {
+ case SNEP_RESPONSE_CONTINUE:
+ {
+ if(g_eSNEPConnectionStatus == SNEP_CONNECTION_RECEIVED_FIRST_PACKET)
+ {
+ //
+ // SNEP Protocol Version
+ //
+ pui8DataPtr[ui8offset++] = SNEP_VERSION;
+
+ //
+ // Response Field
+ //
+ pui8DataPtr[ui8offset++] = (uint8_t) SNEP_RESPONSE_CONTINUE;
+
+ //
+ // Length (4 bytes)
+ //
+ pui8DataPtr[ui8offset++] = 0x00;
+ pui8DataPtr[ui8offset++] = 0x00;
+ pui8DataPtr[ui8offset++] = 0x00;
+ pui8DataPtr[ui8offset++] = 0x00;
+ g_eSNEPConnectionStatus = SNEP_CONNECTION_RECEIVING_N_FRAGMENTS;
+ }
+ break;
+ }
+ case SNEP_RESPONSE_SUCCESS:
+ {
+ if(g_eSNEPConnectionStatus == SNEP_CONNECTION_RECEIVE_COMPLETE)
+ {
+ //
+ // SNEP Protocol Version
+ //
+ pui8DataPtr[ui8offset++] = SNEP_VERSION;
+
+ //
+ // Response Field
+ //
+ pui8DataPtr[ui8offset++] = (uint8_t) SNEP_RESPONSE_SUCCESS;
+
+ //
+ // Length (4 bytes)
+ //
+ pui8DataPtr[ui8offset++] = 0x00;
+ pui8DataPtr[ui8offset++] = 0x00;
+ pui8DataPtr[ui8offset++] = 0x00;
+ pui8DataPtr[ui8offset++] = 0x00;
+ g_eSNEPConnectionStatus = SNEP_CONNECTION_IDLE;
+ }
+ break;
+ }
+ case SNEP_RESPONSE_NOT_FOUND:
+ {
+ break;
+ }
+ case SNEP_RESPONSE_EXCESS_DATA:
+ {
+ break;
+ }
+ case SNEP_RESPONSE_BAD_REQUEST:
+ {
+ break;
+ }
+ case SNEP_RESPONSE_NOT_IMPLEMENTED:
+ {
+ break;
+ }
+ case SNEP_RESPONSE_UNSUPPORTED_VER:
+ {
+ break;
+ }
+ case SNEP_RESPONSE_REJECT:
+ {
+ if(g_eSNEPConnectionStatus == SNEP_CONNECTION_EXCESS_SIZE)
+ {
+ //
+ // SNEP Protocol Version
+ //
+ pui8DataPtr[ui8offset++] = SNEP_VERSION;
+
+ //
+ // Response Field
+ //
+ pui8DataPtr[ui8offset++] = (uint8_t) SNEP_RESPONSE_REJECT;
+
+ //
+ // Length (4 bytes)
+ //
+ pui8DataPtr[ui8offset++] = 0x00;
+ pui8DataPtr[ui8offset++] = 0x00;
+ pui8DataPtr[ui8offset++] = 0x00;
+ pui8DataPtr[ui8offset++] = 0x00;
+ g_eSNEPConnectionStatus = SNEP_CONNECTION_IDLE;
+ }
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+ return ui8offset;
+}
+
+//*****************************************************************************
+//
+//! Processes the data received from a client/server.
+//!
+//! \param pui8RxBuffer is the starting pointer of the SNEP request/response
+//! received.
+//! \param ui8RxLength is the length of the SNEP request/response received.
+//!
+//! This function handles the requests/responses received inside an I-PDU
+//! in the LLCP layer. This function must be called inside
+//! LLCP_processReceivedData().
+//!
+//! \return None
+//
+//*****************************************************************************
+void SNEP_processReceivedData(uint8_t * pui8RxBuffer, uint8_t ui8RxLength)
+{
+ volatile uint8_t ui8SNEPversion;
+ tSNEPCommands eCommandField;
+
+ eCommandField = (tSNEPCommands) pui8RxBuffer[1];
+
+ if((g_eSNEPConnectionStatus == SNEP_CONNECTION_RECEIVED_FIRST_PACKET) ||
+ (g_eSNEPConnectionStatus == SNEP_CONNECTION_RECEIVING_N_FRAGMENTS))
+ {
+ if(g_ui32SNEPRemainingRxPayloadBytes > ui8RxLength)
+ {
+ g_ui8SNEPReceivedBytes = ui8RxLength;
+ g_eSNEPConnectionStatus = SNEP_CONNECTION_RECEIVING_N_FRAGMENTS;
+ g_eRxPacketStatus = RECEIVED_N_FRAGMENT;
+ }
+ else
+ {
+ g_ui8SNEPReceivedBytes = (uint8_t)g_ui32SNEPRemainingRxPayloadBytes;
+ g_eSNEPConnectionStatus = SNEP_CONNECTION_RECEIVE_COMPLETE;
+ g_eRxPacketStatus = RECEIVED_FRAGMENT_COMPLETED;
+ }
+ g_ui32SNEPRemainingRxPayloadBytes = g_ui32SNEPRemainingRxPayloadBytes -
+ g_ui8SNEPReceivedBytes;
+ g_pui8SNEPRxPacketPtr = &pui8RxBuffer[0];
+ }
+ else if(eCommandField >= 0x80)
+ {
+ //
+ // Process Responses
+ //
+ switch(eCommandField)
+ {
+ case SNEP_RESPONSE_CONTINUE:
+ {
+ if(g_eSNEPConnectionStatus ==
+ SNEP_CONNECTION_WAITING_FOR_CONTINUE)
+ {
+ g_eSNEPConnectionStatus =
+ SNEP_CONNECTION_SENDING_N_FRAGMENTS;
+ }
+ break;
+ }
+ case SNEP_RESPONSE_SUCCESS:
+ {
+ if(g_eSNEPConnectionStatus ==
+ SNEP_CONNECTION_WAITING_FOR_SUCCESS)
+ {
+ g_eSNEPConnectionStatus = SNEP_CONNECTION_SEND_COMPLETE;
+ }
+ break;
+ }
+ case SNEP_RESPONSE_NOT_FOUND:
+ {
+ break;
+ }
+ case SNEP_RESPONSE_EXCESS_DATA:
+ {
+ break;
+ }
+ case SNEP_RESPONSE_BAD_REQUEST:
+ {
+ break;
+ }
+ case SNEP_RESPONSE_NOT_IMPLEMENTED:
+ {
+ break;
+ }
+ case SNEP_RESPONSE_UNSUPPORTED_VER:
+ {
+ break;
+ }
+ case SNEP_RESPONSE_REJECT:
+ {
+ break;
+ }
+ default :
+ {
+ break;
+ }
+ }
+ }
+ else
+ {
+ //
+ // Process Requests
+ //
+ switch(eCommandField)
+ {
+ case SNEP_REQUEST_CONTINUE:
+ {
+ break;
+ }
+ case SNEP_REQUEST_GET:
+ {
+ break;
+ }
+ case SNEP_REQUEST_PUT:
+ {
+ ui8SNEPversion = pui8RxBuffer[0];
+ if(ui8SNEPversion == SNEP_VERSION)
+ {
+ //
+ // Update remaining payload bytes
+ //
+ g_ui32SNEPRemainingRxPayloadBytes =
+ (
+ (uint32_t) (pui8RxBuffer[5] & 0xFF) +
+ ((uint32_t) (pui8RxBuffer[4] & 0xFF) << 8) +
+ ((uint32_t) (pui8RxBuffer[3] & 0xFF) << 16) +
+ ((uint32_t) (pui8RxBuffer[2] & 0xFF) << 24)
+ );
+ if(g_ui32SNEPRemainingRxPayloadBytes > SNEP_MAX_PAYLOAD)
+ {
+ g_eSNEPConnectionStatus = SNEP_CONNECTION_EXCESS_SIZE;
+ }
+ else
+ {
+ if (g_ui32SNEPRemainingRxPayloadBytes
+ > (ui8RxLength - 6)) {
+ g_ui8SNEPReceivedBytes = (ui8RxLength - 6);
+ g_eSNEPConnectionStatus =
+ SNEP_CONNECTION_RECEIVED_FIRST_PACKET;
+ g_eRxPacketStatus = RECEIVED_FIRST_FRAGMENT;
+ }
+ else
+ {
+ //
+ // Packet Length
+ //
+ g_ui8SNEPReceivedBytes =
+ (uint8_t) g_ui32SNEPRemainingRxPayloadBytes;
+ g_eSNEPConnectionStatus =
+ SNEP_CONNECTION_RECEIVE_COMPLETE;
+ g_eRxPacketStatus = RECEIVED_FRAGMENT_COMPLETED;
+ }
+ //
+ // Update remaining payload bytes
+ //
+ g_ui32SNEPRemainingRxPayloadBytes =
+ g_ui32SNEPRemainingRxPayloadBytes
+ - g_ui8SNEPReceivedBytes;
+
+ //
+ // Set the g_pui8SNEPRxPacketPtr to the start of payload
+ //
+ g_pui8SNEPRxPacketPtr = &pui8RxBuffer[6];
+
+ }
+ }
+ else
+ {
+ g_eSNEPConnectionStatus = SNEP_WRONG_VERSION_RECEIVED;
+ }
+ break;
+ }
+ case SNEP_REQUEST_REJECT:
+ {
+ break;
+ }
+ default :
+ {
+ break;
+ }
+ }
+ }
+}
+
+//*****************************************************************************
+//
+//! Get RxStatus flag, Clear packet status flag,retrieve length of data and
+//! retrieve data
+//!
+//! \param peReceiveFlag is a pointer to store the RX state status.
+//! \param pui8length is a pointer to store the number of received bytes.
+//! \param pui8DataPtr is a double pointer to store the pointer of data
+//! received.
+//!
+//! The \e peReceiveFlag parameter can be any of the following:
+//!
+//! - \b RECEIVED_NO_FRAGMENT - No Fragment has been received
+//! - \b RECEIVED_FIRST_FRAGMENT - First fragment has been received.
+//! - \b RECEIVED_N_FRAGMENT - N Fragment has been received.
+//! - \b RECEIVED_FRAGMENT_COMPLETED - End of the fragment has been received.
+//!
+//! This function must be called in the main application after the
+//! NFCP2P_proccessStateMachine() is called to ensure the data received is moved
+//! to another buffer and handled when a fragment is received.
+//!
+//! \return None
+//
+//*****************************************************************************
+void SNEP_getReceiveStatus(tPacketStatus * peReceiveFlag, uint8_t * pui8length,
+ uint8_t ** pui8DataPtr)
+{
+ //
+ // Save RX Packet Status Flag
+ //
+ *peReceiveFlag = g_eRxPacketStatus;
+
+ //
+ // Clear the packet status flag
+ //
+ g_eRxPacketStatus = RECEIVED_NO_FRAGMENT;
+
+ //
+ // Save Number of Byted received
+ //
+ *pui8length = g_ui8SNEPReceivedBytes;
+
+ //
+ // Set Data = ReceivedPacket
+ //
+ *pui8DataPtr = g_pui8SNEPRxPacketPtr;
+
+ return;
+}
+
+//*****************************************************************************
+//
+//! Returns current SNEP Connection Status enumeration
+//!
+//! This function returns the current SNEP status flag. It must be called inside
+//! LLCP_processReceivedData() to determine if further I-PDUs are required,
+//! which is when there are requests/responses queued.
+//!
+//! \return g_eSNEPConnectionStatus the current connection status flag.
+//
+//*****************************************************************************
+tSNEPConnectionStatus SNEP_getProtocolStatus(void)
+{
+ return g_eSNEPConnectionStatus;
+}
+
+//*****************************************************************************
+//
+//! Sets current SNEP Connection Status enumeration
+//!
+//! \param eProtocolStatus is the status flag used by the SNEP state machine
+//! SNEP_processReceivedData() to send request/response.
+//! New sent transactions are allowed only when eProtocolStatus is set
+//! to \b SNEP_CONNECTION_IDLE.
+//!
+//! The \e eProtocolStatus parameter can be any of the following:
+//!
+//! - \b SNEP_CONNECTION_IDLE - No ongoing Tx/Rx
+//! - \b SNEP_WRONG_VERSION_RECEIVED - Wrong Version Received
+//! - \b SNEP_CONNECTION_RECEIVED_FIRST_PACKET - Received First Fragment
+//! - \b SNEP_CONNECTION_RECEIVING_N_FRAGMENTS - Received N Fragment
+//! - \b SNEP_CONNECTION_WAITING_FOR_CONTINUE - Waiting for Continue response
+//! - \b SNEP_CONNECTION_WAITING_FOR_SUCCESS - Waiting for Success response
+//! - \b SNEP_CONNECTION_SENDING_N_FRAGMENTS - Sending N Fragment
+//! - \b SNEP_CONNECTION_SEND_COMPLETE - Send Completed
+//! - \b SNEP_CONNECTION_RECEIVE_COMPLETE - Receive Completed
+//! - \b SNEP_CONNECTION_EXCESS_SIZE - Received Excess Size request
+//!
+//! This function is called inside LLCP_processReceivedData(), to set the
+//! \e g_eSNEPConnectionStatus flag to \b SNEP_CONNECTION_IDLE after
+//! a send transaction is completed to allow for further send transactions.
+//!
+//! \return None
+//
+//*****************************************************************************
+void SNEP_setProtocolStatus(tSNEPConnectionStatus eProtocolStatus)
+{
+ g_eSNEPConnectionStatus = eProtocolStatus;
+ return;
+}
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
+
diff --git a/nfclib/snep.h b/nfclib/snep.h
new file mode 100644
index 0000000..561c688
--- /dev/null
+++ b/nfclib/snep.h
@@ -0,0 +1,206 @@
+//*****************************************************************************
+//
+// snep.h - Simple NDEF Exchange Protocol deffinitions
+//
+// Copyright (c) 2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
+//
+//*****************************************************************************
+#ifndef __NFC_SNEP_H__
+#define __NFC_SNEP_H__
+
+#include "types.h"
+
+//*****************************************************************************
+//
+//! \addtogroup nfc_snep_api NFC SNEP API Functions
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// This size is used to limit the maximum size of the incoming NDEF message.
+// The maximum is dependent on the Maximum Information Units (MIU) defined in
+// the LLCP layer.
+// For example for MIU = 248, SNEP_MAX_BUFFER = 248
+//
+//*****************************************************************************
+//
+//! This is the maximum size of a fragment that is sent/received.
+//
+#define SNEP_MAX_BUFFER 248
+
+//
+//! Maximum size of the incoming payload.
+//
+#define SNEP_MAX_PAYLOAD 20000
+
+//
+//! Simple NDEF protocol version specified in the specification.
+//
+#define SNEP_VERSION 0x10
+
+//*****************************************************************************
+//
+// List of SNEP Commands
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+//! SNEPCommand request / responses enumeration.
+//
+//*****************************************************************************
+typedef enum
+{
+ //
+ // SNEP request field value
+ //
+
+ //! See SNEP V1.0 Section 4.1
+ SNEP_REQUEST_CONTINUE = 0x00,
+
+ //! See SNEP V1.0 Section 4.2
+ SNEP_REQUEST_GET = 0x01,
+
+ //! See SNEP V1.0 Section 4.3
+ SNEP_REQUEST_PUT = 0x02,
+ // 03h-7Eh Reserved for future use
+
+ //! See SNEP V1.0 Section 4.4
+ SNEP_REQUEST_REJECT = 0x7F,
+ // 80h-FFh Reserved for response field values
+
+ //
+ // See SNEP Response Field Values
+ //
+ // 00h-7Fh Reserved for request field values
+
+ //! See SNEP V1.0 Section 5.1
+ SNEP_RESPONSE_CONTINUE = 0x80,
+
+ //! See SNEP V1.0 Section 5.2
+ SNEP_RESPONSE_SUCCESS = 0x81,
+
+ //! See SNEP V1.0 Section 5.3
+ SNEP_RESPONSE_NOT_FOUND = 0xC0,
+
+ //! See SNEP V1.0 Section 5.4
+ SNEP_RESPONSE_EXCESS_DATA = 0xC1,
+
+ //! See SNEP V1.0 Section 5.5
+ SNEP_RESPONSE_BAD_REQUEST = 0xC2,
+
+ //! See SNEP V1.0 Section 5.6
+ SNEP_RESPONSE_NOT_IMPLEMENTED = 0xE0,
+
+ //! See SNEP V1.0 Section 5.7
+ SNEP_RESPONSE_UNSUPPORTED_VER = 0xE1,
+
+ //! See SNEP V1.0 Section 5.8
+ SNEP_RESPONSE_REJECT = 0xFF
+}tSNEPCommands;
+
+//*****************************************************************************
+//
+//! SNEP Connection Status Enumeration.
+//
+//*****************************************************************************
+typedef enum
+{
+ //! No ongoing transaction to/from the client
+ SNEP_CONNECTION_IDLE = 0x00,
+
+ //! Wrong version received
+ SNEP_WRONG_VERSION_RECEIVED,
+
+ //! Received first fragment
+ SNEP_CONNECTION_RECEIVED_FIRST_PACKET,
+
+ //! Received n fragment
+ SNEP_CONNECTION_RECEIVING_N_FRAGMENTS,
+
+ //! Waiting for continue response
+ SNEP_CONNECTION_WAITING_FOR_CONTINUE,
+
+ //! Waiting for success response
+ SNEP_CONNECTION_WAITING_FOR_SUCCESS,
+
+ //! Sending n fragment
+ SNEP_CONNECTION_SENDING_N_FRAGMENTS,
+
+ //! Send completed
+ SNEP_CONNECTION_SEND_COMPLETE,
+
+ //! Receive completed
+ SNEP_CONNECTION_RECEIVE_COMPLETE,
+
+ //! Received excess size request.
+ SNEP_CONNECTION_EXCESS_SIZE
+}tSNEPConnectionStatus;
+
+//*****************************************************************************
+//
+//! RX packet status enumeration.
+//
+//*****************************************************************************
+typedef enum
+{
+ //
+ //! No pending received data
+ //
+ RECEIVED_NO_FRAGMENT = 0,
+
+ //
+ //! First fragment received from the client
+ //
+ RECEIVED_FIRST_FRAGMENT,
+
+ //
+ //! N fragment received from the client
+ RECEIVED_N_FRAGMENT,
+
+ //! Last fragment received from the client - packet completed
+ RECEIVED_FRAGMENT_COMPLETED
+}tPacketStatus;
+
+//*****************************************************************************
+//
+// Function Prototypes
+//
+//*****************************************************************************
+void SNEP_init(void);
+void SNEP_setMaxPayload(uint8_t ui8MaxPayload);
+tStatus SNEP_setupPacket(uint8_t * pui8PacketPtr, uint32_t ui32PacketLength);
+uint8_t SNEP_sendRequest(uint8_t * pui8DataPtr, tSNEPCommands eRequestCmd);
+uint8_t SNEP_sendResponse(uint8_t * pui8DataPtr, tSNEPCommands eResponseCmd);
+void SNEP_processReceivedData(uint8_t * pui8RxBuffer, uint8_t ui8RxLength);
+void SNEP_getReceiveStatus(tPacketStatus * peReceiveFlag, uint8_t * length,
+ uint8_t ** pui8DataPtr);
+tSNEPConnectionStatus SNEP_getProtocolStatus(void);
+void SNEP_setProtocolStatus(tSNEPConnectionStatus eProtocolStatus);
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
+
+#endif // __NFC_SNEP_H__
diff --git a/nfclib/ssitrf79x0.c b/nfclib/ssitrf79x0.c
new file mode 100644
index 0000000..b14a393
--- /dev/null
+++ b/nfclib/ssitrf79x0.c
@@ -0,0 +1,826 @@
+//*****************************************************************************
+//
+// ssitrf79x0.c - SSI Driver for the TI TRF79x0 on the dk-lm3s9b96 board.
+//
+// Copyright (c) 2010-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
+//
+//*****************************************************************************
+#include <stdbool.h>
+#include <stdint.h>
+#include "inc/hw_gpio.h"
+#include "inc/hw_memmap.h"
+#include "inc/hw_ssi.h"
+#include "inc/hw_types.h"
+#include "driverlib/gpio.h"
+#include "driverlib/pin_map.h"
+#include "driverlib/rom.h"
+#include "driverlib/rom_map.h"
+#include "driverlib/ssi.h"
+#include "driverlib/sysctl.h"
+#include "ssitrf79x0.h"
+#include "trf79x0.h"
+#include "trf79x0_hw.h"
+
+//*****************************************************************************
+//
+// Raw SPI through SSI access API for the TRF79x0. Most user code will not and
+// should not call these functions but instead use the provided higher level
+// functions in trf79x0.c, directmode.c and iso14443a.c.
+//
+//*****************************************************************************
+//*****************************************************************************
+//
+// Global that holds the clock speed of the MicroController in Hz.
+//
+//*****************************************************************************
+extern uint32_t g_ui32SysClk;
+
+//*****************************************************************************
+//
+// The rate of the SSI clock and derived values.
+//
+//*****************************************************************************
+#define SSI_CLKS_PER_MS (SSI_CLK_RATE / 1000)
+#define STATUS_READS_PER_MS (SSI_CLKS_PER_MS / 16)
+#define SSI_NO_DATA 0
+
+//*****************************************************************************
+//
+// Internal helper function that sends a buffer of data to the TRF79x0, used
+// by all the functions that need to send bytes.
+//
+//*****************************************************************************
+void
+SSITRF79x0GenericWrite(unsigned char const *pucBuffer, unsigned int uiLength)
+{
+ uint32_t ulDummyData;
+
+ while(uiLength > 0)
+ {
+ //
+ // Write address/command/data and clear SSI register of dummy data.
+ //
+ MAP_SSIDataPut(TRF79X0_SSI_BASE, (unsigned long)*pucBuffer);
+ //
+ // Wait until the SSI Module is completed sending uiLength bytes to the SSI module.
+ //
+ while(SSIBusy(TRF79X0_SSI_BASE) == true);
+ MAP_SSIDataGet(TRF79X0_SSI_BASE, &ulDummyData);
+
+ //
+ // Post increment counters.
+ //
+ pucBuffer++;
+ uiLength--;
+ }
+
+
+}
+
+//*****************************************************************************
+//
+// Internal helper function used by all the functions that need to send bytes.
+//
+//*****************************************************************************
+void
+SSITRF79x0DummyWrite(unsigned char const *pucBuffer, unsigned int uiLength)
+{
+ uint32_t ulDummyData;
+
+ while(uiLength > 0)
+ {
+ //
+ // Write address/command/data and clear SSI register of dummy data.
+ //
+ SSIDataPut(TRF79X0_SSI_BASE, (unsigned long)*pucBuffer);
+ SSIDataGet(TRF79X0_SSI_BASE, &ulDummyData);
+
+ //
+ // Post increment counters.
+ //
+ pucBuffer++;
+ uiLength--;
+ }
+}
+
+//*****************************************************************************
+//
+// Internal helper function that receives a buffer of data from the TRF79x0,
+// used by all the functions that need to read bytes.
+//
+//*****************************************************************************
+static void
+SSITRF79x0GenericRead(unsigned char *pucBuffer, unsigned int uiLength)
+{
+ uint32_t ulData;
+
+ while(uiLength > 0)
+ {
+ //
+ // Write dummy data for SSI clock and read data from SSI register.
+ //
+ MAP_SSIDataPut(TRF79X0_SSI_BASE, (unsigned long)SSI_NO_DATA);
+ //
+ // Wait until the SSI Module is completed sending uiLength bytes to the SSI module.
+ //
+ while(SSIBusy(TRF79X0_SSI_BASE) == true);
+ MAP_SSIDataGet(TRF79X0_SSI_BASE, &ulData);
+// SSIDataGet(TRF79X0_SSI_BASE, &ulData);
+
+ //
+ // Read data into buffers and post increment counters.
+ //
+ *pucBuffer++ = (unsigned char)ulData;
+
+ uiLength--;
+ }
+
+}
+
+//*****************************************************************************
+//
+// Asserts the chip select for the TRF79x0.
+//
+//*****************************************************************************
+void
+SSITRF79x0ChipSelectAssert(void)
+{
+ //
+ // Disable the interrupt associated with the TRF79x0.
+ //
+ TRF79x0InterruptDisable();
+
+ //
+ // Assert the chip select for TRF79x0.
+ //
+ MAP_GPIOPinWrite(TRF79X0_CS_BASE, TRF79X0_CS_PIN, 0);
+}
+
+//*****************************************************************************
+//
+// Deasserts the chip select for the TRF79x0
+//
+//*****************************************************************************
+void
+SSITRF79x0ChipSelectDeAssert(void)
+{
+ //
+ // Deassert the chip select for the TRF79x0.
+ //
+ MAP_GPIOPinWrite(TRF79X0_CS_BASE, TRF79X0_CS_PIN, TRF79X0_CS_PIN);
+
+ //
+ // Enable interrupt associated with the TRF79x0.
+ //
+ TRF79x0InterruptEnable();
+}
+
+//*****************************************************************************
+//
+// Initializes the SSI port and determines if the TRF79x0 is available.
+//
+// This function must be called prior to any other function offered by the
+// TRF79x0. It configures the SSI port to run in Motorola/Freescale
+// mode.
+//
+// \return None.
+//
+//*****************************************************************************
+void
+SSITRF79x0Init(void)
+{
+ //
+ // Enable the peripherals used to drive the TRF79x0 on SSI.
+ //
+ MAP_SysCtlPeripheralEnable(TRF79X0_SSI_PERIPH);
+
+ //
+ // Enable the GPIO peripherals associated with the SSI.
+ //
+ MAP_SysCtlPeripheralEnable(TRF79X0_CLK_PERIPH);
+ MAP_SysCtlPeripheralEnable(TRF79X0_RX_PERIPH);
+ MAP_SysCtlPeripheralEnable(TRF79X0_TX_PERIPH);
+ MAP_SysCtlPeripheralEnable(TRF79X0_CS_PERIPH);
+
+ //
+ // Configure the appropriate pins to be SSI instead of GPIO. The CS
+ // is configured as GPIO to support TRF79x0 SPI requirements for R/W
+ // access.
+ //
+ MAP_GPIOPinConfigure(TRF79X0_CLK_CONFIG);
+ MAP_GPIOPinConfigure(TRF79X0_RX_CONFIG);
+ MAP_GPIOPinConfigure(TRF79X0_TX_CONFIG);
+ MAP_GPIOPinTypeSSI(TRF79X0_CLK_BASE, TRF79X0_CLK_PIN);
+ MAP_GPIOPinTypeSSI(TRF79X0_RX_BASE, TRF79X0_RX_PIN);
+ MAP_GPIOPinTypeSSI(TRF79X0_TX_BASE, TRF79X0_TX_PIN);
+ MAP_GPIOPinTypeGPIOOutput(TRF79X0_CS_BASE, TRF79X0_CS_PIN);
+
+ MAP_GPIOPadConfigSet(TRF79X0_CLK_BASE, TRF79X0_CLK_PIN,
+ GPIO_STRENGTH_4MA, GPIO_PIN_TYPE_STD_WPU);
+ MAP_GPIOPadConfigSet(TRF79X0_RX_BASE, TRF79X0_RX_PIN,
+ GPIO_STRENGTH_4MA, GPIO_PIN_TYPE_STD_WPU);
+ MAP_GPIOPadConfigSet(TRF79X0_TX_BASE, TRF79X0_TX_PIN,
+ GPIO_STRENGTH_4MA, GPIO_PIN_TYPE_STD_WPU);
+
+ //
+ // Deassert the SSI chip selects TRF79x0.
+ //
+ MAP_GPIOPinWrite(TRF79X0_CS_BASE, TRF79X0_CS_PIN, TRF79X0_CS_PIN);
+
+ //
+ // Configure the SSI port for 2MHz operation.
+ //
+ MAP_SSIConfigSetExpClk(TRF79X0_SSI_BASE, g_ui32SysClk,
+ SSI_FRF_MOTO_MODE_0, SSI_MODE_MASTER, SSI_CLK_RATE,
+ 8);
+
+ if(RF_DAUGHTER_TRF7970)
+ {
+ //
+ // Switch from SPH=0 to SPH=1. Required for TRF7970.
+ //
+ HWREG(TRF79X0_SSI_BASE + SSI_O_CR0) |= SSI_CR0_SPH;
+ }
+
+ //
+ // Enable the SSI controller.
+ //
+ MAP_SSIEnable(TRF79X0_SSI_BASE);
+}
+
+//*****************************************************************************
+//
+// Writes a single value to TRF79x0 for address provided.
+//
+// \param ucAddress is the register address to write and must be between 0
+// and 0x1f, inclusive.
+// \param ucData is the data byte to write.
+//
+// This function asserts the TRF79x0 chip select, sends a write command,
+// the single data value and then deasserts the chip select.
+//
+// \return None.
+//
+//*****************************************************************************
+void
+SSITRF79x0WriteRegister(unsigned char ucAddress, unsigned char ucData)
+{
+ unsigned char pucCommand[2];
+
+ //
+ // Assert the chip select for TRF79x0.
+ //
+ SSITRF79x0ChipSelectAssert();
+
+ //
+ // Isolate register address.
+ //
+ ucAddress = ucAddress & TRF79X0_ADDRESS_MASK;
+
+ //
+ // Add TRF79x0 write single command.
+ //
+ ucAddress |= TRF79X0_CONTROL_REG_WRITE | TRF79X0_REG_MODE_SINGLE;
+
+ //
+ // Put the address and data into the buffer.
+ //
+ pucCommand[0] = ucAddress;
+ pucCommand[1] = ucData;
+
+ //
+ // Start the write.
+ //
+ SSITRF79x0GenericWrite(pucCommand, sizeof(pucCommand));
+
+ //
+ // Deassert the chip select for the TRF79x0.
+ //
+ SSITRF79x0ChipSelectDeAssert();
+}
+
+//*****************************************************************************
+//
+// Starts a continuous write operation to the given address.
+//
+// \param ucAddress is the register address to start this write command and
+// must be between 0 and 0x1f, inclusive.
+//
+// This function asserts the TRF79x0 chip select and sends a write continuous
+// command. The chip select stays asserted when the function returns and must
+// be released with SSITRF79x0WriteContinuousStop().
+//
+// Typical usage for a write to multiple registers at once is: one call to
+// SSITRF79x0WriteContinuousStart(), one or more calls to
+// SSITRF79x0WriteContinuousData() and one call to
+// SSITRF79x0WriteContinuousStop().
+//
+// \sa SSITRF79x0WriteContinuousData()
+//
+// \return None.
+//
+//*****************************************************************************
+void
+SSITRF79x0WriteContinuousStart(unsigned char ucAddress)
+{
+ //
+ // Assert the chip select for TRF79x0.
+ //
+ SSITRF79x0ChipSelectAssert();
+
+ //
+ // Isolate register address.
+ //
+ ucAddress = ucAddress & TRF79X0_ADDRESS_MASK;
+
+ //
+ // Add TRF79x0 write continuous command.
+ //
+ ucAddress |= TRF79X0_CONTROL_REG_WRITE | TRF79X0_REG_MODE_CONTINUOUS;
+
+ SSITRF79x0GenericWrite(&ucAddress, 1);
+
+ //
+ // Keep chip select asserted for follow-up calls to
+ // SSITRF79x0WriteContinuousData(). Calling code must ensure to finish
+ // with SSITRF79x0WriteContinuousStop().
+ //
+}
+
+//*****************************************************************************
+//
+// Starts a direct continous write operation
+//
+// This function asserts the chip select for the TRF79x0.
+//
+// \return None
+//
+//*****************************************************************************
+void
+SSITRF79x0WriteDirectContinuousStart(void)
+{
+ //
+ // Assert the chip select for TRF79x0.
+ //
+ SSITRF79x0ChipSelectAssert();
+}
+
+//*****************************************************************************
+//
+// Sends data in continuous write mode.
+//
+// \param pucBuffer is a pointer to the data buffer to write.
+// \param uiLength is the length of the data to write in bytes.
+//
+// This function sends data from the buffer to the TRF79x0. The write must
+// have been previously set up with SSITRF79x0WriteContinuousStart().
+//
+// \return None.
+//
+//*****************************************************************************
+void
+SSITRF79x0WriteContinuousData(unsigned char const *pucBuffer,
+ unsigned int uiLength)
+{
+ SSITRF79x0GenericWrite(pucBuffer, uiLength);
+}
+
+//*****************************************************************************
+//
+// Stops a continuous write operation.
+//
+// This function deasserts the TRF79x0 chip select.
+//
+// \return None.
+//
+//*****************************************************************************
+void
+SSITRF79x0WriteContinuousStop(void)
+{
+ //
+ // Deassert the chip select for the TRF79x0.
+ //
+ SSITRF79x0ChipSelectDeAssert();
+}
+
+//*****************************************************************************
+//
+// Reads a single value from TRF79x0 at the address provided.
+//
+// \param ucAddress is the register address to read and must be between 0
+// and 0x1f, inclusive.
+//
+// This function asserts the TRF79x0 chip select, sends a read command,
+// reads a single byte and then deasserts the chip select.
+//
+// \return This function returns the value that was stored in the given
+// register.
+//
+//*****************************************************************************
+unsigned char
+SSITRF79x0ReadRegister(unsigned char ucAddress)
+{
+ unsigned char ucData = 0;
+
+ //
+ // Assert the chip select for TRF79x0.
+ //
+ SSITRF79x0ChipSelectAssert();
+
+ //
+ // Isolate register address.
+ //
+ ucAddress = ucAddress & TRF79X0_ADDRESS_MASK;
+
+ //
+ // Add TRF79x0 read single command.
+ //
+ ucAddress |= TRF79X0_CONTROL_REG_READ | TRF79X0_REG_MODE_SINGLE;
+
+ SSITRF79x0GenericWrite(&ucAddress, 1);
+
+ if(RF_DAUGHTER_TRF7960)
+ {
+ //
+ // Switch from SPH=0 to SPH=1.
+ //
+ HWREG(TRF79X0_SSI_BASE + SSI_O_CR0) |= SSI_CR0_SPH;
+ }
+
+ //
+ // Get the data.
+ //
+ SSITRF79x0GenericRead(&ucData, 1);
+
+ if(RF_DAUGHTER_TRF7960)
+ {
+ //
+ // Switch from SPH=1 to SPH=0.
+ //
+ HWREG(TRF79X0_SSI_BASE + SSI_O_CR0) &= ~SSI_CR0_SPH;
+ }
+
+ //
+ // Deassert the chip select for the TRF79x0.
+ //
+ SSITRF79x0ChipSelectDeAssert();
+
+ return(ucData);
+}
+
+//*****************************************************************************
+//
+// Starts a continuous read operation from the given address.
+//
+// \param ucAddress is the register address to start this read command and must
+// be between 0 and 0x1f, inclusive.
+//
+// This function asserts the TRF79x0 chip select and sends a read continuous
+// command. The chip select stays asserted when the function returns and must
+// be released with SSITRF79x0ReadContinuousStop().
+//
+// Typical usage for a read from multiple registers at once is: one call to
+// SSITRF79x0ReadContinuousStart(), one or more calls to
+// SSITRF79x0ReadContinuousData() and one call to
+// SSITRF79x0ReadContinuousStop().
+//
+// \sa SSITRF79x0ReadContinuousData()
+//
+// \return None.
+//
+//*****************************************************************************
+void
+SSITRF79x0ReadContinuousStart(unsigned char ucAddress)
+{
+ //
+ // Assert the chip select for TRF79x0.
+ //
+ SSITRF79x0ChipSelectAssert();
+
+ //
+ // Isolate register address.
+ //
+ ucAddress = ucAddress & TRF79X0_ADDRESS_MASK;
+
+ //
+ // Add TRF79x0 read continuous command.
+ //
+ ucAddress |= TRF79X0_CONTROL_REG_READ | TRF79X0_REG_MODE_CONTINUOUS;
+
+ SSITRF79x0GenericWrite(&ucAddress, 1);
+
+ if(RF_DAUGHTER_TRF7960)
+ {
+ //
+ // Switch from SPH=0 to SPH=1.
+ //
+ HWREG(TRF79X0_SSI_BASE + SSI_O_CR0) |= SSI_CR0_SPH;
+ }
+}
+
+//*****************************************************************************
+//
+// Receives data in continuous read mode.
+//
+// \param pucBuffer is a pointer to the data buffer to receive data.
+// \param uiLength is the length of the data to read in bytes.
+//
+// This function reads data from the the TRF79x0 into the buffer. The read
+// must have been previously set up with SSITRF79x0ReadContinuousStart().
+//
+// \return None.
+//
+//*****************************************************************************
+void
+SSITRF79x0ReadContinuousData(unsigned char *pucBuffer, unsigned int uiLength)
+{
+ SSITRF79x0GenericRead(pucBuffer, uiLength);
+}
+
+//*****************************************************************************
+//
+// Stop a continuous read operation.
+//
+// This function deasserts the TRF79x0 chip select.
+//
+// \return None.
+//
+//*****************************************************************************
+void
+SSITRF79x0ReadContinuousStop(void)
+{
+ if(RF_DAUGHTER_TRF7960)
+ {
+ //
+ // Switch from SPH=1 to SPH=0.
+ //
+ HWREG(TRF79X0_SSI_BASE + SSI_O_CR0) &= ~SSI_CR0_SPH;
+ }
+
+ //
+ // Deassert the chip select for the TRF79x0.
+ //
+ SSITRF79x0ChipSelectDeAssert();
+}
+
+//*****************************************************************************
+//
+// Reads IRQ status value from TRF79x0.
+//
+// This function reads the TRF79x0 IRQ status register 0x0c and returns its
+// contents. This will make the TRF79x0 release its interrupt request.
+//
+// \note You should use this function instead of a direct read from register
+// 0x0c if you want to retrieve the IRQ status since this function applies
+// a special workaround as indicated in SLOA140.
+//
+// \return Returns the IRQ status
+//
+//*****************************************************************************
+unsigned char
+SSITRF79x0ReadIRQStatus(void)
+{
+ unsigned char pucData[2];
+
+ //
+ // Workaround as per SLOA140: When reading the IRQ status register, do a
+ // continuous read with an additional register to ensure at least one
+ // additional SPI clock after reading the IRQ status. Ignore the second
+ // read result.
+ //
+
+ SSITRF79x0ReadContinuousStart(TRF79X0_IRQ_STATUS_REG);
+ SSITRF79x0ReadContinuousData(pucData, sizeof(pucData));
+ SSITRF79x0ReadContinuousStop();
+
+ return(pucData[0]);
+}
+
+//*****************************************************************************
+//
+// Executes a direct command on the TRF79x0.
+//
+// \param ucCommand is the command to be executed and must be a valid command
+// code between 0 and 0x1f. Definitions for command codes are given in
+// trf79x0.h.
+//
+// \note This function applies a special workaround as indicated in SLOA140.
+//
+// \return Returns void.
+//
+//*****************************************************************************
+void
+SSITRF79x0WriteDirectCommand(unsigned char ucCommand)
+{
+ unsigned char pucCommand[2];
+
+ //
+ // Assert the chip select for TRF79x0.
+ //
+ SSITRF79x0ChipSelectAssert();
+
+ //
+ // Add TRF79x0 direct command.
+ //
+ ucCommand = ucCommand | TRF79X0_CONTROL_CMD;
+
+ //
+ // Workaround as per SLOA140: When sending a command, add a dummy cycle.
+ //
+ pucCommand[0] = ucCommand;
+ pucCommand[1] = SSI_NO_DATA;
+
+ if(ucCommand == TRF79X0_RESET_FIFO_CMD)
+ {
+ SSITRF79x0GenericWrite(pucCommand, sizeof(pucCommand));
+ }
+ else
+ {
+ SSITRF79x0GenericWrite(pucCommand, 1);
+ }
+
+ //
+ // Deassert the chip select for the TRF79x0.
+ //
+ SSITRF79x0ChipSelectDeAssert();
+}
+
+//*****************************************************************************
+//
+// Write Direct Command Tailored for 7970 chip. Ported for redundancy
+//
+// \param ucCommand is the command to be executed and must be a valid command
+// code between 0 and 0x1f. Definitions for command codes are given in
+// trf79x0.h. A dummy command is sent after the direct command to handle
+// issues with the last command somtimes not processing.
+//
+//*****************************************************************************
+void
+SSITRF79x0WriteDirectCommandWithDummy(unsigned char ucCommand)
+{
+ unsigned char pucCommand[2];
+
+ //
+ // Assert the chip select for TRF7970.
+ //
+ SSITRF79x0ChipSelectAssert();
+
+ //
+ // Add TRF7970 direct command.
+ //
+ ucCommand = ucCommand | TRF79X0_CONTROL_CMD;
+
+ //
+ // Workaround as per SLOA140: When sending a command, add a dummy cycle.
+ //
+ pucCommand[0] = ucCommand;
+ pucCommand[1] = SSI_NO_DATA;
+
+ SSITRF79x0GenericWrite(pucCommand, sizeof(pucCommand));
+
+ //
+ // Deassert the chip select for the TRF7970.
+ //
+ SSITRF79x0ChipSelectDeAssert();
+}
+
+//*****************************************************************************
+//
+// Executes a Reset direct command on the TRF79x0.
+//
+// \param ucCommand is the command to be executed and must be a valid command
+// code between 0 and 0x1f. Definitions for command codes are given in
+// trf79x0.h.
+//
+// \note This function applies a special workaround as indicated in SLOA140.
+//
+// \return Returns void.
+//
+//*****************************************************************************
+void
+SSITRF79x0WriteResetFifoDirectCommand(unsigned char ucCommand)
+{
+ unsigned char pucCommand[1];
+
+ //
+ // Assert the chip select for TRF79x0.
+ //
+ SSITRF79x0ChipSelectAssert();
+
+ //
+ // Add TRF79x0 direct command.
+ //
+ ucCommand = ucCommand | TRF79X0_CONTROL_CMD;
+
+ //
+ // Workaround as per SLOA140: When sending a command, add a dummy cycle.
+ //
+ pucCommand[0] = ucCommand;
+
+ SSITRF79x0GenericWrite(pucCommand, sizeof(pucCommand));
+
+ //
+ // Deassert the chip select for the TRF79x0.
+ //
+ SSITRF79x0ChipSelectDeAssert();
+}
+
+//*****************************************************************************
+//
+// Executes: writes a packet to the TRF79x0
+//
+// \param pui8Buffer
+// \param ui8CRCBit
+// \param ui8TotalLength
+// \param ui8PayloadLength
+// \param bHeaderEnable
+//
+// \note
+//
+// \return Returns void.
+//
+//*****************************************************************************
+void SSITRF79x0WritePacket(uint8_t *pui8Buffer, uint8_t ui8CRCBit, \
+ uint8_t ui8TotalLength, uint8_t ui8PayloadLength, bool bHeaderEnable)
+{
+ uint8_t ui8LengthLowerNibble = (ui8TotalLength & 0x0F) << 4;
+ uint8_t ui8LengthHigherNibble = (ui8TotalLength & 0xF0) >> 4;
+ uint8_t pui8HeaderData[2];
+
+ //
+ // Assert the chip select for TRF79x0.
+ //
+ SSITRF79x0ChipSelectAssert();
+
+ if(bHeaderEnable == true)
+ {
+ // RESET FIFO
+ //while (!(IFG2 & UCB0TXIFG)); // USCI_B0 TX buffer ready?
+ pui8HeaderData[0] = 0x8F; // Previous data to TX, RX
+ SSITRF79x0GenericWrite(pui8HeaderData,1);
+ //while(UCB0STAT & UCBUSY);
+
+ // CRC COMMAND
+ //while (!(IFG2 & UCB0TXIFG)); // USCI_B0 TX buffer ready?
+ pui8HeaderData[0] = 0x90 | (ui8CRCBit & 0x01); // Previous data to TX, RX
+ SSITRF79x0GenericWrite(pui8HeaderData,1);
+ //while(UCB0STAT & UCBUSY);
+
+ // WRITE TO LENGTH REG
+ //while (!(IFG2 & UCB0TXIFG)); // USCI_B0 TX buffer ready?
+ pui8HeaderData[0] = 0x3D;
+ SSITRF79x0GenericWrite(pui8HeaderData,1);
+ //while(UCB0STAT & UCBUSY);
+
+ // LENGTH HIGH Nibble
+ //while (!(IFG2 & UCB0TXIFG)); // USCI_B0 TX buffer ready?
+ pui8HeaderData[0] = ui8LengthHigherNibble; // Previous data to TX, RX
+ SSITRF79x0GenericWrite(pui8HeaderData,1);
+ //while(UCB0STAT & UCBUSY);
+
+ // LENGTH LOW Nibble
+ //while (!(IFG2 & UCB0TXIFG)); // USCI_B0 TX buffer ready?
+ pui8HeaderData[0] = ui8LengthLowerNibble; // Previous data to TX, RX
+ SSITRF79x0GenericWrite(pui8HeaderData,1);
+ //while(UCB0STAT & UCBUSY);
+ }
+ else
+ {
+ //while (!(IFG2 & UCB0TXIFG)); // USCI_B0 TX buffer ready?
+ pui8HeaderData[0] = 0x3F;
+ SSITRF79x0GenericWrite(pui8HeaderData,1);
+ //while(UCB0STAT & UCBUSY);
+ }
+
+
+ SSITRF79x0GenericWrite(pui8Buffer,ui8PayloadLength);
+ //while(ui8PayloadLength > 0)
+ //{
+ // while (!(IFG2 & UCB0TXIFG)); // USCI_B0 TX buffer ready?
+ // UCB0TXBUF = *pui8Buffer; // Previous data to TX, RX
+ // while(UCB0STAT & UCBUSY);
+ // pui8Buffer++;
+ // ui8PayloadLength--;
+ //}
+
+ //
+ // Deassert the chip select for the TRF79x0.
+ //
+ SSITRF79x0ChipSelectDeAssert();
+}
diff --git a/nfclib/ssitrf79x0.h b/nfclib/ssitrf79x0.h
new file mode 100644
index 0000000..5b9f8f3
--- /dev/null
+++ b/nfclib/ssitrf79x0.h
@@ -0,0 +1,62 @@
+//*****************************************************************************
+//
+// ssitrf79x0.h - Header file for the TI TRF79x0 SSI driver for the
+// dk-lm3s9b96 boards.
+//
+// Copyright (c) 2010-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
+//
+//*****************************************************************************
+
+#ifndef __SSITRF79X0_H__
+#define __SSITRF79X0_H__
+
+//*****************************************************************************
+//
+// Exported function prototypes.
+//
+//*****************************************************************************
+extern void SSITRF79x0Init(void);
+extern void SSITRF79x0WriteRegister(unsigned char ucAddress,
+ unsigned char ucData);
+extern void SSITRF79x0WriteContinuousStart(unsigned char ucAddress);
+extern void SSITRF79x0WriteContinuousData(unsigned char const *pucBuffer,
+ unsigned int uiLength);
+extern void SSITRF79x0WriteContinuousStop(void);
+extern unsigned char SSITRF79x0ReadRegister(unsigned char ucAddress);
+extern void SSITRF79x0ReadContinuousStart(unsigned char ucAddress);
+extern void SSITRF79x0ReadContinuousData(unsigned char *pucBuffer,
+ unsigned int uiLength);
+extern void SSITRF79x0ReadContinuousStop(void);
+extern unsigned char SSITRF79x0ReadIRQStatus(void);
+extern void SSITRF79x0WriteDirectCommand(unsigned char ucCommand);
+extern void SSITRF79x0WriteDirectContinuousStart(void);
+extern void SSITRF79x0WriteResetFifoDirectCommand(unsigned char ucCommand);
+extern void SSITRF79x0DummyWrite(unsigned char const *pucBuffer,
+ unsigned int uiLength);
+extern void SSITRF79x0WriteDirectCommandWithDummy(unsigned char ucCommand);
+extern void SSITRF79x0WritePacket(uint8_t *pui8Buffer, uint8_t ui8CRCBit,
+ uint8_t ui8TotalLength, uint8_t ui8PayloadLength,
+ bool eHeaderEnable);
+
+extern void SSITRF79x0ChipSelectAssert(void);
+extern void SSITRF79x0GenericWrite(unsigned char const *pucBuffer, unsigned int uiLength);
+extern void SSITRF79x0ChipSelectDeAssert(void);
+
+
+#endif // __SSITRF79X0_H__
diff --git a/nfclib/trf79x0.c b/nfclib/trf79x0.c
new file mode 100644
index 0000000..f0405e4
--- /dev/null
+++ b/nfclib/trf79x0.c
@@ -0,0 +1,1961 @@
+//*****************************************************************************
+//
+// trf79x0.c - Driver for the TI TRF79x0 on the dk-lm3s9b96 board.
+//
+// Copyright (c) 2010-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
+//
+//*****************************************************************************
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "inc/hw_memmap.h"
+#include "inc/hw_types.h"
+#include "inc/hw_ssi.h"
+#include "inc/hw_gpio.h"
+#include "inc/hw_ints.h"
+#include "driverlib/gpio.h"
+#include "driverlib/ssi.h"
+#include "driverlib/sysctl.h"
+#include "driverlib/interrupt.h"
+#include "driverlib/rom.h"
+#include "driverlib/timer.h"
+#include "utils/uartstdio.h"
+#include "ssitrf79x0.h"
+#include "trf79x0_hw.h"
+#include "trf79x0.h"
+#include "nfc.h"
+#include "nfclib/debug.h"
+
+//extern unsigned char g_ucNfcWorkMode = NFC_NONE;
+
+//*****************************************************************************
+//
+// Global Defines
+//
+//*****************************************************************************
+#define NFC_FIFO_SIZE 255
+// Fifo size depends on the maximum payload size defined in LLCP.h
+uint8_t g_fifo_buffer[NFC_FIFO_SIZE];
+uint8_t g_fifo_bytes_received = 0;
+volatile uint8_t g_irq_flag = 0x00;
+volatile uint8_t g_time_out_flag = 0x00;
+
+tTRF79x0TRFMode g_selected_mode = BOARD_INIT;
+tTRF79x0Frequency g_selected_frequency = FREQ_STAND_BY;
+
+// Used for debugging
+#define OUTPUT_FIFO_ENABLE 0
+
+#define TRF7970A_5V_OPERATION 0x01
+
+//*****************************************************************************
+//
+// A global variable indicating which RF daughter board, if any, is currently
+// connected to the development board.
+//
+//*****************************************************************************
+tRFDaughterBoard g_eRFDaughterType = RF_DAUGHTER_NONE;
+
+//*****************************************************************************
+//
+// API for the TRF79x0. Provides register read/write access, command
+// execution, abstracted access to IRQ results and comprehensive transceiver
+// functionality for higher-layer frame transmission and reception.
+//
+// Most user code will only need TRF79x0Init() from this module to set up
+// and initialize the TRF79x0 and will then use the functions defined by
+// some higher layer protocol, such as from iso14443a.c.
+//
+//*****************************************************************************
+//*****************************************************************************
+//
+// The number of counts to pass to SysCtlDelay() to get approximately 1ms
+// delay.
+//
+//*****************************************************************************
+static unsigned long g_ulDelayms;
+
+//*****************************************************************************
+//
+// Global that holds the clock speed of the MicroController in Hz.
+//
+//*****************************************************************************
+extern uint32_t g_ui32SysClk;
+
+//*****************************************************************************
+//
+// This structure holds information about encountered IRQs. The collision
+// position can be queried by TRF79x0GetCollisionPosition().
+// TRF79x0IRQWait() and TRF79x0IRQWaitTimeout() can be used to wait for
+// an interrupt cause to be asserted. TRF79x0IRQClearAll() and
+// TRF79x0IRQClearCauses() can be used to clear indicated causes from this
+// structure, since TRF79x0IRQWait()/TRF79x0IRQWaitTimeout() do not do
+// that.
+//
+//*****************************************************************************
+static volatile struct
+{
+ //
+ // This stores the contents of the IRQ status register at the most recent
+ // IRQ. However, the contents of this field are not reliable since IRQs
+ // may occur shortly after one another and a loop that simply queries state
+ // might miss all but the last of these.
+ //
+ unsigned char ucState;
+
+ //
+ // Indicates whether a collision was detected since the last call to
+ // TRF79x0GetCollisionPosition().
+ //
+ unsigned char ucCollisionDetected;
+
+ //
+ // Stores the last collision position as returned in registers
+ // 0xd and 0xe.
+ //
+ unsigned int uiCollisionPosition;
+
+ //
+ // Bitfield tracking the occurrence of abstract interrupt causes. The
+ // values of enum TRF79x0WaitCondition are used as indices into the
+ // bitfield, e.g. for a TRF79X0_WAIT_TXEND interrupt the bit at
+ // <tt>(1<<TRF79X0_WAIT_TXEND)</tt> is set.
+ //
+ unsigned int uiIrqCauses;
+}
+g_sIRQState;
+
+//*****************************************************************************
+//
+// Definitions for different interrupt status bits.
+//
+//*****************************************************************************
+#define TX_FIFO_ALMOST_EMPTY 0xA0
+#define TX_COMPLETE 0x80
+#define RX_FIFO_ALMOST_FULL 0x60
+#define RX_COMPLETE 0x40
+#define COLLISION_DETECTED 0x02
+
+//*****************************************************************************
+//
+// Timeout to apply while waiting for reception, this is expressed in
+// milliseconds.
+//
+// For a more accurate timeout indication you can program the no-response
+// timer in the TRF79x0 and must enable the no-response interrupt.
+//
+//*****************************************************************************
+#define TRF79X0_RX_TIMEOUT 10
+
+//*****************************************************************************
+//
+// This structure holds information about the transmission state for use by
+// the FIFO refill algorithm in the IRQ handler. It is set up by
+// TRF79x0FIFOWrite().
+//
+//*****************************************************************************
+static volatile struct
+{
+ //
+ // Pointer to the next byte to be transmitted
+ //
+ unsigned char const *pucBuffer;
+
+ //
+ // Number of bytes left that need to be transmitted
+ //
+ unsigned int uiBytesRemaining;
+} g_sTXState;
+
+//*****************************************************************************
+//
+// This structure holds information about the reception state for use by the
+// FIFO read algorithm in the IRQ handler. It is set up by TRF79x0Receive().
+//
+//*****************************************************************************
+static volatile struct
+{
+ //
+ // Pointer to write the next received byte to.
+ //
+ unsigned char *pucBuffer;
+
+ //
+ // Pointer to the received length counter. This is the counter that is
+ // passed in to TRF79x0Receive(). The integer that this pointer points
+ // to contains the number of bytes that were received (and stored in
+ // pucBuffer).
+ //
+ unsigned int *puiLength;
+
+ //
+ // Length of the buffer that pucBuffer pointed to at the start of
+ // reception. No more bytes are received when *puiLength equals this
+ // value.
+ //
+ unsigned int uiMaxLength;
+} g_sRXState;
+
+//*****************************************************************************
+//
+// Initializes the TRF79x0 and its communication interface.
+//
+// This function must be called prior to any other function offered by the
+// TRF79x0. This function initializes the GPIO and pin settings, sets up the
+// communication interface by calling SSITRF79x0Init() and sets up the
+// interrupt handler by calling TRF79x0InterruptInit().
+//
+// \return None.
+//
+//*****************************************************************************
+void
+TRF79x0Init(void)
+{
+ //
+ // Set up GPIO resources for bit-banging output access to EN and MOD
+ // and input for IRQ.
+ //
+ SysCtlPeripheralEnable(TRF79X0_EN_PERIPH);
+ SysCtlPeripheralEnable(TRF79X0_IRQ_PERIPH);
+ if(g_eRFDaughterType != RF_DAUGHTER_TRF7970ABP)
+ {
+ SysCtlPeripheralEnable(TRF79X0_MOD_PERIPH);
+ SysCtlPeripheralEnable(TRF79X0_EN2_PERIPH);
+ SysCtlPeripheralEnable(TRF79X0_ASKOK_PERIPH);
+ }
+
+ //
+ // Set the IRQ pin as an input.
+ //
+ GPIOPinTypeGPIOInput(TRF79X0_IRQ_BASE, TRF79X0_IRQ_PIN);
+
+ //
+ // Set the EN, EN2, MOD, and ASKOK pins as outputs.
+ //
+ GPIOPinTypeGPIOOutput(TRF79X0_EN_BASE, TRF79X0_EN_PIN);
+ if(g_eRFDaughterType != RF_DAUGHTER_TRF7970ABP)
+ {
+ GPIOPinTypeGPIOOutput(TRF79X0_EN2_BASE, TRF79X0_EN2_PIN);
+ GPIOPinTypeGPIOOutput(TRF79X0_MOD_BASE, TRF79X0_MOD_PIN);
+ GPIOPinTypeGPIOOutput(TRF79X0_ASKOK_BASE, TRF79X0_ASKOK_PIN);
+ }
+
+ //
+ // Set the MOD and ASKOK pins to start with a low value.
+ //
+ if(g_eRFDaughterType != RF_DAUGHTER_TRF7970ABP)
+ {
+ GPIOPinWrite(TRF79X0_MOD_BASE, TRF79X0_MOD_PIN, 0);
+ GPIOPinWrite(TRF79X0_ASKOK_BASE, TRF79X0_ASKOK_PIN, 0);
+ }
+
+ //
+ // Set up the SSI communication interface.
+ //
+ SSITRF79x0Init();
+
+ //
+ // Calculate the number of units for a 1ms delay using SysCtlDelay().
+ //
+ // NOTE: the ifdef is necessary because of an API change
+ //
+#ifdef TARGET_IS_TM4C123_RA1
+ //
+ // Blizzard Silicon (and before)
+ //
+ g_ulDelayms=(SysCtlClockGet()/3000);
+#else
+ //
+ // Snowflake Silicon (and after)
+ //
+ g_ulDelayms = (g_ui32SysClk / 3000);
+#endif
+
+ //
+ // Force a toggle on the EN and EN2 pins.
+ //
+ GPIOPinWrite(TRF79X0_EN_BASE, TRF79X0_EN_PIN, 0);
+ GPIOPinWrite(TRF79X0_EN_BASE, TRF79X0_EN_PIN,
+ TRF79X0_EN_PIN);
+
+// //
+// // Delay 2ms between ENABLE.
+// //
+// SysCtlDelay(g_ulDelayms * 2);
+//
+// GPIOPinWrite(TRF79X0_EN2_BASE, TRF79X0_EN2_PIN, 0);
+// GPIOPinWrite(TRF79X0_EN2_BASE, TRF79X0_EN2_PIN,
+// TRF79X0_EN2_PIN);
+
+ //
+ // Delay 2ms before initializing the TRF79x0.
+ //
+ SysCtlDelay(g_ulDelayms * 2);
+
+ //
+ // Initialize the TRF7970 with a software initialization command, idle
+ // command, and set the modulator control register to
+ //
+ if(RF_DAUGHTER_TRF7970)
+ {
+ TRF79x0DirectCommand(TRF79X0_SOFT_INIT_CMD);
+ TRF79x0DirectCommand(TRF79X0_IDLE_CMD);
+ }
+
+ //
+ // Get RF Daughter Board ID TRF7960/TRF7970 ATB
+ //
+ TRF79x0ReadRegister(TRF79X0_MODULATOR_CONTROL_REG);
+
+ TRF79x0WriteRegister(TRF79X0_MODULATOR_CONTROL_REG, 0x01);
+
+ //
+ // Set up the interrupt handler and enable the RX timeout IRQ.
+ //
+ TRF79x0InterruptInit();
+ TRF79x0WriteRegister(TRF79X0_IRQ_MASK_REG,
+ TRF79x0ReadRegister(TRF79X0_IRQ_MASK_REG) | 1);
+
+ //
+ // Delay 4ms before leaving the initialization function.
+ //
+ SysCtlDelay(g_ulDelayms * 4);
+}
+
+//*****************************************************************************
+//
+// Set the Operating mode for the TRF79x0
+//
+// Set bits in ISO_CONTROL_REG based on mode given
+// Supported modes:
+// NFC_P2P_PASSIVE_TARGET_MODE
+// NFC_P2P_INITIATOR_MODE
+//
+// \return None.
+//
+//*****************************************************************************
+void
+TRF79x0SetMode(tTRF79x0TRFMode eMode, tTRF79x0Frequency eFrequency)
+{
+ g_selected_mode = eMode;
+ g_selected_frequency = eFrequency;
+
+ if(g_selected_mode == P2P_PASSIVE_TARGET_MODE)
+ {
+ //
+ // Register 01h. ISO Control Register
+ //
+ if (eFrequency == FREQ_106_KBPS) {
+ TRF79x0WriteRegister(TRF79X0_ISO_CONTROL_REG, 0x21);
+ } else if (eFrequency == FREQ_212_KBPS) {
+ TRF79x0WriteRegister(TRF79X0_ISO_CONTROL_REG, 0x22);
+ } else if (eFrequency == FREQ_424_KBPS) {
+ TRF79x0WriteRegister(TRF79X0_ISO_CONTROL_REG, 0x23);
+ }
+ }
+ else if(g_selected_mode == P2P_INITATIOR_MODE)
+ {
+ if (eFrequency == FREQ_106_KBPS) {
+ TRF79x0WriteRegister(TRF79X0_ISO_CONTROL_REG, 0x31);
+ } else if (eFrequency == FREQ_212_KBPS) {
+ TRF79x0WriteRegister(TRF79X0_ISO_CONTROL_REG, 0x32);
+ } else if (eFrequency == FREQ_424_KBPS) {
+ TRF79x0WriteRegister(TRF79X0_ISO_CONTROL_REG, 0x33);
+ }
+ }
+
+}
+
+//*****************************************************************************
+//
+// Prepare the TRF79x0 interrupt handler.
+//
+// Sets up the GPIO for a level triggered interrupt on the TRF79x0 IRQ line
+// and calls TRF79x0InterruptEnable(). Processor interrupts need to be
+// enabled (IntMasterEnable() from DriverLib) for the interrupt handler to
+// to be actually called.
+//
+// \return None.
+//
+//*****************************************************************************
+void
+TRF79x0InterruptInit(void)
+{
+ //
+ // Set GPIO Interrupt to level triggered active high.
+ //
+ GPIOIntTypeSet(TRF79X0_IRQ_BASE, TRF79X0_IRQ_PIN, GPIO_RISING_EDGE);
+
+ //
+ // Clear out any pending interrupt.
+ //
+ GPIOIntClear(TRF79X0_IRQ_BASE, TRF79X0_IRQ_PIN);
+
+ //
+ // Set GPIO Interrupt Enable.
+ //
+ TRF79x0InterruptEnable();
+
+ //
+ // Enable the GPIO interrupt.
+ //
+ IntEnable(TRF79X0_IRQ_INT);
+}
+
+//*****************************************************************************
+//
+// IRQ pin Interrupt Handler. This function is triggered by the IRQ pin going
+// high. The g_irq_flag flag is set as a result.
+//
+//*****************************************************************************
+void TRF79x0IRQPinInterruptHandler(void)
+{
+ uint32_t ui32IRQGPIOBankIntStatus;
+
+ //
+ // Get the masked interrupt status.
+ //
+ ui32IRQGPIOBankIntStatus=GPIOIntStatus(TRF79X0_IRQ_BASE,true);
+
+
+ //
+ // check if IRQ pin is high
+ //
+ if(ui32IRQGPIOBankIntStatus & TRF79X0_IRQ_PIN)
+ {
+ //
+ // Clear the asserted interrupts.
+ //
+ GPIOIntClear(TRF79X0_IRQ_BASE, TRF79X0_IRQ_PIN);
+
+ //
+ // Set flag appropriately.
+ //
+ g_irq_flag = 0x01;
+ }
+
+}
+
+//*****************************************************************************
+//
+// Internal helper function to transmit up to uiMaxLength bytes from g_sTXState
+// to the FIFO.
+//
+//*****************************************************************************
+static void
+FIFOTransmitSomeBytes(unsigned int uiMaxLength)
+{
+ unsigned int uiLength;
+
+ if(g_sTXState.uiBytesRemaining > 0)
+ {
+ //
+ // There are some bytes in g_sTXState that still need to
+ // be sent.
+ //
+ uiLength = g_sTXState.uiBytesRemaining;
+
+ if(uiLength > uiMaxLength)
+ {
+ //
+ // Clamp number of bytes to be sent to parameter uiMaxLength,
+ // which is 12 for the initial call with an empty FIFO and
+ // 9 for subsequent calls from the IRQ.
+ //
+ uiLength = uiMaxLength;
+ }
+
+ //
+ // Send the data in a continuous write to the FIFO "register".
+ //
+ if(RF_DAUGHTER_TRF7960)
+ {
+ SSITRF79x0WriteContinuousStart(TRF79X0_FIFO_REG);
+ SSITRF79x0WriteContinuousData(g_sTXState.pucBuffer, uiLength);
+ SSITRF79x0WriteContinuousStop();
+ }
+
+ if(RF_DAUGHTER_TRF7970)
+ {
+ SSITRF79x0WriteContinuousData(g_sTXState.pucBuffer, uiLength);
+ SSITRF79x0WriteContinuousStop();
+ }
+
+ //
+ // Update g_sTXState to reflect what we just sent.
+ //
+ g_sTXState.pucBuffer += uiLength;
+ g_sTXState.uiBytesRemaining -= uiLength;
+ }
+}
+
+
+
+
+//*****************************************************************************
+//
+// Clears all IRQ causes from g_sIRQState.
+//
+// You will need to call either this function or TRF79x0IRQClearCauses()
+// before a call to TRF79x0IRQWait() or TRF79x0IRQWaitTimeout() in order to
+// clear sticky causes from the interrupt state. If a cause has been indicated
+// before and is not cleared from the state then the wait functions will
+// return immediately.
+//
+// \return None.
+//
+//*****************************************************************************
+void
+TRF79x0IRQClearAll(void)
+{
+ //
+ // Clear the interrupt causes flags.
+ //
+ g_sIRQState.uiIrqCauses = 0;
+}
+
+//*****************************************************************************
+//
+// Clears all given IRQ causes from g_sIRQState.
+//
+// \param causes is a bitfield of clauses to clear. This is a logical or of
+// one or more terms of the form <tt>(1<<<i>x</i>)</tt> where <i>x</i>
+// is a value from enumeration TRF79x0WaitCondition.
+//
+// You will need to call either this function or TRF79x0IRQClearAll()
+// before a call to TRF79x0IRQWait() or TRF79x0IRQWaitTimeout().
+//
+// \return None.
+//
+//*****************************************************************************
+void
+TRF79x0IRQClearCauses(unsigned int uiCauses)
+{
+ //
+ // Clear the requested interrupt causes.
+ //
+ g_sIRQState.uiIrqCauses &= ~uiCauses;
+}
+
+//*****************************************************************************
+//
+// Returns the last indicated collision position and clears the collision
+// position indicator.
+//
+// \return This function returns the collision position as returned by the
+// TRF79x0 in registers 0xd and 0xe, or -1 if no collision was indicated since
+// the last call to this function.
+//
+//*****************************************************************************
+int
+TRF79x0GetCollisionPosition(void)
+{
+ //
+ // If there were no collisions detected then just return.
+ //
+ if(!g_sIRQState.ucCollisionDetected)
+ {
+ return(-1);
+ }
+
+ //
+ // Clear the collisions detected flag and return the number of collisions
+ // detected.
+ //
+ g_sIRQState.ucCollisionDetected = 0;
+
+ return(g_sIRQState.uiCollisionPosition);
+}
+
+//*****************************************************************************
+//
+// Enables the TRF79x0 IRQ handler.
+//
+// The interrupt handler needs and the processor interrupt to be enabled
+// (IntMasterEnable() from DriverLib) in order for transmission and
+// reception to work.
+//
+// \return None.
+//
+//*****************************************************************************
+void
+TRF79x0InterruptEnable(void)
+{
+ //
+ // Enable interrupts on the pin assigned to the IRQ signal.
+ //
+ GPIOIntEnable(TRF79X0_IRQ_BASE, TRF79X0_IRQ_PIN);
+}
+
+//*****************************************************************************
+//
+// Disables the TRF79x0 IRQ handler.
+//
+// \return None.
+//
+//*****************************************************************************
+void
+TRF79x0InterruptDisable(void)
+{
+ //
+ // Disable interrupts on the pin assigned to the IRQ signal.
+ //
+ GPIOIntDisable(TRF79X0_IRQ_BASE, TRF79X0_IRQ_PIN);
+}
+
+//*****************************************************************************
+//
+// TRF79x0DisableTransmitter - Disable the TRF79x0 Transmitter and Reset Fifo
+//
+//*****************************************************************************
+void TRF79x0DisableTransmitter(void)
+{
+ //
+ // Register 00h. Chip Status Control
+ //
+ TRF79x0WriteRegister(TRF79X0_CHIP_STATUS_CTRL_REG,0x00 | TRF7970A_5V_OPERATION);
+
+ //
+ // Reset FIFO CMD + Dummy byte
+ //
+ TRF79x0ResetFifoCommand();
+}
+
+//*****************************************************************************
+//
+// stop, then start the decoders
+//
+//*****************************************************************************
+void TRF797x0ResetDecoders(void)
+{
+ TRF79x0DirectCommand(TRF79X0_STOP_DECODERS_CMD);
+ TRF79x0DirectCommand(TRF79X0_RUN_DECODERS_CMD);
+
+}
+
+//*****************************************************************************
+//
+//
+//
+//*****************************************************************************
+uint8_t* TRF79x0GetNFCBuffer(void)
+{
+ return g_fifo_buffer;
+}
+
+//*****************************************************************************
+//
+// Waits for an abstract IRQ cause.
+//
+// \param eCondition is the IRQ cause to wait for.
+//
+// Waits until the IRQ handler indicates that the given abstract IRQ cause
+// has been met.
+//
+// \return Returns 1.
+//
+//*****************************************************************************
+int
+TRF79x0IRQWait(unsigned long ulCondition)
+{
+ //
+ // Wait with no timeout.
+ //
+ return(TRF79x0IRQWaitTimeout(ulCondition, 0));
+}
+
+//*****************************************************************************
+//
+// Waits for an abstract IRQ cause or timeout.
+//
+// \param ulCondition is the IRQ cause to wait for.
+// \param ulTimeout is the number of milliseconds to wait before a timeout
+// occurs.
+//
+// Waits until the IRQ handler indicates that the given abstract IRQ cause
+// has been met or the timeout occurs. If ulTimeout is 0 then this function
+// will wait forever.
+//
+// \return This function returns 1 if the condition was reached or 0 if the
+// function aborted due to the timeout being met.
+//
+//*****************************************************************************
+int
+TRF79x0IRQWaitTimeout(unsigned long ulCondition, unsigned long ulTimeout)
+{
+ unsigned long ulTime;
+
+ //
+ // If timeout was not set or not reached, return true.
+ //
+ if(ulTimeout == 0)
+ {
+ return(1);
+ }
+
+ ulTime = 0;
+
+ while((g_sIRQState.uiIrqCauses & ulCondition) == 0)
+ {
+ if(ulTimeout == ulTime)
+ {
+ //
+ // Abort if timeout is set and reached.
+ //
+ break;
+ }
+
+ //
+ // Delay 1ms and check again.
+ //
+ SysCtlDelay(g_ulDelayms);
+
+ //
+ // Increment the loop count.
+ //
+ ulTime++;
+ }
+
+ //
+ // If timeout was set and reached: return false.
+ //
+ if(ulTimeout == ulTime)
+ {
+ return 1;
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+//*****************************************************************************
+//
+// Issues a direct command on the TRF79x0.
+//
+// \param ucCommand is the command to be executed. Must be a valid command
+// code between 0 and 0x1f. Definitions for command codes are given in
+// trf79x0.h.
+//
+// \return None.
+//
+//*****************************************************************************
+void
+TRF79x0DirectCommand(unsigned char ucCommand)
+{
+ SSITRF79x0WriteDirectCommand(ucCommand);
+}
+
+//*****************************************************************************
+//
+// Issues a direct Reset FIFO command on the TRF79x0.
+//
+// \param ucCommand is the command to be executed. Must be a valid command
+// code between 0 and 0x1f. Definitions for command codes are given in
+// trf79x0.h.
+//
+// \return None.
+//
+//*****************************************************************************
+void
+TRF79x0ResetFifoCommand(void)
+{
+ SSITRF79x0WriteResetFifoDirectCommand(TRF79X0_RESET_FIFO_CMD);
+}
+
+//*****************************************************************************
+//
+//! Writes a single value to the TRF79x0 for address provided.
+//!
+//! \param ucAddress is the register address to write to. Must be between 0
+//! and 0x1f, inclusive.
+//! \param ucData is the data byte to be written.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+TRF79x0WriteRegister(unsigned char ucAddress, unsigned char ucData)
+{
+ SSITRF79x0WriteRegister(ucAddress, ucData);
+}
+
+
+//*****************************************************************************
+//
+// Initialize the mode and frequecy for the TRF79x0.
+// Useful for hot switching modes
+//
+// \param eMode is the mode the TRF79x0 is operating in.
+// Implemented: Future Implementation:
+// BOARD_INIT P2P_ACTIVE_TARGET_MODE
+// P2P_INITATIOR_MODE CARD_EMULATION_TYPE_A
+// P2P_PASSIVE_TARGET_MODE CARD_EMULATION_TYPE_B
+//
+// \param eFrequency is the frequency to set the board to.
+// Valid values are:
+// FREQ_STAND_BY
+// FREQ_106_KBPS
+// FREQ_212_KBPS
+// FREQ_424_KBPS
+//
+//*****************************************************************************
+tStatus TRF79x0Init2(tTRF79x0TRFMode eMode, tTRF79x0Frequency eFrequency)
+{
+ uint8_t ui8RxVal;
+ uint8_t ui8RxValCont[2];
+
+ g_selected_mode = eMode;
+ g_selected_frequency = eFrequency;
+
+ if (eMode == BOARD_INIT) {
+
+ do {
+ //
+ // Soft Init Command
+ //
+ TRF79x0DirectCommand(TRF79X0_SOFT_INIT_CMD);
+
+ //
+ // Idle Command
+ //
+ TRF79x0DirectCommand(TRF79X0_IDLE_CMD);
+
+ //
+ // Delay 1ms
+ // NOTE: Sysctl delay takes 3 clock ticks to complete,
+ // thus 1ms = (clock/1000)/3 or clock/3000
+ //
+ SysCtlDelay(g_ulDelayms * 1 );
+
+ //
+ // Register 09h. Modulator Control
+ //
+ ui8RxVal=TRF79x0ReadRegister(TRF79X0_MODULATOR_CONTROL_REG);
+
+ } while (ui8RxVal != 0x91);
+
+ //
+ // Register 09h. Modulator Control
+ //
+ // SYS_CLK (in this case 13.56 MHz) out optional, based on system req.
+ TRF79x0WriteRegister(TRF79X0_MODULATOR_CONTROL_REG, 0x00);
+
+ //
+ // Register 0Bh. Regulator Control
+ //
+ TRF79x0WriteRegister(TRF79X0_REGULATOR_CONTROL_REG, 0x87);
+
+ //
+ // Reset FIFO CMD + Dummy byte
+ //
+ TRF79x0ResetFifoCommand();
+
+ //
+ // Register 00h. Chip Status Control
+ //
+ // +5 V operation
+ TRF79x0WriteRegister(TRF79X0_CHIP_STATUS_CTRL_REG, 0x00 | TRF7970A_5V_OPERATION);
+
+ //
+ // Register 0Dh. Interrupt Mask Register
+ //
+// TRF79x0WriteRegister(TRF79X0_IRQ_MASK_REG, 0x3F);//NO Response IRQEnable
+ TRF79x0WriteRegister(TRF79X0_IRQ_MASK_REG, 0x3E);
+
+ //
+ // Register 14h. FIFO IRQ Level
+ //
+ // RX High = 96 bytes , TX Low = 32 bytes
+ TRF79x0WriteRegister(TRF79X0_FIFO_IRQ_LEVEL_REG, 0x0F);
+ } else if (eMode == P2P_INITATIOR_MODE) {
+ // TODO - Understand why the SOFT Init at start up, does
+ // not allow to send packets to reader
+ //
+ // Soft Init Command
+ //
+ TRF79x0DirectCommand(TRF79X0_SOFT_INIT_CMD);
+
+ //
+ // Idle Command
+ //
+ TRF79x0DirectCommand(TRF79X0_IDLE_CMD);
+
+ // Register 00h. Chip Status Control
+ // RF output active, +5 V operation
+ TRF79x0WriteRegister(TRF79X0_CHIP_STATUS_CTRL_REG, 0x02 | TRF7970A_5V_OPERATION);
+
+ // Check if there an external RF Field
+ TRF79x0DirectCommand(TRF79X0_TEST_EXTERNAL_RF_CMD);
+
+ //
+ // Delay 50uS
+ //
+ SysCtlDelay((g_ulDelayms/1000) * 50);
+
+ ui8RxVal=TRF79x0ReadRegister(TRF79X0_RSSI_LEVEL_REG);
+
+ // If the External RF Field is 0x00, we continue else we return fail
+ if ((ui8RxVal & 0x3F) != 0x00) {
+ //UARTprintf("Initiator Mode field disabled. RSSI: 0x%x \n",
+ //ui8RxVal);
+
+ // Register 00h. Chip Status Control
+ // RF output de-activated, +5 V operation
+ TRF79x0WriteRegister(TRF79X0_CHIP_STATUS_CTRL_REG, 0x00 | TRF7970A_5V_OPERATION);
+ return STATUS_FAIL;
+ }
+
+ //
+ // Register 09h. Modulator Control
+ //
+ // SYS_CLK (in this case 13.56 MHz) out optional, based on system req.
+ TRF79x0WriteRegister(TRF79X0_MODULATOR_CONTROL_REG, 0x00);
+
+ //
+ // Register 0Bh. Regulator Control
+ //
+ TRF79x0WriteRegister(TRF79X0_REGULATOR_CONTROL_REG, 0x01);
+
+ //
+ // Register 14h. FIFO IRQ Level
+ //
+ // RX High = 96 bytes , TX Low = 32 bytes
+ TRF79x0WriteRegister(TRF79X0_FIFO_IRQ_LEVEL_REG, 0x0F);
+
+ //
+ // Register 01h. Chip Status Control
+ //
+ if (eFrequency == FREQ_106_KBPS) {
+ TRF79x0WriteRegister(TRF79X0_ISO_CONTROL_REG, 0x31);
+ } else if (eFrequency == FREQ_212_KBPS) {
+ TRF79x0WriteRegister(TRF79X0_ISO_CONTROL_REG, 0x1A);
+ } else if (eFrequency == FREQ_424_KBPS) {
+ TRF79x0WriteRegister(TRF79X0_ISO_CONTROL_REG, 0x1B);
+ }
+
+ //
+ // Register 0Ah. RX Special Settings
+ //
+ // Turn off transmitter, +5 V operation
+ TRF79x0WriteRegister(TRF79X0_RX_SPECIAL_SETTINGS_REG, 0x2F);
+
+ //
+ // Register 16h. NFC Low Detection Level
+ //
+ TRF79x0WriteRegister(TRF79X0_NFC_LO_FIELD_LEVEL_REG, 0x83);
+
+ //
+ // Register 18h. NFC Target level
+ //
+// TRF79x0WriteRegister(TRF79X0_NFC_TARGET_LEVEL_REG, 0x07);
+
+ //
+ // Register 00h. Chip Status Control
+ //
+ // Turn off transmitter, +5 V operation
+ TRF79x0WriteRegister(TRF79X0_CHIP_STATUS_CTRL_REG, 0x20 |TRF7970A_5V_OPERATION);
+
+ //
+ // Guard Time Delay (GT_F) - 20 mS - Incremented to 30 mS due to the GS3.
+ //
+ SysCtlDelay(g_ulDelayms * 30);
+
+ } else if (eMode == P2P_PASSIVE_TARGET_MODE || eMode == P2P_ACTIVE_TARGET_MODE) {
+ //
+ // Soft Init Command
+ //
+ TRF79x0DirectCommand(TRF79X0_SOFT_INIT_CMD);
+
+ //
+ // Idle Command
+ //
+ TRF79x0DirectCommand(TRF79X0_IDLE_CMD);
+
+ //
+ // Disable Decoder Command
+ //
+ TRF79x0DirectCommand(TRF79X0_STOP_DECODERS_CMD);
+
+ //
+ // Register 01h. ISO Control Register
+ //
+ if (eFrequency == FREQ_106_KBPS) {
+ TRF79x0WriteRegister(TRF79X0_ISO_CONTROL_REG, 0x21);
+ } else if (eFrequency == FREQ_212_KBPS) {
+ TRF79x0WriteRegister(TRF79X0_ISO_CONTROL_REG, 0x22);
+ } else if (eFrequency == FREQ_424_KBPS) {
+ TRF79x0WriteRegister(TRF79X0_ISO_CONTROL_REG, 0x23);
+ }
+
+ //
+ // Register 09h. Modulator Control
+ //
+ // SYS_CLK Disabled, based on system req.
+ TRF79x0WriteRegister(TRF79X0_MODULATOR_CONTROL_REG, 0x00);
+
+ //
+ // Register 0Ah. RX Special Settings
+ //
+// TRF79x0WriteRegister(TRF79X0_RX_SPECIAL_SETTINGS_REG, 0x30);
+
+ //
+ // Register 0Bh. Regulator Control
+ //
+ TRF79x0WriteRegister(TRF79X0_REGULATOR_CONTROL_REG, 0x01);
+
+ //
+ // Register 14h. FIFO IRQ Level
+ //
+ // RX High = 96 bytes , TX Low = 32 bytes
+ TRF79x0WriteRegister(TRF79X0_FIFO_IRQ_LEVEL_REG, 0x0F);
+
+ //
+ // Register 16h. NFC Low Detection Level
+ //
+ TRF79x0WriteRegister(TRF79X0_NFC_LO_FIELD_LEVEL_REG, 0x83);
+
+ //
+ // Register 18h. NFC Target level
+ //
+ TRF79x0WriteRegister(TRF79X0_NFC_TARGET_LEVEL_REG, 0x07);
+
+ //
+ // Register 00h. Chip Status Control
+ //
+ // RF output active, +5 V operation
+ TRF79x0WriteRegister(TRF79X0_CHIP_STATUS_CTRL_REG, 0x20 | TRF7970A_5V_OPERATION);
+
+ //
+ // Read IRQ Register & Collision Register to clear data.
+ //
+ TRF79x0ReadRegisterContinuous(TRF79X0_IRQ_STATUS_REG, ui8RxValCont, 2);
+
+ //
+ // Enable Decoder Command
+ //
+ TRF79x0DirectCommand(TRF79X0_RUN_DECODERS_CMD);
+ }
+
+ return STATUS_SUCCESS;
+}
+
+//*****************************************************************************
+//
+// Write Fifo - used for NFC
+//
+//*****************************************************************************
+tStatus TRF79x0WriteFIFO(uint8_t *pui8Buffer, tTRF79x0CRC eCRCBit,
+ uint8_t ui8Length)
+{
+ tStatus eStatus;
+ tTRF79x0IRQFlag irq_flag = IRQ_STATUS_IDLE;
+ uint8_t remaining_bytes = 0;
+ uint8_t ui8FifoStatusLength = 0;
+ uint8_t ui8PayloadLength = 0;
+ uint8_t pui8IRQBuffer[2];
+
+ if (ui8Length > 127) {
+ ui8PayloadLength = 127;
+ } else {
+ ui8PayloadLength = ui8Length;
+ }
+
+ remaining_bytes = ui8Length - ui8PayloadLength;
+
+ if(g_selected_mode == P2P_ACTIVE_TARGET_MODE)
+ {
+ //
+ // Register 01h. ISO Control Register
+ //
+ if (g_selected_frequency == FREQ_106_KBPS) {
+ TRF79x0WriteRegister(TRF79X0_ISO_CONTROL_REG, 0x31);
+ } else if (g_selected_frequency == FREQ_212_KBPS) {
+ TRF79x0WriteRegister(TRF79X0_ISO_CONTROL_REG, 0x32);
+ } else if (g_selected_frequency == FREQ_424_KBPS) {
+ TRF79x0WriteRegister(TRF79X0_ISO_CONTROL_REG, 0x33);
+ }
+ }
+
+ if (IRQ_IS_SET())
+ {
+ //
+ // Read IRQ Register
+ //
+ TRF79x0ReadRegisterContinuous(TRF79X0_IRQ_STATUS_REG, pui8IRQBuffer, 2);
+ }
+
+ SSITRF79x0WritePacket(pui8Buffer, eCRCBit, ui8Length, ui8PayloadLength, \
+ true);
+
+ while (irq_flag != IRQ_STATUS_TX_COMPLETE) {
+ // Workaround for Type A commands - check the IRQ within 10 mS to
+ // refill FIFO
+ if(g_selected_mode == CARD_EMULATION_TYPE_A)
+ irq_flag = TRF79x0IRQHandler(10);
+ else
+ {
+ // No workaround needed, implement a longer timeout, allowing for
+ // FIFO IRQ to handle the FIFO levels
+ irq_flag = TRF79x0IRQHandler(100);
+ }
+
+ if (irq_flag == IRQ_STATUS_PROTOCOL_ERROR) {
+ eStatus = STATUS_FAIL;
+ break;
+ } else if (irq_flag == IRQ_STATUS_TX_COMPLETE) {
+ if(g_selected_mode == P2P_ACTIVE_TARGET_MODE)
+ {
+ //
+ // Delay 1uS
+ //
+ SysCtlDelay((g_ulDelayms/1000) * 1);
+
+ //
+ // Register 01h. ISO Control Register
+ //
+ if(g_selected_frequency == FREQ_106_KBPS)
+ TRF79x0WriteRegister(TRF79X0_ISO_CONTROL_REG, 0x21);
+ else if(g_selected_frequency == FREQ_212_KBPS)
+ TRF79x0WriteRegister(TRF79X0_ISO_CONTROL_REG, 0x22);
+ else if(g_selected_frequency == FREQ_424_KBPS)
+ TRF79x0WriteRegister(TRF79X0_ISO_CONTROL_REG, 0x23);
+ }
+ eStatus = STATUS_SUCCESS;
+ } else if ((irq_flag == IRQ_STATUS_FIFO_HIGH_OR_LOW
+ || irq_flag == IRQ_STATUS_TIME_OUT) && remaining_bytes > 0) {
+ // Modify the pointer to point to the next address of data for
+ // payload larger than 127 bytes
+ pui8Buffer = pui8Buffer + ui8PayloadLength;
+
+ ui8FifoStatusLength=TRF79x0ReadRegister(TRF79X0_FIFO_STATUS_REG);
+
+ // Check if there are more remaining bytes than available spots on
+ // the TRF7970
+ if (remaining_bytes > (127 - ui8FifoStatusLength)) {
+ // If there are more bytes than available then payload length
+ //is the (127 - ui8FifoStatusLength)
+ ui8PayloadLength = (127 - ui8FifoStatusLength);
+ } else {
+ ui8PayloadLength = remaining_bytes;
+ }
+
+ remaining_bytes = remaining_bytes - ui8PayloadLength;
+
+ SSITRF79x0WritePacket(pui8Buffer, eCRCBit, ui8Length, \
+ ui8PayloadLength, false);
+ }
+ }
+
+ return eStatus;
+}
+
+//*****************************************************************************
+//
+// IRQ Handler
+//
+// NOTE: currently TimerSet, TimerDisable, and TimerInteruptHandler must be
+// implemented by the user.
+//
+//*****************************************************************************
+extern void TimerSet(uint16_t timeout_ms, uint8_t * timeout_flag);
+
+tTRF79x0IRQFlag
+TRF79x0IRQHandler(uint16_t ui16TimeOut)
+{
+ tTRF79x0IRQFlag eIRQStatus = IRQ_STATUS_IDLE;
+ uint8_t pui8IRQBuffer[2];
+ uint8_t pui8TargetProtocol[2];
+ uint8_t ui8FifoStatusLength;
+ uint8_t ui8FifoIndex = 0;
+ uint8_t ui8PacketLength = 0;
+
+ //volatile uint8_t x;
+
+ if (IRQ_IS_SET())
+ {
+ g_irq_flag = 0x01;
+ }
+ else
+ {
+ g_irq_flag = 0x00;
+ //
+ // Initialize a ui16TimeOut timeout
+ //
+ TimerSet(ui16TimeOut, (uint8_t*) &g_time_out_flag);
+
+ }
+
+ //
+ // Check if the IRQ flag has been set
+ //
+ while (g_irq_flag == 0x00 && g_time_out_flag == 0x00) {
+ ;
+ //
+ // Enable Low Power Mode 0
+ //
+ //__bis_SR_register(LPM0_bits);
+ }
+
+ //
+ // Disable Timer
+ //
+ TimerDisable(TIMER0_BASE, TIMER_A);
+
+ if (g_time_out_flag == 0x01) {
+ //MCU_rssiDisplay(0);
+ eIRQStatus = IRQ_STATUS_TIME_OUT;
+ } else {
+
+ TRF79x0ReadRegisterContinuous(TRF79X0_NFC_TARGET_PROTOCOL_REG, \
+ pui8TargetProtocol, 2);
+
+ //
+ // Read IRQ Register
+ //
+ TRF79x0ReadRegisterContinuous(TRF79X0_IRQ_STATUS_REG, pui8IRQBuffer, 2);
+
+ if (pui8IRQBuffer[0] & IRQ_STATUS_FIFO_HIGH_OR_LOW) {
+ if (pui8IRQBuffer[0] & IRQ_STATUS_RX_COMPLETE) {
+ g_fifo_bytes_received = 0;
+ //
+ // Read the FIFO status and FIFO into g_nfc_buffer
+ //
+ ui8FifoStatusLength=TRF79x0ReadRegister(TRF79X0_FIFO_STATUS_REG);
+
+ ui8FifoIndex = 0;
+
+ while ((ui8FifoStatusLength > 0) &&
+ (g_fifo_bytes_received < NFC_FIFO_SIZE))
+ {
+
+ //
+ // Update the received bytes
+ //
+ g_fifo_bytes_received += ui8FifoStatusLength;
+ #ifdef DEBUG
+ //DebugPrintf("%d\n",g_fifo_bytes_received);
+ #endif
+
+ //
+ // Read the FIFO Data
+ //
+ TRF79x0ReadRegisterContinuous(TRF79X0_FIFO_REG,
+ &g_fifo_buffer[ui8FifoIndex], ui8FifoStatusLength);
+
+ ui8PacketLength = g_fifo_buffer[0];
+
+ //
+ // Update ui8FifoIndex
+ //
+ ui8FifoIndex = ui8FifoIndex + ui8FifoStatusLength;
+
+ if (!IRQ_IS_SET())
+ {
+ g_irq_flag = 0;
+ }
+
+ //
+ // Type F - P2P Workaround
+ //
+ if((g_selected_mode == P2P_PASSIVE_TARGET_MODE) ||
+ (g_selected_mode == P2P_INITATIOR_MODE))
+ {
+ //
+ // Check if we have received all the bytes defined in
+ // the first packet.
+ //
+ if(g_fifo_buffer[0] == g_fifo_bytes_received)
+ {
+ eIRQStatus = IRQ_STATUS_RX_COMPLETE;
+ break;
+ }
+ //
+ // If we have not read all the bytes, then every 1 mS
+ // go read out the FIFO status register to ensure we do
+ // not get an overflow flag.
+ //
+ else
+ {
+ //
+ // Initialize a 1 mS timeout
+ //
+ ui16TimeOut = 0x01;
+ TimerSet(ui16TimeOut, (uint8_t*) &g_time_out_flag);
+
+ while(g_irq_flag == 0x00 && g_time_out_flag == 0x00)
+ {
+ //
+ // Enable Low Power Mode 0
+ //
+ // __bis_SR_register(LPM0_bits);
+ }
+
+ //
+ // Disable Timer
+ //
+ TimerDisable(TIMER0_BASE, TIMER_A);
+ }
+
+ }
+ else
+ {
+ while ((g_irq_flag == 0) && (
+ (uint8_t) g_fifo_bytes_received !=
+ ui8PacketLength))
+ {
+ //
+ // Enable Low Power Mode 0
+ //
+ //__bis_SR_register(LPM0_bits);
+ }
+ }
+
+ TRF79x0ReadRegisterContinuous(TRF79X0_IRQ_STATUS_REG,
+ pui8IRQBuffer, 2);
+
+ //
+ // Read the FIFO status and FIFO into g_nfc_buffer
+ //
+ ui8FifoStatusLength =
+ TRF79x0ReadRegister(TRF79X0_FIFO_STATUS_REG);
+ //
+ // Mask off the lower 7 bits.
+ //
+ ui8FifoStatusLength &= 0x7F;
+ }
+
+ //TRF79x0ResetFifoCommand();
+
+ eIRQStatus = IRQ_STATUS_RX_COMPLETE;
+ }
+ else if (pui8IRQBuffer[0] & IRQ_STATUS_TX_COMPLETE)
+ {
+ eIRQStatus = IRQ_STATUS_FIFO_HIGH_OR_LOW;
+ }
+ }
+ else if (pui8IRQBuffer[0] == IRQ_STATUS_RX_COMPLETE)
+ {
+
+ //
+ // Read the FIFO status and FIFO into g_nfc_buffer
+ //
+ ui8FifoStatusLength=TRF79x0ReadRegister(TRF79X0_FIFO_STATUS_REG);
+
+ if (ui8FifoStatusLength != 0) {
+ //
+ // Read the FIFO Data
+ //
+ TRF79x0ReadRegisterContinuous(TRF79X0_FIFO_REG, g_fifo_buffer,
+ ui8FifoStatusLength);
+
+ g_fifo_bytes_received = ui8FifoStatusLength;
+ } else {
+ TRF79x0Init2(g_selected_mode, g_selected_frequency);
+ return IRQ_STATUS_IDLE;
+ }
+
+ // Check if the selected_mode corresponds to the command read in
+ // the command
+ if ((pui8TargetProtocol[0] == 0xC9
+ && g_selected_mode == CARD_EMULATION_TYPE_A)
+ || (pui8TargetProtocol[0] == 0xC5
+ && g_selected_mode == CARD_EMULATION_TYPE_B)
+ || (pui8TargetProtocol[0] == 0xD2
+ && g_selected_mode == P2P_PASSIVE_TARGET_MODE
+ && g_selected_frequency == FREQ_212_KBPS)
+ || (pui8TargetProtocol[0] == 0xD3
+ && g_selected_mode == P2P_PASSIVE_TARGET_MODE
+ && g_selected_frequency == FREQ_424_KBPS)
+ || (pui8TargetProtocol[0] == 0xD2
+ && g_selected_mode == P2P_ACTIVE_TARGET_MODE
+ && g_selected_frequency == FREQ_212_KBPS)
+ || (pui8TargetProtocol[0] == 0xD3
+ && g_selected_mode == P2P_ACTIVE_TARGET_MODE
+ && g_selected_frequency == FREQ_424_KBPS)
+ || (g_selected_mode == P2P_INITATIOR_MODE))
+ {
+ eIRQStatus = IRQ_STATUS_RX_COMPLETE;
+ if(g_selected_mode == P2P_INITATIOR_MODE ||
+ g_selected_mode == P2P_PASSIVE_TARGET_MODE)
+ //
+ // 500 microsecond // TR0
+ //
+ SysCtlDelay(g_ulDelayms / 2);
+ }
+ else
+ TRF79x0Init2(g_selected_mode, g_selected_frequency);
+
+ } else if (pui8IRQBuffer[0] & IRQ_STATUS_COLLISION_AVOID_FINISHED) {
+ eIRQStatus = IRQ_STATUS_COLLISION_AVOID_FINISHED;
+ } else if (pui8IRQBuffer[0] & IRQ_STATUS_RX_COMPLETE) {
+ // Handle the case for P2P Initiator Mode where IRQ is triggered
+ // with value 0xC0 - TODO
+ if(pui8IRQBuffer[0] & IRQ_STATUS_TX_COMPLETE)
+ {
+
+ }
+ else if(pui8IRQBuffer[0] & IRQ_STATUS_PROTOCOL_ERROR)
+ {
+ TRF79x0Init2(g_selected_mode, g_selected_frequency);
+ }
+ else
+ {
+ //
+ // Read the FIFO status and FIFO into g_nfc_buffer
+ //
+ ui8FifoStatusLength =
+ TRF79x0ReadRegister(TRF79X0_FIFO_STATUS_REG);
+
+ TRF79x0ResetFifoCommand();
+ }
+ }
+ else if (pui8IRQBuffer[0] & IRQ_STATUS_PROTOCOL_ERROR
+ || pui8IRQBuffer[0] & IRQ_STATUS_COLLISION_ERROR)
+ {
+ eIRQStatus = IRQ_STATUS_PROTOCOL_ERROR;
+ TRF79x0Init2(g_selected_mode, g_selected_frequency);
+ }
+ else if (pui8IRQBuffer[0] & IRQ_STATUS_TX_COMPLETE)
+ {
+
+ // Reset FIFO CMD + Dummy byte
+ TRF79x0ResetFifoCommand();
+
+ eIRQStatus = IRQ_STATUS_TX_COMPLETE;
+ }
+ else if (pui8IRQBuffer[0] & IRQ_STATUS_RF_FIELD_CHANGE)
+ {
+
+ eIRQStatus = IRQ_STATUS_RF_FIELD_CHANGE;
+ }
+
+ }
+
+ //
+ // Reset Global Flags
+ //
+ g_irq_flag = 0x00;
+ g_time_out_flag = 0x00;
+
+ return eIRQStatus;
+}
+
+//*****************************************************************************
+//
+// Writes a sequence of values to the TRF79x0 starting at the address
+// provided.
+//
+// \param ucAddress is the register address to start the write at. Must be
+// between 0 and 0x1f, inclusive.
+// \param pucData is a pointer to the data buffer to be written.
+// \param uiLength is the length of the buffer and number of bytes to write.
+//
+// \return None.
+//
+//*****************************************************************************
+void
+TRF79x0WriteRegisterContinuous(unsigned char ucAddress, unsigned char *pucData,
+ unsigned int uiLength)
+{
+ SSITRF79x0WriteContinuousStart(ucAddress);
+ SSITRF79x0WriteContinuousData(pucData, uiLength);
+ SSITRF79x0WriteContinuousStop();
+}
+
+//*****************************************************************************
+//
+// Reads IRQ status value from TRF79x0.
+//
+// This function reads the TRF79x0 IRQ status register 0x0c and returns its
+// contents. This will make the TRF79x0 release its interrupt request.
+//
+// \return Returns the IRQ status
+//
+//*****************************************************************************
+unsigned char
+TRF79x0ReadIRQStatus(void)
+{
+ return(SSITRF79x0ReadIRQStatus());
+}
+
+//*****************************************************************************
+//
+// Reads a single value from TRF79x0 at the address provided.
+//
+// \param ucAddress is the register address to read from. Must be between 0
+// and 0x1f, inclusive.
+//
+// \return Returns the value that was stored in the given register.
+//
+//*****************************************************************************
+unsigned char
+TRF79x0ReadRegister(unsigned char ucAddress)
+{
+ return(SSITRF79x0ReadRegister(ucAddress));
+}
+
+//*****************************************************************************
+//
+// Reads a sequence of values from the TRF79x0 starting at the address
+// provided.
+//
+// \param ucAddress is the register address to start the read at. Must be
+// between 0 and 0x1f, inclusive.
+// \param pucData is a pointer to the data buffer to store the read bytes into.
+// \param uiLength is the length of the buffer and number of bytes to read.
+//
+// \return None.
+//
+//*****************************************************************************
+void
+TRF79x0ReadRegisterContinuous(unsigned char ucAddress, unsigned char *pucData,
+ unsigned int uiLength)
+{
+ SSITRF79x0ReadContinuousStart(ucAddress);
+ SSITRF79x0ReadContinuousData(pucData, uiLength);
+ SSITRF79x0ReadContinuousStop();
+}
+
+//*****************************************************************************
+//
+// Writes a sequence of values to the FIFO of the TRF79x0.
+//
+// \param pucData is a pointer to the data buffer to be written.
+// \param length is the length of the buffer and number of bytes to write.
+//
+// This function sets up g_sTXState for the write operation to the FIFO and
+// sends the first chunk of up to 12 bytes. If more bytes need to be written
+// this will be handled by the IRQ handler, which therefore must be enabled.
+//
+// \return None.
+//
+//*****************************************************************************
+void
+TRF79x0FIFOWrite(unsigned char const *pucData, unsigned int uiLength)
+{
+ //
+ // Set up TX state to send the buffer.
+ //
+ g_sTXState.pucBuffer = pucData;
+ g_sTXState.uiBytesRemaining = uiLength;
+
+ //
+ // This will start transmission and write the first couple byte (12 at
+ // most) to the FIFO. If more bytes are to be written then the IRQ handler
+ // will pick up and send the remainder.
+ //
+ FIFOTransmitSomeBytes(12);
+ return;
+}
+
+//*****************************************************************************
+//
+// Writes to the FIFO, starting a transmission by the RF front end.
+//
+// \param pucData is a pointer to the data buffer to be written.
+// \param uiLength is the number of bytes to send.
+// \param uiBits is the additional number of bits to send.
+//
+// This function sets up the TX length byte registers 0x1D and 0x1E with
+// the given bytes and bits and then calls TRF79x0FIFOWrite() to initiate the
+// write to the FIFO.
+// If the RF front end has been enabled for transmission with
+// TRF79x0DirectCommand() with parameter \b TRF79X0_TRANSMIT_NO_CRC_CMD or
+// \b TRF79X0_TRANSMIT_CRC_CMD this function call will start the radio
+// transmission.
+//
+// \return None.
+//
+//*****************************************************************************
+void
+TRF79x0Transmit(unsigned char const *pucData, unsigned int uiLength,
+ unsigned int uiBits)
+{
+ unsigned char pucLengthRegs[2];
+
+ //
+ // Prepare the length to be written into the FIFO for registers 0x1D and
+ // 0x1E.
+ //
+ pucLengthRegs[0] = (uiLength >> 4) & 0xff;
+ pucLengthRegs[1] = (uiLength & 0xf) << 4;
+
+ if(uiBits > 0)
+ {
+ //
+ // Last byte is incomplete.
+ //
+ pucLengthRegs[1] |= ((uiBits & 0x7) << 1) | 1;
+
+ //
+ // This is an additional byte, so increase the number of bytes for the
+ // purpose of SPI transmission below by 1.
+ //
+ uiLength++;
+ }
+
+ //
+ // The data from pucLengthRegs is written to registers 0x1D and 0x1E
+ // in continuous mode. In principle the continuous mode could simply
+ // be kept active in order to write to the FIFO (starts at 0x1F). However
+ // there is a necessary workaround when only one byte needs to be
+ // transmitted (see SLOA140). Also stopping the continuous write here and
+ // separately enabling it in TRF79x0WriteFIFO makes for more logical
+ // function separation.
+ //
+ if(RF_DAUGHTER_TRF7960)
+ {
+ SSITRF79x0WriteContinuousStart(TRF79X0_TX_LENGTH_BYTE1_REG);
+ SSITRF79x0WriteContinuousData(pucLengthRegs, sizeof(pucLengthRegs));
+ SSITRF79x0WriteContinuousStop();
+ }
+
+ if(RF_DAUGHTER_TRF7970)
+ {
+ SSITRF79x0WriteContinuousData(pucLengthRegs, sizeof(pucLengthRegs));
+ }
+
+ TRF79x0FIFOWrite(pucData, uiLength);
+}
+
+//*****************************************************************************
+//
+// Sets up reception from the FIFO
+//
+// \param pucData is a pointer to the data buffer to receive the data.
+// \param puiLength is a pointer to the length of the \e pucData buffer in
+// bytes.
+//
+// This function sets up g_sRXState for the read operation from the FIFO. The
+// actual reading will be handled by the IRQ handler, which therefore must
+// be enabled. When the function returns the \e puiLength parameter will
+// contain the number of bytes that were actually received. These values are
+// updated asynchronously by the IRQ handler.
+//
+// \return None.
+//
+//*****************************************************************************
+void
+TRF79x0Receive(unsigned char *pucData, unsigned int *puiLength)
+{
+ unsigned int uiMaxLength;
+
+ uiMaxLength = *puiLength;
+
+ //
+ // Already received: 0 bytes.
+ //
+ *puiLength = 0;
+
+ //
+ // The uiMaxLength member is the ultimate deciding factor on whether the
+ // IRQ receiver is enabled. So set it to 0 first and only set it to its
+ // final value when the other members are set.
+ //
+ g_sRXState.uiMaxLength = 0;
+
+ g_sRXState.pucBuffer = pucData;
+ g_sRXState.puiLength = puiLength;
+ g_sRXState.uiMaxLength = uiMaxLength;
+}
+
+//*****************************************************************************
+//
+// Sets up reception from the FIFO with wait time out feature
+//
+// \param pucData is a pointer to the data buffer to receive the data.
+// \param puiLength is a pointer to the length of the \e pucData buffer in
+// bytes.
+//
+// This function sets up g_sRXState for the read operation from the FIFO. The
+// actual reading will be handled by the IRQ handler, which therefore must
+// be enabled. When the function returns the \e puiLength parameter will
+// contain the number of bytes that were actually received. These values are
+// updated asynchronously by the IRQ handler.
+//
+// \return None.
+//
+//*****************************************************************************
+void
+TRF79x0ReceiveAgain(unsigned char *pucRXBuf, unsigned int *puiRXLen)
+{
+ if((pucRXBuf != 0) && (puiRXLen != 0) && (*puiRXLen > 0))
+ TRF79x0Receive(pucRXBuf, puiRXLen);
+
+ TRF79x0IRQWaitTimeout(TRF79X0_WAIT_RXEND, TRF79X0_RX_TIMEOUT);
+
+ //
+ // Abort receive job, e.g. if timeout reached.
+ //
+ g_sRXState.uiMaxLength = 0;
+}
+
+//*****************************************************************************
+//
+//
+//
+//*****************************************************************************
+void
+TRF79x0ReceiveEnd(void)
+{
+ TRF79x0IRQClearCauses(TRF79X0_WAIT_RXEND);
+
+ //
+ // Abort receive job, e.g. if timeout reached.
+ //
+ g_sRXState.uiMaxLength = 0;
+
+ TRF79x0ResetFifoCommand();
+}
+
+//*****************************************************************************
+//
+// Coordinated transmission and reception function.
+//
+// \param pucTXBuf is a pointer to the data buffer.
+// \param uiTXLen is the number of full bytes to send.
+// \param uiTXBits is the number of additional bits to send
+// \param pucRXBuf is a pointer to a data buffer to receive data. If this is
+// \b 0 then no reception will take place.
+// \param puiRXLen is pointer that inputs the length of \e pucRXBuf and outputs
+// the number of bytes that were actually received.
+// \param puiRXBits is unused.
+// \param uiFlags is a bitfield of uiFlags to modify the transceiver operation.
+// Should contain at least \b TRF79X0_TRANSCEIVE_NO_CRC,
+// \b TRF79X0_TRANSCEIVE_RX_CRC, \b TRF79X0_TRANSCEIVE_TX_CRC or
+// \b TRF79X0_TRANSCEIVE_CRC. These values indicate whether a CRC should be
+// added when transmitting (\b TRF79X0_TRANSCEIVE_TX_CRC or
+// \b TRF79X0_TRANSCEIVE_CRC) and whether it should be checked when receiving
+// (\b TRF79X0_TRANSCEIVE_RX_CRC or \b TRF79X0_TRANSCEIVE_CRC).
+//
+// This function calls, in order:
+//
+// - TRF79x0WriteRegister() to set up reception with/without CRC (in
+// register 0x1),
+// - TRF79x0DirectCommand() with \b TRF79X0_RESET_FIFO_CMD to clear the FIFO,
+// - TRF79x0DirectCommand() with \b TRF79X0_TRANSMIT_CRC_CMD or
+// \b TRF79X0_TRANSMIT_NO_CRC_CMD to prepare transmission with/without CRC,
+// - TRF79x0IRQClearAll() to clear the IRQ state,
+// - TRF79x0GetCollisionPosition() to clear the stored collision position,
+// - TRF79x0Receive() to set up reception (if enabled),
+// - TRF79x0Transmit() to set up transmission,
+// - TRF79x0IRQWaitTimeout() with \b TRF79X0_WAIT_TXEND to wait for the
+// end of transmission and
+// - TRF79x0IRQWaitTimeout() with \b TRF79X0_WAIT_RXEND to wait for the
+// end of reception (if enabled).
+//
+// The uiFlags and puiRXBits parameters offer for future, source-compatible
+// extensions such as integrated collision handling (which would result in
+// incomplete byte reception).
+//
+// \return None.
+//
+//*****************************************************************************
+void
+TRF79x0Transceive(unsigned char const *pucTXBuf, unsigned int uiTXLen,
+ unsigned int uiTXBits, unsigned char *pucRXBuf,
+ unsigned int *puiRXLen, unsigned int *puiRXBits,
+ unsigned int uiFlags)
+{
+ int iRXEnabled;
+ unsigned char ucISOState;
+ unsigned char ucBuf[30];
+
+ ucISOState = TRF79x0ReadRegister(TRF79X0_ISO_CONTROL_REG);
+
+ if(uiFlags & TRF79X0_TRANSCEIVE_RX_CRC)
+ {
+ //
+ // Receive with CRC.
+ //
+ TRF79x0WriteRegister(TRF79X0_ISO_CONTROL_REG,
+ ucISOState & ~TRF79X0_ISO_CONTROL_RX_CRC_N);
+ }
+ else
+ {
+ //
+ // Receive without CRC.
+ //
+ TRF79x0WriteRegister(TRF79X0_ISO_CONTROL_REG,
+ ucISOState | TRF79X0_ISO_CONTROL_RX_CRC_N);
+ }
+
+ if(RF_DAUGHTER_TRF7960)
+ {
+ TRF79x0DirectCommand(TRF79X0_RESET_FIFO_CMD);
+
+ if(uiFlags & TRF79X0_TRANSCEIVE_TX_CRC)
+ {
+ //
+ // Transmit with CRC.
+ //
+ TRF79x0DirectCommand(TRF79X0_TRANSMIT_CRC_CMD);
+ }
+ else
+ {
+ //
+ // Transmit without CRC.
+ //
+ TRF79x0DirectCommand(TRF79X0_TRANSMIT_NO_CRC_CMD);
+ }
+
+ //
+ // Disable any possible old receive job.
+ //
+ g_sRXState.uiMaxLength = 0;
+
+ //
+ // Clear all IRQ causes.
+ //
+ TRF79x0IRQClearAll();
+
+ //
+ // Clear stored collision position.
+ //
+ TRF79x0GetCollisionPosition();
+
+ //
+ // If receive is enabled, set up receive job.
+ //
+ iRXEnabled = 0;
+
+ if((pucRXBuf != 0) && (puiRXLen != 0) && (*puiRXLen > 0))
+ {
+ TRF79x0Receive(pucRXBuf, puiRXLen);
+ iRXEnabled = 1;
+ }
+
+ //
+ // Writing the FIFO starts the transmission. This function will return
+ // after writing up to 12 bytes with the remaining bytes to be written
+ // by the interrupt handler.
+ //
+ TRF79x0Transmit(pucTXBuf, uiTXLen, uiTXBits);
+
+ //
+ // Wait for the interrupt handler to signal the end of transmission
+ // with no further FIFO loading. This IRQ should always happen, so
+ // no timeout necessary. However, for robustness reasons: Use the RX
+ // timeout.
+ //
+ TRF79x0IRQWaitTimeout(TRF79X0_WAIT_TXEND, TRF79X0_RX_TIMEOUT);
+
+ //
+ // If receive is enabled, wait for receive end.
+ //
+ if(iRXEnabled)
+ {
+ TRF79x0IRQWaitTimeout(TRF79X0_WAIT_RXEND, TRF79X0_RX_TIMEOUT);
+
+ //
+ // Abort receive job, e.g. if timeout reached.
+ //
+ g_sRXState.uiMaxLength = 0;
+ }
+ }
+
+ if(RF_DAUGHTER_TRF7970)
+ {
+ //
+ // Prepare SELECT command
+ //
+ ucBuf[0] = TRF79X0_CONTROL_CMD | TRF79X0_RESET_FIFO_CMD;
+
+ if(uiFlags & TRF79X0_TRANSCEIVE_TX_CRC)
+ {
+ //
+ // Transmit with CRC.
+ //
+ ucBuf[1] = TRF79X0_CONTROL_CMD | TRF79X0_TRANSMIT_CRC_CMD;
+ }
+ else
+ {
+ //
+ // Transmit without CRC.
+ //
+ ucBuf[1] = TRF79X0_CONTROL_CMD | TRF79X0_TRANSMIT_NO_CRC_CMD;
+ }
+
+ //
+ // Disable any possible old receive job.
+ //
+ g_sRXState.uiMaxLength = 0;
+
+ //
+ // Clear all IRQ causes.
+ //
+ TRF79x0IRQClearAll();
+
+ //
+ // Clear stored collision position.
+ //
+ TRF79x0GetCollisionPosition();
+
+ //
+ // If receive is enabled, set up receive job.
+ //
+ iRXEnabled = 0;
+
+ if((pucRXBuf != 0) && (puiRXLen != 0) && (*puiRXLen > 0))
+ {
+ TRF79x0Receive(pucRXBuf, puiRXLen);
+ iRXEnabled = 1;
+ }
+
+ //
+ // Writing the FIFO starts the transmission. This function will return
+ // after writing up to 12 bytes with the remaining bytes to be written
+ // by the interrupt handler.
+ //
+
+ //
+ // Look into what is ucBuf being used for.
+ //
+ ucBuf[2] = 0x3D;
+
+ //
+ // Send the data in a continuous write to the FIFO "register".
+ //
+ SSITRF79x0WriteDirectContinuousStart();
+ SSITRF79x0WriteContinuousData(ucBuf, 3);
+ TRF79x0Transmit(pucTXBuf, uiTXLen, uiTXBits);
+
+ //
+ // Wait for the interrupt handler to signal the end of transmission
+ // with no further FIFO loading. This IRQ should always happen, so
+ // no timeout necessary. However, for robustness reasons: Use the RX
+ // timeout.
+ //
+ TRF79x0IRQWaitTimeout(TRF79X0_WAIT_TXEND, TRF79X0_RX_TIMEOUT);
+
+ //
+ // If receive is enabled, wait for receive end.
+ //
+ if(iRXEnabled)
+ {
+ TRF79x0IRQWaitTimeout(TRF79X0_WAIT_RXEND, TRF79X0_RX_TIMEOUT);
+
+ //
+ // Abort receive job, e.g. if timeout reached.
+ //
+ g_sRXState.uiMaxLength = 0;
+ }
+ }
+}
diff --git a/nfclib/trf79x0.h b/nfclib/trf79x0.h
new file mode 100644
index 0000000..159bec7
--- /dev/null
+++ b/nfclib/trf79x0.h
@@ -0,0 +1,400 @@
+//*****************************************************************************
+//
+// trf79x0.h - Header file for the TI TRF79X0 driver
+//
+// Copyright (c) 2010-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
+//
+//*****************************************************************************
+
+#ifndef __TRF79X0_H__
+#define __TRF79X0_H__
+
+#include "types.h"
+
+//*****************************************************************************
+//
+// Definitions for different interrupt status bits.
+//
+//*****************************************************************************
+#define TX_FIFO_ALMOST_EMPTY 0xA0
+#define TX_COMPLETE 0x80
+#define RX_FIFO_ALMOST_FULL 0x60
+#define RX_COMPLETE 0x40
+#define COLLISION_DETECTED 0x02
+
+//*****************************************************************************
+//
+// Timeout to apply while waiting for reception, this is expressed in
+// milliseconds.
+//
+// For a more accurate timeout indication you can program the no-response
+// timer in the TRF7960 and must enable the no-response interrupt.
+//
+//*****************************************************************************
+#define TRF7960_RX_TIMEOUT 10
+
+//*****************************************************************************
+//
+// An enum defining the various daughter boards that can be attached to the
+// development board.
+//
+//*****************************************************************************
+typedef enum
+{
+ RF_DAUGHTER_NONE = 0,
+ RF_DAUGHTER_TRF7960ATB = 1,
+ RF_DAUGHTER_TRF7970ATB = 2,
+ RF_DAUGHTER_TRF7970ABP = 3,
+ RF_DAUGHTER_UNKNOWN = 0xFFFF
+}
+tRFDaughterBoard;
+
+extern tRFDaughterBoard g_eRFDaughterType;
+#define NFC_NONE 0
+#define NFC_CARD_EMU_TAG4A 1
+#define NFC_CARD_EMU_TAG4B 2
+
+extern unsigned char g_ucNfcWorkMode;
+
+//*****************************************************************************
+//
+// IRQ Status Register (0x0C) for NFC and Card Emulation Operation
+//
+//*****************************************************************************
+#define RF_FIELD_CHANGE 0x04
+#define SDD_COMPLETED 0x08
+
+//*****************************************************************************
+//
+// TRF79X0 Register Definitions.
+//
+//*****************************************************************************
+#define TRF79X0_CHIP_STATUS_CTRL_REG 0x00
+#define TRF79X0_ISO_CONTROL_REG 0x01
+#define TRF79X0_ISO14443B_OPTIONS_REG 0x02
+#define TRF79X0_ISO14443A_OPTIONS_REG 0x03
+#define TRF79X0_TX_TIMER_EPC_HIGH 0x04
+#define TRF79X0_TX_TIMER_EPC_LOW 0x05
+#define TRF79X0_TX_PULSE_LENGTH_CTRL_REG 0x06
+#define TRF79X0_RX_NO_RESPONSE_WAIT_REG 0x07
+#define TRF79X0_RX_WAIT_TIME_REG 0x08
+#define TRF79X0_MODULATOR_CONTROL_REG 0x09
+#define TRF79X0_RX_SPECIAL_SETTINGS_REG 0x0A
+#define TRF79X0_REGULATOR_CONTROL_REG 0x0B
+#define TRF79X0_IRQ_STATUS_REG 0x0C
+#define TRF79X0_IRQ_MASK_REG 0x0D
+#define TRF79X0_COLLISION_POSITION_REG 0x0E
+#define TRF79X0_RSSI_LEVEL_REG 0x0F
+#define TRF79X0_RAM_START_ADDRESS_REG 0x10
+#define TRF797X0_SPECIAL_FUNC_1_REG 0x10
+#define TRF797X0_SPECIAL_FUNC_2_REG 0x11
+#define TRF79X0_FIFO_IRQ_LEVEL_REG 0x14
+#define TRF79X0_NFC_LO_FIELD_LEVEL_REG 0x16
+#define TRF79X0_NFC_ID_REG 0x17
+#define TRF79X0_NFC_TARGET_LEVEL_REG 0x18
+#define TRF79X0_NFC_TARGET_PROTOCOL_REG 0x19
+#define TRF79X0_TEST_SETTING1_REG 0x1A
+#define TRF79X0_TEST_SETTING2_REG 0x1B
+#define TRF79X0_FIFO_STATUS_REG 0x1C
+#define TRF79X0_TX_LENGTH_BYTE1_REG 0x1D
+#define TRF79X0_TX_LENGTH_BYTE2_REG 0x1E
+#define TRF79X0_FIFO_REG 0x1F
+
+//*****************************************************************************
+//
+// TRF79X0 TRF79X0_CHIP_STATUS_CTRL_REG Register Definitions.
+//
+//*****************************************************************************
+#define TRF79X0_STATUS_CTRL_DIRECT 0x40
+#define TRF79X0_STATUS_CTRL_RF_ON 0x20
+#define TRF79X0_STATUS_CTRL_RF_PWR_HALF 0x10
+#define TRF79X0_STATUS_CTRL_RF_PWR_FULL 0x00
+#define TRF79X0_STATUS_CTRL_5V_OPERATION 0x01
+
+//*****************************************************************************
+//
+// TRF79X0 TRF79X0_ISO_CONTROL Register Definitions.
+//
+//*****************************************************************************
+#define TRF79X0_ISO_CONTROL_RX_CRC_N 0x80
+#define TRF79X0_ISO_CONTROL_DIR_MODE 0x40
+#define TRF79X0_ISO_NFC_TARGET 0x00
+#define TRF79X0_ISO_NFC_INITIATOR 0x10
+#define TRF79X0_NFC_PASSIVE_MODE 0x00
+#define TRF79X0_NFC_ACTIVE_MODE 0x08
+#define TRF79X0_NFC_NORMAL_MODE 0x00
+#define TRF79X0_NFC_CARD_EMULATION_MODE 0x40
+#define TRF79X0_ISO_CONTROL_14443A_106K 0x08
+#define TRF79X0_ISO_CONTROL_14443A_106K 0x08
+#define TRF79X0_ISO_CONTROL_14443B_106K 0x0C
+#define TRF79X0_ISO_CONTROL_15693_LOW_1SUB_1OUT4 0x00
+#define TRF79X0_ISO_CONTROL_15693_HIGH_1SUB_1OUT4 0x02
+#define TRF79X0_ISO_CONTROL_15693_HIGH_1SUB_1OUT256 0x03
+
+//*****************************************************************************
+//
+// TRF79X0 TRF79X0_MODULATOR_CONTROL_REG Register Definitions.
+//
+//*****************************************************************************
+#define TRF79X0_MOD_CTRL_SYS_CLK_13_56MHZ 0x30
+#define TRF79X0_MOD_CTRL_SYS_CLK_6_78MHZ 0x20
+#define TRF79X0_MOD_CTRL_SYS_CLK_3_3MHZ 0x10
+#define TRF79X0_MOD_CTRL_SYS_CLK_DISABLE 0x00
+#define TRF79X0_MOD_CTRL_MOD_ASK_30 0x07
+#define TRF79X0_MOD_CTRL_MOD_ASK_22 0x06
+#define TRF79X0_MOD_CTRL_MOD_ASK_16 0x05
+#define TRF79X0_MOD_CTRL_MOD_ASK_13 0x04
+#define TRF79X0_MOD_CTRL_MOD_ASK_8_5 0x03
+#define TRF79X0_MOD_CTRL_MOD_ASK_7 0x02
+#define TRF79X0_MOD_CTRL_MOD_OOK_100 0x01
+#define TRF79X0_MOD_CTRL_MOD_ASK_10 0x00
+
+//*****************************************************************************
+//
+// TRF79X0 TRF79X0_RX_SPECIAL_SETTINGS_REG Register Definitions.
+//
+//*****************************************************************************
+#define TRF79X0_RX_SP_SET_M848 0x20
+#define TRF79X0_RX_SP_SET_C424 0x40
+
+//*****************************************************************************
+//
+// TRF79X0 TRF79X0_REGULATOR_CONTROL_REG Register Definitions.
+//
+//*****************************************************************************
+#define TRF79X0_REGULATOR_CTRL_AUTO_REG 0x80
+#define TRF79X0_REGULATOR_CTRL_VRS_2_7V 0x00
+#define TRF79X0_REGULATOR_CTRL_VRS_2_8V 0x01
+#define TRF79X0_REGULATOR_CTRL_VRS_2_9V 0x02
+#define TRF79X0_REGULATOR_CTRL_VRS_3_0V 0x03
+#define TRF79X0_REGULATOR_CTRL_VRS_3_1V 0x04
+#define TRF79X0_REGULATOR_CTRL_VRS_3_2V 0x05
+#define TRF79X0_REGULATOR_CTRL_VRS_3_3V 0x06
+#define TRF79X0_REGULATOR_CTRL_VRS_3_4V 0x07
+
+//*****************************************************************************
+//
+// TRF79x0 Command Definitions.
+//
+//*****************************************************************************
+#define TRF79X0_IDLE_CMD 0x00
+#define TRF79X0_SOFT_INIT_CMD 0x03
+#define TRF79X0_INITIAL_RF_COLLISION_AVOID_CMD 0x04
+#define TRF79X0_PERFORM_RES_RF_COLLISION_AVOID_CMD 0x05
+#define TRF79X0_PERFORM_RES_RF_COLLISION_AVOID_N0_CMD 0x06
+#define TRF79X0_RESET_FIFO_CMD 0x0F
+#define TRF79X0_TRANSMIT_NO_CRC_CMD 0x10
+#define TRF79X0_TRANSMIT_CRC_CMD 0x11
+#define TRF79X0_DELAY_TRANSMIT_NO_CRC_CMD 0x12
+#define TRF79X0_DELAY_TRANSMIT_CRC_CMD 0x13
+#define TRF79X0_TRANSMIT_NEXT_SLOT_CMD 0x14
+#define TRF79X0_CLOSE_SLOT_SEQUENCE_CMD 0x15
+#define TRF79X0_STOP_DECODERS_CMD 0x16
+#define TRF79X0_RUN_DECODERS_CMD 0x17
+#define TRF79X0_TEST_INTERNAL_RF_CMD 0x18
+#define TRF79X0_TEST_EXTERNAL_RF_CMD 0x19
+#define TRF79X0_RX_ADJUST_GAIN_CMD 0x1A
+
+//*****************************************************************************
+//
+// TRF79x0 Command/Address mode definitions.
+//
+//*****************************************************************************
+#define TRF79X0_ADDRESS_MASK 0x1F
+#define TRF79X0_CONTROL_CMD 0x80
+#define TRF79X0_CONTROL_REG_READ 0x40
+#define TRF79X0_CONTROL_REG_WRITE 0x00
+#define TRF79X0_REG_MODE_SINGLE 0x00
+#define TRF79X0_REG_MODE_CONTINUOUS 0x20
+
+//*****************************************************************************
+//
+// TRF7960/7970 Modulator control register mode default values to
+// determine RF Daughter Board.
+//
+//*****************************************************************************
+#define TRF7960_DEFAULT_ID 0x11
+#define TRF7970_DEFAULT_ID 0x91
+
+//*****************************************************************************
+//
+// The following defines are used with the TRF79x0Transceive() function with
+// the uiFlags parameter.
+//
+//*****************************************************************************
+
+//
+// Transmit without CRC, receive without CRC check.
+//
+#define TRF79X0_TRANSCEIVE_NO_CRC 0
+//
+// Transmit without CRC, receive with CRC check.
+//
+#define TRF79X0_TRANSCEIVE_RX_CRC 1
+//
+// Transmit with CRC, receive without CRC check.
+//
+#define TRF79X0_TRANSCEIVE_TX_CRC 2
+//
+// Transmit with CRC, receive with CRC check.
+//
+#define TRF79X0_TRANSCEIVE_CRC (TRF79X0_TRANSCEIVE_TX_CRC | \
+ TRF79X0_TRANSCEIVE_RX_CRC)
+
+//*****************************************************************************
+//
+// These defines specify abstract IRQ causes to wait for. Since the IRQ
+// state register does not lend itself to easy cumulative storage (for
+// example just because bit 0x80 was set at least once does not mean that the
+// transmission is complete) these are defined to have an abstract way to
+// express certain conditions that one would want to wait for.
+//
+//*****************************************************************************
+
+//
+// Wait for any IRQ to occur.
+//
+#define TRF79X0_WAIT_ANY 0x00000001
+
+//
+// Wait for an IRQ that signifies the end of transmission to occur.
+//
+#define TRF79X0_WAIT_TXEND 0x00000002
+
+//
+// Wait for an IRQ that signifies the end of reception to occur, this
+// will either be 0x40 with no other flags set, or 0x01 for RX timeout.
+//
+#define TRF79X0_WAIT_RXEND 0x00000004
+
+//*****************************************************************************
+//
+// These enumerations are used as part of the state machine layout for NFC P2P
+//
+//*****************************************************************************
+
+//
+// States for the TRF79x0 State Machine
+//
+typedef enum
+{
+ BOARD_INIT = 0,
+ P2P_INITATIOR_MODE,
+ P2P_PASSIVE_TARGET_MODE,
+ P2P_ACTIVE_TARGET_MODE,
+ CARD_EMULATION_TYPE_A,
+ CARD_EMULATION_TYPE_B
+} tTRF79x0TRFMode;
+
+//
+// Frequency Settings for TRF79x0
+//
+typedef enum
+{
+ FREQ_STAND_BY= 0, // Used for Board Initialization
+ FREQ_106_KBPS,
+ FREQ_212_KBPS,
+ FREQ_424_KBPS
+} tTRF79x0Frequency;
+
+//
+// CRC Settings for TRF79x0
+//
+typedef enum
+{
+ CRC_BIT_DISABLE = 0,
+ CRC_BIT_ENABLE
+} tTRF79x0CRC;
+
+//
+// IRQ Flag deffinitions. Defined in datasheet, provided for ease of use
+//
+typedef enum
+{
+ IRQ_STATUS_IDLE = 0x00,
+ IRQ_STATUS_COLLISION_ERROR = 0x01,
+ IRQ_STATUS_COLLISION_AVOID_FINISHED = 0x02,
+ IRQ_STATUS_RF_FIELD_CHANGE = 0x04,
+ IRQ_STATUS_SDD_COMPLETE = 0x08,
+ IRQ_STATUS_PROTOCOL_ERROR = 0x10,
+ IRQ_STATUS_FIFO_HIGH_OR_LOW = 0x20,
+ IRQ_STATUS_RX_COMPLETE = 0x40,
+ IRQ_STATUS_TX_COMPLETE = 0x80,
+ IRQ_STATUS_TIME_OUT = 0xFF
+} tTRF79x0IRQFlag;
+
+//*****************************************************************************
+//
+// Exported function prototypes.
+//
+//*****************************************************************************
+extern void TRF79x0Init(void);
+extern void TRF79x0SetMode(tTRF79x0TRFMode eMode, tTRF79x0Frequency eFrequency);
+extern void TRF79x0Interrupt(void);
+extern void TRF79x0InterruptInit(void);
+extern void TRF79x0InterruptEnable(void);
+extern void TRF79x0InterruptDisable(void);
+extern void TRF79x0DisableTransmitter(void);
+extern void TRF797x0ResetDecoders(void);
+extern uint8_t* TRF79x0GetNFCBuffer(void);
+extern void TRF79x0DirectCommand(uint8_t ucCommand);
+extern void TRF79x0ResetFifoCommand(void);
+extern tStatus TRF79x0Init2(tTRF79x0TRFMode eMode,
+ tTRF79x0Frequency eFrequency);
+tStatus TRF79x0WriteFIFO(uint8_t *pui8Buffer, tTRF79x0CRC eCRCBit,
+ uint8_t ui8Length);
+tTRF79x0IRQFlag TRF79x0IRQHandler(uint16_t ui16TimeOut);
+extern void TRF79x0WriteRegister(unsigned char ucAddress,
+ unsigned char ucData);
+extern void TRF79x0WriteRegisterContinuous(unsigned char ucAddress,
+ unsigned char *pucData,
+ unsigned int uiLength);
+extern unsigned char TRF79x0ReadIRQStatus(void);
+extern unsigned char TRF79x0ReadRegister(unsigned char ucAddress);
+extern void TRF79x0ReadRegisterContinuous(unsigned char ucAddress,
+ unsigned char *pucData,
+ unsigned int uiLength);
+extern void TRF79x0FIFOWrite(unsigned char const *pucData,
+ unsigned int uiLength);
+extern void TRF79x0Receive(unsigned char *pucData, unsigned int *puiLength);
+extern void TRF79x0Transmit(unsigned char const *pucData,
+ unsigned int uiLength, unsigned int uiBits);
+extern void TRF79x0Transceive(unsigned char const *pucTXBuf,
+ unsigned int uiTXLen, unsigned int uiTXBits,
+ unsigned char *pucRXBuf, unsigned int *puiRXLen,
+ unsigned int *puiRXBits, unsigned int uiFlags);
+extern void TRF79x0IRQClearAll(void);
+extern void TRF79x0IRQClearCauses(unsigned int uiCauses);
+extern int TRF79x0IRQWait(unsigned long ulCondition);
+extern int TRF79x0IRQWaitTimeout(unsigned long ulCondition,
+ unsigned long ulTimeout);
+extern int TRF79x0GetCollisionPosition(void);
+extern int TRF79x0IsCollision(void);
+extern void TRF79x0InitialSettings(void);
+extern void TRF79x0ReceiveAgain(unsigned char *pucRXBuf,
+ unsigned int *puiRXLen);
+extern void TRF79x0ReceiveEnd(void);
+extern void TRF79x0TransceiveISO15693(unsigned char const *pucTXBuf,
+ unsigned int uiTXLen,
+ unsigned int uiTXBits, unsigned char *pucRXBuf,
+ unsigned int *puiRXLen, unsigned int *puiRXBits,
+ unsigned int uiFlags);
+extern int SendResponse(int Something, int DataLength, char *DataPtr);
+extern int SendResponse_w_o_CRC(int Something, int DataLength, char *DataPtr);
+#endif
diff --git a/nfclib/trf79x0_hw_example.h b/nfclib/trf79x0_hw_example.h
new file mode 100644
index 0000000..c73e882
--- /dev/null
+++ b/nfclib/trf79x0_hw_example.h
@@ -0,0 +1,489 @@
+//*****************************************************************************
+//
+// trf79x0_hw_example.h - Hardware Pin configuration for TRF79x0 ATB on
+// Tiva C Series Snowflake Class silicon. Tailored for DK-tm4c129x, but will
+// work for any board with a Snowflake chip with RF Headers.
+//
+// Copyright (c) 2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
+//
+//*****************************************************************************
+
+#ifndef __TRF79X0_HW_H__
+#define __TRF79X0_HW_H__
+
+//*****************************************************************************
+//
+// Enable the TRF79x0 that will be used with the TM4C129X board
+// Enabled = 1, Disabled = 0
+//
+//*****************************************************************************
+#define RF_DAUGHTER_TRF7960 0
+#define RF_DAUGHTER_TRF7970 1
+
+//*****************************************************************************
+//
+// Check for correct definition of RF_DAUGTHER_TRF79X0
+//
+//*****************************************************************************
+#if (RF_DAUGHTER_TRF7960 && RF_DAUGHTER_TRF7970)
+#error "Only one TRF79X0 can be defined at the same time."
+#elif (!(RF_DAUGHTER_TRF7960 || RF_DAUGHTER_TRF7970))
+#error "Define the TRF79X0 to be used, none currently defined."
+#endif
+
+//*****************************************************************************
+//
+// Pin definitions for the DK-TM4C129X development board connections to the
+// BoosterPack board.
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+//! \addtogroup nfc_hw NFC Hardware Definitions
+//! @{
+//! This section covers the definitions that control which hardware is used to
+//! communicate with the TRF79x0 EM module. These defines configure which SSI
+//! peripheral is used as well as which pins are assigned to the other
+//! connections to the TRF79x0 EM module. The \b TRF79X0_SSI_* defines are
+//! used to specify the SSI peripheral that is used by the application. The
+//! remaining defines specify the pins used by the NFC APIs. The TRF79x0
+//! EM module requires the following signal connections: CLK, RX, TX, CS, ASKOK,
+//! EN, EN2, IRQ, MOD. To configure these signals, three defines must be set
+//! for each. For example, for the CS signal, the \ref TRF79X0_CS_BASE,
+//! \ref TRF79X0_CS_PERIPH and \ref TRF79X0_CS_PIN defines must be set.
+//!
+//! \b Example: CS pin is on GPIO port E pin 1.
+//! \verbatim
+//!
+//! #define TRF79X0_CS_BASE GPIO_PORTA_BASE
+//! #define TRF79X0_CS_PERIPH SYSCTL_PERIPH_GPIOA
+//! #define TRF79X0_CS_PIN GPIO_PIN_4
+//! \endverbatim
+//!
+//*****************************************************************************
+
+//*****************************************************************************
+//
+//! The clock rate of the SSI clock specified in Hz.
+//!
+//! \b Example: 2-MHz SSI data clock.
+//!
+//! <tt>\#define SSI_CLK_RATE 2000000</tt>
+//!
+//*****************************************************************************
+#define SSI_CLK_RATE 2000000
+#define SSI_CLKS_PER_MS (SSI_CLK_RATE / 1000)
+#define STATUS_READS_PER_MS (SSI_CLKS_PER_MS / 16)
+#define SSI_NO_DATA 0
+
+//*****************************************************************************
+//
+//! Specifies the SSI peripheral for the SSI port that is connected to the
+//! TRF79x0 EM board. The value should be set to SYSCTL_PERIPH_SSIn, where n is
+//! the number of the SSI port being used.
+//!
+//! \b Example: Uses SSI0 peripheral
+//!
+//! <tt>\#define TRF79X0_SSI_PERIPH SYSCTL_PERIPH_SSI0</tt>
+//!
+//*****************************************************************************
+#define TRF79X0_SSI_PERIPH SYSCTL_PERIPH_SSI0
+
+//*****************************************************************************
+//
+//! Specifies the SSI @a base address for the SSI port that is connected to the
+//! TRF79x0 EM board. The value should be set to SYSCTL_PERIPH_SSIn, where n is
+//! the number of the SSI port being used.
+//!
+//! \b Example: Uses SSI0 peripheral
+//!
+//! <tt>\#define TRF79X0_SSI_BASE SSI0_BASE</tt>
+//!
+//*****************************************************************************
+#define TRF79X0_SSI_BASE SSI0_BASE
+
+//*****************************************************************************
+//
+// GPIO pin deffinitions for TRF79x0 SSI signals
+//
+//*****************************************************************************
+
+//
+//! Specifies the @a base address of the GPIO port that is connected to the SSI
+//! Clock signal on the TRF79x0 EM board.
+//!
+//! \b Example: The SSI peripheral CLK signal is on GPIO port A.
+//!
+//! <tt>\#define TRF79X0_CLK_BASE GPIO_PORTA_BASE</tt>
+//
+#define TRF79X0_CLK_BASE GPIO_PORTA_BASE
+
+//
+//! Specifies the @a peripheral for the GPIO port that is connected to the SSI
+//! Clock signal on the TRF79x0 EM board.
+//!
+//! \b Example: The SSI peripheral CLK signal is on GPIO port A.
+//!
+//! <tt>\#define TRF79X0_CLK_PERIPH SYSCTL_PERIPH_GPIOA</tt>
+//
+#define TRF79X0_CLK_PERIPH SYSCTL_PERIPH_GPIOA
+
+//
+//! Specifies the GPIO pin that is connected to the SSI
+//! Clock signal on the TRF79x0 EM board.
+//!
+//! \b Example: The SSI peripheral CLK signal is on GPIO pin 2.
+//!
+//! <tt>\#define TRF79X0_CLK_PIN GPIO_PIN_2</tt>
+//
+#define TRF79X0_CLK_PIN GPIO_PIN_2
+
+//
+//! Specifies the GPIO pin that is connected to
+//! the SSI Clock signal on the TRF79x0 EM board.
+//!
+//! \b Example: The SSI Clock signal is on GPIO port A pin 2.
+//!
+//! <tt>\#define TRF79X0_CLK_CONFIG GPIO_PA2_SSI0CLK</tt>
+//
+#define TRF79X0_CLK_CONFIG GPIO_PA2_SSI0CLK
+
+//
+//! Specifies the @a base address of the GPIO port that is connected to the SSI
+//! TX signal on the TRF79x0 EM board.
+//!
+//! \b Example: The SSI peripheral TX signal is on GPIO port A.
+//!
+//! <tt>\#define TRF79X0_TX_BASE GPIO_PORTA_BASE</tt>
+//
+#define TRF79X0_TX_BASE GPIO_PORTA_BASE
+
+//
+//! Specifies the @a peripheral for the GPIO port that is connected to the SSI
+//! TX signal on the TRF79x0 EM board.
+//!
+//! \b Example: The SSI peripheral TX signal is on GPIO port A.
+//!
+//! <tt>\#define TRF79X0_TX_PERIPH SYSCTL_PERIPH_GPIOA</tt>
+//
+#define TRF79X0_TX_PERIPH SYSCTL_PERIPH_GPIOA
+
+//
+//! Specifies the GPIO pin that is connected to the SSI
+//! TX signal on the TRF79x0 EM board.
+//!
+//! \b Example: The SSI peripheral TX signal is on GPIO pin 4.
+//!
+//! <tt>\#define TRF79X0_TX_PIN GPIO_PIN_4</tt>
+//
+#define TRF79X0_TX_PIN GPIO_PIN_4
+
+//
+//! Specifies the GPIO pin that is connected to
+//! the SSITX (DAT0) signal on the TRF79x0 EM board.
+//!
+//! \b Example: The SSI 1 TX signal is on GPIO port A pin 4.
+//!
+//! <tt>\#define TRF79X0_TX_CONFIG GPIO_PA4_SSI0XDAT0</tt>
+//
+#define TRF79X0_TX_CONFIG GPIO_PA4_SSI0XDAT0
+
+//
+//! Specifies the @a base address of the GPIO port that is connected to the SSI
+//! RX signal on the TRF79x0 EM board.
+//!
+//! \b Example: The SSI peripheral RX signal is on GPIO port A.
+//!
+//! <tt>\#define TRF79X0_RX_BASE GPIO_PORTA_BASE</tt>
+//
+#define TRF79X0_RX_BASE GPIO_PORTA_BASE
+
+//
+//! Specifies the @a peripheral for the GPIO port that is connected to the SSI
+//! RX signal on the TRF79x0 EM board.
+//!
+//! \b Example: The SSI peripheral RX signal is on GPIO port A.
+//!
+//! <tt>\#define TRF79X0_RX_PERIPH SYSCTL_PERIPH_GPIOA</tt>
+//
+#define TRF79X0_RX_PERIPH SYSCTL_PERIPH_GPIOA
+
+//
+//! Specifies the GPIO pin that is connected to the SSI
+//! RX signal on the TRF79x0 EM board.
+//!
+//! \b Example: The SSI peripheral RX signal is on GPIO pin 5.
+//!
+//! <tt>\#define TRF79X0_RX_PIN GPIO_PIN_5</tt>
+//
+#define TRF79X0_RX_PIN GPIO_PIN_5
+
+//
+//! Specifies the GPIO pin that is connected to
+//! the SSIRX (DAT1) signal on the TRF79x0 EM board.
+//!
+//! \b Example: The SSI 1 RX signal is on GPIO port A pin 5.
+//!
+//! <tt>\#define TRF79X0_RX_CONFIG GPIO_PA5_SSI0XDAT1</tt>
+//
+#define TRF79X0_RX_CONFIG GPIO_PA5_SSI0XDAT1
+
+//*****************************************************************************
+//
+// Hardware connection definitions for the TRF79x0 board.
+//
+//*****************************************************************************
+
+//
+//! Specifies the @a base address of the GPIO port that is connected to the SSI
+//! CS signal on the TRF79x0 EM board.
+//!
+//! \b Example: The SSI CS signal is on GPIO port A.
+//!
+//! <tt>\#define TRF79X0_CS_BASE GPIO_PORTA_BASE</tt>
+//
+#define TRF79X0_CS_BASE GPIO_PORTA_BASE
+
+//
+//! Specifies the @a peripheral for the GPIO port that is connected to the SSI
+//! CS signal on the TRF79x0 EM board.
+//!
+//! \b Example: The SSI CS signal is on GPIO port A.
+//!
+//! <tt>\#define TRF79X0_CS_PERIPH SYSCTL_PERIPH_GPIOA</tt>
+//
+#define TRF79X0_CS_PERIPH SYSCTL_PERIPH_GPIOA
+
+//
+//! Specifies the GPIO pin that is connected to the SSI
+//! CS signal on the TRF79x0 EM board.
+//!
+//! \b Example: The SSI peripheral CS signal is on GPIO pin 4.
+//!
+//! <tt>\#define TRF79X0_CS_PIN GPIO_PIN_4</tt>
+//
+#define TRF79X0_CS_PIN GPIO_PIN_3
+
+//
+//! Specifies the @a base address of the GPIO port that is connected to the EN
+//! signal on the TRF79x0 EM board.
+//!
+//! \b Example: The EN signal is on GPIO port D.
+//!
+//! <tt>\#define TRF79X0_EN_BASE GPIO_PORTD_BASE</tt>
+//
+#define TRF79X0_EN_BASE GPIO_PORTD_BASE
+
+//
+//! Specifies the @a peripheral for the GPIO port that is connected to the EN
+//! signal on the TRF79x0 EM board.
+//!
+//! \b Example: The EN signal is on GPIO port D.
+//!
+//! <tt>\#define TRF79X0_EN_PERIPH SYSCTL_PERIPH_GPIOD</tt>
+//
+#define TRF79X0_EN_PERIPH SYSCTL_PERIPH_GPIOD
+
+//
+//! Specifies the GPIO pin that is connected to the EN pin on the
+//! TRF79x0 EM board.
+//!
+//! \b Example: The EN signal is on GPIO pin 2.
+//!
+//! <tt>\#define TRF79X0_EN_PIN GPIO_PIN_2</tt>
+//
+#define TRF79X0_EN_PIN GPIO_PIN_2
+
+//
+//! Specifies the @a base address of the GPIO port that is connected to the EN2
+//! signal on the TRF79x0 EM board.
+//!
+//! \b Example: The EN2 signal is on GPIO port D.
+//!
+//! <tt>\#define TRF79X0_EN2_BASE GPIO_PORTD_BASE</tt>
+//
+#define TRF79X0_EN2_BASE GPIO_PORTD_BASE
+
+//
+//! Specifies the @a peripheral for the GPIO port that is connected to the EN2
+//! signal on the TRF79x0 EM board.
+//!
+//! \b Example: The EN2 signal is on GPIO port D.
+//!
+//! <tt>\#define TRF79X0_EN2_PERIPH SYSCTL_PERIPH_GPIOD</tt>
+//
+#define TRF79X0_EN2_PERIPH SYSCTL_PERIPH_GPIOD
+
+//
+//! Specifies the GPIO pin that is connected to the EN2 signal on the
+//! TRF79x0 EM board.
+//!
+//! \b Example: The EN2 signal is on GPIO pin 3.
+//!
+//! <tt>\#define TRF79X0_EN2_PIN GPIO_PIN_3</tt>
+//
+#define TRF79X0_EN2_PIN GPIO_PIN_3
+
+//
+//! Specifies the @a base address of the GPIO port that is connected to the
+//! ASKOK signal on the TRF79x0 EM board.
+//!
+//! \b Example: The ASKOK signal is on GPIO port J.
+//!
+//! <tt>\#define TRF79X0_ASKOK_BASE GPIO_PORTJ_BASE</tt>
+//
+#define TRF79X0_ASKOK_BASE GPIO_PORTJ_BASE
+
+//
+//! Specifies the @a peripheral for the GPIO port that is connected to the ASKOK
+//! signal on the TRF79x0 EM board.
+//!
+//! \b Example: The ASKOK signal is on GPIO port J.
+//!
+//! <tt>\#define TRF79X0_ASKOK_PERIPH SYSCTL_PERIPH_GPIOJ</tt>
+//
+#define TRF79X0_ASKOK_PERIPH SYSCTL_PERIPH_GPIOJ
+
+//
+//! Specifies the GPIO pin that is connected to the ASKOK signal on
+//! the TRF79x0 EM board.
+//!
+//! \b Example: The ASKOK signal is on GPIO pin 5.
+//!
+//! <tt>\#define TRF79X0_ASKOK_PIN GPIO_PIN_5</tt>
+//
+#define TRF79X0_ASKOK_PIN GPIO_PIN_5
+
+//
+//! Specifies the @a base address of the GPIO port that is connected to the MOD
+//! signal on the TRF79x0 EM board.
+//!
+//! \b Example: The MOD signal is on GPIO port J.
+//!
+//! <tt>\#define TRF79X0_MOD_BASE GPIO_PORTJ_BASE</tt>
+//
+#define TRF79X0_MOD_BASE GPIO_PORTJ_BASE
+
+//
+//! Specifies the @a peripheral for the GPIO port that is connected to the MOD
+//! signal on the TRF79x0 EM board.
+//!
+//! \b Example: The MOD signal is on GPIO port J.
+//!
+//! <tt>\#define TRF79X0_MOD_PERIPH SYSCTL_PERIPH_GPIOJ</tt>
+//
+#define TRF79X0_MOD_PERIPH SYSCTL_PERIPH_GPIOJ
+
+//
+//! Specifies the GPIO pin that is connected to the MOD signal on the
+//! TRF79x0 EM board.
+//!
+//! \b Example: The MOD signal is on GPIO pin 4.
+//!
+//! <tt>\#define TRF79X0_MOD_PIN GPIO_PIN_4</tt>
+//
+#define TRF79X0_MOD_PIN GPIO_PIN_4
+
+//
+//! Specifies the @a base address of the GPIO port that is connected to the IRQ
+//! signal on the TRF79x0 EM board.
+//!
+//! \b Example: The IRQ signal is on GPIO port J.
+//!
+//! <tt>\#define TRF79X0_IRQ_BASE GPIO_PORTJ_BASE</tt>
+//
+#define TRF79X0_IRQ_BASE GPIO_PORTJ_BASE
+
+//
+//! Specifies the @a peripheral for the GPIO port that is connected to the IRQ
+//! signal on the TRF79x0 EM board.
+//!
+//! \b Example: The IRQ signal is on GPIO port J.
+//!
+//! <tt>\#define TRF79X0_IRQ_PERIPH SYSCTL_PERIPH_GPIOJ</tt>
+//
+#define TRF79X0_IRQ_PERIPH SYSCTL_PERIPH_GPIOJ
+
+//
+//! Specifies the GPIO pin that is connected to the IRQ signal on the
+//! TRF79x0 EM board.
+//!
+//! \b Example: The IRQ signal is on GPIO pin 1.
+//!
+//! <tt>\#define TRF79X0_IRQ_PIN GPIO_PIN_1</tt>
+//
+#define TRF79X0_IRQ_PIN GPIO_PIN_1
+
+//
+//! Specifies GPIO interrupt that is tied to the GPIO port that the IRQ signal
+//! is connected to TRF79x0 EM board.
+//!
+//! \b Example: SSI GPIO interrupt is on GPIO port C.
+//!
+//! <tt>\#define TRF79X0_IRQ_INT INT_GPIOC</tt>
+//
+#define TRF79X0_IRQ_INT INT_GPIOJ
+
+//
+// Uses Blue LED part of RGB tricolor LED (arbitrary color choice)
+//
+#define ENABLE_LED_PERIPHERAL SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOQ);
+#define SET_LED_DIRECTION GPIOPinTypeGPIOOutput(GPIO_PORTQ_BASE, GPIO_PIN_4 );
+#define TURN_ON_LED GPIOPinWrite(GPIO_PORTQ_BASE, GPIO_PIN_4, GPIO_PIN_4);
+#define TURN_OFF_LED GPIOPinWrite(GPIO_PORTQ_BASE, GPIO_PIN_4, 0);
+
+//*****************************************************************************
+//
+// Optional LED Defines, useful for boards that have tricolor LED's
+//
+//*****************************************************************************
+#define BOARD_HAS_TRICOLOR_LED 1
+
+#define ENABLE_LED_TRICOLOR_RED_PERIPH SysCtlPeripheralEnable(SYSCTL_PERIPH_GPION);
+#define SET_LED_TRICOLOR_RED_DIRECTION GPIOPinTypeGPIOOutput(GPIO_PORTN_BASE, GPIO_PIN_5 );
+#define TURN_ON_LED_TRICOLOR_RED GPIOPinWrite(GPIO_PORTN_BASE, GPIO_PIN_5, GPIO_PIN_5);
+#define TURN_OFF_LED_TRICOLOR_RED GPIOPinWrite(GPIO_PORTN_BASE, GPIO_PIN_5, 0);
+
+#define ENABLE_LED_TRICOLOR_BLUE_PERIPH SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOQ);
+#define SET_LED_TRICOLOR_BLUE_DIRECTION GPIOPinTypeGPIOOutput(GPIO_PORTQ_BASE, GPIO_PIN_4 );
+#define TURN_ON_LED_TRICOLOR_BLUE GPIOPinWrite(GPIO_PORTQ_BASE, GPIO_PIN_4, GPIO_PIN_4);
+#define TURN_OFF_LED_TRICOLOR_BLUE GPIOPinWrite(GPIO_PORTQ_BASE, GPIO_PIN_4, 0);
+
+#define ENABLE_LED_TRICOLOR_GREEN_PERIPH SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOQ);
+#define SET_LED_TRICOLOR_GREEN_DIRECTION GPIOPinTypeGPIOOutput(GPIO_PORTQ_BASE, GPIO_PIN_7 );
+#define TURN_ON_LED_TRICOLOR_GREEN GPIOPinWrite(GPIO_PORTQ_BASE, GPIO_PIN_7, GPIO_PIN_7);
+#define TURN_OFF_LED_TRICOLOR_GREEN GPIOPinWrite(GPIO_PORTQ_BASE, GPIO_PIN_7, 0);
+
+//*****************************************************************************
+//
+// Macro for IRQ signal from TRF79x0 -> Board
+// left in this format for cross platform compatibility.
+//
+//*****************************************************************************
+#define IRQ_IS_SET() GPIOPinRead(TRF79X0_IRQ_BASE, TRF79X0_IRQ_PIN)
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
+
+#endif // __TRF79X0_HW_H__
diff --git a/nfclib/types.h b/nfclib/types.h
new file mode 100644
index 0000000..b1a655a
--- /dev/null
+++ b/nfclib/types.h
@@ -0,0 +1,36 @@
+//*****************************************************************************
+// types.h - typedefs used for cross architecture code porting / ease of use.
+//
+// Copyright (c) 2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
+//
+//*****************************************************************************
+#ifndef _TYPES_H_
+#define _TYPES_H_
+
+//
+// Boolean Status type. Provided for Cross Compatibility with other chipsets.
+// Not necessary, but useful for porting code between architectures.
+//
+typedef enum
+{
+ STATUS_FAIL = 0,
+ STATUS_SUCCESS
+}tStatus;
+
+#endif //_TYPES_H_
diff --git a/sensorlib/Makefile b/sensorlib/Makefile
new file mode 100644
index 0000000..3b8f43c
--- /dev/null
+++ b/sensorlib/Makefile
@@ -0,0 +1,88 @@
+#******************************************************************************
+#
+# Makefile - Rules for building the sensor library.
+#
+# Copyright (c) 2012-2014 Texas Instruments Incorporated. All rights reserved.
+# Software License Agreement
+#
+# Texas Instruments (TI) is supplying this software for use solely and
+# exclusively on TI's microcontroller products. The software is owned by
+# TI and/or its suppliers, and is protected under applicable copyright
+# laws. You may not combine this software with "viral" open-source
+# software in order to form a larger program.
+#
+# THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+# NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+# NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+# CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+# DAMAGES, FOR ANY REASON WHATSOEVER.
+#
+# This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
+#
+#******************************************************************************
+
+#
+# The base directory for TivaWare.
+#
+ROOT=..
+
+#
+# Include the common make definitions.
+#
+include ${ROOT}/makedefs
+
+#
+# Where to find header files that do not live in the source directory.
+#
+IPATH=..
+
+#
+# The default rule, which causes the sensor library to be built.
+#
+all: ${COMPILER}
+all: ${COMPILER}/libsensor.a
+
+#
+# The rule to clean out all the build products.
+#
+clean:
+ @rm -rf ${COMPILER} ${wildcard *~}
+
+#
+# The rule to create the target directory.
+#
+${COMPILER}:
+ @mkdir -p ${COMPILER}
+
+#
+# Rules for building the sensor library.
+#
+${COMPILER}/libsensor.a: ${COMPILER}/ak8963.o
+${COMPILER}/libsensor.a: ${COMPILER}/ak8975.o
+${COMPILER}/libsensor.a: ${COMPILER}/bmp180.o
+${COMPILER}/libsensor.a: ${COMPILER}/bq27510g3.o
+${COMPILER}/libsensor.a: ${COMPILER}/cm3218.o
+${COMPILER}/libsensor.a: ${COMPILER}/comp_dcm.o
+${COMPILER}/libsensor.a: ${COMPILER}/i2cm_drv.o
+${COMPILER}/libsensor.a: ${COMPILER}/isl29023.o
+${COMPILER}/libsensor.a: ${COMPILER}/kxti9.o
+${COMPILER}/libsensor.a: ${COMPILER}/l3gd20h.o
+${COMPILER}/libsensor.a: ${COMPILER}/lsm303d.o
+${COMPILER}/libsensor.a: ${COMPILER}/lsm303dlhc_accel.o
+${COMPILER}/libsensor.a: ${COMPILER}/lsm303dlhc_mag.o
+${COMPILER}/libsensor.a: ${COMPILER}/magneto.o
+${COMPILER}/libsensor.a: ${COMPILER}/mpu6050.o
+${COMPILER}/libsensor.a: ${COMPILER}/mpu9150.o
+${COMPILER}/libsensor.a: ${COMPILER}/quaternion.o
+${COMPILER}/libsensor.a: ${COMPILER}/sht21.o
+${COMPILER}/libsensor.a: ${COMPILER}/tmp006.o
+${COMPILER}/libsensor.a: ${COMPILER}/tmp100.o
+${COMPILER}/libsensor.a: ${COMPILER}/vector.o
+
+#
+# Include the automatically generated dependency files.
+#
+ifneq (${MAKECMDGOALS},clean)
+-include ${wildcard ${COMPILER}/*.d} __dummy__
+endif
diff --git a/sensorlib/ak8963.c b/sensorlib/ak8963.c
new file mode 100644
index 0000000..5b605a6
--- /dev/null
+++ b/sensorlib/ak8963.c
@@ -0,0 +1,666 @@
+//*****************************************************************************
+//
+// ak8963.c - Driver for the AK8963 magnetometer.
+//
+// Copyright (c) 2013-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
+//
+//*****************************************************************************
+
+#include <stdint.h>
+#include "sensorlib/hw_ak8963.h"
+#include "sensorlib/i2cm_drv.h"
+#include "sensorlib/ak8963.h"
+
+//*****************************************************************************
+//
+//! \addtogroup ak8963_api
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// The states of the AK8963 state machine.
+//
+//*****************************************************************************
+#define AK8963_STATE_IDLE 0 // State machine is idle
+#define AK8963_STATE_READ 1 // Waiting for read
+#define AK8963_STATE_WRITE 2 // Waiting for write
+#define AK8963_STATE_RMW 3 // Waiting for read-modify-write
+
+//*****************************************************************************
+//
+// The factors used to convert the magnetometer readings from the AK8963 into
+// floating point values in tesla
+//
+//*****************************************************************************
+static const float g_fAK8963Factors[] =
+{
+ 0.0000006, // 14-bit = .6 uT/LSB
+ 0.00000015, // 16-bit = .15 uT/LSB
+};
+
+//*****************************************************************************
+//
+// The callback function that is called when I2C transations to/from the
+// AK8963 have completed.
+//
+//*****************************************************************************
+static void
+AK8963Callback(void *pvCallbackData, uint_fast8_t ui8Status)
+{
+ tAK8963 *psInst;
+
+ //
+ // Convert the instance data into a pointer to a tAK8963 structure.
+ //
+ psInst = pvCallbackData;
+
+ //
+ // If the I2C master driver encountered a failure, force the state machine
+ // to the idle state (which will also result in a callback to propagate
+ // the error).
+ //
+ if(ui8Status != I2CM_STATUS_SUCCESS)
+ {
+ psInst->ui8State = AK8963_STATE_IDLE;
+ }
+
+ //
+ // Determine the current state of the AK8963 state machine.
+ //
+ switch(psInst->ui8State)
+ {
+ //
+ // All states that trivially transition to IDLE, and all unknown
+ // states.
+ //
+ case AK8963_STATE_READ:
+ default:
+ {
+ //
+ // The state machine is now idle.
+ //
+ psInst->ui8State = AK8963_STATE_IDLE;
+
+ //
+ // Done.
+ //
+ break;
+ }
+
+ //
+ // A write has just completed.
+ //
+ case AK8963_STATE_WRITE:
+ {
+ //
+ // Set the bit width to the new value. If the register was not
+ // modified, the values will be the same so this has no effect.
+ //
+ psInst->ui8BitOutput = psInst->ui8NewBitOutput;
+
+ //
+ // The state machine is now idle.
+ //
+ psInst->ui8State = AK8963_STATE_IDLE;
+
+ //
+ // Done.
+ //
+ break;
+ }
+
+ //
+ // A read-modify-write just completed
+ //
+ case AK8963_STATE_RMW:
+ {
+ //
+ // See if the AK8963_O_CNTL2 register was just modified.
+ //
+ if(psInst->uCommand.sReadModifyWriteState.pui8Buffer[0] ==
+ AK8963_O_CNTL2)
+ {
+ //
+ // Extract the AK8963_CNTL2_SRST field
+ //
+ if(psInst->uCommand.sReadModifyWriteState.pui8Buffer[1] &
+ AK8963_CNTL2_SRST)
+ {
+ //
+ // A soft reset has happened. Reset the bitoutput
+ // tracking variable
+ //
+ psInst->ui8BitOutput = 0;
+ }
+ }
+
+ //
+ // See if the AK8963_O_CNTL register was just modified.
+ //
+ if(psInst->uCommand.sReadModifyWriteState.pui8Buffer[0] ==
+ AK8963_O_CNTL)
+ {
+ //
+ // Extract the BITM field
+ //
+ psInst->ui8BitOutput =
+ ((psInst->uCommand.sReadModifyWriteState.pui8Buffer[1] &
+ AK8963_CNTL_BITM_M) >> AK8963_CNTL_BITM_S);
+ }
+
+ //
+ // The state machine is now idle.
+ //
+ psInst->ui8State = AK8963_STATE_IDLE;
+
+ //
+ // Done.
+ //
+ break;
+ }
+ }
+
+ //
+ // See if the state machine is now idle and there is a callback function.
+ //
+ if((psInst->ui8State == AK8963_STATE_IDLE) && psInst->pfnCallback)
+ {
+ //
+ // Call the application-supplied callback function.
+ //
+ psInst->pfnCallback(psInst->pvCallbackData, ui8Status);
+ }
+}
+
+//*****************************************************************************
+//
+//! Initializes the AK8963 driver.
+//!
+//! \param psInst is a pointer to the AK8963 instance data.
+//! \param psI2CInst is a pointer to the I2C master driver instance data.
+//! \param ui8I2CAddr is the I2C address of the AK8963 device.
+//! \param pfnCallback is the function to be called when the initialization has
+//! completed (can be \b NULL if a callback is not required).
+//! \param pvCallbackData is a pointer that is passed to the callback function.
+//!
+//! This function initializes the AK8963 driver, preparing it for operation.
+//!
+//! \return Returns 1 if the AK8963 driver was successfully initialized and 0
+//! if it was not.
+//
+//*****************************************************************************
+uint_fast8_t
+AK8963Init(tAK8963 *psInst, tI2CMInstance *psI2CInst, uint_fast8_t ui8I2CAddr,
+ tSensorCallback *pfnCallback, void *pvCallbackData)
+{
+ //
+ // Initialize the AK8963 instance structure.
+ //
+ psInst->psI2CInst = psI2CInst;
+ psInst->ui8Addr = ui8I2CAddr;
+ psInst->ui8State = AK8963_STATE_IDLE;
+ psInst->ui8BitOutput = AK8963_CNTL_BITM_14BIT >> AK8963_CNTL_BITM_S;
+ psInst->ui8NewBitOutput = AK8963_CNTL_BITM_14BIT >> AK8963_CNTL_BITM_S;
+
+ //
+ // The default settings are ok. Return success and call the callback.
+ //
+ if(pfnCallback)
+ {
+ pfnCallback(pvCallbackData, 0);
+ }
+
+ return(1);
+}
+
+//*****************************************************************************
+//
+//! Reads data from AK8963 registers.
+//!
+//! \param psInst is a pointer to the AK8963 instance data.
+//! \param ui8Reg is the first register to read.
+//! \param pui8Data is a pointer to the location to store the data that is
+//! read.
+//! \param ui16Count is the number of data bytes to read.
+//! \param pfnCallback is the function to be called when the data has been read
+//! (can be \b NULL if a callback is not required).
+//! \param pvCallbackData is a pointer that is passed to the callback function.
+//!
+//! This function reads a sequence of data values from consecutive registers in
+//! the AK8963.
+//!
+//! \return Returns 1 if the read was successfully started and 0 if it was
+//! not.
+//
+//*****************************************************************************
+uint_fast8_t
+AK8963Read(tAK8963 *psInst, uint_fast8_t ui8Reg, uint8_t *pui8Data,
+ uint_fast16_t ui16Count, tSensorCallback *pfnCallback,
+ void *pvCallbackData)
+{
+ //
+ // Return a failure if the AK8963 driver is not idle (in other words, there
+ // is already an outstanding request to the AK8963).
+ //
+ if(psInst->ui8State != AK8963_STATE_IDLE)
+ {
+ return(0);
+ }
+
+ //
+ // Save the callback information.
+ //
+ psInst->pfnCallback = pfnCallback;
+ psInst->pvCallbackData = pvCallbackData;
+
+ //
+ // Move the state machine to the wait for read state.
+ //
+ psInst->ui8State = AK8963_STATE_READ;
+
+ //
+ // Read the requested registers from the AK8963.
+ //
+ psInst->uCommand.pui8Buffer[0] = ui8Reg;
+ if(I2CMRead(psInst->psI2CInst, psInst->ui8Addr,
+ psInst->uCommand.pui8Buffer, 1, pui8Data, ui16Count,
+ AK8963Callback, psInst) == 0)
+ {
+ //
+ // The I2C write failed, so move to the idle state and return a
+ // failure.
+ //
+ psInst->ui8State = AK8963_STATE_IDLE;
+ return(0);
+ }
+
+ //
+ // Success.
+ //
+ return(1);
+}
+
+//*****************************************************************************
+//
+//! Writes data to AK8963 registers.
+//!
+//! \param psInst is a pointer to the AK8963 instance data.
+//! \param ui8Reg is the first register to write.
+//! \param pui8Data is a pointer to the data to write.
+//! \param ui16Count is the number of data bytes to write.
+//! \param pfnCallback is the function to be called when the data has been
+//! written (can be \b NULL if a callback is not required).
+//! \param pvCallbackData is a pointer that is passed to the callback function.
+//!
+//! This function writes a sequence of data values to consecutive registers in
+//! the AK8963. The first byte of the \e pui8Data buffer contains the value to
+//! be written into the \e ui8Reg register, the second value contains the data
+//! to be written into the next register, and so on.
+//!
+//! \return Returns 1 if the write was successfully started and 0 if it was
+//! not.
+//
+//*****************************************************************************
+uint_fast8_t
+AK8963Write(tAK8963 *psInst, uint_fast8_t ui8Reg, const uint8_t *pui8Data,
+ uint_fast16_t ui16Count, tSensorCallback *pfnCallback,
+ void *pvCallbackData)
+{
+ //
+ // Return a failure if the AK8963 driver is not idle (in other words, there
+ // is already an outstanding request to the AK8963).
+ //
+ if(psInst->ui8State != AK8963_STATE_IDLE)
+ {
+ return(0);
+ }
+
+ //
+ // Save the callback information.
+ //
+ psInst->pfnCallback = pfnCallback;
+ psInst->pvCallbackData = pvCallbackData;
+
+ //
+ // See if the CNTL2 register is being written.
+ //
+ if((ui8Reg <= AK8963_O_CNTL2) && ((ui8Reg + ui16Count) > AK8963_O_CNTL2))
+ {
+ //
+ // See if a soft reset is being requested.
+ //
+ if(pui8Data[ui8Reg - AK8963_O_CNTL2] & AK8963_CNTL2_SRST)
+ {
+ //
+ // Update the bit width based on the soft reset.
+ //
+ psInst->ui8NewBitOutput = 0;
+ }
+ }
+
+ //
+ // See if the CNTL register is being written.
+ //
+ if((ui8Reg <= AK8963_O_CNTL) && ((ui8Reg + ui16Count) > AK8963_O_CNTL))
+ {
+ //
+ // Extract the new value of the BITM field from the CNTL register
+ // value.
+ //
+ psInst->ui8NewBitOutput = ((pui8Data[ui8Reg - AK8963_O_CNTL] &
+ AK8963_CNTL_BITM_M) >> AK8963_CNTL_BITM_S);
+ }
+
+ //
+ // Move the state machine to the wait for write state.
+ //
+ psInst->ui8State = AK8963_STATE_WRITE;
+
+ //
+ // Write the requested registers to the AK8963.
+ //
+ if(I2CMWrite8(&(psInst->uCommand.sWriteState), psInst->psI2CInst,
+ psInst->ui8Addr, ui8Reg, pui8Data, ui16Count, AK8963Callback,
+ psInst) == 0)
+ {
+ //
+ // The I2C write failed, so move to the idle state and return a
+ // failure.
+ //
+ psInst->ui8State = AK8963_STATE_IDLE;
+ return(0);
+ }
+
+ //
+ // Success.
+ //
+ return(1);
+}
+
+//*****************************************************************************
+//
+//! Performs a read-modify-write of an AK8963 register.
+//!
+//! \param psInst is a pointer to the AK8963 instance data.
+//! \param ui8Reg is the register to modify.
+//! \param ui8Mask is the bit mask that is ANDed with the current register
+//! value.
+//! \param ui8Value is the bit mask that is ORed with the result of the AND
+//! operation.
+//! \param pfnCallback is the function to be called when the data has been
+//! changed (can be \b NULL if a callback is not required).
+//! \param pvCallbackData is a pointer that is passed to the callback function.
+//!
+//! This function changes the value of a register in the AK8963 via a
+//! read-modify-write operation, allowing one of the fields to be changed
+//! without disturbing the other fields. The \e ui8Reg register is read, ANDed
+//! with \e ui8Mask, ORed with \e ui8Value, and then written back to the
+//! AK8963.
+//!
+//! \return Returns 1 if the read-modify-write was successfully started and 0
+//! if it was not.
+//
+//*****************************************************************************
+uint_fast8_t
+AK8963ReadModifyWrite(tAK8963 *psInst, uint_fast8_t ui8Reg,
+ uint_fast8_t ui8Mask, uint_fast8_t ui8Value,
+ tSensorCallback *pfnCallback, void *pvCallbackData)
+{
+ //
+ // Return a failure if the AK8963 driver is not idle (in other words, there
+ // is already an outstanding request to the AK8963).
+ //
+ if(psInst->ui8State != AK8963_STATE_IDLE)
+ {
+ return(0);
+ }
+
+ //
+ // Save the callback information.
+ //
+ psInst->pfnCallback = pfnCallback;
+ psInst->pvCallbackData = pvCallbackData;
+
+ //
+ // Move the state machine to the wait for read-modify-write state.
+ //
+ psInst->ui8State = AK8963_STATE_RMW;
+
+ //
+ // Submit the read-modify-write request to the AK8963.
+ //
+ if(I2CMReadModifyWrite8(&(psInst->uCommand.sReadModifyWriteState),
+ psInst->psI2CInst, psInst->ui8Addr, ui8Reg,
+ ui8Mask, ui8Value, AK8963Callback, psInst) == 0)
+ {
+ //
+ // The I2C read-modify-write failed, so move to the idle state and
+ // return a failure.
+ //
+ psInst->ui8State = AK8963_STATE_IDLE;
+ return(0);
+ }
+
+ //
+ // Success.
+ //
+ return(1);
+}
+
+//*****************************************************************************
+//
+//! Reads the magnetometer data from the AK8963.
+//!
+//! \param psInst is a pointer to the AK8963 instance data.
+//! \param pfnCallback is the function to be called when the data has been read
+//! (can be \b NULL if a callback is not required).
+//! \param pvCallbackData is a pointer that is passed to the callback function.
+//!
+//! This function initiates a read of the AK8963 data registers. When the
+//! read has completed (as indicated by calling the callback function), the new
+//! readings can be obtained via:
+//!
+//! - AK8963DataMagnetoGetRaw()
+//! - AK8963DataMagnetoGetFloat()
+//!
+//! \return Returns 1 if the read was successfully started and 0 if it was not.
+//
+//*****************************************************************************
+uint_fast8_t
+AK8963DataRead(tAK8963 *psInst, tSensorCallback *pfnCallback,
+ void *pvCallbackData)
+{
+ //
+ // Return a failure if the AK8963 driver is not idle (in other words, there
+ // is already an outstanding request to the AK8963).
+ //
+ if(psInst->ui8State != AK8963_STATE_IDLE)
+ {
+ return(0);
+ }
+
+ //
+ // Save the callback information.
+ //
+ psInst->pfnCallback = pfnCallback;
+ psInst->pvCallbackData = pvCallbackData;
+
+ //
+ // Move the state machine to the wait for data read state.
+ //
+ psInst->ui8State = AK8963_STATE_READ;
+
+ //
+ // Read the data registers from the AK8963.
+ //
+ // ST1 + (HXL + HXH) + (HYL + HYH) + (HZL + HZH) + ST2 = 8 bytes
+ //
+ psInst->pui8Data[0] = AK8963_O_ST1;
+ if(I2CMRead(psInst->psI2CInst, psInst->ui8Addr, psInst->pui8Data, 1,
+ psInst->pui8Data, 8, AK8963Callback, psInst) == 0)
+ {
+ //
+ // The I2C read failed, so move to the idle state and return a failure.
+ //
+ psInst->ui8State = AK8963_STATE_IDLE;
+ return(0);
+ }
+
+ //
+ // Success.
+ //
+ return(1);
+}
+
+//*****************************************************************************
+//
+//! Gets the raw magnetometer data from the most recent data read.
+//!
+//! \param psInst is a pointer to the AK8963 instance data.
+//! \param pui16MagnetoX is a pointer to the value into which the raw X-axis
+//! magnetometer data is stored.
+//! \param pui16MagnetoY is a pointer to the value into which the raw Y-axis
+//! magnetometer data is stored.
+//! \param pui16MagnetoZ is a pointer to the value into which the raw Z-axis
+//! magnetometer data is stored.
+//!
+//! This function returns the raw magnetometer data from the most recent data
+//! read. The data is not manipulated in any way by the driver. If any of the
+//! output data pointers are \b NULL, the corresponding data is not provided.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+AK8963DataMagnetoGetRaw(tAK8963 *psInst, uint_fast16_t *pui16MagnetoX,
+ uint_fast16_t *pui16MagnetoY,
+ uint_fast16_t *pui16MagnetoZ)
+{
+ //
+ // Return the raw magnetometer values.
+ //
+ if(pui16MagnetoX)
+ {
+ *pui16MagnetoX = (psInst->pui8Data[2] << 8) | psInst->pui8Data[1];
+ }
+ if(pui16MagnetoY)
+ {
+ *pui16MagnetoY = (psInst->pui8Data[4] << 8) | psInst->pui8Data[3];
+ }
+ if(pui16MagnetoZ)
+ {
+ *pui16MagnetoZ = (psInst->pui8Data[6] << 8) | psInst->pui8Data[5];
+ }
+}
+
+//*****************************************************************************
+//
+//! Gets the magnetometer data from the most recent data read.
+//!
+//! \param psInst is a pointer to the AK8963 instance data.
+//! \param pfMagnetoX is a pointer to the value into which the X-axis
+//! magnetometer data is stored.
+//! \param pfMagnetoY is a pointer to the value into which the Y-axis
+//! magnetometer data is stored.
+//! \param pfMagnetoZ is a pointer to the value into which the Z-axis
+//! magnetometer data is stored.
+//!
+//! This function returns the magnetometer data from the most recent data read,
+//! converted into tesla. If any of the output data pointers are \b NULL, the
+//! corresponding data is not provided.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+AK8963DataMagnetoGetFloat(tAK8963 *psInst, float *pfMagnetoX,
+ float *pfMagnetoY, float *pfMagnetoZ)
+{
+ float fFactor;
+
+ //
+ // Get the conversion factor for the current data format.
+ //
+ fFactor = g_fAK8963Factors[psInst->ui8BitOutput];
+
+ //
+ // Convert the magnetometer values into floating-point tesla values.
+ //
+ if(pfMagnetoX)
+ {
+ *pfMagnetoX = ((float)(int16_t)((psInst->pui8Data[2] << 8) |
+ psInst->pui8Data[1]) * fFactor);
+ }
+ if(pfMagnetoY)
+ {
+ *pfMagnetoY = ((float)(int16_t)((psInst->pui8Data[4] << 8) |
+ psInst->pui8Data[3]) * fFactor);
+ }
+ if(pfMagnetoZ)
+ {
+ *pfMagnetoZ = ((float)(int16_t)((psInst->pui8Data[6] << 8) |
+ psInst->pui8Data[5]) * fFactor);
+ }
+}
+
+//*****************************************************************************
+//
+//! Gets the status registers from the most recent data read.
+//!
+//! \param psInst is a pointer to the AK8963 instance data.
+//! \param pui8Status1 is a pointer to the value into which the ST1 data is
+//! stored.
+//! \param pui8Status2 is a pointer to the value into which the ST2 data is
+//! stored.
+//!
+//! This function returns the magnetometer status registers from the most
+//! recent data read. If any of the output data pointers are \b NULL, the
+//! corresponding data is not be provided.
+//!
+//! Note that the AKM comp routines require ST1 and ST2, so we read them for
+//! that reason.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+AK8963DataGetStatus(tAK8963 *psInst, uint_fast8_t *pui8Status1,
+ uint_fast8_t *pui8Status2)
+{
+ //
+ // Return the status registers
+ //
+ if(pui8Status1)
+ {
+ *pui8Status1 = psInst->pui8Data[0];
+ }
+ if(pui8Status2)
+ {
+ *pui8Status2 = psInst->pui8Data[7];
+ }
+}
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
diff --git a/sensorlib/ak8963.h b/sensorlib/ak8963.h
new file mode 100644
index 0000000..4be56dd
--- /dev/null
+++ b/sensorlib/ak8963.h
@@ -0,0 +1,160 @@
+//*****************************************************************************
+//
+// ak8963.h - Prototypes for the AK8963 magnetometer driver.
+//
+// Copyright (c) 2013-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
+//
+//*****************************************************************************
+
+#ifndef __SENSORLIB_AK8963_H__
+#define __SENSORLIB_AK8963_H__
+
+//*****************************************************************************
+//
+// If building with a C++ compiler, make all of the definitions in this header
+// have a C binding.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+//*****************************************************************************
+//
+// The structure that defines the internal state of the AK8963 driver.
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ // The pointer to the I2C master interface instance used to communicate
+ // with the AK8963.
+ //
+ tI2CMInstance *psI2CInst;
+
+ //
+ // The I2C address of the AK8963.
+ //
+ uint8_t ui8Addr;
+
+ //
+ // The state of the state machine used while accessing the AK8963.
+ //
+ uint8_t ui8State;
+
+ //
+ // The data output bit width.
+ //
+ uint8_t ui8BitOutput;
+
+ //
+ // The new data output bit width, which is used when a register write
+ // succeeds.
+ //
+ uint8_t ui8NewBitOutput;
+
+ //
+ // The data buffer used for sending/receiving data to/from the AK8963.
+ //
+ uint8_t pui8Data[8];
+
+ //
+ // The function that is called when the current request has completed
+ // processing.
+ //
+ tSensorCallback *pfnCallback;
+
+ //
+ // The callback data provided to the callback function.
+ //
+ void *pvCallbackData;
+
+ //
+ // A union of structures that are used for read, write and
+ // read-modify-write operations. Since only one operation can be active at
+ // a time, it is safe to re-use the memory in this manner.
+ //
+ union
+ {
+ //
+ // A buffer used to store the write portion of a register read.
+ //
+ uint8_t pui8Buffer[2];
+
+ //
+ // The write state used to write register values.
+ //
+ tI2CMWrite8 sWriteState;
+
+ //
+ // The read-modify-write state used to modify register values.
+ //
+ tI2CMReadModifyWrite8 sReadModifyWriteState;
+ }
+ uCommand;
+}
+tAK8963;
+
+//*****************************************************************************
+//
+// Function prototypes.
+//
+//*****************************************************************************
+extern uint_fast8_t AK8963Init(tAK8963 *psInst, tI2CMInstance *psI2CInst,
+ uint_fast8_t ui8I2CAddr,
+ tSensorCallback *pfnCallback,
+ void *pvCallbackData);
+extern uint_fast8_t AK8963Read(tAK8963 *psInst, uint_fast8_t ui8Reg,
+ uint8_t *pui8Data, uint_fast16_t ui16Count,
+ tSensorCallback *pfnCallback,
+ void *pvCallbackData);
+extern uint_fast8_t AK8963Write(tAK8963 *psInst, uint_fast8_t ui8Reg,
+ const uint8_t *pui8Data,
+ uint_fast16_t ui16Count,
+ tSensorCallback *pfnCallback,
+ void *pvCallbackData);
+extern uint_fast8_t AK8963ReadModifyWrite(tAK8963 *psInst,
+ uint_fast8_t ui8Reg,
+ uint_fast8_t ui8Mask,
+ uint_fast8_t ui8Value,
+ tSensorCallback *pfnCallback,
+ void *pvCallbackData);
+extern uint_fast8_t AK8963DataRead(tAK8963 *psInst,
+ tSensorCallback *pfnCallback,
+ void *pvCallbackData);
+extern void AK8963DataMagnetoGetRaw(tAK8963 *psInst,
+ uint_fast16_t *pui16MagnetoX,
+ uint_fast16_t *pui16MagnetoY,
+ uint_fast16_t *pui16MagnetoZ);
+extern void AK8963DataMagnetoGetFloat(tAK8963 *psInst, float *pfMagnetoX,
+ float *pfMagnetoY, float *pfMagnetoZ);
+extern void AK8963DataGetStatus(tAK8963 *psInst, uint_fast8_t *pui8Status1,
+ uint_fast8_t *pui8Status2);
+
+//*****************************************************************************
+//
+// Mark the end of the C bindings section for C++ compilers.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __SENSORLIB_AK8963_H__
diff --git a/sensorlib/ak8975.c b/sensorlib/ak8975.c
new file mode 100644
index 0000000..776229c
--- /dev/null
+++ b/sensorlib/ak8975.c
@@ -0,0 +1,558 @@
+//*****************************************************************************
+//
+// ak8975.c - Driver for the AK8975 magnetometer.
+//
+// Copyright (c) 2013-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
+//
+//*****************************************************************************
+
+#include <stdint.h>
+#include "sensorlib/hw_ak8975.h"
+#include "sensorlib/i2cm_drv.h"
+#include "sensorlib/ak8975.h"
+
+//*****************************************************************************
+//
+//! \addtogroup ak8975_api
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// The states of the AK8975 state machine.
+//
+//*****************************************************************************
+#define AK8975_STATE_IDLE 0 // State machine is idle
+#define AK8975_STATE_READ 1 // Waiting for read
+#define AK8975_STATE_WRITE 2 // Waiting for write
+#define AK8975_STATE_RMW 3 // Waiting for read-modify-write
+
+//*****************************************************************************
+//
+// Converting sensor data to tesla (0.3 uT per LSB)
+//
+//*****************************************************************************
+#define CONVERT_TO_TESLA 0.0000003
+
+//*****************************************************************************
+//
+// The callback function that is called when I2C transations to/from the
+// AK8975 have completed.
+//
+//*****************************************************************************
+static void
+AK8975Callback(void *pvCallbackData, uint_fast8_t ui8Status)
+{
+ tAK8975 *psInst;
+
+ //
+ // Convert the instance data into a pointer to a tAK8975 structure.
+ //
+ psInst = pvCallbackData;
+
+ //
+ // If the I2C master driver encountered a failure, force the state machine
+ // to the idle state (which will also result in a callback to propagate the
+ // error).
+ //
+ if(ui8Status != I2CM_STATUS_SUCCESS)
+ {
+ psInst->ui8State = AK8975_STATE_IDLE;
+ }
+
+ //
+ // Determine the current state of the AK8975 state machine.
+ //
+ switch(psInst->ui8State)
+ {
+ //
+ // All states that trivially transition to IDLE, and all unknown
+ // states.
+ //
+ case AK8975_STATE_READ:
+ case AK8975_STATE_WRITE:
+ case AK8975_STATE_RMW:
+ default:
+ {
+ //
+ // The state machine is now idle.
+ //
+ psInst->ui8State = AK8975_STATE_IDLE;
+
+ //
+ // Done.
+ //
+ break;
+ }
+ }
+
+ //
+ // See if the state machine is now idle and there is a callback function.
+ //
+ if((psInst->ui8State == AK8975_STATE_IDLE) && psInst->pfnCallback)
+ {
+ //
+ // Call the application-supplied callback function.
+ //
+ psInst->pfnCallback(psInst->pvCallbackData, ui8Status);
+ }
+}
+
+//*****************************************************************************
+//
+//! Initializes the AK8975 driver.
+//!
+//! \param psInst is a pointer to the AK8975 instance data.
+//! \param psI2CInst is a pointer to the I2C master driver instance data.
+//! \param ui8I2CAddr is the I2C address of the AK8975 device.
+//! \param pfnCallback is the function to be called when the initialization has
+//! completed (can be \b NULL if a callback is not required).
+//! \param pvCallbackData is a pointer that is passed to the callback function.
+//!
+//! This function initializes the AK8975 driver, preparing it for operation.
+//!
+//! \return Returns 1 if the AK8975 driver was successfully initialized and 0
+//! if it was not.
+//
+//*****************************************************************************
+uint_fast8_t
+AK8975Init(tAK8975 *psInst, tI2CMInstance *psI2CInst, uint_fast8_t ui8I2CAddr,
+ tSensorCallback *pfnCallback, void *pvCallbackData)
+{
+ //
+ // Initialize the AK8975 instance structure.
+ //
+ psInst->psI2CInst = psI2CInst;
+ psInst->ui8Addr = ui8I2CAddr;
+ psInst->ui8State = AK8975_STATE_IDLE;
+
+ //
+ // The default settings are ok. Return success and call the callback.
+ //
+ if(pfnCallback)
+ {
+ pfnCallback(pvCallbackData, 0);
+ }
+
+ //
+ // Success.
+ //
+ return(1);
+}
+
+//*****************************************************************************
+//
+//! Reads data from AK8975 registers.
+//!
+//! \param psInst is a pointer to the AK8975 instance data.
+//! \param ui8Reg is the first register to read.
+//! \param pui8Data is a pointer to the location to store the data that is
+//! read.
+//! \param ui16Count is the number of data bytes to read.
+//! \param pfnCallback is the function to be called when the data has been read
+//! (can be \b NULL if a callback is not required).
+//! \param pvCallbackData is a pointer that is passed to the callback function.
+//!
+//! This function reads a sequence of data values from consecutive registers in
+//! the AK8975.
+//!
+//! \return Returns 1 if the write was successfully started and 0 if it was
+//! not.
+//
+//*****************************************************************************
+uint_fast8_t
+AK8975Read(tAK8975 *psInst, uint_fast8_t ui8Reg, uint8_t *pui8Data,
+ uint_fast16_t ui16Count, tSensorCallback *pfnCallback,
+ void *pvCallbackData)
+{
+ //
+ // Return a failure if the AK8975 driver is not idle (in other words, there
+ // is already an outstanding request to the AK8975).
+ //
+ if(psInst->ui8State != AK8975_STATE_IDLE)
+ {
+ return(0);
+ }
+
+ //
+ // Save the callback information.
+ //
+ psInst->pfnCallback = pfnCallback;
+ psInst->pvCallbackData = pvCallbackData;
+
+ //
+ // Move the state machine to the wait for read state.
+ //
+ psInst->ui8State = AK8975_STATE_READ;
+
+ //
+ // Read the requested registers from the AK8975.
+ //
+ psInst->uCommand.pui8Buffer[0] = ui8Reg;
+ if(I2CMRead(psInst->psI2CInst, psInst->ui8Addr,
+ psInst->uCommand.pui8Buffer, 1, pui8Data, ui16Count,
+ AK8975Callback, psInst) == 0)
+ {
+ //
+ // The I2C write failed, so move to the idle state and return a
+ // failure.
+ //
+ psInst->ui8State = AK8975_STATE_IDLE;
+ return(0);
+ }
+
+ //
+ // Success.
+ //
+ return(1);
+}
+
+//*****************************************************************************
+//
+//! Writes data to AK8975 registers.
+//!
+//! \param psInst is a pointer to the AK8975 instance data.
+//! \param ui8Reg is the first register to write.
+//! \param pui8Data is a pointer to the data to write.
+//! \param ui16Count is the number of data bytes to write.
+//! \param pfnCallback is the function to be called when the data has been
+//! written (can be \b NULL if a callback is not required).
+//! \param pvCallbackData is a pointer that is passed to the callback function.
+//!
+//! This function writes a sequence of data values to consecutive registers in
+//! the AK8975. The first byte of the \e pui8Data buffer contains the value to
+//! be written into the \e ui8Reg register, the second value contains the data
+//! to be written into the next register, and so on.
+//!
+//! \return Returns 1 if the write was successfully started and 0 if it was
+//! not.
+//
+//*****************************************************************************
+uint_fast8_t
+AK8975Write(tAK8975 *psInst, uint_fast8_t ui8Reg, uint8_t *pui8Data,
+ uint_fast16_t ui16Count, tSensorCallback *pfnCallback,
+ void *pvCallbackData)
+{
+ //
+ // Return a failure if the AK8975 driver is not idle (in other words, there
+ // is already an outstanding request to the AK8975).
+ //
+ if(psInst->ui8State != AK8975_STATE_IDLE)
+ {
+ return(0);
+ }
+
+ //
+ // Save the callback information.
+ //
+ psInst->pfnCallback = pfnCallback;
+ psInst->pvCallbackData = pvCallbackData;
+
+ //
+ // Move the state machine to the wait for write state.
+ //
+ psInst->ui8State = AK8975_STATE_WRITE;
+
+ //
+ // Write the requested registers to the AK8975.
+ //
+ if(I2CMWrite8(&(psInst->uCommand.sWriteState), psInst->psI2CInst,
+ psInst->ui8Addr, ui8Reg, pui8Data, ui16Count, AK8975Callback,
+ psInst) == 0)
+ {
+ //
+ // The I2C write failed, so move to the idle state and return a
+ // failure.
+ //
+ psInst->ui8State = AK8975_STATE_IDLE;
+ return(0);
+ }
+
+ //
+ // Success.
+ //
+ return(1);
+}
+
+//*****************************************************************************
+//
+//! Performs a read-modify-write of an AK8975 register.
+//!
+//! \param psInst is a pointer to the AK8975 instance data.
+//! \param ui8Reg is the register to modify.
+//! \param ui8Mask is the bit mask that is ANDed with the current register
+//! value.
+//! \param ui8Value is the bit mask that is ORed with the result of the AND
+//! operation.
+//! \param pfnCallback is the function to be called when the data has been
+//! changed (can be \b NULL if a callback is not required).
+//! \param pvCallbackData is a pointer that is passed to the callback function.
+//!
+//! This function changes the value of a register in the AK8975 via a
+//! read-modify-write operation, allowing one of the fields to be changed
+//! without disturbing the other fields. The \e ui8Reg register is read, ANDed
+//! with \e ui8Mask, ORed with \e ui8Value, and then written back to the
+//! AK8975.
+//!
+//! \return Returns 1 if the read-modify-write was successfully started and 0
+//! if it was not.
+//
+//*****************************************************************************
+uint_fast8_t
+AK8975ReadModifyWrite(tAK8975 *psInst, uint_fast8_t ui8Reg,
+ uint_fast8_t ui8Mask, uint_fast8_t ui8Value,
+ tSensorCallback *pfnCallback, void *pvCallbackData)
+{
+ //
+ // Return a failure if the AK8975 driver is not idle (in other words, there
+ // is already an outstanding request to the AK8975).
+ //
+ if(psInst->ui8State != AK8975_STATE_IDLE)
+ {
+ return(0);
+ }
+
+ //
+ // Save the callback information.
+ //
+ psInst->pfnCallback = pfnCallback;
+ psInst->pvCallbackData = pvCallbackData;
+
+ //
+ // Move the state machine to the wait for read-modify-write state.
+ //
+ psInst->ui8State = AK8975_STATE_RMW;
+
+ //
+ // Submit the read-modify-write request to the AK8975.
+ //
+ if(I2CMReadModifyWrite8(&(psInst->uCommand.sReadModifyWriteState),
+ psInst->psI2CInst, psInst->ui8Addr, ui8Reg,
+ ui8Mask, ui8Value, AK8975Callback, psInst) == 0)
+ {
+ //
+ // The I2C read-modify-write failed, so move to the idle state and
+ // return a failure.
+ //
+ psInst->ui8State = AK8975_STATE_IDLE;
+ return(0);
+ }
+
+ //
+ // Success.
+ //
+ return(1);
+}
+
+//*****************************************************************************
+//
+//! Reads the magnetometer data from the AK8975.
+//!
+//! \param psInst is a pointer to the AK8975 instance data.
+//! \param pfnCallback is the function to be called when the data has been read
+//! (can be \b NULL if a callback is not required).
+//! \param pvCallbackData is a pointer that is passed to the callback function.
+//!
+//! This function initiates a read of the AK8975 data registers. When the
+//! read has completed (as indicated by calling the callback function), the new
+//! readings can be obtained via:
+//!
+//! - AK8975DataMagnetoGetRaw()
+//! - AK8975DataMagnetoGetFloat()
+//!
+//! \return Returns 1 if the read was successfully started and 0 if it was not.
+//
+//*****************************************************************************
+uint_fast8_t
+AK8975DataRead(tAK8975 *psInst, tSensorCallback *pfnCallback,
+ void *pvCallbackData)
+{
+ //
+ // Return a failure if the AK8975 driver is not idle (in other words, there
+ // is already an outstanding request to the AK8975).
+ //
+ if(psInst->ui8State != AK8975_STATE_IDLE)
+ {
+ return(0);
+ }
+
+ //
+ // Save the callback information.
+ //
+ psInst->pfnCallback = pfnCallback;
+ psInst->pvCallbackData = pvCallbackData;
+
+ //
+ // Move the state machine to the wait for data read state.
+ //
+ psInst->ui8State = AK8975_STATE_READ;
+
+ //
+ // Read the data registers from the AK8975.
+ //
+ // ST1 + (HXL + HXH) + (HYL + HYH) + (HZL + HZH) + ST2 = 8 bytes
+ //
+ psInst->pui8Data[0] = AK8975_O_ST1;
+ if(I2CMRead(psInst->psI2CInst, psInst->ui8Addr, psInst->pui8Data, 1,
+ psInst->pui8Data, 8, AK8975Callback, psInst) == 0)
+ {
+ //
+ // The I2C read failed, so move to the idle state and return a failure.
+ //
+ psInst->ui8State = AK8975_STATE_IDLE;
+ return(0);
+ }
+
+ //
+ // Success.
+ //
+ return(1);
+}
+
+//*****************************************************************************
+//
+//! Gets the raw magnetometer data from the most recent data read.
+//!
+//! \param psInst is a pointer to the AK8975 instance data.
+//! \param pui16MagnetoX is a pointer to the value into which the raw X-axis
+//! magnetometer data is stored.
+//! \param pui16MagnetoY is a pointer to the value into which the raw Y-axis
+//! magnetometer data is stored.
+//! \param pui16MagnetoZ is a pointer to the value into which the raw Z-axis
+//! magnetometer data is stored.
+//!
+//! This function returns the raw magnetometer data from the most recent data
+//! read. The data is not manipulated in any way by the driver. If any of the
+//! output data pointers are \b NULL, the corresponding data is not provided.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+AK8975DataMagnetoGetRaw(tAK8975 *psInst, uint_fast16_t *pui16MagnetoX,
+ uint_fast16_t *pui16MagnetoY,
+ uint_fast16_t *pui16MagnetoZ)
+{
+ //
+ // Return the raw magnetometer values.
+ //
+ if(pui16MagnetoX)
+ {
+ *pui16MagnetoX = (psInst->pui8Data[2] << 8) | psInst->pui8Data[1];
+ }
+ if(pui16MagnetoY)
+ {
+ *pui16MagnetoY = (psInst->pui8Data[4] << 8) | psInst->pui8Data[3];
+ }
+ if(pui16MagnetoZ)
+ {
+ *pui16MagnetoZ = (psInst->pui8Data[6] << 8) | psInst->pui8Data[5];
+ }
+}
+
+//*****************************************************************************
+//
+//! Gets the magnetometer data from the most recent data read.
+//!
+//! \param psInst is a pointer to the AK8975 instance data.
+//! \param pfMagnetoX is a pointer to the value into which the X-axis
+//! magnetometer data is stored.
+//! \param pfMagnetoY is a pointer to the value into which the Y-axis
+//! magnetometer data is stored.
+//! \param pfMagnetoZ is a pointer to the value into which the Z-axis
+//! magnetometer data is stored.
+//!
+//! This function returns the magnetometer data from the most recent data read,
+//! converted into tesla. If any of the output data pointers are
+//! \b NULL, the corresponding data is not provided.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+AK8975DataMagnetoGetFloat(tAK8975 *psInst, float *pfMagnetoX,
+ float *pfMagnetoY, float *pfMagnetoZ)
+{
+ //
+ // Convert the magnetometer values into floating-point tesla values.
+ //
+ if(pfMagnetoX)
+ {
+ *pfMagnetoX = ((float)(int16_t)((psInst->pui8Data[2] << 8) |
+ psInst->pui8Data[1]) *
+ CONVERT_TO_TESLA);
+ }
+ if(pfMagnetoY)
+ {
+ *pfMagnetoY = ((float)(int16_t)((psInst->pui8Data[4] << 8) |
+ psInst->pui8Data[3]) *
+ CONVERT_TO_TESLA);
+ }
+ if(pfMagnetoZ)
+ {
+ *pfMagnetoZ = ((float)(int16_t)((psInst->pui8Data[6] << 8) |
+ psInst->pui8Data[5]) *
+ CONVERT_TO_TESLA);
+ }
+}
+
+//*****************************************************************************
+//
+//! Gets the status registers from the most recent data read.
+//!
+//! \param psInst is a pointer to the AK8975 instance data.
+//! \param pui8Status1 is a pointer to the value into which the ST1 data is
+//! stored.
+//! \param pui8Status2 is a pointer to the value into which the ST2 data is
+//! stored.
+//!
+//! This function returns the magnetometer status registers from the most
+//! recent data read. If any of the output data pointers are \b NULL, the
+//! corresponding data is not provided.
+//!
+//! Note that the AKM comp routines require ST1 and ST2, so we read
+//! them for that reason.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+AK8975DataGetStatus(tAK8975 *psInst, uint_fast8_t *pui8Status1,
+ uint_fast8_t *pui8Status2)
+{
+ //
+ // Return the status registers
+ //
+ if(pui8Status1)
+ {
+ *pui8Status1 = psInst->pui8Data[0];
+ }
+ if(pui8Status2)
+ {
+ *pui8Status2 = psInst->pui8Data[7];
+ }
+}
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
diff --git a/sensorlib/ak8975.h b/sensorlib/ak8975.h
new file mode 100644
index 0000000..97c2893
--- /dev/null
+++ b/sensorlib/ak8975.h
@@ -0,0 +1,148 @@
+//*****************************************************************************
+//
+// ak8975.h - Prototypes for the AK8975 magnetometer driver.
+//
+// Copyright (c) 2013-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
+//
+//*****************************************************************************
+
+#ifndef __SENSORLIB_AK8975_H__
+#define __SENSORLIB_AK8975_H__
+
+//*****************************************************************************
+//
+// If building with a C++ compiler, make all of the definitions in this header
+// have a C binding.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+//*****************************************************************************
+//
+// The structure that defines the internal state of the AK8975 driver.
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ // The pointer to the I2C master interface instance used to communicate
+ // with the AK8975.
+ //
+ tI2CMInstance *psI2CInst;
+
+ //
+ // The I2C address of the AK8975.
+ //
+ uint8_t ui8Addr;
+
+ //
+ // The state of the state machine used while accessing the AK8975.
+ //
+ uint8_t ui8State;
+
+ //
+ // The data buffer used for sending/receiving data to/from the AK8975.
+ //
+ uint8_t pui8Data[8];
+
+ //
+ // The function that is called when the current request has completed
+ // processing.
+ //
+ tSensorCallback *pfnCallback;
+
+ //
+ // The callback data provided to the callback function.
+ //
+ void *pvCallbackData;
+
+ //
+ // A union of structures that are used for read, write and
+ // read-modify-write operations. Since only one operation can be active at
+ // a time, it is safe to re-use the memory in this manner.
+ //
+ union
+ {
+ //
+ // A buffer used to store the write portion of a register read.
+ //
+ uint8_t pui8Buffer[2];
+
+ //
+ // The write state used to write register values.
+ //
+ tI2CMWrite8 sWriteState;
+
+ //
+ // The read-modify-write state used to modify register values.
+ //
+ tI2CMReadModifyWrite8 sReadModifyWriteState;
+ }
+ uCommand;
+}
+tAK8975;
+
+//*****************************************************************************
+//
+// Function prototypes.
+//
+//*****************************************************************************
+extern uint_fast8_t AK8975Init(tAK8975 *psInst, tI2CMInstance *psI2CInst,
+ uint_fast8_t ui8I2CAddr,
+ tSensorCallback *pfnCallback,
+ void *pvCallbackData);
+extern uint_fast8_t AK8975Read(tAK8975 *psInst, uint_fast8_t ui8Reg,
+ uint8_t *pui8Data, uint_fast16_t ui16Count,
+ tSensorCallback *pfnCallback,
+ void *pvCallbackData);
+extern uint_fast8_t AK8975Write(tAK8975 *psInst, uint_fast8_t ui8Reg,
+ uint8_t *pui8Data, uint_fast16_t ui16Count,
+ tSensorCallback *pfnCallback,
+ void *pvCallbackData);
+extern uint_fast8_t AK8975ReadModifyWrite(tAK8975 *psInst,
+ uint_fast8_t ui8Reg,
+ uint_fast8_t ui8Mask,
+ uint_fast8_t ui8Value,
+ tSensorCallback *pfnCallback,
+ void *pvCallbackData);
+extern uint_fast8_t AK8975DataRead(tAK8975 *psInst,
+ tSensorCallback *pfnCallback,
+ void *pvCallbackData);
+extern void AK8975DataMagnetoGetRaw(tAK8975 *psInst,
+ uint_fast16_t *pui16MagnetoX,
+ uint_fast16_t *pui16MagnetoY,
+ uint_fast16_t *pui16MagnetoZ);
+extern void AK8975DataMagnetoGetFloat(tAK8975 *psInst, float *pfMagnetoX,
+ float *pfMagnetoY, float *pfMagnetoZ);
+extern void AK8975DataGetStatus(tAK8975 *psInst, uint_fast8_t *pui8Status1,
+ uint_fast8_t *pui8Status2);
+
+//*****************************************************************************
+//
+// Mark the end of the C bindings section for C++ compilers.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __SENSORLIB_AK8975_H__
diff --git a/sensorlib/bmp180.c b/sensorlib/bmp180.c
new file mode 100644
index 0000000..a25701e
--- /dev/null
+++ b/sensorlib/bmp180.c
@@ -0,0 +1,919 @@
+//*****************************************************************************
+//
+// bmp180.c - Driver for the BMP180 pressure sensor.
+//
+// Copyright (c) 2012-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
+//
+//*****************************************************************************
+
+#include <math.h>
+#include <stdint.h>
+#include "sensorlib/hw_bmp180.h"
+#include "sensorlib/i2cm_drv.h"
+#include "sensorlib/bmp180.h"
+
+//*****************************************************************************
+//
+//! \addtogroup bmp180_api
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// The states of the BMP180 state machine.
+//
+//*****************************************************************************
+#define BMP180_STATE_IDLE 0 // State machine is idle
+#define BMP180_STATE_INIT1 1 // Waiting for initialization 1
+#define BMP180_STATE_INIT2 2 // Waiting for initialization 2
+#define BMP180_STATE_READ 3 // Waiting for read
+#define BMP180_STATE_WRITE 4 // Waiting for write
+#define BMP180_STATE_RMW 5 // Waiting for read-modify-write
+#define BMP180_STATE_REQ_TEMP 6 // Requested temperature
+#define BMP180_STATE_WAIT_TEMP 7 // Waiting for temperature ready
+#define BMP180_STATE_READ_TEMP 8 // Reading temperature value
+#define BMP180_STATE_REQ_PRES 9 // Requested pressure
+#define BMP180_STATE_WAIT_PRES 10 // Waiting for pressure ready
+#define BMP180_STATE_READ_PRES 11 // Reading pressure value
+
+//*****************************************************************************
+//
+// The callback function that is called when I2C transations to/from the
+// BMP180 have completed.
+//
+//*****************************************************************************
+static void
+BMP180Callback(void *pvCallbackData, uint_fast8_t ui8Status)
+{
+ tBMP180 *psInst;
+ uint16_t ui16ReadVerify;
+
+ //
+ // Convert the instance data into a pointer to a tBMP180 structure.
+ //
+ psInst = pvCallbackData;
+
+ //
+ // If the I2C master driver encountered a failure, force the state machine
+ // to the idle state (which will also result in a callback to propagate the
+ // error).
+ //
+ if(ui8Status != I2CM_STATUS_SUCCESS)
+ {
+ psInst->ui8State = BMP180_STATE_IDLE;
+ }
+
+ //
+ // Determine the current state of the BMP180 state machine.
+ //
+ switch(psInst->ui8State)
+ {
+ //
+ // All states that trivially transition to IDLE, and all unknown
+ // states.
+ //
+ case BMP180_STATE_READ:
+ case BMP180_STATE_READ_PRES:
+ default:
+ {
+ //
+ // The state machine is now idle.
+ //
+ psInst->ui8State = BMP180_STATE_IDLE;
+
+ //
+ // Done.
+ //
+ break;
+ }
+
+ //
+ // The first step of initialization has just completed.
+ //
+ case BMP180_STATE_INIT1:
+ {
+ //
+ // Read the calibration data from the BMP180.
+ //
+ psInst->pui8Data[0] = BMP180_O_AC1_MSB;
+ I2CMRead(psInst->psI2CInst, psInst->ui8Addr, psInst->pui8Data, 1,
+ psInst->uCommand.pui8Buffer, 22, BMP180Callback, psInst);
+
+ //
+ // Move to the wait for initialization step 2 state.
+ //
+ psInst->ui8State = BMP180_STATE_INIT2;
+
+ //
+ // Done.
+ //
+ break;
+ }
+
+ //
+ // The second step of initialization has just completed.
+ //
+ case BMP180_STATE_INIT2:
+ {
+ //
+ // Data communication is checked by verifying that the calibration
+ // data is neither 0 nor 0xFFFF. This is used to check that reset
+ // is complete and the part is ready. It also verifies that we
+ // have valid calibration data before proceeding.
+ //
+ ui16ReadVerify = psInst->uCommand.pui8Buffer[0];
+ ui16ReadVerify <<= 8;
+ ui16ReadVerify |= psInst->uCommand.pui8Buffer[1];
+ if((ui16ReadVerify == 0) || (ui16ReadVerify == 0xFFFF))
+ {
+ //
+ // Reread the calibration data from the BMP180.
+ //
+ psInst->pui8Data[0] = BMP180_O_AC1_MSB;
+ I2CMRead(psInst->psI2CInst, psInst->ui8Addr, psInst->pui8Data,
+ 1, psInst->uCommand.pui8Buffer, 22, BMP180Callback,
+ psInst);
+ }
+ else
+ {
+ //
+ // Extract the calibration data from the data that was read.
+ //
+ psInst->i16AC1 =
+ (int16_t)((psInst->uCommand.pui8Buffer[0] << 8) |
+ psInst->uCommand.pui8Buffer[1]);
+ psInst->i16AC2 =
+ (int16_t)((psInst->uCommand.pui8Buffer[2] << 8) |
+ psInst->uCommand.pui8Buffer[3]);
+ psInst->i16AC3 =
+ (int16_t)((psInst->uCommand.pui8Buffer[4] << 8) |
+ psInst->uCommand.pui8Buffer[5]);
+ psInst->ui16AC4 =
+ (uint16_t)((psInst->uCommand.pui8Buffer[6] << 8) |
+ psInst->uCommand.pui8Buffer[7]);
+ psInst->ui16AC5 =
+ (uint16_t)((psInst->uCommand.pui8Buffer[8] << 8) |
+ psInst->uCommand.pui8Buffer[9]);
+ psInst->ui16AC6 =
+ (uint16_t)((psInst->uCommand.pui8Buffer[10] << 8) |
+ psInst->uCommand.pui8Buffer[11]);
+ psInst->i16B1 =
+ (int16_t)((psInst->uCommand.pui8Buffer[12] << 8) |
+ psInst->uCommand.pui8Buffer[13]);
+ psInst->i16B2 =
+ (int16_t)((psInst->uCommand.pui8Buffer[14] << 8) |
+ psInst->uCommand.pui8Buffer[15]);
+ psInst->i16MC =
+ (int16_t)((psInst->uCommand.pui8Buffer[18] << 8) |
+ psInst->uCommand.pui8Buffer[19]);
+ psInst->i16MD =
+ (int16_t)((psInst->uCommand.pui8Buffer[20] << 8) |
+ psInst->uCommand.pui8Buffer[21]);
+
+ //
+ // The state machine is now idle.
+ //
+ psInst->ui8State = BMP180_STATE_IDLE;
+ }
+
+ //
+ // Done.
+ //
+ break;
+ }
+
+ //
+ // A write has just completed.
+ //
+ case BMP180_STATE_WRITE:
+ {
+ //
+ // Set the mode to the new mode. If the register was not modified,
+ // the values will be the same so this has no effect.
+ //
+ psInst->ui8Mode = psInst->ui8NewMode;
+
+ //
+ // The state machine is now idle.
+ //
+ psInst->ui8State = BMP180_STATE_IDLE;
+
+ //
+ // Done.
+ //
+ break;
+ }
+
+ //
+ // A read-modify-write has just completed.
+ //
+ case BMP180_STATE_RMW:
+ {
+ //
+ // See if the CTRL_MEAS register was just modified.
+ //
+ if(psInst->uCommand.sReadModifyWriteState.pui8Buffer[0] ==
+ BMP180_O_CTRL_MEAS)
+ {
+ //
+ // Extract the measurement mode from the CTRL_MEAS register
+ // value.
+ //
+ psInst->ui8Mode =
+ (psInst->uCommand.sReadModifyWriteState.pui8Buffer[1] &
+ BMP180_CTRL_MEAS_OSS_M);
+ }
+
+ //
+ // The state machine is now idle.
+ //
+ psInst->ui8State = BMP180_STATE_IDLE;
+
+ //
+ // Done.
+ //
+ break;
+ }
+
+ //
+ // The temperature has been requested.
+ //
+ case BMP180_STATE_REQ_TEMP:
+ {
+ //
+ // Read the control register to see if the temperature reading is
+ // available.
+ //
+ I2CMRead(psInst->psI2CInst, psInst->ui8Addr,
+ psInst->uCommand.pui8Buffer, 1,
+ psInst->uCommand.pui8Buffer + 1, 1, BMP180Callback,
+ psInst);
+
+ //
+ // Move to the wait for temperature state.
+ //
+ psInst->ui8State = BMP180_STATE_WAIT_TEMP;
+
+ //
+ // Done.
+ //
+ break;
+ }
+
+ //
+ // Waiting for the temperature reading to be available.
+ //
+ case BMP180_STATE_WAIT_TEMP:
+ {
+ //
+ // See if the temperature reading is available.
+ //
+ if(psInst->uCommand.pui8Buffer[1] & BMP180_CTRL_MEAS_SCO)
+ {
+ //
+ // The temperature reading is not ready yet, so read the
+ // control register again.
+ //
+ I2CMRead(psInst->psI2CInst, psInst->ui8Addr,
+ psInst->uCommand.pui8Buffer, 1,
+ psInst->uCommand.pui8Buffer + 1, 1, BMP180Callback,
+ psInst);
+ }
+ else
+ {
+ //
+ // The temperature reading is ready, so read it now.
+ //
+ psInst->uCommand.pui8Buffer[0] = BMP180_O_OUT_MSB;
+ I2CMRead(psInst->psI2CInst, psInst->ui8Addr,
+ psInst->uCommand.pui8Buffer, 1, psInst->pui8Data, 2,
+ BMP180Callback, psInst);
+
+ //
+ // Move to the temperature reading state.
+ //
+ psInst->ui8State = BMP180_STATE_READ_TEMP;
+ }
+
+ //
+ // Done.
+ //
+ break;
+ }
+
+ //
+ // The temperature reading has been retrieved.
+ //
+ case BMP180_STATE_READ_TEMP:
+ {
+ //
+ // Request the pressure reading from the BMP180.
+ //
+ psInst->uCommand.pui8Buffer[0] = BMP180_O_CTRL_MEAS;
+ psInst->uCommand.pui8Buffer[1] = (BMP180_CTRL_MEAS_SCO |
+ BMP180_CTRL_MEAS_PRESSURE |
+ psInst->ui8Mode);
+ I2CMWrite(psInst->psI2CInst, psInst->ui8Addr,
+ psInst->uCommand.pui8Buffer, 2, BMP180Callback, psInst);
+
+ //
+ // Move to the pressure reading request state.
+ //
+ psInst->ui8State = BMP180_STATE_REQ_PRES;
+
+ //
+ // Done.
+ //
+ break;
+ }
+
+ //
+ // The pressure has been requested.
+ //
+ case BMP180_STATE_REQ_PRES:
+ {
+ //
+ // Read the control register to see if the pressure reading is
+ // available.
+ //
+ I2CMRead(psInst->psI2CInst, psInst->ui8Addr,
+ psInst->uCommand.pui8Buffer, 1,
+ psInst->uCommand.pui8Buffer + 1, 1, BMP180Callback,
+ psInst);
+
+ //
+ // Move to the wait for pressure state.
+ //
+ psInst->ui8State = BMP180_STATE_WAIT_PRES;
+
+ //
+ // Done.
+ //
+ break;
+ }
+
+ //
+ // Waiting for the pressure reading to be available.
+ //
+ case BMP180_STATE_WAIT_PRES:
+ {
+ //
+ // See if the pressure reading is available.
+ //
+ if(psInst->uCommand.pui8Buffer[1] & BMP180_CTRL_MEAS_SCO)
+ {
+ //
+ // The pressure reading is not ready yet, so read the control
+ // register again.
+ //
+ I2CMRead(psInst->psI2CInst, psInst->ui8Addr,
+ psInst->uCommand.pui8Buffer, 1,
+ psInst->uCommand.pui8Buffer + 1, 1, BMP180Callback,
+ psInst);
+ }
+ else
+ {
+ //
+ // The pressure reading is ready, so read it now.
+ //
+ psInst->uCommand.pui8Buffer[0] = BMP180_O_OUT_MSB;
+ I2CMRead(psInst->psI2CInst, psInst->ui8Addr,
+ psInst->uCommand.pui8Buffer, 1, psInst->pui8Data + 2,
+ 3, BMP180Callback, psInst);
+
+ //
+ // Move to the pressure reading state.
+ //
+ psInst->ui8State = BMP180_STATE_READ_PRES;
+ }
+
+ //
+ // Done.
+ //
+ break;
+ }
+ }
+
+ //
+ // See if the state machine is now idle and there is a callback function.
+ //
+ if((psInst->ui8State == BMP180_STATE_IDLE) && psInst->pfnCallback)
+ {
+ //
+ // Call the application-supplied callback function.
+ //
+ psInst->pfnCallback(psInst->pvCallbackData, ui8Status);
+ }
+}
+
+//*****************************************************************************
+//
+//! Initializes the BMP180 driver.
+//!
+//! \param psInst is a pointer to the BMP180 instance data.
+//! \param psI2CInst is a pointer to the I2C master driver instance data.
+//! \param ui8I2CAddr is the I2C address of the BMP180 device.
+//! \param pfnCallback is the function to be called when the initialization has
+//! completed (can be \b NULL if a callback is not required).
+//! \param pvCallbackData is a pointer that is passed to the callback function.
+//!
+//! This function initializes the BMP180 driver, preparing it for operation.
+//!
+//! \return Returns 1 if the BMP180 driver was successfully initialized and 0
+//! if it was not.
+//
+//*****************************************************************************
+uint_fast8_t
+BMP180Init(tBMP180 *psInst, tI2CMInstance *psI2CInst, uint_fast8_t ui8I2CAddr,
+ tSensorCallback *pfnCallback, void *pvCallbackData)
+{
+ //
+ // Initialize the BMP180 instance structure.
+ //
+ psInst->psI2CInst = psI2CInst;
+ psInst->ui8Addr = ui8I2CAddr;
+ psInst->ui8State = BMP180_STATE_INIT1;
+ psInst->ui8Mode = 0;
+ psInst->ui8NewMode = 0;
+
+ //
+ // Save the callback information.
+ //
+ psInst->pfnCallback = pfnCallback;
+ psInst->pvCallbackData = pvCallbackData;
+
+ //
+ // Perform a soft reset of the BMP180.
+ //
+ psInst->pui8Data[0] = BMP180_O_SOFT_RESET;
+ psInst->pui8Data[1] = BMP180_SOFT_RESET_VALUE;
+ if(I2CMWrite(psI2CInst, ui8I2CAddr, psInst->pui8Data, 2, BMP180Callback,
+ psInst) == 0)
+ {
+ //
+ // The I2C write failed, so move to the idle state and return a
+ // failure.
+ //
+ psInst->ui8State = BMP180_STATE_IDLE;
+ return(0);
+ }
+
+ //
+ // Success.
+ //
+ return(1);
+}
+
+//*****************************************************************************
+//
+//! Reads data from BMP180 registers.
+//!
+//! \param psInst is a pointer to the BMP180 instance data.
+//! \param ui8Reg is the first register to read.
+//! \param pui8Data is a pointer to the location to store the data that is
+//! read.
+//! \param ui16Count is the number of data bytes to read.
+//! \param pfnCallback is the function to be called when the data has been read
+//! (can be \b NULL if a callback is not required).
+//! \param pvCallbackData is a pointer that is passed to the callback function.
+//!
+//! This function reads a sequence of data values from consecutive registers in
+//! the BMP180.
+//!
+//! \return Returns 1 if the write was successfully started and 0 if it was
+//! not.
+//
+//*****************************************************************************
+uint_fast8_t
+BMP180Read(tBMP180 *psInst, uint_fast8_t ui8Reg, uint8_t *pui8Data,
+ uint_fast16_t ui16Count, tSensorCallback *pfnCallback,
+ void *pvCallbackData)
+{
+ //
+ // Return a failure if the BMP180 driver is not idle (in other words, there
+ // is already an outstanding request to the BMP180).
+ //
+ if(psInst->ui8State != BMP180_STATE_IDLE)
+ {
+ return(0);
+ }
+
+ //
+ // Save the callback information.
+ //
+ psInst->pfnCallback = pfnCallback;
+ psInst->pvCallbackData = pvCallbackData;
+
+ //
+ // Move the state machine to the wait for read state.
+ //
+ psInst->ui8State = BMP180_STATE_READ;
+
+ //
+ // Read the requested registers from the BMP180.
+ //
+ psInst->uCommand.pui8Buffer[0] = ui8Reg;
+ if(I2CMRead(psInst->psI2CInst, psInst->ui8Addr,
+ psInst->uCommand.pui8Buffer, 1, pui8Data, ui16Count,
+ BMP180Callback, psInst) == 0)
+ {
+ //
+ // The I2C write failed, so move to the idle state and return a
+ // failure.
+ //
+ psInst->ui8State = BMP180_STATE_IDLE;
+ return(0);
+ }
+
+ //
+ // Success.
+ //
+ return(1);
+}
+
+//*****************************************************************************
+//
+//! Writes data to BMP180 registers.
+//!
+//! \param psInst is a pointer to the BMP180 instance data.
+//! \param ui8Reg is the first register to write.
+//! \param pui8Data is a pointer to the data to write.
+//! \param ui16Count is the number of data bytes to write.
+//! \param pfnCallback is the function to be called when the data has been
+//! written (can be \b NULL if a callback is not required).
+//! \param pvCallbackData is a pointer that is passed to the callback function.
+//!
+//! This function writes a sequence of data values to consecutive registers in
+//! the BMP180. The first byte of the \e pui8Data buffer contains the value to
+//! be written into the \e ui8Reg register, the second value contains the data
+//! to be written into the next register, and so on.
+//!
+//! \return Returns 1 if the write was successfully started and 0 if it was
+//! not.
+//
+//*****************************************************************************
+uint_fast8_t
+BMP180Write(tBMP180 *psInst, uint_fast8_t ui8Reg, uint8_t *pui8Data,
+ uint_fast16_t ui16Count, tSensorCallback *pfnCallback,
+ void *pvCallbackData)
+{
+ //
+ // Return a failure if the BMP180 driver is not idle (in other words, there
+ // is already an outstanding request to the BMP180).
+ //
+ if(psInst->ui8State != BMP180_STATE_IDLE)
+ {
+ return(0);
+ }
+
+ //
+ // Save the callback information.
+ //
+ psInst->pfnCallback = pfnCallback;
+ psInst->pvCallbackData = pvCallbackData;
+
+ //
+ // See if the CTRL_MEAS register is being written.
+ //
+ if((ui8Reg <= BMP180_O_CTRL_MEAS) &&
+ ((ui8Reg + ui16Count) > BMP180_O_CTRL_MEAS))
+ {
+ //
+ // Extract the measurement mode from the CTRL_MEAS register value.
+ //
+ psInst->ui8NewMode = (pui8Data[ui8Reg - BMP180_O_CTRL_MEAS] &
+ BMP180_CTRL_MEAS_OSS_M);
+ }
+
+ //
+ // Move the state machine to the wait for write state.
+ //
+ psInst->ui8State = BMP180_STATE_WRITE;
+
+ //
+ // Write the requested registers to the BMP180.
+ //
+ if(I2CMWrite8(&(psInst->uCommand.sWriteState), psInst->psI2CInst,
+ psInst->ui8Addr, ui8Reg, pui8Data, ui16Count, BMP180Callback,
+ psInst) == 0)
+ {
+ //
+ // The I2C write failed, so move to the idle state and return a
+ // failure.
+ //
+ psInst->ui8State = BMP180_STATE_IDLE;
+ return(0);
+ }
+
+ //
+ // Success.
+ //
+ return(1);
+}
+
+//*****************************************************************************
+//
+//! Performs a read-modify-write of a BMP180 register.
+//!
+//! \param psInst is a pointer to the BMP180 instance data.
+//! \param ui8Reg is the register to modify.
+//! \param ui8Mask is the bit mask that is ANDed with the current register
+//! value.
+//! \param ui8Value is the bit mask that is ORed with the result of the AND
+//! operation.
+//! \param pfnCallback is the function to be called when the data has been
+//! changed (can be \b NULL if a callback is not required).
+//! \param pvCallbackData is a pointer that is passed to the callback function.
+//!
+//! This function changes the value of a register in the BMP180 via a
+//! read-modify-write operation, allowing one of the fields to be changed
+//! without disturbing the other fields. The \e ui8Reg register is read, ANDed
+//! with \e ui8Mask, ORed with \e ui8Value, and then written back to the
+//! BMP180.
+//!
+//! \return Returns 1 if the read-modify-write was successfully started and 0
+//! if it was not.
+//
+//*****************************************************************************
+uint_fast8_t
+BMP180ReadModifyWrite(tBMP180 *psInst, uint_fast8_t ui8Reg,
+ uint_fast8_t ui8Mask, uint_fast8_t ui8Value,
+ tSensorCallback *pfnCallback, void *pvCallbackData)
+{
+ //
+ // Return a failure if the BMP180 driver is not idle (in other words, there
+ // is already an outstanding request to the BMP180).
+ //
+ if(psInst->ui8State != BMP180_STATE_IDLE)
+ {
+ return(0);
+ }
+
+ //
+ // Save the callback information.
+ //
+ psInst->pfnCallback = pfnCallback;
+ psInst->pvCallbackData = pvCallbackData;
+
+ //
+ // Move the state machine to the wait for read-modify-write state.
+ //
+ psInst->ui8State = BMP180_STATE_RMW;
+
+ //
+ // Submit the read-modify-write request to the BMP180.
+ //
+ if(I2CMReadModifyWrite8(&(psInst->uCommand.sReadModifyWriteState),
+ psInst->psI2CInst, psInst->ui8Addr, ui8Reg,
+ ui8Mask, ui8Value, BMP180Callback, psInst) == 0)
+ {
+ //
+ // The I2C read-modify-write failed, so move to the idle state and
+ // return a failure.
+ //
+ psInst->ui8State = BMP180_STATE_IDLE;
+ return(0);
+ }
+
+ //
+ // Success.
+ //
+ return(1);
+}
+
+//*****************************************************************************
+//
+//! Reads the pressure data from the BMP180.
+//!
+//! \param psInst is a pointer to the BMP180 instance data.
+//! \param pfnCallback is the function to be called when the data has been read
+//! (can be \b NULL if a callback is not required).
+//! \param pvCallbackData is a pointer that is passed to the callback function.
+//!
+//! This function initiates a read of the BMP180 data registers. When the
+//! read has completed (as indicated by calling the callback function), the
+//! new temperature and pressure readings can be obtained via:
+//!
+//! - BMP180DataPressureGetRaw()
+//! - BMP180DataPressureGetFloat()
+//! - BMP180DataTemperatureGetRaw()
+//! - BMP180DataTemperatureGetFloat()
+//!
+//! \return Returns 1 if the read was successfully started and 0 if it was not.
+//
+//*****************************************************************************
+uint_fast8_t
+BMP180DataRead(tBMP180 *psInst, tSensorCallback *pfnCallback,
+ void *pvCallbackData)
+{
+ //
+ // Return a failure if the BMP180 driver is not idle (in other words, there
+ // is already an outstanding request to the BMP180).
+ //
+ if(psInst->ui8State != BMP180_STATE_IDLE)
+ {
+ return(0);
+ }
+
+ //
+ // Save the callback information.
+ //
+ psInst->pfnCallback = pfnCallback;
+ psInst->pvCallbackData = pvCallbackData;
+
+ //
+ // Move the state machine to the temperature reading request state.
+ //
+ psInst->ui8State = BMP180_STATE_REQ_TEMP;
+
+ //
+ // Request the temperature reading from the BMP180.
+ //
+ psInst->uCommand.pui8Buffer[0] = BMP180_O_CTRL_MEAS;
+ psInst->uCommand.pui8Buffer[1] = (BMP180_CTRL_MEAS_SCO |
+ BMP180_CTRL_MEAS_TEMPERATURE);
+ if(I2CMWrite(psInst->psI2CInst, psInst->ui8Addr,
+ psInst->uCommand.pui8Buffer, 2, BMP180Callback, psInst) == 0)
+ {
+ //
+ // The I2C write failed, so move to the idle state and return a
+ // failure.
+ //
+ psInst->ui8State = BMP180_STATE_IDLE;
+ return(0);
+ }
+
+ //
+ // Success.
+ //
+ return(1);
+}
+
+//*****************************************************************************
+//
+//! Gets the raw pressure data from the most recent data read.
+//!
+//! \param psInst is a pointer to the BMP180 instance data.
+//! \param pui32Pressure is a pointer to the value into which the raw pressure
+//! data is stored.
+//!
+//! This function returns the raw pressure data from the most recent data read.
+//! The data is not manipulated in any way by the driver.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+BMP180DataPressureGetRaw(tBMP180 *psInst, uint_fast32_t *pui32Pressure)
+{
+ //
+ // Return the raw pressure value.
+ //
+ *pui32Pressure = ((psInst->pui8Data[2] << 16) |
+ (psInst->pui8Data[3] << 8) |
+ (psInst->pui8Data[4] & BMP180_OUT_XLSB_M));
+}
+
+//*****************************************************************************
+//
+//! Gets the pressure data from the most recent data read.
+//!
+//! \param psInst is a pointer to the BMP180 instance data.
+//! \param pfPressure is a pointer to the value into which the pressure data is
+//! stored.
+//!
+//! This function returns the pressure data from the most recent data read,
+//! converted into pascals.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+BMP180DataPressureGetFloat(tBMP180 *psInst, float *pfPressure)
+{
+ float fUT, fUP, fX1, fX2, fX3, fB3, fB4, fB5, fB6, fB7, fP;
+ int_fast8_t i8Oss;
+
+ //
+ // Get the oversampling ratio.
+ //
+ i8Oss = psInst->ui8Mode >> BMP180_CTRL_MEAS_OSS_S;
+
+ //
+ // Retrieve the uncompensated temperature and pressure.
+ //
+ fUT = (float)(uint16_t)((psInst->pui8Data[0] << 8) |
+ psInst->pui8Data[1]);
+ fUP = ((float)(int32_t)((psInst->pui8Data[2] << 16) |
+ (psInst->pui8Data[3] << 8) |
+ (psInst->pui8Data[4] & BMP180_OUT_XLSB_M)) /
+ (1 << (8 - i8Oss)));
+
+ //
+ // Calculate the true temperature.
+ //
+ fX1 = ((fUT - (float)psInst->ui16AC6) * (float)psInst->ui16AC5) / 32768.f;
+ fX2 = ((float)psInst->i16MC * 2048.f) / (fX1 + (float)psInst->i16MD);
+ fB5 = fX1 + fX2;
+
+ //
+ // Calculate the true pressure.
+ //
+ fB6 = fB5 - 4000;
+ fX1 = ((float)psInst->i16B2 * ((fB6 * fB6) / 4096)) / 2048;
+ fX2 = ((float)psInst->i16AC2 * fB6) / 2048;
+ fX3 = fX1 + fX2;
+ fB3 = ((((float)psInst->i16AC1 * 4) + fX3) * (1 << i8Oss)) / 4;
+ fX1 = ((float)psInst->i16AC3 * fB6) / 8192;
+ fX2 = ((float)psInst->i16B1 * ((fB6 * fB6) / 4096)) / 65536;
+ fX3 = (fX1 + fX2) / 4;
+ fB4 = (float)psInst->ui16AC4 * ((fX3 / 32768) + 1);
+ fB7 = (fUP - fB3) * (50000 >> i8Oss);
+ fP = (fB7 * 2) / fB4;
+ fX1 = (fP / 256) * (fP / 256);
+ fX1 = (fX1 * 3038) / 65536;
+ fX2 = (fP * -7357) / 65536;
+ fP += (fX1 + fX2 + 3791) / 16;
+ *pfPressure = fP;
+}
+
+//*****************************************************************************
+//
+//! Gets the raw temperature data from the most recent data read.
+//!
+//! \param psInst is a pointer to the BMP180 instance data.
+//! \param pui16Temperature is a pointer to the value into which the raw
+//! temperature data is stored.
+//!
+//! This function returns the raw temperature data from the most recent data
+//! read. The data is not manipulated in any way by the driver.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+BMP180DataTemperatureGetRaw(tBMP180 *psInst, uint_fast16_t *pui16Temperature)
+{
+ //
+ // Return the raw temperature value.
+ //
+ *pui16Temperature = (psInst->pui8Data[0] << 8) | psInst->pui8Data[1];
+}
+
+//*****************************************************************************
+//
+//! Gets the temperature data from the most recent data read.
+//!
+//! \param psInst is a pointer to the BMP180 instance data.
+//! \param pfTemperature is a pointer to the value into which the temperature
+//! data is stored.
+//!
+//! This function returns the temperature data from the most recent data read,
+//! converted into Celsius.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+BMP180DataTemperatureGetFloat(tBMP180 *psInst, float *pfTemperature)
+{
+ float fUT, fX1, fX2, fB5;
+
+ //
+ // Get the uncompensated temperature.
+ //
+ fUT = (float)(uint16_t)((psInst->pui8Data[0] << 8) |
+ psInst->pui8Data[1]);
+
+ //
+ // Calculate the true temperature.
+ //
+ fX1 = ((fUT - (float)psInst->ui16AC6) * (float)psInst->ui16AC5) / 32768.f;
+ fX2 = ((float)psInst->i16MC * 2048.f) / (fX1 + (float)psInst->i16MD);
+ fB5 = fX1 + fX2;
+ *pfTemperature = fB5 / 160.f;
+}
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
diff --git a/sensorlib/bmp180.h b/sensorlib/bmp180.h
new file mode 100644
index 0000000..c56b4df
--- /dev/null
+++ b/sensorlib/bmp180.h
@@ -0,0 +1,207 @@
+//*****************************************************************************
+//
+// bmp180.h - Prototypes for the BMP180 pressure sensor driver.
+//
+// Copyright (c) 2012-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
+//
+//*****************************************************************************
+
+#ifndef __SENSORLIB_BMP180_H__
+#define __SENSORLIB_BMP180_H__
+
+//*****************************************************************************
+//
+// If building with a C++ compiler, make all of the definitions in this header
+// have a C binding.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+//*****************************************************************************
+//
+// The structure that defines the internal state of the BMP180 driver.
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ // The pointer to the I2C master interface instance used to communicate
+ // with the BMP180.
+ //
+ tI2CMInstance *psI2CInst;
+
+ //
+ // The I2C address of the BMP180.
+ //
+ uint8_t ui8Addr;
+
+ //
+ // The state of the state machine used while accessing the BMP180.
+ //
+ uint8_t ui8State;
+
+ //
+ // The sampling mode to be used by the BMP180.
+ //
+ uint8_t ui8Mode;
+
+ //
+ // The new sampling mode, which is used when a register write succeeds.
+ //
+ uint8_t ui8NewMode;
+
+ //
+ // The AC1 calibration from the BMP180.
+ //
+ int16_t i16AC1;
+
+ //
+ // The AC2 calibration from the BMP180.
+ //
+ int16_t i16AC2;
+
+ //
+ // The AC3 calibration from the BMP180.
+ //
+ int16_t i16AC3;
+
+ //
+ // The AC4 calibration from the BMP180.
+ //
+ uint16_t ui16AC4;
+
+ //
+ // The AC5 calibration from the BMP180.
+ //
+ uint16_t ui16AC5;
+
+ //
+ // The AC6 calibration from the BMP180.
+ //
+ uint16_t ui16AC6;
+
+ //
+ // The B1 calibration from the BMP180.
+ //
+ int16_t i16B1;
+
+ //
+ // The B2 calibration from the BMP180.
+ //
+ int16_t i16B2;
+
+ //
+ // The MC calibration from the BMP180.
+ //
+ int16_t i16MC;
+
+ //
+ // The MD calibration from the BMP180.
+ //
+ int16_t i16MD;
+
+ //
+ // The data buffer used for sending/receiving data to/from the BMP180.
+ //
+ uint8_t pui8Data[5];
+
+ //
+ // The function that is called when the current request has completed
+ // processing.
+ //
+ tSensorCallback *pfnCallback;
+
+ //
+ // The pointer provided to the callback function.
+ //
+ void *pvCallbackData;
+
+ //
+ // A union of structures that are used for read, write and
+ // read-modify-write operations. Since only one operation can be active at
+ // a time, it is safe to re-use the memory in this manner.
+ //
+ union
+ {
+ //
+ // A buffer used to store the write portion of a register read. This
+ // is also used to read back the calibration data from the device.
+ //
+ uint8_t pui8Buffer[22];
+
+ //
+ // The write state used to write register values.
+ //
+ tI2CMWrite8 sWriteState;
+
+ //
+ // The read-modify-write state used to modify register values.
+ //
+ tI2CMReadModifyWrite8 sReadModifyWriteState;
+ }
+ uCommand;
+}
+tBMP180;
+
+//*****************************************************************************
+//
+// Function prototypes.
+//
+//*****************************************************************************
+extern uint_fast8_t BMP180Init(tBMP180 *psInst, tI2CMInstance *psI2CInst,
+ uint_fast8_t ui8I2CAddr,
+ tSensorCallback *pfnCallback,
+ void *pvCallbackData);
+extern uint_fast8_t BMP180Read(tBMP180 *psInst, uint_fast8_t ui8Reg,
+ uint8_t *pui8Data, uint_fast16_t ui16Count,
+ tSensorCallback *pfnCallback,
+ void *pvCallbackData);
+extern uint_fast8_t BMP180Write(tBMP180 *psInst, uint_fast8_t ui8Reg,
+ uint8_t *pui8Data, uint_fast16_t ui16Count,
+ tSensorCallback *pfnCallback,
+ void *pvCallbackData);
+extern uint_fast8_t BMP180ReadModifyWrite(tBMP180 *psInst, uint_fast8_t ui8Reg,
+ uint_fast8_t ui8Mask,
+ uint_fast8_t ui8Value,
+ tSensorCallback *pfnCallback,
+ void *pvCallbackData);
+extern uint_fast8_t BMP180DataRead(tBMP180 *psInst,
+ tSensorCallback *pfnCallback,
+ void *pvCallbackData);
+extern void BMP180DataPressureGetRaw(tBMP180 *psInst,
+ uint_fast32_t *pui32Pressure);
+extern void BMP180DataPressureGetFloat(tBMP180 *psInst, float *pfPressure);
+extern void BMP180DataTemperatureGetRaw(tBMP180 *psInst,
+ uint_fast16_t *pui16Temperature);
+extern void BMP180DataTemperatureGetFloat(tBMP180 *psInst,
+ float *pfTemperature);
+
+//*****************************************************************************
+//
+// Mark the end of the C bindings section for C++ compilers.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __SENSORLIB_BMP180_H__
diff --git a/sensorlib/bq27510g3.c b/sensorlib/bq27510g3.c
new file mode 100644
index 0000000..b9453b3
--- /dev/null
+++ b/sensorlib/bq27510g3.c
@@ -0,0 +1,1398 @@
+//*****************************************************************************
+//
+// bq27510g3.c - Driver for the TI BQ27510G3 Battery Fuel Gauge
+//
+// Copyright (c) 2013-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
+//
+//*****************************************************************************
+
+#include <math.h>
+#include <stdint.h>
+#include "sensorlib/hw_bq27510g3.h"
+#include "sensorlib/i2cm_drv.h"
+#include "sensorlib/bq27510g3.h"
+
+//*****************************************************************************
+//
+//! \addtogroup bq27510g3_api
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// The states of the BQ27510G3 state machine.
+//
+//*****************************************************************************
+#define BQ27510G3_STATE_IDLE 0
+#define BQ27510G3_STATE_INIT 1
+#define BQ27510G3_STATE_READ 2
+#define BQ27510G3_STATE_WRITE 3
+#define BQ27510G3_STATE_RMW 4
+#define BQ27510G3_STATE_READ_DATA_1 5
+#define BQ27510G3_STATE_READ_DATA_2 6
+#define BQ27510G3_STATE_READ_DATA_3 7
+
+//*****************************************************************************
+//
+// The constants used to calculate object temperature.
+//
+//*****************************************************************************
+#define T_REF 273
+
+//*****************************************************************************
+//
+// The callback function that is called when I2C transactions to/from the
+// BQ27510G3 have completed.
+//
+//*****************************************************************************
+static void
+BQ27510G3Callback(void *pvCallbackData, uint_fast8_t ui8Status)
+{
+ tBQ27510G3 *psInst;
+
+ //
+ // Convert the instance data into a pointer to a tBQ27510G3 structure.
+ //
+ psInst = pvCallbackData;
+
+ //
+ // If the I2C master driver encountered a failure, force the state machine
+ // to the idle state (which will also result in a callback to propagate the
+ // error).
+ //
+ if(ui8Status != I2CM_STATUS_SUCCESS)
+ {
+ psInst->ui8State = BQ27510G3_STATE_IDLE;
+ }
+
+ //
+ // Determine the current state of the BQ27510G3 state machine.
+ //
+ switch(psInst->ui8State)
+ {
+ //
+ // The first data read state, has finished setup and trigger data read
+ // state 2.
+ //
+ case BQ27510G3_STATE_READ_DATA_1:
+ {
+ //
+ // Move the state machine to the next read state.
+ //
+ psInst->ui8State = BQ27510G3_STATE_READ_DATA_2;
+
+ //
+ // Read the requested data from the BQ27510G3.
+ //
+ psInst->uCommand.pui8Buffer[0] = BQ27510G3_O_NOM_AV_CAP_LSB;
+ I2CMRead(psInst->psI2CInst, psInst->ui8Addr,
+ psInst->uCommand.pui8Buffer, 1, psInst->pui8Data + 6,
+ 24, BQ27510G3Callback, psInst);
+
+ //
+ // break
+ //
+ break;
+ }
+
+ //
+ // The 2nd data read state, has finished setup and trigger data read
+ // state 3. Read state 3 is the final state and when done will return
+ // to idle and trigger the application level callback.
+ //
+ case BQ27510G3_STATE_READ_DATA_2:
+ {
+ //
+ // Move the state machine to the next read state.
+ //
+ psInst->ui8State = BQ27510G3_STATE_READ_DATA_3;
+
+ //
+ // Read the requested data from the BQ27510G3.
+ //
+ psInst->uCommand.pui8Buffer[0] = BQ27510G3_O_INT_TEMP_LSB;
+ I2CMRead(psInst->psI2CInst, psInst->ui8Addr,
+ psInst->uCommand.pui8Buffer, 1, psInst->pui8Data + 30,
+ 2, BQ27510G3Callback, psInst);
+
+ //
+ // break
+ //
+ break;
+ }
+
+ //
+ // All states that trivially transition to IDLE, and all unknown
+ // states.
+ //
+ case BQ27510G3_STATE_INIT:
+ case BQ27510G3_STATE_READ:
+ case BQ27510G3_STATE_WRITE:
+ case BQ27510G3_STATE_READ_DATA_3:
+ case BQ27510G3_STATE_RMW:
+ default:
+ {
+ //
+ // The state machine is now idle.
+ //
+ psInst->ui8State = BQ27510G3_STATE_IDLE;
+
+ //
+ // Done.
+ //
+ break;
+ }
+ }
+
+ //
+ // See if the state machine is now idle and there is a callback function.
+ //
+ if((psInst->ui8State == BQ27510G3_STATE_IDLE) && psInst->pfnCallback)
+ {
+ //
+ // Call the application-supplied callback function.
+ //
+ psInst->pfnCallback(psInst->pvCallbackData, ui8Status);
+ }
+}
+
+//*****************************************************************************
+//
+//! Initializes the BQ27510G3 driver.
+//!
+//! \param psInst is a pointer to the BQ27510G3 instance data.
+//! \param psI2CInst is a pointer to the I2C driver instance data.
+//! \param ui8I2CAddr is the I2C address of the BQ27510G3 device.
+//! \param pfnCallback is the function to be called when the initialization has
+//! completed (can be \b NULL if a callback is not required).
+//! \param pvCallbackData is a pointer that is passed to the callback function.
+//!
+//! This function initializes the BQ27510G3 driver, preparing it for operation.
+//!
+//! \return Returns 1 if the BQ27510G3 driver was successfully initialized and
+//! 0 if it was not.
+//
+//*****************************************************************************
+uint_fast8_t
+BQ27510G3Init(tBQ27510G3 *psInst, tI2CMInstance *psI2CInst,
+ uint_fast8_t ui8I2CAddr, tSensorCallback *pfnCallback,
+ void *pvCallbackData)
+{
+ //
+ // Initialize the BQ27510G3 instance structure
+ //
+ psInst->psI2CInst = psI2CInst;
+ psInst->ui8Addr = ui8I2CAddr;
+ psInst->ui8State = BQ27510G3_STATE_IDLE;
+
+ //
+ // Save the callback information.
+ //
+ psInst->pfnCallback = pfnCallback;
+ psInst->pvCallbackData = pvCallbackData;
+
+ //
+ // The default settings are ok. Return success and call the callback.
+ //
+ if(pfnCallback)
+ {
+ pfnCallback(pvCallbackData, 0);
+ }
+
+ //
+ // Success
+ //
+ return(1);
+}
+
+//*****************************************************************************
+//
+//! Reads data from BQ27510G3 registers.
+//!
+//! \param psInst is a pointer to the BQ27510G3 instance data.
+//! \param ui8Reg is the first register to read.
+//! \param pui16Data is a pointer to the location to store the data that is
+//! read.
+//! \param ui16Count the number of register values to read.
+//! \param pfnCallback is the function to be called when data read is complete
+//! (can be \b NULL if a callback is not required).
+//! \param pvCallbackData is a pointer that is passed to the callback function.
+//!
+//! This function reads a sequence of data values from consecutive registers in
+//! the BQ27510G3.
+//!
+//! \note The BQ27510G3 does not auto-increment the register pointer, so reads
+//! of more than one value returns garbage for the subsequent values.
+//!
+//! \return Returns 1 if the write was successfully started and 0 if it was
+//! not.
+//
+//*****************************************************************************
+uint_fast8_t
+BQ27510G3Read(tBQ27510G3 *psInst, uint_fast8_t ui8Reg, uint16_t *pui16Data,
+ uint_fast16_t ui16Count, tSensorCallback *pfnCallback,
+ void *pvCallbackData)
+{
+ //
+ // Return a failure if the BQ27510G3 driver is not idle (in other words,
+ // there is already an outstanding request to the BQ27510G3).
+ //
+ if(psInst->ui8State != BQ27510G3_STATE_IDLE)
+ {
+ return(0);
+ }
+
+ //
+ // Save the callback information.
+ //
+ psInst->pfnCallback = pfnCallback;
+ psInst->pvCallbackData = pvCallbackData;
+
+ //
+ // Move the state machine to the wait for read state.
+ //
+ psInst->ui8State = BQ27510G3_STATE_READ;
+
+ //
+ // Read the requested registers from the BQ27510G3.
+ //
+ if(I2CMRead16BE(&(psInst->uCommand.sReadState), psInst->psI2CInst,
+ psInst->ui8Addr, ui8Reg, pui16Data, ui16Count,
+ BQ27510G3Callback, psInst) == 0)
+ {
+ //
+ // The I2C write failed, so move to the idle state and return a
+ // failure.
+ //
+ psInst->ui8State = BQ27510G3_STATE_IDLE;
+ return(0);
+ }
+
+ //
+ // Success.
+ //
+ return(1);
+}
+
+//*****************************************************************************
+//
+//! Writes data to BQ27510G3 registers.
+//!
+//! \param psInst is a pointer to the BQ27510G3 instance data.
+//! \param ui8Reg is the first register to write.
+//! \param pui16Data is a pointer to the 16-bit register data to write.
+//! \param ui16Count is the number of 16-bit registers to write.
+//! \param pfnCallback is the function to be called when the data has been
+//! written (can be \b NULL if a callback is not required).
+//! \param pvCallbackData is a pointer that is passed to the callback function.
+//!
+//! This function writes a sequence of data values to consecutive registers in
+//! the BQ27510G3. The first value in the \e pui16Data buffer contains the
+//! data to be written into the \e ui8Reg register, the second value contains
+//! the data to be written into the next register, and so on.
+//!
+//! \note The BQ27510G3 does not auto-increment the register pointer, so writes
+//! of more than one register are rejected by the BQ27510G3.
+//!
+//! \return Returns 1 if the write was successfully started and 0 if it was
+//! not.
+//
+//*****************************************************************************
+uint_fast8_t
+BQ27510G3Write(tBQ27510G3 *psInst, uint_fast8_t ui8Reg,
+ const uint16_t *pui16Data, uint_fast16_t ui16Count,
+ tSensorCallback *pfnCallback, void *pvCallbackData)
+{
+ //
+ // Return a failure if the BQ27510G3 driver is not idle (in other words,
+ // there is already an outstanding request to the BQ27510G3).
+ //
+ if(psInst->ui8State != BQ27510G3_STATE_IDLE)
+ {
+ return(0);
+ }
+
+ //
+ // Save the callback information.
+ //
+ psInst->pfnCallback = pfnCallback;
+ psInst->pvCallbackData = pvCallbackData;
+
+ //
+ // Move the state machine to the wait for write state.
+ //
+ psInst->ui8State = BQ27510G3_STATE_WRITE;
+
+ //
+ // Write the requested registers to the BQ27510G3.
+ //
+ if(I2CMWrite16BE(&(psInst->uCommand.sWriteState), psInst->psI2CInst,
+ psInst->ui8Addr, ui8Reg, pui16Data, ui16Count,
+ BQ27510G3Callback, psInst) == 0)
+ {
+ //
+ // The I2C write failed, so move to the idle state and return a
+ // failure.
+ //
+ psInst->ui8State = BQ27510G3_STATE_IDLE;
+ return(0);
+ }
+
+ //
+ // Success.
+ //
+ return(1);
+}
+
+//*****************************************************************************
+//
+//! Performs a read-modify-write of a BQ27510G3 register.
+//!
+//! \param psInst is a pointer to the BQ27510G3 instance data.
+//! \param ui8Reg is the register offset to read modify and write
+//! \param ui16Mask is the bit mask that is ANDed with the current register
+//! value.
+//! \param ui16Value is the bit mask that is ORed with the result of the AND
+//! operation.
+//! \param pfnCallback is the function to be called when the data has been
+//! changed (can be \b NULL if a callback is not required).
+//! \param pvCallbackData is a pointer that is passed to the callback function.
+//!
+//! This function changes the value of a register in the BQ27510G3 via a
+//! read-modify-write operation, allowing one of the fields to be changed
+//! without disturbing the other fields. The \e ui8Reg register is read, ANDed
+//! with \e ui16Mask, ORed with \e ui16Value, and then written back to the
+//! BQ27510G3.
+//!
+//! \return Returns 1 if the read-modify-write was successfully started and 0
+//! if it was not.
+//
+//*****************************************************************************
+uint_fast8_t
+BQ27510G3ReadModifyWrite(tBQ27510G3 *psInst, uint_fast8_t ui8Reg,
+ uint_fast16_t ui16Mask, uint_fast16_t ui16Value,
+ tSensorCallback *pfnCallback, void *pvCallbackData)
+{
+ //
+ // Return a failure if the BQ27510G3 driver is not idle (in other words,
+ // there is already an outstanding request to the BQ27510G3).
+ //
+ if(psInst->ui8State != BQ27510G3_STATE_IDLE)
+ {
+ return(0);
+ }
+
+ //
+ // Save the callback information.
+ //
+ psInst->pfnCallback = pfnCallback;
+ psInst->pvCallbackData = pvCallbackData;
+
+ //
+ // Move the state machine to the wait for read-modify-write state.
+ //
+ psInst->ui8State = BQ27510G3_STATE_RMW;
+
+ //
+ // Submit the read-modify-write request to the BQ27510G3.
+ //
+ if(I2CMReadModifyWrite16BE(&(psInst->uCommand.sReadModifyWriteState),
+ psInst->psI2CInst, psInst->ui8Addr, ui8Reg,
+ ui16Mask, ui16Value, BQ27510G3Callback,
+ psInst) == 0)
+ {
+ //
+ // The I2C read-modify-write failed, so move to the idle state and
+ // return a failure.
+ //
+ psInst->ui8State = BQ27510G3_STATE_IDLE;
+ return(0);
+ }
+
+ //
+ // Success.
+ //
+ return(1);
+}
+
+//*****************************************************************************
+//
+//! Performs a read of a BQ27510G3 data register.
+//!
+//! \param psInst is a pointer to the BQ27510G3 instance data.
+//! \param pfnCallback is the function to be called when the data has been read
+//! (can be \b NULL if a callback is not required).
+//! \param pvCallbackData is a pointer that is passed to the callback function.
+//!
+//! This function initiates a read of the BQ27510G3 data registers. When the
+//! read has completed (as indicated by calling the callback function), the new
+//! readings can be obtained via functions like:
+//!
+//! - BQ27510G3DataTCurrentInstantaneousGetRaw()
+//! - BQ27510G3DataTCurrentInstantaneousGetFloat()
+//!
+//! \return Returns 1 if the read was successfully started and 0 if it was not.
+//
+//*****************************************************************************
+uint_fast8_t
+BQ27510G3DataRead(tBQ27510G3 *psInst, tSensorCallback *pfnCallback,
+ void *pvCallbackData)
+{
+ //
+ // Return a failure if the BQ27510G3 driver is not idle (in other words,
+ // there is already an outstanding request to the BQ27510G3).
+ //
+ if(psInst->ui8State != BQ27510G3_STATE_IDLE)
+ {
+ return(0);
+ }
+
+ //
+ // Save the callback information.
+ //
+ psInst->pfnCallback = pfnCallback;
+ psInst->pvCallbackData = pvCallbackData;
+
+ //
+ // Move the state machine to the first read state. Reads are done in three
+ // parts based on address ranges of the information being read.
+ //
+ psInst->ui8State = BQ27510G3_STATE_READ_DATA_1;
+
+ //
+ // Read the requested data from the BQ27510G3.
+ //
+ psInst->uCommand.pui8Buffer[0] = BQ27510G3_O_AT_RATE_TTE_LSB;
+ if(I2CMRead(psInst->psI2CInst, psInst->ui8Addr,
+ psInst->uCommand.pui8Buffer, 1, psInst->pui8Data, 6,
+ BQ27510G3Callback, psInst) == 0)
+ {
+ //
+ // The I2C read failed, so move to the idle state and return a failure.
+ //
+ psInst->ui8State = BQ27510G3_STATE_IDLE;
+ return(0);
+ }
+
+ //
+ // Success.
+ //
+ return(1);
+}
+
+//*****************************************************************************
+//
+//! Gets the raw "at rate time to empty" data.
+//!
+//! \param psInst is a pointer to the BQ27510G3 instance data.
+//! \param pi16Data is a pointer to the value into which the raw data is
+//! stored.
+//!
+//! This function returns the raw measurement data from the most recent data
+//! read. The data is not manipulated in any way by the driver.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+BQ27510G3DataAtRateTimeToEmptyGetRaw(tBQ27510G3 *psInst, int16_t *pi16Data)
+{
+ //
+ // Return the raw data value.
+ //
+ *pi16Data = ((int16_t)psInst->pui8Data[1] << 8) | psInst->pui8Data[0];
+}
+
+//*****************************************************************************
+//
+//! Gets the "at rate time to empty" data as a floating point value.
+//!
+//! \param psInst is a pointer to the BQ27510G3 instance data.
+//! \param pfData is a pointer to the value into which the data is stored as
+//! floating point.
+//!
+//! This function returns the data from the most recent data read,
+//! converted into float value. Units are minutes.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+BQ27510G3DataAtRateTimeToEmptyGetFloat(tBQ27510G3 *psInst, float *pfData)
+{
+ int16_t i16Data;
+
+ //
+ // Get the raw readings.
+ //
+ BQ27510G3DataAtRateTimeToEmptyGetRaw(psInst, &i16Data);
+
+ //
+ // Covert to float.
+ //
+ *pfData = (float)(i16Data);
+
+}
+
+//*****************************************************************************
+//
+//! Gets the raw battery temperature from the most recent data read.
+//!
+//! \param psInst is a pointer to the BQ27510G3 instance data.
+//! \param pi16Data is a pointer to the value into which the raw data is
+//! stored.
+//!
+//! This function returns the raw measurement data from the most recent data
+//! read. The data is not manipulated in any way by the driver.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+BQ27510G3DataTemperatureBatteryGetRaw(tBQ27510G3 *psInst, int16_t *pi16Data)
+{
+ //
+ // Return the raw data value.
+ //
+ *pi16Data = ((int16_t)psInst->pui8Data[3] << 8) | psInst->pui8Data[2];
+}
+
+//*****************************************************************************
+//
+//! Gets the battery temperature measurement data from the most recent data
+//! read.
+//!
+//! \param psInst is a pointer to the BQ27510G3 instance data.
+//! \param pfData is a pointer to the value into which the data is stored as
+//! floating point.
+//!
+//! This function returns the data from the most recent data read,
+//! converted into float value. Units are degrees Celsius.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+BQ27510G3DataTemperatureBatteryGetFloat(tBQ27510G3 *psInst, float *pfData)
+{
+ int16_t i16Data;
+
+ //
+ // Get the raw readings.
+ //
+ BQ27510G3DataTemperatureBatteryGetRaw(psInst, &i16Data);
+
+ //
+ // Device returns the units as 0.1 degrees K. Convert first to whole
+ // degrees then from K to C
+ //
+ *pfData = (float)(i16Data);
+ *pfData = *pfData / 10.0f;
+ *pfData -= 272.15f;
+
+
+}
+
+//*****************************************************************************
+//
+//! Gets the raw battery voltage measurement data from the most recent data
+//! read.
+//!
+//! \param psInst is a pointer to the BQ27510G3 instance data.
+//! \param pi16Data is a pointer to the value into which the raw data is
+//! stored.
+//!
+//! This function returns the raw measurement data from the most recent data
+//! read. The data is not manipulated in any way by the driver.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+BQ27510G3DataVoltageBatteryGetRaw(tBQ27510G3 *psInst, int16_t *pi16Data)
+{
+ //
+ // Return the raw data value.
+ //
+ *pi16Data = ((int16_t)psInst->pui8Data[5] << 8) | psInst->pui8Data[4];
+}
+
+//*****************************************************************************
+//
+//! Gets the battery voltage measurement from the most recent data read.
+//!
+//! \param psInst is a pointer to the BQ27510G3 instance data.
+//! \param pfData is a pointer to the value into which the data is stored as
+//! floating point.
+//!
+//! This function returns the data from the most recent data read,
+//! converted into float value. Units are volts.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+BQ27510G3DataVoltageBatteryGetFloat(tBQ27510G3 *psInst, float *pfData)
+{
+ int16_t i16Data;
+
+ //
+ // Get the raw readings.
+ //
+ BQ27510G3DataVoltageBatteryGetRaw(psInst, &i16Data);
+
+ //
+ // Covert to float.
+ //
+ *pfData = (float)(i16Data);
+ *pfData = *pfData / 1000.0f;
+
+}
+
+//*****************************************************************************
+//
+//! Gets the raw nominal available capacity measurement from the most recent
+//! data read.
+//!
+//! \param psInst is a pointer to the BQ27510G3 instance data.
+//! \param pi16Data is a pointer to the value into which the raw data is
+//! stored.
+//!
+//! This function returns the raw measurement data from the most recent data
+//! read. The data is not manipulated in any way by the driver.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+BQ27510G3DataCapacityNominalAvailableGetRaw(tBQ27510G3 *psInst,
+ int16_t *pi16Data)
+{
+ //
+ // Return the raw data value.
+ //
+ *pi16Data = ((int16_t)psInst->pui8Data[7] << 8) | psInst->pui8Data[6];
+}
+
+//*****************************************************************************
+//
+//! Gets the measurement data from the most recent data read.
+//!
+//! \param psInst is a pointer to the BQ27510G3 instance data.
+//! \param pfData is a pointer to the value into which the data is stored as
+//! floating point.
+//!
+//! This function returns the data from the most recent data read,
+//! converted into float value. Units are amp-hours (Ah).
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+BQ27510G3DataCapacityNominalAvailableGetFloat(tBQ27510G3 *psInst, float *pfData)
+{
+ int16_t i16Data;
+
+ //
+ // Get the raw readings.
+ //
+ BQ27510G3DataCapacityNominalAvailableGetRaw(psInst, &i16Data);
+
+ //
+ // Covert to float.
+ //
+ *pfData = (float)(i16Data);
+ *pfData = *pfData / 1000.0f;
+
+}
+
+//*****************************************************************************
+//
+//! Gets the raw available capacity of a new battery from the most recent data
+//! read.
+//!
+//! \param psInst is a pointer to the BQ27510G3 instance data.
+//! \param pi16Data is a pointer to the value into which the raw data is
+//! stored.
+//!
+//! This function returns the raw measurement data from the most recent data
+//! read. The data is not manipulated in any way by the driver.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+BQ27510G3DataCapacityFullAvailableGetRaw(tBQ27510G3 *psInst, int16_t *pi16Data)
+{
+ //
+ // Return the raw data value.
+ //
+ *pi16Data = ((int16_t)psInst->pui8Data[9] << 8) | psInst->pui8Data[8];
+}
+
+//*****************************************************************************
+//
+//! Gets the measurement data from the most recent data read.
+//!
+//! \param psInst is a pointer to the BQ27510G3 instance data.
+//! \param pfData is a pointer to the value into which the data is stored as
+//! floating point.
+//!
+//! This function returns the data from the most recent data read,
+//! converted into float value. Units are amp-hours (Ah).
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+BQ27510G3DataCapacityFullAvailableGetFloat(tBQ27510G3 *psInst, float *pfData)
+{
+ int16_t i16Data;
+
+ //
+ // Get the raw readings.
+ //
+ BQ27510G3DataCapacityFullAvailableGetRaw(psInst, &i16Data);
+
+ //
+ // Covert to float.
+ //
+ *pfData = (float)(i16Data);
+ *pfData = *pfData / 1000.0f;
+
+}
+
+//*****************************************************************************
+//
+//! Gets the raw remaining capacity of measurement from the most recent data
+//! read.
+//!
+//! \param psInst is a pointer to the BQ27510G3 instance data.
+//! \param pi16Data is a pointer to the value into which the raw data is
+//! stored.
+//!
+//! This function returns the raw measurement data from the most recent data
+//! read. The data is not manipulated in any way by the driver.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+BQ27510G3DataCapacityRemainingGetRaw(tBQ27510G3 *psInst, int16_t *pi16Data)
+{
+ //
+ // Return the raw data value.
+ //
+ *pi16Data = ((int16_t)psInst->pui8Data[11] << 8) | psInst->pui8Data[10];
+}
+
+//*****************************************************************************
+//
+//! Gets the measurement data from the most recent data read.
+//!
+//! \param psInst is a pointer to the BQ27510G3 instance data.
+//! \param pfData is a pointer to the value into which the data is stored as
+//! floating point.
+//!
+//! This function returns the data from the most recent data read,
+//! converted into float value. Units are amp-hours (Ah).
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+BQ27510G3DataCapacityRemainingGetFloat(tBQ27510G3 *psInst, float *pfData)
+{
+ int16_t i16Data;
+
+ //
+ // Get the raw readings.
+ //
+ BQ27510G3DataCapacityRemainingGetRaw(psInst, &i16Data);
+
+ //
+ // Covert to float.
+ //
+ *pfData = (float)(i16Data);
+ *pfData = *pfData / 1000.0f;
+
+}
+
+//*****************************************************************************
+//
+//! Gets the raw full charge capacity from the most recent data
+//! read.
+//!
+//! \param psInst is a pointer to the BQ27510G3 instance data.
+//! \param pi16Data is a pointer to the value into which the raw data is
+//! stored.
+//!
+//! This function returns the raw measurement data from the most recent data
+//! read. The data is not manipulated in any way by the driver.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+BQ27510G3DataCapacityFullChargeGetRaw(tBQ27510G3 *psInst, int16_t *pi16Data)
+{
+ //
+ // Return the raw data value.
+ //
+ *pi16Data = ((int16_t)psInst->pui8Data[13] << 8) | psInst->pui8Data[12];
+}
+
+//*****************************************************************************
+//
+//! Gets the measurement data from the most recent data read.
+//!
+//! \param psInst is a pointer to the BQ27510G3 instance data.
+//! \param pfData is a pointer to the value into which the data is stored as
+//! floating point.
+//!
+//! This function returns the data from the most recent data read,
+//! converted into float value. Units are amp-hours (Ah).
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+BQ27510G3DataCapacityFullChargeGetFloat(tBQ27510G3 *psInst, float *pfData)
+{
+ int16_t i16Data;
+
+ //
+ // Get the raw readings.
+ //
+ BQ27510G3DataCapacityFullChargeGetRaw(psInst, &i16Data);
+
+ //
+ // Covert to float.
+ //
+ *pfData = (float)(i16Data);
+ *pfData = *pfData / 1000.0f;
+
+}
+
+
+//*****************************************************************************
+//
+//! Gets the raw average current measurement from the most recent data
+//! read.
+//!
+//! \param psInst is a pointer to the BQ27510G3 instance data.
+//! \param pi16Data is a pointer to the value into which the raw data is
+//! stored.
+//!
+//! This function returns the raw measurement data from the most recent data
+//! read. The data is not manipulated in any way by the driver.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+BQ27510G3DataCurrentAverageGetRaw(tBQ27510G3 *psInst, int16_t *pi16Data)
+{
+ //
+ // Return the raw data value.
+ //
+ *pi16Data = ((int16_t)psInst->pui8Data[15] << 8) | psInst->pui8Data[14];
+}
+
+//*****************************************************************************
+//
+//! Gets the measurement data from the most recent data read.
+//!
+//! \param psInst is a pointer to the BQ27510G3 instance data.
+//! \param pfData is a pointer to the value into which the data is stored as
+//! floating point.
+//!
+//! This function returns the data from the most recent data read,
+//! converted into float value. Units are amps.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+BQ27510G3DataCurrentAverageGetFloat(tBQ27510G3 *psInst, float *pfData)
+{
+ int16_t i16Data;
+
+ //
+ // Get the raw readings.
+ //
+ BQ27510G3DataCurrentAverageGetRaw(psInst, &i16Data);
+
+ //
+ // Covert to float.
+ //
+ *pfData = (float)(i16Data);
+ *pfData = *pfData / 1000.0f;
+
+}
+
+
+//*****************************************************************************
+//
+//! Gets the raw time to empty estimate from the most recent data
+//! read.
+//!
+//! \param psInst is a pointer to the BQ27510G3 instance data.
+//! \param pi16Data is a pointer to the value into which the raw data is
+//! stored.
+//!
+//! This function returns the raw measurement data from the most recent data
+//! read. The data is not manipulated in any way by the driver.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+BQ27510G3DataTimeToEmptyGetRaw(tBQ27510G3 *psInst, int16_t *pi16Data)
+{
+ //
+ // Return the raw data value.
+ //
+ *pi16Data = ((int16_t)psInst->pui8Data[17] << 8) | psInst->pui8Data[16];
+}
+
+//*****************************************************************************
+//
+//! Gets the measurement data from the most recent data read.
+//!
+//! \param psInst is a pointer to the BQ27510G3 instance data.
+//! \param pfData is a pointer to the value into which the data is stored as
+//! floating point.
+//!
+//! This function returns the data from the most recent data read,
+//! converted into float value. Units are minutes. Value of 65,535 indicates
+//! battery is not being discharged.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+BQ27510G3DataTimeToEmptyGetFloat(tBQ27510G3 *psInst, float *pfData)
+{
+ int16_t i16Data;
+
+ //
+ // Get the raw readings.
+ //
+ BQ27510G3DataTimeToEmptyGetRaw(psInst, &i16Data);
+
+ //
+ // Covert to float.
+ //
+ *pfData = (float)(i16Data);
+
+}
+
+//*****************************************************************************
+//
+//! Gets the raw standby current from the most recent data read.
+//!
+//! \param psInst is a pointer to the BQ27510G3 instance data.
+//! \param pi16Data is a pointer to the value into which the raw data is
+//! stored.
+//!
+//! This function returns the raw measurement data from the most recent data
+//! read. The data is not manipulated in any way by the driver.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+BQ27510G3DataCurrentStandbyGetRaw(tBQ27510G3 *psInst, int16_t *pi16Data)
+{
+ //
+ // Return the raw data value.
+ //
+ *pi16Data = ((int16_t)psInst->pui8Data[19] << 8) | psInst->pui8Data[18];
+}
+
+//*****************************************************************************
+//
+//! Gets the measurement data from the most recent data read.
+//!
+//! \param psInst is a pointer to the BQ27510G3 instance data.
+//! \param pfData is a pointer to the value into which the data is stored as
+//! floating point.
+//!
+//! This function returns the data from the most recent data read,
+//! converted into float value. Units are amps.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+BQ27510G3DataCurrentStandbyGetFloat(tBQ27510G3 *psInst, float *pfData)
+{
+ int16_t i16Data;
+
+ //
+ // Get the raw readings.
+ //
+ BQ27510G3DataCurrentStandbyGetRaw(psInst, &i16Data);
+
+ //
+ // Covert to float.
+ //
+ *pfData = (float)(i16Data);
+ *pfData = *pfData / 1000.0f;
+
+}
+
+//*****************************************************************************
+//
+//! Gets the raw standby time to empty data from the most recent data
+//! read.
+//!
+//! \param psInst is a pointer to the BQ27510G3 instance data.
+//! \param pi16Data is a pointer to the value into which the raw data is
+//! stored.
+//!
+//! This function returns the raw measurement data from the most recent data
+//! read. The data is not manipulated in any way by the driver.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+BQ27510G3DataTimeToEmptyStandbyGetRaw(tBQ27510G3 *psInst, int16_t *pi16Data)
+{
+ //
+ // Return the raw data value.
+ //
+ *pi16Data = ((int16_t)psInst->pui8Data[21] << 8) | psInst->pui8Data[20];
+}
+
+//*****************************************************************************
+//
+//! Gets the measurement data from the most recent data read.
+//!
+//! \param psInst is a pointer to the BQ27510G3 instance data.
+//! \param pfData is a pointer to the value into which the data is stored as
+//! floating point.
+//!
+//! This function returns the data from the most recent data read,
+//! converted into float value. Units are minutes.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+BQ27510G3DataTimeToEmptyStandbyGetFloat(tBQ27510G3 *psInst, float *pfData)
+{
+ int16_t i16Data;
+
+ //
+ // Get the raw readings.
+ //
+ BQ27510G3DataTimeToEmptyStandbyGetRaw(psInst, &i16Data);
+
+ //
+ // Covert to float.
+ //
+ *pfData = (float)(i16Data);
+
+}
+
+//*****************************************************************************
+//
+//! Gets the raw cycle count data from the most recent data read.
+//!
+//! \param psInst is a pointer to the BQ27510G3 instance data.
+//! \param pi16Data is a pointer to the value into which the raw data is
+//! stored.
+//!
+//! This function returns the raw measurement data from the most recent data
+//! read. The data is not manipulated in any way by the driver.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+BQ27510G3DataCycleCountGetRaw(tBQ27510G3 *psInst, int16_t *pi16Data)
+{
+ //
+ // Return the raw data value.
+ //
+ *pi16Data = ((int16_t)psInst->pui8Data[25] << 8) | psInst->pui8Data[24];
+}
+
+//*****************************************************************************
+//
+//! Gets the measurement data from the most recent data read.
+//!
+//! \param psInst is a pointer to the BQ27510G3 instance data.
+//! \param pfData is a pointer to the value into which the data is stored as
+//! floating point.
+//!
+//! This function returns the data from the most recent data read, converted
+//! into float value. This data does not have units.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+BQ27510G3DataCycleCountGetFloat(tBQ27510G3 *psInst, float *pfData)
+{
+ int16_t i16Data;
+
+ //
+ // Get the raw readings.
+ //
+ BQ27510G3DataCycleCountGetRaw(psInst, &i16Data);
+
+ //
+ // Covert to float.
+ //
+ *pfData = (float)(i16Data);
+
+}
+
+//*****************************************************************************
+//
+//! Gets the raw health data from the most recent data read.
+//!
+//! \param psInst is a pointer to the BQ27510G3 instance data.
+//! \param pi16Data is a pointer to the value into which the raw data is
+//! stored.
+//!
+//! This function returns the raw measurement data from the most recent data
+//! read. The data is not manipulated in any way by the driver.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+BQ27510G3DataHealthGetRaw(tBQ27510G3 *psInst, int16_t *pi16Data)
+{
+ //
+ // Return the raw data value.
+ //
+ *pi16Data = ((int16_t)psInst->pui8Data[23] << 8) | psInst->pui8Data[22];
+}
+
+//*****************************************************************************
+//
+//! Gets the health data from the most recent health data read.
+//!
+//! \param psInst is a pointer to the BQ27510G3 instance data.
+//! \param pfHealth is a pointer to the value into which the battery
+//! health data is stored as floating point ratio of current/design capacity.
+//!
+//! This function returns the health data from the most recent data read,
+//! converted into percent health. The health status bits are dropped. These
+//! can be obtained with BQ27510G3DataHealthGetRaw function.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+BQ27510G3DataHealthGetFloat(tBQ27510G3 *psInst, float *pfHealth)
+{
+ int16_t i16Health;
+
+ //
+ // Get the raw readings.
+ //
+ BQ27510G3DataHealthGetRaw(psInst, &i16Health);
+
+ //
+ // Mask off health bit field
+ //
+ *pfHealth = (float)(i16Health & 0xFF);
+
+}
+
+//*****************************************************************************
+//
+//! Gets the raw charge state data from the most recent data read.
+//!
+//! \param psInst is a pointer to the BQ27510G3 instance data.
+//! \param pi16Data is a pointer to the value into which the raw data is
+//! stored.
+//!
+//! This function returns the raw measurement data from the most recent data
+//! read. The data is not manipulated in any way by the driver.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+BQ27510G3DataChargeStateGetRaw(tBQ27510G3 *psInst, int16_t *pi16Data)
+{
+ //
+ // Return the raw data value.
+ //
+ *pi16Data = ((int16_t)psInst->pui8Data[27] << 8) | psInst->pui8Data[26];
+}
+
+//*****************************************************************************
+//
+//! Gets the charge state from the most recent data read.
+//!
+//! \param psInst is a pointer to the BQ27510G3 instance data.
+//! \param pfData is a pointer to the value into which the data is stored as
+//! floating point.
+//!
+//! This function returns the charge state from the most recent data read,
+//! converted into percent charged.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+BQ27510G3DataChargeStateGetFloat(tBQ27510G3 *psInst, float *pfData)
+{
+ int16_t i16Data;
+
+ //
+ // Get the raw readings.
+ //
+ BQ27510G3DataChargeStateGetRaw(psInst, &i16Data);
+
+ //
+ // Convert to floating point.
+ //
+ *pfData = (float)(i16Data);
+
+}
+
+//*****************************************************************************
+//
+//! Gets the instantaneous current data from the most recent data read.
+//!
+//! \param psInst is a pointer to the BQ27510G3 instance data.
+//! \param pi16Data is a pointer to the value into which the raw data is
+//! stored.
+//!
+//! This function returns the raw measurement data from the most recent data
+//! read. The data is not manipulated in any way by the driver.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+BQ27510G3DataCurrentInstantaneousGetRaw(tBQ27510G3 *psInst, int16_t *pi16Data)
+{
+ //
+ // Return the raw data value.
+ //
+ *pi16Data = ((int16_t)psInst->pui8Data[29] << 8) | psInst->pui8Data[28];
+}
+
+//*****************************************************************************
+//
+//! Gets the instantaneous current data from the most recent data read.
+//!
+//! \param psInst is a pointer to the BQ27510G3 instance data.
+//! \param pfData is a pointer to the value into which the data is stored as
+//! floating point.
+//!
+//! This function returns the current measurement from the most recent data
+//! read, converted into floating point amps.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+BQ27510G3DataCurrentInstantaneousGetFloat(tBQ27510G3 *psInst, float *pfData)
+{
+ int16_t i16Data;
+
+ //
+ // Get the raw readings.
+ //
+ BQ27510G3DataCurrentInstantaneousGetRaw(psInst, &i16Data);
+
+ //
+ // Convert to floating point.
+ //
+ *pfData = (float)(i16Data);
+ *pfData /= 1000.0f;
+
+}
+
+//*****************************************************************************
+//
+//! Gets the raw internal temparature data from the most recent data read.
+//!
+//! \param psInst is a pointer to the BQ27510G3 instance data.
+//! \param pi16Data is a pointer to the value into which the raw data is
+//! stored.
+//!
+//! This function returns the raw measurement data from the most recent data
+//! read. The data is not manipulated in any way by the driver.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+BQ27510G3DataTemperatureInternalGetRaw(tBQ27510G3 *psInst, int16_t *pi16Data)
+{
+ //
+ // Return the raw data value.
+ //
+ *pi16Data = ((int16_t)psInst->pui8Data[31] << 8) | psInst->pui8Data[30];
+}
+
+//*****************************************************************************
+//
+//! Gets the internal temperature data from the most recent data read.
+//!
+//! \param psInst is a pointer to the BQ27510G3 instance data.
+//! \param pfData is a pointer to the value into which the data is stored as
+//! floating point.
+//!
+//! This function returns the internal temperature from the most recent data
+//! read.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+BQ27510G3DataTemperatureInternalGetFloat(tBQ27510G3 *psInst, float *pfData)
+{
+ int16_t i16Data;
+
+ //
+ // Get the raw readings.
+ //
+ BQ27510G3DataTemperatureInternalGetRaw(psInst, &i16Data);
+
+ //
+ // Convert to floating point Kelvin, then Celsius.
+ //
+ *pfData = (float)(i16Data);
+ *pfData = *pfData / 10.0f;
+ *pfData -= 272.15f;
+
+
+
+}
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
diff --git a/sensorlib/bq27510g3.h b/sensorlib/bq27510g3.h
new file mode 100644
index 0000000..928da94
--- /dev/null
+++ b/sensorlib/bq27510g3.h
@@ -0,0 +1,210 @@
+//*****************************************************************************
+//
+// bq27510g3.c - Prototypes for the TI BQ27510G3 Battery Fuel Guage
+// driver.
+//
+// Copyright (c) 2013-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
+//
+//*****************************************************************************
+
+#ifndef __SENSORLIB_BQ27510G3_H__
+#define __SENSORLIB_BQ27510G3_H__
+
+//*****************************************************************************
+//
+// If building with a C++ compiler, make all of the definitions in this header
+// have a C binding.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+//*****************************************************************************
+//
+// The structure that defines the internal state of the BQ27510G3 driver.
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ // The pointer to the I2C master interface instance used to communicate
+ // with the BQ27510G3.
+ //
+ tI2CMInstance *psI2CInst;
+
+ //
+ // The I2C address of the BQ27510G3.
+ //
+ uint8_t ui8Addr;
+
+ //
+ // The state of the state machine used while accessing the BQ27510G3.
+ //
+ uint8_t ui8State;
+
+ //
+ // The data buffer used for sending/receiving data to/from the BQ27510G3.
+ //
+ uint8_t pui8Data[32];
+
+ //
+ // The function that is called when the current request has completed
+ // processing.
+ //
+ tSensorCallback *pfnCallback;
+
+ //
+ // The pointer provided to the callback function.
+ //
+ void *pvCallbackData;
+
+ //
+ // A union of structures that are used for read, write and
+ // read-modify-write operations. Since only one operation can be active at
+ // a time, it is safe to re-use the memory in this manner.
+ //
+ union
+ {
+ //
+ // A buffer used to store the write portion of a register read.
+ //
+ uint8_t pui8Buffer[4];
+
+ //
+ // The read state used to read register values.
+ //
+ tI2CMRead16BE sReadState;
+
+ //
+ // The write state used to write register values.
+ //
+ tI2CMWrite16BE sWriteState;
+
+ //
+ // The read-modify-write state used to modify register values.
+ //
+ tI2CMReadModifyWrite16 sReadModifyWriteState;
+ }
+ uCommand;
+}
+tBQ27510G3;
+
+//*****************************************************************************
+//
+// Function prototypes.
+//
+//*****************************************************************************
+extern uint_fast8_t BQ27510G3Init(tBQ27510G3 *psInst, tI2CMInstance *psI2CInst,
+ uint_fast8_t ui8I2CAddr,
+ tSensorCallback *pfnCallback,
+ void *pvCallbackData);
+extern uint_fast8_t BQ27510G3Read(tBQ27510G3 *psInst, uint_fast8_t ui8Reg,
+ uint16_t *pui16Data, uint_fast16_t ui16Count,
+ tSensorCallback *pfnCallback,
+ void *pvCallbackData);
+extern uint_fast8_t BQ27510G3Write(tBQ27510G3 *psInst, uint_fast8_t ui8Reg,
+ const uint16_t *pui16Data,
+ uint_fast16_t ui16Count,
+ tSensorCallback *pfnCallback,
+ void *pvCallbackData);
+extern uint_fast8_t BQ27510G3ReadModifyWrite(tBQ27510G3 *psInst,
+ uint_fast8_t ui8Reg,
+ uint_fast16_t ui16Mask,
+ uint_fast16_t ui16Value,
+ tSensorCallback *pfnCallback,
+ void *pvCallbackData);
+extern uint_fast8_t BQ27510G3DataRead(tBQ27510G3 *psInst,
+ tSensorCallback *pfnCallback,
+ void *pvCallbackData);
+
+extern void BQ27510G3DataAtRateTimeToEmptyGetRaw(tBQ27510G3 *psInst,
+ int16_t *pui16Data);
+extern void BQ27510G3DataAtRateTimeToEmptyGetFloat(tBQ27510G3 *psInst,
+ float *pfData);
+extern void BQ27510G3DataTemperatureBatteryGetRaw(tBQ27510G3 *psInst,
+ int16_t *pui16Data);
+extern void BQ27510G3DataTemperatureBatteryGetFloat(tBQ27510G3 *psInst,
+ float *pfData);
+extern void BQ27510G3DataVoltageBatteryGetRaw(tBQ27510G3 *psInst,
+ int16_t *pui16Data);
+extern void BQ27510G3DataVoltageBatteryGetFloat(tBQ27510G3 *psInst,
+ float *pfData);
+extern void BQ27510G3DataCapacityNominalAvailableGetRaw(tBQ27510G3 *psInst,
+ int16_t *pui16Data);
+extern void BQ27510G3DataCapacityNominalAvailalbeGetFloat(tBQ27510G3 *psInst,
+ float *pfData);
+extern void BQ27510G3DataCapacityFullAvailableGetRaw(tBQ27510G3 *psInst,
+ int16_t *pui16Data);
+extern void BQ27510G3DataCapacityFullAvailableGetFloat(tBQ27510G3 *psInst,
+ float *pfData);
+extern void BQ27510G3DataCapacityRemainingGetRaw(tBQ27510G3 *psInst,
+ int16_t *pui16Data);
+extern void BQ27510G3DataCapacityRemainingGetFloat(tBQ27510G3 *psInst,
+ float *pfData);
+extern void BQ27510G3DataCapacityFullChargeGetRaw(tBQ27510G3 *psInst,
+ int16_t *pui16Data);
+extern void BQ27510G3DataCapacityFullChargeGetFloat(tBQ27510G3 *psInst,
+ float *pfData);
+extern void BQ27510G3DataCurrentAverageGetRaw(tBQ27510G3 *psInst,
+ int16_t *pui16Data);
+extern void BQ27510G3DataCurrentAverageGetFloat(tBQ27510G3 *psInst,
+ float *pfData);
+extern void BQ27510G3DataTimeToEmptyGetRaw(tBQ27510G3 *psInst,
+ int16_t *pui16Data);
+extern void BQ27510G3DataTimeToEmptyGetFloat(tBQ27510G3 *psInst,
+ float *pfData);
+extern void BQ27510G3DataCurrentStandbyGetRaw(tBQ27510G3 *psInst,
+ int16_t *pui16Data);
+extern void BQ27510G3DataCurrentStandbyGetFloat(tBQ27510G3 *psInst,
+ float *pfData);
+extern void BQ27510G3DataTimeToEmptyStandbyGetRaw(tBQ27510G3 *psInst,
+ int16_t *pui16Data);
+extern void BQ27510G3DataTimeToEmptyStandbyGetFloat(tBQ27510G3 *psInst,
+ float *pfData);
+extern void BQ27510G3DataCycleCountGetRaw(tBQ27510G3 *psInst,
+ int16_t *pui16Data);
+extern void BQ27510G3DataCycleCountGetFloat(tBQ27510G3 *psInst, float *pfData);
+extern void BQ27510G3DataHealthGetRaw(tBQ27510G3 *psInst, int16_t *pui16Data);
+extern void BQ27510G3DataHealthGetFloat(tBQ27510G3 *psInst, float *pfData);
+extern void BQ27510G3DataChargeStateGetRaw(tBQ27510G3 *psInst,
+ int16_t *pui16Data);
+extern void BQ27510G3DataChargeStateGetFloat(tBQ27510G3 *psInst,
+ float *pfData);
+extern void BQ27510G3DataCurrentInstantaneousGetRaw(tBQ27510G3 *psInst,
+ int16_t *pui16Data);
+extern void BQ27510G3DataCurrentInstantaneousGetFloat(tBQ27510G3 *psInst,
+ float *pfData);
+extern void BQ27510G3DataTemperatureInternalGetRaw(tBQ27510G3 *psInst,
+ int16_t *pui16Data);
+extern void BQ27510G3DataTemperatureInternalGetFloat(tBQ27510G3 *psInst,
+ float *pfData);
+
+//*****************************************************************************
+//
+// Mark the end of the C bindings section for C++ compilers.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __SENSORLIB_BQ27510G3_H__
+
diff --git a/sensorlib/ccs/.ccsproject b/sensorlib/ccs/.ccsproject
new file mode 100644
index 0000000..b4eaafa
--- /dev/null
+++ b/sensorlib/ccs/.ccsproject
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<?ccsproject version="1.0"?>
+<projectOptions>
+ <deviceVariant value="Cortex M.TM4C1230C3PM"/>
+ <deviceFamily value="TMS470"/>
+ <deviceEndianness value="little"/>
+ <codegenToolVersion value="5.0.4"/>
+ <isElfFormat value="true"/>
+</projectOptions>
diff --git a/sensorlib/ccs/.cproject b/sensorlib/ccs/.cproject
new file mode 100644
index 0000000..10acdbf
--- /dev/null
+++ b/sensorlib/ccs/.cproject
@@ -0,0 +1,147 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<?fileVersion 4.0.0?>
+
+<cproject storage_type_id="org.eclipse.cdt.core.XmlProjectDescriptionStorage">
+ <storageModule configRelations="2" moduleId="org.eclipse.cdt.core.settings">
+ <cconfiguration id="com.ti.ccstudio.buildDefinitions.TMS470.Debug.20798163">
+ <storageModule buildSystemId="org.eclipse.cdt.managedbuilder.core.configurationDataProvider" id="com.ti.ccstudio.buildDefinitions.TMS470.Debug.20798163" moduleId="org.eclipse.cdt.core.settings" name="Debug">
+ <macros>
+ <stringMacro name="SW_ROOT" type="VALUE_PATH_DIR" value="${PROJECT_ROOT}/../.."/>
+ </macros>
+ <externalSettings/>
+ <extensions>
+ <extension id="com.ti.ccstudio.binaryparser.CoffParser" point="org.eclipse.cdt.core.BinaryParser"/>
+ <extension id="com.ti.ccstudio.errorparser.CoffErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
+ <extension id="com.ti.ccstudio.errorparser.LinkErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
+ <extension id="com.ti.ccstudio.errorparser.AsmErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
+ </extensions>
+ </storageModule>
+ <storageModule moduleId="cdtBuildSystem" version="4.0.0">
+ <configuration artifactExtension="lib" artifactName="${ProjName}" buildProperties="" cleanCommand="${CG_CLEAN_CMD}" description="" id="com.ti.ccstudio.buildDefinitions.TMS470.Debug.20798163" name="Debug" parent="com.ti.ccstudio.buildDefinitions.TMS470.Debug">
+ <folderInfo id="com.ti.ccstudio.buildDefinitions.TMS470.Debug.20798163." name="/" resourcePath="">
+ <toolChain id="com.ti.ccstudio.buildDefinitions.TMS470_5.0.libraryDebugToolchain.1583161084" name="TI Build Tools" superClass="com.ti.ccstudio.buildDefinitions.TMS470_5.0.libraryDebugToolchain" targetTool="com.ti.ccstudio.buildDefinitions.TMS470_5.0.library.librarianDebug.624051952">
+ <option id="com.ti.ccstudio.buildDefinitions.core.OPT_TAGS.1302413647" superClass="com.ti.ccstudio.buildDefinitions.core.OPT_TAGS" valueType="stringList">
+ <listOptionValue builtIn="false" value="DEVICE_CONFIGURATION_ID=Cortex M.TM4C1230C3PM"/>
+ <listOptionValue builtIn="false" value="DEVICE_ENDIANNESS=little"/>
+ <listOptionValue builtIn="false" value="OUTPUT_FORMAT=ELF"/>
+ <listOptionValue builtIn="false" value="CCS_MBS_VERSION=5.1.0.01"/>
+ <listOptionValue builtIn="false" value="OUTPUT_TYPE=staticLibrary"/>
+ </option>
+ <option id="com.ti.ccstudio.buildDefinitions.core.OPT_CODEGEN_VERSION.298639692" superClass="com.ti.ccstudio.buildDefinitions.core.OPT_CODEGEN_VERSION" value="5.0.4" valueType="string"/>
+ <targetPlatform id="com.ti.ccstudio.buildDefinitions.TMS470_5.0.library.targetPlatformDebug.367896764" name="Platform" superClass="com.ti.ccstudio.buildDefinitions.TMS470_5.0.library.targetPlatformDebug"/>
+ <builder buildPath="${BuildDirectory}" id="com.ti.ccstudio.buildDefinitions.TMS470_5.0.library.builderDebug.1545349647" name="GNU Make.Debug" superClass="com.ti.ccstudio.buildDefinitions.TMS470_5.0.library.builderDebug"/>
+ <tool id="com.ti.ccstudio.buildDefinitions.TMS470_5.0.library.compilerDebug.1190414836" name="ARM Compiler" superClass="com.ti.ccstudio.buildDefinitions.TMS470_5.0.library.compilerDebug">
+ <option id="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compilerID.SILICON_VERSION.1976576711" superClass="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compilerID.SILICON_VERSION" value="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compilerID.SILICON_VERSION.7M4" valueType="enumerated"/>
+ <option id="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compilerID.CODE_STATE.1809370431" superClass="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compilerID.CODE_STATE" value="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compilerID.CODE_STATE.16" valueType="enumerated"/>
+ <option id="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compilerID.ABI.1323823706" superClass="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compilerID.ABI" value="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compilerID.ABI.eabi" valueType="enumerated"/>
+ <option id="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compilerID.FLOAT_SUPPORT.314310918" superClass="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compilerID.FLOAT_SUPPORT" value="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compilerID.FLOAT_SUPPORT.FPv4SPD16" valueType="enumerated"/>
+ <option id="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compilerID.DEBUGGING_MODEL.1564303441" superClass="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compilerID.DEBUGGING_MODEL" value="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compilerID.DEBUGGING_MODEL.SYMDEBUG__DWARF" valueType="enumerated"/>
+ <option id="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compilerID.DIAG_WARNING.1640770023" superClass="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compilerID.DIAG_WARNING" valueType="stringList">
+ <listOptionValue builtIn="false" value="225"/>
+ </option>
+ <option id="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compilerID.DISPLAY_ERROR_NUMBER.1528006369" superClass="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compilerID.DISPLAY_ERROR_NUMBER" value="true" valueType="boolean"/>
+ <option id="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compilerID.DIAG_WRAP.989036988" superClass="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compilerID.DIAG_WRAP" value="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compilerID.DIAG_WRAP.off" valueType="enumerated"/>
+ <option id="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compilerID.INCLUDE_PATH.1393096055" superClass="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compilerID.INCLUDE_PATH" valueType="includePath">
+ <listOptionValue builtIn="false" value="&quot;${CG_TOOL_ROOT}/include&quot;"/>
+ <listOptionValue builtIn="false" value="&quot;${SW_ROOT}&quot;"/>
+ </option>
+ <option id="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compilerID.LITTLE_ENDIAN.1025879328" superClass="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compilerID.LITTLE_ENDIAN" value="true" valueType="boolean"/>
+ <option id="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compilerID.GEN_FUNC_SUBSECTIONS.634502098" superClass="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compilerID.GEN_FUNC_SUBSECTIONS" value="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compilerID.GEN_FUNC_SUBSECTIONS.on" valueType="enumerated"/>
+ <option id="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compilerID.OPT_LEVEL.896160998" superClass="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compilerID.OPT_LEVEL" value="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compilerID.OPT_LEVEL.2" valueType="enumerated"/>
+ <option id="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compilerID.GCC.1653793740" superClass="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compilerID.GCC" value="true" valueType="boolean"/>
+ <option id="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compilerID.UAL.531288458" superClass="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compilerID.UAL" value="true" valueType="boolean"/>
+ <option id="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compilerID.DEFINE.915288487" superClass="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compilerID.DEFINE" valueType="definedSymbols">
+ <listOptionValue builtIn="false" value="ccs=&quot;ccs&quot;"/>
+ </option>
+ <inputType id="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compiler.inputType__C_SRCS.1957406136" name="C Sources" superClass="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compiler.inputType__C_SRCS"/>
+ <inputType id="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compiler.inputType__CPP_SRCS.2078906287" name="C++ Sources" superClass="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compiler.inputType__CPP_SRCS"/>
+ <inputType id="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compiler.inputType__ASM_SRCS.1259429713" name="Assembly Sources" superClass="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compiler.inputType__ASM_SRCS"/>
+ <inputType id="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compiler.inputType__ASM2_SRCS.1619339108" name="Assembly Sources" superClass="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compiler.inputType__ASM2_SRCS"/>
+ </tool>
+ <tool id="com.ti.ccstudio.buildDefinitions.TMS470_5.0.library.librarianDebug.624051952" name="ARM Archiver" superClass="com.ti.ccstudio.buildDefinitions.TMS470_5.0.library.librarianDebug">
+ <option id="com.ti.ccstudio.buildDefinitions.TMS470_5.0.archiverID.OUTPUT_FILE.1445718960" superClass="com.ti.ccstudio.buildDefinitions.TMS470_5.0.archiverID.OUTPUT_FILE" value="&quot;${ProjName}.lib&quot;" valueType="string"/>
+ </tool>
+ </toolChain>
+ </folderInfo>
+ </configuration>
+ </storageModule>
+ <storageModule moduleId="org.eclipse.cdt.core.externalSettings"/>
+ </cconfiguration>
+ <cconfiguration id="com.ti.ccstudio.buildDefinitions.TMS470.Release.1321180849">
+ <storageModule buildSystemId="org.eclipse.cdt.managedbuilder.core.configurationDataProvider" id="com.ti.ccstudio.buildDefinitions.TMS470.Release.1321180849" moduleId="org.eclipse.cdt.core.settings" name="Release">
+ <macros>
+ <stringMacro name="SW_ROOT" type="VALUE_PATH_DIR" value="${PROJECT_ROOT}/../.."/>
+ </macros>
+ <externalSettings/>
+ <extensions>
+ <extension id="com.ti.ccstudio.binaryparser.CoffParser" point="org.eclipse.cdt.core.BinaryParser"/>
+ <extension id="com.ti.ccstudio.errorparser.CoffErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
+ <extension id="com.ti.ccstudio.errorparser.LinkErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
+ <extension id="com.ti.ccstudio.errorparser.AsmErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
+ </extensions>
+ </storageModule>
+ <storageModule moduleId="cdtBuildSystem" version="4.0.0">
+ <configuration artifactExtension="lib" artifactName="${ProjName}" buildProperties="" cleanCommand="${CG_CLEAN_CMD}" description="" id="com.ti.ccstudio.buildDefinitions.TMS470.Release.1321180849" name="Release" parent="com.ti.ccstudio.buildDefinitions.TMS470.Release">
+ <folderInfo id="com.ti.ccstudio.buildDefinitions.TMS470.Release.1321180849." name="/" resourcePath="">
+ <toolChain id="com.ti.ccstudio.buildDefinitions.TMS470_5.0.library.ReleaseToolchain.1905987288" name="TI Build Tools" superClass="com.ti.ccstudio.buildDefinitions.TMS470_5.0.library.ReleaseToolchain" targetTool="com.ti.ccstudio.buildDefinitions.TMS470_5.0.library.librarianRelease.680964683">
+ <option id="com.ti.ccstudio.buildDefinitions.core.OPT_TAGS.217154684" superClass="com.ti.ccstudio.buildDefinitions.core.OPT_TAGS" valueType="stringList">
+ <listOptionValue builtIn="false" value="DEVICE_CONFIGURATION_ID=Cortex M.TM4C1230C3PM"/>
+ <listOptionValue builtIn="false" value="DEVICE_ENDIANNESS=little"/>
+ <listOptionValue builtIn="false" value="OUTPUT_FORMAT=ELF"/>
+ <listOptionValue builtIn="false" value="CCS_MBS_VERSION=5.1.0.01"/>
+ <listOptionValue builtIn="false" value="OUTPUT_TYPE=staticLibrary"/>
+ </option>
+ <option id="com.ti.ccstudio.buildDefinitions.core.OPT_CODEGEN_VERSION.1983422785" superClass="com.ti.ccstudio.buildDefinitions.core.OPT_CODEGEN_VERSION" value="5.0.4" valueType="string"/>
+ <targetPlatform id="com.ti.ccstudio.buildDefinitions.TMS470_5.0.library.targetPlatformRelease.891055822" name="Platform" superClass="com.ti.ccstudio.buildDefinitions.TMS470_5.0.library.targetPlatformRelease"/>
+ <builder buildPath="${BuildDirectory}" id="com.ti.ccstudio.buildDefinitions.TMS470_5.0.library.builderRelease.1928903911" name="GNU Make.Release" superClass="com.ti.ccstudio.buildDefinitions.TMS470_5.0.library.builderRelease"/>
+ <tool id="com.ti.ccstudio.buildDefinitions.TMS470_5.0.library.compilerRelease.1258115376" name="ARM Compiler" superClass="com.ti.ccstudio.buildDefinitions.TMS470_5.0.library.compilerRelease">
+ <option id="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compilerID.SILICON_VERSION.390501534" superClass="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compilerID.SILICON_VERSION" value="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compilerID.SILICON_VERSION.7M4" valueType="enumerated"/>
+ <option id="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compilerID.CODE_STATE.1425349915" superClass="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compilerID.CODE_STATE" value="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compilerID.CODE_STATE.16" valueType="enumerated"/>
+ <option id="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compilerID.ABI.2087744685" superClass="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compilerID.ABI" value="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compilerID.ABI.eabi" valueType="enumerated"/>
+ <option id="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compilerID.FLOAT_SUPPORT.917798771" superClass="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compilerID.FLOAT_SUPPORT" value="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compilerID.FLOAT_SUPPORT.FPv4SPD16" valueType="enumerated"/>
+ <option id="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compilerID.DIAG_WARNING.122667932" superClass="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compilerID.DIAG_WARNING" valueType="stringList">
+ <listOptionValue builtIn="false" value="225"/>
+ </option>
+ <option id="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compilerID.DISPLAY_ERROR_NUMBER.1996927083" superClass="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compilerID.DISPLAY_ERROR_NUMBER" value="true" valueType="boolean"/>
+ <option id="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compilerID.DIAG_WRAP.1819529191" superClass="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compilerID.DIAG_WRAP" value="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compilerID.DIAG_WRAP.off" valueType="enumerated"/>
+ <option id="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compilerID.INCLUDE_PATH.2064778685" superClass="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compilerID.INCLUDE_PATH" valueType="includePath">
+ <listOptionValue builtIn="false" value="&quot;${CG_TOOL_ROOT}/include&quot;"/>
+ <listOptionValue builtIn="false" value="&quot;${SW_ROOT}&quot;"/>
+ </option>
+ <option id="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compilerID.LITTLE_ENDIAN.412050452" superClass="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compilerID.LITTLE_ENDIAN" value="true" valueType="boolean"/>
+ <option id="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compilerID.GEN_FUNC_SUBSECTIONS.1185189428" superClass="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compilerID.GEN_FUNC_SUBSECTIONS" value="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compilerID.GEN_FUNC_SUBSECTIONS.on" valueType="enumerated"/>
+ <option id="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compilerID.GCC.89395542" superClass="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compilerID.GCC" value="true" valueType="boolean"/>
+ <option id="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compilerID.UAL.1244023322" superClass="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compilerID.UAL" value="true" valueType="boolean"/>
+ <option id="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compilerID.DEFINE.493563444" superClass="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compilerID.DEFINE" valueType="definedSymbols">
+ <listOptionValue builtIn="false" value="ccs=&quot;ccs&quot;"/>
+ </option>
+ <inputType id="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compiler.inputType__C_SRCS.404442260" name="C Sources" superClass="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compiler.inputType__C_SRCS"/>
+ <inputType id="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compiler.inputType__CPP_SRCS.1334731655" name="C++ Sources" superClass="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compiler.inputType__CPP_SRCS"/>
+ <inputType id="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compiler.inputType__ASM_SRCS.360970955" name="Assembly Sources" superClass="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compiler.inputType__ASM_SRCS"/>
+ <inputType id="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compiler.inputType__ASM2_SRCS.1419155761" name="Assembly Sources" superClass="com.ti.ccstudio.buildDefinitions.TMS470_5.0.compiler.inputType__ASM2_SRCS"/>
+ </tool>
+ <tool id="com.ti.ccstudio.buildDefinitions.TMS470_5.0.library.librarianRelease.680964683" name="ARM Archiver" superClass="com.ti.ccstudio.buildDefinitions.TMS470_5.0.library.librarianRelease">
+ <option id="com.ti.ccstudio.buildDefinitions.TMS470_5.0.archiverID.OUTPUT_FILE.1181599114" superClass="com.ti.ccstudio.buildDefinitions.TMS470_5.0.archiverID.OUTPUT_FILE" value="&quot;${ProjName}.lib&quot;" valueType="string"/>
+ </tool>
+ </toolChain>
+ </folderInfo>
+ </configuration>
+ </storageModule>
+ <storageModule moduleId="org.eclipse.cdt.core.externalSettings"/>
+ </cconfiguration>
+ </storageModule>
+ <storageModule moduleId="org.eclipse.cdt.core.LanguageSettingsProviders"/>
+ <storageModule moduleId="cdtBuildSystem" version="4.0.0">
+ <project id="sensorlib.com.ti.ccstudio.buildDefinitions.TMS470.ProjectType.2137497005" name="ARM" projectType="com.ti.ccstudio.buildDefinitions.TMS470.ProjectType"/>
+ </storageModule>
+ <storageModule moduleId="scannerConfiguration"/>
+ <storageModule moduleId="org.eclipse.cdt.core.language.mapping">
+ <project-mappings>
+ <content-type-mapping configuration="" content-type="org.eclipse.cdt.core.asmSource" language="com.ti.ccstudio.core.TIASMLanguage"/>
+ <content-type-mapping configuration="" content-type="org.eclipse.cdt.core.cHeader" language="com.ti.ccstudio.core.TIGCCLanguage"/>
+ <content-type-mapping configuration="" content-type="org.eclipse.cdt.core.cSource" language="com.ti.ccstudio.core.TIGCCLanguage"/>
+ <content-type-mapping configuration="" content-type="org.eclipse.cdt.core.cxxHeader" language="com.ti.ccstudio.core.TIGPPLanguage"/>
+ <content-type-mapping configuration="" content-type="org.eclipse.cdt.core.cxxSource" language="com.ti.ccstudio.core.TIGPPLanguage"/>
+ </project-mappings>
+ </storageModule>
+</cproject>
diff --git a/sensorlib/ccs/.project b/sensorlib/ccs/.project
new file mode 100644
index 0000000..250724d
--- /dev/null
+++ b/sensorlib/ccs/.project
@@ -0,0 +1,140 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>sensorlib</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.cdt.managedbuilder.core.genmakebuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder</name>
+ <triggers>full,incremental,</triggers>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>com.ti.ccstudio.core.ccsNature</nature>
+ <nature>org.eclipse.cdt.core.cnature</nature>
+ <nature>org.eclipse.cdt.managedbuilder.core.managedBuildNature</nature>
+ <nature>org.eclipse.cdt.core.ccnature</nature>
+ <nature>org.eclipse.cdt.managedbuilder.core.ScannerConfigNature</nature>
+ </natures>
+ <linkedResources>
+ <link>
+ <name>ak8963.c</name>
+ <type>1</type>
+ <locationURI>SW_ROOT/sensorlib/ak8963.c</locationURI>
+ </link>
+ <link>
+ <name>ak8975.c</name>
+ <type>1</type>
+ <locationURI>SW_ROOT/sensorlib/ak8975.c</locationURI>
+ </link>
+ <link>
+ <name>bmp180.c</name>
+ <type>1</type>
+ <locationURI>SW_ROOT/sensorlib/bmp180.c</locationURI>
+ </link>
+ <link>
+ <name>bq27510g3.c</name>
+ <type>1</type>
+ <locationURI>SW_ROOT/sensorlib/bq27510g3.c</locationURI>
+ </link>
+ <link>
+ <name>cm3218.c</name>
+ <type>1</type>
+ <locationURI>SW_ROOT/sensorlib/cm3218.c</locationURI>
+ </link>
+ <link>
+ <name>comp_dcm.c</name>
+ <type>1</type>
+ <locationURI>SW_ROOT/sensorlib/comp_dcm.c</locationURI>
+ </link>
+ <link>
+ <name>i2cm_drv.c</name>
+ <type>1</type>
+ <locationURI>SW_ROOT/sensorlib/i2cm_drv.c</locationURI>
+ </link>
+ <link>
+ <name>isl29023.c</name>
+ <type>1</type>
+ <locationURI>SW_ROOT/sensorlib/isl29023.c</locationURI>
+ </link>
+ <link>
+ <name>kxti9.c</name>
+ <type>1</type>
+ <locationURI>SW_ROOT/sensorlib/kxti9.c</locationURI>
+ </link>
+ <link>
+ <name>l3gd20h.c</name>
+ <type>1</type>
+ <locationURI>SW_ROOT/sensorlib/l3gd20h.c</locationURI>
+ </link>
+ <link>
+ <name>lsm303d.c</name>
+ <type>1</type>
+ <locationURI>SW_ROOT/sensorlib/lsm303d.c</locationURI>
+ </link>
+ <link>
+ <name>lsm303dlhc_accel.c</name>
+ <type>1</type>
+ <locationURI>SW_ROOT/sensorlib/lsm303dlhc_accel.c</locationURI>
+ </link>
+ <link>
+ <name>lsm303dlhc_mag.c</name>
+ <type>1</type>
+ <locationURI>SW_ROOT/sensorlib/lsm303dlhc_mag.c</locationURI>
+ </link>
+ <link>
+ <name>magneto.c</name>
+ <type>1</type>
+ <locationURI>SW_ROOT/sensorlib/magneto.c</locationURI>
+ </link>
+ <link>
+ <name>mpu6050.c</name>
+ <type>1</type>
+ <locationURI>SW_ROOT/sensorlib/mpu6050.c</locationURI>
+ </link>
+ <link>
+ <name>mpu9150.c</name>
+ <type>1</type>
+ <locationURI>SW_ROOT/sensorlib/mpu9150.c</locationURI>
+ </link>
+ <link>
+ <name>quaternion.c</name>
+ <type>1</type>
+ <locationURI>SW_ROOT/sensorlib/quaternion.c</locationURI>
+ </link>
+ <link>
+ <name>sht21.c</name>
+ <type>1</type>
+ <locationURI>SW_ROOT/sensorlib/sht21.c</locationURI>
+ </link>
+ <link>
+ <name>tmp006.c</name>
+ <type>1</type>
+ <locationURI>SW_ROOT/sensorlib/tmp006.c</locationURI>
+ </link>
+ <link>
+ <name>tmp100.c</name>
+ <type>1</type>
+ <locationURI>SW_ROOT/sensorlib/tmp100.c</locationURI>
+ </link>
+ <link>
+ <name>vector.c</name>
+ <type>1</type>
+ <locationURI>SW_ROOT/sensorlib/vector.c</locationURI>
+ </link>
+ </linkedResources>
+ <variableList>
+ <variable>
+ <name>SW_ROOT</name>
+ <value>$%7BPARENT-2-PROJECT_LOC%7D</value>
+ </variable>
+ </variableList>
+</projectDescription>
diff --git a/sensorlib/ccs/.settings/org.eclipse.cdt.codan.core.prefs b/sensorlib/ccs/.settings/org.eclipse.cdt.codan.core.prefs
new file mode 100644
index 0000000..98b6350
--- /dev/null
+++ b/sensorlib/ccs/.settings/org.eclipse.cdt.codan.core.prefs
@@ -0,0 +1,3 @@
+eclipse.preferences.version=1
+inEditor=false
+onBuild=false
diff --git a/sensorlib/ccs/Debug/sensorlib.lib b/sensorlib/ccs/Debug/sensorlib.lib
new file mode 100644
index 0000000..953d9c6
--- /dev/null
+++ b/sensorlib/ccs/Debug/sensorlib.lib
Binary files differ
diff --git a/sensorlib/ccs/macros.ini_initial b/sensorlib/ccs/macros.ini_initial
new file mode 100644
index 0000000..08b716d
--- /dev/null
+++ b/sensorlib/ccs/macros.ini_initial
@@ -0,0 +1 @@
+SW_ROOT = ../..
diff --git a/sensorlib/cm3218.c b/sensorlib/cm3218.c
new file mode 100644
index 0000000..bb2251f
--- /dev/null
+++ b/sensorlib/cm3218.c
@@ -0,0 +1,468 @@
+//*****************************************************************************
+//
+// cm3218.c - Driver for the CM3218 light sensor
+//
+// Copyright (c) 2013-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
+//
+//*****************************************************************************
+
+#include <math.h>
+#include <stdint.h>
+#include "sensorlib/hw_cm3218.h"
+#include "sensorlib/i2cm_drv.h"
+#include "sensorlib/cm3218.h"
+
+//*****************************************************************************
+//
+//! \addtogroup cm3218_api
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// The states of the CM3218 state machine.
+//
+//*****************************************************************************
+#define CM3218_STATE_IDLE 0
+#define CM3218_STATE_INIT 1
+#define CM3218_STATE_READ 2
+#define CM3218_STATE_WRITE 3
+
+//*****************************************************************************
+//
+// Sensitivity setting to floating point range value lookup table.
+//
+//*****************************************************************************
+const float g_pfSensitivityLookup[4] =
+{
+ 0.02857,
+ 0.01328,
+ 0.00714,
+ 0.003571
+};
+
+//*****************************************************************************
+//
+// The callback function that is called when I2C transations to/from the CM3218
+// have completed.
+//
+//*****************************************************************************
+static void
+CM3218Callback(void *pvCallbackData, uint_fast8_t ui8Status)
+{
+ tCM3218 *psInst;
+
+ //
+ // Convert the instance data into a pointer to a tCM3218 structure.
+ //
+ psInst = pvCallbackData;
+
+ //
+ // If the I2C master driver encountered a failure, force the state machine
+ // to the idle state (which will also result in a callback to propagate the
+ // error).
+ //
+ if(ui8Status != I2CM_STATUS_SUCCESS)
+ {
+ psInst->ui8State = CM3218_STATE_IDLE;
+ }
+
+ //
+ // Determine the current state of the CM3218 state machine.
+ //
+ switch(psInst->ui8State)
+ {
+ //
+ // All states that trivially transition to IDLE, and all unknown
+ // states.
+ //
+ case CM3218_STATE_INIT:
+ case CM3218_STATE_READ:
+ default:
+ {
+ //
+ // The state machine is now idle.
+ //
+ psInst->ui8State = CM3218_STATE_IDLE;
+ break;
+ }
+
+ //
+ // A write has just completed.
+ //
+ case CM3218_STATE_WRITE:
+ {
+ //
+ // Set the integration time to the new integration time. If the
+ // register was not modified, the values will be the same so this
+ // has no effect.
+ //
+ psInst->ui8IntTime = psInst->ui8NewIntTime;
+
+ //
+ // The state machine is now idle.
+ //
+ psInst->ui8State = CM3218_STATE_IDLE;
+
+ //
+ // Done.
+ //
+ break;
+ }
+ }
+
+ //
+ // See if the state machine is now idle and there is a callback function.
+ //
+ if((psInst->ui8State == CM3218_STATE_IDLE) && psInst->pfnCallback)
+ {
+ //
+ // Call the application-supplied callback function.
+ //
+ psInst->pfnCallback(psInst->pvCallbackData, ui8Status);
+ }
+}
+
+//*****************************************************************************
+//
+//! Initializes the CM3218 driver.
+//!
+//! \param psInst is a pointer to the CM3218 instance data.
+//! \param psI2CInst is a pointer to the I2C driver instance data.
+//! \param ui8I2CAddr is the I2C address of the CM3218 device.
+//! \param pfnCallback is the function to be called when the initialization has
+//! completed (can be \b NULL if a callback is not required).
+//! \param pvCallbackData is a pointer that is passed to the callback function.
+//!
+//! This function initializes the CM3218 driver, preparing it for operation.
+//!
+//! \return Returns 1 if the CM3218 driver was successfully initialized and 0
+//! if it was not.
+//
+//*****************************************************************************
+uint_fast8_t
+CM3218Init(tCM3218 *psInst, tI2CMInstance *psI2CInst, uint_fast8_t ui8I2CAddr,
+ tSensorCallback *pfnCallback, void *pvCallbackData)
+{
+ //
+ // Initialize the CM3218 instance structure
+ //
+ psInst->psI2CInst = psI2CInst;
+ psInst->ui8Addr = ui8I2CAddr;
+ psInst->ui8State = CM3218_STATE_IDLE;
+ psInst->ui8IntTime = CM3218_CMD_CONFIG_IT_10 >> CM3218_CMD_CONFIG_IT_S;
+ psInst->ui8NewIntTime = CM3218_CMD_CONFIG_IT_10 >> CM3218_CMD_CONFIG_IT_S;
+
+ //
+ // The default settings are ok. Call the callback function if provided.
+ //
+ if(pfnCallback)
+ {
+ pfnCallback(pvCallbackData, 0);
+ }
+
+ //
+ // Success
+ //
+ return(1);
+}
+
+//*****************************************************************************
+//
+//! Reads data from CM3218 registers.
+//!
+//! \param psInst is a pointer to the CM3218 instance data.
+//! \param ui8Reg is the first register to read.
+//! \param pui16Data is a pointer to the location to store the data that is
+//! read.
+//! \param ui16Count the number of register values bytes to read.
+//! \param pfnCallback is the function to be called when data read is complete
+//! (can be \b NULL if a callback is not required).
+//! \param pvCallbackData is a pointer that is passed to the callback function.
+//!
+//! This function reads a sequence of data values from consecutive registers in
+//! the CM3218.
+//!
+//! \note The CM3218 does not auto-increment the register pointer, so reads of
+//! more than one value returns the same data.
+//!
+//! \return Returns 1 if the write was successfully started and 0 if it was
+//! not.
+//
+//*****************************************************************************
+uint_fast8_t
+CM3218Read(tCM3218 *psInst, uint_fast8_t ui8Reg, uint16_t *pui16Data,
+ uint_fast16_t ui16Count, tSensorCallback *pfnCallback,
+ void *pvCallbackData)
+{
+ //
+ // Return a failure if the CM3218 driver is not idle (in other words, there
+ // is already an outstanding request to the CM3218).
+ //
+ if(psInst->ui8State != CM3218_STATE_IDLE)
+ {
+ return(0);
+ }
+
+ //
+ // Save the callback information.
+ //
+ psInst->pfnCallback = pfnCallback;
+ psInst->pvCallbackData = pvCallbackData;
+
+ //
+ // Move the state machine to the wait for read state.
+ //
+ psInst->ui8State = CM3218_STATE_READ;
+
+ //
+ // Read the requested registers from the CM3218.
+ //
+ if(I2CMRead16BE(&(psInst->uCommand.sReadState), psInst->psI2CInst,
+ psInst->ui8Addr, ui8Reg, pui16Data, ui16Count,
+ CM3218Callback, psInst) == 0)
+ {
+ //
+ // The I2C write failed, so move to the idle state and return a
+ // failure.
+ //
+ psInst->ui8State = CM3218_STATE_IDLE;
+ return(0);
+ }
+
+ //
+ // Success.
+ //
+ return(1);
+}
+
+//*****************************************************************************
+//
+//! Writes data to CM3218 registers.
+//!
+//! \param psInst is a pointer to the CM3218 instance data.
+//! \param ui8Reg is the first register to write.
+//! \param pui16Data is a pointer to the 16-bit register data to write.
+//! \param ui16Count is the number of data bytes to write.
+//! \param pfnCallback is the function to be called when the data has been
+//! written (can be \b NULL if a callback is not required).
+//! \param pvCallbackData is a pointer that is passed to the callback function.
+//!
+//! This function writes a sequence of data values to consecutive registers in
+//! the CM3218. The first value in the \e pui16Data buffer contains the data
+//! to be written into the \e ui8Reg register, the second value contains the
+//! data to be written into the next register, and so on.
+//!
+//! \note The CM3218 does not auto-increment the register pointer, so writes of
+//! more than one register are rejected by the CM3218.
+//!
+//! \return Returns 1 if the write was successfully started and 0 if it was
+//! not.
+//
+//*****************************************************************************
+uint_fast8_t
+CM3218Write(tCM3218 *psInst, uint_fast8_t ui8Reg, const uint16_t *pui16Data,
+ uint_fast16_t ui16Count, tSensorCallback *pfnCallback,
+ void *pvCallbackData)
+{
+ //
+ // Return a failure if the CM3218 driver is not idle (in other words, there
+ // is already an outstanding request to the CM3218).
+ //
+ if(psInst->ui8State != CM3218_STATE_IDLE)
+ {
+ return(0);
+ }
+
+ //
+ // Save the callback information.
+ //
+ psInst->pfnCallback = pfnCallback;
+ psInst->pvCallbackData = pvCallbackData;
+
+ //
+ // See if the CMD_CONFIG register is being written.
+ //
+ if((ui8Reg <= CM3218_CMD_CONFIG) &&
+ ((ui8Reg + ui16Count) > CM3218_CMD_CONFIG))
+ {
+ //
+ // Extract the integration time from the CMD_CONFIG register value.
+ //
+ psInst->ui8NewIntTime = ((pui16Data[ui8Reg - CM3218_CMD_CONFIG] &
+ CM3218_CMD_CONFIG_IT_M) >>
+ CM3218_CMD_CONFIG_IT_S);
+ }
+
+ //
+ // Move the state machine to the wait for write state.
+ //
+ psInst->ui8State = CM3218_STATE_WRITE;
+
+ //
+ // Write the requested registers to the CM3218.
+ //
+ if(I2CMWrite16BE(&(psInst->uCommand.sWriteState), psInst->psI2CInst,
+ psInst->ui8Addr, ui8Reg, pui16Data, ui16Count,
+ CM3218Callback, psInst) == 0)
+ {
+ //
+ // The I2C write failed, so move to the idle state and return a
+ // failure.
+ //
+ psInst->ui8State = CM3218_STATE_IDLE;
+ return(0);
+ }
+
+ //
+ // Success.
+ //
+ return(1);
+}
+
+//*****************************************************************************
+//
+//! Reads the light data from the CM3218.
+//!
+//! \param psInst is a pointer to the CM3218 instance data.
+//! \param pfnCallback is the function to be called when the data has been read
+//! (can be \b NULL if a callback is not required).
+//! \param pvCallbackData is a pointer that is passed to the callback function.
+//!
+//! This function initiates a read of the CM3218 data registers. When the read
+//! has completed (as indicated by calling the callback function), the new
+//! readings can be obtained via:
+//!
+//! - CM3218DataLightVisibleGetRaw()
+//! - CM3218DataLightVisibleGetFloat()
+//!
+//! \return Returns 1 if the read was successfully started and 0 if it was not.
+//
+//*****************************************************************************
+uint_fast8_t
+CM3218DataRead(tCM3218 *psInst, tSensorCallback *pfnCallback,
+ void *pvCallbackData)
+{
+ //
+ // Return a failure if the CM3218 driver is not idle (in other words, there
+ // is already an outstanding request to the CM3218).
+ //
+ if(psInst->ui8State != CM3218_STATE_IDLE)
+ {
+ return(0);
+ }
+
+ //
+ // Save the callback information.
+ //
+ psInst->pfnCallback = pfnCallback;
+ psInst->pvCallbackData = pvCallbackData;
+
+ //
+ // Move the state machine to the wait for data read
+ //
+ psInst->ui8State = CM3218_STATE_READ;
+
+ //
+ // Read the ambient light data from the CM3218.
+ //
+ psInst->uCommand.pui8Buffer[0] = CM3218_CMD_ALS_DATA;
+ if(I2CMRead(psInst->psI2CInst, psInst->ui8Addr,
+ psInst->uCommand.pui8Buffer, 1, psInst->pui8Data, 2,
+ CM3218Callback, psInst) == 0)
+ {
+ //
+ // The I2C read failed, so move to the idle state and return a failure.
+ //
+ psInst->ui8State = CM3218_STATE_IDLE;
+ return(0);
+ }
+
+ //
+ // Success.
+ //
+ return(1);
+}
+
+//*****************************************************************************
+//
+//! Gets the raw measurement data from the most recent data read.
+//!
+//! \param psInst is a pointer to the CM3218 instance data.
+//! \param pui16Visible is a pointer to the value into which the raw visible
+//! light data is stored.
+//!
+//! This function returns the raw measurement data from the most recent data
+//! read. The data is not manipulated in any way by the driver.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+CM3218DataLightVisibleGetRaw(tCM3218 *psInst, uint16_t *pui16Visible)
+{
+ //
+ // Return the raw Light value.
+ //
+ *pui16Visible = (psInst->pui8Data[1] << 8) | psInst->pui8Data[0];
+}
+
+//*****************************************************************************
+//
+//! Gets the measurement data from the most recent data read.
+//!
+//! \param psInst is a pointer to the CM3218 instance data.
+//! \param pfVisibleLight is a pointer to the value into which the light
+//! data is stored as floating point lux.
+//!
+//! This function returns the light data from the most recent data read,
+//! converted into lux.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+CM3218DataLightVisibleGetFloat(tCM3218 *psInst, float *pfVisibleLight)
+{
+ uint16_t ui16Light;
+ float fSensitivity;
+
+ //
+ // Get the raw light data from the instance structure
+ //
+ CM3218DataLightVisibleGetRaw(psInst, &ui16Light);
+
+ //
+ // Get the floating point values for sensitivity
+ //
+ fSensitivity = g_pfSensitivityLookup[psInst->ui8IntTime];
+
+ //
+ // Calculate light reading in lux.
+ //
+ *pfVisibleLight = ((float)ui16Light) * fSensitivity;
+}
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
diff --git a/sensorlib/cm3218.h b/sensorlib/cm3218.h
new file mode 100644
index 0000000..fad9f11
--- /dev/null
+++ b/sensorlib/cm3218.h
@@ -0,0 +1,149 @@
+//*****************************************************************************
+//
+// CM3218.h - Prototypes for the CM3218 light sensor
+// driver.
+//
+// Copyright (c) 2012-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
+//
+//*****************************************************************************
+
+#ifndef __SENSORLIB_CM3218_H__
+#define __SENSORLIB_CM3218_H__
+
+//*****************************************************************************
+//
+// If building with a C++ compiler, make all of the definitions in this header
+// have a C binding.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+//*****************************************************************************
+//
+// The structure that defines the internal state of the CM3218 driver.
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ // The pointer to the I2C master interface instance used to communicate
+ // with the CM3218.
+ //
+ tI2CMInstance *psI2CInst;
+
+ //
+ // The I2C address of the CM3218.
+ //
+ uint8_t ui8Addr;
+
+ //
+ // The state of the state machine used while accessing the CM3218.
+ //
+ uint8_t ui8State;
+
+ //
+ // The data buffer used for sending/receiving data to/from the CM3218.
+ //
+ uint8_t pui8Data[4];
+
+ //
+ // The integration time, which determines the sensitivity.
+ //
+ uint8_t ui8IntTime;
+
+ //
+ // The new integration time, which is used when a register write succeeds.
+ //
+ uint8_t ui8NewIntTime;
+
+ //
+ // The function that is called when the current request has completed
+ // processing.
+ //
+ tSensorCallback *pfnCallback;
+
+ //
+ // The pointer provided to the callback function.
+ //
+ void *pvCallbackData;
+
+ //
+ // A union of structures that are used for read and write operations.
+ // Since only one operation can be active at a time, it is safe to re-use
+ // the memory in this manner.
+ //
+ union
+ {
+ //
+ // A buffer used to store the write portion of a register read.
+ //
+ uint8_t pui8Buffer[4];
+
+ //
+ // The read state used to read register values.
+ //
+ tI2CMRead16BE sReadState;
+
+ //
+ // The write state used to write register values.
+ //
+ tI2CMWrite16BE sWriteState;
+ }
+ uCommand;
+}
+tCM3218;
+
+//*****************************************************************************
+//
+// Function prototypes.
+//
+//*****************************************************************************
+extern uint_fast8_t CM3218Init(tCM3218 *psInst, tI2CMInstance *psI2CInst,
+ uint_fast8_t ui8I2CAddr,
+ tSensorCallback *pfnCallback,
+ void *pvCallbackData);
+extern uint_fast8_t CM3218Read(tCM3218 *psInst, uint_fast8_t ui8Reg,
+ uint16_t *pui16Data, uint_fast16_t ui16Count,
+ tSensorCallback *pfnCallback,
+ void *pvCallbackData);
+extern uint_fast8_t CM3218Write(tCM3218 *psInst, uint_fast8_t ui8Reg,
+ const uint16_t *pui16Data,
+ uint_fast16_t ui16Count,
+ tSensorCallback *pfnCallback,
+ void *pvCallbackData);
+extern uint_fast8_t CM3218DataRead(tCM3218 *psInst,
+ tSensorCallback *pfnCallback,
+ void *pvCallbackData);
+extern void CM3218DataLightVisibleGetRaw(tCM3218 *psInst,
+ uint16_t *pui16Visible);
+extern void CM3218DataLightVisibleGetFloat(tCM3218 *psInst, float *pfVisible);
+
+//*****************************************************************************
+//
+// Mark the end of the C bindings section for C++ compilers.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __SENSORLIB_CM3218_H__
diff --git a/sensorlib/comp_dcm.c b/sensorlib/comp_dcm.c
new file mode 100644
index 0000000..42db71d
--- /dev/null
+++ b/sensorlib/comp_dcm.c
@@ -0,0 +1,634 @@
+//*****************************************************************************
+//
+// comp_dcm.c - Complementary filter algorithm on a Direction Cosine Matrix for
+// fusing sensor data from an accelerometer, gyroscope, and
+// magnetometer.
+//
+// Copyright (c) 2012-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
+//
+//*****************************************************************************
+
+#include <math.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include "driverlib/debug.h"
+#include "sensorlib/comp_dcm.h"
+#include "sensorlib/vector.h"
+
+//*****************************************************************************
+//
+//! \addtogroup comp_dcm_api
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// If M_PI has not been defined by the system headers, define it here.
+//
+//*****************************************************************************
+#ifndef M_PI
+#define M_PI 3.14159265358979323846
+#endif
+
+//*****************************************************************************
+//
+//! Initializes the complementary filter DCM attitude estimation state.
+//!
+//! \param psDCM is a pointer to the DCM state structure.
+//! \param fDeltaT is the amount of time between DCM updates, in seconds.
+//! \param fScaleA is the weight of the accelerometer reading in determining
+//! the updated attitude estimation.
+//! \param fScaleG is the weight of the gyroscope reading in determining the
+//! updated attitude estimation.
+//! \param fScaleM is the weight of the magnetometer reading in determining the
+//! updated attitude estimation.
+//!
+//! This function initializes the complementary filter DCM attitude estimation
+//! state, and must be called prior to performing any attitude estimation.
+//!
+//! New readings must be supplied to the complementary filter DCM attitude
+//! estimation algorithm at the rate specified by the \e fDeltaT parameter.
+//! Failure to provide new readings at this rate results in inaccuracies in the
+//! attitude estimation.
+//!
+//! The \e fScaleA, \e fScaleG, and \e fScaleM weights must sum to one.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+CompDCMInit(tCompDCM *psDCM, float fDeltaT, float fScaleA, float fScaleG,
+ float fScaleM)
+{
+ //
+ // Initialize the DCM matrix to the identity matrix.
+ //
+ psDCM->ppfDCM[0][0] = 1.0;
+ psDCM->ppfDCM[0][1] = 0.0;
+ psDCM->ppfDCM[0][2] = 0.0;
+ psDCM->ppfDCM[1][0] = 0.0;
+ psDCM->ppfDCM[1][1] = 1.0;
+ psDCM->ppfDCM[1][2] = 0.0;
+ psDCM->ppfDCM[2][0] = 0.0;
+ psDCM->ppfDCM[2][1] = 0.0;
+ psDCM->ppfDCM[2][2] = 1.0;
+
+ //
+ // Save the time delta between DCM updates.
+ //
+ psDCM->fDeltaT = fDeltaT;
+
+ //
+ // Save the scaling factors that are applied to the accelerometer,
+ // gyroscope, and magnetometer readings.
+ //
+ psDCM->fScaleA = fScaleA;
+ psDCM->fScaleG = fScaleG;
+ psDCM->fScaleM = fScaleM;
+}
+
+//*****************************************************************************
+//
+//! Updates the accelerometer reading used by the complementary filter DCM
+//! algorithm.
+//!
+//! \param psDCM is a pointer to the DCM state structure.
+//! \param fAccelX is the accelerometer reading in the X body axis.
+//! \param fAccelY is the accelerometer reading in the Y body axis.
+//! \param fAccelZ is the accelerometer reading in the Z body axis.
+//!
+//! This function updates the accelerometer reading used by the complementary
+//! filter DCM algorithm. The accelerometer readings provided to this function
+//! are used by subsequent calls to CompDCMStart() and CompDCMUpdate() to
+//! compute the attitude estimate.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+CompDCMAccelUpdate(tCompDCM *psDCM, float fAccelX, float fAccelY,
+ float fAccelZ)
+{
+ //
+ // The user should never pass in values that are not-a-number
+ //
+ ASSERT(!isnan(fAccelX));
+ ASSERT(!isnan(fAccelY));
+ ASSERT(!isnan(fAccelZ));
+
+ //
+ // Save the new accelerometer reading.
+ //
+ psDCM->pfAccel[0] = fAccelX;
+ psDCM->pfAccel[1] = fAccelY;
+ psDCM->pfAccel[2] = fAccelZ;
+}
+
+//*****************************************************************************
+//
+//! Updates the gyroscope reading used by the complementary filter DCM
+//! algorithm.
+//!
+//! \param psDCM is a pointer to the DCM state structure.
+//! \param fGyroX is the gyroscope reading in the X body axis.
+//! \param fGyroY is the gyroscope reading in the Y body axis.
+//! \param fGyroZ is the gyroscope reading in the Z body axis.
+//!
+//! This function updates the gyroscope reading used by the complementary
+//! filter DCM algorithm. The gyroscope readings provided to this function are
+//! used by subsequent calls to CompDCMUpdate() to compute the attitude
+//! estimate.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+CompDCMGyroUpdate(tCompDCM *psDCM, float fGyroX, float fGyroY, float fGyroZ)
+{
+ //
+ // The user should never pass in values that are not-a-number
+ //
+ ASSERT(!isnan(fGyroX));
+ ASSERT(!isnan(fGyroY));
+ ASSERT(!isnan(fGyroZ));
+
+ //
+ // Save the new gyroscope reading.
+ //
+ psDCM->pfGyro[0] = fGyroX;
+ psDCM->pfGyro[1] = fGyroY;
+ psDCM->pfGyro[2] = fGyroZ;
+}
+
+//*****************************************************************************
+//
+//! Updates the magnetometer reading used by the complementary filter DCM
+//! algorithm.
+//!
+//! \param psDCM is a pointer to the DCM state structure.
+//! \param fMagnetoX is the magnetometer reading in the X body axis.
+//! \param fMagnetoY is the magnetometer reading in the Y body axis.
+//! \param fMagnetoZ is the magnetometer reading in the Z body axis.
+//!
+//! This function updates the magnetometer reading used by the complementary
+//! filter DCM algorithm. The magnetometer readings provided to this function
+//! are used by subsequent calls to CompDCMStart() and CompDCMUpdate() to
+//! compute the attitude estimate.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+CompDCMMagnetoUpdate(tCompDCM *psDCM, float fMagnetoX, float fMagnetoY,
+ float fMagnetoZ)
+{
+ //
+ // The user should never pass in values that are not-a-number
+ //
+ ASSERT(!isnan(fMagnetoX));
+ ASSERT(!isnan(fMagnetoY));
+ ASSERT(!isnan(fMagnetoZ));
+
+ //
+ // Save the new magnetometer reading.
+ //
+ psDCM->pfMagneto[0] = fMagnetoX;
+ psDCM->pfMagneto[1] = fMagnetoY;
+ psDCM->pfMagneto[2] = fMagnetoZ;
+}
+
+//*****************************************************************************
+//
+//! Starts the complementary filter DCM attitude estimation from an initial
+//! sensor reading.
+//!
+//! \param psDCM is a pointer to the DCM state structure.
+//!
+//! This function computes the initial complementary filter DCM attitude
+//! estimation state based on the initial accelerometer and magnetometer
+//! reading. While not necessary for the attitude estimation to converge,
+//! using an initial state based on sensor readings results in quicker
+//! convergence.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+CompDCMStart(tCompDCM *psDCM)
+{
+ float pfI[3], pfJ[3], pfK[3];
+
+ //
+ // The magnetometer reading forms the initial I vector, pointing north.
+ //
+ pfI[0] = psDCM->pfMagneto[0];
+ pfI[1] = psDCM->pfMagneto[1];
+ pfI[2] = psDCM->pfMagneto[2];
+
+ //
+ // The accelerometer reading forms the initial K vector, pointing down.
+ //
+ pfK[0] = psDCM->pfAccel[0];
+ pfK[1] = psDCM->pfAccel[1];
+ pfK[2] = psDCM->pfAccel[2];
+
+ //
+ // Compute the initial J vector, which is the cross product of the K and I
+ // vectors.
+ //
+ VectorCrossProduct(pfJ, pfK, pfI);
+
+ //
+ // Recompute the I vector from the cross product of the J and K vectors.
+ // This makes it fully orthogonal, which it wasn't before since magnetic
+ // north points inside the Earth in many places.
+ //
+ VectorCrossProduct(pfI, pfJ, pfK);
+
+ //
+ // Normalize the I, J, and K vectors.
+ //
+ VectorScale(pfI, pfI, 1 / sqrtf(VectorDotProduct(pfI, pfI)));
+ VectorScale(pfJ, pfJ, 1 / sqrtf(VectorDotProduct(pfJ, pfJ)));
+ VectorScale(pfK, pfK, 1 / sqrtf(VectorDotProduct(pfK, pfK)));
+
+ //
+ // Initialize the DCM matrix from the I, J, and K vectors.
+ //
+ psDCM->ppfDCM[0][0] = pfI[0];
+ psDCM->ppfDCM[0][1] = pfI[1];
+ psDCM->ppfDCM[0][2] = pfI[2];
+ psDCM->ppfDCM[1][0] = pfJ[0];
+ psDCM->ppfDCM[1][1] = pfJ[1];
+ psDCM->ppfDCM[1][2] = pfJ[2];
+ psDCM->ppfDCM[2][0] = pfK[0];
+ psDCM->ppfDCM[2][1] = pfK[1];
+ psDCM->ppfDCM[2][2] = pfK[2];
+}
+
+//*****************************************************************************
+//
+//! Updates the complementary filter DCM attitude estimation based on an
+//! updated set of sensor readings.
+//!
+//! \param psDCM is a pointer to the DCM state structure.
+//!
+//! This function updates the complementary filter DCM attitude estimation
+//! state based on the current sensor readings. This function must be called
+//! at the rate specified to CompDCMInit(), with new readings supplied at an
+//! appropriate rate (for example, magnetometers typically sample at a much
+//! slower rate than accelerometers and gyroscopes).
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+CompDCMUpdate(tCompDCM *psDCM)
+{
+ float pfI[3], pfJ[3], pfK[3], pfDelta[3], pfTemp[3], fError;
+ bool bNAN;
+
+ //
+ // The magnetometer reading forms the new Im vector, pointing north.
+ //
+ pfI[0] = psDCM->pfMagneto[0];
+ pfI[1] = psDCM->pfMagneto[1];
+ pfI[2] = psDCM->pfMagneto[2];
+
+ //
+ // The accelerometer reading forms the new Ka vector, pointing down.
+ //
+ pfK[0] = psDCM->pfAccel[0];
+ pfK[1] = psDCM->pfAccel[1];
+ pfK[2] = psDCM->pfAccel[2];
+
+ //
+ // Compute the new J vector, which is the cross product of the Ka and Im
+ // vectors.
+ //
+ VectorCrossProduct(pfJ, pfK, pfI);
+
+ //
+ // Recompute the Im vector from the cross product of the J and Ka vectors.
+ // This makes it fully orthogonal, which it wasn't before since magnetic
+ // north points inside the Earth in many places.
+ //
+ VectorCrossProduct(pfI, pfJ, pfK);
+
+ //
+ // Normalize the Im and Ka vectors.
+ //
+ VectorScale(pfI, pfI, 1 / sqrtf(VectorDotProduct(pfI, pfI)));
+ VectorScale(pfK, pfK, 1 / sqrtf(VectorDotProduct(pfK, pfK)));
+
+ //
+ // Compute and scale the rotation as inferred from the accelerometer,
+ // storing it in the rotation accumulator.
+ //
+ VectorCrossProduct(pfTemp, psDCM->ppfDCM[2], pfK);
+ VectorScale(pfDelta, pfTemp, psDCM->fScaleA);
+
+ //
+ // Compute and scale the rotation as measured by the gyroscope, adding it
+ // to the rotation accumulator.
+ //
+ pfTemp[0] = psDCM->pfGyro[0] * psDCM->fDeltaT * psDCM->fScaleG;
+ pfTemp[1] = psDCM->pfGyro[1] * psDCM->fDeltaT * psDCM->fScaleG;
+ pfTemp[2] = psDCM->pfGyro[2] * psDCM->fDeltaT * psDCM->fScaleG;
+ VectorAdd(pfDelta, pfDelta, pfTemp);
+
+ //
+ // Compute and scale the rotation as inferred from the magnetometer, adding
+ // it to the rotation accumulator.
+ //
+ VectorCrossProduct(pfTemp, psDCM->ppfDCM[0], pfI);
+ VectorScale(pfTemp, pfTemp, psDCM->fScaleM);
+ VectorAdd(pfDelta, pfDelta, pfTemp);
+
+ //
+ // Rotate the I vector from the DCM matrix by the scaled rotation.
+ //
+ VectorCrossProduct(pfI, pfDelta, psDCM->ppfDCM[0]);
+ VectorAdd(psDCM->ppfDCM[0], psDCM->ppfDCM[0], pfI);
+
+ //
+ // Rotate the K vector from the DCM matrix by the scaled rotation.
+ //
+ VectorCrossProduct(pfK, pfDelta, psDCM->ppfDCM[2]);
+ VectorAdd(psDCM->ppfDCM[2], psDCM->ppfDCM[2], pfK);
+
+ //
+ // Compute the orthogonality error between the rotated I and K vectors and
+ // adjust each by half the error, bringing them closer to orthogonality.
+ //
+ fError = VectorDotProduct(psDCM->ppfDCM[0], psDCM->ppfDCM[2]) / -2.0;
+ VectorScale(pfI, psDCM->ppfDCM[0], fError);
+ VectorScale(pfK, psDCM->ppfDCM[2], fError);
+ VectorAdd(psDCM->ppfDCM[0], psDCM->ppfDCM[0], pfK);
+ VectorAdd(psDCM->ppfDCM[2], psDCM->ppfDCM[2], pfI);
+
+ //
+ // Normalize the I and K vectors.
+ //
+ VectorScale(psDCM->ppfDCM[0], psDCM->ppfDCM[0],
+ 0.5 * (3.0 - VectorDotProduct(psDCM->ppfDCM[0],
+ psDCM->ppfDCM[0])));
+ VectorScale(psDCM->ppfDCM[2], psDCM->ppfDCM[2],
+ 0.5 * (3.0 - VectorDotProduct(psDCM->ppfDCM[2],
+ psDCM->ppfDCM[2])));
+
+ //
+ // Compute the rotated J vector from the cross product of the rotated,
+ // corrected K and I vectors.
+ //
+ VectorCrossProduct(psDCM->ppfDCM[1], psDCM->ppfDCM[2], psDCM->ppfDCM[0]);
+
+ //
+ // Determine if the newly updated DCM contains any invalid (in other words,
+ // NaN) values.
+ //
+ bNAN = (isnan(psDCM->ppfDCM[0][0]) ||
+ isnan(psDCM->ppfDCM[0][1]) ||
+ isnan(psDCM->ppfDCM[0][2]) ||
+ isnan(psDCM->ppfDCM[1][0]) ||
+ isnan(psDCM->ppfDCM[1][1]) ||
+ isnan(psDCM->ppfDCM[1][2]) ||
+ isnan(psDCM->ppfDCM[2][0]) ||
+ isnan(psDCM->ppfDCM[2][1]) ||
+ isnan(psDCM->ppfDCM[2][2]));
+
+ //
+ // As a debug measure, we check for NaN in the DCM. The user can trap
+ // this event depending on their implementation of __error__. Should they
+ // choose to disable interrupts and loop forever then they will have
+ // preserved the stack and can analyze how they arrived at NaN.
+ //
+ ASSERT(!bNAN);
+
+ //
+ // If any part of the matrix is not-a-number then reset the DCM back to the
+ // identity matrix.
+ //
+ if(bNAN)
+ {
+ psDCM->ppfDCM[0][0] = 1.0;
+ psDCM->ppfDCM[0][1] = 0.0;
+ psDCM->ppfDCM[0][2] = 0.0;
+ psDCM->ppfDCM[1][0] = 0.0;
+ psDCM->ppfDCM[1][1] = 1.0;
+ psDCM->ppfDCM[1][2] = 0.0;
+ psDCM->ppfDCM[2][0] = 0.0;
+ psDCM->ppfDCM[2][1] = 0.0;
+ psDCM->ppfDCM[2][2] = 1.0;
+ }
+}
+
+//*****************************************************************************
+//
+//! Returns the current DCM attitude estimation matrix.
+//!
+//! \param psDCM is a pointer to the DCM state structure.
+//! \param ppfDCM is a pointer to the array into which to store the DCM matrix
+//! values.
+//!
+//! This function returns the current value of the DCM matrix.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+CompDCMMatrixGet(tCompDCM *psDCM, float ppfDCM[3][3])
+{
+ //
+ // Return the current DCM matrix.
+ //
+ ppfDCM[0][0] = psDCM->ppfDCM[0][0];
+ ppfDCM[0][1] = psDCM->ppfDCM[0][1];
+ ppfDCM[0][2] = psDCM->ppfDCM[0][2];
+ ppfDCM[1][0] = psDCM->ppfDCM[1][0];
+ ppfDCM[1][1] = psDCM->ppfDCM[1][1];
+ ppfDCM[1][2] = psDCM->ppfDCM[1][2];
+ ppfDCM[2][0] = psDCM->ppfDCM[2][0];
+ ppfDCM[2][1] = psDCM->ppfDCM[2][1];
+ ppfDCM[2][2] = psDCM->ppfDCM[2][2];
+}
+
+//*****************************************************************************
+//
+//! Computes the Euler angles from the DCM attitude estimation matrix.
+//!
+//! \param psDCM is a pointer to the DCM state structure.
+//! \param pfRoll is a pointer to the value into which the roll is stored.
+//! \param pfPitch is a pointer to the value into which the pitch is stored.
+//! \param pfYaw is a pointer to the value into which the yaw is stored.
+//!
+//! This function computes the Euler angles that are represented by the DCM
+//! attitude estimation matrix. If any of the Euler angles is not required,
+//! the corresponding parameter can be \b NULL.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+CompDCMComputeEulers(tCompDCM *psDCM, float *pfRoll, float *pfPitch,
+ float *pfYaw)
+{
+ //
+ // Compute the roll, pitch, and yaw as required.
+ //
+ if(pfRoll)
+ {
+ *pfRoll = atan2f(psDCM->ppfDCM[2][1], psDCM->ppfDCM[2][2]);
+ }
+ if(pfPitch)
+ {
+ *pfPitch = -asinf(psDCM->ppfDCM[2][0]);
+ }
+ if(pfYaw)
+ {
+ *pfYaw = atan2f(psDCM->ppfDCM[1][0], psDCM->ppfDCM[0][0]);
+ }
+}
+
+//*****************************************************************************
+//
+//! Computes the quaternion from the DCM attitude estimation matrix.
+//!
+//! \param psDCM is a pointer to the DCM state structure.
+//! \param pfQuaternion is an array into which the quaternion is stored.
+//!
+//! This function computes the quaternion that is represented by the DCM
+//! attitude estimation matrix.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+CompDCMComputeQuaternion(tCompDCM *psDCM, float pfQuaternion[4])
+{
+ float fQs, fQx, fQy, fQz;
+
+ //
+ // Partially compute Qs, Qx, Qy, and Qz based on the DCM diagonals. The
+ // square root, an expensive operation, is computed for only one of these
+ // as determined later.
+ //
+ fQs = 1 + psDCM->ppfDCM[0][0] + psDCM->ppfDCM[1][1] + psDCM->ppfDCM[2][2];
+ fQx = 1 + psDCM->ppfDCM[0][0] - psDCM->ppfDCM[1][1] - psDCM->ppfDCM[2][2];
+ fQy = 1 - psDCM->ppfDCM[0][0] + psDCM->ppfDCM[1][1] - psDCM->ppfDCM[2][2];
+ fQz = 1 - psDCM->ppfDCM[0][0] - psDCM->ppfDCM[1][1] + psDCM->ppfDCM[2][2];
+
+ //
+ // See if Qs is the largest of the diagonal values.
+ //
+ if((fQs > fQx) && (fQs > fQy) && (fQs > fQz))
+ {
+ //
+ // Finish the computation of Qs.
+ //
+ fQs = sqrtf(fQs) / 2;
+
+ //
+ // Compute the values of the quaternion based on Qs.
+ //
+ pfQuaternion[0] = fQs;
+ pfQuaternion[1] = ((psDCM->ppfDCM[2][1] - psDCM->ppfDCM[1][2]) /
+ (4 * fQs));
+ pfQuaternion[2] = ((psDCM->ppfDCM[0][2] - psDCM->ppfDCM[2][0]) /
+ (4 * fQs));
+ pfQuaternion[3] = ((psDCM->ppfDCM[1][0] - psDCM->ppfDCM[0][1]) /
+ (4 * fQs));
+ }
+
+ //
+ // Qs is not the largest, so see if Qx is the largest remaining diagonal
+ // value.
+ //
+ else if((fQx > fQy) && (fQx > fQz))
+ {
+ //
+ // Finish the computation of Qx.
+ //
+ fQx = sqrtf(fQx) / 2;
+
+ //
+ // Compute the values of the quaternion based on Qx.
+ //
+ pfQuaternion[0] = ((psDCM->ppfDCM[2][1] - psDCM->ppfDCM[1][2]) /
+ (4 * fQx));
+ pfQuaternion[1] = fQx;
+ pfQuaternion[2] = ((psDCM->ppfDCM[1][0] + psDCM->ppfDCM[0][1]) /
+ (4 * fQx));
+ pfQuaternion[3] = ((psDCM->ppfDCM[0][2] + psDCM->ppfDCM[2][0]) /
+ (4 * fQx));
+ }
+
+ //
+ // Qs and Qx are not the largest, so see if Qy is the largest remaining
+ // diagonal value.
+ //
+ else if(fQy > fQz)
+ {
+ //
+ // Finish the computation of Qy.
+ //
+ fQy = sqrtf(fQy) / 2;
+
+ //
+ // Compute the values of the quaternion based on Qy.
+ //
+ pfQuaternion[0] = ((psDCM->ppfDCM[0][2] - psDCM->ppfDCM[2][0]) /
+ (4 * fQy));
+ pfQuaternion[1] = ((psDCM->ppfDCM[1][0] + psDCM->ppfDCM[0][1]) /
+ (4 * fQy));
+ pfQuaternion[2] = fQy;
+ pfQuaternion[3] = ((psDCM->ppfDCM[2][1] + psDCM->ppfDCM[1][2]) /
+ (4 * fQy));
+ }
+
+ //
+ // Qz is the largest diagonal value.
+ //
+ else
+ {
+ //
+ // Finish the computation of Qz.
+ //
+ fQz = sqrtf(fQz) / 2;
+
+ //
+ // Compute the values of the quaternion based on Qz.
+ //
+ pfQuaternion[0] = ((psDCM->ppfDCM[1][0] - psDCM->ppfDCM[0][1]) /
+ (4 * fQz));
+ pfQuaternion[1] = ((psDCM->ppfDCM[0][2] + psDCM->ppfDCM[2][0]) /
+ (4 * fQz));
+ pfQuaternion[2] = ((psDCM->ppfDCM[2][1] + psDCM->ppfDCM[1][2]) /
+ (4 * fQz));
+ pfQuaternion[3] = fQz;
+ }
+}
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
diff --git a/sensorlib/comp_dcm.h b/sensorlib/comp_dcm.h
new file mode 100644
index 0000000..860bda9
--- /dev/null
+++ b/sensorlib/comp_dcm.h
@@ -0,0 +1,120 @@
+//*****************************************************************************
+//
+// comp_dcm.h - Prototypes for the complementary filter direction cosine matrix
+// functions.
+//
+// Copyright (c) 2012-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
+//
+//*****************************************************************************
+
+#ifndef __SENSORLIB_COMP_DCM_H__
+#define __SENSORLIB_COMP_DCM_H__
+
+//*****************************************************************************
+//
+// If building with a C++ compiler, make all of the definitions in this header
+// have a C binding.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+//*****************************************************************************
+//
+// The structure that defines the internal state of the complementary filter
+// DCM algorithm.
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ // The state of the direction cosine matrix.
+ //
+ float ppfDCM[3][3];
+
+ //
+ // The time delta between updates to the DCM.
+ //
+ float fDeltaT;
+
+ //
+ // The scaling factor for the DCM update based on the accelerometer
+ // reading.
+ //
+ float fScaleA;
+
+ //
+ // The scaling factor for the DCM update based on the gyroscope reading.
+ //
+ float fScaleG;
+
+ //
+ // The scaling factor for the DCM update based on the magnetometer reading.
+ //
+ float fScaleM;
+
+ //
+ // The most recent accelerometer readings.
+ //
+ float pfAccel[3];
+
+ //
+ // The most recent gyroscope readings.
+ //
+ float pfGyro[3];
+
+ //
+ // The most recent magnetometer readings.
+ //
+ float pfMagneto[3];
+}
+tCompDCM;
+
+//*****************************************************************************
+//
+// Prototypes.
+//
+//*****************************************************************************
+extern void CompDCMInit(tCompDCM *psDCM, float fDeltaT, float fScaleA,
+ float fScaleG, float fScaleM);
+extern void CompDCMAccelUpdate(tCompDCM *psDCM, float fAccelX, float fAccelY,
+ float fAccelZ);
+extern void CompDCMGyroUpdate(tCompDCM *psDCM, float fGyroX, float fGyroY,
+ float fGyroZ);
+extern void CompDCMMagnetoUpdate(tCompDCM *psDCM, float fMagnetoX,
+ float fMagnetoY, float fMagnetoZ);
+extern void CompDCMStart(tCompDCM *psDCM);
+extern void CompDCMUpdate(tCompDCM *psDCM);
+extern void CompDCMMatrixGet(tCompDCM *psDCM, float ppfDCM[3][3]);
+extern void CompDCMComputeEulers(tCompDCM *psDCM, float *pfRoll,
+ float *pfPitch, float *pfYaw);
+extern void CompDCMComputeQuaternion(tCompDCM *psDCM, float pfQuaternion[4]);
+
+//*****************************************************************************
+//
+// Mark the end of the C bindings section for C++ compilers.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __SENSORLIB_COMP_DCM_H__
diff --git a/sensorlib/ewarm/Exe/sensorlib.a b/sensorlib/ewarm/Exe/sensorlib.a
new file mode 100644
index 0000000..408cb46
--- /dev/null
+++ b/sensorlib/ewarm/Exe/sensorlib.a
Binary files differ
diff --git a/sensorlib/gcc/libsensor.a b/sensorlib/gcc/libsensor.a
new file mode 100644
index 0000000..ae22311
--- /dev/null
+++ b/sensorlib/gcc/libsensor.a
Binary files differ
diff --git a/sensorlib/hw_ak8963.h b/sensorlib/hw_ak8963.h
new file mode 100644
index 0000000..53e43f2
--- /dev/null
+++ b/sensorlib/hw_ak8963.h
@@ -0,0 +1,209 @@
+//*****************************************************************************
+//
+// hw_ak8963.h - Macros used when accessing the Asahi Kasei AK8963
+// magnetometer.
+//
+// Copyright (c) 2013-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
+//
+//*****************************************************************************
+
+#ifndef __SENSORLIB_HW_AK8963_H__
+#define __SENSORLIB_HW_AK8963_H__
+
+//*****************************************************************************
+//
+// The following are defines for the AK8963 register addresses.
+//
+//*****************************************************************************
+#define AK8963_O_WIA 0x00 // Device ID register
+#define AK8963_O_INFO 0x01 // Information register
+#define AK8963_O_ST1 0x02 // Status 1 register
+#define AK8963_O_HXL 0x03 // X-axis LSB output register
+#define AK8963_O_HXH 0x04 // X-axis MSB output register
+#define AK8963_O_HYL 0x05 // Y-axis LSB output register
+#define AK8963_O_HYH 0x06 // Y-axis MSB output register
+#define AK8963_O_HZL 0x07 // Z-axis LSB output register
+#define AK8963_O_HZH 0x08 // Z-axis MSB output register
+#define AK8963_O_ST2 0x09 // Status 2 register
+#define AK8963_O_CNTL 0x0A // Control register
+#define AK8963_O_CNTL2 0x0B // Control 2 register
+#define AK8963_O_ASTC 0x0C // Self-test register
+#define AK8963_O_I2CDIS 0x0F // Disable I2C bus interface
+#define AK8963_O_ASAX 0x10 // X-axis sensitivity register
+#define AK8963_O_ASAY 0x11 // Y-axis sensitivity register
+#define AK8963_O_ASAZ 0x12 // Z-axis sensitivity register
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the AK8963_O_WIA register.
+//
+//*****************************************************************************
+#define AK8963_WIA_M 0xFF // Device ID
+#define AK8963_WIA_AK8963 0x48 // AK8963
+#define AK8963_WIA_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the AK8963_O_INFO register.
+//
+//*****************************************************************************
+#define AK8963_INFO_M 0xFF // Device information value
+#define AK8963_INFO_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the AK8963_O_ST1 register.
+//
+//*****************************************************************************
+#define AK8963_ST1_DOR 0x02 // Data overrun
+#define AK8963_ST1_DRDY 0x01 // Data ready
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the AK8963_O_HXL register.
+//
+//*****************************************************************************
+#define AK8963_HXL_M 0xFF // Output data
+#define AK8963_HXL_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the AK8963_O_HXH register.
+//
+//*****************************************************************************
+#define AK8963_HXH_M 0xFF // Output data
+#define AK8963_HXH_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the AK8963_O_HYL register.
+//
+//*****************************************************************************
+#define AK8963_HYL_M 0xFF // Output data
+#define AK8963_HYL_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the AK8963_O_HYH register.
+//
+//*****************************************************************************
+#define AK8963_HYH_M 0xFF // Output data
+#define AK8963_HYH_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the AK8963_O_HZL register.
+//
+//*****************************************************************************
+#define AK8963_HZL_M 0xFF // Output data
+#define AK8963_HZL_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the AK8963_O_HZH register.
+//
+//*****************************************************************************
+#define AK8963_HZH_M 0xFF // Output data
+#define AK8963_HZH_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the AK8963_O_ST2 register.
+//
+//*****************************************************************************
+#define AK8963_ST2_BITM_M 0x10 // Output bit setting
+#define AK8963_ST2_BITM_14BIT 0x00 // 14-bit output
+#define AK8963_ST2_BITM_16BIT 0x10 // 16-bit output
+#define AK8963_ST2_HOFL 0x08 // Magnetic sensor overflow
+#define AK8963_ST2_BITM_S 4
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the AK8963_O_CNTL register.
+//
+//*****************************************************************************
+#define AK8963_CNTL_BITM_M 0x10 // Output bit setting
+#define AK8963_CNTL_BITM_14BIT 0x00 // 14-bit output
+#define AK8963_CNTL_BITM_16BIT 0x10 // 16-bit output
+#define AK8963_CNTL_MODE_M 0x0F // Operation mode
+#define AK8963_CNTL_MODE_POWER_DOWN \
+ 0x00 // Power-down mode
+#define AK8963_CNTL_MODE_SINGLE 0x01 // Single measurement mode
+#define AK8963_CNTL_MODE_CONT_1 0x02 // Continuous measurement mode 1
+ // (8Hz)
+#define AK8963_CNTL_MODE_EXT_TRIG \
+ 0x04 // External trigger measurement
+ // mode
+#define AK8963_CNTL_MODE_CONT_2 0x06 // Continuous measurement mode 2
+ // (100Hz)
+#define AK8963_CNTL_MODE_SELF_TEST \
+ 0x08 // Self-test mode
+#define AK8963_CNTL_MODE_FUSE_ROM \
+ 0x0F // Fuse ROM access mode
+#define AK8963_CNTL_BITM_S 4
+#define AK8963_CNTL_MODE_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the AK8963_O_CNTL2 register.
+//
+//*****************************************************************************
+#define AK8963_CNTL2_SRST 0x01 // Register reset
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the AK8963_O_ASTC register.
+//
+//*****************************************************************************
+#define AK8963_ASTC_SELF 0x40 // Generate magnetic field for
+ // self-test
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the AK8963_O_I2CDIS
+// register.
+//
+//*****************************************************************************
+#define AK8963_I2CDIS_I2CDIS 0xFF // Disable I2C bus interface
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the AK8963_O_ASAX register.
+//
+//*****************************************************************************
+#define AK8963_ASAX_M 0xFF // X-axis sensitivity adjustment
+#define AK8963_ASAX_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the AK8963_O_ASAY register.
+//
+//*****************************************************************************
+#define AK8963_ASAY_M 0xFF // Y-axis sensitivity adjustment
+#define AK8963_ASAY_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the AK8963_O_ASAZ register.
+//
+//*****************************************************************************
+#define AK8963_ASAZ_M 0xFF // Z-axis sensitivity adjustment
+#define AK8963_ASAZ_S 0
+
+#endif // __SENSORLIB_HW_AK8963_H__
diff --git a/sensorlib/hw_ak8975.h b/sensorlib/hw_ak8975.h
new file mode 100644
index 0000000..e1cb847
--- /dev/null
+++ b/sensorlib/hw_ak8975.h
@@ -0,0 +1,177 @@
+//*****************************************************************************
+//
+// hw_ak8975.h - Macros used when accessing the Asahi Kasei AK8975
+// magnetometer.
+//
+// Copyright (c) 2013-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
+//
+//*****************************************************************************
+
+#ifndef __SENSORLIB_HW_AK8975_H__
+#define __SENSORLIB_HW_AK8975_H__
+
+//*****************************************************************************
+//
+// The following are defines for the AK8975 register addresses.
+//
+//*****************************************************************************
+#define AK8975_O_WIA 0x00 // Device ID register
+#define AK8975_O_INFO 0x01 // Information register
+#define AK8975_O_ST1 0x02 // Status 1 register
+#define AK8975_O_HXL 0x03 // X-axis LSB output register
+#define AK8975_O_HXH 0x04 // X-axis MSB output register
+#define AK8975_O_HYL 0x05 // Y-axis LSB output register
+#define AK8975_O_HYH 0x06 // Y-axis MSB output register
+#define AK8975_O_HZL 0x07 // Z-axis LSB output register
+#define AK8975_O_HZH 0x08 // Z-axis MSB output register
+#define AK8975_O_ST2 0x09 // Status 2 register
+#define AK8975_O_CNTL 0x0A // Control register
+#define AK8975_O_ASTC 0x0C // Self-test register
+#define AK8975_O_ASAX 0x10 // X-axis sensitivity register
+#define AK8975_O_ASAY 0x11 // Y-axis sensitivity register
+#define AK8975_O_ASAZ 0x12 // Z-axis sensitivity register
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the AK8975_O_WIA register.
+//
+//*****************************************************************************
+#define AK8975_WIA_M 0xFF // Device ID
+#define AK8975_WIA_AK8975 0x48 // AK8975
+#define AK8975_WIA_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the AK8975_O_INFO register.
+//
+//*****************************************************************************
+#define AK8975_INFO_M 0xFF // Device information value
+#define AK8975_INFO_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the AK8975_O_ST1 register.
+//
+//*****************************************************************************
+#define AK8975_ST1_DRDY 0x01 // Data ready
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the AK8975_O_HXL register.
+//
+//*****************************************************************************
+#define AK8975_HXL_M 0xFF // Output data
+#define AK8975_HXL_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the AK8975_O_HXH register.
+//
+//*****************************************************************************
+#define AK8975_HXH_M 0xFF // Output data
+#define AK8975_HXH_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the AK8975_O_HYL register.
+//
+//*****************************************************************************
+#define AK8975_HYL_M 0xFF // Output data
+#define AK8975_HYL_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the AK8975_O_HYH register.
+//
+//*****************************************************************************
+#define AK8975_HYH_M 0xFF // Output data
+#define AK8975_HYH_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the AK8975_O_HZL register.
+//
+//*****************************************************************************
+#define AK8975_HZL_M 0xFF // Output data
+#define AK8975_HZL_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the AK8975_O_HZH register.
+//
+//*****************************************************************************
+#define AK8975_HZH_M 0xFF // Output data
+#define AK8975_HZH_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the AK8975_O_ST2 register.
+//
+//*****************************************************************************
+#define AK8975_ST2_HOFL 0x08 // Magnetic sensor overflow
+#define AK8975_ST2_DERR 0x04 // Data error
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the AK8975_O_CNTL register.
+//
+//*****************************************************************************
+#define AK8975_CNTL_MODE_M 0x0F // Operation mode
+#define AK8975_CNTL_MODE_POWER_DOWN \
+ 0x00 // Power-down mode
+#define AK8975_CNTL_MODE_SINGLE 0x01 // Single measurement mode
+#define AK8975_CNTL_MODE_SELF_TEST \
+ 0x08 // Self-test mode
+#define AK8975_CNTL_MODE_FUSE_ROM \
+ 0x0F // Fuse ROM access mode
+#define AK8975_CNTL_MODE_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the AK8975_O_ASTC register.
+//
+//*****************************************************************************
+#define AK8975_ASTC_SELF 0x40 // Generate magnetic field for
+ // self-test
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the AK8975_O_ASAX register.
+//
+//*****************************************************************************
+#define AK8975_ASAX_M 0xFF // X-axis sensitivity adjustment
+#define AK8975_ASAX_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the AK8975_O_ASAY register.
+//
+//*****************************************************************************
+#define AK8975_ASAY_M 0xFF // Y-axis sensitivity adjustment
+#define AK8975_ASAY_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the AK8975_O_ASAZ register.
+//
+//*****************************************************************************
+#define AK8975_ASAZ_M 0xFF // Z-axis sensitivity adjustment
+#define AK8975_ASAZ_S 0
+
+#endif // __SENSORLIB_HW_AK8975_H__
diff --git a/sensorlib/hw_bmp180.h b/sensorlib/hw_bmp180.h
new file mode 100644
index 0000000..7f8e3fe
--- /dev/null
+++ b/sensorlib/hw_bmp180.h
@@ -0,0 +1,349 @@
+//*****************************************************************************
+//
+// hw_bmp180.h - Macros used when accessing the Bosch BMP180 barometric
+// pressure sensor.
+//
+// Copyright (c) 2013-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
+//
+//*****************************************************************************
+
+#ifndef __SENSORLIB_HW_BMP180_H__
+#define __SENSORLIB_HW_BMP180_H__
+
+//*****************************************************************************
+//
+// The following are defines for the BMP180 register addresses.
+//
+//*****************************************************************************
+#define BMP180_O_AC1_MSB 0xAA // AC1 MSB register
+#define BMP180_O_AC1_LSB 0xAB // AC1 LSB register
+#define BMP180_O_AC2_MSB 0xAC // AC2 MSB register
+#define BMP180_O_AC2_LSB 0xAD // AC2 LSB register
+#define BMP180_O_AC3_MSB 0xAE // AC3 MSB register
+#define BMP180_O_AC3_LSB 0xAF // AC3 LSB register
+#define BMP180_O_AC4_MSB 0xB0 // AC4 MSB register
+#define BMP180_O_AC4_LSB 0xB1 // AC4 LSB register
+#define BMP180_O_AC5_MSB 0xB2 // AC5 MSB register
+#define BMP180_O_AC5_LSB 0xB3 // AC5 LSB register
+#define BMP180_O_AC6_MSB 0xB4 // AC6 MSB register
+#define BMP180_O_AC6_LSB 0xB5 // AC6 LSB register
+#define BMP180_O_B1_MSB 0xB6 // B1 MSB register
+#define BMP180_O_B1_LSB 0xB7 // B1 LSB register
+#define BMP180_O_B2_MSB 0xB8 // B2 MSB register
+#define BMP180_O_B2_LSB 0xB9 // B2 LSB register
+#define BMP180_O_MB_MSB 0xBA // MB MSB register
+#define BMP180_O_MB_LSB 0xBB // MB LSB register
+#define BMP180_O_MC_MSB 0xBC // MC MSB register
+#define BMP180_O_MC_LSB 0xBD // MC LSB register
+#define BMP180_O_MD_MSB 0xBE // MD MSB register
+#define BMP180_O_MD_LSB 0xBF // MD LSB register
+#define BMP180_O_ID 0xD0 // Device ID register
+#define BMP180_O_SOFT_RESET 0xE0 // Soft reset register
+#define BMP180_O_CTRL_MEAS 0xF4 // Measurement control register
+#define BMP180_O_OUT_MSB 0xF6 // ADC data MSB register
+#define BMP180_O_OUT_LSB 0xF7 // ADC data LSB register
+#define BMP180_O_OUT_XLSB 0xF8 // ADC data XLSB register
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the BMP180_O_AC1_MSB
+// register.
+//
+//*****************************************************************************
+#define BMP180_AC1_MSB_M 0xFF // MSB of AC1 calibration
+ // coefficient
+#define BMP180_AC1_MSB_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the BMP180_O_AC1_LSB
+// register.
+//
+//*****************************************************************************
+#define BMP180_AC1_LSB_M 0xFF // LSB of AC1 calibration
+ // coefficient
+#define BMP180_AC1_LSB_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the BMP180_O_AC2_MSB
+// register.
+//
+//*****************************************************************************
+#define BMP180_AC2_MSB_M 0xFF // MSB of AC2 calibration
+ // coefficient
+#define BMP180_AC2_MSB_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the BMP180_O_AC2_LSB
+// register.
+//
+//*****************************************************************************
+#define BMP180_AC2_LSB_M 0xFF // LSB of AC2 calibration
+ // coefficient
+#define BMP180_AC2_LSB_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the BMP180_O_AC3_MSB
+// register.
+//
+//*****************************************************************************
+#define BMP180_AC3_MSB_M 0xFF // MSB of AC3 calibration
+ // coefficient
+#define BMP180_AC3_MSB_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the BMP180_O_AC3_LSB
+// register.
+//
+//*****************************************************************************
+#define BMP180_AC3_LSB_M 0xFF // LSB of AC3 calibration
+ // coefficient
+#define BMP180_AC3_LSB_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the BMP180_O_AC4_MSB
+// register.
+//
+//*****************************************************************************
+#define BMP180_AC4_MSB_M 0xFF // MSB of AC4 calibration
+ // coefficient
+#define BMP180_AC4_MSB_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the BMP180_O_AC4_LSB
+// register.
+//
+//*****************************************************************************
+#define BMP180_AC4_LSB_M 0xFF // LSB of AC4 calibration
+ // coefficient
+#define BMP180_AC4_LSB_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the BMP180_O_AC5_MSB
+// register.
+//
+//*****************************************************************************
+#define BMP180_AC5_MSB_M 0xFF // MSB of AC5 calibration
+ // coefficient
+#define BMP180_AC5_MSB_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the BMP180_O_AC5_LSB
+// register.
+//
+//*****************************************************************************
+#define BMP180_AC5_LSB_M 0xFF // LSB of AC5 calibration
+ // coefficient
+#define BMP180_AC5_LSB_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the BMP180_O_AC6_MSB
+// register.
+//
+//*****************************************************************************
+#define BMP180_AC6_MSB_M 0xFF // MSB of AC6 calibration
+ // coefficient
+#define BMP180_AC6_MSB_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the BMP180_O_AC6_LSB
+// register.
+//
+//*****************************************************************************
+#define BMP180_AC6_LSB_M 0xFF // LSB of AC6 calibration
+ // coefficient
+#define BMP180_AC6_LSB_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the BMP180_O_B1_MSB
+// register.
+//
+//*****************************************************************************
+#define BMP180_B1_MSB_M 0xFF // MSB of B1 calibration
+ // coefficient
+#define BMP180_B1_MSB_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the BMP180_O_B1_LSB
+// register.
+//
+//*****************************************************************************
+#define BMP180_B1_LSB_M 0xFF // LSB of B1 calibration
+ // coefficient
+#define BMP180_B1_LSB_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the BMP180_O_B2_MSB
+// register.
+//
+//*****************************************************************************
+#define BMP180_B2_MSB_M 0xFF // MSB of B2 calibration
+ // coefficient
+#define BMP180_B2_MSB_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the BMP180_O_B2_LSB
+// register.
+//
+//*****************************************************************************
+#define BMP180_B2_LSB_M 0xFF // LSB of B2 calibration
+ // coefficient
+#define BMP180_B2_LSB_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the BMP180_O_MB_MSB
+// register.
+//
+//*****************************************************************************
+#define BMP180_MB_MSB_M 0xFF // MSB of MB calibration
+ // coefficient
+#define BMP180_MB_MSB_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the BMP180_O_MB_LSB
+// register.
+//
+//*****************************************************************************
+#define BMP180_MB_LSB_M 0xFF // LSB of MB calibration
+ // coefficient
+#define BMP180_MB_LSB_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the BMP180_O_MC_MSB
+// register.
+//
+//*****************************************************************************
+#define BMP180_MC_MSB_M 0xFF // MSB of MC calibration
+ // coefficient
+#define BMP180_MC_MSB_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the BMP180_O_MC_LSB
+// register.
+//
+//*****************************************************************************
+#define BMP180_MC_LSB_M 0xFF // LSB of MC calibration
+ // coefficient
+#define BMP180_MC_LSB_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the BMP180_O_MD_MSB
+// register.
+//
+//*****************************************************************************
+#define BMP180_MD_MSB_M 0xFF // MSB of MD calibration
+ // coefficient
+#define BMP180_MD_MSB_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the BMP180_O_MD_LSB
+// register.
+//
+//*****************************************************************************
+#define BMP180_MD_LSB_M 0xFF // LSB of MD calibration
+ // coefficient
+#define BMP180_MD_LSB_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the BMP180_O_ID register.
+//
+//*****************************************************************************
+#define BMP180_ID_M 0xFF // Device ID
+#define BMP180_ID_BMP180 0x55 // BMP180
+#define BMP180_ID_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the BMP180_O_SOFT_RESET
+// register.
+//
+//*****************************************************************************
+#define BMP180_SOFT_RESET_M 0xFF // Soft reset value
+#define BMP180_SOFT_RESET_VALUE 0xB6 // Request a soft reset
+#define BMP180_SOFT_RESET_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the BMP180_O_CTRL_MEAS
+// register.
+//
+//*****************************************************************************
+#define BMP180_CTRL_MEAS_OSS_M 0xC0 // Oversampling ratio
+#define BMP180_CTRL_MEAS_OSS_1 0x00 // Single sampling
+#define BMP180_CTRL_MEAS_OSS_2 0x40 // 2x oversampling
+#define BMP180_CTRL_MEAS_OSS_4 0x80 // 4x oversampling
+#define BMP180_CTRL_MEAS_OSS_8 0xC0 // 8x oversampling
+#define BMP180_CTRL_MEAS_SCO 0x20 // Start of conversion
+#define BMP180_CTRL_MEAS_M 0x1F // Measurement control
+#define BMP180_CTRL_MEAS_TEMPERATURE \
+ 0x0E // Temperature measurement
+#define BMP180_CTRL_MEAS_PRESSURE \
+ 0x14 // Pressure measurement
+#define BMP180_CTRL_MEAS_OSS_S 6
+#define BMP180_CTRL_MEAS_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the BMP180_O_OUT_MSB
+// register.
+//
+//*****************************************************************************
+#define BMP180_OUT_MSB_M 0xFF // Bits [20:13] of the ADC data
+#define BMP180_OUT_MSB_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the BMP180_O_OUT_LSB
+// register.
+//
+//*****************************************************************************
+#define BMP180_OUT_LSB_M 0xFF // Bits [12:5] of the ADC data
+#define BMP180_OUT_LSB_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the BMP180_O_OUT_XLSB
+// register.
+//
+//*****************************************************************************
+#define BMP180_OUT_XLSB_M 0xF8 // Bits [4:0] of the ADC data
+#define BMP180_OUT_XLSB_S 3
+
+#endif // __SENSORLIB_HW_BMP180_H__
diff --git a/sensorlib/hw_bq27510g3.h b/sensorlib/hw_bq27510g3.h
new file mode 100644
index 0000000..f0b3309
--- /dev/null
+++ b/sensorlib/hw_bq27510g3.h
@@ -0,0 +1,148 @@
+//*****************************************************************************
+//
+// hw_bq27510g3.h - Macros used when accessing the TI BQ27510-G3 Fuel Gauge
+//
+// Copyright (c) 2013-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
+//
+//*****************************************************************************
+
+#ifndef __SENSORLIB_HW_BQ27510G3_H__
+#define __SENSORLIB_HW_BQ27510G3_H__
+
+//*****************************************************************************
+//
+// The following are defines for the BQ27510G3 register addresses
+//
+//*****************************************************************************
+#define BQ27510G3_O_CNTL_LSB 0x00 // System Control Register LSB
+#define BQ27510G3_O_CNTL_MSB 0x01 // System Control Register MSB
+#define BQ27510G3_O_AT_RATE_LSB 0x02 // Discharge current value LSB
+#define BQ27510G3_O_AT_RATE_MSB 0x03 // Discharge current value MSB
+#define BQ27510G3_O_AT_RATE_TTE_LSB \
+ 0x04 // Remaining operating time of
+ // battery with current AT_RATE LSB
+#define BQ27510G3_O_AT_RATE_TTE_MSB \
+ 0x05 // Remaining operating time of
+ // battery with current AT_RATE MSB
+#define BQ27510G3_O_TEMP_LSB 0x06 // Battery temperature LSB
+#define BQ27510G3_O_TEMP_MSB 0x07 // Battery temperature MSB
+#define BQ27510G3_O_VOLT_LSB 0x08 // Battery cell-pack voltage LSB
+#define BQ27510G3_O_VOLT_MSB 0x09 // Battery cell-pack voltage MSB
+#define BQ27510G3_O_FLAGS_LSB 0x0A // Holds various operating status
+ // value of gas-guage LSB
+#define BQ27510G3_O_FLAGS_MSB 0x0B // Holds various operating status
+ // value of gas-guage MSB
+#define BQ27510G3_O_NOM_AV_CAP_LSB \
+ 0x0C // Uncompensated battery capacity
+ // remaining LSB
+#define BQ27510G3_O_NOM_AV_CAP_MSB \
+ 0x0D // Uncompensated battery capacity
+ // remaining MSB
+#define BQ27510G3_O_FULL_AV_CAP_LSB \
+ 0x0E // Uncompensated capacity of fully
+ // charged battery LSB
+#define BQ27510G3_O_FULL_AV_CAP_MSB \
+ 0x0F // Uncompensated capacity of fully
+ // charged battery MSB
+#define BQ27510G3_O_REM_CAP_LSB 0x10 // Compensated battery capacity
+ // remaining LSB
+#define BQ27510G3_O_REM_CAP_MSB 0x11 // Compensated battery capacity
+ // remaining MSB
+#define BQ27510G3_O_FULL_CHRG_CAP_LSB \
+ 0x12 // Compensated battery capacity
+ // when fully charged LSB
+#define BQ27510G3_O_FULL_CHRG_CAP_MSB \
+ 0x13 // Compensated battery capacity
+ // when fully charged MSB
+#define BQ27510G3_O_AVG_I_LSB 0x14 // Average current flow through
+ // sense resistor LSB
+#define BQ27510G3_O_AVG_I_MSB 0x15 // Average current flow through
+ // sense resistor MSB
+#define BQ27510G3_O_TTE_LSB 0x16 // Predicted remaining battery life
+ // (minutes) LSB
+#define BQ27510G3_O_TTE_MSB 0x17 // Predicted remaining battery life
+ // (minutes) MSB
+#define BQ27510G3_O_STBY_I_LSB 0x18 // Standbye current through sense
+ // resistor LSB
+#define BQ27510G3_O_STBY_I_MSB 0x19 // Standbye current through sense
+ // resistor MSB
+#define BQ27510G3_O_STBY_TTE_LSB \
+ 0x1A // Predicted remaining standby
+ // battery life LSB
+#define BQ27510G3_O_STBY_TTE_MSB \
+ 0x1B // Predicted remaining standby
+ // battery life MSB
+#define BQ27510G3_O_STATE_OF_HEALTH_LSB \
+ 0x1C // State of health (percent) LSB
+#define BQ27510G3_O_STATE_OF_HEALTH_MSB \
+ 0x1D // State of health (percent) MSB
+#define BQ27510G3_O_CYC_COUNT_LSB \
+ 0x1E // Number of battery cycles
+ // experienced LSB
+#define BQ27510G3_O_CYC_COUNT_MSB \
+ 0x1F // Number of battery cycles
+ // experienced MSB
+#define BQ27510G3_O_STATE_OF_CHRG_LSB \
+ 0x20 // State of charge (percent) LSB
+#define BQ27510G3_O_STATE_OF_CHRG_MSB \
+ 0x21 // State of charge (percent) MSB
+#define BQ27510G3_O_INST_I_LSB 0x22 // Instananeous current flow
+ // through sense resistor LSB
+#define BQ27510G3_O_INST_I_MSB 0x23 // Instananeous current flow
+ // through sense resistor MSB
+#define BQ27510G3_O_INT_TEMP_LSB \
+ 0x28 // Internal tmeperature LSB
+#define BQ27510G3_O_INT_TEMP_MSB \
+ 0x29 // Internal tmeperature MSB
+#define BQ27510G3_O_RES_SCALE_LSB \
+ 0x2A // Resistance Scale LSB
+#define BQ27510G3_O_RES_SCALE_MSB \
+ 0x2B // Resistance Scale MSB
+#define BQ27510G3_O_OP_CFG_LSB 0x2C // Operating Configuration LSB
+#define BQ27510G3_O_OP_CFG_MSB 0x2D // Operating Configuration MSB
+#define BQ27510G3_O_DCAP_LSB 0x2E // Designed capacity of battery LSB
+#define BQ27510G3_O_DCAP_MSB 0x2F // Designed capacity of battery MSB
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the BQ27510G3_O_CNTL_LSB
+// register.
+//
+//*****************************************************************************
+#define BQ27510G3_CNTL_LSB_FUNC_M \
+ 0xFF // Functions
+#define BQ27510G3_CNTL_LSB_FUNC_STATUS \
+ 0x00 // reports DF checksum, hibernate,
+ // IT, etc
+#define BQ27510G3_CNTL_LSB_FUNC_DEVTYPE \
+ 0x01 // reports device type (for
+ // example: 0x0520)
+#define BQ27510G3_CNTL_LSB_FUNC_FWVER \
+ 0x02 // reports firmware version on the
+ // device type
+#define BQ27510G3_CNTL_LSB_FUNC_PREVCMD \
+ 0x07 // reports previous Control()
+ // subcommand code
+#define BQ27510G3_CNTL_LSB_FUNC_RESET \
+ 0x41 // forces a full reset of the fuel
+ // gauge
+#define BQ27510G3_CNTL_LSB_FUNC_S \
+ 0
+
+#endif // __SENSORLIB_HW_BQ27510G3_H__
diff --git a/sensorlib/hw_cm3218.h b/sensorlib/hw_cm3218.h
new file mode 100644
index 0000000..87f959b
--- /dev/null
+++ b/sensorlib/hw_cm3218.h
@@ -0,0 +1,96 @@
+//*****************************************************************************
+//
+// hw_cm3218.h - Macros used for accessing the Capella CM3218 ambient light
+// sensor
+//
+// Copyright (c) 2013-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
+//
+//*****************************************************************************
+
+#ifndef __SENSORLIB_HW_CM3218_H__
+#define __SENSORLIB_HW_CM3218_H__
+
+//*****************************************************************************
+//
+// The following are defines for the CM3218 Commands and Registers
+//
+//*****************************************************************************
+#define CM3218_CMD_CONFIG 0x00 // Configure sensitivity,
+ // integration time, persistence
+ // protect, interrupts, and power
+#define CM3218_CMD_HIGH_THRESHOLD \
+ 0x01 // High threshold window setting
+#define CM3218_CMD_LOW_THRESHOLD \
+ 0x02 // Low threshold window setting
+#define CM3218_CMD_ALS_DATA 0x04 // Read ambient light data
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the CM3218_CMD_CONFIG
+// register.
+//
+//*****************************************************************************
+#define CM3218_CMD_CONFIG_SM_M 0x1800 // ALS sensitivity mode selection
+#define CM3218_CMD_CONFIG_SM_10 0x0000 // Sensitivty * 1.0
+#define CM3218_CMD_CONFIG_SM_20 0x0800 // Sensitivty * 2.0
+#define CM3218_CMD_CONFIG_SM_05 0x1000 // Sensitivty * 0.5
+#define CM3218_CMD_CONFIG_SM_RSVD \
+ 0x1800 // Reserved
+#define CM3218_CMD_CONFIG_IT_M 0x00C0 // ALS integration time setting
+#define CM3218_CMD_CONFIG_IT_05 0x0000 // integration time 0.5T
+#define CM3218_CMD_CONFIG_IT_10 0x0040 // integration time 1.0T (default)
+#define CM3218_CMD_CONFIG_IT_20 0x0080 // integration time 2.0T
+#define CM3218_CMD_CONFIG_IT_40 0x00C0 // integration time 4.0T
+#define CM3218_CMD_CONFIG_PERS_M \
+ 0x0030 // ALS persistence protect number
+ // setting
+#define CM3218_CMD_CONFIG_PERS_1 \
+ 0x0000 // Persistence setting of 1
+#define CM3218_CMD_CONFIG_PERS_2 \
+ 0x0010 // Persistence setting of 2
+#define CM3218_CMD_CONFIG_PERS_4 \
+ 0x0020 // Persistence setting of 4
+#define CM3218_CMD_CONFIG_PERS_8 \
+ 0x0030 // Persistence setting of 8
+#define CM3218_CMD_CONFIG_RSVD_M \
+ 0x00C // Reserved
+#define CM3218_CMD_CONFIG_RSVD_DEFAULT \
+ 0x0004 // Default setting
+#define CM3218_CMD_CONFIG_INT_M 0x2 // Interrupt Control
+#define CM3218_CMD_CONFIG_INT_DISABLE \
+ 0x0 // Disable interrupts
+#define CM3218_CMD_CONFIG_INT_ENABLE \
+ 0x2 // Enable interrupts
+#define CM3218_CMD_CONFIG_POWER_M \
+ 0x1 // Power Control
+#define CM3218_CMD_CONFIG_POWER_ON \
+ 0x0 // Power On
+#define CM3218_CMD_CONFIG_POWER_OFF \
+ 0x1 // Power Off
+#define CM3218_CMD_CONFIG_SM_S 11
+#define CM3218_CMD_CONFIG_IT_S 6
+#define CM3218_CMD_CONFIG_PERS_S \
+ 4
+#define CM3218_CMD_CONFIG_RSVD_S \
+ 2
+#define CM3218_CMD_CONFIG_INT_S 1
+#define CM3218_CMD_CONFIG_POWER_S \
+ 0
+
+#endif // __SENSORLIB_HW_CM3218_H__
diff --git a/sensorlib/hw_isl29023.h b/sensorlib/hw_isl29023.h
new file mode 100644
index 0000000..66f65ea
--- /dev/null
+++ b/sensorlib/hw_isl29023.h
@@ -0,0 +1,128 @@
+//*****************************************************************************
+//
+// hw_isl29023.h - Macros used when accessing the Intersil ISL29023 ambient
+// light sensor
+//
+// Copyright (c) 2013-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
+//
+//*****************************************************************************
+
+#ifndef __SENSORLIB_HW_ISL29023_H__
+#define __SENSORLIB_HW_ISL29023_H__
+
+//*****************************************************************************
+//
+// The following are defines for the ISL29023 Register Addresses
+//
+//*****************************************************************************
+#define ISL29023_O_CMD_I 0x00 // ISL29023 command register one
+#define ISL29023_O_CMD_II 0x01
+#define ISL29023_O_DATA_OUT_LSB 0x02 // Least significant byte of data
+#define ISL29023_O_DATA_OUT_MSB 0x03 // Most significant byte of data
+#define ISL29023_O_INT_LT_LSB 0x04 // Interrupt lower threshold least
+ // significant byte.
+#define ISL29023_O_INT_LT_MSB 0x05 // Interrupt lower threshold most
+ // significant byte.
+#define ISL29023_O_INT_HT_LSB 0x06 // Interrupt high threshold least
+ // significant byte.
+#define ISL29023_O_INT_HT_MSB 0x07 // Interrupt high threshold most
+ // signficant byte
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the ISL29023_O_CMD_I
+// register.
+//
+//*****************************************************************************
+#define ISL29023_CMD_I_OP_MODE_M \
+ 0xE0 // Operation Mode
+#define ISL29023_CMD_I_OP_MODE_POWER_DOWN \
+ 0x00 // Power Down the device (Default)
+#define ISL29023_CMD_I_OP_MODE_RESERVED_3 \
+ 0x0E // RESERVED
+#define ISL29023_CMD_I_OP_MODE_ALS_LOW \
+ 0x20 // Measure ALS once per integration
+ // cyle
+#define ISL29023_CMD_I_OP_MODE_IR_ONCE \
+ 0x40 // Measure IR once
+#define ISL29023_CMD_I_OP_MODE_RESERVED_1 \
+ 0x60 // RESERVED
+#define ISL29023_CMD_I_OP_MODE_RESERVED_2 \
+ 0x80 // RESERVED
+#define ISL29023_CMD_I_OP_MODE_ALS_CONT \
+ 0xA0 // Measure ambient light sensor
+ // continuously.
+#define ISL29023_CMD_I_OP_MODE_IR_CONT \
+ 0xC // Measure infrared sensor
+ // continuously
+#define ISL29023_CMD_I_INT_FLAG_M \
+ 0x04 // Interrupt flag
+#define ISL29023_CMD_I_INT_FLAG 0x04 // Interrupt flag
+#define ISL29023_CMD_I_INT_PERSIST_M \
+ 0x03 // Consecutive measurements outside
+ // threshold before interrupt
+#define ISL29023_CMD_I_INT_PERSIST_1 \
+ 0x00 // Interrupt on first cycle outside
+ // threshold
+#define ISL29023_CMD_I_INT_PERSIST_4 \
+ 0x01 // Interrupt on fourth cycle
+ // oustside threshold
+#define ISL29023_CMD_I_INT_PERSIST_8 \
+ 0x02 // Interrupt on eigth cycle outside
+ // threshold
+#define ISL29023_CMD_I_INT_PERSIST_16 \
+ 0x03 // Interrupt on sixteenth cycle
+ // outside threshold
+#define ISL29023_CMD_I_OP_MODE_S \
+ 5
+#define ISL29023_CMD_I_INT_FLAG_S \
+ 2
+#define ISL_29023_CMD_I_INT_PERSIST_S \
+ 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the ISL29023_O_CMD_II
+// register.
+//
+//*****************************************************************************
+#define ISL29023_CMD_II_ADC_RES_M \
+ 0x0C // ADC resolution setting
+#define ISL29023_CMD_II_ADC_RES_16 \
+ 0x00 // 16 bit resolution
+#define ISL29023_CMD_II_ADC_RES_12 \
+ 0x04 // 12 bit resolution
+#define ISL29023_CMD_II_ADC_RES_8 \
+ 0x08 // 8 bit resolution
+#define ISL29023_CMD_II_ADC_RES_4 \
+ 0x0C // 4 bit resolution
+#define ISL29023_CMD_II_RANGE_M 0x03 // Sensor Range Setting in Lux
+#define ISL29023_CMD_II_RANGE_1K \
+ 0x00 // 1000 lux range
+#define ISL29023_CMD_II_RANGE_4K \
+ 0x01 // 4000 lux range
+#define ISL29023_CMD_II_RANGE_16K \
+ 0x02 // 16000 lux range
+#define ISL29023_CMD_II_RANGE_64K \
+ 0x03 // 64000 lux range
+#define ISL29023_CMD_II_ADC_RES_S \
+ 2
+#define ISL29023_CMD_II_RANGE_S 0
+
+#endif // __SENSORLIB_HW_ISL29023_H__
diff --git a/sensorlib/hw_kxti9.h b/sensorlib/hw_kxti9.h
new file mode 100644
index 0000000..4ffc53a
--- /dev/null
+++ b/sensorlib/hw_kxti9.h
@@ -0,0 +1,619 @@
+//*****************************************************************************
+//
+// hw_kxti9.h - Macros used when accessing the Kionix KXTI9 accelerometer.
+//
+// Copyright (c) 2013-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
+//
+//*****************************************************************************
+
+#ifndef __SENSORLIB_HW_KXTI9_H__
+#define __SENSORLIB_HW_KXTI9_H__
+
+//*****************************************************************************
+//
+// The following are defines for the KXTI9 register addresses.
+//
+//*****************************************************************************
+#define KXTI9_O_XOUT_HFP_L 0x00 // X-axis high-pass data LSB
+ // register
+#define KXTI9_O_XOUT_HFP_H 0x01 // X-axis high-pass data MSB
+ // register
+#define KXTI9_O_YOUT_HFP_L 0x02 // Y-axis high-pass data LSB
+ // register
+#define KXTI9_O_YOUT_HFP_H 0x03 // Y-axis high-pass data MSB
+ // register
+#define KXTI9_O_ZOUT_HFP_L 0x04 // Z-axis high-pass data LSB
+ // register
+#define KXTI9_O_ZOUT_HFP_H 0x05 // Z-axis high-pass data MSB
+ // register
+#define KXTI9_O_XOUT_L 0x06 // X-axis data LSB register
+#define KXTI9_O_XOUT_H 0x07 // X-axis data MSB register
+#define KXTI9_O_YOUT_L 0x08 // Y-axis data LSB register
+#define KXTI9_O_YOUT_H 0x09 // Y-axis data MSB register
+#define KXTI9_O_ZOUT_L 0x0A // Z-axis data LSB register
+#define KXTI9_O_ZOUT_H 0x0B // Z-axis data MSB register
+#define KXTI9_O_DCST_RESP 0x0C // Digital Control Status register
+#define KXTI9_O_WHO_AM_I 0x0F // Who Am I register
+#define KXTI9_O_TILT_POS_CUR 0x10 // Current tilt position register
+#define KXTI9_O_TILT_POS_PRE 0x11 // Previous tilt position register
+#define KXTI9_O_INT_SRC1 0x15 // Interrupt source register 1
+#define KXTI9_O_INT_SRC2 0x16 // Interrupt source register2
+#define KXTI9_O_STATUS 0x18 // Status register
+#define KXTI9_O_INT_REL 0x1A // Interrupt clear/release register
+#define KXTI9_O_CTRL1 0x1B // Control register 1
+#define KXTI9_O_CTRL2 0x1C // Control register 2
+#define KXTI9_O_CTRL3 0x1D // Control register 3
+#define KXTI9_O_INT_CTRL1 0x1E // Interrupt control register 1
+#define KXTI9_O_INT_CTRL2 0x1F // Interrupt control register 2
+#define KXTI9_O_INT_CTRL3 0x20 // Interrupt control register 3
+#define KXTI9_O_DATA_CTRL 0x21 // Data control register
+#define KXTI9_O_TILT_TIMER 0x28 // Tilt timer register
+#define KXTI9_O_WUF_TIMER 0x29 // Wake-up timer register
+#define KXTI9_O_TDT_TIMER 0x2B // TDT timer register
+#define KXTI9_O_TDT_H_THRESH 0x2C // Jerk threshold high register
+#define KXTI9_O_TDT_L_THRESH 0x2D // Jerk threshold low register
+#define KXTI9_O_TDT_TAP_TIMER 0x2E // TDT tap timer register
+#define KXTI9_O_TDT_TOTAL_TIMER 0x2F // TDT double tap timer register
+#define KXTI9_O_TDT_LATENCY_TIMER \
+ 0x30 // TDT tap latency timer register
+#define KXTI9_O_TDT_WINDOW_TIMER \
+ 0x31 // TDT tap window timer register
+#define KXTI9_O_BUF_CTRL1 0x32 // Buffer control 1 register
+#define KXTI9_O_BUF_CTRL2 0x33 // Buffer control 2 register
+#define KXTI9_O_STATUS1 0x34 // Buffer status 1 register
+#define KXTI9_O_STATUS2 0x35 // Buffer status 2 register
+#define KXTI9_O_BUF_CLEAR 0x36 // Buffer status clear register
+#define KXTI9_O_SELF_TEST 0x3A // Self-test register
+#define KXTI9_O_WUF_THRESH 0x5A // Wake-up threshold register
+#define KXTI9_O_TILT_ANGLE 0x5C // Tilt angle register
+#define KXTI9_O_HYST_SET 0x5F // Hysteresis set register
+#define KXTI9_O_BUF_READ 0x7F // Buffer read register
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the KXTI9_O_XOUT_HPF_L
+// register.
+//
+//*****************************************************************************
+#define KXTI9_XOUT_HPF_L_M 0xF0 // Bits [3:0] of high-pass filtered
+ // X-axis data
+#define KXTI9_XOUT_HPF_L_S 4
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the KXTI9_O_XOUT_HPF_H
+// register.
+//
+//*****************************************************************************
+#define KXTI9_XOUT_HPF_H_M 0xFF // Bits [11:4] of high-pass
+ // filtered X-axis data
+#define KXTI9_XOUT_HPF_H_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the KXTI9_O_YOUT_HPF_L
+// register.
+//
+//*****************************************************************************
+#define KXTI9_YOUT_HPF_L_M 0xF0 // Bits [3:0] of high-pass filtered
+ // Y-axis data
+#define KXTI9_YOUT_HPF_L_S 4
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the KXTI9_O_YOUT_HPF_H
+// register.
+//
+//*****************************************************************************
+#define KXTI9_YOUT_HPF_H_M 0xFF // Bits [11:4] of high-pass
+ // filtered Y-axis data
+#define KXTI9_YOUT_HPF_H_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the KXTI9_O_ZOUT_HPF_L
+// register.
+//
+//*****************************************************************************
+#define KXTI9_ZOUT_HPF_L_M 0xF0 // Bits [3:0] of high-pass filtered
+ // Z-axis data
+#define KXTI9_ZOUT_HPF_L_S 4
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the KXTI9_O_ZOUT_HPF_H
+// register.
+//
+//*****************************************************************************
+#define KXTI9_ZOUT_HPF_H_M 0xFF // Bits [11:4] of high-pass
+ // filtered Z-axis data
+#define KXTI9_ZOUT_HPF_H_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the KXTI9_O_XOUT_L register.
+//
+//*****************************************************************************
+#define KXTI9_XOUT_L_M 0xF0 // Bits [3:0] of X-axis data
+#define KXTI9_XOUT_L_S 4
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the KXTI9_O_XOUT_H register.
+//
+//*****************************************************************************
+#define KXTI9_XOUT_H_M 0xFF // Bits [11:4] of X-axis data
+#define KXTI9_XOUT_H_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the KXTI9_O_YOUT_L register.
+//
+//*****************************************************************************
+#define KXTI9_YOUT_L_M 0xF0 // Bits [3:0] of Y-axis data
+#define KXTI9_YOUT_L_S 4
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the KXTI9_O_YOUT_H register.
+//
+//*****************************************************************************
+#define KXTI9_YOUT_H_M 0xFF // Bits [11:4] of Y-axis data
+#define KXTI9_YOUT_H_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the KXTI9_O_ZOUT_L register.
+//
+//*****************************************************************************
+#define KXTI9_ZOUT_L_M 0xF0 // Bits [3:0] of Z-axis data
+#define KXTI9_ZOUT_L_S 4
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the KXTI9_O_ZOUT_H register.
+//
+//*****************************************************************************
+#define KXTI9_ZOUT_H_M 0xFF // Bits [11:4] of Z-axis data
+#define KXTI9_ZOUT_H_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the KXTI9_O_DCST_RESP
+// register.
+//
+//*****************************************************************************
+#define KXTI9_DCST_RESP_M 0xFF // Check field
+#define KXTI9_DCST_RESP_DEF 0x55 // Default response
+#define KXTI9_DCST_RESP_INIT 0xAA // Post-initialization response
+#define KXTI9_DCST_RESP_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the KXTI9_O_WHO_AM_I
+// register.
+//
+//*****************************************************************************
+#define KXTI9_DCST_RESP_M 0xFF // Identification field
+#define KXTI9_WHO_AM_I_KXTI9 0x04 // KXTI9
+#define KXTI9_WHO_AM_I_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the KXTI9_O_TILT_POS_CUR
+// register.
+//
+//*****************************************************************************
+#define KXTI9_TILT_POS_CUR_LE 0x20 // Left state (X-)
+#define KXTI9_TILT_POS_CUR_RI 0x10 // Right state (X+)
+#define KXTI9_TILT_POS_CUR_DO 0x08 // Down state (Y-)
+#define KXTI9_TILT_POS_CUR_UP 0x04 // Up state (Y+)
+#define KXTI9_TILT_POS_CUR_FD 0x02 // Face-down state (Z-)
+#define KXTI9_TILT_POS_CUR_FU 0x01 // Face-up state (Z+)
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the KXTI9_O_TILT_POS_PRE
+// register.
+//
+//*****************************************************************************
+#define KXTI9_TILT_POS_PRE_LE 0x20 // Left state (X-)
+#define KXTI9_TILT_POS_PRE_RI 0x10 // Right state (X+)
+#define KXTI9_TILT_POS_PRE_DO 0x08 // Down state (Y-)
+#define KXTI9_TILT_POS_PRE_UP 0x04 // Up state (Y+)
+#define KXTI9_TILT_POS_PRE_FD 0x02 // Face-down state (Z-)
+#define KXTI9_TILT_POS_PRE_FU 0x01 // Face-up state (Z+)
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the KXTI9_O_INT_SRC1
+// register.
+//
+//*****************************************************************************
+#define KXTI9_INT_SRC1_TLE 0x20 // X negative (X-) reported
+#define KXTI9_INT_SRC1_TRI 0x10 // X positive (X+) reported
+#define KXTI9_INT_SRC1_TDO 0x08 // Y negative (Y-) reported
+#define KXTI9_INT_SRC1_TUP 0x04 // Y positive (Y+) reported
+#define KXTI9_INT_SRC1_TFD 0x02 // Z negative (Z-) reported
+#define KXTI9_INT_SRC1_TFU 0x01 // Z positive (Z+) reported
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the KXTI9_O_INT_SRC2
+// register.
+//
+//*****************************************************************************
+#define KXTI9_INT_SRC2_WMI 0x20 // Buffer sample threshold reached
+#define KXTI9_INT_SRC2_DRDY 0x10 // New accel data ready
+#define KXTI9_INT_SRC2_TDTS_M 0x0C // Tap event detected
+#define KXTI9_INT_SRC2_TDTS_NONE \
+ 0x00 // No tap event
+#define KXTI9_INT_SRC2_TDTS_SINGLE \
+ 0x01 // Single tap event
+#define KXTI9_INT_SRC2_TDTS_DOUBLE \
+ 0x02 // Double tap event
+#define KXTI9_INT_SRC2_TDTS_DIRECTIONAL \
+ 0x03 // Double tap event
+#define KXTI9_INT_SRC2_WUFS 0x02 // Wake-up
+#define KXTI9_INT_SRC2_TPS 0x01 // Tilt position change
+#define KXTI9_INT_SRC2_S 2
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the KXTI9_O_STATUS register.
+//
+//*****************************************************************************
+#define KXTI9_STATUS_INT 0x10 // Interrupt event
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the KXTI9_O_INT_REL
+// register.
+//
+//*****************************************************************************
+#define KXTI9_INT_REL_M 0xFF // Data is unpredictable
+#define KXTI9_INT_REL_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the KXTI9_O_CTRL1 register.
+//
+//*****************************************************************************
+#define KXTI9_CTRL1_PC1 0x80 // Operating mode
+#define KXTI9_CTRL1_RES 0x40 // Performance (resolution) mode
+#define KXTI9_CTRL1_DRDYE 0x20 // New data interrupt enable
+#define KXTI9_CTRL1_GSEL_M 0x18 // Acceleration range
+#define KXTI9_CTRL1_GSEL_2G 0x00 // +/-2g
+#define KXTI9_CTRL1_GSEL_4G 0x01 // +/-4g
+#define KXTI9_CTRL1_GSEL_8G 0x02 // +/-8g
+#define KXTI9_CTRL1_TDTE 0x04 // Directional tap enable
+#define KXTI9_CTRL1_WUFE 0x02 // Wake-up enable
+#define KXTI9_CTRL1_TPE 0x01 // Tilt position enable
+#define KXTI9_CTRL1_GSEL_S 3
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the KXTI9_O_CTRL2 register.
+//
+//*****************************************************************************
+#define KXTI9_CTRL2_OTDTH 0x80 // Output data rate selection for
+ // directional tap
+#define KXTI9_CTRL2_LEM 0x20 // Left state tilt enable
+#define KXTI9_CTRL2_RIM 0x10 // Right state tilt enable
+#define KXTI9_CTRL2_DOM 0x08 // Down state tilt enable
+#define KXTI9_CTRL2_UPM 0x04 // Up state tilt enable
+#define KXTI9_CTRL2_FDM 0x02 // Face-down state tilt enable
+#define KXTI9_CTRL2_FUM 0x01 // Face-up state tilt enable
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the KXTI9_O_CTRL3 register.
+//
+//*****************************************************************************
+#define KXTI9_CTRL3_SRST 0x80 // Initiate software reset
+#define KXTI9_CTRL3_OTP_M 0x60 // Output data rate for tilt
+ // position
+#define KXTI9_CTRL3_OTP_1_6HZ 0x00 // Data rate is 1.6Hz
+#define KXTI9_CTRL3_OTP_6_3HZ 0x01 // Data rate is 6.3Hz
+#define KXTI9_CTRL3_OTP_12_5HZ 0x02 // Data rate is 12.5Hz
+#define KXTI9_CTRL3_OTP_50HZ 0x03 // Data rate is 50Hz
+#define KXTI9_CTRL3_OWUF_M 0x60 // Output data rate for motion
+ // detection and high-pass outputs
+#define KXTI9_CTRL3_OWUF_25HZ 0x00 // Data rate is 25Hz
+#define KXTI9_CTRL3_OWUF_50HZ 0x01 // Data rate is 50Hz
+#define KXTI9_CTRL3_OWUF_100HZ 0x02 // Data rate is 100Hz
+#define KXTI9_CTRL3_OWUF_200HZ 0x03 // Data rate is 200Hz
+#define KXTI9_CTRL3_DCST 0x10 // Digital communication self-test
+#define KXTI9_CTRL3_OTDT_M 0x0C // Encoding values change based on
+ // value of OTDTH bit
+#define KXTI9_CTRL3_OTDT_0 0x00 // Encoding 0 is 50Hz or 12.5Hz
+#define KXTI9_CTRL3_OTDT_1 0x01 // Encoding 1 is 100Hz or 25Hz
+#define KXTI9_CTRL3_OTDT_2 0x02 // Encoding 2 is 200Hz or 800Hz
+#define KXTI9_CTRL3_OTDT_3 0x03 // Encoding 3 is 400Hz or 1600Hz
+#define KXTI9_CTRL3_OTP_S 5
+#define KXTI9_CTRL3_OTDT_S 2
+#define KXTI9_CTRL3_OWUF_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the KXTI9_O_INT_CTRL1
+// register.
+//
+//*****************************************************************************
+#define KXTI9_INT_CTRL1_IEN 0x20 // Interrupt pin enable
+#define KXTI9_INT_CTRL1_IEA 0x10 // Interrupt pin polarity
+#define KXTI9_INT_CTRL1_IEL 0x08 // Interrupt pin response
+#define KXTI9_INT_CTRL1_IEU 0x04 // Interrupt pin alternative
+ // response
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the KXTI9_O_INT_CTRL2
+// register.
+//
+//*****************************************************************************
+#define KXTI9_INT_CTRL2_XBW 0x80 // X-axis motion interrupt enable
+#define KXTI9_INT_CTRL2_YBW 0x40 // Y-axis motion interrupt enable
+#define KXTI9_INT_CTRL2_ZBW 0x20 // Z-axis motion interrupt enable
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the KXTI9_O_INT_CTRL3
+// register.
+//
+//*****************************************************************************
+#define KXTI9_INT_CTRL3_TMEN 0x40 // Tap masking scheme enable
+#define KXTI9_INT_CTRL3_TLEM 0x20 // X negative interrupt enable
+#define KXTI9_INT_CTRL3_TRIM 0x10 // X positive interrupt enable
+#define KXTI9_INT_CTRL3_TDOM 0x08 // Y negative interrupt enable
+#define KXTI9_INT_CTRL3_TUPM 0x04 // Y positive interrupt enable
+#define KXTI9_INT_CTRL3_TFDM 0x02 // Z negative interrupt enable
+#define KXTI9_INT_CTRL3_TFUM 0x01 // Z positive interrupt enable
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the KXTI9_O_DATA_CTRL
+// register.
+//
+//*****************************************************************************
+#define KXTI9_DATA_CTRL_HPFRO_M 0x30 // High-pass filter roll-off
+ // frequency
+#define KXTI9_DATA_CTRL_HPFRO_50HZ \
+ 0x00 // Roll-off at 50Hz
+#define KXTI9_DATA_CTRL_HPFRO_100HZ \
+ 0x01 // Roll-off at 100Hz
+#define KXTI9_DATA_CTRL_HPFRO_200HZ \
+ 0x02 // Roll-off at 200Hz
+#define KXTI9_DATA_CTRL_HPFRO_400HZ \
+ 0x03 // Roll-off at 400Hz
+#define KXTI9_DATA_CTRL_OSA_M 0x07 // Output data rate and roll-off
+ // for low-pass filter outputs
+#define KXTI9_DATA_CTRL_OSA_12_5HZ \
+ 0x00 // 12.5Hz data rate, 6.25Hz LPF
+ // roll-off
+#define KXTI9_DATA_CTRL_OSA_25HZ \
+ 0x01 // 25Hz data rate, 12.5Hz LPF
+ // roll-off
+#define KXTI9_DATA_CTRL_OSA_50HZ \
+ 0x02 // 50Hz data rate, 25Hz LPF
+ // roll-off
+#define KXTI9_DATA_CTRL_OSA_100HZ \
+ 0x03 // 100Hz data rate, 50Hz LPF
+ // roll-off
+#define KXTI9_DATA_CTRL_OSA_200HZ \
+ 0x04 // 200Hz data rate, 100Hz LPF
+ // roll-off
+#define KXTI9_DATA_CTRL_OSA_400HZ \
+ 0x05 // 400Hz data rate, 200Hz LPF
+ // roll-off
+#define KXTI9_DATA_CTRL_OSA_800HZ \
+ 0x06 // 800Hz data rate, 400Hz LPF
+ // roll-off
+#define KXTI9_DATA_CTRL_HPFRO_S 4
+#define KXTI9_DATA_CTRL_OSA_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the KXTI9_O_TILT_TIMER
+// register.
+//
+//*****************************************************************************
+#define KXTI9_TILT_TIMER_M 0xFF // Initial timer count
+#define KXTI9_TILT_TIMER_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the KXTI9_O_WUF_TIMER
+// register.
+//
+//*****************************************************************************
+#define KXTI9_WUF_TIMER_M 0xFF // Initial timer count
+#define KXTI9_WUF_TIMER_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the KXTI9_O_TDT_TIMER
+// register.
+//
+//*****************************************************************************
+#define KXTI9_TDT_TIMER_M 0xFF // Initial timer count
+#define KXTI9_TDT_TIMER_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the KXTI9_O_TDT_H_THRESH
+// register.
+//
+//*****************************************************************************
+#define KXTI9_TDT_H_THRESH_M 0xFF // Threshold high value
+#define KXTI9_TDT_H_THRESH_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the KXTI9_O_TDT_L_THRESH
+// register.
+//
+//*****************************************************************************
+#define KXTI9_TDT_L_THRESH_M 0xFF // Threshold low value
+#define KXTI9_TDT_L_THRESH_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the KXTI9_O_TDT_TAP_TIMER
+// register.
+//
+//*****************************************************************************
+#define KXTI9_TDT_TAP_TIMER_M 0xFF // Tap event counter
+#define KXTI9_TDT_TAP_TIMER_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the KXTI9_O_TDT_TOTAL_TIMER
+// register.
+//
+//*****************************************************************************
+#define KXTI9_TDT_TOTAL_TIMER_M 0xFF // Double tap event counter
+#define KXTI9_TDT_TOTAL_TIMER_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the
+// KXTI9_O_TDT_LATENCY_TIMER register.
+//
+//*****************************************************************************
+#define KXTI9_TDT_LATENCY_TIMER_M \
+ 0xFF // Tap event latency counter
+#define KXTI9_TDT_LATENCY_TIMER_S \
+ 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the KXTI9_O_TDT_WINDOW_TIMER
+// register.
+//
+//*****************************************************************************
+#define KXTI9_TDT_WINDOW_TIMER_M \
+ 0xFF // Tap event window counter
+#define KXTI9_TDT_WINDOW_TIMER_S \
+ 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the KXTI9_O_BUF_CTRL1
+// register.
+//
+//*****************************************************************************
+#define KXTI9_BUF_CTRL1_M 0x7F // Buffer sample threshold
+#define KXTI9_BUF_CTRL1_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the KXTI9_O_BUF_CTRL2
+// register.
+//
+//*****************************************************************************
+#define KXTI9_BUF_CTRL2_BUFE 0x80 // Buffer enable
+#define KXTI9_BUF_CTRL2_BUF_RES 0x40 // Buffer resolution
+#define KXTI9_BUF_CTRL2_BUF_M_M 0x03 // Buffer mode
+#define KXTI9_BUF_CTRL2_BUF_M_FIFO \
+ 0x00 // FIFO mode
+#define KXTI9_BUF_CTRL2_BUF_M_STREAM \
+ 0x01 // Stream mode
+#define KXTI9_BUF_CTRL2_BUF_M_TRIG \
+ 0x02 // Trigger mode
+#define KXTI9_BUF_CTRL2_BUF_M_FILO \
+ 0x03 // FILO mode
+#define KXTI9_BUF_CTRL2_BUF_M_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the KXTI9_O_STATUS1
+// register.
+//
+//*****************************************************************************
+#define KXTI9_STATUS1_SMP_LEV_M 0xFF // Number of bytes in sample buffer
+#define KXTI9_STATUS1_SMP_LEV_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the KXTI9_O_STATUS2
+// register.
+//
+//*****************************************************************************
+#define KXTI9_STATUS2_BUF_TRIG 0x80 // Trigger mode status
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the KXTI9_O_BUF_CLEAR
+// register.
+//
+//*****************************************************************************
+#define KXTI9_BUF_CLEAR_M 0xFF // Data is unpredictable
+#define KXTI9_BUF_CLEAR_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the KXTI9_O_SELF_TEST
+// register.
+//
+//*****************************************************************************
+#define KXTI9_SELF_TEST_M 0xFF // Writing 0xCA enables MEMS
+ // self-test
+#define KXTI9_SELF_TEST_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the KXTI9_O_WUF_THRESH
+// register.
+//
+//*****************************************************************************
+#define KXTI9_WUF_THRESH_M 0xFF // Acceleration wake-up threshold
+#define KXTI9_WUF_THRESH_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the KXTI9_O_TILT_ANGLE
+// register.
+//
+//*****************************************************************************
+#define KXTI9_TILT_ANGLE_M 0xFF // Tilt angle threshold
+#define KXTI9_TILT_ANGLE_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the KXTI9_O_HYST_SET
+// register.
+//
+//*****************************************************************************
+#define KXTI9_HYST_SET_RES_M 0xE0 // Factory set value - do not
+ // change
+#define KXTI9_HYST_SET_HYST_M 0x1F // Hysteresis angle
+#define KXTI9_HYST_SET_RES_S 5
+#define KXTI9_HYST_SET_HYST_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the KXTI9_O_BUF_READ
+// register.
+//
+//*****************************************************************************
+#define KXTI9_BUF_READ_M 0xFF // Read data from buffer
+#define KXTI9_BUF_READ_S 0
+
+#endif // __SENSORLIB_HW_KXTI9_H__
diff --git a/sensorlib/hw_l3gd20h.h b/sensorlib/hw_l3gd20h.h
new file mode 100644
index 0000000..4a9a459
--- /dev/null
+++ b/sensorlib/hw_l3gd20h.h
@@ -0,0 +1,468 @@
+//*****************************************************************************
+//
+// hw_l3gd20h.h - Macros used when accessing the ST L3GD20H gyroscope
+//
+// Copyright (c) 2013-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
+//
+//*****************************************************************************
+
+#ifndef __SENSORLIB_HW_L3GD20H_H__
+#define __SENSORLIB_HW_L3GD20H_H__
+
+//*****************************************************************************
+//
+// The following are defines for the L3GD20H register addresses
+//
+//*****************************************************************************
+#define L3GD20H_O_WHOAMI 0x0F // Device idenfitication register
+#define L3GD20H_O_CTRL1 0x20 // Control 1 - power settings
+#define L3GD20H_O_CTRL2 0x21 // control 2
+#define L3GD20H_O_CTRL3 0x22 // Control 3
+#define L3GD20H_O_CTRL4 0x23 // Control 4
+#define L3GD20H_O_CTRL5 0x24 // Control 5
+#define L3GD20H_O_REFERENCE 0x25 // Reference register
+#define L3GD20H_O_OUT_TEMP 0x26 // Temperature data; -1LSB/deg,
+ // two's complement
+#define L3GD20H_O_STATUS 0x27 // Status register
+#define L3GD20H_O_OUT_X_LSB 0x28 // X-axis LSB
+#define L3GD20H_O_OUT_X_MSB 0x29 // X-axis MSB
+#define L3GD20H_O_OUT_Y_LSB 0x2A // Y-axis LSB
+#define L3GD20H_O_OUT_Y_MSB 0x2B // Y-axis MSB
+#define L3GD20H_O_OUT_Z_LSB 0x2C // Z-axis LSB
+#define L3GD20H_O_OUT_Z_MSB 0x2D // Z-axis MSB
+#define L3GD20H_O_FIFO_CTRL 0x2E // FIFO control
+#define L3GD20H_O_FIFO_SRC 0x2F // FIFO_SRC register
+#define L3GD20H_O_IG_CFG 0x30 // Interrupt generation control
+#define L3GD20H_O_IG_SRC 0x31 // interrupt source register (read
+ // only)
+#define L3GD20H_O_IG_THS_XH 0x32 // Hi-X threshold
+#define L3GD20H_O_IG_THS_XL 0x33 // Lo-X threshold
+#define L3GD20H_O_IG_THS_TH 0x34 // Hi-Y threshold
+#define L3GD20H_O_IG_THS_TL 0x35 // Lo-Y threshold
+#define L3GD20H_O_IG_THS_ZH 0x36 // Hi-Z threshold
+#define L3GD20H_O_IG_THS_ZL 0x37 // Lo-X threshold
+#define L3GD20H_O_IG_DURATION 0x38 // Interrupt generation duration
+ // register
+#define L3GD20H_O_LOW_ODR 0x39 // Low-speed output data rate (ODR)
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the L3GD20H_O_CTRL1
+// register.
+//
+//*****************************************************************************
+#define L3GD20H_CTRL1_DR_M 0xC0 // ODR select, x8 if Low_ODR = 0
+#define L3GD20H_CTRL1_DR_12_5_HZ \
+ 0x00 // 12.5Hz or 100Hz
+#define L3GD20H_CTRL1_DR_25_HZ 0x40 // 25Hz or 200Hz
+#define L3GD20H_CTRL1_DR_50_HZ 0x80 // 50Hz or 400Hz
+#define L3GD20H_CTRL1_DR_800_HZ 0xC0 // 800Hz of Low_ODR=0, or 50Hz
+ // otherwise
+#define L3GD20H_CTRL1_BW_M 0x30 // Bandwidth select
+#define L3GD20H_CTRL1_POWER_M 0x08 // Power control
+#define L3GD20H_CTRL1_POWER_LOWPOW \
+ 0x00
+#define L3GD20H_CTRL1_POWER_NORMAL \
+ 0x08
+#define L3GD20H_CTRL1_AXIS_M 0x7 // Axis power control
+#define L3GD20H_CTRL1_AXIS_Y_EN 0x01 // Y-axis enable
+#define L3GD20H_CTRL1_AXIS_X_EN 0x02 // X-axis enable
+#define L3GD20H_CTRL1_AXIS_Z_EN 0x04 // Z-axis enable
+#define L3GD20H_CTRL1_DR_S 6
+#define L3GD20H_CTRL1_BW_S 4
+#define L3GD20H_CTRL1_AXIS_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the L3GD20H_O_CTRL2
+// register.
+//
+//*****************************************************************************
+#define L3GD20H_CTRL2_EXTREN_M 0x80 // edge sensitive
+#define L3GD20H_CTRL2_EXTREN_DIS \
+ 0x00
+#define L3GD20H_CTRL2_EXTREN_EN 0x80
+#define L3GD20H_CTRL2_LVLEN_M 0x40 // level sensitive
+#define L3GD20H_CTRL2_LVLEN_DIS 0x00
+#define L3GD20H_CTRL2_LVLEN_EN 0x40
+#define L3GD20H_CTRL2_HPM_M 0x30 // high pass filter mode selection
+#define L3GD20H_CTRL2_HPCF_M 0x0F // high pass cutoff frequency
+ // selection
+#define L3GD20H_CTRL2_HPM_S 4
+#define L3GD20H_CTRL2_HPCF_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the L3GD20H_O_CTRL3
+// register.
+//
+//*****************************************************************************
+#define L3GD20H_CTRL3_INT1_IG_M 0x80 // Interrupt enable on INT1 pin
+#define L3GD20H_CTRL3_INT1_IG_DIS \
+ 0x00
+#define L3GD20H_CTRL3_INT1_IG_EN \
+ 0x80
+#define L3GD20H_CTRL3_INT1_BOOT_M \
+ 0x40 // Boot status available on INT1
+ // pin.
+#define L3GD20H_CTRL3_INT1_BOOT_DIS \
+ 0x00
+#define L3GD20H_CTRL3_INT1_BOOT_EN \
+ 0x40
+#define L3GD20H_CTRL3_H_LACTIVE_M \
+ 0x20 // Interrupt active configuration
+ // on INT; default value: 0 (0:
+ // high; 1:low)
+#define L3GD20H_CTRL3_H_LACTIVE_HI \
+ 0x00
+#define L3GD20H_CTRL3_H_LACTIVE_LOW \
+ 0x20
+#define L3GD20H_CTRL3_DRIVE_TYPE_M \
+ 0x10 // Push- Pull / Open drain; default
+ // value: 0 (0: push-pull; 1: open
+ // drain)
+#define L3GD20H_CTRL3_DRIVE_TYPE_PP \
+ 0x00
+#define L3GD20H_CTRL3_DRIVE_TYPE_OD \
+ 0x10
+#define L3GD20H_CTRL3_INT2_DRDY_M \
+ 0x08 // Date Ready on DRDY/INT2 pin;
+ // default value: 0
+#define L3GD20H_CTRL3_INT2_DRDY_DIS \
+ 0x00
+#define L3GD20H_CTRL3_INT2_DRDY_EN \
+ 0x08
+#define L3GD20H_CTRL3_INT2_FTH_M \
+ 0x04 // FIFO Threshold interrupt on
+ // DRDY/INT2 pin; default value: 0
+#define L3GD20H_CTRL3_INT2_FTH_DIS \
+ 0x00
+#define L3GD20H_CTRL3_INT2_FTH_EN \
+ 0x04
+#define L3GD20H_CTRL3_INT2_ORUN_M \
+ 0x02 // FIFO Overrun interrupt on
+ // DRDY/INT2 pin; default value: 0
+#define L3GD20H_CTRL3_INT2_ORUN_DIS \
+ 0x00
+#define L3GD20H_CTRL3_INT2_ORUN_EN \
+ 0x02
+#define L3GD20H_CTRL3_INT2_EMPTY_M \
+ 0x01 // FIFO Empty interrupt on
+ // DRDY/INT2 pin; default value: 0
+#define L3GD20H_CTRL3_INT2_EMPTY_DIS \
+ 0x00
+#define L3GD20H_CTRL3_INT2_EMPTY_EN \
+ 0x01
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the L3GD20H_O_CTRL4
+// register.
+//
+//*****************************************************************************
+#define L3GD20H_CTRL4_BDU_M 0x80 // Block data update; default
+ // value: 0 (0: continuous update;
+ // 1: output registers not updated
+ // until MSB and LSB reading)
+#define L3GD20H_CTRL4_BDU_CONTINUOUS \
+ 0x00
+#define L3GD20H_CTRL4_BDU_MSBLSB \
+ 0x80
+#define L3GD20H_CTRL4_ENDIAN_M 0x40 // Endian selection
+#define L3GD20H_CTRL4_ENDIAN_LITTLE \
+ 0x00
+#define L3GD20H_CTRL4_ENDIAN_BIG \
+ 0x40
+#define L3GD20H_CTRL4_FS_M 0x30 // full scale selection; default
+ // value: 0
+#define L3GD20H_CTRL4_FS_245DPS 0x00 // 245 degrees per second
+#define L3GD20H_CTRL4_FS_500DPS 0x10 // 500 degrees per second
+#define L3GD20H_CTRL4_FS_2000DPS \
+ 0x30 // 2000 degrees per second
+#define L3GD20H_CTRL4_IMPEN_M 0x08 // level sensitive latched enable;
+ // default value: 0
+#define L3GD20H_CTRL4_IMPEN_LVL_DIS \
+ 0x00
+#define L3GD20H_CTRL4_IMPEN_LVL_EN \
+ 0x08
+#define L3GD20H_CTRL4_SELFTEST_M \
+ 0x06 // self-test mode
+#define L3GD20H_CTRL4_SELFTEST_NORMAL \
+ 0x00 // Normal mode (not self test,
+ // default)
+#define L3GD20H_CTRL4_SELFTEST_MODE0 \
+ 0x02 // Self-test mode 0 (+)
+#define L3GD20H_CTRL4_SELFTEST_MODE1 \
+ 0x06 // Self-test mode 1 (-)
+#define L3GD20H_CTRL4_SIM_M 0x01 // SPI Serial Interface Mode
+ // selection (default = 0, 4-wire)
+#define L3GD20H_CTRL4_SIM_4WIRE 0x00
+#define L3GD20H_CTRL4_SIM_3WIRE 0x01
+#define L3GD20H_CTRL4_FS_S 4
+#define L3GD20H_CTRL4_SELFTEST_S \
+ 1
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the L3GD20H_O_CTRL5
+// register.
+//
+//*****************************************************************************
+#define L3GD20H_CTRL5_REBOOTCTL_M \
+ 0x80 // Reboot memory conent
+#define L3GD20H_CTRL5_REBOOTCTL_NORMAL \
+ 0x00
+#define L3GD20H_CTRL5_REBOOTCTL_REBOOT \
+ 0x80
+#define L3GD20H_CTRL5_FIFOCTL_M 0x40 // FIFO control
+#define L3GD20H_CTRL5_FIFOCTL_DIS \
+ 0x00
+#define L3GD20H_CTRL5_FIFOCTL_EN \
+ 0x40
+#define L3GD20H_CTRL5_STOPONFTH_M \
+ 0x20 // Sensing chain FIFO stop values
+ // memorization at FIFO Threshold;
+ // default value: 0
+#define L3GD20H_CTRL5_STOPONFTH_UNLIMITED \
+ 0x00
+#define L3GD20H_CTRL5_STOPONFTH_THRESH_LIMITED \
+ 0x20
+#define L3GD20H_CTRL5_HPEN_M 0x10 // high pass filtern enable
+ // (default 0)
+#define L3GD20H_CTRL5_HPEN_DIS 0x00
+#define L3GD20H_CTRL5_HPEN_EN 0x10
+#define L3GD20H_CTRL5_IG_SEL_M 0x0C // interrupt generator section
+ // configuration
+#define L3GD20H_CTRL5_OUT_SEL_M 0x03 // out selection configuration
+#define L3GD20H_CTRL5_IG_SEL_S 2
+#define L3GD20H_CTRL5_OUT_SEL_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the L3GD20H_O_STATUS
+// register.
+//
+//*****************************************************************************
+#define L3GD20H_STATUS_OR_M 0xF0 // Axis data overrun
+#define L3GD20H_STATUS_OR_X 0x10 // X-axis data overrun
+#define L3GD20H_STATUS_OR_Y 0x20 // Y-axis data overrun
+#define L3GD20H_STATUS_OR_Z 0x40 // Z-axis data overrun
+#define L3GD20H_STATUS_OR_ZYX 0x80 // X, Y, and X data overrun
+#define L3GD20H_STATUS_DA_M 0xF // Axis data available
+#define L3GD20H_STATUS_DA_X 0x01 // X-axis data available
+#define L3GD20H_STATUS_DA_Y 0x02 // Y-axis data available
+#define L3GD20H_STATUS_DA_Z 0x04 // Z-axis data available
+#define L3GD20H_STATUS_DA_ZYX 0x08 // X, Y, and X data available
+#define L3GD20H_STATUS_OR_S 4
+#define L3GD20H_STATUS_DA_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the L3GD20H_O_FIFO_CTRL
+// register.
+//
+//*****************************************************************************
+#define L3GD20H_FIFO_CTRL_THRESH_M \
+ 0x1F // FIFO Threshold setting
+#define L3GD20H_FIFO_CTRL_MODE_M \
+ 0xE // FIFO mode setting
+#define L3GD20H_FIFO_CTRL_MODE_S \
+ 5
+#define L3GD20H_FIFO_CTRL_THRESH_S \
+ 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the L3GD20H_O_FIFO_SRC
+// register.
+//
+//*****************************************************************************
+#define L3GD20H_FIFO_SRC_FTH_M 0x80 // FIFO threshold is greater than
+ // or equal to level or less than
+ // level
+#define L3GD20H_FIFO_SRC_FTH_LT 0x00
+#define L3GD20H_FIFO_SRC_FTH_GEQ \
+ 0x80
+#define L3GD20H_FIFO_SRC_OVRN_M 0x40 // overrun status bit
+#define L3GD20H_FIFO_SRC_OVRN_FILLED \
+ 0x40
+#define L3GD20H_FIFO_SRC_EMPTY_M \
+ 0x20 // FIFO empty
+#define L3GD20H_FIFO_SRC_EMPTY_EMPTY \
+ 0x20
+#define L3GD20H_FIFO_SRC_STORE_SAMPLES_M \
+ 0x1F // FIFO stored data level of the
+ // unread samples
+#define L3GD20H_FIFO_SRC_STORE_SAMPLES_S \
+ 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the L3GD20H_O_IG_CFG
+// register.
+//
+//*****************************************************************************
+#define L3GD20H_IG_CFG_ANDOR_M 0x80 // AND/OR combination of Interrupt
+ // events; default value: 0
+#define L3GD20H_IG_CFG_ANDOR_OR 0x00
+#define L3GD20H_IG_CFG_ANDOR_AND \
+ 0x80
+#define L3GD20H_IG_CFG_LIR_M 0x40 // Latch Interrupt Request; default
+ // value: 0
+#define L3GD20H_IG_CFG_LIR_LATCHED \
+ 0x40
+#define L3GD20H_IG_CFG_ZHI_M 0x20 // enable interrupt generation on
+ // Z-hi event
+#define L3GD20H_IG_CFG_ZHI_EN 0x20
+#define L3GD20H_IG_CFG_ZLI_M 0x10 // enable interrupt generation on
+ // Z-low event
+#define L3GD20H_IG_CFG_ZLI_EN 0x10
+#define L3GD20H_IG_CFG_YHI_M 0x08 // enable interrupt generation on
+ // Y-hi event
+#define L3GD20H_IG_CFG_YHI_EN 0x08
+#define L3GD20H_IG_CFG_YLI_M 0x04 // enable interrupt generation on
+ // Y-low event
+#define L3GD20H_IG_CFG_YLI_EN 0x04
+#define L3GD20H_IG_CFG_XHI_M 0x02 // enable interrupt generation on
+ // X-hi event
+#define L3GD20H_IG_CFG_XHI_EN 0x02
+#define L3GD20H_IG_CFG_XLI_M 0x01 // enable interrupt generation on
+ // X-low event
+#define L3GD20H_IG_CFG_XLI_EN 0x01
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the L3GD20H_O_IG_SRC
+// register.
+//
+//*****************************************************************************
+#define L3GD20H_IG_SRC_IA_M 0x40 // interrupt active
+#define L3GD20H_IG_SRC_IA_ACTIVE \
+ 0x40
+#define L3GD20H_IG_SRC_ZH_M 0x20 // Z-Hi event occurred
+#define L3GD20H_IG_SRC_ZH_OCCURRED \
+ 0x20
+#define L3GD20H_IG_SRC_ZL_M 0x10 // Z-Low event occurred
+#define L3GD20H_IG_SRC_ZL_OCCURRED \
+ 0x10
+#define L3GD20H_IG_SRC_YH_M 0x08 // Y-Hi event occurred
+#define L3GD20H_IG_SRC_YH_OCCURRED \
+ 0x08
+#define L3GD20H_IG_SRC_YL_M 0x04 // Y-Low event occurred
+#define L3GD20H_IG_SRC_YL_OCCURRED \
+ 0x04
+#define L3GD20H_IG_SRC_XH_M 0x02 // X-Hi event occurred
+#define L3GD20H_IG_SRC_XH_OCCURRED \
+ 0x02
+#define L3GD20H_IG_SRC_XL_M 0x01 // X-Low event occurred
+#define L3GD20H_IG_SRC_XL_OCCURRED \
+ 0x01
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the L3GD20H_O_IG_THS_XH
+// register.
+//
+//*****************************************************************************
+#define L3GD20H_IG_THS_XH_DCRM_M \
+ 0x80 // interrupt generation counter
+ // mode
+#define L3GD20H_IG_THS_XH_DCRM_RESET \
+ 0x00
+#define L3GD20H_IG_THS_XH_DCRM_DECREMENT \
+ 0x80
+#define L3GD20H_IG_THS_XH_THSX_M \
+ 0x7F // THSX[14-8], default 0x0
+#define L3GD20H_IG_THS_XH_THSX_S \
+ 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the L3GD20H_O_IG_THS_TH
+// register.
+//
+//*****************************************************************************
+#define L3GD20H_IG_THS_TH_THSY_M \
+ 0x7F // THSY[14-8], default 0x0
+#define L3GD20H_IG_THS_TH_THSY_S \
+ 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the L3GD20H_O_IG_THS_ZH
+// register.
+//
+//*****************************************************************************
+#define L3GD20H_IG_THS_ZH_THSX_M \
+ 0x7F // THSZ[14-8], default 0x0
+#define L3GD20H_IG_THS_ZH_THSX_S \
+ 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the L3GD20H_O_IG_DURATION
+// register.
+//
+//*****************************************************************************
+#define L3GD20H_IG_DURATION_WAIT_M \
+ 0x80 // If WAIT is enabled then DURATION
+ // samples must occur before
+ // asserting the interrupt.
+#define L3GD20H_IG_DURATION_WAIT_DIS \
+ 0x00
+#define L3GD20H_IG_DURATION_WAIT_EN \
+ 0x80
+#define L3GD20H_IG_DURATION_DURATION_M \
+ 0x7F // Duration D[6-0]
+#define L3GD20H_IG_DURATION_DURATION_S \
+ 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the L3GD20H_O_LOW_ODR
+// register.
+//
+//*****************************************************************************
+#define L3GD20H_LOW_ODR_DRDY_HL_M \
+ 0x20 // DRDY/INT2 active level
+#define L3GD20H_LOW_ODR_DRDY_HL_ACTIVE_LOW \
+ 0x00
+#define L3GD20H_LOW_ODR_DRDY_HL_ACTIVE_HIGH \
+ 0x20
+#define L3GD20H_LOW_ODR_I2C_DISABLE_M \
+ 0x08 // disable I2C interface
+#define L3GD20H_LOW_ODR_I2C_DISABLE_BOTH \
+ 0x00
+#define L3GD20H_LOW_ODR_I2C_DISABLE_SPI_ONLY \
+ 0x08
+#define L3GD20H_LOW_ODR_SWRESET_M \
+ 0x04 // software reset
+#define L3GD20H_LOW_ODR_SWRESET_NORMAL \
+ 0x00
+#define L3GD20H_LOW_ODR_SWRESET_RESET \
+ 0x04
+#define L3GD20H_LOW_ODR_DATARATE_M \
+ 0x01 // Low-speed data rate enable;
+ // default value: 0
+#define L3GD20H_LOW_ODR_DATARATE_HIGH \
+ 0x00
+#define L3GD20H_LOW_ODR_DATARATE_LOW \
+ 0x01
+
+#endif // __SENSORLIB_HW_L3GD20H_H__
diff --git a/sensorlib/hw_lsm303d.h b/sensorlib/hw_lsm303d.h
new file mode 100644
index 0000000..19ea89e
--- /dev/null
+++ b/sensorlib/hw_lsm303d.h
@@ -0,0 +1,1017 @@
+//*****************************************************************************
+//
+// hw_lsm303d.h - Macros used when accessing the ST LSM303D
+// accelerometer/magnetometer
+//
+// Copyright (c) 2013-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
+//
+//*****************************************************************************
+
+#ifndef __SENSORLIB_HW_LSM303D_H__
+#define __SENSORLIB_HW_LSM303D_H__
+
+//*****************************************************************************
+//
+// The following are defines for the LSM303D register addresses
+//
+//*****************************************************************************
+#define LSM303D_O_TEMP_OUT_LSB 0x5 // Temperature bits 7-0
+#define LSM303D_O_TEMP_OUT_MSB 0x6 // Temperature bits 11-8
+#define LSM303D_O_MAG_STATUS 0x7 // Magnetic status register
+#define LSM303D_O_MAG_OUT_X_MSB 0x08 // X-axis MSB
+#define LSM303D_O_MAG_OUT_X_LSB 0x09 // X-axis LSB
+#define LSM303D_O_MAG_OUT_Y_MSB 0x0A // Y-axis MSB
+#define LSM303D_O_MAG_OUT_Y_LSB 0x0B // Y-axis LSB
+#define LSM303D_O_MAG_OUT_Z_MSB 0x0C // Z-axis MSB
+#define LSM303D_O_MAG_OUT_Z_LSB 0x0D // Z-axis LSB
+#define LSM303D_O_WHO_AM_I 0x0F // ID register, constant 0x49
+#define LSM303D_O_MAG_INT_CTRL 0x12 // magnetic control register
+#define LSM303D_O_MAG_INT_SRC 0x13 // Interrupt source (status) for
+ // magnetometer interrupt
+#define LSM303D_O_MAG_THS_MSB 0x14 // Threshold MSB
+#define LSM303D_O_MAG_THS_LSB 0x15 // Threshold LSB. Even though the
+ // threshold is expressed in
+ // absolute value, the device
+ // detects both positive and
+ // negative thresholds.
+#define LSM303D_O_MAG_OFFSET_X_MSB \
+ 0x16 // MSB of Magnetic offset for
+ // X-axis. The value is expressed
+ // in 16-bit as 2s complement.
+#define LSM303D_O_MAG_OFFSET_X_LSB \
+ 0x17 // LSB of Magnetic offset for
+ // X-axis. The value is expressed
+ // in 16-bit as 2s complement.
+#define LSM303D_O_MAG_OFFSET_Y_MSB \
+ 0x18 // MSB of Magnetic offset for
+ // Y-axis. The value is expressed
+ // in 16-bit as 2s complement.
+#define LSM303D_O_MAG_OFFSET_Y_LSB \
+ 0x19 // LSB of Magnetic offset for
+ // Y-axis. The value is expressed
+ // in 16-bit as 2s complement.
+#define LSM303D_O_MAG_OFFSET_Z_MSB \
+ 0x1A // MSB of Magnetic offset for
+ // Z-axis. The value is expressed
+ // in 16-bit as 2s complement.
+#define LSM303D_O_MAG_OFFSET_Z_LSB \
+ 0x1B // LSB of Magnetic offset for
+ // Z-axis. The value is expressed
+ // in 16-bit as 2s complement.
+#define LSM303D_O_ACCEL_REFERENCE_X \
+ 0x1C // Reference value for high-pass
+ // filter for X-axis acceleration
+ // data.
+#define LSM303D_O_ACCEL_REFERENCE_Y \
+ 0x1D // Reference value for high-pass
+ // filter for Y-axis acceleration
+ // data.
+#define LSM303D_O_ACCEL_REFERENCE_Z \
+ 0x1E // Reference value for high-pass
+ // filter for Z-axis acceleration
+ // data.
+#define LSM303D_O_CTRL0 0x1F // Accel control 0
+#define LSM303D_O_CTRL1 0x20 // Control 1 - power settings
+#define LSM303D_O_CTRL2 0x21 // Control 2
+#define LSM303D_O_CTRL3 0x22 // Control 3
+#define LSM303D_O_CTRL4 0x23 // Control 4
+#define LSM303D_O_CTRL5 0x24 // Control 5
+#define LSM303D_O_CTRL6 0x25 // Control 6
+#define LSM303D_O_CTRL7 0x26 // Control 7
+#define LSM303D_O_STATUS 0x27 // Status register
+#define LSM303D_O_OUT_X_LSB 0x28 // X-axis LSB
+#define LSM303D_O_OUT_X_MSB 0x29 // X-axis MSB
+#define LSM303D_O_OUT_Y_LSB 0x2A // Y-axis LSB
+#define LSM303D_O_OUT_Y_MSB 0x2B // Y-axis MSB
+#define LSM303D_O_OUT_Z_LSB 0x2C // Z-axis LSB
+#define LSM303D_O_OUT_Z_MSB 0x2D // Z-axis MSB
+#define LSM303D_O_FIFO_CTRL 0x2E // FIFO control
+#define LSM303D_O_FIFO_SRC 0x2F // FIFO_SRC register
+#define LSM303D_O_INT1_CFG 0x30 // INT1 interrupt generation; this
+ // register only writable after
+ // boot
+#define LSM303D_O_INT1_SRC 0x31 // interrupt source register (read
+ // only)
+#define LSM303D_O_INT1_THS 0x32 // Interrupt 1 threshold
+#define LSM303D_O_INT1_DURATION 0x33 // INT1 duration register
+#define LSM303D_O_INT2_CFG 0x34 // INT2 interrupt generation; this
+ // register only writable after
+ // boot
+#define LSM303D_O_INT2_SRC 0x35 // INT2 source register (read only)
+#define LSM303D_O_INT2_THS 0x36 // INT2 threshold
+#define LSM303D_O_INT2_DURATION 0x37 // INT2 duration register
+#define LSM303D_O_CLICK_CFG 0x38 // Click config A register
+#define LSM303D_O_CLICK_SRC 0x39 // Click source A
+#define LSM303D_O_CLICK_THS 0x3A // click-click threshold
+#define LSM303D_O_TIME_LIMIT 0x3B // Time Limit A register
+#define LSM303D_O_TIME_LATENCY 0x3C // Time Latency A register; 1 LSB =
+ // 1/ODR; TLA7 through TLA0 define
+ // the time interval that starts
+ // after the first click detection
+ // where the click detection
+ // procedure is disabled, in cases
+ // where the device is configured
+ // for double click detection
+#define LSM303D_O_TIME_WINDOW 0x3D // Time Window A register; 1 LSB =
+ // 1/ODR; TW7 through TW0 define
+ // the maximum interval of time
+ // that can elapse after the end of
+ // the latency interval in which
+ // the click detection procedure
+ // can start, in cases where the
+ // device is configured for double
+ // click detection
+#define LSM303D_O_ACT_THS 0x3E // Sleep to Wake, Return to Sleep
+ // activation threshold 1LSb = 16mg
+#define LSM303D_O_ACT_DUR 0x3F // Sleep to Wake, Return to Sleep
+ // duration DUR = (Act_DUR +
+ // 1)*8/ODR
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the LSM303D_O_TEMP_OUT_LSB
+// register.
+//
+//*****************************************************************************
+#define LSM303D_TEMP_OUT_LSB_LSB_M \
+ 0xFF
+#define LSM303D_TEMP_OUT_LSB_LSB_S \
+ 4
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the LSM303D_O_TEMP_OUT_MSB
+// register.
+//
+//*****************************************************************************
+#define LSM303D_TEMP_OUT_MSB_MSB_M \
+ 0x0F
+#define LSM303D_TEMP_OUT_MSB_MSB_S \
+ 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the LSM303D_O_MAG_STATUS
+// register.
+//
+//*****************************************************************************
+#define LSM303D_MAG_STATUS_ZYXTMOR_M \
+ 0x80 // X,Y,Z axis and temp data overrun
+#define LSM303D_MAG_STATUS_ZYXTMOR_TRUE \
+ 0x80
+#define LSM303D_MAG_STATUS_ZMOR_M \
+ 0x40 // Z-axis mag data overrun
+#define LSM303D_MAG_STATUS_ZMOR_TRUE \
+ 0x40
+#define LSM303D_MAG_STATUS_YMOR_M \
+ 0x20 // Y-axis mag data overrun
+#define LSM303D_MAG_STATUS_YMOR_TRUE \
+ 0x20
+#define LSM303D_MAG_STATUS_XMOR_M \
+ 0x10 // X-axis mag data overrun
+#define LSM303D_MAG_STATUS_XMOR_TRUE \
+ 0x10
+#define LSM303D_MAG_STATUS_ZYXTMD_M \
+ 0x08 // X,Y,Z axis and temp data
+ // available
+#define LSM303D_MAG_STATUS_ZYXTMD_AVAIL \
+ 0x08
+#define LSM303D_MAG_STATUS_ZMD_M \
+ 0x04 // New mag data available for Z
+ // axis
+#define LSM303D_MAG_STATUS_ZMD_AVAIL \
+ 0x04
+#define LSM303D_MAG_STATUS_YMD_M \
+ 0x02 // New mag data available for Y
+ // axis
+#define LSM303D_MAG_STATUS_YMD_AVAIL \
+ 0x02
+#define LSM303D_MAG_STATUS_XMD_M \
+ 0x01 // New mag data available for X
+ // axis
+#define LSM303D_MAG_STATUS_XMD_AVAIL \
+ 0x01
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the LSM303D_O_MAG_INT_CTRL
+// register.
+//
+//*****************************************************************************
+#define LSM303D_MAG_INT_CTRL_XINT_M \
+ 0x80 // Enable interrupt recognition on
+ // X-axis for magnetic data.
+#define LSM303D_MAG_INT_CTRL_XINT_ENABLE \
+ 0x80
+#define LSM303D_MAG_INT_CTRL_YINT_M \
+ 0x40 // Enable interrupt recognition on
+ // Y-axis for magnetic data.
+#define LSM303D_MAG_INT_CTRL_YINT_ENABLE \
+ 0x40
+#define LSM303D_MAG_INT_CTRL_ZINT_M \
+ 0x20 // Enable interrupt recognition on
+ // Z-axis for magnetic data.
+#define LSM303D_MAG_INT_CTRL_ZINT_ENABLE \
+ 0x20
+#define LSM303D_MAG_INT_CTRL_PINCFG_M \
+ 0x10 // interrupt pin drive
+ // configuration
+#define LSM303D_MAG_INT_CTRL_PINCFG_PUSHPULL \
+ 0x00
+#define LSM303D_MAG_INT_CTRL_PINCFG_OPENDRAIN \
+ 0x10
+#define LSM303D_MAG_INT_CTRL_POLARITY_M \
+ 0x08 // interrupt polarity
+#define LSM303D_MAG_INT_CTRL_POLARITY_LOW \
+ 0x00
+#define LSM303D_MAG_INT_CTRL_POLARITY_HIGH \
+ 0x08
+#define LSM303D_MAG_INT_CTRL_LATCH_M \
+ 0x04 // latch interrupt request
+#define LSM303D_MAG_INT_CTRL_LATCH_ENABLE \
+ 0x04
+#define LSM303D_MAG_INT_CTRL_4D_M \
+ 0x02 // 4D detection on acceleration
+ // data is enabled when 6D bit in
+ // IG_CFG1
+#define LSM303D_MAG_INT_CTRL_4D_ENABLE \
+ 0x02
+#define LSM303D_MAG_INT_CTRL_MI_M \
+ 0x01 // Interrupt generation for
+ // magnetic data
+#define LSM303D_MAG_INT_CTRL_MI_ENABLE \
+ 0x01
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the LSM303D_O_MAG_INT_SRC
+// register.
+//
+//*****************************************************************************
+#define LSM303D_MAG_INT_SRC_M_PTH_X_M \
+ 0x80 // Magnetic value on X-axis exceeds
+ // the threshold on the positive
+ // side.
+#define LSM303D_MAG_INT_SRC_M_PTH_X_ACTIVE \
+ 0x80
+#define LSM303D_MAG_INT_SRC_M_PTH_Y_M \
+ 0x40 // Magnetic value on Y-axis exceeds
+ // the threshold on the positive
+ // side.
+#define LSM303D_MAG_INT_SRC_M_PTH_Y_ACTIVE \
+ 0x40
+#define LSM303D_MAG_INT_SRC_M_PTH_Z_M \
+ 0x20 // Magnetic value on Z-axis exceeds
+ // the threshold on the positive
+ // side.
+#define LSM303D_MAG_INT_SRC_M_PTH_Z_ACTIVE \
+ 0x20
+#define LSM303D_MAG_INT_SRC_M_NTH_X_M \
+ 0x10 // Magnetic value on X-axis exceeds
+ // the threshold on the negative
+ // side.
+#define LSM303D_MAG_INT_SRC_M_NTH_X_ACTIVE \
+ 0x10
+#define LSM303D_MAG_INT_SRC_M_NTH_Y_M \
+ 0x08 // Magnetic value on Y-axis exceeds
+ // the threshold on the negative
+ // side.
+#define LSM303D_MAG_INT_SRC_M_NTH_Y_ACTIVE \
+ 0x08
+#define LSM303D_MAG_INT_SRC_M_NTH_Z_M \
+ 0x04 // Magnetic value on Z-axis exceeds
+ // the threshold on the negative
+ // side.
+#define LSM303D_MAG_INT_SRC_M_NTH_Z_ACTIVE \
+ 0x04
+#define LSM303D_MAG_INT_SRC_MROI_M \
+ 0x02 // Internal measurement range
+ // overflow on magnetic value.
+#define LSM303D_MAG_INT_SRC_MROI_ACTIVE \
+ 0x02
+#define LSM303D_MAG_INT_SRC_MINT_M \
+ 0x01 // Magnetic interrupt event. The
+ // magnetic field value exceeds the
+ // threshold.
+#define LSM303D_MAG_INT_SRC_MINT_ACTIVE \
+ 0x01
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the LSM303D_O_CTRL0
+// register.
+//
+//*****************************************************************************
+#define LSM303D_CTRL0_BOOT_M 0x80 // Reboot memory content.
+#define LSM303D_CTRL0_BOOT_REBOOT \
+ 0x80
+#define LSM303D_CTRL0_FIFO_M 0x40 // FIFO enable.
+#define LSM303D_CTRL0_FIFO_ENABLE \
+ 0x40
+#define LSM303D_CTRL0_FTH_M 0x20 // FIFO programmable threshold
+ // enable.
+#define LSM303D_CTRL0_FTH_ENABLE \
+ 0x20
+#define LSM303D_CTRL0_HPCLICK_M 0x04 // High-pass filter enabled for
+ // click function.
+#define LSM303D_CTRL0_HPCLICK_ENABLE \
+ 0x04
+#define LSM303D_CTRL0_HPIS1_M 0x02 // High-pass filter enabled for
+ // interrupt generator 1
+#define LSM303D_CTRL0_HPIS1_ENABLE \
+ 0x02
+#define LSM303D_CTRL0_HPIS2_M 0x01 // High-pass filter enabled for
+ // interrupt generator 2
+#define LSM303D_CTRL0_HPIS2_ENABLE \
+ 0x01
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the LSM303D_O_CTRL1
+// register.
+//
+//*****************************************************************************
+#define LSM303D_CTRL1_AODR_M 0xF0 // accel output data rate selection
+#define LSM303D_CTRL1_AODR_PD 0x00 // Power-down mode
+#define LSM303D_CTRL1_AODR_3_125HZ \
+ 0x10
+#define LSM303D_CTRL1_AODR_6_2HZ \
+ 0x20
+#define LSM303D_CTRL1_AODR_12_5HZ \
+ 0x30
+#define LSM303D_CTRL1_AODR_25HZ 0x40
+#define LSM303D_CTRL1_AODR_50HZ 0x50
+#define LSM303D_CTRL1_AODR_100HZ \
+ 0x60
+#define LSM303D_CTRL1_AODR_200HZ \
+ 0x70
+#define LSM303D_CTRL1_AODR_400HZ \
+ 0x80
+#define LSM303D_CTRL1_AODR_800HZ \
+ 0x90
+#define LSM303D_CTRL1_AODR_1600HZ \
+ 0xA0
+#define LSM303D_CTRL1_BDU_M 0x08 // Block data update for
+ // acceleration and magnetic data.
+ // (0: continuous update; 1: output
+ // registers not updated until MSB
+ // and LSB have been read), default
+ // continuous
+#define LSM303D_CTRL1_BDU_CONTINUOUS \
+ 0x00
+#define LSM303D_CTRL1_BDU_BLOCK 0x08
+#define LSM303D_CTRL1_AXIS_M 0x7 // Axis power control
+#define LSM303D_CTRL1_AXIS_Y_EN 0x01 // Y-axis enable
+#define LSM303D_CTRL1_AXIS_X_EN 0x02 // X-axis enable
+#define LSM303D_CTRL1_AXIS_Z_EN 0x04 // Z-axis enable
+#define LSM303D_CTRL1_AODR_S 4
+#define LSM303D_CTRL1_AXIS_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the LSM303D_O_CTRL2
+// register.
+//
+//*****************************************************************************
+#define LSM303D_CTRL2_AFS_M 0x38 // Acceleration full-scale
+ // selection.
+#define LSM303D_CTRL2_AFS_2G 0x00 // +/- 2G sensitivity
+#define LSM303D_CTRL2_AFS_4G 0x08 // +/- 4G sensitivity
+#define LSM303D_CTRL2_AFS_6G 0x10 // +/- 6G sensitivity
+#define LSM303D_CTRL2_AFS_8G 0x18 // +/- 8G sensitivity
+#define LSM303D_CTRL2_AFS_16G 0x40 // +/- 16G sensitivity
+#define LSM303D_CTRL2_ABW_M 0xC // anti-alias filter bandwidth
+#define LSM303D_CTRL2_ABW_773HZ 0x00
+#define LSM303D_CTRL2_ABW_194HZ 0x40
+#define LSM303D_CTRL2_ABW_362HZ 0x80
+#define LSM303D_CTRL2_ABW_50HZ 0xC0
+#define LSM303D_CTRL2_AST_M 0x02 // Acceleration self-test enable.
+#define LSM303D_CTRL2_AST_ENABLE \
+ 0x02
+#define LSM303D_CTRL2_SIM_M 0x01 // SPI Serial Interface mode
+ // selection. (default: 4 wire)
+#define LSM303D_CTRL2_SIM_4WIRE 0x00
+#define LSM303D_CTRL2_SIM_3WIRE 0x01
+#define LSM303D_CTRL2_ABW_S 6
+#define LSM303D_CTRL2_AFS_S 3
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the LSM303D_O_CTRL3
+// register.
+//
+//*****************************************************************************
+#define LSM303D_CTRL3_INT1_BOOT_M \
+ 0x80 // Boot on INT1 enable
+#define LSM303D_CTRL3_INT1_BOOT_EN \
+ 0x80
+#define LSM303D_CTRL3_INT1_CLICK_M \
+ 0x40 // Click generator interrupt on
+ // INT1.
+#define LSM303D_CTRL3_INT1_CLICK_EN \
+ 0x40
+#define LSM303D_CTRL3_INT1_IG1_M \
+ 0x20 // Inertial interrupt generator 1
+ // on INT1
+#define LSM303D_CTRL3_INT1_IG1_EN \
+ 0x20
+#define LSM303D_CTRL3_INT1_IG2_M \
+ 0x10 // Inertial interrupt generator 2
+ // on INT1
+#define LSM303D_CTRL3_INT1_IG2_EN \
+ 0x10
+#define LSM303D_CTRL3_INT1_IGM_M \
+ 0x08 // Magnetic interrupt generator on
+ // INT1
+#define LSM303D_CTRL3_INT1_IGM_EN \
+ 0x08
+#define LSM303D_CTRL3_INT1_ACCEL_DRDY_M \
+ 0x04 // Accelerometer data-ready signal
+ // on INT1
+#define LSM303D_CTRL3_INT1_ACCEL_DRDY_EN \
+ 0x04
+#define LSM303D_CTRL3_INT1_MAG_DRDY_M \
+ 0x02 // Magnetometer data-ready signal
+ // on INT1.
+#define LSM303D_CTRL3_INT1_MAG_DRDY_EN \
+ 0x02
+#define LSM303D_CTRL3_INT1_EMPTY_M \
+ 0x01 // FIFO empty indication on INT1
+#define LSM303D_CTRL3_INT1_EMPTY_EN \
+ 0x01
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the LSM303D_O_CTRL4
+// register.
+//
+//*****************************************************************************
+#define LSM303D_CTRL4_INT2_CLICK_M \
+ 0x80 // Click generator interrupt on
+ // INT2
+#define LSM303D_CTRL4_INT2_CLICK_EN \
+ 0x80
+#define LSM303D_CTRL4_INT2_IG1_M \
+ 0x40 // Inertial interrupt generator 1
+ // on INT2
+#define LSM303D_CTRL4_INT2_IG1_EN \
+ 0x40
+#define LSM303D_CTRL4_INT2_IG2_M \
+ 0x20 // Inertial interrupt generator 2
+ // on INT2
+#define LSM303D_CTRL4_INT2_IG2_EN \
+ 0x20
+#define LSM303D_CTRL4_INT2_IGM_M \
+ 0x10 // Magnetic interrupt generator on
+ // INT2
+#define LSM303D_CTRL4_INT2_IGM_EN \
+ 0x10
+#define LSM303D_CTRL4_INT2_ACCEL_DRDY_M \
+ 0x08 // Accelerometer data-ready signal
+ // on INT2
+#define LSM303D_CTRL4_INT2_ACCEL_DRDY_EN \
+ 0x08
+#define LSM303D_CTRL4_INT2_MAG_DRDY_M \
+ 0x04 // Magnetometer data-ready signal
+ // on INT2
+#define LSM303D_CTRL4_INT2_MAG_DRDY_EN \
+ 0x04
+#define LSM303D_CTRL4_INT2_OVR_M \
+ 0x02 // FIFO overrun interrupt on INT2
+#define LSM303D_CTRL4_INT2_OVR_EN \
+ 0x02
+#define LSM303D_CTRL4_INT2_FTH_M \
+ 0x01 // FIFO threshold interrupt on INT2
+#define LSM303D_CTRL4_INT2_FTH_EN \
+ 0x01
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the LSM303D_O_CTRL5
+// register.
+//
+//*****************************************************************************
+#define LSM303D_CTRL5_TEMP_M 0x80 // Temperature sensor enable.
+#define LSM303D_CTRL5_TEMP_EN 0x80
+#define LSM303D_CTRL5_MRES_M 0x60 // Magnetic resolution selection
+#define LSM303D_CTRL5_MRES_LOW 0x00 // low resolution
+#define LSM303D_CTRL5_MRES_HIGH 0x60 // high resolution
+#define LSM303D_CTRL5_MODR_M 0x1C // mag output data rate selection
+#define LSM303D_CTRL5_MODR_3_125HZ \
+ 0x00
+#define LSM303D_CTRL5_MODR_6_2HZ \
+ 0x04
+#define LSM303D_CTRL5_MODR_12_5HZ \
+ 0x08
+#define LSM303D_CTRL5_MODR_25HZ 0x0C
+#define LSM303D_CTRL5_MODR_50HZ 0x10
+#define LSM303D_CTRL5_MODR_100HZ \
+ 0x14
+#define LSM303D_CTRL5_LIR2_M 0x02 // latch interrupt request on int2
+#define LSM303D_CTRL5_LIR2_EN 0x02
+#define LSM303D_CTRL5_LIR1_M 0x01 // latch interrupt request on int1
+#define LSM303D_CTRL5_LIR1_EN 0x01
+#define LSM303D_CTRL5_MRES_S 5
+#define LSM303D_CTRL5_MODR_S 2
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the LSM303D_O_CTRL6
+// register.
+//
+//*****************************************************************************
+#define LSM303D_CTRL6_MFS_M 0x60 // magnetic full scale select
+#define LSM303D_CTRL6_MFS_2G 0x00 // +/- 2 gauss
+#define LSM303D_CTRL6_MFS_4G 0x20 // +/- 4 gauss
+#define LSM303D_CTRL6_MFS_8G 0x40 // +/- 8 gauss
+#define LSM303D_CTRL6_MFS_12G 0x60 // +/- 16 gauss
+#define LSM303D_CTRL6_MFS_S 5
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the LSM303D_O_CTRL7
+// register.
+//
+//*****************************************************************************
+#define LSM303D_CTRL7_AHPM_M 0xC0 // High-pass filter mode selection
+ // for acceleration data
+#define LSM303D_CTRL7_AHPM_NORMAL \
+ 0x00
+#define LSM303D_CTRL7_AHPM_REFERENCE \
+ 0x40
+#define LSM303D_CTRL7_AHPM_AUTORESET \
+ 0xC0
+#define LSM303D_CTRL7_AFDS_M 0x20 // default: internal filter
+ // bypassed
+#define LSM303D_CTRL7_AFDS_BYPASSED \
+ 0x00
+#define LSM303D_CTRL7_AFDS_FILTERED \
+ 0x20
+#define LSM303D_CTRL7_TEMP_ONLY_M \
+ 0x10 // Temperature sensor only mode,
+ // mag off
+#define LSM303D_CTRL7_TEMP_ONLY_EN \
+ 0x10
+#define LSM303D_CTRL7_MLP_M 0x04 // Magnetic data low-power mode. If
+ // this bit is 1, the M_ODR [2:0]
+ // is set to 3.125 Hz independently
+ // from the MODR settings.
+#define LSM303D_CTRL7_MLP_NORMAL \
+ 0x00
+#define LSM303D_CTRL7_MLP_LOWPOWER \
+ 0x04
+#define LSM303D_CTRL7_MD_M 0x3 // Magnetic sensor mode selection
+#define LSM303D_CTRL7_MD_CONTINUOUS \
+ 0x00
+#define LSM303D_CTRL7_MD_SINGLE 0x01
+#define LSM303D_CTRL7_MD_POWERDOWN \
+ 0x02
+#define LSM303D_CTRL7_AHPM_S 6
+#define LSM303D_CTRL7_MD_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the LSM303D_O_STATUS
+// register.
+//
+//*****************************************************************************
+#define LSM303D_STATUS_OR_M 0xF0 // Accel Axis data overrun
+#define LSM303D_STATUS_OR_X 0x10 // Accel X-axis data overrun
+#define LSM303D_STATUS_OR_Y 0x20 // Accel Y-axis data overrun
+#define LSM303D_STATUS_OR_Z 0x40 // Accel Z-axis data overrun
+#define LSM303D_STATUS_OR_ZYX 0x80 // Accel X, Y, and X data overrun
+#define LSM303D_STATUS_DA_M 0xF // Accel data available
+#define LSM303D_STATUS_DA_X 0x01 // Accel X-axis data available
+#define LSM303D_STATUS_DA_Y 0x02 // Accel Y-axis data available
+#define LSM303D_STATUS_DA_Z 0x04 // Accel Z-axis data available
+#define LSM303D_STATUS_DA_ZYX 0x08 // Accel X, Y, and X data available
+#define LSM303D_STATUS_OR_S 4
+#define LSM303D_STATUS_DA_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the LSM303D_O_FIFO_CTRL
+// register.
+//
+//*****************************************************************************
+#define LSM303D_FIFO_CTRL_MODE_M \
+ 0xE0 // FIFO mode setting
+#define LSM303D_FIFO_CTRL_MODE_BYPASS \
+ 0x00 // Bypass mode
+#define LSM303D_FIFO_CTRL_MODE_FIFO \
+ 0x20 // FIFO mode
+#define LSM303D_FIFO_CTRL_MODE_STREAM \
+ 0x40 // Stream mode
+#define LSM303D_FIFO_CTRL_MODE_S2F \
+ 0x60 // Stream-to-FIFO mode
+#define LSM303D_FIFO_CTRL_MODE_B2S \
+ 0x80 // Bypass-to-stream mode
+#define LSM303D_FIFO_CTRL_THRESH_M \
+ 0x1F // FIFO Threshold setting
+#define LSM303D_FIFO_CTRL_MODE_S \
+ 5
+#define LSM303D_FIFO_CTRL_THRESH_S \
+ 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the LSM303D_O_FIFO_SRC
+// register.
+//
+//*****************************************************************************
+#define LSM303D_FIFO_SRC_FTH_M 0x80 // FIFO threshold is greater than
+ // or equal to level or less than
+ // level
+#define LSM303D_FIFO_SRC_FTH_LT 0x00
+#define LSM303D_FIFO_SRC_FTH_GEQ \
+ 0x80
+#define LSM303D_FIFO_SRC_OVRN_M 0x40 // overrun status bit
+#define LSM303D_FIFO_SRC_OVRN_FILLED \
+ 0x40
+#define LSM303D_FIFO_SRC_EMPTY_M \
+ 0x20 // FIFO empty
+#define LSM303D_FIFO_SRC_EMPTY_EMPTY \
+ 0x20
+#define LSM303D_FIFO_SRC_STORE_SAMPLES_M \
+ 0x1F // FIFO stored data level of the
+ // unread samples
+#define LSM303D_FIFO_SRC_STORE_SAMPLES_S \
+ 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the LSM303D_O_INT1_CFG
+// register.
+//
+//*****************************************************************************
+#define LSM303D_INT1_CFG_ANDOR_M \
+ 0x80 // AND/OR combination of Interrupt
+ // events; default value: 0
+#define LSM303D_INT1_CFG_ANDOR_OR \
+ 0x00
+#define LSM303D_INT1_CFG_ANDOR_AND \
+ 0x80
+#define LSM303D_INT1_CFG_6D_M 0x40 // 6-direction function enabled
+#define LSM303D_INT1_CFG_6D_EN 0x40
+#define LSM303D_INT1_CFG_ZHI_M 0x20 // enable interrupt generation on
+ // Z-hi event
+#define LSM303D_INT1_CFG_ZHI_EN 0x20
+#define LSM303D_INT1_CFG_ZUPE_M 0x20 // enable interrupt generation on
+ // Z-hi event
+#define LSM303D_INT1_CFG_ZUPE_EN \
+ 0x20
+#define LSM303D_INT1_CFG_ZDOWNE_M \
+ 0x10 // enable interrupt generation on
+ // Z-low event
+#define LSM303D_INT1_CFG_ZDOWNE_EN \
+ 0x10
+#define LSM303D_INT1_CFG_ZLI_M 0x10 // enable interrupt generation on
+ // Z-low event
+#define LSM303D_INT1_CFG_ZLI_EN 0x10
+#define LSM303D_INT1_CFG_YUPE_M 0x08 // enable interrupt generation on
+ // Y-hi event
+#define LSM303D_INT1_CFG_YUPE_EN \
+ 0x08
+#define LSM303D_INT1_CFG_YHI_M 0x08 // enable interrupt generation on
+ // Y-hi event
+#define LSM303D_INT1_CFG_YHI_EN 0x08
+#define LSM303D_INT1_CFG_YDOWNE_M \
+ 0x04 // enable interrupt generation on
+ // Y-low event
+#define LSM303D_INT1_CFG_YDOWNE_EN \
+ 0x04
+#define LSM303D_INT1_CFG_YLI_M 0x04 // enable interrupt generation on
+ // Y-low event
+#define LSM303D_INT1_CFG_YLI_EN 0x04
+#define LSM303D_INT1_CFG_XUPE_M 0x02 // enable interrupt generation on
+ // X-hi event
+#define LSM303D_INT1_CFG_XUPE_EN \
+ 0x02
+#define LSM303D_INT1_CFG_XHI_M 0x02 // enable interrupt generation on
+ // X-hi event
+#define LSM303D_INT1_CFG_XHI_EN 0x02
+#define LSM303D_INT1_CFG_XDOWNE_M \
+ 0x01 // enable interrupt generation on
+ // X-low event
+#define LSM303D_INT1_CFG_XDOWNE_EN \
+ 0x01
+#define LSM303D_INT1_CFG_XLI_M 0x01 // enable interrupt generation on
+ // X-low event
+#define LSM303D_INT1_CFG_XLI_EN 0x01
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the LSM303D_O_INT1_SRC
+// register.
+//
+//*****************************************************************************
+#define LSM303D_INT1_SRC_ZERO_M 0x80 // This bit must be zero
+#define LSM303D_INT1_SRC_ZERO_ZERO \
+ 0x00
+#define LSM303D_INT1_SRC_ZERO_INVALID \
+ 0x80
+#define LSM303D_INT1_SRC_IA_M 0x40 // interrupt active
+#define LSM303D_INT1_SRC_IA_ACTIVE \
+ 0x40
+#define LSM303D_INT1_SRC_ZH_M 0x20 // Z-Hi event occurred
+#define LSM303D_INT1_SRC_ZH_OCCURRED \
+ 0x20
+#define LSM303D_INT1_SRC_ZL_M 0x10 // Z-Low event occurred
+#define LSM303D_INT1_SRC_ZL_OCCURRED \
+ 0x10
+#define LSM303D_INT1_SRC_YH_M 0x08 // Y-Hi event occurred
+#define LSM303D_INT1_SRC_YH_OCCURRED \
+ 0x08
+#define LSM303D_INT1_SRC_YL_M 0x04 // Y-Low event occurred
+#define LSM303D_INT1_SRC_YL_OCCURRED \
+ 0x04
+#define LSM303D_INT1_SRC_XH_M 0x02 // X-Hi event occurred
+#define LSM303D_INT1_SRC_XH_OCCURRED \
+ 0x02
+#define LSM303D_INT1_SRC_XL_M 0x01 // X-Low event occurred
+#define LSM303D_INT1_SRC_XL_OCCURRED \
+ 0x01
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the LSM303D_O_INT1_THS
+// register.
+//
+//*****************************************************************************
+#define LSM303D_INT1_THS_ZERO_M 0x80 // This bit must be zero
+#define LSM303D_INT1_THS_ZERO_ZERO \
+ 0x00
+#define LSM303D_INT1_THS_ZERO_INVALID \
+ 0x80
+#define LSM303D_INT1_THS_THS_M 0x7F // THS[6-0] Interrupt threshold,
+ // default 0x0
+#define LSM303D_INT1_THS_THS_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the LSM303D_O_INT1_DURATION
+// register.
+//
+//*****************************************************************************
+#define LSM303D_INT1_DURATION_ZERO_M \
+ 0x80 // This bit must be zero
+#define LSM303D_INT1_DURATION_ZERO_ZERO \
+ 0x00
+#define LSM303D_INT1_DURATION_ZERO_INVALID \
+ 0x80
+#define LSM303D_INT1_DURATION_DURATION_M \
+ 0x7F // Duration D[6-0]
+#define LSM303D_INT1_DURATION_DURATION_S \
+ 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the LSM303D_O_INT2_CFG
+// register.
+//
+//*****************************************************************************
+#define LSM303D_INT2_CFG_ANDOR_M \
+ 0x80 // AND/OR combination of Interrupt
+ // events; default value: 0
+#define LSM303D_INT2_CFG_ANDOR_OR \
+ 0x00
+#define LSM303D_INT2_CFG_ANDOR_AND \
+ 0x80
+#define LSM303D_INT2_CFG_6D_M 0x40 // 6-direction function enabled
+#define LSM303D_INT2_CFG_6D_EN 0x40
+#define LSM303D_INT2_CFG_ZHI_M 0x20 // enable interrupt generation on
+ // Z-hi event
+#define LSM303D_INT2_CFG_ZHI_EN 0x20
+#define LSM303D_INT2_CFG_ZLI_M 0x10 // enable interrupt generation on
+ // Z-low event
+#define LSM303D_INT2_CFG_ZLI_EN 0x10
+#define LSM303D_INT2_CFG_YHI_M 0x08 // enable interrupt generation on
+ // Y-hi event
+#define LSM303D_INT2_CFG_YHI_EN 0x08
+#define LSM303D_INT2_CFG_YLI_M 0x04 // enable interrupt generation on
+ // Y-low event
+#define LSM303D_INT2_CFG_YLI_EN 0x04
+#define LSM303D_INT2_CFG_XHI_M 0x02 // enable interrupt generation on
+ // X-hi event
+#define LSM303D_INT2_CFG_XHI_EN 0x02
+#define LSM303D_INT2_CFG_XLI_M 0x01 // enable interrupt generation on
+ // X-low event
+#define LSM303D_INT2_CFG_XLI_EN 0x01
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the LSM303D_O_INT2_SRC
+// register.
+//
+//*****************************************************************************
+#define LSM303D_INT2_SRC_ZERO_M 0x80 // This bit must be zero
+#define LSM303D_INT2_SRC_ZERO_ZERO \
+ 0x00
+#define LSM303D_INT2_SRC_ZERO_INVALID \
+ 0x80
+#define LSM303D_INT2_SRC_IA_M 0x40 // interrupt active
+#define LSM303D_INT2_SRC_IA_ACTIVE \
+ 0x40
+#define LSM303D_INT2_SRC_ZH_M 0x20 // Z-Hi event occurred
+#define LSM303D_INT2_SRC_ZH_OCCURRED \
+ 0x20
+#define LSM303D_INT2_SRC_ZL_M 0x10 // Z-Low event occurred
+#define LSM303D_INT2_SRC_ZL_OCCURRED \
+ 0x10
+#define LSM303D_INT2_SRC_YH_M 0x08 // Y-Hi event occurred
+#define LSM303D_INT2_SRC_YH_OCCURRED \
+ 0x08
+#define LSM303D_INT2_SRC_YL_M 0x04 // Y-Low event occurred
+#define LSM303D_INT2_SRC_YL_OCCURRED \
+ 0x04
+#define LSM303D_INT2_SRC_XH_M 0x02 // X-Hi event occurred
+#define LSM303D_INT2_SRC_XH_OCCURRED \
+ 0x02
+#define LSM303D_INT2_SRC_XL_M 0x01 // X-Low event occurred
+#define LSM303D_INT2_SRC_XL_OCCURRED \
+ 0x01
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the LSM303D_O_INT2_THS
+// register.
+//
+//*****************************************************************************
+#define LSM303D_INT2_THS_ZERO_M 0x80 // This bit must be zero
+#define LSM303D_INT2_THS_ZERO_ZERO \
+ 0x00
+#define LSM303D_INT2_THS_ZERO_INVALID \
+ 0x80
+#define LSM303D_INT2_THS_THS_M 0x7F // THS[6-0] Interrupt threshold,
+ // default 0x0
+#define LSM303D_INT2_THS_THS_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the LSM303D_O_INT2_DURATION
+// register.
+//
+//*****************************************************************************
+#define LSM303D_INT2_DURATION_ZERO_M \
+ 0x80 // This bit must be zero
+#define LSM303D_INT2_DURATION_ZERO_ZERO \
+ 0x00
+#define LSM303D_INT2_DURATION_ZERO_INVALID \
+ 0x80
+#define LSM303D_INT2_DURATION_DURATION_M \
+ 0x7F // Duration D[6-0]
+#define LSM303D_INT2_DURATION_DURATION_S \
+ 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the LSM303D_O_CLICK_CFG
+// register.
+//
+//*****************************************************************************
+#define LSM303D_CLICK_CFG_ZD_M 0x20 // Enable interrupt double click on
+ // Z axis
+#define LSM303D_CLICK_CFG_ZD_DIS \
+ 0x00
+#define LSM303D_CLICK_CFG_ZD_EN 0x20
+#define LSM303D_CLICK_CFG_ZS_M 0x10 // Enable interrupt single click on
+ // Z axis
+#define LSM303D_CLICK_CFG_ZS_DIS \
+ 0x00
+#define LSM303D_CLICK_CFG_ZS_EN 0x10
+#define LSM303D_CLICK_CFG_YD_M 0x08 // Enable interrupt double click on
+ // Y axis
+#define LSM303D_CLICK_CFG_YD_DIS \
+ 0x00
+#define LSM303D_CLICK_CFG_YD_EN 0x08
+#define LSM303D_CLICK_CFG_YS_M 0x04 // Enable interrupt single click on
+ // Y axis
+#define LSM303D_CLICK_CFG_YS_DIS \
+ 0x00
+#define LSM303D_CLICK_CFG_YS_EN 0x04
+#define LSM303D_CLICK_CFG_XD_M 0x02 // Enable interrupt double click on
+ // X axis
+#define LSM303D_CLICK_CFG_XD_DIS \
+ 0x00
+#define LSM303D_CLICK_CFG_XD_EN 0x02
+#define LSM303D_CLICK_CFG_XS_M 0x01 // Enable interrupt single click on
+ // X axis
+#define LSM303D_CLICK_CFG_XS_DIS \
+ 0x00
+#define LSM303D_CLICK_CFG_XS_EN 0x01
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the LSM303D_O_CLICK_SRC
+// register.
+//
+//*****************************************************************************
+#define LSM303D_CLICK_SRC_IA_M 0x40 // Interrupt pending
+#define LSM303D_CLICK_SRC_IA_NONE \
+ 0x00
+#define LSM303D_CLICK_SRC_IA_PENDING \
+ 0x40
+#define LSM303D_CLICK_SRC_DCLICK_M \
+ 0x20 // double click-click enable
+#define LSM303D_CLICK_SRC_DCLICK_DIS \
+ 0x00
+#define LSM303D_CLICK_SRC_DCLICK_EN \
+ 0x20
+#define LSM303D_CLICK_SRC_SCLICK_M \
+ 0x10 // single click-click enable
+#define LSM303D_CLICK_SRC_SCLICK_DIS \
+ 0x00
+#define LSM303D_CLICK_SRC_SCLICK_EN \
+ 0x10
+#define LSM303D_CLICK_SRC_SIGN_M \
+ 0x08 // click-click sign
+#define LSM303D_CLICK_SRC_SIGN_POSITIVE \
+ 0x00
+#define LSM303D_CLICK_SRC_SIGN_NEGATIVE \
+ 0x08
+#define LSM303D_CLICK_SRC_AXIS_M \
+ 0x7 // Axis click detection
+#define LSM303D_CLICK_SRC_AXIS_X \
+ 0x01 // X click-click detection
+#define LSM303D_CLICK_SRC_AXIS_Y \
+ 0x02 // Y click-click detection
+#define LSM303D_CLICK_SRC_AXIS_Z \
+ 0x04 // Z click-click detection
+#define LSM303D_CLICK_SRC_AXIS_S \
+ 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the LSM303D_O_CLICK_THS
+// register.
+//
+//*****************************************************************************
+#define LSM303D_CLICK_THS_THS_M 0x7F // Threshold; 1 LSB = full-scale /
+ // 128; THS6 through THS0 define
+ // the threshold which is used by
+ // the system to start the click
+ // detection procedure; the
+ // threshold value is expressed
+ // over 7 bits as an unsigned
+ // number
+#define LSM303D_CLICK_THS_THS_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the LSM303D_O_TIME_LIMIT
+// register.
+//
+//*****************************************************************************
+#define LSM303D_TIME_LIMIT_TLI_M \
+ 0x7F // Time Limit; 1 LSB = 1/ODR; TLI7
+ // through TLI0 define the maximum
+ // time interval that can elapse
+ // between the start of the click
+ // detection procedure (the
+ // acceleration on the selected
+ // channel exceeds the programmed
+ // threshold) and when the
+ // acceleration goes back below the
+ // threshold
+#define LSM303D_TIME_LIMIT_TLI_S \
+ 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the LSM303D_O_ACT_THS
+// register.
+//
+//*****************************************************************************
+#define LSM303D_ACT_THS_THRESHOLD_M \
+ 0x7F
+#define LSM303D_ACT_THS_THRESHOLD_S \
+ 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the LSM303D_O_ACT_DUR
+// register.
+//
+//*****************************************************************************
+#define LSM303D_ACT_DUR_THRESHOLD_M \
+ 0x7F
+#define LSM303D_ACT_DUR_THRESHOLD_S \
+ 0
+
+#endif // __SENSORLIB_HW_LSM303D_H__
diff --git a/sensorlib/hw_lsm303dlhc.h b/sensorlib/hw_lsm303dlhc.h
new file mode 100644
index 0000000..06cf9ba
--- /dev/null
+++ b/sensorlib/hw_lsm303dlhc.h
@@ -0,0 +1,1034 @@
+//*****************************************************************************
+//
+// hw_lsm303dlhc.h - Macros used when accessing the ST LSM303DLHC accel/mag
+// combo
+//
+// Copyright (c) 2013-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
+//
+//*****************************************************************************
+
+#ifndef __SENSORLIB_HW_LSM303DLHC_H__
+#define __SENSORLIB_HW_LSM303DLHC_H__
+
+//*****************************************************************************
+//
+// The following are defines for the LSM303DLHC register addresses
+//
+//*****************************************************************************
+#define LSM303DLHC_O_MAG_CRA 0x0 // Magnetometer control
+#define LSM303DLHC_O_MAG_CRB 0x01 // Gain configuration
+#define LSM303DLHC_O_MAG_MR 0x02 // Mode configuration
+#define LSM303DLHC_O_MAG_OUT_X_MSB \
+ 0x03 // X-axis MSB
+#define LSM303DLHC_O_MAG_OUT_X_LSB \
+ 0x04 // X-axis LSB
+#define LSM303DLHC_O_MAG_OUT_Y_MSB \
+ 0x05 // Y-axis MSB
+#define LSM303DLHC_O_MAG_OUT_Y_LSB \
+ 0x06 // Y-axis LSB
+#define LSM303DLHC_O_MAG_OUT_Z_MSB \
+ 0x07 // Z-axis MSB
+#define LSM303DLHC_O_MAG_OUT_Z_LSB \
+ 0x08 // Z-axis LSB
+#define LSM303DLHC_O_MAG_SR 0x09 // Status register
+#define LSM303DLHC_O_MAG_IRA 0x0A
+#define LSM303DLHC_O_MAG_IRB 0x0B
+#define LSM303DLHC_O_MAG_IRC 0x0C
+#define LSM303DLHC_O_CTRL1 0x20 // Control 1 - power settings
+#define LSM303DLHC_O_CTRL2 0x21 // Control 2
+#define LSM303DLHC_O_CTRL3 0x22 // Control 3
+#define LSM303DLHC_O_CTRL4 0x23 // Control 4
+#define LSM303DLHC_O_CTRL5 0x24 // Control 5
+#define LSM303DLHC_O_CTRL6 0x25 // Control 6
+#define LSM303DLHC_O_REFERENCE 0x26 // Reference/Datacapture_A
+#define LSM303DLHC_O_STATUS 0x27 // Status register
+#define LSM303DLHC_O_OUT_X_LSB 0x28 // X-axis LSB
+#define LSM303DLHC_O_OUT_X_MSB 0x29 // X-axis MSB
+#define LSM303DLHC_O_OUT_Y_LSB 0x2A // Y-axis LSB
+#define LSM303DLHC_O_OUT_Y_MSB 0x2B // Y-axis MSB
+#define LSM303DLHC_O_OUT_Z_LSB 0x2C // Z-axis LSB
+#define LSM303DLHC_O_OUT_Z_MSB 0x2D // Z-axis MSB
+#define LSM303DLHC_O_FIFO_CTRL 0x2E // FIFO control
+#define LSM303DLHC_O_FIFO_SRC 0x2F // FIFO_SRC register
+#define LSM303DLHC_O_INT1_CFG_A 0x30 // INT1 interrupt generation; this
+ // register only writable after
+ // boot
+#define LSM303DLHC_O_INT1_SRC_A 0x31 // interrupt source register (read
+ // only)
+#define LSM303DLHC_O_MAG_TEMP_OUT_MSB \
+ 0x31 // Temperature bits 11-4
+#define LSM303DLHC_O_MAG_TEMP_OUT_LSB \
+ 0x32 // Temperature bits 3-0
+#define LSM303DLHC_O_INT1_THS_A 0x32 // Interrupt 1 threshold
+#define LSM303DLHC_O_INT1_DURATION_A \
+ 0x33 // INT1 duration register
+#define LSM303DLHC_O_INT2_CFG_A 0x34 // INT2 interrupt generation; this
+ // register only writable after
+ // boot
+#define LSM303DLHC_O_INT2_SRC_A 0x35 // INT2 source register (read only)
+#define LSM303DLHC_O_INT2_THS_A 0x36 // INT2 threshold
+#define LSM303DLHC_O_INT2_DURATION_A \
+ 0x37 // INT2 duration register
+#define LSM303DLHC_O_CLICK_CFG_A \
+ 0x38 // Click config A register
+#define LSM303DLHC_O_CLICK_SRC_A \
+ 0x39 // Click source A
+#define LSM303DLHC_O_CLICK_THS_A \
+ 0x3A // click-click threshold
+#define LSM303DLHC_O_TIME_LIMIT_A \
+ 0x3B // Time Limit A register
+#define LSM303DLHC_O_TIME_LATENCY_A \
+ 0x3C // Time Latency A register; 1 LSB =
+ // 1/ODR; TLA7 through TLA0 define
+ // the time interval that starts
+ // after the first click detection
+ // where the click detection
+ // procedure is disabled, in cases
+ // where the device is configured
+ // for double click detection
+#define LSM303DLHC_O_TIME_WINDOW_A \
+ 0x3D // Time Window A register; 1 LSB =
+ // 1/ODR; TW7 through TW0 define
+ // the maximum interval of time
+ // that can elapse after the end of
+ // the latency interval in which
+ // the click detection procedure
+ // can start, in cases where the
+ // device is configured for double
+ // click detection
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the LSM303DLHC_O_MAG_CRA
+// register.
+//
+//*****************************************************************************
+#define LSM303DLHC_MAG_CRA_TEMP_M \
+ 0x80 // Temperature sensor enable
+#define LSM303DLHC_MAG_CRA_TEMP_DIS \
+ 0x00
+#define LSM303DLHC_MAG_CRA_TEMP_EN \
+ 0x80
+#define LSM303DLHC_MAG_CRA_DO_M 0x1C // Data output rate
+#define LSM303DLHC_MAG_CRA_DO_0_75HZ \
+ 0x00 // 0.75 Hz
+#define LSM303DLHC_MAG_CRA_DO_1_5HZ \
+ 0x04 // 1.5 Hz
+#define LSM303DLHC_MAG_CRA_DO_3_0HZ \
+ 0x08 // 3.0 Hz
+#define LSM303DLHC_MAG_CRA_DO_7_5HZ \
+ 0x0C // 7.5 Hz
+#define LSM303DLHC_MAG_CRA_DO_15HZ \
+ 0x10 // 15 Hz
+#define LSM303DLHC_MAG_CRA_DO_30HZ \
+ 0x14 // 30 Hz
+#define LSM303DLHC_MAG_CRA_DO_75HZ \
+ 0x18 // 75 Hz
+#define LSM303DLHC_MAG_CRA_DO_220HZ \
+ 0x1C // 220 Hz
+#define LSM303DLHC_MAG_CRA_DO_S 2
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the LSM303DLHC_O_MAG_CRB
+// register.
+//
+//*****************************************************************************
+#define LSM303DLHC_MAG_CRB_GAIN_M \
+ 0xE0 // Gain selection
+#define LSM303DLHC_MAG_CRB_GAIN_1_3GAUSS \
+ 0x20 // +/- 1.3 gauss, 1100 LSB/gauss
+#define LSM303DLHC_MAG_CRB_GAIN_1_9GAUSS \
+ 0x40 // +/- 1.9 gauss, 855 LSB/gauss
+#define LSM303DLHC_MAG_CRB_GAIN_2_5GAUSS \
+ 0x60 // +/- 2.5 gauss, 670 LSB/gauss
+#define LSM303DLHC_MAG_CRB_GAIN_4_0GAUSS \
+ 0x80 // +/- 4.0 gauss, 450 LSB/guass
+#define LSM303DLHC_MAG_CRB_GAIN_4_7GAUSS \
+ 0xA0 // +/- 4.7 gauss, 400 LSB/gauss
+#define LSM303DLHC_MAG_CRB_GAIN_5_6GAUSS \
+ 0xC0 // +/- 5.6 gauss, 330 LSB/gauss
+#define LSM303DLHC_MAG_CRB_GAIN_8_1GAUSS \
+ 0xE0 // +/- 8.1 gauss, 230 LSB/gauss
+#define LSM303DLHC_MAG_CRB_GAIN_S \
+ 5
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the LSM303DLHC_O_MAG_MR
+// register.
+//
+//*****************************************************************************
+#define LSM303DLHC_MAG_MR_MODE_M \
+ 0x3 // Mode select bits
+#define LSM303DLHC_MAG_MR_MODE_CONTINUOUS \
+ 0x00 // Continuous conversion mode
+#define LSM303DLHC_MAG_MR_MODE_SINGLE \
+ 0x01 // Single conversion mode
+#define LSM303DLHC_MAG_MR_MODE_SLEEP \
+ 0x02 // Sleep mode
+#define LSM303DLHC_MAG_MR_MODE_S \
+ 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the LSM303DLHC_O_MAG_SR
+// register.
+//
+//*****************************************************************************
+#define LSM303DLHC_MAG_SR_LOCK_M \
+ 0x02 // Data output register lock; once
+ // a new set of measurements is
+ // available, this bit is set when
+ // the first magnetic field data
+ // register has been read
+#define LSM303DLHC_MAG_SR_LOCK_LOCKED \
+ 0x02
+#define LSM303DLHC_MAG_SR_DATA_M \
+ 0x01 // Data ready bit; this bit is set
+ // when a new set of measures are
+ // available
+#define LSM303DLHC_MAG_SR_DATA_READ \
+ 0x01
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the LSM303DLHC_O_MAG_IRA
+// register.
+//
+//*****************************************************************************
+#define LSM303DLHC_MAG_IRA_CONSTANT_M \
+ 0xFF
+#define LSM303DLHC_MAG_IRA_CONSTANT_VAL \
+ 0x48
+#define LSM303DLHC_MAG_IRA_CONSTANT_S \
+ 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the LSM303DLHC_O_MAG_IRB
+// register.
+//
+//*****************************************************************************
+#define LSM303DLHC_MAG_IRB_CONSTANT_M \
+ 0xFF
+#define LSM303DLHC_MAG_IRB_CONSTANT_VAL \
+ 0x34
+#define LSM303DLHC_MAG_IRB_CONSTANT_S \
+ 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the LSM303DLHC_O_MAG_IRC
+// register.
+//
+//*****************************************************************************
+#define LSM303DLHC_MAG_IRC_CONSTANT_M \
+ 0xFF
+#define LSM303DLHC_MAG_IRC_CONSTANT_VAL \
+ 0x33
+#define LSM303DLHC_MAG_IRC_CONSTANT_S \
+ 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the LSM303DLHC_O_CTRL1
+// register.
+//
+//*****************************************************************************
+#define LSM303DLHC_CTRL1_ODR_M 0xF0 // data rate selection
+#define LSM303DLHC_CTRL1_ODR_PD 0x00 // Power-down mode
+#define LSM303DLHC_CTRL1_ODR_1HZ \
+ 0x10
+#define LSM303DLHC_CTRL1_ODR_10HZ \
+ 0x20
+#define LSM303DLHC_CTRL1_ODR_25HZ \
+ 0x30
+#define LSM303DLHC_CTRL1_ODR_50HZ \
+ 0x40
+#define LSM303DLHC_CTRL1_ODR_100HZ \
+ 0x50
+#define LSM303DLHC_CTRL1_ODR_200HZ \
+ 0x60
+#define LSM303DLHC_CTRL1_ODR_400HZ \
+ 0x70
+#define LSM303DLHC_CTRL1_ODR_1620HZ \
+ 0x80 // Low power mode
+#define LSM303DLHC_CTRL1_ODR_5376HZ \
+ 0x90 // 1.344KHz normal, 5.376KHz low
+ // power
+#define LSM303DLHC_CTRL1_POWER_M \
+ 0x08 // Power control
+#define LSM303DLHC_CTRL1_POWER_LOWPOW \
+ 0x00
+#define LSM303DLHC_CTRL1_POWER_NORMAL \
+ 0x08
+#define LSM303DLHC_CTRL1_AXIS_M 0x7 // Axis power control
+#define LSM303DLHC_CTRL1_AXIS_Y_EN \
+ 0x01 // Y-axis enable
+#define LSM303DLHC_CTRL1_AXIS_X_EN \
+ 0x02 // X-axis enable
+#define LSM303DLHC_CTRL1_AXIS_Z_EN \
+ 0x04 // Z-axis enable
+#define LSM303DLHC_CTRL1_ODR_S 4
+#define LSM303DLHC_CTRL1_AXIS_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the LSM303DLHC_O_CTRL2
+// register.
+//
+//*****************************************************************************
+#define LSM303DLHC_CTRL2_HPMODE_M \
+ 0xC0 // high pass filter mode selection
+#define LSM303DLHC_CTRL2_HPMODE_NORMAL_RESET \
+ 0x00 // normal mode (reset reading
+ // HP_RESET_FILTER)
+#define LSM303DLHC_CTRL2_HPMODE_REFERENCE \
+ 0x40 // reference signal for filtering
+#define LSM303DLHC_CTRL2_HPMODE_NORMAL \
+ 0x80 // Normal mode
+#define LSM303DLHC_CTRL2_HPMODE_AUTORESET \
+ 0xC0 // autoreset on interrupt event
+#define LSM303DLHC_CTRL2_HPCUTOFF_M \
+ 0x30 // high pass filter cut-off
+ // frequency selection
+#define LSM303DLHC_CTRL2_FDS_M 0x08 // Filtered data selection
+#define LSM303DLHC_CTRL2_FDS_BYPASSED \
+ 0x00
+#define LSM303DLHC_CTRL2_FDS_FILTERED \
+ 0x08
+#define LSM303DLHC_CTRL2_HPCLICK_M \
+ 0x04 // High pass filter enabled for
+ // CLICK function
+#define LSM303DLHC_CTRL2_HPCLICK_BYPASSED \
+ 0x00
+#define LSM303DLHC_CTRL2_HPCLICK_FILTERED \
+ 0x04
+#define LSM303DLHC_CTRL2_HPIS2_M \
+ 0x02 // High pass filter enabled for AOI
+ // function on Interrupt 2
+#define LSM303DLHC_CTRL2_HPIS2_BYPASSED \
+ 0x00
+#define LSM303DLHC_CTRL2_HPIS2_FILTERED \
+ 0x02
+#define LSM303DLHC_CTRL2_HPIS1_M \
+ 0x01 // High pass filter enabled for AOI
+ // function on Interrupt 1
+#define LSM303DLHC_CTRL2_HPIS1_BYPASSED \
+ 0x00
+#define LSM303DLHC_CTRL2_HPIS1_FILTERED \
+ 0x01
+#define LSM303DLHC_CTRL2_HPMODE_S \
+ 6
+#define LSM303DLHC_CTRL2_HPCUTOFF_S \
+ 4
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the LSM303DLHC_O_CTRL3
+// register.
+//
+//*****************************************************************************
+#define LSM303DLHC_CTRL3_I1CLICK_M \
+ 0x80 // CLICK on INT1
+#define LSM303DLHC_CTRL3_I1CLICK_DIS \
+ 0x00
+#define LSM303DLHC_CTRL3_I1CLICK_EN \
+ 0x80
+#define LSM303DLHC_CTRL3_I1AOI1_M \
+ 0x40 // AOI1 on INT1
+#define LSM303DLHC_CTRL3_I1AOI1_DIS \
+ 0x00
+#define LSM303DLHC_CTRL3_I1AOI1_EN \
+ 0x40
+#define LSM303DLHC_CTRL3_I1AOI2_M \
+ 0x20 // AOI2 on INT1
+#define LSM303DLHC_CTRL3_I1AOI2_DIS \
+ 0x00
+#define LSM303DLHC_CTRL3_I1AOI2_EN \
+ 0x20
+#define LSM303DLHC_CTRL3_I1DRDY1_M \
+ 0x10 // DRDY1 on INT1
+#define LSM303DLHC_CTRL3_I1DRDY1_DIS \
+ 0x00
+#define LSM303DLHC_CTRL3_I1DRDY1_EN \
+ 0x10
+#define LSM303DLHC_CTRL3_I1DRDY2_M \
+ 0x08 // DRDY2 on INT1
+#define LSM303DLHC_CTRL3_I1DRDY2_DIS \
+ 0x00
+#define LSM303DLHC_CTRL3_I1DRDY2_EN \
+ 0x08
+#define LSM303DLHC_CTRL3_I1WTM_M \
+ 0x04 // FIFO watermark interrupt on INT1
+#define LSM303DLHC_CTRL3_I1WTM_DIS \
+ 0x00
+#define LSM303DLHC_CTRL3_I1WTM_EN \
+ 0x04
+#define LSM303DLHC_CTRL3_I1OVERRUN_M \
+ 0x02 // FIFO overrun interrupt on INT1
+#define LSM303DLHC_CTRL3_I1OVERRUN_DIS \
+ 0x00
+#define LSM303DLHC_CTRL3_I1OVERRUN_EN \
+ 0x02
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the LSM303DLHC_O_CTRL4
+// register.
+//
+//*****************************************************************************
+#define LSM303DLHC_CTRL4_BDU_M 0x80 // Block data update; default
+ // value: 0 (0: continuous update;
+ // 1: output registers not updated
+ // until MSB and LSB reading)
+#define LSM303DLHC_CTRL4_BDU_CONTINUOUS \
+ 0x00
+#define LSM303DLHC_CTRL4_BDU_MSBLSB \
+ 0x80
+#define LSM303DLHC_CTRL4_ENDIAN_M \
+ 0x40 // Endian selection
+#define LSM303DLHC_CTRL4_ENDIAN_LITTLE \
+ 0x00
+#define LSM303DLHC_CTRL4_ENDIAN_BIG \
+ 0x40
+#define LSM303DLHC_CTRL4_FS_M 0x30 // full scale selection; default
+ // value: 0
+#define LSM303DLHC_CTRL4_FS_2G 0x00
+#define LSM303DLHC_CTRL4_FS_4G 0x10
+#define LSM303DLHC_CTRL4_FS_8G 0x20
+#define LSM303DLHC_CTRL4_FS_16G 0x30
+#define LSM303DLHC_CTRL4_RESOLUTION_M \
+ 0x08 // resolution output mode
+#define LSM303DLHC_CTRL4_RESOLUTION_LOW \
+ 0x00
+#define LSM303DLHC_CTRL4_RESOLUTION_HIGH \
+ 0x08
+#define LSM303DLHC_CTRL4_SIM_M 0x01 // SPI Serial Interface Mode
+ // selection (default = 0, 4-wire)
+#define LSM303DLHC_CTRL4_SIM_4WIRE \
+ 0x00
+#define LSM303DLHC_CTRL4_SIM_3WIRE \
+ 0x01
+#define LSM303DLHC_CTRL4_FS_S 4
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the LSM303DLHC_O_CTRL5
+// register.
+//
+//*****************************************************************************
+#define LSM303DLHC_CTRL5_REBOOTCTL_M \
+ 0x80 // Reboot memory conent
+#define LSM303DLHC_CTRL5_REBOOTCTL_NORMAL \
+ 0x00
+#define LSM303DLHC_CTRL5_REBOOTCTL_REBOOT \
+ 0x80
+#define LSM303DLHC_CTRL5_FIFO_M 0x40 // FIFO enable
+#define LSM303DLHC_CTRL5_FIFO_DIS \
+ 0x00
+#define LSM303DLHC_CTRL5_FIFO_EN \
+ 0x40
+#define LSM303DLHC_CTRL5_LIR_INT1_M \
+ 0x08 // Latch interrupt on INT1
+#define LSM303DLHC_CTRL5_LIR_INT1_DIS \
+ 0x00
+#define LSM303DLHC_CTRL5_LIR_INT1_EN \
+ 0x08
+#define LSM303DLHC_CTRL5_D4D_INT1_M \
+ 0x04 // 4D Int enable on INT1
+#define LSM303DLHC_CTRL5_D4D_INT1_DIS \
+ 0x00
+#define LSM303DLHC_CTRL5_D4D_INT1_EN \
+ 0x04
+#define LSM303DLHC_CTRL5_LIR_INT2_M \
+ 0x02 // Latch interrupt request on
+ // INT2_SRC register, with INT2_SRC
+ // register cleared by reading
+ // INT2_SRC itself; default value:
+ // 0
+#define LSM303DLHC_CTRL5_LIR_INT2_DIS \
+ 0x00
+#define LSM303DLHC_CTRL5_LIR_INT2_EN \
+ 0x02
+#define LSM303DLHC_CTRL5_D4D_INT2_M \
+ 0x01 // 4D enable: 4D detection is
+ // enabled on INT2 when 6D bit on
+ // INT2_CFG is set to 1
+#define LSM303DLHC_CTRL5_D4D_INT2_DIS \
+ 0x00
+#define LSM303DLHC_CTRL5_D4D_INT2_EN \
+ 0x01
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the LSM303DLHC_O_CTRL6
+// register.
+//
+//*****************************************************************************
+#define LSM303DLHC_CTRL6_I2_CLICK_M \
+ 0x80 // CLICK interrupt on PAD2
+#define LSM303DLHC_CTRL6_I2_CLICK_DIS \
+ 0x00
+#define LSM303DLHC_CTRL6_I2_CLICK_EN \
+ 0x80
+#define LSM303DLHC_CTRL6_I2_INT1_M \
+ 0x40 // Interrupt 1 on PAD2; default
+ // value 0
+#define LSM303DLHC_CTRL6_I2_INT1_DIS \
+ 0x00
+#define LSM303DLHC_CTRL6_I2_INT1_EN \
+ 0x40
+#define LSM303DLHC_CTRL6_I2_INT2_M \
+ 0x20 // Interrupt 2 on PAD2; default
+ // value 0
+#define LSM303DLHC_CTRL6_I2_INT2_DIS \
+ 0x00
+#define LSM303DLHC_CTRL6_I2_INT2_EN \
+ 0x20
+#define LSM303DLHC_CTRL6_BOOT_I2_M \
+ 0x10 // Reboot memory content on PAD2;
+ // default value: 0
+#define LSM303DLHC_CTRL6_BOOT_I2_DIS \
+ 0x00
+#define LSM303DLHC_CTRL6_BOOT_I2_EN \
+ 0x10
+#define LSM303DLHC_CTRL6_P2_ACT_M \
+ 0x08 // active function status on PAD2
+#define LSM303DLHC_CTRL6_P2_ACT_DIS \
+ 0x00
+#define LSM303DLHC_CTRL6_P2_ACT_EN \
+ 0x08
+#define LSM303DLHC_CTRL6_H_LACTIVE_M \
+ 0x02 // interrupt active configuration
+ // on INT; default value 0 (0:
+ // high; 1:low)
+#define LSM303DLHC_CTRL6_H_LACTIVE_HI \
+ 0x00
+#define LSM303DLHC_CTRL6_H_LACTIVE_LOW \
+ 0x02
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the LSM303DLHC_O_STATUS
+// register.
+//
+//*****************************************************************************
+#define LSM303DLHC_STATUS_OR_M 0xF0 // Axis data overrun
+#define LSM303DLHC_STATUS_OR_X 0x10 // X-axis data overrun
+#define LSM303DLHC_STATUS_OR_Y 0x20 // Y-axis data overrun
+#define LSM303DLHC_STATUS_OR_Z 0x40 // Z-axis data overrun
+#define LSM303DLHC_STATUS_OR_ZYX \
+ 0x80 // X, Y, and X data overrun
+#define LSM303DLHC_STATUS_DA_M 0xF // Axis data available
+#define LSM303DLHC_STATUS_DA_X 0x01 // X-axis data available
+#define LSM303DLHC_STATUS_DA_Y 0x02 // Y-axis data available
+#define LSM303DLHC_STATUS_DA_Z 0x04 // Z-axis data available
+#define LSM303DLHC_STATUS_DA_ZYX \
+ 0x08 // X, Y, and X data available
+#define LSM303DLHC_STATUS_OR_S 4
+#define LSM303DLHC_STATUS_DA_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the LSM303DLHC_O_FIFO_CTRL
+// register.
+//
+//*****************************************************************************
+#define LSM303DLHC_FIFO_CTRL_TR_M \
+ 0x20
+#define LSM303DLHC_FIFO_CTRL_TR_INT1 \
+ 0x00
+#define LSM303DLHC_FIFO_CTRL_TR_INT2 \
+ 0x20
+#define LSM303DLHC_FIFO_CTRL_THRESH_M \
+ 0x1F // FIFO Threshold setting
+#define LSM303DLHC_FIFO_CTRL_MODE_M \
+ 0xC // FIFO mode setting
+#define LSM303DLHC_FIFO_CTRL_MODE_BYPASS \
+ 0x00 // Bypass mode
+#define LSM303DLHC_FIFO_CTRL_MODE_FIFO \
+ 0x40 // FIFO mode
+#define LSM303DLHC_FIFO_CTRL_MODE_STREAM \
+ 0x80 // Stream mode
+#define LSM303DLHC_FIFO_CTRL_MODE_TRIGGER \
+ 0xC0 // Trigger mode
+#define LSM303DLHC_FIFO_CTRL_MODE_S \
+ 6
+#define LSM303DLHC_FIFO_CTRL_THRESH_S \
+ 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the LSM303DLHC_O_FIFO_SRC
+// register.
+//
+//*****************************************************************************
+#define LSM303DLHC_FIFO_SRC_FTH_M \
+ 0x80 // FIFO threshold is greater than
+ // or equal to level or less than
+ // level
+#define LSM303DLHC_FIFO_SRC_FTH_LT \
+ 0x00
+#define LSM303DLHC_FIFO_SRC_FTH_GEQ \
+ 0x80
+#define LSM303DLHC_FIFO_SRC_OVRN_M \
+ 0x40 // overrun status bit
+#define LSM303DLHC_FIFO_SRC_OVRN_FILLED \
+ 0x40
+#define LSM303DLHC_FIFO_SRC_EMPTY_M \
+ 0x20 // FIFO empty
+#define LSM303DLHC_FIFO_SRC_EMPTY_EMPTY \
+ 0x20
+#define LSM303DLHC_FIFO_SRC_STORE_SAMPLES_M \
+ 0x1F // FIFO stored data level of the
+ // unread samples
+#define LSM303DLHC_FIFO_SRC_STORE_SAMPLES_S \
+ 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the LSM303DLHC_O_INT1_CFG_A
+// register.
+//
+//*****************************************************************************
+#define LSM303DLHC_INT1_CFG_A_ANDOR_M \
+ 0x80 // AND/OR combination of Interrupt
+ // events; default value: 0
+#define LSM303DLHC_INT1_CFG_A_ANDOR_OR \
+ 0x00
+#define LSM303DLHC_INT1_CFG_A_ANDOR_AND \
+ 0x80
+#define LSM303DLHC_INT1_CFG_A_6D_M \
+ 0x40 // 6-direction function enabled
+#define LSM303DLHC_INT1_CFG_A_6D_EN \
+ 0x40
+#define LSM303DLHC_INT1_CFG_A_ZHI_M \
+ 0x20 // enable interrupt generation on
+ // Z-hi event
+#define LSM303DLHC_INT1_CFG_A_ZHI_EN \
+ 0x20
+#define LSM303DLHC_INT1_CFG_A_ZUPE_M \
+ 0x20 // enable interrupt generation on
+ // Z-hi event
+#define LSM303DLHC_INT1_CFG_A_ZUPE_EN \
+ 0x20
+#define LSM303DLHC_INT1_CFG_A_ZDOWNE_M \
+ 0x10 // enable interrupt generation on
+ // Z-low event
+#define LSM303DLHC_INT1_CFG_A_ZDOWNE_EN \
+ 0x10
+#define LSM303DLHC_INT1_CFG_A_ZLI_M \
+ 0x10 // enable interrupt generation on
+ // Z-low event
+#define LSM303DLHC_INT1_CFG_A_ZLI_EN \
+ 0x10
+#define LSM303DLHC_INT1_CFG_A_YUPE_M \
+ 0x08 // enable interrupt generation on
+ // Y-hi event
+#define LSM303DLHC_INT1_CFG_A_YUPE_EN \
+ 0x08
+#define LSM303DLHC_INT1_CFG_A_YHI_M \
+ 0x08 // enable interrupt generation on
+ // Y-hi event
+#define LSM303DLHC_INT1_CFG_A_YHI_EN \
+ 0x08
+#define LSM303DLHC_INT1_CFG_A_YDOWNE_M \
+ 0x04 // enable interrupt generation on
+ // Y-low event
+#define LSM303DLHC_INT1_CFG_A_YDOWNE_EN \
+ 0x04
+#define LSM303DLHC_INT1_CFG_A_YLI_M \
+ 0x04 // enable interrupt generation on
+ // Y-low event
+#define LSM303DLHC_INT1_CFG_A_YLI_EN \
+ 0x04
+#define LSM303DLHC_INT1_CFG_A_XHI_M \
+ 0x02 // enable interrupt generation on
+ // X-hi event
+#define LSM303DLHC_INT1_CFG_A_XHI_EN \
+ 0x02
+#define LSM303DLHC_INT1_CFG_A_XUPE_M \
+ 0x02 // enable interrupt generation on
+ // X-hi event
+#define LSM303DLHC_INT1_CFG_A_XUPE_EN \
+ 0x02
+#define LSM303DLHC_INT1_CFG_A_XLI_M \
+ 0x01 // enable interrupt generation on
+ // X-low event
+#define LSM303DLHC_INT1_CFG_A_XLI_EN \
+ 0x01
+#define LSM303DLHC_INT1_CFG_A_XDOWNE_M \
+ 0x01 // enable interrupt generation on
+ // X-low event
+#define LSM303DLHC_INT1_CFG_A_XDOWNE_EN \
+ 0x01
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the LSM303DLHC_O_INT1_SRC_A
+// register.
+//
+//*****************************************************************************
+#define LSM303DLHC_INT1_SRC_A_ZERO_M \
+ 0x80 // This bit must be zero
+#define LSM303DLHC_INT1_SRC_A_ZERO_ZERO \
+ 0x00
+#define LSM303DLHC_INT1_SRC_A_ZERO_INVALID \
+ 0x80
+#define LSM303DLHC_INT1_SRC_A_IA_M \
+ 0x40 // interrupt active
+#define LSM303DLHC_INT1_SRC_A_IA_ACTIVE \
+ 0x40
+#define LSM303DLHC_INT1_SRC_A_ZH_M \
+ 0x20 // Z-Hi event occurred
+#define LSM303DLHC_INT1_SRC_A_ZH_OCCURRED \
+ 0x20
+#define LSM303DLHC_INT1_SRC_A_ZL_M \
+ 0x10 // Z-Low event occurred
+#define LSM303DLHC_INT1_SRC_A_ZL_OCCURRED \
+ 0x10
+#define LSM303DLHC_INT1_SRC_A_YH_M \
+ 0x08 // Y-Hi event occurred
+#define LSM303DLHC_INT1_SRC_A_YH_OCCURRED \
+ 0x08
+#define LSM303DLHC_INT1_SRC_A_YL_M \
+ 0x04 // Y-Low event occurred
+#define LSM303DLHC_INT1_SRC_A_YL_OCCURRED \
+ 0x04
+#define LSM303DLHC_INT1_SRC_A_XH_M \
+ 0x02 // X-Hi event occurred
+#define LSM303DLHC_INT1_SRC_A_XH_OCCURRED \
+ 0x02
+#define LSM303DLHC_INT1_SRC_A_XL_M \
+ 0x01 // X-Low event occurred
+#define LSM303DLHC_INT1_SRC_A_XL_OCCURRED \
+ 0x01
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the
+// LSM303DLHC_O_MAG_TEMP_OUT_MSB register.
+//
+//*****************************************************************************
+#define LSM303DLHC_MAG_TEMP_OUT_MSB_MSB_M \
+ 0xFF
+#define LSM303DLHC_MAG_TEMP_OUT_MSB_MSB_S \
+ 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the
+// LSM303DLHC_O_MAG_TEMP_OUT_LSB register.
+//
+//*****************************************************************************
+#define LSM303DLHC_MAG_TEMP_OUT_LSB_LSB_M \
+ 0xF0
+#define LSM303DLHC_MAG_TEMP_OUT_LSB_LSB_S \
+ 4
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the LSM303DLHC_O_INT1_THS_A
+// register.
+//
+//*****************************************************************************
+#define LSM303DLHC_INT1_THS_A_ZERO_M \
+ 0x80 // This bit must be zero
+#define LSM303DLHC_INT1_THS_A_ZERO_ZERO \
+ 0x00
+#define LSM303DLHC_INT1_THS_A_ZERO_INVALID \
+ 0x80
+#define LSM303DLHC_INT1_THS_A_THS_M \
+ 0x7F // THS[6-0] Interrupt threshold,
+ // default 0x0
+#define LSM303DLHC_INT1_THS_A_THS_S \
+ 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the
+// LSM303DLHC_O_INT1_DURATION_A register.
+//
+//*****************************************************************************
+#define LSM303DLHC_INT1_DURATION_A_ZERO_M \
+ 0x80 // This bit must be zero
+#define LSM303DLHC_INT1_DURATION_A_ZERO_ZERO \
+ 0x00
+#define LSM303DLHC_INT1_DURATION_A_ZERO_INVALID \
+ 0x80
+#define LSM303DLHC_INT1_DURATION_A_DURATION_M \
+ 0x7F // Duration D[6-0]
+#define LSM303DLHC_INT1_DURATION_A_DURATION_S \
+ 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the LSM303DLHC_O_INT2_CFG_A
+// register.
+//
+//*****************************************************************************
+#define LSM303DLHC_INT2_CFG_A_ANDOR_M \
+ 0x80 // AND/OR combination of Interrupt
+ // events; default value: 0
+#define LSM303DLHC_INT2_CFG_A_ANDOR_OR \
+ 0x00
+#define LSM303DLHC_INT2_CFG_A_ANDOR_AND \
+ 0x80
+#define LSM303DLHC_INT2_CFG_A_6D_M \
+ 0x40 // 6-direction function enabled
+#define LSM303DLHC_INT2_CFG_A_6D_EN \
+ 0x40
+#define LSM303DLHC_INT2_CFG_A_ZHI_M \
+ 0x20 // enable interrupt generation on
+ // Z-hi event
+#define LSM303DLHC_INT2_CFG_A_ZHI_EN \
+ 0x20
+#define LSM303DLHC_INT2_CFG_A_ZLI_M \
+ 0x10 // enable interrupt generation on
+ // Z-low event
+#define LSM303DLHC_INT2_CFG_A_ZLI_EN \
+ 0x10
+#define LSM303DLHC_INT2_CFG_A_YHI_M \
+ 0x08 // enable interrupt generation on
+ // Y-hi event
+#define LSM303DLHC_INT2_CFG_A_YHI_EN \
+ 0x08
+#define LSM303DLHC_INT2_CFG_A_YLI_M \
+ 0x04 // enable interrupt generation on
+ // Y-low event
+#define LSM303DLHC_INT2_CFG_A_YLI_EN \
+ 0x04
+#define LSM303DLHC_INT2_CFG_A_XHI_M \
+ 0x02 // enable interrupt generation on
+ // X-hi event
+#define LSM303DLHC_INT2_CFG_A_XHI_EN \
+ 0x02
+#define LSM303DLHC_INT2_CFG_A_XLI_M \
+ 0x01 // enable interrupt generation on
+ // X-low event
+#define LSM303DLHC_INT2_CFG_A_XLI_EN \
+ 0x01
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the LSM303DLHC_O_INT2_SRC_A
+// register.
+//
+//*****************************************************************************
+#define LSM303DLHC_INT2_SRC_A_ZERO_M \
+ 0x80 // This bit must be zero
+#define LSM303DLHC_INT2_SRC_A_ZERO_ZERO \
+ 0x00
+#define LSM303DLHC_INT2_SRC_A_ZERO_INVALID \
+ 0x80
+#define LSM303DLHC_INT2_SRC_A_IA_M \
+ 0x40 // interrupt active
+#define LSM303DLHC_INT2_SRC_A_IA_ACTIVE \
+ 0x40
+#define LSM303DLHC_INT2_SRC_A_ZH_M \
+ 0x20 // Z-Hi event occurred
+#define LSM303DLHC_INT2_SRC_A_ZH_OCCURRED \
+ 0x20
+#define LSM303DLHC_INT2_SRC_A_ZL_M \
+ 0x10 // Z-Low event occurred
+#define LSM303DLHC_INT2_SRC_A_ZL_OCCURRED \
+ 0x10
+#define LSM303DLHC_INT2_SRC_A_YH_M \
+ 0x08 // Y-Hi event occurred
+#define LSM303DLHC_INT2_SRC_A_YH_OCCURRED \
+ 0x08
+#define LSM303DLHC_INT2_SRC_A_YL_M \
+ 0x04 // Y-Low event occurred
+#define LSM303DLHC_INT2_SRC_A_YL_OCCURRED \
+ 0x04
+#define LSM303DLHC_INT2_SRC_A_XH_M \
+ 0x02 // X-Hi event occurred
+#define LSM303DLHC_INT2_SRC_A_XH_OCCURRED \
+ 0x02
+#define LSM303DLHC_INT2_SRC_A_XL_M \
+ 0x01 // X-Low event occurred
+#define LSM303DLHC_INT2_SRC_A_XL_OCCURRED \
+ 0x01
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the LSM303DLHC_O_INT2_THS_A
+// register.
+//
+//*****************************************************************************
+#define LSM303DLHC_INT2_THS_A_ZERO_M \
+ 0x80 // This bit must be zero
+#define LSM303DLHC_INT2_THS_A_ZERO_ZERO \
+ 0x00
+#define LSM303DLHC_INT2_THS_A_ZERO_INVALID \
+ 0x80
+#define LSM303DLHC_INT2_THS_A_THS_M \
+ 0x7F // THS[6-0] Interrupt threshold,
+ // default 0x0
+#define LSM303DLHC_INT2_THS_A_THS_S \
+ 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the
+// LSM303DLHC_O_INT2_DURATION_A register.
+//
+//*****************************************************************************
+#define LSM303DLHC_INT2_DURATION_A_ZERO_M \
+ 0x80 // This bit must be zero
+#define LSM303DLHC_INT2_DURATION_A_ZERO_ZERO \
+ 0x00
+#define LSM303DLHC_INT2_DURATION_A_ZERO_INVALID \
+ 0x80
+#define LSM303DLHC_INT2_DURATION_A_DURATION_M \
+ 0x7F // Duration D[6-0]
+#define LSM303DLHC_INT2_DURATION_A_DURATION_S \
+ 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the LSM303DLHC_O_CLICK_CFG_A
+// register.
+//
+//*****************************************************************************
+#define LSM303DLHC_CLICK_CFG_A_ZD_M \
+ 0x20 // Enable interrupt double click on
+ // Z axis
+#define LSM303DLHC_CLICK_CFG_A_ZD_DIS \
+ 0x00
+#define LSM303DLHC_CLICK_CFG_A_ZD_EN \
+ 0x20
+#define LSM303DLHC_CLICK_CFG_A_ZS_M \
+ 0x10 // Enable interrupt single click on
+ // Z axis
+#define LSM303DLHC_CLICK_CFG_A_ZS_DIS \
+ 0x00
+#define LSM303DLHC_CLICK_CFG_A_ZS_EN \
+ 0x10
+#define LSM303DLHC_CLICK_CFG_A_YD_M \
+ 0x08 // Enable interrupt double click on
+ // Y axis
+#define LSM303DLHC_CLICK_CFG_A_YD_DIS \
+ 0x00
+#define LSM303DLHC_CLICK_CFG_A_YD_EN \
+ 0x08
+#define LSM303DLHC_CLICK_CFG_A_YS_M \
+ 0x04 // Enable interrupt single click on
+ // Y axis
+#define LSM303DLHC_CLICK_CFG_A_YS_DIS \
+ 0x00
+#define LSM303DLHC_CLICK_CFG_A_YS_EN \
+ 0x04
+#define LSM303DLHC_CLICK_CFG_A_XD_M \
+ 0x02 // Enable interrupt double click on
+ // X axis
+#define LSM303DLHC_CLICK_CFG_A_XD_DIS \
+ 0x00
+#define LSM303DLHC_CLICK_CFG_A_XD_EN \
+ 0x02
+#define LSM303DLHC_CLICK_CFG_A_XS_M \
+ 0x01 // Enable interrupt single click on
+ // X axis
+#define LSM303DLHC_CLICK_CFG_A_XS_DIS \
+ 0x00
+#define LSM303DLHC_CLICK_CFG_A_XS_EN \
+ 0x01
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the LSM303DLHC_O_CLICK_SRC_A
+// register.
+//
+//*****************************************************************************
+#define LSM303DLHC_CLICK_SRC_A_IA_M \
+ 0x40 // Interrupt pending
+#define LSM303DLHC_CLICK_SRC_A_IA_NONE \
+ 0x00
+#define LSM303DLHC_CLICK_SRC_A_IA_PENDING \
+ 0x40
+#define LSM303DLHC_CLICK_SRC_A_DCLICK_M \
+ 0x20 // double click-click enable
+#define LSM303DLHC_CLICK_SRC_A_DCLICK_DIS \
+ 0x00
+#define LSM303DLHC_CLICK_SRC_A_DCLICK_EN \
+ 0x20
+#define LSM303DLHC_CLICK_SRC_A_SCLICK_M \
+ 0x10 // single click-click enable
+#define LSM303DLHC_CLICK_SRC_A_SCLICK_DIS \
+ 0x00
+#define LSM303DLHC_CLICK_SRC_A_SCLICK_EN \
+ 0x10
+#define LSM303DLHC_CLICK_SRC_A_SIGN_M \
+ 0x08 // click-click sign
+#define LSM303DLHC_CLICK_SRC_A_SIGN_POSITIVE \
+ 0x00
+#define LSM303DLHC_CLICK_SRC_A_SIGN_NEGATIVE \
+ 0x08
+#define LSM303DLHC_CLICK_SRC_A_AXIS_M \
+ 0x7 // Axis click detection
+#define LSM303DLHC_CLICK_SRC_A_AXIS_X \
+ 0x01 // X click-click detection
+#define LSM303DLHC_CLICK_SRC_A_AXIS_Y \
+ 0x02 // Y click-click detection
+#define LSM303DLHC_CLICK_SRC_A_AXIS_Z \
+ 0x04 // Z click-click detection
+#define LSM303DLHC_CLICK_SRC_A_AXIS_S \
+ 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the LSM303DLHC_O_CLICK_THS_A
+// register.
+//
+//*****************************************************************************
+#define LSM303DLHC_CLICK_THS_A_THS_M \
+ 0x7F // Threshold; 1 LSB = full-scale /
+ // 128; THS6 through THS0 define
+ // the threshold which is used by
+ // the system to start the click
+ // detection procedure; the
+ // threshold value is expressed
+ // over 7 bits as an unsigned
+ // number
+#define LSM303DLHC_CLICK_THS_A_THS_S \
+ 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the
+// LSM303DLHC_O_TIME_LIMIT_A register.
+//
+//*****************************************************************************
+#define LSM303DLHC_TIME_LIMIT_A_TLI_M \
+ 0x7F // Time Limit; 1 LSB = 1/ODR; TLI7
+ // through TLI0 define the maximum
+ // time interval that can elapse
+ // between the start of the click
+ // detection procedure (the
+ // acceleration on the selected
+ // channel exceeds the programmed
+ // threshold) and when the
+ // acceleration goes back below the
+ // threshold
+#define LSM303DLHC_TIME_LIMIT_A_TLI_S \
+ 0
+
+#endif // __SENSORLIB_HW_LSM303DLHC_H__
diff --git a/sensorlib/hw_mpu6050.h b/sensorlib/hw_mpu6050.h
new file mode 100644
index 0000000..32706e9
--- /dev/null
+++ b/sensorlib/hw_mpu6050.h
@@ -0,0 +1,1313 @@
+//*****************************************************************************
+//
+// hw_mpu6050.h - Macros used when accessing the Invensense MPU6050
+// accelerometer/gyroscope/magnetometer.
+//
+// Copyright (c) 2013-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
+//
+//*****************************************************************************
+
+#ifndef __SENSORLIB_HW_MPU6050_H__
+#define __SENSORLIB_HW_MPU6050_H__
+
+//*****************************************************************************
+//
+// The following are defines for the MPU6050 register addresses.
+//
+//*****************************************************************************
+#define MPU6050_O_SELF_TEST_X 0x0D // Self test X register
+#define MPU6050_O_SELF_TEST_Y 0x0E // Self test Y register
+#define MPU6050_O_SELF_TEST_Z 0x0F // Self test Z register
+#define MPU6050_O_SELF_TEST_A 0x10 // Self test A register
+#define MPU6050_O_SMPLRT_DIV 0x19 // Sample rate divider register
+#define MPU6050_O_CONFIG 0x1A // Configuration register
+#define MPU6050_O_GYRO_CONFIG 0x1B // Gyro configuration register
+#define MPU6050_O_ACCEL_CONFIG 0x1C // Accelerometer configuration
+ // register
+#define MPU6050_O_MOT_THR 0x1F // Motion detection threshold
+ // register
+#define MPU6050_O_FIFO_EN 0x23 // FIFO enable register
+#define MPU6050_O_I2C_MST_CTRL 0x24 // I2C master control register
+#define MPU6050_O_I2C_SLV0_ADDR 0x25 // I2C slave 0 address register
+#define MPU6050_O_I2C_SLV0_REG 0x26 // I2C slave 0 register number
+ // register
+#define MPU6050_O_I2C_SLV0_CTRL 0x27 // I2C slave 0 control register
+#define MPU6050_O_I2C_SLV1_ADDR 0x28 // I2C slave 1 address register
+#define MPU6050_O_I2C_SLV1_REG 0x29 // I2C slave 1 register number
+ // register
+#define MPU6050_O_I2C_SLV1_CTRL 0x2A // I2C slave 1 control register
+#define MPU6050_O_I2C_SLV2_ADDR 0x2B // I2C slave 2 address register
+#define MPU6050_O_I2C_SLV2_REG 0x2C // I2C slave 2 register number
+ // register
+#define MPU6050_O_I2C_SLV2_CTRL 0x2D // I2C slave 2 control register
+#define MPU6050_O_I2C_SLV3_ADDR 0x2E // I2C slave 3 address register
+#define MPU6050_O_I2C_SLV3_REG 0x2F // I2C slave 3 register number
+ // register
+#define MPU6050_O_I2C_SLV3_CTRL 0x30 // I2C slave 3 control register
+#define MPU6050_O_I2C_SLV4_ADDR 0x31 // I2C slave 4 address register
+#define MPU6050_O_I2C_SLV4_REG 0x32 // I2C slave 4 register number
+ // register
+#define MPU6050_O_I2C_SLV4_DO 0x33 // I2C slave 4 output data register
+#define MPU6050_O_I2C_SLV4_CTRL 0x34 // I2C slave 4 control register
+#define MPU6050_O_I2C_SLV4_DI 0x35 // I2C slave 4 input data register
+#define MPU6050_O_I2C_MST_STATUS \
+ 0x36 // I2C master status register
+#define MPU6050_O_INT_PIN_CFG 0x37 // INT pin configuration register
+#define MPU6050_O_INT_ENABLE 0x38 // Interrupt enable register
+#define MPU6050_O_INT_STATUS 0x3A // Interrupt status register
+#define MPU6050_O_ACCEL_XOUT_H 0x3B // X-axis acceleration data MSB
+ // register
+#define MPU6050_O_ACCEL_XOUT_L 0x3C // X-axis acceleration data LSB
+ // register
+#define MPU6050_O_ACCEL_YOUT_H 0x3D // Y-axis acceleration data MSB
+ // register
+#define MPU6050_O_ACCEL_YOUT_L 0x3E // Y-axis accelearation data LSB
+ // register
+#define MPU6050_O_ACCEL_ZOUT_H 0x3F // Z-axis acceleration data MSB
+ // register
+#define MPU6050_O_ACCEL_ZOUT_L 0x40 // Z-axis acceleration data LSB
+ // register
+#define MPU6050_O_TEMP_OUT_H 0x41 // Temperature data MSB register
+#define MPU6050_O_TEMP_OUT_L 0x42 // Temperature data LSB register
+#define MPU6050_O_GYRO_XOUT_H 0x43 // X-axis gyro data MSB register
+#define MPU6050_O_GYRO_XOUT_L 0x44 // X-axis gyro data LSB register
+#define MPU6050_O_GYRO_YOUT_H 0x45 // Y-axis gyro data MSB register
+#define MPU6050_O_GYRO_YOUT_L 0x46 // Y-axis gyro data LSB register
+#define MPU6050_O_GYRO_ZOUT_H 0x47 // Z-axis gyro data MSB register
+#define MPU6050_O_GYRO_ZOUT_L 0x48 // Z-axis gyro data LSB register
+#define MPU6050_O_EXT_SENS_DATA_00 \
+ 0x49 // External sensor data 0 register
+#define MPU6050_O_EXT_SENS_DATA_01 \
+ 0x4A // External sensor data 1 register
+#define MPU6050_O_EXT_SENS_DATA_02 \
+ 0x4B // External sensor data 2 register
+#define MPU6050_O_EXT_SENS_DATA_03 \
+ 0x4C // External sensor data 3 register
+#define MPU6050_O_EXT_SENS_DATA_04 \
+ 0x4D // External sensor data 4 register
+#define MPU6050_O_EXT_SENS_DATA_05 \
+ 0x4E // External sensor data 5 register
+#define MPU6050_O_EXT_SENS_DATA_06 \
+ 0x4F // External sensor data 6 register
+#define MPU6050_O_EXT_SENS_DATA_07 \
+ 0x50 // External sensor data 7 register
+#define MPU6050_O_EXT_SENS_DATA_08 \
+ 0x51 // External sensor data 8 register
+#define MPU6050_O_EXT_SENS_DATA_09 \
+ 0x52 // External sensor data 9 register
+#define MPU6050_O_EXT_SENS_DATA_10 \
+ 0x53 // External sensor data 10 register
+#define MPU6050_O_EXT_SENS_DATA_11 \
+ 0x54 // External sensor data 11 register
+#define MPU6050_O_EXT_SENS_DATA_12 \
+ 0x55 // External sensor data 12 register
+#define MPU6050_O_EXT_SENS_DATA_13 \
+ 0x56 // External sensor data 13 register
+#define MPU6050_O_EXT_SENS_DATA_14 \
+ 0x57 // External sensor data 14 register
+#define MPU6050_O_EXT_SENS_DATA_15 \
+ 0x58 // External sensor data 15 register
+#define MPU6050_O_EXT_SENS_DATA_16 \
+ 0x59 // External sensor data 16 register
+#define MPU6050_O_EXT_SENS_DATA_17 \
+ 0x5A // External sensor data 17 register
+#define MPU6050_O_EXT_SENS_DATA_18 \
+ 0x5B // External sensor data 18 register
+#define MPU6050_O_EXT_SENS_DATA_19 \
+ 0x5C // External sensor data 19 register
+#define MPU6050_O_EXT_SENS_DATA_20 \
+ 0x5D // External sensor data 20 register
+#define MPU6050_O_EXT_SENS_DATA_21 \
+ 0x5E // External sensor data 21 register
+#define MPU6050_O_EXT_SENS_DATA_22 \
+ 0x5F // External sensor data 22 register
+#define MPU6050_O_EXT_SENS_DATA_23 \
+ 0x60 // External sensor data 23 register
+#define MPU6050_O_I2C_SLV0_DO 0x63 // I2C slave 0 output data register
+#define MPU6050_O_I2C_SLV1_DO 0x64 // I2C slave 1 output data register
+#define MPU6050_O_I2C_SLV2_DO 0x65 // I2C slave 2 output data register
+#define MPU6050_O_I2C_SLV3_DO 0x66 // I2C slave 3 output data register
+#define MPU6050_O_I2C_MST_DELAY_CTRL \
+ 0x67 // I2C master delay control
+ // register
+#define MPU6050_O_SIGNAL_PATH_RESET \
+ 0x68 // Signal path reset register
+#define MPU6050_O_MOT_DETECT_CTRL \
+ 0x69 // Motion detection control
+ // register
+#define MPU6050_O_USER_CTRL 0x6A // User control register
+#define MPU6050_O_PWR_MGMT_1 0x6B // Power management 1 register
+#define MPU6050_O_PWR_MGMT_2 0x6C // Power management 2 register
+#define MPU6050_O_FIFO_COUNTH 0x72 // FIFO count MSB register
+#define MPU6050_O_FIFO_COUNTL 0x73 // FIFO count LSB register
+#define MPU6050_O_FIFO_R_W 0x74 // FIFO read write register
+#define MPU6050_O_WHO_AM_I 0x75 // Who am I register
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the MPU6050_O_SELF_TEST_X
+// register.
+//
+//*****************************************************************************
+#define MPU6050_SELF_TEST_X_XA_TEST_M \
+ 0xE0 // Accelerometer XA_TEST[4:2]
+#define MPU6050_SELF_TEST_X_XG_TEST_M \
+ 0x1F // Gyro XG_TEST[4:0]
+#define MPU6050_SELF_TEST_X_XA_TEST_S \
+ 5
+#define MPU6050_SELF_TEST_X_XG_TEST_S \
+ 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the MPU6050_O_SELF_TEST_Y
+// register.
+//
+//*****************************************************************************
+#define MPU6050_SELF_TEST_Y_YA_TEST_M \
+ 0xE0 // Accelerometer YA_TEST[4:2]
+#define MPU6050_SELF_TEST_Y_YG_TEST_M \
+ 0x1F // Gyro YG_TEST[4:0]
+#define MPU6050_SELF_TEST_Y_YA_TEST_S \
+ 5
+#define MPU6050_SELF_TEST_Y_YG_TEST_S \
+ 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the MPU6050_O_SELF_TEST_Z
+// register.
+//
+//*****************************************************************************
+#define MPU6050_SELF_TEST_Z_ZA_TEST_M \
+ 0xE0 // Accelerometer ZA_TEST[4:2]
+#define MPU6050_SELF_TEST_Z_ZG_TEST_M \
+ 0x1F // Gyro ZG_TEST[4:0]
+#define MPU6050_SELF_TEST_Z_ZA_TEST_S \
+ 5
+#define MPU6050_SELF_TEST_Z_ZG_TEST_S \
+ 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the MPU6050_O_SELF_TEST_A
+// register.
+//
+//*****************************************************************************
+#define MPU6050_SELF_TEST_A_XA_TEST_M \
+ 0x30 // Accelerometer XA_TEST[1:0]
+#define MPU6050_SELF_TEST_A_YA_TEST_M \
+ 0x0C // Accelerometer YA_TEST[1:0]
+#define MPU6050_SELF_TEST_A_ZA_TEST_M \
+ 0x03 // Accelerometer ZA_TEST[1:0]
+#define MPU6050_SELF_TEST_A_XA_TEST_S \
+ 4
+#define MPU6050_SELF_TEST_A_YA_TEST_S \
+ 2
+#define MPU6050_SELF_TEST_A_ZA_TEST_S \
+ 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the MPU6050_O_SMPLRT_DIV
+// register.
+//
+//*****************************************************************************
+#define MPU6050_SMPLRT_DIV_M 0xFF // Gyro output rate divider
+#define MPU6050_SMPLRT_DIV_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the MPU6050_O_CONFIG
+// register.
+//
+//*****************************************************************************
+#define MPU6050_CONFIG_EXT_SYNC_SET_M \
+ 0x38 // FSYNC pin sample location
+#define MPU6050_CONFIG_EXT_SYNC_SET_DIS \
+ 0x00 // FSYNC input disabled
+#define MPU6050_CONFIG_EXT_SYNC_SET_TEMP_OUT_L \
+ 0x08 // FSYNC on TEMP_OUT_L[0]
+#define MPU6050_CONFIG_EXT_SYNC_SET_GYRO_XOUT_L \
+ 0x10 // FSYNC on GYRO_XOUT_L[0]
+#define MPU6050_CONFIG_EXT_SYNC_SET_GYRO_YOUT_L \
+ 0x18 // FSYNC on GYRO_YOUT_L[0]
+#define MPU6050_CONFIG_EXT_SYNC_SET_GYRO_ZOUT_L \
+ 0x20 // FSYNC on GYRO_ZOUT_L[0]
+#define MPU6050_CONFIG_EXT_SYNC_SET_ACCEL_XOUT_L \
+ 0x28 // FSYNC on ACCEL_XOUT_L[0]
+#define MPU6050_CONFIG_EXT_SYNC_SET_ACCEL_YOUT_L \
+ 0x30 // FSYNC on ACCEL_YOUT_L[0]
+#define MPU6050_CONFIG_EXT_SYNC_SET_ACCEL_ZOUT_L \
+ 0x38 // FSYNC on ACCEL_ZOUT_L[0]
+#define MPU6050_CONFIG_DLPF_CFG_M \
+ 0x07 // Digital low-pass filter
+ // configuration
+#define MPU6050_CONFIG_DLPF_CFG_260_256 \
+ 0x00 // 260 Hz accelerometer bandwidth,
+ // 256 Hz gyro bandwidth
+#define MPU6050_CONFIG_DLPF_CFG_184_188 \
+ 0x01 // 184 Hz accelerometer bandwidth,
+ // 188 Hz gyro bandwidth
+#define MPU6050_CONFIG_DLPF_CFG_94_98 \
+ 0x02 // 94 Hz accelerometer bandwidth,
+ // 98 Hz gyro bandwidth
+#define MPU6050_CONFIG_DLPF_CFG_44_42 \
+ 0x03 // 44 Hz accelerometer bandwidth,
+ // 42 Hz gyro bandwidth
+#define MPU6050_CONFIG_DLPF_CFG_21_20 \
+ 0x04 // 21 Hz accelerometer bandwidth,
+ // 20 Hz gyro bandwidth
+#define MPU6050_CONFIG_DLPF_CFG_10_10 \
+ 0x05 // 10 Hz accelerometer bandwidth,
+ // 10 Hz gyro bandwidth
+#define MPU6050_CONFIG_DLPF_CFG_5_5 \
+ 0x06 // 5 Hz accelerometer bandwidth, 5
+ // Hz gyro bandwidth
+#define MPU6050_CONFIG_EXT_SYNC_SET_S \
+ 3
+#define MPU6050_CONFIG_DLPF_CFG_S \
+ 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the MPU6050_O_GYRO_CONFIG
+// register.
+//
+//*****************************************************************************
+#define MPU6050_GYRO_CONFIG_FS_SEL_M \
+ 0x18 // Gyro full-scale range
+#define MPU6050_GYRO_CONFIG_FS_SEL_250 \
+ 0x00 // Gyro full-scale range +/- 250
+ // degrees/sec
+#define MPU6050_GYRO_CONFIG_FS_SEL_500 \
+ 0x08 // Gyro full-scale range +/- 500
+ // degrees/sec
+#define MPU6050_GYRO_CONFIG_FS_SEL_1000 \
+ 0x10 // Gyro full-scale range +/- 1000
+ // degrees/sec
+#define MPU6050_GYRO_CONFIG_FS_SEL_2000 \
+ 0x18 // Gyro full-scale range +/- 2000
+ // degrees/sec
+#define MPU6050_GYRO_CONFIG_FS_SEL_S \
+ 3
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the MPU6050_O_ACCEL_CONFIG
+// register.
+//
+//*****************************************************************************
+#define MPU6050_ACCEL_CONFIG_XA_ST \
+ 0x80 // X-axis accelerometer self-test
+ // enable
+#define MPU6050_ACCEL_CONFIG_YA_ST \
+ 0x40 // Y-axis accelerometer self-test
+ // enable
+#define MPU6050_ACCEL_CONFIG_ZA_ST \
+ 0x20 // Z-axis accelerometer self-test
+ // enable
+#define MPU6050_ACCEL_CONFIG_AFS_SEL_M \
+ 0x18 // Accelerometer full-scale range
+#define MPU6050_ACCEL_CONFIG_AFS_SEL_2G \
+ 0x00 // Accelerometer full-scale range 2
+ // g
+#define MPU6050_ACCEL_CONFIG_AFS_SEL_4G \
+ 0x08 // Accelerometer full-scale range 4
+ // g
+#define MPU6050_ACCEL_CONFIG_AFS_SEL_8G \
+ 0x10 // Accelerometer full-scale range 8
+ // g
+#define MPU6050_ACCEL_CONFIG_AFS_SEL_16G \
+ 0x18 // Accelerometer full-scale range
+ // 16 g
+#define MPU6050_ACCEL_CONFIG_AFS_SEL_S \
+ 3
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the MPU6050_O_MOT_THR
+// register.
+//
+//*****************************************************************************
+#define MPU6050_MOT_THR_M 0xFF // Motion detection threshold value
+#define MPU6050_MOT_THR_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the MPU6050_O_FIFO_EN
+// register.
+//
+//*****************************************************************************
+#define MPU6050_FIFO_EN_TEMP 0x80 // Temperature sensor FIFO enable
+#define MPU6050_FIFO_EN_XG 0x40 // X-axis gyro FIFO enable
+#define MPU6050_FIFO_EN_YG 0x20 // Y-axis gyro FIFO enable
+#define MPU6050_FIFO_EN_ZG 0x10 // Z-axis gyro FIFO enable
+#define MPU6050_FIFO_EN_ACCEL 0x08 // Accelerometer FIFO enable
+#define MPU6050_FIFO_EN_SLV2 0x04 // Slave 2 FIFO enable
+#define MPU6050_FIFO_EN_SLV1 0x02 // Slave 1 FIFO enable
+#define MPU6050_FIFO_EN_SLV0 0x01 // Slave 0 FIFO enable
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the MPU6050_O_I2C_MST_CTRL
+// register.
+//
+//*****************************************************************************
+#define MPU6050_I2C_MST_CTRL_MULT_MST_EN \
+ 0x80 // Multi-master enable
+#define MPU6050_I2C_MST_CTRL_WAIT_FOR_ES \
+ 0x40 // Wait for external sensor data
+#define MPU6050_I2C_MST_CTRL_SLV3_FIFO_EN \
+ 0x20 // Slave 3 FIFO enable
+#define MPU6050_I2C_MST_CTRL_I2C_MST_P_NSR \
+ 0x10 // No repeated start conditions
+#define MPU6050_I2C_MST_CTRL_I2C_MST_CLK_M \
+ 0x0F // I2C master clock speed
+#define MPU6050_I2C_MST_CTRL_I2C_MST_CLK_348 \
+ 0x00 // 348 kHz I2C master clock
+#define MPU6050_I2C_MST_CTRL_I2C_MST_CLK_333 \
+ 0x01 // 333 kHz I2C master clock
+#define MPU6050_I2C_MST_CTRL_I2C_MST_CLK_320 \
+ 0x02 // 320 kHz I2C master clock
+#define MPU6050_I2C_MST_CTRL_I2C_MST_CLK_308 \
+ 0x03 // 308 kHz I2C master clock
+#define MPU6050_I2C_MST_CTRL_I2C_MST_CLK_296 \
+ 0x04 // 296 kHz I2C master clock
+#define MPU6050_I2C_MST_CTRL_I2C_MST_CLK_286 \
+ 0x05 // 286 kHz I2C master clock
+#define MPU6050_I2C_MST_CTRL_I2C_MST_CLK_276 \
+ 0x06 // 276 kHz I2C master clock
+#define MPU6050_I2C_MST_CTRL_I2C_MST_CLK_267 \
+ 0x07 // 267 kHz I2C master clock
+#define MPU6050_I2C_MST_CTRL_I2C_MST_CLK_258 \
+ 0x08 // 258 kHz I2C master clock
+#define MPU6050_I2C_MST_CTRL_I2C_MST_CLK_500 \
+ 0x09 // 500 kHz I2C master clock
+#define MPU6050_I2C_MST_CTRL_I2C_MST_CLK_471 \
+ 0x0A // 471 kHz I2C master clock
+#define MPU6050_I2C_MST_CTRL_I2C_MST_CLK_444 \
+ 0x0B // 444 kHz I2C master clock
+#define MPU6050_I2C_MST_CTRL_I2C_MST_CLK_421 \
+ 0x0C // 421 kHz I2C master clock
+#define MPU6050_I2C_MST_CTRL_I2C_MST_CLK_400 \
+ 0x0D // 400 kHz I2C master clock
+#define MPU6050_I2C_MST_CTRL_I2C_MST_CLK_381 \
+ 0x0E // 381 kHz I2C master clock
+#define MPU6050_I2C_MST_CTRL_I2C_MST_CLK_364 \
+ 0x0F // 364 kHz I2C master clock
+#define MPU6050_I2C_MST_CTRL_I2C_MST_CLK_S \
+ 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the MPU6050_O_I2C_SLV0_ADDR
+// register.
+//
+//*****************************************************************************
+#define MPU6050_I2C_SLV0_ADDR_RW \
+ 0x80 // Read/not write
+#define MPU6050_I2C_SLV0_ADDR_M 0x7F // Slave address
+#define MPU6050_I2C_SLV0_ADDR_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the MPU6050_O_I2C_SLV0_REG
+// register.
+//
+//*****************************************************************************
+#define MPU6050_I2C_SLV0_REG_M 0xFF // Slave register number
+#define MPU6050_I2C_SLV0_REG_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the MPU6050_O_I2C_SLV0_CTRL
+// register.
+//
+//*****************************************************************************
+#define MPU6050_I2C_SLV0_CTRL_EN \
+ 0x80 // Enable slave
+#define MPU6050_I2C_SLV0_CTRL_BYTE_SW \
+ 0x40 // Byte-swap word pairs
+#define MPU6050_I2C_SLV0_CTRL_REG_DIS \
+ 0x20 // Disable register number transfer
+#define MPU6050_I2C_SLV0_CTRL_GRP \
+ 0x10 // Word pair grouping
+#define MPU6050_I2C_SLV0_CTRL_LEN_M \
+ 0x0F // Number of bytes to transfer
+#define MPU6050_I2C_SLV0_CTRL_LEN_S \
+ 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the MPU6050_O_I2C_SLV1_ADDR
+// register.
+//
+//*****************************************************************************
+#define MPU6050_I2C_SLV1_ADDR_RW \
+ 0x80 // Read/not write
+#define MPU6050_I2C_SLV1_ADDR_M 0x7F // Slave address
+#define MPU6050_I2C_SLV1_ADDR_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the MPU6050_O_I2C_SLV1_REG
+// register.
+//
+//*****************************************************************************
+#define MPU6050_I2C_SLV1_REG_M 0xFF // Slave register number
+#define MPU6050_I2C_SLV1_REG_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the MPU6050_O_I2C_SLV1_CTRL
+// register.
+//
+//*****************************************************************************
+#define MPU6050_I2C_SLV1_CTRL_EN \
+ 0x80 // Enable slave
+#define MPU6050_I2C_SLV1_CTRL_BYTE_SW \
+ 0x40 // Byte-swap word pairs
+#define MPU6050_I2C_SLV1_CTRL_REG_DIS \
+ 0x20 // Disable register number transfer
+#define MPU6050_I2C_SLV1_CTRL_GRP \
+ 0x10 // Word pair grouping
+#define MPU6050_I2C_SLV1_CTRL_LEN_M \
+ 0x0F // Number of bytes to transfer
+#define MPU6050_I2C_SLV1_CTRL_LEN_S \
+ 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the MPU6050_O_I2C_SLV2_ADDR
+// register.
+//
+//*****************************************************************************
+#define MPU6050_I2C_SLV2_ADDR_RW \
+ 0x80 // Read/not write
+#define MPU6050_I2C_SLV2_ADDR_M 0x7F // Slave address
+#define MPU6050_I2C_SLV2_ADDR_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the MPU6050_O_I2C_SLV2_REG
+// register.
+//
+//*****************************************************************************
+#define MPU6050_I2C_SLV2_REG_M 0xFF // Slave register number
+#define MPU6050_I2C_SLV2_REG_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the MPU6050_O_I2C_SLV2_CTRL
+// register.
+//
+//*****************************************************************************
+#define MPU6050_I2C_SLV2_CTRL_EN \
+ 0x80 // Enable slave
+#define MPU6050_I2C_SLV2_CTRL_BYTE_SW \
+ 0x40 // Byte-swap word pairs
+#define MPU6050_I2C_SLV2_CTRL_REG_DIS \
+ 0x20 // Disable register number transfer
+#define MPU6050_I2C_SLV2_CTRL_GRP \
+ 0x10 // Word pair grouping
+#define MPU6050_I2C_SLV2_CTRL_LEN_M \
+ 0x0F // Number of bytes to transfer
+#define MPU6050_I2C_SLV2_CTRL_LEN_S \
+ 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the MPU6050_O_I2C_SLV3_ADDR
+// register.
+//
+//*****************************************************************************
+#define MPU6050_I2C_SLV3_ADDR_RW \
+ 0x80 // Read/not write
+#define MPU6050_I2C_SLV3_ADDR_M 0x7F // Slave address
+#define MPU6050_I2C_SLV3_ADDR_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the MPU6050_O_I2C_SLV3_REG
+// register.
+//
+//*****************************************************************************
+#define MPU6050_I2C_SLV3_REG_M 0xFF // Slave register number
+#define MPU6050_I2C_SLV3_REG_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the MPU6050_O_I2C_SLV3_CTRL
+// register.
+//
+//*****************************************************************************
+#define MPU6050_I2C_SLV3_CTRL_EN \
+ 0x80 // Enable slave
+#define MPU6050_I2C_SLV3_CTRL_BYTE_SW \
+ 0x40 // Byte-swap word pairs
+#define MPU6050_I2C_SLV3_CTRL_REG_DIS \
+ 0x20 // Disable register number transfer
+#define MPU6050_I2C_SLV3_CTRL_GRP \
+ 0x10 // Word pair grouping
+#define MPU6050_I2C_SLV3_CTRL_LEN_M \
+ 0x0F // Number of bytes to transfer
+#define MPU6050_I2C_SLV3_CTRL_LEN_S \
+ 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the MPU6050_O_I2C_SLV4_ADDR
+// register.
+//
+//*****************************************************************************
+#define MPU6050_I2C_SLV4_ADDR_RW \
+ 0x80 // Read/not write
+#define MPU6050_I2C_SLV4_ADDR_M 0x7F // Slave address
+#define MPU6050_I2C_SLV4_ADDR_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the MPU6050_O_I2C_SLV4_REG
+// register.
+//
+//*****************************************************************************
+#define MPU6050_I2C_SLV4_REG_M 0xFF // Slave register number
+#define MPU6050_I2C_SLV4_REG_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the MPU6050_O_I2C_SLV4_CTRL
+// register.
+//
+//*****************************************************************************
+#define MPU6050_I2C_SLV4_CTRL_EN \
+ 0x80 // Enable slave
+#define MPU6050_I2C_SLV4_CTRL_INT_EN \
+ 0x40 // Interrupt enable
+#define MPU6050_I2C_SLV4_CTRL_REG_DIS \
+ 0x20 // Disable register number transfer
+#define MPU6050_I2C_SLV4_CTRL_I2C_MST_DLY_M \
+ 0x1F // Slave access delay
+#define MPU6050_I2C_SLV4_CTRL_I2C_MST_DLY_S \
+ 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the MPU6050_O_I2C_SLV4_DI
+// register.
+//
+//*****************************************************************************
+#define MPU6050_I2C_SLV4_DI_M 0xFF // Input data
+#define MPU6050_I2C_SLV4_DI_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the MPU6050_O_I2C_MST_STATUS
+// register.
+//
+//*****************************************************************************
+#define MPU6050_I2C_MST_STATUS_PASS_THROUGH \
+ 0x80 // Pass through FSYNC interrupt
+ // status
+#define MPU6050_I2C_MST_STATUS_I2C_SLV4_DONE \
+ 0x40 // I2C slave 4 completion status
+#define MPU6050_I2C_MST_STATUS_I2C_LOST_ARB \
+ 0x20 // I2C arbitration lost status
+#define MPU6050_I2C_MST_STATUS_I2C_SLV4_NACK \
+ 0x10 // I2C slave 4 NACK status
+#define MPU6050_I2C_MST_STATUS_I2C_SLV3_NACK \
+ 0x08 // I2C slave 3 NACK status
+#define MPU6050_I2C_MST_STATUS_I2C_SLV2_NACK \
+ 0x04 // I2C slave 2 NACK status
+#define MPU6050_I2C_MST_STATUS_I2C_SLV1_NACK \
+ 0x02 // I2C slave 1 NACK status
+#define MPU6050_I2C_MST_STATUS_I2C_SLV0_NACK \
+ 0x01 // I2C slave 0 NACK status
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the MPU6050_O_INT_PIN_CFG
+// register.
+//
+//*****************************************************************************
+#define MPU6050_INT_PIN_CFG_INT_LEVEL \
+ 0x80 // INT pin active low
+#define MPU6050_INT_PIN_CFG_INT_OPEN \
+ 0x40 // INT pin open-drain
+#define MPU6050_INT_PIN_CFG_LATCH_INT_EN \
+ 0x20 // Latch INT pin output
+#define MPU6050_INT_PIN_CFG_INT_RD_CLEAR \
+ 0x10 // Interrupt clear on any read
+#define MPU6050_INT_PIN_CFG_FSYNC_INT_LEVEL \
+ 0x08 // FSYNC pin active low
+#define MPU6050_INT_PIN_CFG_FSYNC_INT_EN \
+ 0x04 // FSYNC pin interrupt enable
+#define MPU6050_INT_PIN_CFG_I2C_BYPASS_EN \
+ 0x02 // I2C bypass enable
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the MPU6050_O_INT_ENABLE
+// register.
+//
+//*****************************************************************************
+#define MPU6050_INT_ENABLE_MOT_EN \
+ 0x40 // Motion detection interrupt
+ // enable
+#define MPU6050_INT_ENABLE_FIFO_OFLOW_EN \
+ 0x10 // FIFO overflow interrupt enable
+#define MPU6050_INT_ENABLE_I2C_MST_INT_EN \
+ 0x08 // I2C master interrupt enable
+#define MPU6050_INT_ENABLE_DATA_RDY_EN \
+ 0x01 // Data ready interrupt enable
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the MPU6050_O_INT_STATUS
+// register.
+//
+//*****************************************************************************
+#define MPU6050_INT_STATUS_MOT_INT \
+ 0x40 // Motion detection interrupt
+ // status
+#define MPU6050_INT_STATUS_FIFO_OFLOW_INT \
+ 0x10 // FIFO overflow interrupt status
+#define MPU6050_INT_STATUS_I2C_MST_INT \
+ 0x08 // I2C master interrupt status
+#define MPU6050_INT_STATUS_DATA_RDY_INT \
+ 0x01 // Data ready interrupt status
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the MPU6050_O_ACCEL_XOUT_H
+// register.
+//
+//*****************************************************************************
+#define MPU6050_ACCEL_XOUT_H_M 0xFF // Bits [15:8] of X-axis
+ // acceleration data
+#define MPU6050_ACCEL_XOUT_H_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the MPU6050_O_ACCEL_XOUT_L
+// register.
+//
+//*****************************************************************************
+#define MPU6050_ACCEL_XOUT_L_M 0xFF // Bits [7:0] of X-axis
+ // acceleration data
+#define MPU6050_ACCEL_XOUT_L_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the MPU6050_O_ACCEL_YOUT_H
+// register.
+//
+//*****************************************************************************
+#define MPU6050_ACCEL_YOUT_H_M 0xFF // Bits [15:8] of Y-axis
+ // acceleration data
+#define MPU6050_ACCEL_YOUT_H_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the MPU6050_O_ACCEL_YOUT_L
+// register.
+//
+//*****************************************************************************
+#define MPU6050_ACCEL_YOUT_L_M 0xFF // Bits [7:0] of Y-axis
+ // acceleration data
+#define MPU6050_ACCEL_YOUT_L_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the MPU6050_O_ACCEL_ZOUT_H
+// register.
+//
+//*****************************************************************************
+#define MPU6050_ACCEL_ZOUT_H_M 0xFF // Bits [15:8] of Z-axis
+ // acceleration data
+#define MPU6050_ACCEL_ZOUT_H_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the MPU6050_O_ACCEL_ZOUT_L
+// register.
+//
+//*****************************************************************************
+#define MPU6050_ACCEL_ZOUT_L_M 0xFF // Bits [7:0] of Z-axis
+ // acceleration data
+#define MPU6050_ACCEL_ZOUT_L_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the MPU6050_O_TEMP_OUT_H
+// register.
+//
+//*****************************************************************************
+#define MPU6050_ACCEL_TEMP_OUT_H_M \
+ 0xFF // Bits [15:8] of temperature data
+#define MPU6050_ACCEL_TEMP_OUT_H_S \
+ 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the MPU6050_O_TEMP_OUT_L
+// register.
+//
+//*****************************************************************************
+#define MPU6050_ACCEL_TEMP_OUT_L_M \
+ 0xFF // Bits [7:0] of temperature data
+#define MPU6050_ACCEL_TEMP_OUT_L_S \
+ 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the MPU6050_O_GYRO_XOUT_H
+// register.
+//
+//*****************************************************************************
+#define MPU6050_GYRO_XOUT_H_M 0xFF // Bits [15:8] of X-axis gyro data
+#define MPU6050_GYRO_XOUT_H_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the MPU6050_O_GYRO_XOUT_L
+// register.
+//
+//*****************************************************************************
+#define MPU6050_GYRO_XOUT_L_M 0xFF // Bits [7:0] of X-axis gyro data
+#define MPU6050_GYRO_XOUT_L_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the MPU6050_O_GYRO_YOUT_H
+// register.
+//
+//*****************************************************************************
+#define MPU6050_GYRO_YOUT_H_M 0xFF // Bits [15:8] of Y-axis gyro data
+#define MPU6050_GYRO_YOUT_H_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the MPU6050_O_GYRO_YOUT_L
+// register.
+//
+//*****************************************************************************
+#define MPU6050_GYRO_YOUT_L_M 0xFF // Bits [7:0] of Y-axis gyro data
+#define MPU6050_GYRO_YOUT_L_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the MPU6050_O_GYRO_ZOUT_H
+// register.
+//
+//*****************************************************************************
+#define MPU6050_GYRO_ZOUT_H_M 0xFF // Bits [15:8] of Z-axis gyro data
+#define MPU6050_GYRO_ZOUT_H_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the MPU6050_O_GYRO_ZOUT_L
+// register.
+//
+//*****************************************************************************
+#define MPU6050_GYRO_ZOUT_L_M 0xFF // Bits [7:0] of Z-axis gyro data
+#define MPU6050_GYRO_ZOUT_L_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the
+// MPU6050_O_EXT_SENS_DATA_00 register.
+//
+//*****************************************************************************
+#define MPU6050_EXT_SENS_DATA_00_M \
+ 0xFF // External sensor data
+#define MPU6050_EXT_SENS_DATA_00_S \
+ 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the
+// MPU6050_O_EXT_SENS_DATA_01 register.
+//
+//*****************************************************************************
+#define MPU6050_EXT_SENS_DATA_01_M \
+ 0xFF // External sensor data
+#define MPU6050_EXT_SENS_DATA_01_S \
+ 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the
+// MPU6050_O_EXT_SENS_DATA_02 register.
+//
+//*****************************************************************************
+#define MPU6050_EXT_SENS_DATA_02_M \
+ 0xFF // External sensor data
+#define MPU6050_EXT_SENS_DATA_02_S \
+ 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the
+// MPU6050_O_EXT_SENS_DATA_03 register.
+//
+//*****************************************************************************
+#define MPU6050_EXT_SENS_DATA_03_M \
+ 0xFF // External sensor data
+#define MPU6050_EXT_SENS_DATA_03_S \
+ 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the
+// MPU6050_O_EXT_SENS_DATA_04 register.
+//
+//*****************************************************************************
+#define MPU6050_EXT_SENS_DATA_04_M \
+ 0xFF // External sensor data
+#define MPU6050_EXT_SENS_DATA_04_S \
+ 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the
+// MPU6050_O_EXT_SENS_DATA_05 register.
+//
+//*****************************************************************************
+#define MPU6050_EXT_SENS_DATA_05_M \
+ 0xFF // External sensor data
+#define MPU6050_EXT_SENS_DATA_05_S \
+ 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the
+// MPU6050_O_EXT_SENS_DATA_06 register.
+//
+//*****************************************************************************
+#define MPU6050_EXT_SENS_DATA_06_M \
+ 0xFF // External sensor data
+#define MPU6050_EXT_SENS_DATA_06_S \
+ 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the
+// MPU6050_O_EXT_SENS_DATA_07 register.
+//
+//*****************************************************************************
+#define MPU6050_EXT_SENS_DATA_07_M \
+ 0xFF // External sensor data
+#define MPU6050_EXT_SENS_DATA_07_S \
+ 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the
+// MPU6050_O_EXT_SENS_DATA_08 register.
+//
+//*****************************************************************************
+#define MPU6050_EXT_SENS_DATA_08_M \
+ 0xFF // External sensor data
+#define MPU6050_EXT_SENS_DATA_08_S \
+ 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the
+// MPU6050_O_EXT_SENS_DATA_09 register.
+//
+//*****************************************************************************
+#define MPU6050_EXT_SENS_DATA_09_M \
+ 0xFF // External sensor data
+#define MPU6050_EXT_SENS_DATA_09_S \
+ 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the
+// MPU6050_O_EXT_SENS_DATA_10 register.
+//
+//*****************************************************************************
+#define MPU6050_EXT_SENS_DATA_10_M \
+ 0xFF // External sensor data
+#define MPU6050_EXT_SENS_DATA_10_S \
+ 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the
+// MPU6050_O_EXT_SENS_DATA_11 register.
+//
+//*****************************************************************************
+#define MPU6050_EXT_SENS_DATA_11_M \
+ 0xFF // External sensor data
+#define MPU6050_EXT_SENS_DATA_11_S \
+ 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the
+// MPU6050_O_EXT_SENS_DATA_12 register.
+//
+//*****************************************************************************
+#define MPU6050_EXT_SENS_DATA_12_M \
+ 0xFF // External sensor data
+#define MPU6050_EXT_SENS_DATA_12_S \
+ 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the
+// MPU6050_O_EXT_SENS_DATA_13 register.
+//
+//*****************************************************************************
+#define MPU6050_EXT_SENS_DATA_13_M \
+ 0xFF // External sensor data
+#define MPU6050_EXT_SENS_DATA_13_S \
+ 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the
+// MPU6050_O_EXT_SENS_DATA_14 register.
+//
+//*****************************************************************************
+#define MPU6050_EXT_SENS_DATA_14_M \
+ 0xFF // External sensor data
+#define MPU6050_EXT_SENS_DATA_14_S \
+ 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the
+// MPU6050_O_EXT_SENS_DATA_15 register.
+//
+//*****************************************************************************
+#define MPU6050_EXT_SENS_DATA_15_M \
+ 0xFF // External sensor data
+#define MPU6050_EXT_SENS_DATA_15_S \
+ 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the
+// MPU6050_O_EXT_SENS_DATA_16 register.
+//
+//*****************************************************************************
+#define MPU6050_EXT_SENS_DATA_16_M \
+ 0xFF // External sensor data
+#define MPU6050_EXT_SENS_DATA_16_S \
+ 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the
+// MPU6050_O_EXT_SENS_DATA_17 register.
+//
+//*****************************************************************************
+#define MPU6050_EXT_SENS_DATA_17_M \
+ 0xFF // External sensor data
+#define MPU6050_EXT_SENS_DATA_17_S \
+ 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the
+// MPU6050_O_EXT_SENS_DATA_18 register.
+//
+//*****************************************************************************
+#define MPU6050_EXT_SENS_DATA_18_M \
+ 0xFF // External sensor data
+#define MPU6050_EXT_SENS_DATA_18_S \
+ 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the
+// MPU6050_O_EXT_SENS_DATA_19 register.
+//
+//*****************************************************************************
+#define MPU6050_EXT_SENS_DATA_19_M \
+ 0xFF // External sensor data
+#define MPU6050_EXT_SENS_DATA_19_S \
+ 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the
+// MPU6050_O_EXT_SENS_DATA_20 register.
+//
+//*****************************************************************************
+#define MPU6050_EXT_SENS_DATA_20_M \
+ 0xFF // External sensor data
+#define MPU6050_EXT_SENS_DATA_20_S \
+ 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the
+// MPU6050_O_EXT_SENS_DATA_21 register.
+//
+//*****************************************************************************
+#define MPU6050_EXT_SENS_DATA_21_M \
+ 0xFF // External sensor data
+#define MPU6050_EXT_SENS_DATA_21_S \
+ 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the
+// MPU6050_O_EXT_SENS_DATA_22 register.
+//
+//*****************************************************************************
+#define MPU6050_EXT_SENS_DATA_22_M \
+ 0xFF // External sensor data
+#define MPU6050_EXT_SENS_DATA_22_S \
+ 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the
+// MPU6050_O_EXT_SENS_DATA_23 register.
+//
+//*****************************************************************************
+#define MPU6050_EXT_SENS_DATA_23_M \
+ 0xFF // External sensor data
+#define MPU6050_EXT_SENS_DATA_23_S \
+ 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the MPU6050_O_I2C_SLV0_DO
+// register.
+//
+//*****************************************************************************
+#define MPU6050_I2C_SLV0_DO_M 0xFF // Output data
+#define MPU6050_I2C_SLV0_DO_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the MPU6050_O_I2C_SLV1_DO
+// register.
+//
+//*****************************************************************************
+#define MPU6050_I2C_SLV1_DO_M 0xFF // Output data
+#define MPU6050_I2C_SLV1_DO_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the MPU6050_O_I2C_SLV2_DO
+// register.
+//
+//*****************************************************************************
+#define MPU6050_I2C_SLV2_DO_M 0xFF // Output data
+#define MPU6050_I2C_SLV2_DO_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the MPU6050_O_I2C_SLV3_DO
+// register.
+//
+//*****************************************************************************
+#define MPU6050_I2C_SLV3_DO_M 0xFF // Output data
+#define MPU6050_I2C_SLV3_DO_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the
+// MPU6050_O_I2C_MST_DELAY_CTRL register.
+//
+//*****************************************************************************
+#define MPU6050_I2C_MST_DELAY_CTRL_DELAY_ES_SHADOW \
+ 0x80 // Delay external sensor data
+#define MPU6050_I2C_MST_DELAY_CTRL_I2C_SLV4_DLY_EN \
+ 0x10 // I2C slave 4 delay enable
+#define MPU6050_I2C_MST_DELAY_CTRL_I2C_SLV3_DLY_EN \
+ 0x08 // I2C slave 3 delay enable
+#define MPU6050_I2C_MST_DELAY_CTRL_I2C_SLV2_DLY_EN \
+ 0x04 // I2C slave 2 delay enable
+#define MPU6050_I2C_MST_DELAY_CTRL_I2C_SLV1_DLY_EN \
+ 0x02 // I2C slave 1 delay enable
+#define MPU6050_I2C_MST_DELAY_CTRL_I2C_SLV0_DLY_EN \
+ 0x01 // I2C slave 0 delay enable
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the
+// MPU6050_O_SIGNAL_PATH_RESET register.
+//
+//*****************************************************************************
+#define MPU6050_SIGNAL_PATH_RESET_GYRO \
+ 0x04 // Reset gyro
+#define MPU6050_SIGNAL_PATH_RESET_ACCEL \
+ 0x02 // Reset accelerometer
+#define MPU6050_SIGNAL_PATH_RESET_TEMP \
+ 0x01 // Reset temperature sensor
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the
+// MPU6050_O_MOT_DETECT_CTRL register.
+//
+//*****************************************************************************
+#define MPU6050_MOT_DETECT_CTRL_ACCEL_ON_DELAY_M \
+ 0x30 // Accelerometer wake-up delay
+#define MPU6050_MOT_DETECT_CTRL_ACCEL_ON_DELAY_4MS \
+ 0x00 // Delay 4 ms
+#define MPU6050_MOT_DETECT_CTRL_ACCEL_ON_DELAY_5MS \
+ 0x10 // Delay 5 ms
+#define MPU6050_MOT_DETECT_CTRL_ACCEL_ON_DELAY_6MS \
+ 0x20 // Delay 6 ms
+#define MPU6050_MOT_DETECT_CTRL_ACCEL_ON_DELAY_7MS \
+ 0x30 // Delay 7 ms
+#define MPU6050_MOT_DETECT_CTRL_ACCEL_ON_DELAY_S \
+ 4
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the MPU6050_O_USER_CTRL
+// register.
+//
+//*****************************************************************************
+#define MPU6050_USER_CTRL_FIFO_EN \
+ 0x40 // FIFO enable
+#define MPU6050_USER_CTRL_I2C_MST_EN \
+ 0x20 // I2C master mode enable
+#define MPU6050_USER_CTRL_I2C_IF_DIS \
+ 0x10 // Write as zero
+#define MPU6050_USER_CTRL_FIFO_RESET \
+ 0x04 // Reset FIFO buffer
+#define MPU6050_USER_CTRL_I2C_MST_RESET \
+ 0x02 // Reset I2C master
+#define MPU6050_USER_CTRL_SIG_COND_RESET \
+ 0x01 // Reset all sensors
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the MPU6050_O_PWR_MGMT_1
+// register.
+//
+//*****************************************************************************
+#define MPU6050_PWR_MGMT_1_DEVICE_RESET \
+ 0x80 // Device reset
+#define MPU6050_PWR_MGMT_1_SLEEP \
+ 0x40 // Enter sleep mode
+#define MPU6050_PWR_MGMT_1_CYCLE \
+ 0x20 // Enable automatic sleep
+#define MPU6050_PWR_MGMT_1_TEMP_DIS \
+ 0x08 // Disable temperature sensor
+#define MPU6050_PWR_MGMT_1_CLKSEL_M \
+ 0x07 // Clock source select
+#define MPU6050_PWR_MGMT_1_CLKSEL_INT \
+ 0x00 // Internal 8 MHz oscillator
+#define MPU6050_PWR_MGMT_1_CLKSEL_XG \
+ 0x01 // PLL with X-axis gyro reference
+#define MPU6050_PWR_MGMT_1_CLKSEL_YG \
+ 0x02 // PLL with Y-axis gyro reference
+#define MPU6050_PWR_MGMT_1_CLKSEL_ZG \
+ 0x03 // PLL with Z-axis gyro reference
+#define MPU6050_PWR_MGMT_1_CLKSEL_EXT32K \
+ 0x04 // PLL with external 32.768 kHz
+ // reference
+#define MPU6050_PWR_MGMT_1_CLKSEL_EXT19M \
+ 0x05 // PLL with external 19.2 MHz
+ // reference
+#define MPU6050_PWR_MGMT_1_CLKSEL_STOP \
+ 0x07 // Clock disable
+#define MPU6050_PWR_MGMT_1_CLKSEL_S \
+ 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the MPU6050_O_PWR_MGMT_2
+// register.
+//
+//*****************************************************************************
+#define MPU6050_PWR_MGMT_2_LP_WAKE_CTRL_M \
+ 0xC0 // Wake-up frequency
+#define MPU6050_PWR_MGMT_2_LP_WAKE_CTRL_1_25 \
+ 0x00 // Wake-up at 1.25 Hz
+#define MPU6050_PWR_MGMT_2_LP_WAKE_CTRL_5 \
+ 0x40 // Wake-up at 5 Hz
+#define MPU6050_PWR_MGMT_2_LP_WAKE_CTRL_20 \
+ 0x80 // Wake-up at 20 Hz
+#define MPU6050_PWR_MGMT_2_LP_WAKE_CTRL_40 \
+ 0xC0 // Wake-up at 40 Hz
+#define MPU6050_PWR_MGMT_2_STBY_XA \
+ 0x20 // Put X-axis accelerometer into
+ // standby mode
+#define MPU6050_PWR_MGMT_2_STBY_YA \
+ 0x10 // Put Y-axis accelerometer into
+ // standby mode
+#define MPU6050_PWR_MGMT_2_STBY_ZA \
+ 0x08 // Put Z-axis accelerometer into
+ // standby mode
+#define MPU6050_PWR_MGMT_2_STBY_XG \
+ 0x04 // Put X-axis gyro into standby
+ // mode
+#define MPU6050_PWR_MGMT_2_STBY_YG \
+ 0x02 // Put Y-axis gyro into standby
+ // mode
+#define MPU6050_PWR_MGMT_2_STBY_ZG \
+ 0x01 // Put Z-axis gyro into standby
+ // mode
+#define MPU6050_PWR_MGMT_2_LP_WAKE_CTRL_S \
+ 6
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the MPU6050_O_FIFO_COUNTH
+// register.
+//
+//*****************************************************************************
+#define MPU6050_FIFO_COUNTH_M 0xFF // FIFO count [15:8]
+#define MPU6050_FIFO_COUNTH_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the MPU6050_O_FIFO_COUNTL
+// register.
+//
+//*****************************************************************************
+#define MPU6050_FIFO_COUNTL_M 0xFF // FIFO count [7:0]
+#define MPU6050_FIFO_COUNTL_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the MPU6050_O_FIFO_R_W
+// register.
+//
+//*****************************************************************************
+#define MPU6050_FIFO_R_W_M 0xFF // FIFO data
+#define MPU6050_FIFO_R_W_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the MPU6050_O_WHO_AM_I
+// register.
+//
+//*****************************************************************************
+#define MPU6050_WHO_AM_I_M 0x7E // I2C address
+#define MPU6050_WHO_AM_I_MPU6050 \
+ 0x68 // MPU6050
+#define MPU6050_WHO_AM_I_S 1
+
+#endif // __SENSORLIB_HW_MPU6050_H__
diff --git a/sensorlib/hw_mpu9150.h b/sensorlib/hw_mpu9150.h
new file mode 100644
index 0000000..b586d1b
--- /dev/null
+++ b/sensorlib/hw_mpu9150.h
@@ -0,0 +1,1454 @@
+//*****************************************************************************
+//
+// hw_mpu9150.h - Macros used when accessing the Invensense MPU9150
+// accelerometer/gyroscope/magnetometer.
+//
+// Copyright (c) 2013-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
+//
+//*****************************************************************************
+
+#ifndef __SENSORLIB_HW_MPU9150_H__
+#define __SENSORLIB_HW_MPU9150_H__
+
+//*****************************************************************************
+//
+// The following are defines for the MPU9150 register addresses.
+//
+//*****************************************************************************
+#define MPU9150_O_SELF_TEST_X 0x0D // Self test X register
+#define MPU9150_O_SELF_TEST_Y 0x0E // Self test Y register
+#define MPU9150_O_SELF_TEST_Z 0x0F // Self test Z register
+#define MPU9150_O_SELF_TEST_A 0x10 // Self test A register
+#define MPU9150_O_SMPLRT_DIV 0x19 // Sample rate divider register
+#define MPU9150_O_CONFIG 0x1A // Configuration register
+#define MPU9150_O_GYRO_CONFIG 0x1B // Gyro configuration register
+#define MPU9150_O_ACCEL_CONFIG 0x1C // Accelerometer configuration
+ // register
+#define MPU9150_O_FF_THR 0x1D // Free-fall threshold register
+#define MPU9150_O_FF_DUR 0x1E // Free-fall duration register
+#define MPU9150_O_MOT_THR 0x1F // Motion detection threshold
+ // register
+#define MPU9150_O_MOT_DUR 0x20 // Motion detection duration
+ // register
+#define MPU9150_O_ZRMOT_THR 0x21 // Zero motion detection threshold
+ // register
+#define MPU9150_O_ZRMOT_DUR 0x22 // Zero motion detection duration
+ // register
+#define MPU9150_O_FIFO_EN 0x23 // FIFO enable register
+#define MPU9150_O_I2C_MST_CTRL 0x24 // I2C master control register
+#define MPU9150_O_I2C_SLV0_ADDR 0x25 // I2C slave 0 address register
+#define MPU9150_O_I2C_SLV0_REG 0x26 // I2C slave 0 register number
+ // register
+#define MPU9150_O_I2C_SLV0_CTRL 0x27 // I2C slave 0 control register
+#define MPU9150_O_I2C_SLV1_ADDR 0x28 // I2C slave 1 address register
+#define MPU9150_O_I2C_SLV1_REG 0x29 // I2C slave 1 register number
+ // register
+#define MPU9150_O_I2C_SLV1_CTRL 0x2A // I2C slave 1 control register
+#define MPU9150_O_I2C_SLV2_ADDR 0x2B // I2C slave 2 address register
+#define MPU9150_O_I2C_SLV2_REG 0x2C // I2C slave 2 register number
+ // register
+#define MPU9150_O_I2C_SLV2_CTRL 0x2D // I2C slave 2 control register
+#define MPU9150_O_I2C_SLV3_ADDR 0x2E // I2C slave 3 address register
+#define MPU9150_O_I2C_SLV3_REG 0x2F // I2C slave 3 register number
+ // register
+#define MPU9150_O_I2C_SLV3_CTRL 0x30 // I2C slave 3 control register
+#define MPU9150_O_I2C_SLV4_ADDR 0x31 // I2C slave 4 address register
+#define MPU9150_O_I2C_SLV4_REG 0x32 // I2C slave 4 register number
+ // register
+#define MPU9150_O_I2C_SLV4_DO 0x33 // I2C slave 4 output data register
+#define MPU9150_O_I2C_SLV4_CTRL 0x34 // I2C slave 4 control register
+#define MPU9150_O_I2C_SLV4_DI 0x35 // I2C slave 4 input data register
+#define MPU9150_O_I2C_MST_STATUS \
+ 0x36 // I2C master status register
+#define MPU9150_O_INT_PIN_CFG 0x37 // INT pin configuration register
+#define MPU9150_O_INT_ENABLE 0x38 // Interrupt enable register
+#define MPU9150_O_INT_STATUS 0x3A // Interrupt status register
+#define MPU9150_O_ACCEL_XOUT_H 0x3B // X-axis acceleration data MSB
+ // register
+#define MPU9150_O_ACCEL_XOUT_L 0x3C // X-axis acceleration data LSB
+ // register
+#define MPU9150_O_ACCEL_YOUT_H 0x3D // Y-axis acceleration data MSB
+ // register
+#define MPU9150_O_ACCEL_YOUT_L 0x3E // Y-axis accelearation data LSB
+ // register
+#define MPU9150_O_ACCEL_ZOUT_H 0x3F // Z-axis acceleration data MSB
+ // register
+#define MPU9150_O_ACCEL_ZOUT_L 0x40 // Z-axis acceleration data LSB
+ // register
+#define MPU9150_O_TEMP_OUT_H 0x41 // Temperature data MSB register
+#define MPU9150_O_TEMP_OUT_L 0x42 // Temperature data LSB register
+#define MPU9150_O_GYRO_XOUT_H 0x43 // X-axis gyro data MSB register
+#define MPU9150_O_GYRO_XOUT_L 0x44 // X-axis gyro data LSB register
+#define MPU9150_O_GYRO_YOUT_H 0x45 // Y-axis gyro data MSB register
+#define MPU9150_O_GYRO_YOUT_L 0x46 // Y-axis gyro data LSB register
+#define MPU9150_O_GYRO_ZOUT_H 0x47 // Z-axis gyro data MSB register
+#define MPU9150_O_GYRO_ZOUT_L 0x48 // Z-axis gyro data LSB register
+#define MPU9150_O_EXT_SENS_DATA_00 \
+ 0x49 // External sensor data 0 register
+#define MPU9150_O_EXT_SENS_DATA_01 \
+ 0x4A // External sensor data 1 register
+#define MPU9150_O_EXT_SENS_DATA_02 \
+ 0x4B // External sensor data 2 register
+#define MPU9150_O_EXT_SENS_DATA_03 \
+ 0x4C // External sensor data 3 register
+#define MPU9150_O_EXT_SENS_DATA_04 \
+ 0x4D // External sensor data 4 register
+#define MPU9150_O_EXT_SENS_DATA_05 \
+ 0x4E // External sensor data 5 register
+#define MPU9150_O_EXT_SENS_DATA_06 \
+ 0x4F // External sensor data 6 register
+#define MPU9150_O_EXT_SENS_DATA_07 \
+ 0x50 // External sensor data 7 register
+#define MPU9150_O_EXT_SENS_DATA_08 \
+ 0x51 // External sensor data 8 register
+#define MPU9150_O_EXT_SENS_DATA_09 \
+ 0x52 // External sensor data 9 register
+#define MPU9150_O_EXT_SENS_DATA_10 \
+ 0x53 // External sensor data 10 register
+#define MPU9150_O_EXT_SENS_DATA_11 \
+ 0x54 // External sensor data 11 register
+#define MPU9150_O_EXT_SENS_DATA_12 \
+ 0x55 // External sensor data 12 register
+#define MPU9150_O_EXT_SENS_DATA_13 \
+ 0x56 // External sensor data 13 register
+#define MPU9150_O_EXT_SENS_DATA_14 \
+ 0x57 // External sensor data 14 register
+#define MPU9150_O_EXT_SENS_DATA_15 \
+ 0x58 // External sensor data 15 register
+#define MPU9150_O_EXT_SENS_DATA_16 \
+ 0x59 // External sensor data 16 register
+#define MPU9150_O_EXT_SENS_DATA_17 \
+ 0x5A // External sensor data 17 register
+#define MPU9150_O_EXT_SENS_DATA_18 \
+ 0x5B // External sensor data 18 register
+#define MPU9150_O_EXT_SENS_DATA_19 \
+ 0x5C // External sensor data 19 register
+#define MPU9150_O_EXT_SENS_DATA_20 \
+ 0x5D // External sensor data 20 register
+#define MPU9150_O_EXT_SENS_DATA_21 \
+ 0x5E // External sensor data 21 register
+#define MPU9150_O_EXT_SENS_DATA_22 \
+ 0x5F // External sensor data 22 register
+#define MPU9150_O_EXT_SENS_DATA_23 \
+ 0x60 // External sensor data 23 register
+#define MPU9150_O_MOT_DETECT_STATUS \
+ 0x61 // Motion detection status register
+#define MPU9150_O_I2C_SLV0_DO 0x63 // I2C slave 0 output data register
+#define MPU9150_O_I2C_SLV1_DO 0x64 // I2C slave 1 output data register
+#define MPU9150_O_I2C_SLV2_DO 0x65 // I2C slave 2 output data register
+#define MPU9150_O_I2C_SLV3_DO 0x66 // I2C slave 3 output data register
+#define MPU9150_O_I2C_MST_DELAY_CTRL \
+ 0x67 // I2C master delay control
+ // register
+#define MPU9150_O_SIGNAL_PATH_RESET \
+ 0x68 // Signal path reset register
+#define MPU9150_O_MOT_DETECT_CTRL \
+ 0x69 // Motion detection control
+ // register
+#define MPU9150_O_USER_CTRL 0x6A // User control register
+#define MPU9150_O_PWR_MGMT_1 0x6B // Power management 1 register
+#define MPU9150_O_PWR_MGMT_2 0x6C // Power management 2 register
+#define MPU9150_O_FIFO_COUNTH 0x72 // FIFO count MSB register
+#define MPU9150_O_FIFO_COUNTL 0x73 // FIFO count LSB register
+#define MPU9150_O_FIFO_R_W 0x74 // FIFO read write register
+#define MPU9150_O_WHO_AM_I 0x75 // Who am I register
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the MPU9150_O_SELF_TEST_X
+// register.
+//
+//*****************************************************************************
+#define MPU9150_SELF_TEST_X_XA_TEST_M \
+ 0xE0 // Accelerometer XA_TEST[4:2]
+#define MPU9150_SELF_TEST_X_XG_TEST_M \
+ 0x1F // Gyro XG_TEST[4:0]
+#define MPU9150_SELF_TEST_X_XA_TEST_S \
+ 5
+#define MPU9150_SELF_TEST_X_XG_TEST_S \
+ 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the MPU9150_O_SELF_TEST_Y
+// register.
+//
+//*****************************************************************************
+#define MPU9150_SELF_TEST_Y_YA_TEST_M \
+ 0xE0 // Accelerometer YA_TEST[4:2]
+#define MPU9150_SELF_TEST_Y_YG_TEST_M \
+ 0x1F // Gyro YG_TEST[4:0]
+#define MPU9150_SELF_TEST_Y_YA_TEST_S \
+ 5
+#define MPU9150_SELF_TEST_Y_YG_TEST_S \
+ 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the MPU9150_O_SELF_TEST_Z
+// register.
+//
+//*****************************************************************************
+#define MPU9150_SELF_TEST_Z_ZA_TEST_M \
+ 0xE0 // Accelerometer ZA_TEST[4:2]
+#define MPU9150_SELF_TEST_Z_ZG_TEST_M \
+ 0x1F // Gyro ZG_TEST[4:0]
+#define MPU9150_SELF_TEST_Z_ZA_TEST_S \
+ 5
+#define MPU9150_SELF_TEST_Z_ZG_TEST_S \
+ 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the MPU9150_O_SELF_TEST_A
+// register.
+//
+//*****************************************************************************
+#define MPU9150_SELF_TEST_A_XA_TEST_M \
+ 0x30 // Accelerometer XA_TEST[1:0]
+#define MPU9150_SELF_TEST_A_YA_TEST_M \
+ 0x0C // Accelerometer YA_TEST[1:0]
+#define MPU9150_SELF_TEST_A_ZA_TEST_M \
+ 0x03 // Accelerometer ZA_TEST[1:0]
+#define MPU9150_SELF_TEST_A_XA_TEST_S \
+ 4
+#define MPU9150_SELF_TEST_A_YA_TEST_S \
+ 2
+#define MPU9150_SELF_TEST_A_ZA_TEST_S \
+ 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the MPU9150_O_SMPLRT_DIV
+// register.
+//
+//*****************************************************************************
+#define MPU9150_SMPLRT_DIV_M 0xFF // Gyro output rate divider
+#define MPU9150_SMPLRT_DIV_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the MPU9150_O_CONFIG
+// register.
+//
+//*****************************************************************************
+#define MPU9150_CONFIG_EXT_SYNC_SET_M \
+ 0x38 // FSYNC pin sample location
+#define MPU9150_CONFIG_EXT_SYNC_SET_DIS \
+ 0x00 // FSYNC input disabled
+#define MPU9150_CONFIG_EXT_SYNC_SET_TEMP_OUT_L \
+ 0x08 // FSYNC on TEMP_OUT_L[0]
+#define MPU9150_CONFIG_EXT_SYNC_SET_GYRO_XOUT_L \
+ 0x10 // FSYNC on GYRO_XOUT_L[0]
+#define MPU9150_CONFIG_EXT_SYNC_SET_GYRO_YOUT_L \
+ 0x18 // FSYNC on GYRO_YOUT_L[0]
+#define MPU9150_CONFIG_EXT_SYNC_SET_GYRO_ZOUT_L \
+ 0x20 // FSYNC on GYRO_ZOUT_L[0]
+#define MPU9150_CONFIG_EXT_SYNC_SET_ACCEL_XOUT_L \
+ 0x28 // FSYNC on ACCEL_XOUT_L[0]
+#define MPU9150_CONFIG_EXT_SYNC_SET_ACCEL_YOUT_L \
+ 0x30 // FSYNC on ACCEL_YOUT_L[0]
+#define MPU9150_CONFIG_EXT_SYNC_SET_ACCEL_ZOUT_L \
+ 0x38 // FSYNC on ACCEL_ZOUT_L[0]
+#define MPU9150_CONFIG_DLPF_CFG_M \
+ 0x07 // Digital low-pass filter
+ // configuration
+#define MPU9150_CONFIG_DLPF_CFG_260_256 \
+ 0x00 // 260 Hz accelerometer bandwidth,
+ // 256 Hz gyro bandwidth
+#define MPU9150_CONFIG_DLPF_CFG_184_188 \
+ 0x01 // 184 Hz accelerometer bandwidth,
+ // 188 Hz gyro bandwidth
+#define MPU9150_CONFIG_DLPF_CFG_94_98 \
+ 0x02 // 94 Hz accelerometer bandwidth,
+ // 98 Hz gyro bandwidth
+#define MPU9150_CONFIG_DLPF_CFG_44_42 \
+ 0x03 // 44 Hz accelerometer bandwidth,
+ // 42 Hz gyro bandwidth
+#define MPU9150_CONFIG_DLPF_CFG_21_20 \
+ 0x04 // 21 Hz accelerometer bandwidth,
+ // 20 Hz gyro bandwidth
+#define MPU9150_CONFIG_DLPF_CFG_10_10 \
+ 0x05 // 10 Hz accelerometer bandwidth,
+ // 10 Hz gyro bandwidth
+#define MPU9150_CONFIG_DLPF_CFG_5_5 \
+ 0x06 // 5 Hz accelerometer bandwidth, 5
+ // Hz gyro bandwidth
+#define MPU9150_CONFIG_EXT_SYNC_SET_S \
+ 3
+#define MPU9150_CONFIG_DLPF_CFG_S \
+ 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the MPU9150_O_GYRO_CONFIG
+// register.
+//
+//*****************************************************************************
+#define MPU9150_GYRO_CONFIG_XG_ST \
+ 0x80 // X-axis gyro self-test enable
+#define MPU9150_GYRO_CONFIG_YG_ST \
+ 0x40 // Y-axis gyro self-test enable
+#define MPU9150_GYRO_CONFIG_ZG_ST \
+ 0x20 // Z-axis gyro self-test enable
+#define MPU9150_GYRO_CONFIG_FS_SEL_M \
+ 0x18 // Gyro full-scale range
+#define MPU9150_GYRO_CONFIG_FS_SEL_250 \
+ 0x00 // Gyro full-scale range +/- 250
+ // degrees/sec
+#define MPU9150_GYRO_CONFIG_FS_SEL_500 \
+ 0x08 // Gyro full-scale range +/- 500
+ // degrees/sec
+#define MPU9150_GYRO_CONFIG_FS_SEL_1000 \
+ 0x10 // Gyro full-scale range +/- 1000
+ // degrees/sec
+#define MPU9150_GYRO_CONFIG_FS_SEL_2000 \
+ 0x18 // Gyro full-scale range +/- 2000
+ // degrees/sec
+#define MPU9150_GYRO_CONFIG_FS_SEL_S \
+ 3
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the MPU9150_O_ACCEL_CONFIG
+// register.
+//
+//*****************************************************************************
+#define MPU9150_ACCEL_CONFIG_XA_ST \
+ 0x80 // X-axis accelerometer self-test
+ // enable
+#define MPU9150_ACCEL_CONFIG_YA_ST \
+ 0x40 // Y-axis accelerometer self-test
+ // enable
+#define MPU9150_ACCEL_CONFIG_ZA_ST \
+ 0x20 // Z-axis accelerometer self-test
+ // enable
+#define MPU9150_ACCEL_CONFIG_AFS_SEL_M \
+ 0x18 // Accelerometer full-scale range
+#define MPU9150_ACCEL_CONFIG_AFS_SEL_2G \
+ 0x00 // Accelerometer full-scale range 2
+ // g
+#define MPU9150_ACCEL_CONFIG_AFS_SEL_4G \
+ 0x08 // Accelerometer full-scale range 4
+ // g
+#define MPU9150_ACCEL_CONFIG_AFS_SEL_8G \
+ 0x10 // Accelerometer full-scale range 8
+ // g
+#define MPU9150_ACCEL_CONFIG_AFS_SEL_16G \
+ 0x18 // Accelerometer full-scale range
+ // 16 g
+#define MPU9150_ACCEL_CONFIG_ACCEL_HPF_M \
+ 0x07 // High-pass filter setting
+#define MPU9150_ACCEL_CONFIG_ACCEL_HPF_RESET \
+ 0x00 // High-pass filter reset
+#define MPU9150_ACCEL_CONFIG_ACCEL_HPF_5HZ \
+ 0x01 // High-pass filter at 5 Hz
+#define MPU9150_ACCEL_CONFIG_ACCEL_HPF_2_5HZ \
+ 0x02 // High-pass filter at 2.5 Hz
+#define MPU9150_ACCEL_CONFIG_ACCEL_HPF_1_25HZ \
+ 0x03 // High-pass filter at 1.25 Hz
+#define MPU9150_ACCEL_CONFIG_ACCEL_HPF_0_63HZ \
+ 0x04 // High-pass filter at 0.63 Hz
+#define MPU9150_ACCEL_CONFIG_ACCEL_HPF_HOLD \
+ 0x07 // High-pass filter hold
+#define MPU9150_ACCEL_CONFIG_AFS_SEL_S \
+ 3
+#define MPU9150_ACCEL_CONFIG_ACCEL_HPF_S \
+ 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the MPU9150_O_FF_THR
+// register.
+//
+//*****************************************************************************
+#define MPU9150_FF_THR_M 0xFF // Free-fall threshold value
+#define MPU9150_FF_THR_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the MPU9150_O_FF_DUR
+// register.
+//
+//*****************************************************************************
+#define MPU9150_FF_DUR_M 0xFF // Free-fall duration value
+#define MPU9150_FF_DUR_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the MPU9150_O_MOT_THR
+// register.
+//
+//*****************************************************************************
+#define MPU9150_MOT_THR_M 0xFF // Motion detection threshold value
+#define MPU9150_MOT_THR_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the MPU9150_O_MOT_DUR
+// register.
+//
+//*****************************************************************************
+#define MPU9150_MOT_DUR_M 0xFF // Motion detection duration value
+#define MPU9150_MOT_DUR_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the MPU9150_O_ZRMOT_THR
+// register.
+//
+//*****************************************************************************
+#define MPU9150_ZRMOT_THR_M 0xFF // Zero motion detection threshold
+ // value
+#define MPU9150_ZRMOT_THR_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the MPU9150_O_ZRMOT_DUR
+// register.
+//
+//*****************************************************************************
+#define MPU9150_ZRMOT_DUR_M 0xFF // Zero motion detection duration
+ // value
+#define MPU9150_ZRMOT_DUR_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the MPU9150_O_FIFO_EN
+// register.
+//
+//*****************************************************************************
+#define MPU9150_FIFO_EN_TEMP 0x80 // Temperature sensor FIFO enable
+#define MPU9150_FIFO_EN_XG 0x40 // X-axis gyro FIFO enable
+#define MPU9150_FIFO_EN_YG 0x20 // Y-axis gyro FIFO enable
+#define MPU9150_FIFO_EN_ZG 0x10 // Z-axis gyro FIFO enable
+#define MPU9150_FIFO_EN_ACCEL 0x08 // Accelerometer FIFO enable
+#define MPU9150_FIFO_EN_SLV2 0x04 // Slave 2 FIFO enable
+#define MPU9150_FIFO_EN_SLV1 0x02 // Slave 1 FIFO enable
+#define MPU9150_FIFO_EN_SLV0 0x01 // Slave 0 FIFO enable
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the MPU9150_O_I2C_MST_CTRL
+// register.
+//
+//*****************************************************************************
+#define MPU9150_I2C_MST_CTRL_MULT_MST_EN \
+ 0x80 // Multi-master enable
+#define MPU9150_I2C_MST_CTRL_WAIT_FOR_ES \
+ 0x40 // Wait for external sensor data
+#define MPU9150_I2C_MST_CTRL_SLV3_FIFO_EN \
+ 0x20 // Slave 3 FIFO enable
+#define MPU9150_I2C_MST_CTRL_I2C_MST_P_NSR \
+ 0x10 // No repeated start conditions
+#define MPU9150_I2C_MST_CTRL_I2C_MST_CLK_M \
+ 0x0F // I2C master clock speed
+#define MPU9150_I2C_MST_CTRL_I2C_MST_CLK_348 \
+ 0x00 // 348 kHz I2C master clock
+#define MPU9150_I2C_MST_CTRL_I2C_MST_CLK_333 \
+ 0x01 // 333 kHz I2C master clock
+#define MPU9150_I2C_MST_CTRL_I2C_MST_CLK_320 \
+ 0x02 // 320 kHz I2C master clock
+#define MPU9150_I2C_MST_CTRL_I2C_MST_CLK_308 \
+ 0x03 // 308 kHz I2C master clock
+#define MPU9150_I2C_MST_CTRL_I2C_MST_CLK_296 \
+ 0x04 // 296 kHz I2C master clock
+#define MPU9150_I2C_MST_CTRL_I2C_MST_CLK_286 \
+ 0x05 // 286 kHz I2C master clock
+#define MPU9150_I2C_MST_CTRL_I2C_MST_CLK_276 \
+ 0x06 // 276 kHz I2C master clock
+#define MPU9150_I2C_MST_CTRL_I2C_MST_CLK_267 \
+ 0x07 // 267 kHz I2C master clock
+#define MPU9150_I2C_MST_CTRL_I2C_MST_CLK_258 \
+ 0x08 // 258 kHz I2C master clock
+#define MPU9150_I2C_MST_CTRL_I2C_MST_CLK_500 \
+ 0x09 // 500 kHz I2C master clock
+#define MPU9150_I2C_MST_CTRL_I2C_MST_CLK_471 \
+ 0x0A // 471 kHz I2C master clock
+#define MPU9150_I2C_MST_CTRL_I2C_MST_CLK_444 \
+ 0x0B // 444 kHz I2C master clock
+#define MPU9150_I2C_MST_CTRL_I2C_MST_CLK_421 \
+ 0x0C // 421 kHz I2C master clock
+#define MPU9150_I2C_MST_CTRL_I2C_MST_CLK_400 \
+ 0x0D // 400 kHz I2C master clock
+#define MPU9150_I2C_MST_CTRL_I2C_MST_CLK_381 \
+ 0x0E // 381 kHz I2C master clock
+#define MPU9150_I2C_MST_CTRL_I2C_MST_CLK_364 \
+ 0x0F // 364 kHz I2C master clock
+#define MPU9150_I2C_MST_CTRL_I2C_MST_CLK_S \
+ 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the MPU9150_O_I2C_SLV0_ADDR
+// register.
+//
+//*****************************************************************************
+#define MPU9150_I2C_SLV0_ADDR_RW \
+ 0x80 // Read/not write
+#define MPU9150_I2C_SLV0_ADDR_M 0x7F // Slave address
+#define MPU9150_I2C_SLV0_ADDR_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the MPU9150_O_I2C_SLV0_REG
+// register.
+//
+//*****************************************************************************
+#define MPU9150_I2C_SLV0_REG_M 0xFF // Slave register number
+#define MPU9150_I2C_SLV0_REG_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the MPU9150_O_I2C_SLV0_CTRL
+// register.
+//
+//*****************************************************************************
+#define MPU9150_I2C_SLV0_CTRL_EN \
+ 0x80 // Enable slave
+#define MPU9150_I2C_SLV0_CTRL_BYTE_SW \
+ 0x40 // Byte-swap word pairs
+#define MPU9150_I2C_SLV0_CTRL_REG_DIS \
+ 0x20 // Disable register number transfer
+#define MPU9150_I2C_SLV0_CTRL_GRP \
+ 0x10 // Word pair grouping
+#define MPU9150_I2C_SLV0_CTRL_LEN_M \
+ 0x0F // Number of bytes to transfer
+#define MPU9150_I2C_SLV0_CTRL_LEN_S \
+ 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the MPU9150_O_I2C_SLV1_ADDR
+// register.
+//
+//*****************************************************************************
+#define MPU9150_I2C_SLV1_ADDR_RW \
+ 0x80 // Read/not write
+#define MPU9150_I2C_SLV1_ADDR_M 0x7F // Slave address
+#define MPU9150_I2C_SLV1_ADDR_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the MPU9150_O_I2C_SLV1_REG
+// register.
+//
+//*****************************************************************************
+#define MPU9150_I2C_SLV1_REG_M 0xFF // Slave register number
+#define MPU9150_I2C_SLV1_REG_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the MPU9150_O_I2C_SLV1_CTRL
+// register.
+//
+//*****************************************************************************
+#define MPU9150_I2C_SLV1_CTRL_EN \
+ 0x80 // Enable slave
+#define MPU9150_I2C_SLV1_CTRL_BYTE_SW \
+ 0x40 // Byte-swap word pairs
+#define MPU9150_I2C_SLV1_CTRL_REG_DIS \
+ 0x20 // Disable register number transfer
+#define MPU9150_I2C_SLV1_CTRL_GRP \
+ 0x10 // Word pair grouping
+#define MPU9150_I2C_SLV1_CTRL_LEN_M \
+ 0x0F // Number of bytes to transfer
+#define MPU9150_I2C_SLV1_CTRL_LEN_S \
+ 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the MPU9150_O_I2C_SLV2_ADDR
+// register.
+//
+//*****************************************************************************
+#define MPU9150_I2C_SLV2_ADDR_RW \
+ 0x80 // Read/not write
+#define MPU9150_I2C_SLV2_ADDR_M 0x7F // Slave address
+#define MPU9150_I2C_SLV2_ADDR_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the MPU9150_O_I2C_SLV2_REG
+// register.
+//
+//*****************************************************************************
+#define MPU9150_I2C_SLV2_REG_M 0xFF // Slave register number
+#define MPU9150_I2C_SLV2_REG_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the MPU9150_O_I2C_SLV2_CTRL
+// register.
+//
+//*****************************************************************************
+#define MPU9150_I2C_SLV2_CTRL_EN \
+ 0x80 // Enable slave
+#define MPU9150_I2C_SLV2_CTRL_BYTE_SW \
+ 0x40 // Byte-swap word pairs
+#define MPU9150_I2C_SLV2_CTRL_REG_DIS \
+ 0x20 // Disable register number transfer
+#define MPU9150_I2C_SLV2_CTRL_GRP \
+ 0x10 // Word pair grouping
+#define MPU9150_I2C_SLV2_CTRL_LEN_M \
+ 0x0F // Number of bytes to transfer
+#define MPU9150_I2C_SLV2_CTRL_LEN_S \
+ 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the MPU9150_O_I2C_SLV3_ADDR
+// register.
+//
+//*****************************************************************************
+#define MPU9150_I2C_SLV3_ADDR_RW \
+ 0x80 // Read/not write
+#define MPU9150_I2C_SLV3_ADDR_M 0x7F // Slave address
+#define MPU9150_I2C_SLV3_ADDR_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the MPU9150_O_I2C_SLV3_REG
+// register.
+//
+//*****************************************************************************
+#define MPU9150_I2C_SLV3_REG_M 0xFF // Slave register number
+#define MPU9150_I2C_SLV3_REG_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the MPU9150_O_I2C_SLV3_CTRL
+// register.
+//
+//*****************************************************************************
+#define MPU9150_I2C_SLV3_CTRL_EN \
+ 0x80 // Enable slave
+#define MPU9150_I2C_SLV3_CTRL_BYTE_SW \
+ 0x40 // Byte-swap word pairs
+#define MPU9150_I2C_SLV3_CTRL_REG_DIS \
+ 0x20 // Disable register number transfer
+#define MPU9150_I2C_SLV3_CTRL_GRP \
+ 0x10 // Word pair grouping
+#define MPU9150_I2C_SLV3_CTRL_LEN_M \
+ 0x0F // Number of bytes to transfer
+#define MPU9150_I2C_SLV3_CTRL_LEN_S \
+ 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the MPU9150_O_I2C_SLV4_ADDR
+// register.
+//
+//*****************************************************************************
+#define MPU9150_I2C_SLV4_ADDR_RW \
+ 0x80 // Read/not write
+#define MPU9150_I2C_SLV4_ADDR_M 0x7F // Slave address
+#define MPU9150_I2C_SLV4_ADDR_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the MPU9150_O_I2C_SLV4_REG
+// register.
+//
+//*****************************************************************************
+#define MPU9150_I2C_SLV4_REG_M 0xFF // Slave register number
+#define MPU9150_I2C_SLV4_REG_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the MPU9150_O_I2C_SLV4_CTRL
+// register.
+//
+//*****************************************************************************
+#define MPU9150_I2C_SLV4_CTRL_EN \
+ 0x80 // Enable slave
+#define MPU9150_I2C_SLV4_CTRL_INT_EN \
+ 0x40 // Interrupt enable
+#define MPU9150_I2C_SLV4_CTRL_REG_DIS \
+ 0x20 // Disable register number transfer
+#define MPU9150_I2C_SLV4_CTRL_I2C_MST_DLY_M \
+ 0x1F // Slave access delay
+#define MPU9150_I2C_SLV4_CTRL_I2C_MST_DLY_S \
+ 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the MPU9150_O_I2C_SLV4_DI
+// register.
+//
+//*****************************************************************************
+#define MPU9150_I2C_SLV4_DI_M 0xFF // Input data
+#define MPU9150_I2C_SLV4_DI_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the MPU9150_O_I2C_MST_STATUS
+// register.
+//
+//*****************************************************************************
+#define MPU9150_I2C_MST_STATUS_PASS_THROUGH \
+ 0x80 // Pass through FSYNC interrupt
+ // status
+#define MPU9150_I2C_MST_STATUS_I2C_SLV4_DONE \
+ 0x40 // I2C slave 4 completion status
+#define MPU9150_I2C_MST_STATUS_I2C_LOST_ARB \
+ 0x20 // I2C arbitration lost status
+#define MPU9150_I2C_MST_STATUS_I2C_SLV4_NACK \
+ 0x10 // I2C slave 4 NACK status
+#define MPU9150_I2C_MST_STATUS_I2C_SLV3_NACK \
+ 0x08 // I2C slave 3 NACK status
+#define MPU9150_I2C_MST_STATUS_I2C_SLV2_NACK \
+ 0x04 // I2C slave 2 NACK status
+#define MPU9150_I2C_MST_STATUS_I2C_SLV1_NACK \
+ 0x02 // I2C slave 1 NACK status
+#define MPU9150_I2C_MST_STATUS_I2C_SLV0_NACK \
+ 0x01 // I2C slave 0 NACK status
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the MPU9150_O_INT_PIN_CFG
+// register.
+//
+//*****************************************************************************
+#define MPU9150_INT_PIN_CFG_INT_LEVEL \
+ 0x80 // INT pin active low
+#define MPU9150_INT_PIN_CFG_INT_OPEN \
+ 0x40 // INT pin open-drain
+#define MPU9150_INT_PIN_CFG_LATCH_INT_EN \
+ 0x20 // Latch INT pin output
+#define MPU9150_INT_PIN_CFG_INT_RD_CLEAR \
+ 0x10 // Interrupt clear on any read
+#define MPU9150_INT_PIN_CFG_FSYNC_INT_LEVEL \
+ 0x08 // FSYNC pin active low
+#define MPU9150_INT_PIN_CFG_FSYNC_INT_EN \
+ 0x04 // FSYNC pin interrupt enable
+#define MPU9150_INT_PIN_CFG_I2C_BYPASS_EN \
+ 0x02 // I2C bypass enable
+#define MPU9150_INT_PIN_CFG_CLKOUT_EN \
+ 0x01 // CLKOUT enable
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the MPU9150_O_INT_ENABLE
+// register.
+//
+//*****************************************************************************
+#define MPU9150_INT_ENABLE_FF_EN \
+ 0x80 // Free-fall interrupt enable
+#define MPU9150_INT_ENABLE_MOT_EN \
+ 0x40 // Motion detection interrupt
+ // enable
+#define MPU9150_INT_ENABLE_ZMOT_EN \
+ 0x20 // Zero motion interrupt enable
+#define MPU9150_INT_ENABLE_FIFO_OFLOW_EN \
+ 0x10 // FIFO overflow interrupt enable
+#define MPU9150_INT_ENABLE_I2C_MST_INT_EN \
+ 0x08 // I2C master interrupt enable
+#define MPU9150_INT_ENABLE_DATA_RDY_EN \
+ 0x01 // Data ready interrupt enable
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the MPU9150_O_INT_STATUS
+// register.
+//
+//*****************************************************************************
+#define MPU9150_INT_STATUS_FF_INT \
+ 0x80 // Free-fall interrupt status
+#define MPU9150_INT_STATUS_MOT_INT \
+ 0x40 // Motion detection interrupt
+ // status
+#define MPU9150_INT_STATUS_ZMOT_INT \
+ 0x20 // Zero motion interrupt status
+#define MPU9150_INT_STATUS_FIFO_OFLOW_INT \
+ 0x10 // FIFO overflow interrupt status
+#define MPU9150_INT_STATUS_I2C_MST_INT \
+ 0x08 // I2C master interrupt status
+#define MPU9150_INT_STATUS_DATA_RDY_INT \
+ 0x01 // Data ready interrupt status
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the MPU9150_O_ACCEL_XOUT_H
+// register.
+//
+//*****************************************************************************
+#define MPU9150_ACCEL_XOUT_H_M 0xFF // Bits [15:8] of X-axis
+ // acceleration data
+#define MPU9150_ACCEL_XOUT_H_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the MPU9150_O_ACCEL_XOUT_L
+// register.
+//
+//*****************************************************************************
+#define MPU9150_ACCEL_XOUT_L_M 0xFF // Bits [7:0] of X-axis
+ // acceleration data
+#define MPU9150_ACCEL_XOUT_L_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the MPU9150_O_ACCEL_YOUT_H
+// register.
+//
+//*****************************************************************************
+#define MPU9150_ACCEL_YOUT_H_M 0xFF // Bits [15:8] of Y-axis
+ // acceleration data
+#define MPU9150_ACCEL_YOUT_H_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the MPU9150_O_ACCEL_YOUT_L
+// register.
+//
+//*****************************************************************************
+#define MPU9150_ACCEL_YOUT_L_M 0xFF // Bits [7:0] of Y-axis
+ // acceleration data
+#define MPU9150_ACCEL_YOUT_L_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the MPU9150_O_ACCEL_ZOUT_H
+// register.
+//
+//*****************************************************************************
+#define MPU9150_ACCEL_ZOUT_H_M 0xFF // Bits [15:8] of Z-axis
+ // acceleration data
+#define MPU9150_ACCEL_ZOUT_H_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the MPU9150_O_ACCEL_ZOUT_L
+// register.
+//
+//*****************************************************************************
+#define MPU9150_ACCEL_ZOUT_L_M 0xFF // Bits [7:0] of Z-axis
+ // acceleration data
+#define MPU9150_ACCEL_ZOUT_L_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the MPU9150_O_TEMP_OUT_H
+// register.
+//
+//*****************************************************************************
+#define MPU9150_ACCEL_TEMP_OUT_H_M \
+ 0xFF // Bits [15:8] of temperature data
+#define MPU9150_ACCEL_TEMP_OUT_H_S \
+ 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the MPU9150_O_TEMP_OUT_L
+// register.
+//
+//*****************************************************************************
+#define MPU9150_ACCEL_TEMP_OUT_L_M \
+ 0xFF // Bits [7:0] of temperature data
+#define MPU9150_ACCEL_TEMP_OUT_L_S \
+ 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the MPU9150_O_GYRO_XOUT_H
+// register.
+//
+//*****************************************************************************
+#define MPU9150_GYRO_XOUT_H_M 0xFF // Bits [15:8] of X-axis gyro data
+#define MPU9150_GYRO_XOUT_H_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the MPU9150_O_GYRO_XOUT_L
+// register.
+//
+//*****************************************************************************
+#define MPU9150_GYRO_XOUT_L_M 0xFF // Bits [7:0] of X-axis gyro data
+#define MPU9150_GYRO_XOUT_L_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the MPU9150_O_GYRO_YOUT_H
+// register.
+//
+//*****************************************************************************
+#define MPU9150_GYRO_YOUT_H_M 0xFF // Bits [15:8] of Y-axis gyro data
+#define MPU9150_GYRO_YOUT_H_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the MPU9150_O_GYRO_YOUT_L
+// register.
+//
+//*****************************************************************************
+#define MPU9150_GYRO_YOUT_L_M 0xFF // Bits [7:0] of Y-axis gyro data
+#define MPU9150_GYRO_YOUT_L_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the MPU9150_O_GYRO_ZOUT_H
+// register.
+//
+//*****************************************************************************
+#define MPU9150_GYRO_ZOUT_H_M 0xFF // Bits [15:8] of Z-axis gyro data
+#define MPU9150_GYRO_ZOUT_H_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the MPU9150_O_GYRO_ZOUT_L
+// register.
+//
+//*****************************************************************************
+#define MPU9150_GYRO_ZOUT_L_M 0xFF // Bits [7:0] of Z-axis gyro data
+#define MPU9150_GYRO_ZOUT_L_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the
+// MPU9150_O_EXT_SENS_DATA_00 register.
+//
+//*****************************************************************************
+#define MPU9150_EXT_SENS_DATA_00_M \
+ 0xFF // External sensor data
+#define MPU9150_EXT_SENS_DATA_00_S \
+ 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the
+// MPU9150_O_EXT_SENS_DATA_01 register.
+//
+//*****************************************************************************
+#define MPU9150_EXT_SENS_DATA_01_M \
+ 0xFF // External sensor data
+#define MPU9150_EXT_SENS_DATA_01_S \
+ 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the
+// MPU9150_O_EXT_SENS_DATA_02 register.
+//
+//*****************************************************************************
+#define MPU9150_EXT_SENS_DATA_02_M \
+ 0xFF // External sensor data
+#define MPU9150_EXT_SENS_DATA_02_S \
+ 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the
+// MPU9150_O_EXT_SENS_DATA_03 register.
+//
+//*****************************************************************************
+#define MPU9150_EXT_SENS_DATA_03_M \
+ 0xFF // External sensor data
+#define MPU9150_EXT_SENS_DATA_03_S \
+ 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the
+// MPU9150_O_EXT_SENS_DATA_04 register.
+//
+//*****************************************************************************
+#define MPU9150_EXT_SENS_DATA_04_M \
+ 0xFF // External sensor data
+#define MPU9150_EXT_SENS_DATA_04_S \
+ 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the
+// MPU9150_O_EXT_SENS_DATA_05 register.
+//
+//*****************************************************************************
+#define MPU9150_EXT_SENS_DATA_05_M \
+ 0xFF // External sensor data
+#define MPU9150_EXT_SENS_DATA_05_S \
+ 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the
+// MPU9150_O_EXT_SENS_DATA_06 register.
+//
+//*****************************************************************************
+#define MPU9150_EXT_SENS_DATA_06_M \
+ 0xFF // External sensor data
+#define MPU9150_EXT_SENS_DATA_06_S \
+ 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the
+// MPU9150_O_EXT_SENS_DATA_07 register.
+//
+//*****************************************************************************
+#define MPU9150_EXT_SENS_DATA_07_M \
+ 0xFF // External sensor data
+#define MPU9150_EXT_SENS_DATA_07_S \
+ 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the
+// MPU9150_O_EXT_SENS_DATA_08 register.
+//
+//*****************************************************************************
+#define MPU9150_EXT_SENS_DATA_08_M \
+ 0xFF // External sensor data
+#define MPU9150_EXT_SENS_DATA_08_S \
+ 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the
+// MPU9150_O_EXT_SENS_DATA_09 register.
+//
+//*****************************************************************************
+#define MPU9150_EXT_SENS_DATA_09_M \
+ 0xFF // External sensor data
+#define MPU9150_EXT_SENS_DATA_09_S \
+ 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the
+// MPU9150_O_EXT_SENS_DATA_10 register.
+//
+//*****************************************************************************
+#define MPU9150_EXT_SENS_DATA_10_M \
+ 0xFF // External sensor data
+#define MPU9150_EXT_SENS_DATA_10_S \
+ 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the
+// MPU9150_O_EXT_SENS_DATA_11 register.
+//
+//*****************************************************************************
+#define MPU9150_EXT_SENS_DATA_11_M \
+ 0xFF // External sensor data
+#define MPU9150_EXT_SENS_DATA_11_S \
+ 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the
+// MPU9150_O_EXT_SENS_DATA_12 register.
+//
+//*****************************************************************************
+#define MPU9150_EXT_SENS_DATA_12_M \
+ 0xFF // External sensor data
+#define MPU9150_EXT_SENS_DATA_12_S \
+ 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the
+// MPU9150_O_EXT_SENS_DATA_13 register.
+//
+//*****************************************************************************
+#define MPU9150_EXT_SENS_DATA_13_M \
+ 0xFF // External sensor data
+#define MPU9150_EXT_SENS_DATA_13_S \
+ 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the
+// MPU9150_O_EXT_SENS_DATA_14 register.
+//
+//*****************************************************************************
+#define MPU9150_EXT_SENS_DATA_14_M \
+ 0xFF // External sensor data
+#define MPU9150_EXT_SENS_DATA_14_S \
+ 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the
+// MPU9150_O_EXT_SENS_DATA_15 register.
+//
+//*****************************************************************************
+#define MPU9150_EXT_SENS_DATA_15_M \
+ 0xFF // External sensor data
+#define MPU9150_EXT_SENS_DATA_15_S \
+ 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the
+// MPU9150_O_EXT_SENS_DATA_16 register.
+//
+//*****************************************************************************
+#define MPU9150_EXT_SENS_DATA_16_M \
+ 0xFF // External sensor data
+#define MPU9150_EXT_SENS_DATA_16_S \
+ 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the
+// MPU9150_O_EXT_SENS_DATA_17 register.
+//
+//*****************************************************************************
+#define MPU9150_EXT_SENS_DATA_17_M \
+ 0xFF // External sensor data
+#define MPU9150_EXT_SENS_DATA_17_S \
+ 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the
+// MPU9150_O_EXT_SENS_DATA_18 register.
+//
+//*****************************************************************************
+#define MPU9150_EXT_SENS_DATA_18_M \
+ 0xFF // External sensor data
+#define MPU9150_EXT_SENS_DATA_18_S \
+ 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the
+// MPU9150_O_EXT_SENS_DATA_19 register.
+//
+//*****************************************************************************
+#define MPU9150_EXT_SENS_DATA_19_M \
+ 0xFF // External sensor data
+#define MPU9150_EXT_SENS_DATA_19_S \
+ 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the
+// MPU9150_O_EXT_SENS_DATA_20 register.
+//
+//*****************************************************************************
+#define MPU9150_EXT_SENS_DATA_20_M \
+ 0xFF // External sensor data
+#define MPU9150_EXT_SENS_DATA_20_S \
+ 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the
+// MPU9150_O_EXT_SENS_DATA_21 register.
+//
+//*****************************************************************************
+#define MPU9150_EXT_SENS_DATA_21_M \
+ 0xFF // External sensor data
+#define MPU9150_EXT_SENS_DATA_21_S \
+ 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the
+// MPU9150_O_EXT_SENS_DATA_22 register.
+//
+//*****************************************************************************
+#define MPU9150_EXT_SENS_DATA_22_M \
+ 0xFF // External sensor data
+#define MPU9150_EXT_SENS_DATA_22_S \
+ 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the
+// MPU9150_O_EXT_SENS_DATA_23 register.
+//
+//*****************************************************************************
+#define MPU9150_EXT_SENS_DATA_23_M \
+ 0xFF // External sensor data
+#define MPU9150_EXT_SENS_DATA_23_S \
+ 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the
+// MPU9150_O_MOT_DETECT_STATUS register.
+//
+//*****************************************************************************
+#define MPU9150_MOT_DETECT_STATUS_MOT_XNEG \
+ 0x80 // Negative X-axis motion detect
+ // status
+#define MPU9150_MOT_DETECT_STATUS_MOT_XPOS \
+ 0x40 // Positive X-axis motion detect
+ // status
+#define MPU9150_MOT_DETECT_STATUS_MOT_YNEG \
+ 0x20 // Negative Y-axis motion detect
+ // status
+#define MPU9150_MOT_DETECT_STATUS_MOT_YPOS \
+ 0x10 // Positive Y-axis motion detect
+ // status
+#define MPU9150_MOT_DETECT_STATUS_MOT_ZNEG \
+ 0x08 // Negative Z-axis motion detect
+ // status
+#define MPU9150_MOT_DETECT_STATUS_MOT_ZPOS \
+ 0x04 // Positive Z-axis motion detect
+ // status
+#define MPU9150_MOT_DETECT_STATUS_MOT_ZRMOT \
+ 0x01 // Zero motion detect status
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the MPU9150_O_I2C_SLV0_DO
+// register.
+//
+//*****************************************************************************
+#define MPU9150_I2C_SLV0_DO_M 0xFF // Output data
+#define MPU9150_I2C_SLV0_DO_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the MPU9150_O_I2C_SLV1_DO
+// register.
+//
+//*****************************************************************************
+#define MPU9150_I2C_SLV1_DO_M 0xFF // Output data
+#define MPU9150_I2C_SLV1_DO_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the MPU9150_O_I2C_SLV2_DO
+// register.
+//
+//*****************************************************************************
+#define MPU9150_I2C_SLV2_DO_M 0xFF // Output data
+#define MPU9150_I2C_SLV2_DO_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the MPU9150_O_I2C_SLV3_DO
+// register.
+//
+//*****************************************************************************
+#define MPU9150_I2C_SLV3_DO_M 0xFF // Output data
+#define MPU9150_I2C_SLV3_DO_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the
+// MPU9150_O_I2C_MST_DELAY_CTRL register.
+//
+//*****************************************************************************
+#define MPU9150_I2C_MST_DELAY_CTRL_DELAY_ES_SHADOW \
+ 0x80 // Delay external sensor data
+#define MPU9150_I2C_MST_DELAY_CTRL_I2C_SLV4_DLY_EN \
+ 0x10 // I2C slave 4 delay enable
+#define MPU9150_I2C_MST_DELAY_CTRL_I2C_SLV3_DLY_EN \
+ 0x08 // I2C slave 3 delay enable
+#define MPU9150_I2C_MST_DELAY_CTRL_I2C_SLV2_DLY_EN \
+ 0x04 // I2C slave 2 delay enable
+#define MPU9150_I2C_MST_DELAY_CTRL_I2C_SLV1_DLY_EN \
+ 0x02 // I2C slave 1 delay enable
+#define MPU9150_I2C_MST_DELAY_CTRL_I2C_SLV0_DLY_EN \
+ 0x01 // I2C slave 0 delay enable
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the
+// MPU9150_O_SIGNAL_PATH_RESET register.
+//
+//*****************************************************************************
+#define MPU9150_SIGNAL_PATH_RESET_GYRO \
+ 0x04 // Reset gyro
+#define MPU9150_SIGNAL_PATH_RESET_ACCEL \
+ 0x02 // Reset accelerometer
+#define MPU9150_SIGNAL_PATH_RESET_TEMP \
+ 0x01 // Reset temperature sensor
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the
+// MPU9150_O_MOT_DETECT_CTRL register.
+//
+//*****************************************************************************
+#define MPU9150_MOT_DETECT_CTRL_ACCEL_ON_DELAY_M \
+ 0x30 // Accelerometer wake-up delay
+#define MPU9150_MOT_DETECT_CTRL_ACCEL_ON_DELAY_4MS \
+ 0x00 // Delay 4 ms
+#define MPU9150_MOT_DETECT_CTRL_ACCEL_ON_DELAY_5MS \
+ 0x10 // Delay 5 ms
+#define MPU9150_MOT_DETECT_CTRL_ACCEL_ON_DELAY_6MS \
+ 0x20 // Delay 6 ms
+#define MPU9150_MOT_DETECT_CTRL_ACCEL_ON_DELAY_7MS \
+ 0x30 // Delay 7 ms
+#define MPU9150_MOT_DETECT_CTRL_FF_COUNT_M \
+ 0x0C // Free-fall counter decrement rate
+#define MPU9150_MOT_DETECT_CTRL_FF_COUNT_RESET \
+ 0x00 // Reset counter
+#define MPU9150_MOT_DETECT_CTRL_FF_COUNT_1 \
+ 0x04 // Decrement by 1
+#define MPU9150_MOT_DETECT_CTRL_FF_COUNT_2 \
+ 0x08 // Decrement by 2
+#define MPU9150_MOT_DETECT_CTRL_FF_COUNT_4 \
+ 0x0C // Decrement by 4
+#define MPU9150_MOT_DETECT_CTRL_MOT_COUNT_M \
+ 0x03 // Motion detect counter decrement
+ // rate
+#define MPU9150_MOT_DETECT_CTRL_MOT_COUNT_RESET \
+ 0x00 // Reset counter
+#define MPU9150_MOT_DETECT_CTRL_MOT_COUNT_1 \
+ 0x04 // Decrement by 1
+#define MPU9150_MOT_DETECT_CTRL_MOT_COUNT_2 \
+ 0x08 // Decrement by 2
+#define MPU9150_MOT_DETECT_CTRL_MOT_COUNT_4 \
+ 0x0C // Decrement by 4
+#define MPU9150_MOT_DETECT_CTRL_ACCEL_ON_DELAY_S \
+ 4
+#define MPU9150_MOT_DETECT_CTRL_FF_COUNT_S \
+ 2
+#define MPU9150_MOT_DETECT_CTRL_MOT_COUNT_S \
+ 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the MPU9150_O_USER_CTRL
+// register.
+//
+//*****************************************************************************
+#define MPU9150_USER_CTRL_FIFO_EN \
+ 0x40 // FIFO enable
+#define MPU9150_USER_CTRL_I2C_MST_EN \
+ 0x20 // I2C master mode enable
+#define MPU9150_USER_CTRL_I2C_IF_DIS \
+ 0x10 // Write as zero
+#define MPU9150_USER_CTRL_FIFO_RESET \
+ 0x04 // Reset FIFO buffer
+#define MPU9150_USER_CTRL_I2C_MST_RESET \
+ 0x02 // Reset I2C master
+#define MPU9150_USER_CTRL_SIG_COND_RESET \
+ 0x01 // Reset all sensors
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the MPU9150_O_PWR_MGMT_1
+// register.
+//
+//*****************************************************************************
+#define MPU9150_PWR_MGMT_1_DEVICE_RESET \
+ 0x80 // Device reset
+#define MPU9150_PWR_MGMT_1_SLEEP \
+ 0x40 // Enter sleep mode
+#define MPU9150_PWR_MGMT_1_CYCLE \
+ 0x20 // Enable automatic sleep
+#define MPU9150_PWR_MGMT_1_TEMP_DIS \
+ 0x08 // Disable temperature sensor
+#define MPU9150_PWR_MGMT_1_CLKSEL_M \
+ 0x07 // Clock source select
+#define MPU9150_PWR_MGMT_1_CLKSEL_INT \
+ 0x00 // Internal 8 MHz oscillator
+#define MPU9150_PWR_MGMT_1_CLKSEL_XG \
+ 0x01 // PLL with X-axis gyro reference
+#define MPU9150_PWR_MGMT_1_CLKSEL_YG \
+ 0x02 // PLL with Y-axis gyro reference
+#define MPU9150_PWR_MGMT_1_CLKSEL_ZG \
+ 0x03 // PLL with Z-axis gyro reference
+#define MPU9150_PWR_MGMT_1_CLKSEL_EXT32K \
+ 0x04 // PLL with external 32.768 kHz
+ // reference
+#define MPU9150_PWR_MGMT_1_CLKSEL_EXT19M \
+ 0x05 // PLL with external 19.2 MHz
+ // reference
+#define MPU9150_PWR_MGMT_1_CLKSEL_STOP \
+ 0x07 // Clock disable
+#define MPU9150_PWR_MGMT_1_CLKSEL_S \
+ 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the MPU9150_O_PWR_MGMT_2
+// register.
+//
+//*****************************************************************************
+#define MPU9150_PWR_MGMT_2_LP_WAKE_CTRL_M \
+ 0xC0 // Wake-up frequency
+#define MPU9150_PWR_MGMT_2_LP_WAKE_CTRL_1_25 \
+ 0x00 // Wake-up at 1.25 Hz
+#define MPU9150_PWR_MGMT_2_LP_WAKE_CTRL_5 \
+ 0x40 // Wake-up at 5 Hz
+#define MPU9150_PWR_MGMT_2_LP_WAKE_CTRL_20 \
+ 0x80 // Wake-up at 20 Hz
+#define MPU9150_PWR_MGMT_2_LP_WAKE_CTRL_40 \
+ 0xC0 // Wake-up at 40 Hz
+#define MPU9150_PWR_MGMT_2_STBY_XA \
+ 0x20 // Put X-axis accelerometer into
+ // standby mode
+#define MPU9150_PWR_MGMT_2_STBY_YA \
+ 0x10 // Put Y-axis accelerometer into
+ // standby mode
+#define MPU9150_PWR_MGMT_2_STBY_ZA \
+ 0x08 // Put Z-axis accelerometer into
+ // standby mode
+#define MPU9150_PWR_MGMT_2_STBY_XG \
+ 0x04 // Put X-axis gyro into standby
+ // mode
+#define MPU9150_PWR_MGMT_2_STBY_YG \
+ 0x02 // Put Y-axis gyro into standby
+ // mode
+#define MPU9150_PWR_MGMT_2_STBY_ZG \
+ 0x01 // Put Z-axis gyro into standby
+ // mode
+#define MPU9150_PWR_MGMT_2_LP_WAKE_CTRL_S \
+ 6
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the MPU9150_O_FIFO_COUNTH
+// register.
+//
+//*****************************************************************************
+#define MPU9150_FIFO_COUNTH_M 0x07 // FIFO count [10:8]
+#define MPU9150_FIFO_COUNTH_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the MPU9150_O_FIFO_COUNTL
+// register.
+//
+//*****************************************************************************
+#define MPU9150_FIFO_COUNTL_M 0xFF // FIFO count [7:0]
+#define MPU9150_FIFO_COUNTL_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the MPU9150_O_FIFO_R_W
+// register.
+//
+//*****************************************************************************
+#define MPU9150_FIFO_R_W_M 0xFF // FIFO data
+#define MPU9150_FIFO_R_W_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the MPU9150_O_WHO_AM_I
+// register.
+//
+//*****************************************************************************
+#define MPU9150_WHO_AM_I_M 0x7E // I2C address
+#define MPU9150_WHO_AM_I_MPU9150 \
+ 0x68 // MPU9150
+#define MPU9150_WHO_AM_I_S 1
+
+#endif // __SENSORLIB_HW_MPU9150_H__
diff --git a/sensorlib/hw_sht21.h b/sensorlib/hw_sht21.h
new file mode 100644
index 0000000..550af75
--- /dev/null
+++ b/sensorlib/hw_sht21.h
@@ -0,0 +1,76 @@
+//*****************************************************************************
+//
+// hw_sht21.h - Macros used for accessing the Intersil SHT21 humidity sensor
+//
+// Copyright (c) 2013-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
+//
+//*****************************************************************************
+
+#ifndef __SENSORLIB_HW_SHT21_H__
+#define __SENSORLIB_HW_SHT21_H__
+
+//*****************************************************************************
+//
+// The following are defines for the SHT21 Commands and Registers
+//
+//*****************************************************************************
+#define SHT21_CMD_MEAS_T_HOLD 0xE3 // Measure temperatue with I2C bus
+ // hold
+#define SHT21_CMD_MEAS_RH_HOLD 0xE5 // Measure humidity with I2C bus
+ // hold
+#define SHT21_CMD_WRITE_CONFIG 0xE6 // Write the user config register
+#define SHT21_CMD_READ_CONFIG 0xE7 // Read the user config register
+#define SHT21_CMD_MEAS_T 0xF3 // Measure temperature polled
+#define SHT21_CMD_MEAS_RH 0xF5 // Measure humidity polled
+#define SHT21_CMD_SOFT_RESET 0xFE // Perform a device reset
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the SHT21_CONFIG register.
+//
+//*****************************************************************************
+#define SHT21_CONFIG_RES_M 0x81 // Resolution config for
+ // temperature and humidity
+#define SHT21_CONFIG_RES_12 0x00 // RH 12 bit, T 14 bit
+#define SHT21_CONFIG_RES_8 0x01 // RH 8 bit, T 12 bit
+#define SHT21_CONFIG_RES_10 0x80 // RH 10 bit, T 13 bit
+#define SHT21_CONFIG_RES_11 0x81 // RH 11 bit, T 11 bit
+#define SHT21_CONFIG_BATT_M 0x40 // Battery status indicator
+#define SHT21_CONFIG_BATT_GOOD 0x00
+#define SHT21_CONFIG_BATT_LOW 0x40
+#define SHT21_CONFIG_HEATER_M 0x04 // On chip heater for test and
+ // diagnostics
+#define SHT21_CONFIG_HEATER_DISABLE \
+ 0x00 // Heater off
+#define SHT21_CONFIG_HEATER_ENABLE \
+ 0x04 // Heater on
+#define SHT21_CONFIG_OTP_RELOAD_M \
+ 0x02 // OTP reload control; soft reset
+ // is preferred
+#define SHT21_CONFIG_OTP_RELOAD_ENABLE \
+ 0x00 // OTP reload enabled
+#define SHT21_CONFIG_OTP_RELOAD_DISABLE \
+ 0x02 // OTP reload disabled
+#define SHT21_CONFIG_BATT_S 6
+#define SHT21_CONFIG_HEATER_S 2
+#define SHT21_CONFIG_OTP_RELOAD_S \
+ 1
+#define SHT21_CONFIG_RES_S 0
+
+#endif // __SENSORLIB_HW_SHT21_H__
diff --git a/sensorlib/hw_tmp006.h b/sensorlib/hw_tmp006.h
new file mode 100644
index 0000000..6c350c8
--- /dev/null
+++ b/sensorlib/hw_tmp006.h
@@ -0,0 +1,75 @@
+//*****************************************************************************
+//
+// hw_tmp006.h - Macros used when accessing the Texas Instruments TMP006
+// Infrared Temperature Sensor
+//
+// Copyright (c) 2013-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
+//
+//*****************************************************************************
+
+#ifndef __SENSORLIB_HW_TMP006_H__
+#define __SENSORLIB_HW_TMP006_H__
+
+//*****************************************************************************
+//
+// The following are defines for the TMP006 Register Addresses
+//
+//*****************************************************************************
+#define TMP006_O_VOBJECT 0x00 // Raw object voltage measurement
+#define TMP006_O_TAMBIENT 0x01 // Die temperature of the TMP006
+#define TMP006_O_CONFIG 0x02 // TMP006 Configuration
+#define TMP006_O_MFG_ID 0xFE // TMP006 Manufacture
+ // Identification
+#define TMP006_O_DEV_ID 0xFF // TMP006 Device Identification
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the TMP006_O_CONFIG
+// register.
+//
+//*****************************************************************************
+#define TMP006_CONFIG_RESET_M 0x8000 // TMP006 device reset
+#define TMP006_CONFIG_RESET_ASSERT \
+ 0x8000 // Reset TMP006; self clearing
+#define TMP006_CONFIG_MODE_M 0x7000 // Operation mode
+#define TMP006_CONFIG_MODE_PD 0x0000 // Power down
+#define TMP006_CONFIG_MODE_CONT 0x7000 // Continuous sampling
+#define TMP006_CONFIG_CR_M 0x0E00 // Conversion rate setting
+#define TMP006_CONFIG_CR_4 0x0000 // 4Hz conversion rate
+#define TMP006_CONFIG_CR_2 0x0200 // 2Hz conversion rate
+#define TMP006_CONFIG_CR_1 0x0400 // 1Hz conversion rate
+#define TMP006_CONFIG_CR_0_5 0x0600 // 0.5Hz conversion rate
+#define TMP006_CONFIG_CR_0_25 0x0800 // 0.25Hz conversion rate
+#define TMP006_CONFIG_EN_DRDY_PIN_M \
+ 0x0100 // Enable the DRDY output pin
+#define TMP006_CONFIG_DIS_DRDY_PIN \
+ 0x0000 // DRDY pin disabled
+#define TMP006_CONFIG_EN_DRDY_PIN \
+ 0x0100 // DRDY pin enabled
+#define TMP006_CONFIG_DRDY_M 0x0080 // Data ready flag
+#define TMP006_CONFIG_IN_PROG 0x0000 // Conversion in progress
+#define TMP006_CONFIG_DRDY 0x0080 // Conversion complete
+#define TMP006_CONFIG_RESET_S 15
+#define TMP006_CONFIG_MODE_S 12
+#define TMP006_CONFIG_CR_S 9
+#define TMP006_CONFIG_EN_DRDY_PIN_S \
+ 8
+#define TMP006_CONFIG_DRDY_S 7
+
+#endif // __SENSORLIB_HW_TMP006_H__
diff --git a/sensorlib/hw_tmp100.h b/sensorlib/hw_tmp100.h
new file mode 100644
index 0000000..5debb87
--- /dev/null
+++ b/sensorlib/hw_tmp100.h
@@ -0,0 +1,93 @@
+//*****************************************************************************
+//
+// hw_tmp100.h - Macros used when accessing the Texas Instruments TMP100
+// Temperature Sensor
+//
+// Copyright (c) 2013-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
+//
+//*****************************************************************************
+
+#ifndef __SENSORLIB_HW_TMP100_H__
+#define __SENSORLIB_HW_TMP100_H__
+
+//*****************************************************************************
+//
+// The following are defines for the TMP100 Register Addresses
+//
+//*****************************************************************************
+#define TMP100_O_TEMP 0x00 // Temperature register
+#define TMP100_O_CONFIG 0x01 // Configuration register
+#define TMP100_O_TEMP_LOW 0x02 // Temperature low register
+#define TMP100_O_TEMP_HIGH 0x03 // Temperature high register
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the TMP100_O_TEMP register.
+//
+//*****************************************************************************
+#define TMP100_TEMP_M 0xFFFF // Temperature data
+#define TMP100_TEMP_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the TMP100_O_CONFIG
+// register.
+//
+//*****************************************************************************
+#define TMP100_CONFIG_OS_ALERT 0x80 // Starts a one-shot when written,
+ // reports alert when read
+#define TMP100_CONFIG_RES_M 0x60 // Converter resolution
+#define TMP100_CONFIG_RES_9BIT 0x00 // 9-bit resolution (40 ms
+ // conversion time)
+#define TMP100_CONFIG_RES_10BIT 0x20 // 10-bit resolution (80 ms
+ // conversion time)
+#define TMP100_CONFIG_RES_11BIT 0x40 // 11-bit resolution (160 ms
+ // conversion time)
+#define TMP100_CONFIG_RES_12BIT 0x60 // 12-bit resolution (320 ms
+ // conversion time)
+#define TMP100_CONFIG_CR_M 0x18 // Consecutive fault configuration
+#define TMP100_CONFIG_FAULT_1 0x00 // 1 consecutive fault
+#define TMP100_CONFIG_FAULT_2 0x08 // 2 consecutive faults
+#define TMP100_CONFIG_FAULT_4 0x10 // 4 consecutive faults
+#define TMP100_CONFIG_FAULT_6 0x18 // 6 consecutive faults
+#define TMP100_CONFIG_POL 0x04 // Alert pin polarity
+#define TMP100_CONFIG_TM 0x02 // Thermostat mode
+#define TMP100_CONFIG_SD 0x01 // Shutdown mode
+#define TMP100_CONFIG_RES_S 5
+#define TMP100_CONFIG_FAULT_S 3
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the TMP100_O_TEMP_LOW
+// register.
+//
+//*****************************************************************************
+#define TMP100_TEMP_LOW_M 0xFFFF // Temperature low data
+#define TMP100_TEMP_LOW_S 0
+
+//*****************************************************************************
+//
+// The following are defines for the bit fields in the TMP100_O_TEMP_HIGH
+// register.
+//
+//*****************************************************************************
+#define TMP100_TEMP_HIGH_M 0xFFFF // Temperature high data
+#define TMP100_TEMP_HIGH_S 0
+
+#endif // __SENSORLIB_HW_TMP100_H__
diff --git a/sensorlib/i2cm_drv.c b/sensorlib/i2cm_drv.c
new file mode 100644
index 0000000..1e603e2
--- /dev/null
+++ b/sensorlib/i2cm_drv.c
@@ -0,0 +1,2256 @@
+//*****************************************************************************
+//
+// i2cm_drv.c - Interrupt-driven I2C master driver.
+//
+// Copyright (c) 2012-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
+//
+//*****************************************************************************
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "inc/hw_i2c.h"
+#include "inc/hw_memmap.h"
+#include "inc/hw_types.h"
+#include "driverlib/debug.h"
+#include "driverlib/i2c.h"
+#include "driverlib/interrupt.h"
+#include "driverlib/rom.h"
+#include "driverlib/rom_map.h"
+#include "sensorlib/i2cm_drv.h"
+
+//*****************************************************************************
+//
+//! \addtogroup i2cm_drv_api
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// The states in the interrupt handler state machine.
+//
+//*****************************************************************************
+#define STATE_IDLE 0
+#define STATE_WRITE_NEXT 1
+#define STATE_WRITE_FINAL 2
+#define STATE_WRITE_PAUSE 3
+#define STATE_READ_ONE 4
+#define STATE_READ_FIRST 5
+#define STATE_READ_NEXT 6
+#define STATE_READ_FINAL 7
+#define STATE_READ_PAUSE 8
+#define STATE_READ_WAIT 9
+#define STATE_CALLBACK 10
+
+//*****************************************************************************
+//
+// The states in the I2C read-modify-write state machine.
+//
+//*****************************************************************************
+#define I2CM_RMW_STATE_IDLE 0
+#define I2CM_RMW_STATE_READ 1
+#define I2CM_RMW_STATE_WRITE 2
+
+//*****************************************************************************
+//
+//! Writes data to an I2C device.
+//!
+//! \param psInst is a pointer to the I2C master instance data.
+//! \param ui8Addr is the address of the I2C device to access.
+//! \param pui8Data is a pointer to the data buffer to be written.
+//! \param ui16Count is the number of bytes to be written.
+//! \param pfnCallback is the function to be called when the write has
+//! completed (can be \b NULL if a callback is not required).
+//! \param pvCallbackData is a pointer that is passed to the callback function.
+//!
+//! This function adds an I2C write to the queue of commands to be sent. If
+//! successful, the I2C write is then performed in the background using the
+//! interrupt handler. When the write is complete, the callback function, if
+//! provided, is called in the context of the I2C master interrupt handler.
+//!
+//! The first byte of the data buffer contains the I2C address of the device to
+//! access, and the remaining \e ui16Count bytes contain the data to be written
+//! to the device. The \e ui16Count parameter can be zero if there are no
+//! bytes to be written.
+//!
+//! \return Returns 1 if the command was successfully added to the queue and 0
+//! if it was not.
+//
+// The extern here provides a non-inline definition for this function to handle
+// the case where the compiler chooses not to inline the function (which is a
+// valid choice for the compiler to make).
+//
+//*****************************************************************************
+extern uint_fast8_t I2CMWrite(tI2CMInstance *psInst, uint_fast8_t ui8Addr,
+ const uint8_t *pui8Data, uint_fast16_t ui16Count,
+ tSensorCallback pfnCallback,
+ void *pvCallbackData);
+
+//*****************************************************************************
+//
+//! Reads data from an I2C device.
+//!
+//! \param psInst is a pointer to the I2C master instance data.
+//! \param ui8Addr is the address of the I2C device to access.
+//! \param pui8WriteData is a pointer to the data buffer to be written.
+//! \param ui16WriteCount is the number of bytes to be written.
+//! \param pui8ReadData is a pointer to the buffer to be filled with the read
+//! data.
+//! \param ui16ReadCount is the number of bytes to be read.
+//! \param pfnCallback is the function to be called when the transfer has
+//! completed (can be \b NULL if a callback is not required).
+//! \param pvCallbackData is a pointer that is passed to the callback function.
+//!
+//! This function adds an I2C read to the queue of commands to be sent. If
+//! successful, the I2C read is then performed in the background using the
+//! interrupt handler. When the read is complete, the callback function, if
+//! provided, is called in the context of the I2C master interrupt handler.
+//!
+//! The first byte of \e pui8WriteData contains the I2C address of the device
+//! to access, the next \e ui16WriteCount bytes contains the data to be written
+//! to the device. The data read from the device is written into the first
+//! \e ui16ReadCount bytes of \e pui8ReadData. The \e ui16WriteCount or
+//! \e ui16ReadCount parameters can be zero if there are no bytes to be read or
+//! written. The write bytes are sent to the device first, and then the read
+//! bytes are read from the device afterward.
+//!
+//! \return Returns 1 if the command was successfully added to the queue and 0
+//! if it was not.
+//
+// The extern here provides a non-inline definition for this function to handle
+// the case where the compiler chooses not to inline the function (which is a
+// valid choice for the compiler to make).
+//
+//*****************************************************************************
+extern uint_fast8_t I2CMRead(tI2CMInstance *psInst, uint_fast8_t ui8Addr,
+ const uint8_t *pui8WriteData,
+ uint_fast16_t ui16WriteCount,
+ uint8_t *pui8ReadData,
+ uint_fast16_t ui16ReadCount,
+ tSensorCallback pfnCallback,
+ void *pvCallbackData);
+
+//*****************************************************************************
+//
+//! Writes data in batches to an I2C device.
+//!
+//! \param psInst is a pointer to the I2C master instance data.
+//! \param ui8Addr is the address of the I2C device to access.
+//! \param pui8Data is a pointer to the data buffer to be written.
+//! \param ui16Count is the number of bytes to be written.
+//! \param ui16BatchSize is the number of bytes in each write batch.
+//! \param pfnCallback is the function to be called when the transfer has
+//! completed (can be \b NULL if a callback is not required).
+//! \param pvCallbackData is a pointer that is passed to the callback function.
+//!
+//! This function adds an I2C write to the queue of commands to be sent. If
+//! successful, the I2C write is then performed in the background using the
+//! interrupt handler. When the write is complete, the callback function, if
+//! provided, is called in the context of the I2C master interrupt handler.
+//!
+//! The first byte of the data buffer contains the I2C address of the device to
+//! access, and the remaining \e ui16Count bytes contain the data to be written
+//! to the device. The \e ui16Count parameter can be zero if there are no
+//! bytes to be written.
+//!
+//! The data is written in batches of \e ui16WriteBatchSize. The callback
+//! function is called after each batch is written, and I2CMTransferResume()
+//! must be called when the next batch should be written.
+//!
+//! \return Returns 1 if the command was successfully added to the queue and 0
+//! if it was not.
+//
+// The extern here provides a non-inline definition for this function to handle
+// the case where the compiler chooses not to inline the function (which is a
+// valid choice for the compiler to make).
+//
+//*****************************************************************************
+extern uint_fast8_t I2CMWriteBatched(tI2CMInstance *psInst,
+ uint_fast8_t ui8Addr,
+ const uint8_t *pui8Data,
+ uint_fast16_t ui16Count,
+ uint_fast16_t ui16BatchSize,
+ tSensorCallback pfnCallback,
+ void *pvCallbackData);
+
+//*****************************************************************************
+//
+//! Reads data in batches from an I2C device.
+//!
+//! \param psInst is a pointer to the I2C master instance data.
+//! \param ui8Addr is the address of the I2C device to access.
+//! \param pui8WriteData is a pointer to the data buffer to be written.
+//! \param ui16WriteCount is the number of bytes to be written.
+//! \param ui16WriteBatchSize is the number of bytes in each write batch.
+//! \param pui8ReadData is a pointer to the buffer to be filled with the read
+//! data.
+//! \param ui16ReadCount is the number of bytes to be read.
+//! \param ui16ReadBatchSize is the number of bytes in each read batch.
+//! \param pfnCallback is the function to be called when the transfer has
+//! completed (can be \b NULL if a callback is not required).
+//! \param pvCallbackData is a pointer that is passed to the callback function.
+//!
+//! This function adds an I2C read to the queue of commands to be sent. If
+//! successful, the I2C read is then performed in the background using the
+//! interrupt handler. When the read is complete, the callback function, if
+//! provided, is called in the context of the I2C master interrupt handler.
+//!
+//! The first byte of \e pui8WriteData contains the I2C address of the device
+//! to access, the next \e ui16WriteCount bytes contains the data to be written
+//! to the device. The data read from the device is written into the first
+//! \e ui16ReadCount bytes of \e pui8ReadData. The \e ui16WriteCount or
+//! \e ui16ReadCount parameters can be zero if there are no bytes to be read or
+//! written. The write bytes are sent to the device first, and then the read
+//! bytes are read from the device afterward.
+//!
+//! The data is written in batches of \e ui16WriteBatchSize. The callback
+//! function is called after each batch is written, and I2CMTransferResume()
+//! must be called when the next batch should be written.
+//!
+//! The data is read in batches of \e ui16ReadBatchSize. The callback function
+//! is called after each batch is read, and I2CMTransferResume() must be called
+//! when the next batch should be read.
+//!
+//! \return Returns 1 if the command was successfully added to the queue and 0
+//! if it was not.
+//
+// The extern here provides a non-inline definition for this function to handle
+// the case where the compiler chooses not to inline the function (which is a
+// valid choice for the compiler to make).
+//
+//*****************************************************************************
+extern uint_fast8_t I2CMReadBatched(tI2CMInstance *psInst,
+ uint_fast8_t ui8Addr,
+ const uint8_t *pui8WriteData,
+ uint_fast16_t ui16WriteCount,
+ uint_fast16_t ui16WriteBatchSize,
+ uint8_t *pui8ReadData,
+ uint_fast16_t ui16ReadCount,
+ uint_fast16_t ui16ReadBatchSize,
+ tSensorCallback pfnCallback,
+ void *pvCallbackData);
+
+//*****************************************************************************
+//
+//! Performs a read-modify-write of 16 bits of big-endian data in an I2C
+//! device.
+//!
+//! \param psInst is a pointer to the read-modify-write instance data.
+//! \param psI2CInst is a pointer to the I2C master instance data.
+//! \param ui8Addr is the address of the I2C device to access.
+//! \param ui8Reg is the register in the I2C device to access.
+//! \param ui16Mask is the mask indicating the register bits that should be
+//! maintained.
+//! \param ui16Value is the value indicating the new value for the register
+//! bits that are not maintained.
+//! \param pfnCallback is the function to be called when the write has
+//! completed (can be \b NULL if a callback is not required).
+//! \param pvCallbackData is a pointer that is passed to the callback function.
+//!
+//! This function initiates a read-modify-write transaction of 16 bits of
+//! big-endian data in an I2C device. The modify portion of the operation is
+//! performed by AND-ing the register value with \e ui16Mask and then OR-ing
+//! the result with \e ui16Value. When the read-modify-write is complete, the
+//! callback function, if provided, is called in the context of the I2C master
+//! interrupt handler.
+//!
+//! If the mask (in \e ui16Mask) is zero, then none of the bits in the current
+//! register value are maintained. In this case, the read portion of the
+//! read-modify-write is bypassed, and the new register value (in \e ui16Value)
+//! is directly written to the I2C device.
+//!
+//! \return Returns 1 if the command was successfully added to the queue and 0
+//! if it was not.
+//
+// The extern here provides a non-inline definition for this function to handle
+// the case where the compiler chooses not to inline the function (which is a
+// valid choice for the compiler to make).
+//
+//*****************************************************************************
+extern uint_fast8_t I2CMReadModifyWrite16BE(tI2CMReadModifyWrite16 *psInst,
+ tI2CMInstance *psI2CInst,
+ uint_fast8_t ui8Addr,
+ uint_fast8_t ui8Reg,
+ uint_fast16_t ui16Mask,
+ uint_fast16_t ui16Value,
+ tSensorCallback *pfnCallback,
+ void *pvCallbackData);
+
+//*****************************************************************************
+//
+// This function handles the idle state of the I2C master state machine.
+//
+//*****************************************************************************
+static void
+I2CMStateIdle(tI2CMInstance *psInst, tI2CMCommand *pCommand)
+{
+ //
+ // Do nothing if there is not another transfer in the queue.
+ //
+ if(psInst->ui8ReadPtr == psInst->ui8WritePtr)
+ {
+ return;
+ }
+
+ //
+ // See if there is any data to be written.
+ //
+ if(pCommand->ui16WriteCount != 0)
+ {
+ //
+ // Set the slave address and indicate a write.
+ //
+ MAP_I2CMasterSlaveAddrSet(psInst->ui32Base, pCommand->ui8Addr, false);
+
+ //
+ // Place the first data byte to be written in the data register.
+ //
+ MAP_I2CMasterDataPut(psInst->ui32Base, pCommand->pui8WriteData[0]);
+
+ //
+ // See if there is just a single byte to be written and no bytes to be
+ // read.
+ //
+ if((pCommand->ui16WriteCount == 1) && (pCommand->ui16ReadCount == 0))
+ {
+ //
+ // Perform a single byte send.
+ //
+ MAP_I2CMasterControl(psInst->ui32Base, I2C_MASTER_CMD_SINGLE_SEND);
+
+ //
+ // The next state is the callback state.
+ //
+ psInst->ui8State = STATE_CALLBACK;
+ }
+
+ //
+ // Otherwise, see if there is just a single byte to be written and at
+ // least one byte to be read.
+ //
+ else if(pCommand->ui16WriteCount == 1)
+ {
+ //
+ // Perform a single send, writing the first byte as the only byte.
+ //
+ MAP_I2CMasterControl(psInst->ui32Base,
+ I2C_MASTER_CMD_BURST_SEND_START);
+
+ //
+ // Set the next state of the interrupt state machine based on the
+ // number of bytes to read.
+ //
+ psInst->ui8State = ((pCommand->ui16ReadCount == 1) ?
+ STATE_READ_ONE : STATE_READ_FIRST);
+ }
+
+ //
+ // Otherwise, there is more than one byte to be written.
+ //
+ else
+ {
+ //
+ // Start the burst cycle, writing the first byte.
+ //
+ MAP_I2CMasterControl(psInst->ui32Base,
+ I2C_MASTER_CMD_BURST_SEND_START);
+
+ //
+ // Set the index to indicate that the first byte has been
+ // transmitted.
+ //
+ psInst->ui16Index = 1;
+
+ //
+ // Set the next state of the interrupt state machine based on the
+ // number of bytes to write.
+ //
+ psInst->ui8State = ((pCommand->ui16WriteCount != 2) ?
+ STATE_WRITE_NEXT : STATE_WRITE_FINAL);
+ }
+ }
+ else
+ {
+ //
+ // Set the slave address and indicate a read.
+ //
+ MAP_I2CMasterSlaveAddrSet(psInst->ui32Base, pCommand->ui8Addr, true);
+
+ //
+ // Set the index to indicate that the first byte is being read.
+ //
+ psInst->ui16Index = 0;
+
+ //
+ // See if there is just a single byte to be read.
+ //
+ if(pCommand->ui16ReadCount == 1)
+ {
+ //
+ // Perform a single byte read.
+ //
+ MAP_I2CMasterControl(psInst->ui32Base,
+ I2C_MASTER_CMD_SINGLE_RECEIVE);
+
+ //
+ // The next state is the wait for final read state.
+ //
+ psInst->ui8State = STATE_READ_WAIT;
+ }
+ else
+ {
+ //
+ // Start the burst receive.
+ //
+ MAP_I2CMasterControl(psInst->ui32Base,
+ I2C_MASTER_CMD_BURST_RECEIVE_START);
+
+ //
+ // Set the next state appropriately. If the read count is two, the
+ // next state must finish the transaction. If it is greater than
+ // two, the burst read must be continued.
+ //
+ psInst->ui8State = ((pCommand->ui16ReadCount == 2) ?
+ STATE_READ_FINAL : STATE_READ_NEXT);
+ }
+ }
+}
+
+//*****************************************************************************
+//
+// This function handles the write next state of the I2C master state machine.
+//
+//*****************************************************************************
+static void
+I2CMStateWriteNext(tI2CMInstance *psInst, tI2CMCommand *pCommand)
+{
+ //
+ // See if the write batch has been sent.
+ //
+ if(psInst->ui16Index == pCommand->ui16WriteBatchSize)
+ {
+ //
+ // Move to the write pause state.
+ //
+ psInst->ui8State = STATE_WRITE_PAUSE;
+
+ //
+ // Call the callback function.
+ //
+ if(pCommand->pfnCallback)
+ {
+ pCommand->pfnCallback(pCommand->pvCallbackData,
+ I2CM_STATUS_BATCH_DONE);
+ }
+ }
+ else
+ {
+ //
+ // Write the next byte to the data register.
+ //
+ MAP_I2CMasterDataPut(psInst->ui32Base,
+ pCommand->pui8WriteData[psInst->ui16Index]);
+ psInst->ui16Index++;
+
+ //
+ // Continue the burst write.
+ //
+ MAP_I2CMasterControl(psInst->ui32Base, I2C_MASTER_CMD_BURST_SEND_CONT);
+
+ //
+ // If there is one byte left, set the next state to the final write
+ // state.
+ //
+ if((pCommand->ui16WriteCount - psInst->ui16Index) == 1)
+ {
+ psInst->ui8State = STATE_WRITE_FINAL;
+ }
+ }
+}
+
+//*****************************************************************************
+//
+// This function handles the write final state of the I2C master state machine.
+//
+//*****************************************************************************
+static void
+I2CMStateWriteFinal(tI2CMInstance *psInst, tI2CMCommand *pCommand)
+{
+ //
+ // See if the write batch has been sent.
+ //
+ if(psInst->ui16Index == pCommand->ui16WriteBatchSize)
+ {
+ //
+ // Move to the write pause state.
+ //
+ psInst->ui8State = STATE_WRITE_PAUSE;
+
+ //
+ // Call the callback function.
+ //
+ if(pCommand->pfnCallback)
+ {
+ pCommand->pfnCallback(pCommand->pvCallbackData,
+ I2CM_STATUS_BATCH_DONE);
+ }
+ }
+ else
+ {
+ //
+ // Write the final byte to the data register.
+ //
+ MAP_I2CMasterDataPut(psInst->ui32Base,
+ pCommand->pui8WriteData[psInst->ui16Index]);
+
+ //
+ // See if there is data to be read after this byte is written.
+ //
+ if(pCommand->ui16ReadCount == 0)
+ {
+ //
+ // Finish the burst write.
+ //
+ MAP_I2CMasterControl(psInst->ui32Base,
+ I2C_MASTER_CMD_BURST_SEND_FINISH);
+
+ //
+ // The next state is the callback state.
+ //
+ psInst->ui8State = STATE_CALLBACK;
+ }
+ else
+ {
+ //
+ // Finish the burst write.
+ //
+ MAP_I2CMasterControl(psInst->ui32Base,
+ I2C_MASTER_CMD_BURST_SEND_CONT);
+
+ //
+ // Set the next state of the interrupt state machine based on the
+ // number of bytes to read.
+ //
+ psInst->ui8State = ((pCommand->ui16ReadCount == 1) ?
+ STATE_READ_ONE : STATE_READ_FIRST);
+ }
+ }
+}
+
+//*****************************************************************************
+//
+// This function handles the write pause state of the I2C master state machine.
+//
+//*****************************************************************************
+static void
+I2CMStateWritePause(tI2CMInstance *psInst, tI2CMCommand *pCommand)
+{
+ //
+ // Decrement the write count by the batch size.
+ //
+ pCommand->ui16WriteCount -= pCommand->ui16WriteBatchSize;
+
+ //
+ // Write the next byte to the data register.
+ //
+ MAP_I2CMasterDataPut(psInst->ui32Base, pCommand->pui8WriteData[0]);
+
+ //
+ // Set the index to indicate that the first byte has been transmitted.
+ //
+ psInst->ui16Index = 1;
+
+ //
+ // See if there is more than one byte left to be written.
+ //
+ if((pCommand->ui16WriteCount - psInst->ui16Index) == 0)
+ {
+ //
+ // See if there is data to be read after this byte is written.
+ //
+ if(pCommand->ui16ReadCount == 0)
+ {
+ //
+ // Finish the burst write.
+ //
+ MAP_I2CMasterControl(psInst->ui32Base,
+ I2C_MASTER_CMD_BURST_SEND_FINISH);
+
+ //
+ // The next state is the callback state.
+ //
+ psInst->ui8State = STATE_CALLBACK;
+ }
+ else
+ {
+ //
+ // Finish the burst write.
+ //
+ MAP_I2CMasterControl(psInst->ui32Base,
+ I2C_MASTER_CMD_BURST_SEND_CONT);
+
+ //
+ // Set the next state of the interrupt state machine based on the
+ // number of bytes to read.
+ //
+ psInst->ui8State = ((pCommand->ui16ReadCount == 1) ?
+ STATE_READ_ONE : STATE_READ_FIRST);
+ }
+ }
+ else
+ {
+ //
+ // Continue the burst write.
+ //
+ MAP_I2CMasterControl(psInst->ui32Base, I2C_MASTER_CMD_BURST_SEND_CONT);
+
+ //
+ // The next state is the write next state.
+ //
+ if((pCommand->ui16WriteCount - psInst->ui16Index) == 1)
+ {
+ psInst->ui8State = STATE_WRITE_FINAL;
+ }
+ else
+ {
+ psInst->ui8State = STATE_WRITE_NEXT;
+ }
+ }
+}
+
+//*****************************************************************************
+//
+// This function handles the read one state of the I2C master state machine.
+//
+//*****************************************************************************
+static void
+I2CMStateReadOne(tI2CMInstance *psInst, tI2CMCommand *pCommand)
+{
+ //
+ // Put the I2C master into receive mode.
+ //
+ MAP_I2CMasterSlaveAddrSet(psInst->ui32Base, pCommand->ui8Addr, true);
+
+ //
+ // Perform a single byte read.
+ //
+ MAP_I2CMasterControl(psInst->ui32Base, I2C_MASTER_CMD_SINGLE_RECEIVE);
+
+ //
+ // Set the index to indicate that the first byte is being read.
+ //
+ psInst->ui16Index = 0;
+
+ //
+ // The next state is the wait for final read state.
+ //
+ psInst->ui8State = STATE_READ_WAIT;
+}
+
+//*****************************************************************************
+//
+// This function handles the read first state of the I2C master state machine.
+//
+//*****************************************************************************
+static void
+I2CMStateReadFirst(tI2CMInstance *psInst, tI2CMCommand *pCommand)
+{
+ //
+ // Put the I2C master into receive mode.
+ //
+ MAP_I2CMasterSlaveAddrSet(psInst->ui32Base, pCommand->ui8Addr, true);
+
+ //
+ // Start the burst receive.
+ //
+ MAP_I2CMasterControl(psInst->ui32Base, I2C_MASTER_CMD_BURST_RECEIVE_START);
+
+ //
+ // Set the index to indicate that the first byte is being read.
+ //
+ psInst->ui16Index = 0;
+
+ //
+ // Set the next state appropriately. If the count is greater than two it
+ // is the middle of the burst read. If exactly two, the next state must
+ // finish the transaction.
+ //
+ psInst->ui8State = ((pCommand->ui16ReadCount == 2) ?
+ STATE_READ_FINAL : STATE_READ_NEXT);
+}
+
+//*****************************************************************************
+//
+// This function handles the read next state of the I2C master state machine.
+//
+//*****************************************************************************
+static void
+I2CMStateReadNext(tI2CMInstance *psInst, tI2CMCommand *pCommand)
+{
+ //
+ // Read the received character.
+ //
+ pCommand->pui8ReadData[psInst->ui16Index] =
+ MAP_I2CMasterDataGet(psInst->ui32Base);
+ psInst->ui16Index++;
+
+ //
+ // See if the read batch has been filled.
+ //
+ if(psInst->ui16Index == pCommand->ui16ReadBatchSize)
+ {
+ //
+ // Move to the read pause state.
+ //
+ psInst->ui8State = STATE_READ_PAUSE;
+
+ //
+ // Call the callback function.
+ //
+ if(pCommand->pfnCallback)
+ {
+ pCommand->pfnCallback(pCommand->pvCallbackData,
+ I2CM_STATUS_BATCH_READY);
+ }
+ }
+ else
+ {
+ //
+ // Continue the burst read.
+ //
+ MAP_I2CMasterControl(psInst->ui32Base,
+ I2C_MASTER_CMD_BURST_RECEIVE_CONT);
+
+ //
+ // If there are two characters left to be read, make the next state be
+ // the end of burst read state.
+ //
+ if((pCommand->ui16ReadCount - psInst->ui16Index) == 2)
+ {
+ psInst->ui8State = STATE_READ_FINAL;
+ }
+ }
+}
+
+//*****************************************************************************
+//
+// This function handles the read final state of the I2C master state machine.
+//
+//*****************************************************************************
+static void
+I2CMStateReadFinal(tI2CMInstance *psInst, tI2CMCommand *pCommand)
+{
+ //
+ // Read the received character.
+ //
+ pCommand->pui8ReadData[psInst->ui16Index] =
+ MAP_I2CMasterDataGet(psInst->ui32Base);
+ psInst->ui16Index++;
+
+ //
+ // See if the read batch has been filled.
+ //
+ if(psInst->ui16Index == pCommand->ui16ReadBatchSize)
+ {
+ //
+ // Move to the read pause state.
+ //
+ psInst->ui8State = STATE_READ_PAUSE;
+
+ //
+ // Call the callback function.
+ //
+ if(pCommand->pfnCallback)
+ {
+ pCommand->pfnCallback(pCommand->pvCallbackData,
+ I2CM_STATUS_BATCH_READY);
+ }
+ }
+ else
+ {
+ //
+ // Finish the burst read.
+ //
+ MAP_I2CMasterControl(psInst->ui32Base,
+ I2C_MASTER_CMD_BURST_RECEIVE_FINISH);
+
+ //
+ // The next state is the wait for final read state.
+ //
+ psInst->ui8State = STATE_READ_WAIT;
+ }
+}
+
+//*****************************************************************************
+//
+// This function handles the read pause state of the I2C master state machine.
+//
+//*****************************************************************************
+static void
+I2CMStateReadPause(tI2CMInstance *psInst, tI2CMCommand *pCommand)
+{
+ //
+ // Decrement the read count by the batch size.
+ //
+ pCommand->ui16ReadCount -= pCommand->ui16ReadBatchSize;
+
+ //
+ // Reset the read index.
+ //
+ psInst->ui16Index = 0;
+
+ //
+ // See if there is more than one byte left to be read.
+ //
+ if((pCommand->ui16ReadCount - psInst->ui16Index) == 1)
+ {
+ //
+ // Finish the burst read.
+ //
+ MAP_I2CMasterControl(psInst->ui32Base,
+ I2C_MASTER_CMD_BURST_RECEIVE_FINISH);
+
+ //
+ // The next state is the wait for final read state.
+ //
+ psInst->ui8State = STATE_READ_WAIT;
+ }
+ else
+ {
+ //
+ // Continue the burst read.
+ //
+ MAP_I2CMasterControl(psInst->ui32Base,
+ I2C_MASTER_CMD_BURST_RECEIVE_CONT);
+
+ //
+ // Determine the next state based on the number of bytes left to read.
+ //
+ if((pCommand->ui16ReadCount - psInst->ui16Index) == 2)
+ {
+ psInst->ui8State = STATE_READ_FINAL;
+ }
+ else
+ {
+ psInst->ui8State = STATE_READ_NEXT;
+ }
+ }
+}
+
+//*****************************************************************************
+//
+// This function handles the read wait state of the I2C master state machine.
+//
+//*****************************************************************************
+static void
+I2CMStateReadWait(tI2CMInstance *psInst, tI2CMCommand *pCommand)
+{
+ //
+ // Read the received character.
+ //
+ pCommand->pui8ReadData[psInst->ui16Index] =
+ MAP_I2CMasterDataGet(psInst->ui32Base);
+
+ //
+ // The state machine is now in the callback state.
+ //
+ psInst->ui8State = STATE_CALLBACK;
+}
+
+//*****************************************************************************
+//
+// This function handles the callback state of the I2C master state machine.
+//
+//*****************************************************************************
+static void
+I2CMStateCallback(tI2CMInstance *psInst, tI2CMCommand *pCommand,
+ uint32_t ui32Status)
+{
+ tSensorCallback *pfnCallback;
+ void *pvCallbackData;
+
+ //
+ // Save the callback information.
+ //
+ pfnCallback = pCommand->pfnCallback;
+ pvCallbackData = pCommand->pvCallbackData;
+
+ //
+ // This command has been completed, so increment the read pointer.
+ //
+ psInst->ui8ReadPtr++;
+ if(psInst->ui8ReadPtr == NUM_I2CM_COMMANDS)
+ {
+ psInst->ui8ReadPtr = 0;
+ }
+
+ //
+ // If there is a callback function then call it now.
+ //
+ if(pfnCallback)
+ {
+ //
+ // Convert the status from the I2C driver into the I2C master
+ // driver status.
+ //
+ if((ui32Status & (I2C_MCS_ARBLST | I2C_MCS_ERROR)) == 0)
+ {
+ ui32Status = I2CM_STATUS_SUCCESS;
+ }
+ else if(ui32Status & I2C_MCS_ARBLST)
+ {
+ ui32Status = I2CM_STATUS_ARB_LOST;
+ }
+ else if(ui32Status & I2C_MCS_ADRACK)
+ {
+ ui32Status = I2CM_STATUS_ADDR_NACK;
+ }
+ else if(ui32Status & I2C_MCS_DATACK)
+ {
+ ui32Status = I2CM_STATUS_DATA_NACK;
+ }
+ else
+ {
+ ui32Status = I2CM_STATUS_ERROR;
+ }
+
+ //
+ // Call the callback function.
+ //
+ pfnCallback(pvCallbackData, ui32Status);
+ }
+
+ //
+ // The state machine is now idle.
+ //
+ psInst->ui8State = STATE_IDLE;
+}
+
+//*****************************************************************************
+//
+//! Handles I2C master interrupts.
+//!
+//! \param psInst is a pointer to the I2C master instance data.
+//!
+//! This function performs the processing required in response to an I2C
+//! interrupt. The application-supplied interrupt handler should call this
+//! function with the correct instance data in response to the I2C interrupt.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+I2CMIntHandler(tI2CMInstance *psInst)
+{
+ tI2CMCommand *pCommand;
+ uint32_t ui32Status;
+
+ //
+ // Clear the I2C interrupt.
+ //
+ MAP_I2CMasterIntClear(psInst->ui32Base);
+ ui32Status = HWREG(psInst->ui32Base + I2C_O_MCS);
+
+ //
+ // Get a pointer to the current command.
+ //
+ pCommand = &(psInst->pCommands[psInst->ui8ReadPtr]);
+
+ //
+ // See if an error occurred during the last transaction.
+ //
+ if((ui32Status & (I2C_MCS_ERROR | I2C_MCS_ARBLST)) &&
+ (psInst->ui8State != STATE_IDLE))
+ {
+ //
+ // An error occurred, so halt the I2C transaction. The error stop
+ // command for send and receive is identical, so it does not matter
+ // which one is used here. Only issue the stop if the bus is busy.
+ //
+ if(ui32Status & I2C_MCS_BUSBSY)
+ {
+ MAP_I2CMasterControl(psInst->ui32Base,
+ I2C_MASTER_CMD_BURST_SEND_ERROR_STOP);
+ }
+
+ //
+ // Move to the callback state.
+ //
+ psInst->ui8State = STATE_CALLBACK;
+ }
+
+ //
+ // Loop forever. Most states will return when they have completed their
+ // action. However, a few states require multi-state processing, so those
+ // states will break and this loop repeated.
+ //
+ while(1)
+ {
+ //
+ // Determine what to do based on the current state.
+ //
+ switch(psInst->ui8State)
+ {
+ //
+ // The idle state.
+ //
+ case STATE_IDLE:
+ {
+ //
+ // Handle the idle state.
+ //
+ I2CMStateIdle(psInst, pCommand);
+
+ //
+ // This state is done and the next state should be handled at
+ // the next interrupt.
+ //
+ return;
+ }
+
+ //
+ // The state for the middle of a burst write.
+ //
+ case STATE_WRITE_NEXT:
+ {
+ //
+ // Handle the write next state.
+ //
+ I2CMStateWriteNext(psInst, pCommand);
+
+ //
+ // This state is done and the next state should be handled at
+ // the next interrupt.
+ //
+ return;
+ }
+
+ //
+ // The state for the final write of a burst sequence.
+ //
+ case STATE_WRITE_FINAL:
+ {
+ //
+ // Handle the write final state.
+ //
+ I2CMStateWriteFinal(psInst, pCommand);
+
+ //
+ // This state is done and the next state should be handled at
+ // the next interrupt.
+ //
+ return;
+ }
+
+ //
+ // The state for a paused write.
+ //
+ case STATE_WRITE_PAUSE:
+ {
+ //
+ // Handle the write pause state.
+ //
+ I2CMStateWritePause(psInst, pCommand);
+
+ //
+ // This state is done and the next state should be handled at
+ // the next interrupt.
+ //
+ return;
+ }
+
+ //
+ // The state for a single byte read.
+ //
+ case STATE_READ_ONE:
+ {
+ //
+ // Handle the read one state.
+ //
+ I2CMStateReadOne(psInst, pCommand);
+
+ //
+ // This state is done and the next state should be handled at
+ // the next interrupt.
+ //
+ return;
+ }
+
+ //
+ // The state for the start of a burst read.
+ //
+ case STATE_READ_FIRST:
+ {
+ //
+ // Handle the read first state.
+ //
+ I2CMStateReadFirst(psInst, pCommand);
+
+ //
+ // This state is done and the next state should be handled at
+ // the next interrupt.
+ //
+ return;
+ }
+
+ //
+ // The state for the middle of a burst read.
+ //
+ case STATE_READ_NEXT:
+ {
+ //
+ // Handle the read next state.
+ //
+ I2CMStateReadNext(psInst, pCommand);
+
+ //
+ // This state is done and the next state should be handled at
+ // the next interrupt.
+ //
+ return;
+ }
+
+ //
+ // The state for the end of a burst read.
+ //
+ case STATE_READ_FINAL:
+ {
+ //
+ // Handle the read final state.
+ //
+ I2CMStateReadFinal(psInst, pCommand);
+
+ //
+ // This state is done and the next state should be handled at
+ // the next interrupt.
+ //
+ return;
+ }
+
+ //
+ // The state for a paused read.
+ //
+ case STATE_READ_PAUSE:
+ {
+ //
+ // Handle the read pause state.
+ //
+ I2CMStateReadPause(psInst, pCommand);
+
+ //
+ // This state is done and the next state should be handled at
+ // the next interrupt.
+ //
+ return;
+ }
+
+ //
+ // This state is for the final read of a single or burst read.
+ //
+ case STATE_READ_WAIT:
+ {
+ //
+ // Handle the read wait state.
+ //
+ I2CMStateReadWait(psInst, pCommand);
+
+ //
+ // This state is done and the next state needs to be handled
+ // immediately.
+ //
+ break;
+ }
+
+ //
+ // This state is for providing the transaction complete callback.
+ //
+ case STATE_CALLBACK:
+ {
+ //
+ // Handle the callback state.
+ //
+ I2CMStateCallback(psInst, pCommand, ui32Status);
+
+ //
+ // If an error occurred, this state is done. The completion of
+ // the error handling stop condition above, if issued, will
+ // cause the next state to be processed.
+ //
+ if((ui32Status & (I2C_MCS_ERROR | I2C_MCS_ARBLST)) &&
+ (ui32Status & I2C_MCS_BUSBSY))
+ {
+ return;
+ }
+
+ //
+ // Update the pointer to the current command.
+ //
+ pCommand = &(psInst->pCommands[psInst->ui8ReadPtr]);
+
+ //
+ // This state is done and the next state needs to be handled
+ // immediately.
+ //
+ break;
+ }
+ }
+ }
+}
+
+//*****************************************************************************
+//
+//! Initializes the I2C master driver.
+//!
+//! \param psInst is a pointer to the I2C master instance data.
+//! \param ui32Base is the base address of the I2C module.
+//! \param ui8Int is the interrupt number for the I2C module.
+//! \param ui8TxDMA is the uDMA channel number used for transmitting data to
+//! the I2C module.
+//! \param ui8RxDMA is the uDMA channel number used for receiving data from
+//! the I2C module.
+//! \param ui32Clock is the clock frequency of the input clock to the I2C
+//! module.
+//!
+//! This function prepares both the I2C master module and driver for operation,
+//! and must be the first I2C master driver function called for each I2C master
+//! instance. It is assumed that the application has enabled the I2C module,
+//! configured the I2C pins, and provided an I2C interrupt handler that calls
+//! I2CMIntHandler().
+//!
+//! The uDMA module cannot be used at present to transmit/receive data, so the
+//! \e ui8TxDMA and \e ui8RxDMA parameters are unused. They are reserved for
+//! future use and should be set to 0xff in order to ensure future
+//! compatibility.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+I2CMInit(tI2CMInstance *psInst, uint32_t ui32Base, uint_fast8_t ui8Int,
+ uint_fast8_t ui8TxDMA, uint_fast8_t ui8RxDMA, uint32_t ui32Clock)
+{
+ //
+ // Check the arguments.
+ //
+ ASSERT(psInst);
+ ASSERT((ui32Base == I2C0_BASE) || (ui32Base == I2C1_BASE) ||
+ (ui32Base == I2C2_BASE) || (ui32Base == I2C3_BASE) ||
+ (ui32Base == I2C4_BASE) || (ui32Base == I2C5_BASE) ||
+ (ui32Base == I2C6_BASE) || (ui32Base == I2C7_BASE) ||
+ (ui32Base == I2C8_BASE) || (ui32Base == I2C9_BASE));
+ ASSERT(ui8Int);
+ ASSERT(ui32Clock);
+
+ //
+ // Initialize the state structure.
+ //
+ psInst->ui32Base = ui32Base;
+ psInst->ui8Int = ui8Int;
+ psInst->ui8TxDMA = ui8TxDMA;
+ psInst->ui8RxDMA = ui8RxDMA;
+ psInst->ui8State = STATE_IDLE;
+ psInst->ui8ReadPtr = 0;
+ psInst->ui8WritePtr = 0;
+
+ //
+ // Initialize the I2C master module.
+ //
+ MAP_I2CMasterInitExpClk(ui32Base, ui32Clock, true);
+
+ //
+ // Enable the I2C interrupt.
+ //
+ MAP_IntEnable(ui8Int);
+ MAP_I2CMasterIntEnableEx(ui32Base, I2C_MASTER_INT_DATA);
+}
+
+//*****************************************************************************
+//
+//! Sends a command to an I2C device.
+//!
+//! \param psInst is a pointer to the I2C master instance data.
+//! \param ui8Addr is the address of the I2C device to access.
+//! \param pui8WriteData is a pointer to the data buffer to be written.
+//! \param ui16WriteCount is the number of bytes to be written.
+//! \param ui16WriteBatchSize is the number of bytes in each write batch.
+//! \param pui8ReadData is a pointer to the buffer to be filled with the read
+//! data.
+//! \param ui16ReadCount is the number of bytes to be read.
+//! \param ui16ReadBatchSize is the number of bytes to be read in each batch.
+//! \param pfnCallback is the function to be called when the transfer has
+//! completed (can be \b NULL if a callback is not required).
+//! \param pvCallbackData is a pointer that is passed to the callback function.
+//!
+//! This function adds an I2C command to the queue of commands to be sent. If
+//! successful, the I2C command is then transferred in the background using the
+//! interrupt handler. When the transfer is complete, the callback function,
+//! if provided, is called in the context of the I2C master interrupt handler.
+//!
+//! The first byte of \e pui8WriteData contains the I2C address of the device
+//! to access, the next \e ui16WriteCount bytes contains the data to be written
+//! to the device. The data read from the device is written into the first
+//! \e ui16ReadCount bytes of \e pui8ReadData. The \e ui16WriteCount or
+//! \e ui16ReadCount parameters can be zero if there are no bytes to be read or
+//! written. The write bytes are sent to the device first, and then the read
+//! bytes are read from the device afterward.
+//!
+//! If \e ui16WriteBatchSize is less than \e ui16WriteCount, the write portion
+//! of the transfer is broken up into as many \e ui16WriteBatchSize batches as
+//! required to write \e ui16WriteCount bytes. After each batch, the callback
+//! function is called with an \b I2CM_STATUS_BATCH_DONE status, and the
+//! transfer is paused (with the I2C bus held). The transfer is resumed when
+//! I2CMTransferResume() is called. This procedure can be used to perform very
+//! large writes without requiring all the data be available at once, at the
+//! expense of tying up the I2C bus for the extended duration of the transfer.
+//!
+//! If \e ui16ReadBatchSize is less than \e ui16ReadCount, the read portion of
+//! the transfer is broken up into as many \e ui16ReadBatchSize batches as
+//! required to read \e ui16ReadCount bytes. After each batch, the callback
+//! function is called with an \b I2CM_STATUS_BATCH_READY status, and the
+//! transfer is paused (with the I2C bus held). The transfer is resumed when
+//! I2CMTransferResume() is called. This procedure can be used to perform very
+//! large reads without requiring a large SRAM buffer, at the expense of tying
+//! up the I2C bus for the extended duration of the transfer.
+//!
+//! \return Returns 1 if the command was successfully added to the queue and 0
+//! if it was not.
+//
+//*****************************************************************************
+uint_fast8_t
+I2CMCommand(tI2CMInstance *psInst, uint_fast8_t ui8Addr,
+ const uint8_t *pui8WriteData, uint_fast16_t ui16WriteCount,
+ uint_fast16_t ui16WriteBatchSize, uint8_t *pui8ReadData,
+ uint_fast16_t ui16ReadCount, uint_fast16_t ui16ReadBatchSize,
+ tSensorCallback *pfnCallback, void *pvCallbackData)
+{
+ uint_fast8_t ui8Next, ui8Enabled;
+ tI2CMCommand *pCommand;
+
+ //
+ // Check the arguments.
+ //
+ ASSERT(psInst);
+ ASSERT(pui8WriteData || !ui16WriteCount);
+ ASSERT(!ui16WriteCount || (ui16WriteBatchSize > 0));
+ ASSERT(pui8ReadData || !ui16ReadCount);
+ ASSERT(!ui16ReadCount || (ui16ReadBatchSize > 0));
+
+ //
+ // Disable the I2C interrupt.
+ //
+ if(MAP_IntIsEnabled(psInst->ui8Int))
+ {
+ ui8Enabled = 1;
+ MAP_IntDisable(psInst->ui8Int);
+ }
+ else
+ {
+ ui8Enabled = 0;
+ }
+
+ //
+ // Compute the new value of the write pointer (after this command is added
+ // to the queue).
+ //
+ ui8Next = psInst->ui8WritePtr + 1;
+ if(ui8Next == NUM_I2CM_COMMANDS)
+ {
+ ui8Next = 0;
+ }
+
+ //
+ // Return a failure if the command queue is full.
+ //
+ if(psInst->ui8ReadPtr == ui8Next)
+ {
+ if(ui8Enabled)
+ {
+ MAP_IntEnable(psInst->ui8Int);
+ }
+ return(0);
+ }
+
+ //
+ // Get a pointer to the command structure.
+ //
+ pCommand = &(psInst->pCommands[psInst->ui8WritePtr]);
+
+ //
+ // Fill in the command structure with the details of this command.
+ //
+ pCommand->ui8Addr = ui8Addr;
+ pCommand->pui8WriteData = pui8WriteData;
+ pCommand->ui16WriteCount = ui16WriteCount;
+ pCommand->ui16WriteBatchSize = ui16WriteBatchSize;
+ pCommand->pui8ReadData = pui8ReadData;
+ pCommand->ui16ReadCount = ui16ReadCount;
+ pCommand->ui16ReadBatchSize = ui16ReadBatchSize;
+ pCommand->pfnCallback = pfnCallback;
+ pCommand->pvCallbackData = pvCallbackData;
+
+ //
+ // Update the write pointer.
+ //
+ psInst->ui8WritePtr = ui8Next;
+
+ //
+ // See if the state machine is idle.
+ //
+ if(psInst->ui8State == STATE_IDLE)
+ {
+ //
+ // Generate a fake I2C interrupt, which will commence the I2C transfer.
+ //
+ IntTrigger(psInst->ui8Int);
+ }
+
+ //
+ // Re-enable the I2C master interrupt.
+ //
+ if(ui8Enabled)
+ {
+ MAP_IntEnable(psInst->ui8Int);
+ }
+
+ //
+ // Success.
+ //
+ return(1);
+}
+
+//*****************************************************************************
+//
+//! Resumes an I2C transfer.
+//!
+//! \param psInst is a pointer to the I2C master instance data.
+//! \param pui8Data is a pointer to the buffer to be used for the next batch of
+//! data.
+//!
+//! This function resumes an I2C transfer that has been paused via the use of
+//! the write or read batch size capability.
+//!
+//! \return Returns 1 if the transfer was resumed and 0 if there was not a
+//! paused transfer to resume.
+//
+//*****************************************************************************
+uint_fast8_t
+I2CMTransferResume(tI2CMInstance *psInst, uint8_t *pui8Data)
+{
+ //
+ // Check the arguments.
+ //
+ ASSERT(psInst);
+ ASSERT(pui8Data);
+
+ //
+ // Return an error if there is not a paused transfer.
+ //
+ if((psInst->ui8State != STATE_WRITE_PAUSE) &&
+ (psInst->ui8State != STATE_READ_PAUSE))
+ {
+ return(0);
+ }
+
+ //
+ // Save the pointer for the next buffer.
+ //
+ if(psInst->ui8State == STATE_WRITE_PAUSE)
+ {
+ psInst->pCommands[psInst->ui8ReadPtr].pui8WriteData = pui8Data;
+ }
+ else
+ {
+ psInst->pCommands[psInst->ui8ReadPtr].pui8ReadData = pui8Data;
+ }
+
+ //
+ // Trigger the I2C interrupt, resuming the transfer.
+ //
+ IntTrigger(psInst->ui8Int);
+
+ //
+ // Success.
+ //
+ return(1);
+}
+
+//*****************************************************************************
+//
+// The callback function that is called when I2C transactions as part of of a
+// read-modify-write operation of 8 bits of data have completed.
+//
+//*****************************************************************************
+static void
+I2CMReadModifyWrite8Callback(void *pvCallbackData, uint_fast8_t ui8Status)
+{
+ tI2CMReadModifyWrite8 *psInst;
+
+ //
+ // Convert the instance data into a pointer to a tI2CMReadModifyWrite8
+ // structure.
+ //
+ psInst = pvCallbackData;
+
+ //
+ // If the I2C master driver encountered a failure, force the state machine
+ // to the idle state (which will also result ina callback to propagate the
+ // error).
+ //
+ if(ui8Status != I2CM_STATUS_SUCCESS)
+ {
+ psInst->ui8State = I2CM_RMW_STATE_IDLE;
+ }
+
+ //
+ // Determine the current state of the I2C master read-modify-write state
+ // machine.
+ //
+ switch(psInst->ui8State)
+ {
+ //
+ // The read portion of the read-modify-write has completed.
+ //
+ case I2CM_RMW_STATE_READ:
+ {
+ //
+ // Modify the register data that was just read.
+ //
+ psInst->pui8Buffer[1] = ((psInst->pui8Buffer[1] &
+ psInst->ui8Mask) | psInst->ui8Value);
+
+ //
+ // Write the data back to the device.
+ //
+ I2CMWrite(psInst->psI2CInst, psInst->ui8Addr, psInst->pui8Buffer,
+ 2, I2CMReadModifyWrite8Callback, psInst);
+
+ //
+ // Move to the wait for write state.
+ //
+ psInst->ui8State = I2CM_RMW_STATE_WRITE;
+
+ //
+ // Done.
+ //
+ break;
+ }
+
+ //
+ // The write portion of the read-modify-write has completed.
+ //
+ case I2CM_RMW_STATE_WRITE:
+ {
+ //
+ // Move to the idle state.
+ //
+ psInst->ui8State = I2CM_RMW_STATE_IDLE;
+
+ //
+ // Done.
+ //
+ break;
+ }
+ }
+
+ //
+ // See if the state machine is now idle and there is a callback function.
+ //
+ if((psInst->ui8State == I2CM_RMW_STATE_IDLE) && psInst->pfnCallback)
+ {
+ //
+ // Call the application-supplied callback function.
+ //
+ psInst->pfnCallback(psInst->pvCallbackData, ui8Status);
+ }
+}
+
+//*****************************************************************************
+//
+//! Performs a read-modify-write of 8 bits of data in an I2C device.
+//!
+//! \param psInst is a pointer to the read-modify-write instance data.
+//! \param psI2CInst is a pointer to the I2C master instance data.
+//! \param ui8Addr is the address of the I2C device to access.
+//! \param ui8Reg is the register in the I2C device to access.
+//! \param ui8Mask is the mask indicating the register bits that should be
+//! maintained.
+//! \param ui8Value is the value indicating the new value for the register bits
+//! that are not maintained.
+//! \param pfnCallback is the function to be called when the write has
+//! completed (can be \b NULL if a callback is not required).
+//! \param pvCallbackData is a pointer that is passed to the callback function.
+//!
+//! This function initiates a read-modify-write transaction of 8 bits of data
+//! in an I2C device. The modify portion of the operation is performed by
+//! AND-ing the register value with \e ui8Mask and then OR-ing the result with
+//! \e ui8Value. When the read-modify-write is complete, the callback
+//! function, if provided, is called in the context of the I2C master interrupt
+//! handler.
+//!
+//! If the mask (in \e ui8Mask) is zero, then none of the bits in the current
+//! register value are maintained. In this case, the read portion of the
+//! read-modify-write is bypassed, and the new register value (in \e ui8Value)
+//! is directly written to the I2C device.
+//!
+//! \return Returns 1 if the command was successfully added to the queue and 0
+//! if it was not.
+//
+//*****************************************************************************
+uint_fast8_t
+I2CMReadModifyWrite8(tI2CMReadModifyWrite8 *psInst, tI2CMInstance *psI2CInst,
+ uint_fast8_t ui8Addr, uint_fast8_t ui8Reg,
+ uint_fast8_t ui8Mask, uint_fast8_t ui8Value,
+ tSensorCallback *pfnCallback, void *pvCallbackData)
+{
+ //
+ // Check the arguments.
+ //
+ ASSERT(psInst);
+ ASSERT(psI2CInst);
+
+ //
+ // Fill in the read-modify-write structure with the details of this
+ // request.
+ //
+ psInst->psI2CInst = psI2CInst;
+ psInst->ui8Addr = ui8Addr;
+ psInst->ui8Mask = ui8Mask;
+ psInst->ui8Value = ui8Value;
+ psInst->pfnCallback = pfnCallback;
+ psInst->pvCallbackData = pvCallbackData;
+
+ //
+ // Construct the I2C command to access the requested register.
+ //
+ psInst->pui8Buffer[0] = ui8Reg;
+
+ //
+ // See if this is a write or a read-modify-write.
+ //
+ if(ui8Mask == 0)
+ {
+ //
+ // Set the state to waiting for the write portion of the
+ // read-modify-write.
+ //
+ psInst->ui8State = I2CM_RMW_STATE_WRITE;
+
+ //
+ // Set the new register value in the command buffer.
+ //
+ psInst->pui8Buffer[1] = ui8Value;
+
+ //
+ // Add the write command to the I2C master queue.
+ //
+ if(I2CMWrite(psI2CInst, ui8Addr, psInst->pui8Buffer, 2,
+ I2CMReadModifyWrite8Callback, psInst) == 0)
+ {
+ return(0);
+ }
+ }
+ else
+ {
+ //
+ // Set the state to waiting for the read portion of the
+ // read-modify-write.
+ //
+ psInst->ui8State = I2CM_RMW_STATE_READ;
+
+ //
+ // Add the read command to the I2C master queue.
+ //
+ if(I2CMRead(psI2CInst, ui8Addr, psInst->pui8Buffer, 1,
+ psInst->pui8Buffer + 1, 1, I2CMReadModifyWrite8Callback,
+ psInst) == 0)
+ {
+ return(0);
+ }
+ }
+
+ //
+ // Success.
+ //
+ return(1);
+}
+
+//*****************************************************************************
+//
+// The callback function that is called when I2C transactions as part of a
+// read-modify-write operation of 16 bits of little-endian data have completed.
+//
+//*****************************************************************************
+static void
+I2CMReadModifyWrite16LECallback(void *pvCallbackData, uint_fast8_t ui8Status)
+{
+ tI2CMReadModifyWrite16 *psInst;
+ uint16_t ui16Value;
+
+ //
+ // Convert the instance data into a pointer to a tI2CMReadModifyWrite16
+ // structure.
+ //
+ psInst = pvCallbackData;
+
+ //
+ // If the I2C master driver encountered a failure, force the state machine
+ // to the idle state (which will also result ina callback to propagate the
+ // error).
+ //
+ if(ui8Status != I2CM_STATUS_SUCCESS)
+ {
+ psInst->ui8State = I2CM_RMW_STATE_IDLE;
+ }
+
+ //
+ // Determine the current state of the I2C master read-modify-write state
+ // machine.
+ //
+ switch(psInst->ui8State)
+ {
+ //
+ // The read portion of the read-modify-write has completed.
+ //
+ case I2CM_RMW_STATE_READ:
+ {
+ //
+ // Modify the register data that was just read.
+ //
+ ui16Value = (psInst->pui8Buffer[2] << 8) | psInst->pui8Buffer[1];
+ ui16Value = (ui16Value & psInst->ui16Mask) | psInst->ui16Value;
+ psInst->pui8Buffer[1] = ui16Value & 0xff;
+ psInst->pui8Buffer[2] = (ui16Value >> 8) & 0xff;
+
+ //
+ // Write the data back to the device.
+ //
+ I2CMWrite(psInst->psI2CInst, psInst->ui8Addr, psInst->pui8Buffer,
+ 3, I2CMReadModifyWrite16LECallback, psInst);
+
+ //
+ // Move to the wait for write state.
+ //
+ psInst->ui8State = I2CM_RMW_STATE_WRITE;
+
+ //
+ // Done.
+ //
+ break;
+ }
+
+ //
+ // The write portion of the read-modify-write has completed.
+ //
+ case I2CM_RMW_STATE_WRITE:
+ {
+ //
+ // Move to the idle state.
+ //
+ psInst->ui8State = I2CM_RMW_STATE_IDLE;
+
+ //
+ // Done.
+ //
+ break;
+ }
+ }
+
+ //
+ // See if the state machine is now idle and there is a callback function.
+ //
+ if((psInst->ui8State == I2CM_RMW_STATE_IDLE) && psInst->pfnCallback)
+ {
+ //
+ // Call the application-supplied callback function.
+ //
+ psInst->pfnCallback(psInst->pvCallbackData, ui8Status);
+ }
+}
+
+//*****************************************************************************
+//
+//! Performs a read-modify-write of 16 bits of little-endian data in an I2C
+//! device.
+//!
+//! \param psInst is a pointer to the read-modify-write instance data.
+//! \param psI2CInst is a pointer to the I2C master instance data.
+//! \param ui8Addr is the address of the I2C device to access.
+//! \param ui8Reg is the register in the I2C device to access.
+//! \param ui16Mask is the mask indicating the register bits that should be
+//! maintained.
+//! \param ui16Value is the value indicating the new value for the register
+//! bits that are not maintained.
+//! \param pfnCallback is the function to be called when the write has
+//! completed (can be \b NULL if a callback is not required).
+//! \param pvCallbackData is a pointer that is passed to the callback function.
+//!
+//! This function initiates a read-modify-write transaction of 16 bits of
+//! little-endian data in an I2C device. The modify portion of the operation
+//! is performed by AND-ing the register value with \e ui16Mask and then OR-ing
+//! the result with \e ui16Value. When the read-modify-write is complete, the
+//! callback function, if provided, is called in the context of the I2C master
+//! interrupt handler.
+//!
+//! If the mask (in \e ui16Mask) is zero, then none of the bits in the current
+//! register value are maintained. In this case, the read portion of the
+//! read-modify-write is bypassed, and the new register value (in \e ui16Value)
+//! is directly written to the I2C device.
+//!
+//! \return Returns 1 if the command was successfully added to the queue and 0
+//! if it was not.
+//
+//*****************************************************************************
+uint_fast8_t
+I2CMReadModifyWrite16LE(tI2CMReadModifyWrite16 *psInst,
+ tI2CMInstance *psI2CInst, uint_fast8_t ui8Addr,
+ uint_fast8_t ui8Reg, uint_fast16_t ui16Mask,
+ uint_fast16_t ui16Value, tSensorCallback *pfnCallback,
+ void *pvCallbackData)
+{
+ //
+ // Check the arguments.
+ //
+ ASSERT(psInst);
+ ASSERT(psI2CInst);
+
+ //
+ // Fill in the read-modify-write structure with the details of this
+ // request.
+ //
+ psInst->psI2CInst = psI2CInst;
+ psInst->ui8Addr = ui8Addr;
+ psInst->ui16Mask = ui16Mask;
+ psInst->ui16Value = ui16Value;
+ psInst->pfnCallback = pfnCallback;
+ psInst->pvCallbackData = pvCallbackData;
+
+ //
+ // Construct the I2C command to access the requested register.
+ //
+ psInst->pui8Buffer[0] = ui8Reg;
+
+ //
+ // See if this is a write or a read-modify-write.
+ //
+ if(ui16Mask == 0)
+ {
+ //
+ // Set the state to waiting for the write portion of the
+ // read-modify-write.
+ //
+ psInst->ui8State = I2CM_RMW_STATE_WRITE;
+
+ //
+ // Set the new register value in the command buffer.
+ //
+ psInst->pui8Buffer[1] = ui16Value & 0xff;
+ psInst->pui8Buffer[2] = (ui16Value >> 8) & 0xff;
+
+ //
+ // Add the write command to the I2C master queue.
+ //
+ if(I2CMWrite(psI2CInst, ui8Addr, psInst->pui8Buffer, 3,
+ I2CMReadModifyWrite16LECallback, psInst) == 0)
+ {
+ return(0);
+ }
+ }
+ else
+ {
+ //
+ // Set the state to waiting for the read portion of the
+ // read-modify-write.
+ //
+ psInst->ui8State = I2CM_RMW_STATE_READ;
+
+ //
+ // Add the read command to the I2C master queue.
+ //
+ if(I2CMRead(psI2CInst, ui8Addr, psInst->pui8Buffer, 1,
+ psInst->pui8Buffer + 1, 2, I2CMReadModifyWrite16LECallback,
+ psInst) == 0)
+ {
+ return(0);
+ }
+ }
+
+ //
+ // Success.
+ //
+ return(1);
+}
+
+//*****************************************************************************
+//
+// The callback function that is called when I2C transactions as part of a
+// write operation of 8-bit data have completed.
+//
+//*****************************************************************************
+static void
+I2CMWrite8Callback(void *pvCallbackData, uint_fast8_t ui8Status)
+{
+ tI2CMWrite8 *psInst;
+
+ //
+ // Convert the instance data into a pointer to a tI2CMWrite8 structure.
+ //
+ psInst = pvCallbackData;
+
+ //
+ // See if the current batch is done and more data is needed.
+ //
+ if(ui8Status == I2CM_STATUS_BATCH_DONE)
+ {
+ //
+ // Place the next two bytes into the write buffer.
+ //
+ psInst->pui8Buffer[0] = psInst->pui8Data[0];
+ if(psInst->ui16Count > 1)
+ {
+ psInst->pui8Buffer[1] = psInst->pui8Data[1];
+ }
+
+ //
+ // Advance past the next two bytes of the input buffer.
+ //
+ psInst->pui8Data += 2;
+ psInst->ui16Count -= 2;
+
+ //
+ // Resume the batched write.
+ //
+ I2CMTransferResume(psInst->psI2CInst, psInst->pui8Buffer);
+ }
+
+ //
+ // The transfer has completed, or an error has occurred. In both cases,
+ // see if there is a callback function.
+ //
+ else if(psInst->pfnCallback)
+ {
+ //
+ // Call the application-supplied callback function.
+ //
+ psInst->pfnCallback(psInst->pvCallbackData, ui8Status);
+ }
+}
+
+//*****************************************************************************
+//
+//! Performs a write of 8-bit data to an I2C device.
+//!
+//! \param psInst is a pointer to the 8-bit write instance data.
+//! \param psI2CInst is a pointer to the I2C master instance data.
+//! \param ui8Addr is the address of the I2C device to access.
+//! \param ui8Reg is the register in the I2C device to access.
+//! \param pui8Data is a pointer to the register data to be written.
+//! \param ui16Count is the number of register values to be written.
+//! \param pfnCallback is the function to be called when the write has
+//! completed (can be \b NULL if a callback is not required).
+//! \param pvCallbackData is a pointer that is passed to the callback function.
+//!
+//! This function initiates a write transaction of 8-bit data to an I2C device.
+//!
+//! \return Returns 1 if the command was successfully added to the queue and 0
+//! if it was not.
+//
+//*****************************************************************************
+uint_fast8_t
+I2CMWrite8(tI2CMWrite8 *psInst, tI2CMInstance *psI2CInst, uint_fast8_t ui8Addr,
+ uint_fast8_t ui8Reg, const uint8_t *pui8Data,
+ uint_fast16_t ui16Count, tSensorCallback *pfnCallback,
+ void *pvCallbackData)
+{
+ //
+ // Check the arguments.
+ //
+ ASSERT(psInst);
+ ASSERT(psI2CInst);
+
+ //
+ // Fill in the write structure with the details of this request.
+ //
+ psInst->psI2CInst = psI2CInst;
+ psInst->pui8Data = pui8Data + 1;
+ psInst->ui16Count = ui16Count - 1;
+ psInst->pfnCallback = pfnCallback;
+ psInst->pvCallbackData = pvCallbackData;
+
+ //
+ // Initiate the I2C write to this device.
+ //
+ psInst->pui8Buffer[0] = ui8Reg;
+ psInst->pui8Buffer[1] = pui8Data[0];
+ if(I2CMWriteBatched(psI2CInst, ui8Addr, psInst->pui8Buffer, ui16Count + 1,
+ 2, I2CMWrite8Callback, psInst) == 0)
+ {
+ //
+ // The I2C write failed, so return a failure.
+ //
+ return(0);
+ }
+
+ //
+ // Success.
+ //
+ return(1);
+}
+
+//*****************************************************************************
+//
+// The callback function that is called when I2C transactions as part of a read
+// operation of 16-bit big-endian data have completed.
+//
+//*****************************************************************************
+static void
+I2CMRead16BECallback(void *pvCallbackData, uint_fast8_t ui8Status)
+{
+ tI2CMRead16BE *psInst;
+ uint8_t ui8Temp;
+
+ //
+ // Convert the instance data into a pointer to a tI2CMRead16BE structure.
+ //
+ psInst = pvCallbackData;
+
+ //
+ // See if the transaction completed successfully.
+ //
+ if(ui8Status == I2CM_STATUS_SUCCESS)
+ {
+ //
+ // Loop through the 16-bit values read from the I2C device.
+ //
+ while(psInst->ui16Count--)
+ {
+ //
+ // Byte swap this value.
+ //
+ ui8Temp = psInst->pui8Data[0];
+ psInst->pui8Data[0] = psInst->pui8Data[1];
+ psInst->pui8Data[1] = ui8Temp;
+
+ //
+ // Skip to the next value.
+ //
+ psInst->pui8Data += 2;
+ }
+ }
+
+ //
+ // See if there is a callback function.
+ //
+ if(psInst->pfnCallback)
+ {
+ //
+ // Call the application-supplied callback function.
+ //
+ psInst->pfnCallback(psInst->pvCallbackData, ui8Status);
+ }
+}
+
+//*****************************************************************************
+//
+//! Performs a read of 16-bit big-endian data from an I2C device.
+//!
+//! \param psInst is a pointer to the 16-bit big-endian read instance data.
+//! \param psI2CInst is a pointer to the I2C master instance data.
+//! \param ui8Addr is the address of the I2C device to access.
+//! \param ui8Reg is the register in the I2C device to access.
+//! \param pui16Data is a pointer to the buffer to be filled with the register
+//! data.
+//! \param ui16Count is the number of 16-bit register values to be read.
+//! \param pfnCallback is the function to be called when the read has
+//! completed (can be \b NULL if a callback is not required).
+//! \param pvCallbackData is a pointer that is passed to the callback function.
+//!
+//! This function initiates a read transaction of 16-bit big-endian data from
+//! an I2C device. The data is provided by the device in big-endian format and
+//! is byte-swapped as it is read from the I2C device, returning the data in
+//! little-endian format.
+//!
+//! \return Returns 1 if the command was successfully added to the queue and 0
+//! if it was not.
+//
+//*****************************************************************************
+uint_fast8_t
+I2CMRead16BE(tI2CMRead16BE *psInst, tI2CMInstance *psI2CInst,
+ uint_fast8_t ui8Addr, uint_fast8_t ui8Reg,
+ uint16_t *pui16Data, uint_fast16_t ui16Count,
+ tSensorCallback *pfnCallback, void *pvCallbackData)
+{
+ //
+ // Check the arguments.
+ //
+ ASSERT(psInst);
+ ASSERT(psI2CInst);
+
+ //
+ // Fill in the read structure with the details of this request.
+ //
+ psInst->psI2CInst = psI2CInst;
+ psInst->pui8Data = (uint8_t *)pui16Data;
+ psInst->ui16Count = ui16Count;
+ psInst->pfnCallback = pfnCallback;
+ psInst->pvCallbackData = pvCallbackData;
+
+ //
+ // Initiate the I2C write to this device.
+ //
+ psInst->pui8Data[0] = ui8Reg;
+ if(I2CMRead(psI2CInst, ui8Addr, psInst->pui8Data, 1, psInst->pui8Data,
+ ui16Count * 2, I2CMRead16BECallback, psInst) == 0)
+ {
+ //
+ // The I2C write failed, so return a failure.
+ //
+ return(0);
+ }
+
+ //
+ // Success.
+ //
+ return(1);
+}
+
+//*****************************************************************************
+//
+// The callback function that is called when I2C transactions as part of a
+// write operation of 16-bit big-endian data have completed.
+//
+//*****************************************************************************
+static void
+I2CMWrite16BECallback(void *pvCallbackData, uint_fast8_t ui8Status)
+{
+ tI2CMWrite16BE *psInst;
+
+ //
+ // Convert the instance data into a pointer to a tI2CMWrite16BE structure.
+ //
+ psInst = pvCallbackData;
+
+ //
+ // See if the current batch is done and more data is needed.
+ //
+ if(ui8Status == I2CM_STATUS_BATCH_DONE)
+ {
+ //
+ // Place the next two bytes into the write buffer.
+ //
+ psInst->pui8Buffer[0] = psInst->pui8Data[0];
+ if(psInst->ui16Count > 1)
+ {
+ psInst->pui8Buffer[1] = psInst->pui8Data[3];
+ }
+
+ //
+ // Advance past the next two bytes of the input buffer.
+ //
+ psInst->pui8Data += 2;
+ psInst->ui16Count--;
+
+ //
+ // Resume the batched write.
+ //
+ I2CMTransferResume(psInst->psI2CInst, psInst->pui8Buffer);
+ }
+
+ //
+ // The transfer has completed, or an error has occurred. In both cases,
+ // see if there is a callback function.
+ //
+ else if(psInst->pfnCallback)
+ {
+ //
+ // Call the application-supplied callback function.
+ //
+ psInst->pfnCallback(psInst->pvCallbackData, ui8Status);
+ }
+}
+
+//*****************************************************************************
+//
+//! Performs a write of 16-bit big-endian data to an I2C device.
+//!
+//! \param psInst is a pointer to the 16-bit big-endian write instance data.
+//! \param psI2CInst is a pointer to the I2C master instance data.
+//! \param ui8Addr is the address of the I2C device to access.
+//! \param ui8Reg is the register in the I2C device to access.
+//! \param pui16Data is a pointer to the register data to be written.
+//! \param ui16Count is the number of 16-bit register values to be written.
+//! \param pfnCallback is the function to be called when the write has
+//! completed (can be \b NULL if a callback is not required).
+//! \param pvCallbackData is a pointer that is passed to the callback function.
+//!
+//! This function initiates a write transaction of 16-bit big-endian data to an
+//! I2C device. The data in the buffer is provided in little-endian format and
+//! is byte-swapped as it is being written to the I2C device.
+//!
+//! \return Returns 1 if the command was successfully added to the queue and 0
+//! if it was not.
+//
+//*****************************************************************************
+uint_fast8_t
+I2CMWrite16BE(tI2CMWrite16BE *psInst, tI2CMInstance *psI2CInst,
+ uint_fast8_t ui8Addr, uint_fast8_t ui8Reg,
+ const uint16_t *pui16Data, uint_fast16_t ui16Count,
+ tSensorCallback *pfnCallback, void *pvCallbackData)
+{
+ //
+ // Check the arguments.
+ //
+ ASSERT(psInst);
+ ASSERT(psI2CInst);
+
+ //
+ // Fill in the write structure with the details of this request.
+ //
+ psInst->psI2CInst = psI2CInst;
+ psInst->pui8Data = (const uint8_t *)pui16Data;
+ psInst->ui16Count = ui16Count;
+ psInst->pfnCallback = pfnCallback;
+ psInst->pvCallbackData = pvCallbackData;
+
+ //
+ // Initiate the I2C write to this device.
+ //
+ psInst->pui8Buffer[0] = ui8Reg;
+ psInst->pui8Buffer[1] = psInst->pui8Data[1];
+ if(I2CMWriteBatched(psI2CInst, ui8Addr, psInst->pui8Buffer,
+ (ui16Count * 2) + 1, 2, I2CMWrite16BECallback,
+ psInst) == 0)
+ {
+ //
+ // The I2C write failed, so return a failure.
+ //
+ return(0);
+ }
+
+ //
+ // Success.
+ //
+ return(1);
+}
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
diff --git a/sensorlib/i2cm_drv.h b/sensorlib/i2cm_drv.h
new file mode 100644
index 0000000..397c04d
--- /dev/null
+++ b/sensorlib/i2cm_drv.h
@@ -0,0 +1,544 @@
+//*****************************************************************************
+//
+// i2cm_drv.h - Prototypes for the interrupt-driven I2C master driver.
+//
+// Copyright (c) 2012-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
+//
+//*****************************************************************************
+
+#ifndef __SENSORLIB_I2CM_DRV_H__
+#define __SENSORLIB_I2CM_DRV_H__
+
+//*****************************************************************************
+//
+// If building with a C++ compiler, make all of the definitions in this header
+// have a C binding.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+//*****************************************************************************
+//
+// A prototype for the callback function used by the I2C master driver.
+//
+//*****************************************************************************
+typedef void (tSensorCallback)(void *pvData, uint_fast8_t ui8Status);
+
+//*****************************************************************************
+//
+// The possible status values that can be returned by the I2C command callback.
+//
+//*****************************************************************************
+#define I2CM_STATUS_SUCCESS 0
+#define I2CM_STATUS_ADDR_NACK 1
+#define I2CM_STATUS_DATA_NACK 2
+#define I2CM_STATUS_ARB_LOST 3
+#define I2CM_STATUS_ERROR 4
+#define I2CM_STATUS_BATCH_DONE 5
+#define I2CM_STATUS_BATCH_READY 6
+
+//*****************************************************************************
+//
+// The maximum number of outstanding commands for each I2C master instance.
+//
+//*****************************************************************************
+#define NUM_I2CM_COMMANDS 10
+
+//*****************************************************************************
+//
+// The structure that defines an I2C master command.
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ // The I2C address of the device being accessed.
+ //
+ uint8_t ui8Addr;
+
+ //
+ // The data buffer containing the data to be written.
+ //
+ const uint8_t *pui8WriteData;
+
+ //
+ // The total number of bytes to be written by the command.
+ //
+ uint16_t ui16WriteCount;
+
+ //
+ // The number of bytes to be written in each batch.
+ //
+ uint16_t ui16WriteBatchSize;
+
+ //
+ // The data buffer to store data that has been read.
+ //
+ uint8_t *pui8ReadData;
+
+ //
+ // The total number of bytes to be read by the command.
+ //
+ uint16_t ui16ReadCount;
+
+ //
+ // The number of bytes to be read in each chuck.
+ //
+ uint16_t ui16ReadBatchSize;
+
+ //
+ // The function that is called when this command has been transferred.
+ //
+ tSensorCallback *pfnCallback;
+
+ //
+ // The pointer provided to the callback function.
+ //
+ void *pvCallbackData;
+}
+tI2CMCommand;
+
+//*****************************************************************************
+//
+// The structure that contains the state of an I2C master instance.
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ // The base address of the I2C module.
+ //
+ uint32_t ui32Base;
+
+ //
+ // The interrupt number associated with the I2C module.
+ //
+ uint8_t ui8Int;
+
+ //
+ // The uDMA channel used to write data to the I2C module.
+ //
+ uint8_t ui8TxDMA;
+
+ //
+ // The uDMA channel used to read data from the I2C module.
+ //
+ uint8_t ui8RxDMA;
+
+ //
+ // The current state of the I2C master driver.
+ //
+ uint8_t ui8State;
+
+ //
+ // The offset of the next command to be read. The buffer is empty when
+ // this value is equal to the write pointer.
+ //
+ uint8_t ui8ReadPtr;
+
+ //
+ // The offset of the next space in the buffer to write a command. The
+ // buffer is full if this value is one less than the read pointer.
+ //
+ uint8_t ui8WritePtr;
+
+ //
+ // The index into the data buffer of the next byte to be transferred.
+ //
+ uint16_t ui16Index;
+
+ //
+ // An array of commands queued up to be sent via the I2C module.
+ //
+ tI2CMCommand pCommands[NUM_I2CM_COMMANDS];
+}
+tI2CMInstance;
+
+//*****************************************************************************
+//
+// The structure that contains the state of an I2C read-modify-write request of
+// 8 bits of data.
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ // A pointer to the I2C master interface instance used for the
+ // read-modify-write request.
+ //
+ tI2CMInstance *psI2CInst;
+
+ //
+ // The buffer used for the I2C transfers.
+ //
+ uint8_t pui8Buffer[4];
+
+ //
+ // The current state of the I2C read-modify-write state machine.
+ //
+ uint8_t ui8State;
+
+ //
+ // The I2C address of the device being accessed.
+ //
+ uint8_t ui8Addr;
+
+ //
+ // The value to AND with the I2C register data.
+ //
+ uint8_t ui8Mask;
+
+ //
+ // The value to OR with the I2C register data.
+ //
+ uint8_t ui8Value;
+
+ //
+ // The function that is called when the read-modify-write has been
+ // completed.
+ //
+ tSensorCallback *pfnCallback;
+
+ //
+ // The pointer provided to the callback function.
+ //
+ void *pvCallbackData;
+}
+tI2CMReadModifyWrite8;
+
+//*****************************************************************************
+//
+// The structure that contains the state of an I2C read-modify-write request of
+// 16 bits of data.
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ // A pointer to the I2C master interface instance used for the
+ // read-modify-write request.
+ //
+ tI2CMInstance *psI2CInst;
+
+ //
+ // The buffer used for the I2C transfers.
+ //
+ uint8_t pui8Buffer[4];
+
+ //
+ // The current state of the I2C read-modify-write state machine.
+ //
+ uint8_t ui8State;
+
+ //
+ // The I2C address of the device being accessed.
+ //
+ uint8_t ui8Addr;
+
+ //
+ // The value to AND with the I2C register data.
+ //
+ uint16_t ui16Mask;
+
+ //
+ // The value to OR with the I2C register data.
+ //
+ uint16_t ui16Value;
+
+ //
+ // The function that is called when the read-modify-write has been
+ // completed.
+ //
+ tSensorCallback *pfnCallback;
+
+ //
+ // The pointer provided to the callback function.
+ //
+ void *pvCallbackData;
+}
+tI2CMReadModifyWrite16;
+
+//*****************************************************************************
+//
+// The structure that contains the state of an I2C write request of 8-bit data.
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ // A pointer to the I2C master interface instance used for the write
+ // request.
+ //
+ tI2CMInstance *psI2CInst;
+
+ //
+ // The buffer used for the I2C transfers.
+ //
+ uint8_t pui8Buffer[2];
+
+ //
+ // The number of values to write to the I2C device.
+ //
+ uint16_t ui16Count;
+
+ //
+ // A pointer to the buffer containing the data to write to the I2C device.
+ //
+ const uint8_t *pui8Data;
+
+ //
+ // The function that is called when the write has been completed.
+ //
+ tSensorCallback *pfnCallback;
+
+ //
+ // The pointer provided to the callback function.
+ //
+ void *pvCallbackData;
+}
+tI2CMWrite8;
+
+//*****************************************************************************
+//
+// The structure that contains the state of an I2C read request of 16-bit data
+// from a big-endian device.
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ // A pointer to the I2C master interface instance used for the read
+ // request.
+ //
+ tI2CMInstance *psI2CInst;
+
+ //
+ // A pointer to the buffer containing the data read from the I2C device.
+ //
+ uint8_t *pui8Data;
+
+ //
+ // The number of 16-bit values to read from the I2C device.
+ //
+ uint16_t ui16Count;
+
+ //
+ // The function that is called when the read has been completed.
+ //
+ tSensorCallback *pfnCallback;
+
+ //
+ // The pointer provided to the callback function.
+ //
+ void *pvCallbackData;
+}
+tI2CMRead16BE;
+
+//*****************************************************************************
+//
+// The structure that contains the state of an I2C write request of 16-bit data
+// to a big-endian device.
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ // A pointer to the I2C master interface instance used for the write
+ // request.
+ //
+ tI2CMInstance *psI2CInst;
+
+ //
+ // The buffer used for the I2C transfers.
+ //
+ uint8_t pui8Buffer[2];
+
+ //
+ // The number of 16-bit values to write to the I2C device.
+ //
+ uint16_t ui16Count;
+
+ //
+ // A pointer to the buffer containing the data to write to the I2C device.
+ //
+ const uint8_t *pui8Data;
+
+ //
+ // The function that is called when the write has been completed.
+ //
+ tSensorCallback *pfnCallback;
+
+ //
+ // The pointer provided to the callback function.
+ //
+ void *pvCallbackData;
+}
+tI2CMWrite16BE;
+
+//*****************************************************************************
+//
+// Prototypes.
+//
+//*****************************************************************************
+extern void I2CMIntHandler(tI2CMInstance *psInst);
+extern void I2CMInit(tI2CMInstance *psInst, uint32_t ui32Base,
+ uint_fast8_t ui8Int, uint_fast8_t ui8TxDMA,
+ uint_fast8_t ui8RxDMA, uint32_t ui32Clock);
+extern uint_fast8_t I2CMCommand(tI2CMInstance *psInst, uint_fast8_t ui8Addr,
+ const uint8_t *pui8WriteData,
+ uint_fast16_t ui16WriteCount,
+ uint_fast16_t ui16WriteBatchSize,
+ uint8_t *pui8ReadData,
+ uint_fast16_t ui16ReadCount,
+ uint_fast16_t ui16ReadBatchSize,
+ tSensorCallback *pfnCallback,
+ void *pvCallbackData);
+extern uint_fast8_t I2CMTransferResume(tI2CMInstance *psInst,
+ uint8_t *pui8Data);
+extern uint_fast8_t I2CMReadModifyWrite8(tI2CMReadModifyWrite8 *psInst,
+ tI2CMInstance *psI2CInst,
+ uint_fast8_t ui8Addr,
+ uint_fast8_t ui8Reg,
+ uint_fast8_t ui8Mask,
+ uint_fast8_t ui8Value,
+ tSensorCallback *pfnCallback,
+ void *pvCallbackData);
+extern uint_fast8_t I2CMReadModifyWrite16LE(tI2CMReadModifyWrite16 *psInst,
+ tI2CMInstance *psI2CInst,
+ uint_fast8_t ui8Addr,
+ uint_fast8_t ui8Reg,
+ uint_fast16_t ui16Mask,
+ uint_fast16_t ui16Value,
+ tSensorCallback *pfnCallback,
+ void *pvCallbackData);
+extern uint_fast8_t I2CMWrite8(tI2CMWrite8 *psInst, tI2CMInstance *psI2CInst,
+ uint_fast8_t ui8Addr, uint_fast8_t ui8Reg,
+ const uint8_t *pui8Data,
+ uint_fast16_t ui16Count,
+ tSensorCallback *pfnCallback,
+ void *pvCallbackData);
+extern uint_fast8_t I2CMRead16BE(tI2CMRead16BE *psInst,
+ tI2CMInstance *psI2CInst,
+ uint_fast8_t ui8Addr, uint_fast8_t ui8Reg,
+ uint16_t *pui16Data, uint_fast16_t ui16Count,
+ tSensorCallback *pfnCallback,
+ void *pvCallbackData);
+extern uint_fast8_t I2CMWrite16BE(tI2CMWrite16BE *psInst,
+ tI2CMInstance *psI2CInst,
+ uint_fast8_t ui8Addr, uint_fast8_t ui8Reg,
+ const uint16_t *pui16Data,
+ uint_fast16_t ui16Count,
+ tSensorCallback *pfnCallback,
+ void *pvCallbackData);
+
+//*****************************************************************************
+//
+// A convenience wrapper around I2CMCommand to perform a write.
+//
+//*****************************************************************************
+inline uint_fast8_t
+I2CMWrite(tI2CMInstance *psInst, uint_fast8_t ui8Addr, const uint8_t *pui8Data,
+ uint_fast16_t ui16Count, tSensorCallback *pfnCallback,
+ void *pvCallbackData)
+{
+ return(I2CMCommand(psInst, ui8Addr, pui8Data, ui16Count, ui16Count, 0, 0,
+ 0, pfnCallback, pvCallbackData));
+}
+
+//*****************************************************************************
+//
+// A convenience wrapper around I2CMCommand to perform a read.
+//
+//*****************************************************************************
+inline uint_fast8_t
+I2CMRead(tI2CMInstance *psInst, uint_fast8_t ui8Addr,
+ const uint8_t *pui8WriteData, uint_fast16_t ui16WriteCount,
+ uint8_t *pui8ReadData, uint_fast16_t ui16ReadCount,
+ tSensorCallback *pfnCallback, void *pvCallbackData)
+{
+ return(I2CMCommand(psInst, ui8Addr, pui8WriteData, ui16WriteCount,
+ ui16WriteCount, pui8ReadData, ui16ReadCount,
+ ui16ReadCount, pfnCallback, pvCallbackData));
+}
+
+//*****************************************************************************
+//
+// A convenience wrapper around I2CMCommand to perform a batched write.
+//
+//*****************************************************************************
+inline uint_fast8_t
+I2CMWriteBatched(tI2CMInstance *psInst, uint_fast8_t ui8Addr,
+ const uint8_t *pui8Data, uint_fast16_t ui16Count,
+ uint_fast16_t ui16BatchSize, tSensorCallback *pfnCallback,
+ void *pvCallbackData)
+{
+ return(I2CMCommand(psInst, ui8Addr, pui8Data, ui16Count, ui16BatchSize, 0,
+ 0, 0, pfnCallback, pvCallbackData));
+}
+
+//*****************************************************************************
+//
+// A convenience wrapper around I2CMCommand to perform a batched read.
+//
+//*****************************************************************************
+inline uint_fast8_t
+I2CMReadBatched(tI2CMInstance *psInst, uint_fast8_t ui8Addr,
+ const uint8_t *pui8WriteData, uint_fast16_t ui16WriteCount,
+ uint_fast16_t ui16WriteBatchSize, uint8_t *pui8ReadData,
+ uint_fast16_t ui16ReadCount, uint_fast16_t ui16ReadBatchSize,
+ tSensorCallback *pfnCallback, void *pvCallbackData)
+{
+ return(I2CMCommand(psInst, ui8Addr, pui8WriteData, ui16WriteCount,
+ ui16WriteBatchSize, pui8ReadData, ui16ReadCount,
+ ui16ReadBatchSize, pfnCallback, pvCallbackData));
+}
+
+//*****************************************************************************
+//
+// A 16-bit big-endian read-modify-write in terms of the little-endian version.
+//
+//*****************************************************************************
+inline uint_fast8_t
+I2CMReadModifyWrite16BE(tI2CMReadModifyWrite16 *psInst,
+ tI2CMInstance *psI2CInst, uint_fast8_t ui8Addr,
+ uint_fast8_t ui8Reg, uint_fast16_t ui16Mask,
+ uint_fast16_t ui16Value, tSensorCallback *pfnCallback,
+ void *pvCallbackData)
+{
+ return(I2CMReadModifyWrite16LE(psInst, psI2CInst, ui8Addr, ui8Reg,
+ (((ui16Mask & 0xff00) >> 8) |
+ ((ui16Mask & 0x00ff) << 8)),
+ (((ui16Value & 0xff00) >> 8) |
+ ((ui16Value & 0x00ff) << 8)),
+ pfnCallback, pvCallbackData));
+}
+
+//*****************************************************************************
+//
+// Mark the end of the C bindings section for C++ compilers.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __SENSORLIB_I2CM_DRV_H__
diff --git a/sensorlib/isl29023.c b/sensorlib/isl29023.c
new file mode 100644
index 0000000..313ced9
--- /dev/null
+++ b/sensorlib/isl29023.c
@@ -0,0 +1,668 @@
+//*****************************************************************************
+//
+// isl29023.c - Driver for the ISL29023 Light Sensor
+//
+// Copyright (c) 2013-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
+//
+//*****************************************************************************
+
+#include <stdint.h>
+#include <stdbool.h>
+#include "sensorlib/hw_isl29023.h"
+#include "sensorlib/i2cm_drv.h"
+#include "sensorlib/isl29023.h"
+
+//*****************************************************************************
+//
+//! \addtogroup isl29023_api
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// Range setting to floating point range value lookup table
+//
+//*****************************************************************************
+const float g_fRangeLookup[4] =
+{
+ 1000.0,
+ 4000.0,
+ 16000.0,
+ 64000.0
+};
+
+//*****************************************************************************
+//
+// Resolution setting to floating point resolution value lookup table
+//
+//*****************************************************************************
+const float g_fResolutionLookup[4] =
+{
+ 65536.0,
+ 4096.0,
+ 256.0,
+ 16.0
+};
+
+//*****************************************************************************
+//
+// Beta value lookup based on datasheet typical values for DATA_IR1, DATA_IR2,
+// DATA_IR3, DATA_IR4. These should be reasonable for 16 bit conversions.
+// However, Beta changes with resolution and background IR conditions.
+//
+//*****************************************************************************
+const float g_fBetaLookup[4] =
+{
+ 95.238,
+ 23.810,
+ 5.952,
+ 1.486
+};
+
+//*****************************************************************************
+//
+// The states of the ISL29023 state machine.
+//
+//*****************************************************************************
+#define ISL29023_STATE_IDLE 0
+#define ISL29023_STATE_INIT 1
+#define ISL29023_STATE_READ 2
+#define ISL29023_STATE_WRITE 3
+#define ISL29023_STATE_RMW 4
+#define ISL29023_STATE_READ_DATA 5
+
+//*****************************************************************************
+//
+// The callback function that is called when I2C transations to/from the
+// ISL29023 have completed.
+//
+//*****************************************************************************
+static void
+ISL29023Callback(void *pvCallbackData, uint_fast8_t ui8Status)
+{
+ tISL29023 *psInst;
+ uint8_t *pui8Data;
+
+ //
+ // Convert the instance data into a pointer to a tBMA180 structure.
+ //
+ psInst = (tISL29023 *)pvCallbackData;
+
+ //
+ // If the I2C master driver encountered a failure, force the state machine
+ // to the idle state (which will also result in a callback to propagate the
+ // error).
+ //
+ if(ui8Status != I2CM_STATUS_SUCCESS)
+ {
+ psInst->ui8State = ISL29023_STATE_IDLE;
+ }
+
+ //
+ // Determine the current state of the ISL29023 state machine.
+ //
+ switch(psInst->ui8State)
+ {
+ //
+ // All states that trivially transition to IDLE, and all unknown
+ // states.
+ //
+ case ISL29023_STATE_INIT:
+ case ISL29023_STATE_READ:
+ case ISL29023_STATE_READ_DATA:
+ default:
+ {
+ //
+ // A register operation is complete. Return to IDLE state
+ // the value read from the register is in the pui8Data buffer and
+ // can be accessed directly by the calling application after
+ // receiving the callback.
+ //
+ psInst->ui8State = ISL29023_STATE_IDLE;
+ break;
+ }
+
+ //
+ // A write to the ISL29023 control and config registers is complete.
+ //
+ case ISL29023_STATE_WRITE:
+ {
+ //
+ // Set the range and resolution to the new values. If the register
+ // was not modified, the values will be the same so this has no
+ // effect.
+ //
+ psInst->ui8Range = psInst->ui8NewRange;
+ psInst->ui8Resolution = psInst->ui8NewResolution;
+
+ //
+ // The state machine is now idle.
+ //
+ psInst->ui8State = ISL29023_STATE_IDLE;
+
+ //
+ // Done.
+ //
+ break;
+ }
+
+ //
+ // A read modify write operation has just completed.
+ //
+ case ISL29023_STATE_RMW:
+ {
+ //
+ // Check if the register that was written contained the range or
+ // resolution data that we need to track.
+ //
+ pui8Data = psInst->uCommand.sReadModifyWriteState.pui8Buffer;
+ if((pui8Data[0] == ISL29023_O_CMD_II) &&
+ (ui8Status == I2CM_STATUS_SUCCESS))
+ {
+ //
+ // Store the latest range and resolution settings
+ //
+ psInst->ui8Range = ((pui8Data[1] & ISL29023_CMD_II_RANGE_M) >>
+ ISL29023_CMD_II_RANGE_S);
+ psInst->ui8Resolution = ((pui8Data[1] &
+ ISL29023_CMD_II_ADC_RES_M) >>
+ ISL29023_CMD_II_ADC_RES_S);
+ }
+
+ //
+ // The state machine is now idle.
+ //
+ psInst->ui8State = ISL29023_STATE_IDLE;
+
+ //
+ // Done.
+ //
+ break;
+ }
+ }
+
+ //
+ // See if the state machine is now idle and there is a callback function.
+ //
+ if((psInst->ui8State == ISL29023_STATE_IDLE) && psInst->pfnCallback)
+ {
+ //
+ // Call the application-supplied callback function.
+ //
+ psInst->pfnCallback(psInst->pvCallbackData, ui8Status);
+ }
+}
+
+//*****************************************************************************
+//
+//! Initializes the ISL29023 driver.
+//!
+//! \param psInst is a pointer to the ISL29023 instance data.
+//! \param psI2CInst is a pointer to the I2C driver instance data.
+//! \param ui8I2CAddr is the I2C address of the ISL29023 device.
+//! \param pfnCallback is the function to be called when the initialization has
+//! completed (can be \b NULL if a callback is not required).
+//! \param pvCallbackData is a pointer that is passed to the callback function.
+//!
+//! This function initializes the ISL29023 driver, preparing it for operation.
+//! This function also asserts a reset signal to the ISL29023 to clear any
+//! previous configuration data.
+//!
+//! \return Returns 1 if the ISL29023 driver was successfully initialized and 0
+//! if it was not.
+//
+//*****************************************************************************
+uint_fast8_t
+ISL29023Init(tISL29023 *psInst, tI2CMInstance *psI2CInst,
+ uint_fast8_t ui8I2CAddr, tSensorCallback *pfnCallback,
+ void *pvCallbackData)
+{
+ //
+ // Initialize the ISL29023 instance structure
+ //
+ psInst->psI2CInst = psI2CInst;
+ psInst->ui8Addr = ui8I2CAddr;
+ psInst->ui8State = ISL29023_STATE_INIT;
+ psInst->ui8Range = ISL29023_CMD_II_RANGE_1K >> ISL29023_CMD_II_RANGE_S;
+ psInst->ui8NewRange = ISL29023_CMD_II_RANGE_1K >> ISL29023_CMD_II_RANGE_S;
+ psInst->ui8Resolution = (ISL29023_CMD_II_ADC_RES_16 >>
+ ISL29023_CMD_II_ADC_RES_S);
+ psInst->ui8NewResolution = (ISL29023_CMD_II_ADC_RES_16 >>
+ ISL29023_CMD_II_ADC_RES_S);
+
+ //
+ // Save the callback information.
+ //
+ psInst->pfnCallback = pfnCallback;
+ psInst->pvCallbackData = pvCallbackData;
+
+ //
+ // Put the device into power down mode.
+ //
+ psInst->pui8Data[0] = ISL29023_O_CMD_I;
+ psInst->pui8Data[1] = ISL29023_CMD_I_OP_MODE_POWER_DOWN;
+ if(I2CMWrite(psInst->psI2CInst, psInst->ui8Addr, psInst->pui8Data, 2,
+ ISL29023Callback, psInst) == 0)
+ {
+ //
+ // The I2C write failed, so move to the idle state and return a
+ // failure.
+ //
+ psInst->ui8State = ISL29023_STATE_IDLE;
+ return(0);
+ }
+
+ //
+ // Success
+ //
+ return(1);
+}
+
+//*****************************************************************************
+//
+//! Reads data from ISL29023 registers.
+//!
+//! \param psInst is a pointer to the ISL29023 instance data.
+//! \param ui8Reg is the first register to read.
+//! \param pui8Data is a pointer to the location to store the data that is
+//! read.
+//! \param ui16Count is the number of data bytes to read.
+//! \param pfnCallback is the function to be called when the data has been read
+//! (can be \b NULL if a callback is not required).
+//! \param pvCallbackData is a pointer that is passed to the callback function.
+//!
+//! This function reads a sequence of data values from consecutive registers in
+//! the ISL29023.
+//!
+//! \return Returns 1 if the write was successfully started and 0 if it was
+//! not.
+//
+//*****************************************************************************
+uint_fast8_t
+ISL29023Read(tISL29023 *psInst, uint_fast8_t ui8Reg, uint8_t *pui8Data,
+ uint_fast16_t ui16Count, tSensorCallback *pfnCallback,
+ void *pvCallbackData)
+{
+ //
+ // Return a failure if the ISL29023 driver is not idle (in other words,
+ // there is already an outstanding request to the ISL29023).
+ //
+ if(psInst->ui8State != ISL29023_STATE_IDLE)
+ {
+ return(0);
+ }
+ //
+ // Store the Callback information
+ //
+ psInst->pfnCallback = pfnCallback;
+ psInst->pvCallbackData = pvCallbackData;
+
+ //
+ // set ISL29023 state
+ //
+ psInst->ui8State = ISL29023_STATE_READ;
+
+ //
+ // Load the command buffer with the appropriate register information
+ //
+ psInst->uCommand.pui8Buffer[0] = ui8Reg;
+
+ //
+ // Start the I2CM read and return indication.
+ //
+ if(I2CMRead(psInst->psI2CInst, psInst->ui8Addr,
+ psInst->uCommand.pui8Buffer, 1, pui8Data, ui16Count,
+ ISL29023Callback, psInst) == 0)
+ {
+ psInst->ui8State = ISL29023_STATE_IDLE;
+ return(0);
+ }
+
+ return(1);
+}
+
+//*****************************************************************************
+//
+//! Write register data to the ISL29023.
+//!
+//! \param psInst is a pointer to the ISL29023 instance data.
+//! \param ui8Reg is the first register to write.
+//! \param pui8Data is a pointer to the data to write.
+//! \param ui16Count is the number of data bytes to write.
+//! \param pfnCallback is the function to be called when the data has been
+//! written (can be \b NULL if a callback is not required).
+//! \param pvCallbackData is a pointer that is passed to the callback function.
+//!
+//! This function writes a sequence of data values to consecutive registers in
+//! the ISL29023. The first byte of the \e pui8Data buffer contains the value
+//! to be written into the \e ui8Reg register, the second value contains the
+//! data to be written into the next register, and so on.
+//!
+//! \return Returns 1 if the write was successfully started and 0 if it was
+//! not.
+//
+//*****************************************************************************
+uint_fast8_t
+ISL29023Write(tISL29023 *psInst, uint_fast8_t ui8Reg, uint8_t *pui8Data,
+ uint_fast16_t ui16Count, tSensorCallback *pfnCallback,
+ void *pvCallbackData)
+{
+ //
+ // Return a failure if the ISL29023 driver is not idle (in other words,
+ // there is already an outstanding request to the ISL29023).
+ //
+ if(psInst->ui8State != ISL29023_STATE_IDLE)
+ {
+ return(0);
+ }
+
+ //
+ // Save the callback information
+ //
+ psInst->pfnCallback = pfnCallback;
+ psInst->pvCallbackData = pvCallbackData;
+
+ //
+ // See if the CMD_II register is being written.
+ //
+ if((ui8Reg <= ISL29023_O_CMD_II) &&
+ ((ui8Reg + ui16Count) > ISL29023_O_CMD_II))
+ {
+ //
+ // Extract the range and resolution from the CMD_II register value.
+ //
+ psInst->ui8NewRange = ((pui8Data[ui8Reg - ISL29023_O_CMD_II] &
+ ISL29023_CMD_II_RANGE_M) >>
+ ISL29023_CMD_II_RANGE_S);
+ psInst->ui8NewResolution = ((pui8Data[ui8Reg - ISL29023_O_CMD_II] &
+ ISL29023_CMD_II_ADC_RES_M) >>
+ ISL29023_CMD_II_ADC_RES_S);
+ }
+
+ //
+ // Move state machine to the write state
+ //
+ psInst->ui8State = ISL29023_STATE_WRITE;
+
+ //
+ // Add the i2c address and the register offset to the data buffer.
+ //
+ if(I2CMWrite8(&(psInst->uCommand.sWriteState), psInst->psI2CInst,
+ psInst->ui8Addr, ui8Reg, pui8Data, ui16Count,
+ ISL29023Callback, psInst) == 0)
+ {
+ //
+ // I2C write failed, move to idle state and return the failure.
+ //
+ psInst->ui8State = ISL29023_STATE_IDLE;
+ return(0);
+ }
+
+ //
+ // Success.
+ //
+ return(1);
+}
+
+//*****************************************************************************
+//
+//! Performs a read-modify-write of an ISL29023 register.
+//!
+//! \param psInst is a pointer to the ISL29023 instance data.
+//! \param ui8Reg is the register to modify.
+//! \param ui8Mask is the bit mask that is ANDed with the current register
+//! value.
+//! \param ui8Value is the bit mask that is ORed with the result of the AND
+//! operation.
+//! \param pfnCallback is the function to be called when the data has been
+//! changed (can be \b NULL if a callback is not required).
+//! \param pvCallbackData is a pointer that is passed to the callback function.
+//!
+//! This function changes the value of a register in the ISL29023 via a
+//! read-modify-write operation, allowing one of the fields to be changed
+//! without disturbing the other fields. The \e ui8Reg register is read, ANDed
+//! with \e ui8Mask, ORed with \e ui8Value, and then written back to the
+//! ISL29023.
+//!
+//! \return Returns 1 if the read-modify-write was successfully started and 0
+//! if it was not.
+//
+//*****************************************************************************
+uint_fast8_t
+ISL29023ReadModifyWrite(tISL29023 *psInst, uint_fast8_t ui8Reg,
+ uint8_t ui8Mask, uint8_t ui8Value,
+ tSensorCallback *pfnCallback, void *pvCallbackData)
+{
+ //
+ // Return a failure if the ISL29023 driver is not in the idle state.
+ //
+ if(psInst->ui8State != ISL29023_STATE_IDLE)
+ {
+ return(0);
+ }
+
+ //
+ // Save the callback information
+ //
+ psInst->pfnCallback = pfnCallback;
+ psInst->pvCallbackData = pvCallbackData;
+
+ //
+ // set ISL29023 state
+ //
+ psInst->ui8State = ISL29023_STATE_RMW;
+
+ //
+ // Submit the read-modify-write request to the ISL29023.
+ //
+ if(I2CMReadModifyWrite8(&(psInst->uCommand.sReadModifyWriteState),
+ psInst->psI2CInst, psInst->ui8Addr, ui8Reg,
+ ui8Mask, ui8Value, ISL29023Callback, psInst) == 0)
+ {
+ //
+ // The I2C read-modify-write failed, so move to the idle state and
+ // return a failure.
+ //
+ psInst->ui8State = ISL29023_STATE_IDLE;
+ return(0);
+ }
+
+ //
+ // Success.
+ //
+ return(1);
+}
+
+//*****************************************************************************
+//
+//! Reads the light data from the ISL29023.
+//!
+//! \param psInst is a pointer to the ISL29023 instance data.
+//! \param pfnCallback is the function to be called when the data has been read
+//! (can be \b NULL if a callback is not required).
+//! \param pvCallbackData is a pointer that is passed to the callback function.
+//!
+//! This function initiates a read of the ISL29023 data registers. When the
+//! read has completed (as indicated by calling the callback function), the new
+//! readings can be obtained via:
+//!
+//! - ISL29023DataLightVisibleGetRaw()
+//! - ISL29023DataLightVisibleGetFloat()
+//! - ISL29023DataLightIRGetRaw()
+//! - ISL29023DataLightIRGetFloat()
+//!
+//! \return Returns 1 if the read was successfully started and 0 if it was not.
+//
+//*****************************************************************************
+uint_fast8_t
+ISL29023DataRead(tISL29023 *psInst, tSensorCallback *pfnCallback,
+ void *pvCallbackData)
+{
+ //
+ // Return a failure if the ISL29023 driver is not idle (in other words,
+ // there is already an outstanding request to the ISL29023).
+ //
+ if(psInst->ui8State != ISL29023_STATE_IDLE)
+ {
+ return(0);
+ }
+
+ //
+ // Store the Callback information
+ //
+ psInst->pfnCallback = pfnCallback;
+ psInst->pvCallbackData = pvCallbackData;
+
+ //
+ // set ISL29023 state
+ //
+ psInst->ui8State = ISL29023_STATE_READ_DATA;
+
+ psInst->uCommand.pui8Buffer[0] = ISL29023_O_DATA_OUT_LSB;
+ if(I2CMRead(psInst->psI2CInst, psInst->ui8Addr,
+ psInst->uCommand.pui8Buffer, 1, psInst->pui8Data, 2,
+ ISL29023Callback, psInst) == 0)
+ {
+ //
+ // The I2C read failed, so move to the idle state and return a failure.
+ //
+ psInst->ui8State = ISL29023_STATE_IDLE;
+ return(0);
+ }
+
+ //
+ // Success.
+ //
+ return(1);
+}
+
+//*****************************************************************************
+//
+//! Gets the raw measurement data from the most recent data read.
+//!
+//! \param psInst is a pointer to the ISL29023 instance data.
+//! \param pui16Visible is a pointer to the value into which the raw light data
+//! is stored.
+//!
+//! This function returns the raw measurement data from the most recent data
+//! read. The data is not manipulated in any way by the driver.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+ISL29023DataLightVisibleGetRaw(tISL29023 *psInst, uint16_t *pui16Visible)
+{
+ //
+ // Return the raw light value.
+ //
+ *pui16Visible = (psInst->pui8Data[1] << 8) | psInst->pui8Data[0];
+}
+
+//*****************************************************************************
+//
+//! Gets the measurement data from the most recent data read.
+//!
+//! \param psInst is a pointer to the ISL29023 instance data.
+//! \param pfVisibleLight is a pointer to the value into which the light data
+//! is stored as floating point lux.
+//!
+//! This function returns the light data from the most recent data read,
+//! converted into lux.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+ISL29023DataLightVisibleGetFloat(tISL29023 *psInst, float *pfVisibleLight)
+{
+ uint16_t ui16Light;
+ float fRange, fResolution;
+
+ //
+ // Get the raw light data from the instance structure
+ //
+ ISL29023DataLightVisibleGetRaw(psInst, &ui16Light);
+
+ //
+ // Get the floating point values for range and resolution from the lookup.
+ //
+ fRange = g_fRangeLookup[psInst->ui8Range];
+ fResolution = g_fResolutionLookup[psInst->ui8Resolution];
+
+ //
+ // Calculate light reading in lux.
+ //
+ *pfVisibleLight = ((float)ui16Light) * (fRange / fResolution);
+}
+
+//*****************************************************************************
+//
+//! Gets the raw measurement data from the most recent data read.
+//!
+//! \param psInst is a pointer to the ISL29023 instance data.
+//! \param pui16IR is a pointer to the value into which the raw IR data is
+//! stored.
+//!
+//! This function returns the raw measurement data from the most recent data
+//! read. The data is not manipulated in any way by the driver.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+ISL29023DataLightIRGetRaw(tISL29023 *psInst, uint16_t *pui16IR)
+{
+ //
+ // Return the raw light value.
+ //
+ *pui16IR = (psInst->pui8Data[1] << 8) | psInst->pui8Data[0];
+}
+
+//*****************************************************************************
+//
+//! Gets the measurement data from the most recent data read.
+//!
+//! \param psInst is a pointer to the ISL29023 instance data.
+//! \param pfIR is a pointer to the value into which the IR data is stored as
+//! floating point lux.
+//!
+//! This function returns the IR data from the most recent data read, converted
+//! into lux.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+ISL29023DataLightIRGetFloat(tISL29023 *psInst, float *pfIR)
+{
+ uint16_t i16IR;
+
+ ISL29023DataLightIRGetRaw(psInst, &i16IR);
+
+ *pfIR = ((float) i16IR) / g_fBetaLookup[psInst->ui8Range];
+}
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
diff --git a/sensorlib/isl29023.h b/sensorlib/isl29023.h
new file mode 100644
index 0000000..184c702
--- /dev/null
+++ b/sensorlib/isl29023.h
@@ -0,0 +1,166 @@
+//*****************************************************************************
+//
+// isl29023.h - Prototypes for the ISL29023 light sensor driver.
+//
+// Copyright (c) 2013-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
+//
+//*****************************************************************************
+
+#ifndef __SENSORLIB_ISL29023_H__
+#define __SENSORLIB_ISL29023_H__
+
+//*****************************************************************************
+//
+// If building with a C++ compiler, make all of the definitions in this header
+// have a C binding.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+//*****************************************************************************
+//
+// The structure that defines the internal state of the ISL29023 driver.
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ // The pointer to the I2C master interface instance used to communicate
+ // with the ISL29023.
+ //
+ tI2CMInstance *psI2CInst;
+
+ //
+ // The I2C address of the ISL29023.
+ //
+ uint8_t ui8Addr;
+
+ //
+ // The state of the state machine used while accessing the ISL29023.
+ //
+ uint8_t ui8State;
+
+ //
+ // The data buffer used for sending/receiving data to/from the ISL29023.
+ //
+ uint8_t pui8Data[4];
+
+ //
+ // Instance copy of the range setting. Used in GetFloat functions
+ //
+ uint8_t ui8Range;
+
+ //
+ // The new range, which is used when a register write succeeds.
+ //
+ uint8_t ui8NewRange;
+
+ //
+ // Instance copy of the resolution setting. Used in GetFloat function.
+ //
+ uint8_t ui8Resolution;
+
+ //
+ // The new resolution, which is used when a register write succeeds.
+ //
+ uint8_t ui8NewResolution;
+
+ //
+ // The function that is called when the current request has completed
+ // processing.
+ //
+ tSensorCallback *pfnCallback;
+
+ //
+ // The pointer provided to the callback function.
+ //
+ void *pvCallbackData;
+
+ //
+ // A union of structures that are used for read, write and
+ // read-modify-write operations. Since only one operation can be active at
+ // a time, it is safe to re-use the memory in this manner.
+ //
+ union
+ {
+ //
+ // A buffer used to store the write portion of a register read.
+ //
+ uint8_t pui8Buffer[3];
+
+ //
+ // The write state used to write register values.
+ //
+ tI2CMWrite8 sWriteState;
+
+ //
+ // The read-modify-write state used to modify register values.
+ //
+ tI2CMReadModifyWrite8 sReadModifyWriteState;
+ }
+ uCommand;
+}
+tISL29023;
+
+//*****************************************************************************
+//
+// Function prototypes.
+//
+//*****************************************************************************
+extern uint_fast8_t ISL29023Init(tISL29023 *psInst, tI2CMInstance *psI2CInst,
+ uint_fast8_t ui8I2CAddr,
+ tSensorCallback *pfnCallback,
+ void *pvCallbackData);
+extern uint_fast8_t ISL29023Read(tISL29023 *psInst, uint_fast8_t ui8Reg,
+ uint8_t *pui8Data, uint_fast16_t ui16Count,
+ tSensorCallback *pfnCallback,
+ void *pvCallbackData);
+extern uint_fast8_t ISL29023Write(tISL29023 *psInst, uint_fast8_t ui8Reg,
+ uint8_t *pui8Data, uint_fast16_t ui16Count,
+ tSensorCallback *pfnCallback,
+ void *pvCallbackData);
+extern uint_fast8_t ISL29023ReadModifyWrite(tISL29023 *psInst,
+ uint_fast8_t ui8Reg,
+ uint8_t ui8Mask, uint8_t ui8Value,
+ tSensorCallback *pfnCallback,
+ void *pvCallbackData);
+extern uint_fast8_t ISL29023DataRead(tISL29023 *psInst,
+ tSensorCallback *pfnCallback,
+ void *pvCallbackData);
+extern void ISL29023DataLightVisibleGetRaw(tISL29023 *psInst,
+ uint16_t *pui16Visible);
+extern void ISL29023DataLightVisibleGetFloat(tISL29023 *psInst,
+ float *pfVisible);
+extern void ISL29023DataLightIRGetRaw(tISL29023 *psInst, uint16_t *pui16IR);
+extern void ISL29023DataLightIRGetFloat(tISL29023 *psInst, float *pfIR);
+
+//*****************************************************************************
+//
+// Mark the end of the C bindings section for C++ compilers.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __SENSORLIB_ISL29023_H__
+
diff --git a/sensorlib/kxti9.c b/sensorlib/kxti9.c
new file mode 100644
index 0000000..38de17b
--- /dev/null
+++ b/sensorlib/kxti9.c
@@ -0,0 +1,777 @@
+//*****************************************************************************
+//
+// kxti9.c - Driver for the KXTI9 accelerometer.
+//
+// Copyright (c) 2012-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
+//
+//*****************************************************************************
+
+#include <stdint.h>
+#include "sensorlib/hw_kxti9.h"
+#include "sensorlib/i2cm_drv.h"
+#include "sensorlib/kxti9.h"
+
+//*****************************************************************************
+//
+//! \addtogroup kxti9_api
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// The states of the KXTI9 state machine.
+//
+//*****************************************************************************
+#define KXTI9_STATE_IDLE 0 // State machine is idle
+#define KXTI9_STATE_INIT_RES 1 // Waiting for intialization
+#define KXTI9_STATE_INIT_WAIT 2 // Waiting for reset to complete
+#define KXTI9_STATE_LAST 3 // Last state of init
+#define KXTI9_STATE_READ 4 // Waiting for read
+#define KXTI9_STATE_WRITE 5 // Waiting for write
+#define KXTI9_STATE_RMW 6 // Waiting for read-modify-write
+
+//*****************************************************************************
+//
+// The factors used to convert the 8-bit acceleration readings from the KXTI9
+// into floating point values in m/s^2.
+//
+//*****************************************************************************
+static const float g_fAccelFactors8[] =
+{
+ (2.0 * 9.81) / 128.0,
+ (4.0 * 9.81) / 128.0,
+ (8.0 * 9.81) / 128.0
+};
+
+//*****************************************************************************
+//
+// The factors used to convert the 12-bit acceleration readings from the KXTI9
+// into floating point values in m/s^2.
+//
+//*****************************************************************************
+static const float g_fAccelFactors12[] =
+{
+ (2.0 * 9.81) / 2048.0,
+ (4.0 * 9.81) / 2048.0,
+ (8.0 * 9.81) / 2048.0
+};
+
+//*****************************************************************************
+//
+// The callback function that is called when I2C transations to/from the KXTI9
+// have completed.
+//
+//*****************************************************************************
+static void
+KXTI9Callback(void *pvCallbackData, uint_fast8_t ui8Status)
+{
+ tKXTI9 *psInst;
+
+ //
+ // Convert the instance data into a pointer to a tKXTI9 structure.
+ //
+ psInst = pvCallbackData;
+
+ //
+ // If the I2C master driver encountered a failure, force the state machine
+ // to the idle state (which will also result in a callback to propagate the
+ // error).
+ //
+ if((ui8Status != I2CM_STATUS_SUCCESS) &&
+ (psInst->ui8State != KXTI9_STATE_INIT_WAIT))
+ {
+ psInst->ui8State = KXTI9_STATE_IDLE;
+ }
+
+ //
+ // Determine the current state of the KXTI9 state machine.
+ //
+ switch(psInst->ui8State)
+ {
+ //
+ // All states that trivially transition to IDLE, and all unknown
+ // states.
+ //
+ case KXTI9_STATE_LAST:
+ case KXTI9_STATE_READ:
+ default:
+ {
+ //
+ // The state machine is now idle.
+ //
+ psInst->ui8State = KXTI9_STATE_IDLE;
+
+ //
+ // Done.
+ //
+ break;
+ }
+
+ case KXTI9_STATE_INIT_RES:
+ {
+ //
+ // Try to read back to determine if reset is done. We expect to see
+ // a NAK.
+ //
+ psInst->uCommand.pui8Buffer[0] = KXTI9_O_CTRL3;
+ I2CMRead(psInst->psI2CInst, psInst->ui8Addr,
+ psInst->uCommand.pui8Buffer, 1, psInst->pui8Data, 1,
+ KXTI9Callback, psInst);
+
+ psInst->ui8State = KXTI9_STATE_INIT_WAIT;
+ break;
+ }
+
+ case KXTI9_STATE_INIT_WAIT:
+ {
+ //
+ // Check to see if there was finally an ACK.
+ //
+ if(ui8Status != I2CM_STATUS_SUCCESS)
+ {
+ //
+ // Read again.
+ //
+ psInst->uCommand.pui8Buffer[0] = KXTI9_O_CTRL3;
+ I2CMRead(psInst->psI2CInst, psInst->ui8Addr,
+ psInst->uCommand.pui8Buffer, 1, psInst->pui8Data, 1,
+ KXTI9Callback, psInst);
+ }
+ else
+ {
+ //
+ // Check the read data to make sure it jibes.
+ //
+ if(psInst->pui8Data[0] == 0x4d)
+ {
+ //
+ // Device is out of reset, enable the device.
+ //
+ psInst->uCommand.pui8Buffer[0] = KXTI9_O_CTRL1;
+ psInst->uCommand.pui8Buffer[1] = KXTI9_CTRL1_PC1;
+ I2CMWrite(psInst->psI2CInst, psInst->ui8Addr,
+ psInst->uCommand.pui8Buffer, 2, KXTI9Callback,
+ psInst);
+ }
+ else
+ {
+ ui8Status = I2CM_STATUS_ERROR;
+ }
+
+ //
+ // This is the last init write.
+ //
+ psInst->ui8State = KXTI9_STATE_LAST;
+ }
+ break;
+ }
+
+ case KXTI9_STATE_WRITE:
+ {
+ //
+ // Set the accelerometer range and resolution to the new value.
+ // If the register was not modified, the values will be the same so
+ // this has no effect.
+ //
+ psInst->ui8Resolution = psInst->ui8NewResolution;
+ psInst->ui8Range = psInst->ui8NewRange;
+
+ //
+ // The state machine is now idle.
+ //
+ psInst->ui8State = KXTI9_STATE_IDLE;
+ break;
+ }
+
+ case KXTI9_STATE_RMW:
+ {
+ //
+ // See if the CTRL3 register was just modified.
+ //
+ if(psInst->uCommand.sReadModifyWriteState.pui8Buffer[0] ==
+ KXTI9_O_CTRL3)
+ {
+ //
+ // See if a soft reset has been issued.
+ //
+ if(psInst->uCommand.sReadModifyWriteState.pui8Buffer[1] &
+ KXTI9_CTRL3_SRST)
+ {
+ //
+ // Default range setting is +/- 2 g
+ //
+ psInst->ui8Range = 0;
+ psInst->ui8NewRange = 0;
+
+ //
+ // Default resolution is 8-bit.
+ //
+ psInst->ui8Resolution = 0;
+ psInst->ui8NewResolution = 0;
+ }
+ }
+
+ //
+ // See if the CTRL1 register was just modified.
+ //
+ if(psInst->uCommand.sReadModifyWriteState.pui8Buffer[0] ==
+ KXTI9_O_CTRL1)
+ {
+ //
+ // Extract the range and resolution from the register value.
+ //
+ psInst->ui8Range =
+ ((psInst->uCommand.sReadModifyWriteState.pui8Buffer[1] &
+ KXTI9_CTRL1_GSEL_M) >> KXTI9_CTRL1_GSEL_S);
+ psInst->ui8Resolution =
+ ((psInst->uCommand.sReadModifyWriteState.pui8Buffer[1] &
+ KXTI9_CTRL1_RES) >> 6);
+ }
+
+ //
+ // The state machine is now idle.
+ //
+ psInst->ui8State = KXTI9_STATE_IDLE;
+ break;
+ }
+ }
+
+ //
+ // See if the state machine is now idle and there is a callback function.
+ //
+ if((psInst->ui8State == KXTI9_STATE_IDLE) && psInst->pfnCallback)
+ {
+ //
+ // Call the application-supplied callback function.
+ //s
+ psInst->pfnCallback(psInst->pvCallbackData, ui8Status);
+ }
+}
+
+//*****************************************************************************
+//
+//! Initializes the KXTI9 driver.
+//!
+//! \param psInst is a pointer to the KXTI9 instance data.
+//! \param psI2CInst is a pointer to the I2C master driver instance data.
+//! \param ui8I2CAddr is the I2C address of the KXTI9 device.
+//! \param pfnCallback is the function to be called when the initialization has
+//! completed (can be \b NULL if a callback is not required).
+//! \param pvCallbackData is a pointer that is passed to the callback function.
+//!
+//! This function initializes the KXTI9 driver, preparing it for operation.
+//!
+//! \return Returns 1 if the KXTI9 driver was successfully initialized and 0
+//! if it was not.
+//
+//*****************************************************************************
+uint_fast8_t
+KXTI9Init(tKXTI9 *psInst, tI2CMInstance *psI2CInst, uint_fast8_t ui8I2CAddr,
+ tSensorCallback *pfnCallback, void *pvCallbackData)
+{
+ //
+ // Initialize the KXTI9 instance structure.
+ //
+ psInst->psI2CInst = psI2CInst;
+ psInst->ui8Addr = ui8I2CAddr;
+ psInst->ui8State = KXTI9_STATE_INIT_RES;
+ psInst->ui8Resolution = 0;
+ psInst->ui8NewResolution = 0;
+ psInst->ui8Range = KXTI9_CTRL1_GSEL_2G >> KXTI9_CTRL1_GSEL_S;
+ psInst->ui8NewRange = KXTI9_CTRL1_GSEL_2G >> KXTI9_CTRL1_GSEL_S;
+
+ //
+ // Save the callback information.
+ //
+ psInst->pfnCallback = pfnCallback;
+ psInst->pvCallbackData = pvCallbackData;
+
+ //
+ // Write the EE_W bit of CTRL_REG0 (allowing the configuration registers to
+ // be modified).
+ //
+ psInst->pui8Data[0] = KXTI9_O_CTRL3;
+ psInst->pui8Data[1] = KXTI9_CTRL3_SRST;
+ if(I2CMWrite(psInst->psI2CInst, ui8I2CAddr, psInst->pui8Data, 2,
+ KXTI9Callback, psInst) == 0)
+ {
+ //
+ // The I2C write failed, so move to the idle state and return a
+ // failure.
+ //
+ psInst->ui8State = KXTI9_STATE_IDLE;
+ return(0);
+ }
+
+ //
+ // Success.
+ //
+ return(1);
+}
+
+//*****************************************************************************
+//
+//! Reads data from KXTI9 registers.
+//!
+//! \param psInst is a pointer to the KXTI9 instance data.
+//! \param ui8Reg is the first register to read.
+//! \param pui8Data is a pointer to the location to store the data that is
+//! read.
+//! \param ui16Count is the number of data bytes to read.
+//! \param pfnCallback is the function to be called when the data has been read
+//! (can be \b NULL if a callback is not required).
+//! \param pvCallbackData is a pointer that is passed to the callback function.
+//!
+//! This function reads a sequence of data values from consecutive registers in
+//! the KXTI9.
+//!
+//! \return Returns 1 if the write was successfully started and 0 if it was
+//! not.
+//
+//*****************************************************************************
+uint_fast8_t
+KXTI9Read(tKXTI9 *psInst, uint_fast8_t ui8Reg, uint8_t *pui8Data,
+ uint_fast16_t ui16Count, tSensorCallback *pfnCallback,
+ void *pvCallbackData)
+{
+ //
+ // Return a failure if the KXTI9 driver is not idle (in other words, there
+ // is already an outstanding request to the KXTI9).
+ //
+ if(psInst->ui8State != KXTI9_STATE_IDLE)
+ {
+ return(0);
+ }
+
+ //
+ // Save the callback information.
+ //
+ psInst->pfnCallback = pfnCallback;
+ psInst->pvCallbackData = pvCallbackData;
+
+ //
+ // Move the state machine to the wait for read state.
+ //
+ psInst->ui8State = KXTI9_STATE_READ;
+
+ //
+ // Read the requested registers from the KXTI9.
+ //
+ psInst->uCommand.pui8Buffer[0] = ui8Reg;
+ if(I2CMRead(psInst->psI2CInst, psInst->ui8Addr,
+ psInst->uCommand.pui8Buffer, 1, pui8Data, ui16Count,
+ KXTI9Callback, psInst) == 0)
+ {
+ //
+ // The I2C write failed, so move to the idle state and return a
+ // failure.
+ //
+ psInst->ui8State = KXTI9_STATE_IDLE;
+ return(0);
+ }
+
+ //
+ // Success.
+ //
+ return(1);
+}
+
+//*****************************************************************************
+//
+//! Writes data to KXTI9 registers.
+//!
+//! \param psInst is a pointer to the KXTI9 instance data.
+//! \param ui8Reg is the first register to write.
+//! \param pui8Data is a pointer to the data to write.
+//! \param ui16Count is the number of data bytes to write.
+//! \param pfnCallback is the function to be called when the data has been
+//! written (can be \b NULL if a callback is not required).
+//! \param pvCallbackData is a pointer that is passed to the callback function.
+//!
+//! This function writes a sequence of data values to consecutive registers in
+//! the KXTI9. The first byte of the \e pui8Data buffer contains the value to
+//! be written into the \e ui8Reg register, the second value contains the data
+//! to be written into the next register, and so on.
+//!
+//! \return Returns 1 if the write was successfully started and 0 if it was
+//! not.
+//
+//*****************************************************************************
+uint_fast8_t
+KXTI9Write(tKXTI9 *psInst, uint_fast8_t ui8Reg, uint8_t *pui8Data,
+ uint_fast16_t ui16Count, tSensorCallback *pfnCallback,
+ void *pvCallbackData)
+{
+ //
+ // Return a failure if the KXTI9 driver is not idle (in other words, there
+ // is already an outstanding request to the KXTI9).
+ //
+ if(psInst->ui8State != KXTI9_STATE_IDLE)
+ {
+ return(0);
+ }
+
+ //
+ // Save the callback information.
+ //
+ psInst->pfnCallback = pfnCallback;
+ psInst->pvCallbackData = pvCallbackData;
+
+ psInst->ui8NewRange = psInst->ui8Range;
+ psInst->ui8NewResolution = psInst->ui8Resolution;
+
+ //
+ // See if the CTRL3 register is being written.
+ //
+ if((ui8Reg <= KXTI9_O_CTRL3) &&
+ ((ui8Reg + ui16Count) > KXTI9_O_CTRL3))
+ {
+ //
+ // See if a soft reset is being requested.
+ //
+ if(pui8Data[ui8Reg - KXTI9_O_CTRL3] & KXTI9_CTRL3_SRST)
+ {
+ //
+ // Default range setting is +/- 2 g.
+ //
+ psInst->ui8NewRange = 0;
+
+ //
+ // Default resolution is 8-bit.
+ //
+ psInst->ui8NewResolution = 0;
+ }
+ }
+
+ //
+ // See if the CTRL1 register is being written.
+ //
+ if((ui8Reg <= KXTI9_O_CTRL1) &&
+ ((ui8Reg + ui16Count) > KXTI9_O_CTRL1))
+ {
+ //
+ // Extract the range and resolution the register value.
+ //
+ psInst->ui8NewRange =
+ ((pui8Data[ui8Reg - KXTI9_O_CTRL1] & KXTI9_CTRL1_GSEL_M)
+ >> KXTI9_CTRL1_GSEL_S);
+ psInst->ui8NewResolution =
+ ((pui8Data[ui8Reg - KXTI9_O_CTRL1] & KXTI9_CTRL1_RES) >> 6);
+ }
+
+ //
+ // Save the details of this write.
+ //
+ psInst->uCommand.sWriteState.pui8Data = pui8Data;
+ psInst->uCommand.sWriteState.ui16Count = ui16Count;
+
+ //
+ // Move the state machine to the wait for write state.
+ //
+ psInst->ui8State = KXTI9_STATE_WRITE;
+
+ //
+ // Write the requested registers to the KXTI9.
+ //
+ pui8Data[0] = ui8Reg;
+ if(I2CMWrite(psInst->psI2CInst, psInst->ui8Addr, pui8Data, ui16Count + 1,
+ KXTI9Callback, psInst) == 0)
+ {
+ //
+ // The I2C write failed, so move to the idle state and return a
+ // failure.
+ //
+ psInst->ui8State = KXTI9_STATE_IDLE;
+ return(0);
+ }
+
+ //
+ // Success.
+ //
+ return(1);
+}
+
+//*****************************************************************************
+//
+//! Performs a read-modify-write of a KXTI9 register.
+//!
+//! \param psInst is a pointer to the KXTI9 instance data.
+//! \param ui8Reg is the register to modify.
+//! \param ui8Mask is the bit mask that is ANDed with the current register
+//! value.
+//! \param ui8Value is the bit mask that is ORed with the result of the AND
+//! operation.
+//! \param pfnCallback is the function to be called when the data has been
+//! changed (can be \b NULL if a callback is not required).
+//! \param pvCallbackData is a pointer that is passed to the callback function.
+//!
+//! This function changes the value of a register in the KXTI9 via a
+//! read-modify-write operation, allowing one of the fields to be changed
+//! without disturbing the other fields. The \e ui8Reg register is read, ANDed
+//! with \e ui8Mask, ORed with \e ui8Value, and then written back to the
+//! KXTI9.
+//!
+//! \return Returns 1 if the read-modify-write was successfully started and 0
+//! if it was not.
+//
+//*****************************************************************************
+uint_fast8_t
+KXTI9ReadModifyWrite(tKXTI9 *psInst, uint_fast8_t ui8Reg,
+ uint_fast8_t ui8Mask, uint_fast8_t ui8Value,
+ tSensorCallback *pfnCallback, void *pvCallbackData)
+{
+ //
+ // Return a failure if the KXTI9 driver is not idle (in other words, there
+ // is already an outstanding request to the KXTI9).
+ //
+ if(psInst->ui8State != KXTI9_STATE_IDLE)
+ {
+ return(0);
+ }
+
+ //
+ // Save the callback information.
+ //
+ psInst->pfnCallback = pfnCallback;
+ psInst->pvCallbackData = pvCallbackData;
+
+ //
+ // Move the state machine to the wait for read-modify-write state.
+ //
+ psInst->ui8State = KXTI9_STATE_RMW;
+
+ //
+ // Submit the read-modify-write request to the KXTI9.
+ //
+ if(I2CMReadModifyWrite8(&(psInst->uCommand.sReadModifyWriteState),
+ psInst->psI2CInst, psInst->ui8Addr, ui8Reg,
+ ui8Mask, ui8Value, KXTI9Callback, psInst) == 0)
+ {
+ //
+ // The I2C read-modify-write failed, so move to the idle state and
+ // return a failure.
+ //
+ psInst->ui8State = KXTI9_STATE_IDLE;
+ return(0);
+ }
+
+ //
+ // Success.
+ //
+ return(1);
+}
+
+//*****************************************************************************
+//
+//! Reads the acceleration and temperature data from the KXTI9.
+//!
+//! \param psInst is a pointer to the KXTI9 instance data.
+//! \param pfnCallback is the function to be called when the data has been read
+//! (can be \b NULL if a callback is not required).
+//! \param pvCallbackData is a pointer that is passed to the callback function.
+//!
+//! This function initiates a read of the KXTI9 data registers. When the read
+//! has completed (as indicated by calling the callback function), the new
+//! readings can be obtained via:
+//!
+//! - KXTI9DataAccelGetRaw()
+//! - KXTI9DataAccelGetFloat()
+//! - KXTI9DataTemperatureGetRaw()
+//! - KXTI9DataTemperatureGetFloat()
+//!
+//! \return Returns 1 if the read was successfully started and 0 if it was not.
+//
+//*****************************************************************************
+uint_fast8_t
+KXTI9DataRead(tKXTI9 *psInst, tSensorCallback *pfnCallback,
+ void *pvCallbackData)
+{
+ //
+ // Return a failure if the KXTI9 driver is not idle (in other words, there
+ // is already an outstanding request to the KXTI9).
+ //
+ if(psInst->ui8State != KXTI9_STATE_IDLE)
+ {
+ return(0);
+ }
+
+ //
+ // Save the callback information.
+ //
+ psInst->pfnCallback = pfnCallback;
+ psInst->pvCallbackData = pvCallbackData;
+
+ //
+ // Move the state machine to the wait for data read state.
+ //
+ psInst->ui8State = KXTI9_STATE_READ;
+
+ //
+ // Read the data registers from the KXTI9.
+ //
+ psInst->pui8Data[0] = KXTI9_O_XOUT_L;
+ if(I2CMRead(psInst->psI2CInst, psInst->ui8Addr, psInst->pui8Data, 1,
+ psInst->pui8Data, 6, KXTI9Callback, psInst) == 0)
+ {
+ //
+ // The I2C read failed, so move to the idle state and return a failure.
+ //
+ psInst->ui8State = KXTI9_STATE_IDLE;
+ return(0);
+ }
+
+ //
+ // Success.
+ //
+ return(1);
+}
+
+//*****************************************************************************
+//
+//! Gets the raw acceleration data from the most recent data read.
+//!
+//! \param psInst is a pointer to the KXTI9 instance data.
+//! \param pui16AccelX is a pointer to the value into which the raw X-axis
+//! acceleration data is stored.
+//! \param pui16AccelY is a pointer to the value into which the raw Y-axis
+//! acceleration data is stored.
+//! \param pui16AccelZ is a pointer to the value into which the raw Z-axis
+//! acceleration data is stored.
+//!
+//! This function returns the raw acceleration data from the most recent data
+//! read. The data is not manipulated in any way by the driver. If any of the
+//! output data pointers are \b NULL, the corresponding data is not provided.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+KXTI9DataAccelGetRaw(tKXTI9 *psInst, uint_fast16_t *pui16AccelX,
+ uint_fast16_t *pui16AccelY, uint_fast16_t *pui16AccelZ)
+{
+ //
+ // Return the raw acceleration values.
+ //
+ if(pui16AccelX)
+ {
+ *pui16AccelX = ((psInst->pui8Data[1] << 4) |
+ (psInst->pui8Data[0] >> 4));
+ }
+ if(pui16AccelY)
+ {
+ *pui16AccelY = ((psInst->pui8Data[3] << 4) |
+ (psInst->pui8Data[2] >> 4));
+ }
+ if(pui16AccelZ)
+ {
+ *pui16AccelZ = ((psInst->pui8Data[5] << 4) |
+ (psInst->pui8Data[4] >> 4));
+ }
+}
+
+//*****************************************************************************
+//
+//! Gets the acceleration data from the most recent data read.
+//!
+//! \param psInst is a pointer to the KXTI9 instance data.
+//! \param pfAccelX is a pointer to the value into which the X-axis
+//! acceleration data is stored.
+//! \param pfAccelY is a pointer to the value into which the Y-axis
+//! acceleration data is stored.
+//! \param pfAccelZ is a pointer to the value into which the Z-axis
+//! acceleration data is stored.
+//!
+//! This function returns the acceleration data from the most recent data read,
+//! converted into g. If any of the output data pointers are \b NULL, the
+//! corresponding data is not provided.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+KXTI9DataAccelGetFloat(tKXTI9 *psInst, float *pfAccelX, float *pfAccelY,
+ float *pfAccelZ)
+{
+ float fFactor;
+ int16_t iX, iY, iZ;
+
+ //
+ // Get the acceleration conversion factor for the current range.
+ //
+ fFactor = (psInst->ui8Resolution == 0) ? g_fAccelFactors8[psInst->ui8Range] :
+ g_fAccelFactors12[psInst->ui8Range];
+
+ if(psInst->ui8Resolution)
+ {
+ //
+ // Get conversion data and store in temporary variables.
+ //
+ iX = (int16_t)((psInst->pui8Data[1] << 4) | (psInst->pui8Data[0] >> 4));
+ iY = (int16_t)((psInst->pui8Data[3] << 4) | (psInst->pui8Data[2] >> 4));
+ iZ = (int16_t)((psInst->pui8Data[5] << 4) | (psInst->pui8Data[4] >> 4));
+
+ //
+ // Sign extend 12-bit data.
+ //
+ iX |= (iX & 0x800) ? 0xf000 : 0;
+ iY |= (iY & 0x800) ? 0xf000 : 0;
+ iZ |= (iZ & 0x800) ? 0xf000 : 0;
+ }
+ else
+ {
+ //
+ // Chop off the lower 4 bits of the data. 8-bit mode only returns 8
+ // valid bits, but can have garbage in the lower 4.
+ //
+ iX = (int16_t)(psInst->pui8Data[1]);
+ iY = (int16_t)(psInst->pui8Data[3]);
+ iZ = (int16_t)(psInst->pui8Data[5]);
+
+ //
+ // Sign extend 8-bit data.
+ //
+ iX |= (iX & 0x80) ? 0xff00 : 0;
+ iY |= (iY & 0x80) ? 0xff00 : 0;
+ iZ |= (iZ & 0x80) ? 0xff00 : 0;
+ }
+
+ //
+ // Convert the acceleration values into floating-point g values.
+ //
+ if(pfAccelX)
+ {
+ *pfAccelX = (float)(iX) * fFactor;
+ }
+ if(pfAccelY)
+ {
+ *pfAccelY = (float)(iY) * fFactor;
+ }
+ if(pfAccelZ)
+ {
+ *pfAccelZ = (float)(iZ) * fFactor;
+ }
+}
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
diff --git a/sensorlib/kxti9.h b/sensorlib/kxti9.h
new file mode 100644
index 0000000..1c8e7fc
--- /dev/null
+++ b/sensorlib/kxti9.h
@@ -0,0 +1,170 @@
+//*****************************************************************************
+//
+// KXTI9.h - Prototypes for the KXTI9 accelerometer driver.
+//
+// Copyright (c) 2012-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
+//
+//*****************************************************************************
+
+#ifndef __SENSORLIB_KXTI9_H__
+#define __SENSORLIB_KXTI9_H__
+
+//*****************************************************************************
+//
+// If building with a C++ compiler, make all of the definitions in this header
+// have a C binding.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+//*****************************************************************************
+//
+// The structure that defines the internal state of the KXTI9 driver.
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ // The pointer to the I2C master interface instance used to communicate
+ // with the KXTI9.
+ //
+ tI2CMInstance *psI2CInst;
+
+ //
+ // The I2C address of the KXTI9.
+ //
+ uint8_t ui8Addr;
+
+ //
+ // The state of the state machine used while accessing the KXTI9.
+ //
+ uint8_t ui8State;
+
+ //
+ // The ADC resolution of the KXTI9.
+ //
+ uint8_t ui8Resolution;
+
+ uint8_t ui8NewResolution;
+
+ //
+ // The current operating range (g force) of the KXTI9.
+ //
+ uint8_t ui8Range;
+
+ uint8_t ui8NewRange;
+
+ //
+ // The data buffer used for sending/receiving data to/from the KXTI9.
+ //
+ uint8_t pui8Data[7];
+
+ //
+ // The function that is called when the current request has completed
+ // processing.
+ //
+ tSensorCallback *pfnCallback;
+
+ //
+ // The pointer provided to the callback function.
+ //
+ void *pvCallbackData;
+
+ //
+ // A union of structures that are used for read, write and
+ // read-modify-write operations. Since only one operation can be active at
+ // a time, it is safe to re-use the memory in this manner.
+ //
+ union
+ {
+ //
+ // A buffer used to store the write portion of a register read.
+ //
+ uint8_t pui8Buffer[2];
+
+ //
+ // The write state used to write register values.
+ //
+ struct
+ {
+ //
+ // The buffer that is being written to the KXTI9.
+ //
+ uint8_t *pui8Data;
+
+ //
+ // The number of bytes being written to the KXTI9.
+ //
+ uint16_t ui16Count;
+ }
+ sWriteState;
+
+ //
+ // The read-modify-write state used to modify register values.
+ //
+ tI2CMReadModifyWrite8 sReadModifyWriteState;
+ }
+ uCommand;
+}
+tKXTI9;
+
+//*****************************************************************************
+//
+// Function prototypes.
+//
+//*****************************************************************************
+extern uint_fast8_t KXTI9Init(tKXTI9 *psInst, tI2CMInstance *psI2CInst,
+ uint_fast8_t ui8I2CAddr,
+ tSensorCallback *pfnCallback,
+ void *pvCallbackData);
+extern uint_fast8_t KXTI9Read(tKXTI9 *psInst, uint_fast8_t ui8Reg,
+ uint8_t *pui8Data, uint_fast16_t ui16Count,
+ tSensorCallback *pfnCallback,
+ void *pvCallbackData);
+extern uint_fast8_t KXTI9Write(tKXTI9 *psInst, uint_fast8_t ui8Reg,
+ uint8_t *pui8Data, uint_fast16_t ui16Count,
+ tSensorCallback *pfnCallback,
+ void *pvCallbackData);
+extern uint_fast8_t KXTI9ReadModifyWrite(tKXTI9 *psInst, uint_fast8_t ui8Reg,
+ uint_fast8_t ui8Mask,
+ uint_fast8_t ui8Value,
+ tSensorCallback *pfnCallback,
+ void *pvCallbackData);
+extern uint_fast8_t KXTI9DataRead(tKXTI9 *psInst,
+ tSensorCallback *pfnCallback,
+ void *pvCallbackData);
+extern void KXTI9DataAccelGetRaw(tKXTI9 *psInst, uint_fast16_t *pui16AccelX,
+ uint_fast16_t *pui16AccelY,
+ uint_fast16_t *pui16AccelZ);
+extern void KXTI9DataAccelGetFloat(tKXTI9 *psInst, float *pfAccelX,
+ float *pfAccelY, float *pfAccelZ);
+
+//*****************************************************************************
+//
+// Mark the end of the C bindings section for C++ compilers.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __SENSORLIB_KXTI9_H__
diff --git a/sensorlib/l3gd20h.c b/sensorlib/l3gd20h.c
new file mode 100644
index 0000000..6694660
--- /dev/null
+++ b/sensorlib/l3gd20h.c
@@ -0,0 +1,722 @@
+//*****************************************************************************
+//
+// l3gd20h.c - Driver for the ST L3GD20H gyroscope.
+//
+// Copyright (c) 2013-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
+//
+//*****************************************************************************
+
+#include <stdint.h>
+#include "sensorlib/hw_l3gd20h.h"
+#include "sensorlib/i2cm_drv.h"
+#include "sensorlib/l3gd20h.h"
+
+//*****************************************************************************
+//
+//! \addtogroup l3gd20h_api
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// The states of the L3GD20H state machine.
+//
+//*****************************************************************************
+#define L3GD20H_STATE_IDLE 0 // State machine is idle
+#define L3GD20H_STATE_INIT_RES 1 // Waiting for initialization
+#define L3GD20H_STATE_INIT_WAIT 2 // Waiting for reset to complete
+#define L3GD20H_STATE_READ 3 // Waiting for read
+#define L3GD20H_STATE_WRITE 4 // Waiting for write
+#define L3GD20H_STATE_RMW 5 // Waiting for read-modify-write
+
+//*****************************************************************************
+//
+// The factors used to convert the gyroscope readings from the L3GD20H into
+// floating point values in radians per second.
+//
+// Per the data-sheet, the sensitivity is 8.75, 17.50, and 70.00 mdps/digit for
+// for 245, 500, and 2000 DPS scales respectively.
+//
+// mdeg 1 deg PI rad
+// 8.75 ---- * ---- * --- = 1.5271630955e-4f rad/sec per digit
+// sec 1000 mdeg 180 deg
+//
+// Values are obtained by taking the degree per second conversion factors
+// from the data sheet and then converting to radians per sec (1 degree =
+// 0.0174532925 radians).
+//
+//*****************************************************************************
+static const float g_pfL3GD20HGyroFactors[] =
+{
+ 1.5271631e-5f, // Range = +/- 245 dps
+ 3.0543262e-4f, // Range = +/- 500 dps
+ 1.2217305e-3f, // Range = +/- 2000 dps
+ 1.2217305e-3f // Range = +/- 2000 dps
+};
+
+//*****************************************************************************
+//
+// The callback function that is called when I2C transations to/from the
+// L3GD20H have completed.
+//
+//*****************************************************************************
+static void
+L3GD20HCallback(void *pvCallbackData, uint_fast8_t ui8Status)
+{
+ tL3GD20H *psInst;
+
+ //
+ // Convert the instance data into a pointer to a tL3GD20H structure.
+ //
+ psInst = pvCallbackData;
+
+ //
+ // If the I2C master driver encountered a failure, force the state machine
+ // to the idle state (which will also result in a callback to propagate the
+ // error).
+ //
+ if(ui8Status != I2CM_STATUS_SUCCESS)
+ {
+ psInst->ui8State = L3GD20H_STATE_IDLE;
+ }
+
+ //
+ // Determine the current state of the L3GD20H state machine.
+ //
+ switch(psInst->ui8State)
+ {
+ //
+ // All states that trivially transition to IDLE, and all unknown
+ // states.
+ //
+ case L3GD20H_STATE_READ:
+ default:
+ {
+ //
+ // The state machine is now idle.
+ //
+ psInst->ui8State = L3GD20H_STATE_IDLE;
+
+ //
+ // Done.
+ //
+ break;
+ }
+
+ //
+ // L3GD20H Device reset was issued
+ //
+ case L3GD20H_STATE_INIT_RES:
+ {
+ //
+ // Issue a read of the status register to confirm reset is done.
+ //
+ psInst->uCommand.pui8Buffer[0] = L3GD20H_O_LOW_ODR;
+ I2CMRead(psInst->psI2CInst, psInst->ui8Addr,
+ psInst->uCommand.pui8Buffer, 1, psInst->pui8Data, 1,
+ L3GD20HCallback, psInst);
+
+ psInst->ui8State = L3GD20H_STATE_INIT_WAIT;
+
+ //
+ // Done.
+ //
+ break;
+ }
+
+ //
+ // Status register was read, check if reset is done before proceeding.
+ //
+ case L3GD20H_STATE_INIT_WAIT:
+ {
+ //
+ // Check the value read back from status to determine if device
+ // is still in reset or if it is ready.
+ //
+ if(psInst->pui8Data[0] & L3GD20H_LOW_ODR_SWRESET_M)
+ {
+ //
+ // Device still in reset so begin polling this register.
+ //
+ psInst->uCommand.pui8Buffer[0] = L3GD20H_O_LOW_ODR;
+ I2CMRead(psInst->psI2CInst, psInst->ui8Addr,
+ psInst->uCommand.pui8Buffer, 1, psInst->pui8Data, 1,
+ L3GD20HCallback, psInst);
+ }
+ else
+ {
+ //
+ // Device is out of reset, move to the idle state.
+ //
+ psInst->ui8State = L3GD20H_STATE_IDLE;
+ }
+
+ //
+ // Done.
+ //
+ break;
+ }
+
+ //
+ // A write just completed
+ //
+ case L3GD20H_STATE_WRITE:
+ {
+ //
+ // Set the gyroscope ranges to the new values. If the register was
+ // not modified, the values will be the same so this has no effect.
+ //
+ psInst->ui8GyroFsSel = psInst->ui8NewGyroFsSel;
+
+ //
+ // The state machine is now idle.
+ //
+ psInst->ui8State = L3GD20H_STATE_IDLE;
+
+ //
+ // Done.
+ //
+ break;
+ }
+
+ //
+ // A read-modify-write just completed
+ //
+ case L3GD20H_STATE_RMW:
+ {
+ //
+ // See if the PWR_MGMT_1 register was just modified.
+ //
+ if(psInst->uCommand.sReadModifyWriteState.pui8Buffer[0] ==
+ L3GD20H_O_LOW_ODR)
+ {
+ //
+ // See if a soft reset has been issued.
+ //
+ if(psInst->uCommand.sReadModifyWriteState.pui8Buffer[1] &
+ L3GD20H_LOW_ODR_SWRESET_M)
+ {
+ //
+ // Default range setting is +/- 245 degrees/s
+ //
+ psInst->ui8GyroFsSel = 0;
+ psInst->ui8NewGyroFsSel = 0;
+ }
+ }
+
+ //
+ // See if the GYRO_CONFIG register was just modified.
+ //
+ if(psInst->uCommand.sReadModifyWriteState.pui8Buffer[0] ==
+ L3GD20H_O_CTRL4)
+ {
+ //
+ // Extract the FS_SEL from the GYRO_CONFIG register value.
+ //
+ psInst->ui8GyroFsSel =
+ ((psInst->uCommand.sReadModifyWriteState.pui8Buffer[1] &
+ L3GD20H_CTRL4_FS_M) >>
+ L3GD20H_CTRL4_FS_S);
+ }
+
+ //
+ // The state machine is now idle.
+ //
+ psInst->ui8State = L3GD20H_STATE_IDLE;
+
+ //
+ // Done.
+ //
+ break;
+ }
+ }
+
+ //
+ // See if the state machine is now idle and there is a callback function.
+ //
+ if((psInst->ui8State == L3GD20H_STATE_IDLE) && psInst->pfnCallback)
+ {
+ //
+ // Call the application-supplied callback function.
+ //
+ psInst->pfnCallback(psInst->pvCallbackData, ui8Status);
+ }
+}
+
+//*****************************************************************************
+//
+//! Initializes the L3GD20H driver.
+//!
+//! \param psInst is a pointer to the L3GD20H instance data.
+//! \param psI2CInst is a pointer to the I2C master driver instance data.
+//! \param ui8I2CAddr is the I2C address of the L3GD20H device.
+//! \param pfnCallback is the function to be called when the initialization has
+//! completed (can be \b NULL if a callback is not required).
+//! \param pvCallbackData is a pointer that is passed to the callback function.
+//!
+//! This function initializes the L3GD20H driver, preparing it for operation.
+//!
+//! \return Returns 1 if the L3GD20H driver was successfully initialized and 0
+//! if it was not.
+//
+//*****************************************************************************
+uint_fast8_t
+L3GD20HInit(tL3GD20H *psInst, tI2CMInstance *psI2CInst,
+ uint_fast8_t ui8I2CAddr, tSensorCallback *pfnCallback,
+ void *pvCallbackData)
+{
+ //
+ // Initialize the L3GD20H instance structure.
+ //
+ psInst->psI2CInst = psI2CInst;
+ psInst->ui8Addr = ui8I2CAddr;
+
+ //
+ // Save the callback information.
+ //
+ psInst->pfnCallback = pfnCallback;
+ psInst->pvCallbackData = pvCallbackData;
+
+ //
+ // Default range setting is +/- 245 degrees/s
+ //
+ psInst->ui8GyroFsSel =
+ (L3GD20H_CTRL4_FS_245DPS & L3GD20H_CTRL4_FS_M) >> L3GD20H_CTRL4_FS_S;
+ psInst->ui8NewGyroFsSel =
+ (L3GD20H_CTRL4_FS_245DPS & L3GD20H_CTRL4_FS_M) >> L3GD20H_CTRL4_FS_S;
+
+ //
+ // Set the state to show we are initiating a reset.
+ //
+ psInst->ui8State = L3GD20H_STATE_INIT_RES;
+
+ //
+ // Load the buffer with command to perform device reset
+ //
+ psInst->pui8Data[0] = L3GD20H_O_LOW_ODR;
+ psInst->pui8Data[1] = L3GD20H_LOW_ODR_SWRESET_RESET;
+ if(I2CMWrite(psInst->psI2CInst, psInst->ui8Addr,
+ psInst->uCommand.pui8Buffer, 2, L3GD20HCallback, psInst) == 0)
+ {
+ psInst->ui8State = L3GD20H_STATE_IDLE;
+ return(0);
+ }
+
+ //
+ // Success
+ //
+ return(1);
+}
+
+//*****************************************************************************
+//
+//! Reads data from L3GD20H registers.
+//!
+//! \param psInst is a pointer to the L3GD20H instance data.
+//! \param ui8Reg is the first register to read.
+//! \param pui8Data is a pointer to the location to store the data that is
+//! read.
+//! \param ui16Count is the number of data bytes to read.
+//! \param pfnCallback is the function to be called when the data has been read
+//! (can be \b NULL if a callback is not required).
+//! \param pvCallbackData is a pointer that is passed to the callback function.
+//!
+//! This function reads a sequence of data values from consecutive registers in
+//! the L3GD20H.
+//!
+//! \return Returns 1 if the write was successfully started and 0 if it was
+//! not.
+//
+//*****************************************************************************
+uint_fast8_t
+L3GD20HRead(tL3GD20H *psInst, uint_fast8_t ui8Reg, uint8_t *pui8Data,
+ uint_fast16_t ui16Count, tSensorCallback *pfnCallback,
+ void *pvCallbackData)
+{
+ //
+ // Return a failure if the L3GD20H driver is not idle (in other words,
+ // there is already an outstanding request to the L3GD20H).
+ //
+ if(psInst->ui8State != L3GD20H_STATE_IDLE)
+ {
+ return(0);
+ }
+
+ //
+ // Save the callback information.
+ //
+ psInst->pfnCallback = pfnCallback;
+ psInst->pvCallbackData = pvCallbackData;
+
+ //
+ // Move the state machine to the wait for read state.
+ //
+ psInst->ui8State = L3GD20H_STATE_READ;
+
+ //
+ // Read the requested registers from the L3GD20H.
+ //
+ psInst->uCommand.pui8Buffer[0] = ui8Reg;
+ if(I2CMRead(psInst->psI2CInst, psInst->ui8Addr,
+ psInst->uCommand.pui8Buffer, 1, pui8Data, ui16Count,
+ L3GD20HCallback, psInst) == 0)
+ {
+ //
+ // The I2C write failed, so move to the idle state and return a
+ // failure.
+ //
+ psInst->ui8State = L3GD20H_STATE_IDLE;
+ return(0);
+ }
+
+ //
+ // Success.
+ //
+ return(1);
+}
+
+//*****************************************************************************
+//
+//! Writes data to L3GD20H registers.
+//!
+//! \param psInst is a pointer to the L3GD20H instance data.
+//! \param ui8Reg is the first register to write.
+//! \param pui8Data is a pointer to the data to write.
+//! \param ui16Count is the number of data bytes to write.
+//! \param pfnCallback is the function to be called when the data has been
+//! written (can be \b NULL if a callback is not required).
+//! \param pvCallbackData is a pointer that is passed to the callback function.
+//!
+//! This function writes a sequence of data values to consecutive registers in
+//! the L3GD20H. The first byte of the \e pui8Data buffer contains the value
+//! to be written into the \e ui8Reg register, the second value contains the
+//! data to be written into the next register, and so on.
+//!
+//! \return Returns 1 if the write was successfully started and 0 if it was
+//! not.
+//
+//*****************************************************************************
+uint_fast8_t
+L3GD20HWrite(tL3GD20H *psInst, uint_fast8_t ui8Reg, const uint8_t *pui8Data,
+ uint_fast16_t ui16Count, tSensorCallback *pfnCallback,
+ void *pvCallbackData)
+{
+ //
+ // Return a failure if the L3GD20H driver is not idle (in other words,
+ // there is already an outstanding request to the L3GD20H).
+ //
+ if(psInst->ui8State != L3GD20H_STATE_IDLE)
+ {
+ return(0);
+ }
+
+ //
+ // Save the callback information.
+ //
+ psInst->pfnCallback = pfnCallback;
+ psInst->pvCallbackData = pvCallbackData;
+
+ //
+ // See if the PWR_MGMT_1 register is being written.
+ //
+ if((ui8Reg <= L3GD20H_O_LOW_ODR) &&
+ ((ui8Reg + ui16Count) > L3GD20H_O_LOW_ODR))
+ {
+ //
+ // See if a soft reset is being requested.
+ //
+ if(pui8Data[ui8Reg - L3GD20H_O_LOW_ODR] & L3GD20H_LOW_ODR_SWRESET_M)
+ {
+ //
+ // Default range setting is +/- 245 degrees/s.
+ //
+ psInst->ui8NewGyroFsSel = 0;
+ }
+ }
+
+ //
+ // See if the GYRO_CONFIG register is being written.
+ //
+ if((ui8Reg <= L3GD20H_O_CTRL4) &&
+ ((ui8Reg + ui16Count) > L3GD20H_O_CTRL4))
+ {
+ //
+ // Extract the FS_SEL from the GYRO_CONFIG register value.
+ //
+ psInst->ui8NewGyroFsSel = ((pui8Data[ui8Reg - L3GD20H_O_CTRL4] &
+ L3GD20H_CTRL4_FS_M) >>
+ L3GD20H_CTRL4_FS_S);
+ }
+
+ //
+ // Move the state machine to the wait for write state.
+ //
+ psInst->ui8State = L3GD20H_STATE_WRITE;
+
+ //
+ // Write the requested registers to the L3GD20H.
+ //
+ if(I2CMWrite8(&(psInst->uCommand.sWriteState), psInst->psI2CInst,
+ psInst->ui8Addr, ui8Reg, pui8Data, ui16Count,
+ L3GD20HCallback, psInst) == 0)
+ {
+ //
+ // The I2C write failed, so move to the idle state and return a
+ // failure.
+ //
+ psInst->ui8State = L3GD20H_STATE_IDLE;
+ return(0);
+ }
+
+ //
+ // Success.
+ //
+ return(1);
+}
+
+//*****************************************************************************
+//
+//! Performs a read-modify-write of a L3GD20H register.
+//!
+//! \param psInst is a pointer to the L3GD20H instance data.
+//! \param ui8Reg is the register to modify.
+//! \param ui8Mask is the bit mask that is ANDed with the current register
+//! value.
+//! \param ui8Value is the bit mask that is ORed with the result of the AND
+//! operation.
+//! \param pfnCallback is the function to be called when the data has been
+//! changed (can be \b NULL if a callback is not required).
+//! \param pvCallbackData is a pointer that is passed to the callback function.
+//!
+//! This function changes the value of a register in the L3GD20H via a
+//! read-modify-write operation, allowing one of the fields to be changed
+//! without disturbing the other fields. The \e ui8Reg register is read, ANDed
+//! with \e ui8Mask, ORed with \e ui8Value, and then written back to the
+//! L3GD20H.
+//!
+//! \return Returns 1 if the read-modify-write was successfully started and 0
+//! if it was not.
+//
+//*****************************************************************************
+uint_fast8_t
+L3GD20HReadModifyWrite(tL3GD20H *psInst, uint_fast8_t ui8Reg,
+ uint_fast8_t ui8Mask, uint_fast8_t ui8Value,
+ tSensorCallback *pfnCallback, void *pvCallbackData)
+{
+ //
+ // Return a failure if the L3GD20H driver is not idle (in other words,
+ // there is already an outstanding request to the L3GD20H).
+ //
+ if(psInst->ui8State != L3GD20H_STATE_IDLE)
+ {
+ return(0);
+ }
+
+ //
+ // Save the callback information.
+ //
+ psInst->pfnCallback = pfnCallback;
+ psInst->pvCallbackData = pvCallbackData;
+
+ //
+ // Move the state machine to the wait for read-modify-write state.
+ //
+ psInst->ui8State = L3GD20H_STATE_RMW;
+
+ //
+ // Submit the read-modify-write request to the L3GD20H.
+ //
+ if(I2CMReadModifyWrite8(&(psInst->uCommand.sReadModifyWriteState),
+ psInst->psI2CInst, psInst->ui8Addr, ui8Reg,
+ ui8Mask, ui8Value, L3GD20HCallback, psInst) == 0)
+ {
+ //
+ // The I2C read-modify-write failed, so move to the idle state and
+ // return a failure.
+ //
+ psInst->ui8State = L3GD20H_STATE_IDLE;
+ return(0);
+ }
+
+ //
+ // Success.
+ //
+ return(1);
+}
+
+//*****************************************************************************
+//
+//! Reads the gyroscope data from the L3GD20H.
+//!
+//! \param psInst is a pointer to the L3GD20H instance data.
+//! \param pfnCallback is the function to be called when the data has been read
+//! (can be \b NULL if a callback is not required).
+//! \param pvCallbackData is a pointer that is passed to the callback function.
+//!
+//! This function initiates a read of the L3GD20H data registers. When the
+//! read has completed (as indicated by calling the callback function), the new
+//! readings can be obtained via:
+//!
+//! - L3GD20HDataGyroGetRaw()
+//! - L3GD20HDataGyroGetFloat()
+//!
+//! \return Returns 1 if the read was successfully started and 0 if it was not.
+//
+//*****************************************************************************
+uint_fast8_t
+L3GD20HDataRead(tL3GD20H *psInst, tSensorCallback *pfnCallback,
+ void *pvCallbackData)
+{
+ //
+ // Return a failure if the L3GD20H driver is not idle (in other words,
+ // there is already an outstanding request to the L3GD20H).
+ //
+ if(psInst->ui8State != L3GD20H_STATE_IDLE)
+ {
+ return(0);
+ }
+
+ //
+ // Save the callback information.
+ //
+ psInst->pfnCallback = pfnCallback;
+ psInst->pvCallbackData = pvCallbackData;
+
+ //
+ // Move the state machine to the wait for data read state.
+ //
+ psInst->ui8State = L3GD20H_STATE_READ;
+
+ //
+ // Read the data registers from the L3GD20H.
+ //
+ psInst->pui8Data[0] = L3GD20H_O_STATUS | 0x80;
+ if(I2CMRead(psInst->psI2CInst, psInst->ui8Addr, psInst->pui8Data, 1,
+ psInst->pui8Data, 7, L3GD20HCallback, psInst) == 0)
+ {
+ //
+ // The I2C read failed, so move to the idle state and return a failure.
+ //
+ psInst->ui8State = L3GD20H_STATE_IDLE;
+ return(0);
+ }
+
+ //
+ // Success.
+ //
+ return(1);
+}
+
+//*****************************************************************************
+//
+//! Gets the raw gyroscope data from the most recent data read.
+//!
+//! \param psInst is a pointer to the L3GD20H instance data.
+//! \param pui16GyroX is a pointer to the value into which the raw X-axis
+//! gyroscope data is stored.
+//! \param pui16GyroY is a pointer to the value into which the raw Y-axis
+//! gyroscope data is stored.
+//! \param pui16GyroZ is a pointer to the value into which the raw Z-axis
+//! gyroscope data is stored.
+//!
+//! This function returns the raw gyroscope data from the most recent data
+//! read. The data is not manipulated in any way by the driver. If any of the
+//! output data pointers are \b NULL, the corresponding data is not provided.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+L3GD20HDataGyroGetRaw(tL3GD20H *psInst, uint_fast16_t *pui16GyroX,
+ uint_fast16_t *pui16GyroY, uint_fast16_t *pui16GyroZ)
+{
+ //
+ // Return the raw gyroscope values.
+ //
+ if(pui16GyroX)
+ {
+ *pui16GyroX = (psInst->pui8Data[2] << 8) | psInst->pui8Data[1];
+ }
+ if(pui16GyroY)
+ {
+ *pui16GyroY = (psInst->pui8Data[4] << 8) | psInst->pui8Data[3];
+ }
+ if(pui16GyroZ)
+ {
+ *pui16GyroZ = (psInst->pui8Data[6] << 8) | psInst->pui8Data[5];
+ }
+}
+
+//*****************************************************************************
+//
+//! Gets the gyroscope data from the most recent data read.
+//!
+//! \param psInst is a pointer to the L3GD20H instance data.
+//! \param pfGyroX is a pointer to the value into which the X-axis gyroscope
+//! data is stored.
+//! \param pfGyroY is a pointer to the value into which the Y-axis gyroscope
+//! data is stored.
+//! \param pfGyroZ is a pointer to the value into which the Z-axis gyroscope
+//! data is stored.
+//!
+//! This function returns the gyroscope data from the most recent data read,
+//! converted into radians per second. If any of the output data pointers are
+//! \b NULL, the corresponding data is not provided.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+L3GD20HDataGyroGetFloat(tL3GD20H *psInst, float *pfGyroX, float *pfGyroY,
+ float *pfGyroZ)
+{
+ float fFactor;
+
+ //
+ // Get the conversion factor for the current data format.
+ //
+ fFactor = g_pfL3GD20HGyroFactors[psInst->ui8GyroFsSel];
+
+ //
+ // Convert the gyroscope values into rad/sec.
+ //
+ if(pfGyroX)
+ {
+ *pfGyroX = ((float)(int16_t)((psInst->pui8Data[2] << 8) |
+ psInst->pui8Data[1]) * fFactor);
+ }
+ if(pfGyroY)
+ {
+ *pfGyroY = ((float)(int16_t)((psInst->pui8Data[4] << 8) |
+ psInst->pui8Data[3]) * fFactor);
+ }
+ if(pfGyroZ)
+ {
+ *pfGyroZ = ((float)(int16_t)((psInst->pui8Data[6] << 8) |
+ psInst->pui8Data[5]) * fFactor);
+ }
+}
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
diff --git a/sensorlib/l3gd20h.h b/sensorlib/l3gd20h.h
new file mode 100644
index 0000000..c56bf36
--- /dev/null
+++ b/sensorlib/l3gd20h.h
@@ -0,0 +1,158 @@
+//*****************************************************************************
+//
+// l3gd20h.c - Driver for the ST L3GD20H gyroscope.
+//
+// Copyright (c) 2013-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
+//
+//*****************************************************************************
+
+#ifndef __SENSORLIB_L3GD20H_H__
+#define __SENSORLIB_L3GD20H_H__
+
+//*****************************************************************************
+//
+// If building with a C++ compiler, make all of the definitions in this header
+// have a C binding.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+//*****************************************************************************
+//
+// The structure that defines the internal state of the L3GD20H driver.
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ // The pointer to the I2C master interface instance used to communicate
+ // with the L3GD20H.
+ //
+ tI2CMInstance *psI2CInst;
+
+ //
+ // The I2C address of the L3GD20H.
+ //
+ uint8_t ui8Addr;
+
+ //
+ // The state of the state machine used while accessing the L3GD20H.
+ //
+ uint8_t ui8State;
+
+ //
+ // The current gyroscope fs_sel setting.
+ //
+ uint8_t ui8GyroFsSel;
+
+ //
+ // The new gyroscope fs_sel setting, which is used when a register write
+ // succeeds.
+ //
+ uint8_t ui8NewGyroFsSel;
+
+ //
+ // The data buffer used for sending/receiving data to/from the L3GD20H.
+ // We need 7 bytes (1 status + 3axis * 2bytes per axis)
+ //
+ uint8_t pui8Data[8];
+
+ //
+ // The function that is called when the current request has completed
+ // processing.
+ //
+ tSensorCallback *pfnCallback;
+
+ //
+ // The callback data provided to the callback function.
+ //
+ void *pvCallbackData;
+
+ //
+ // A union of structures that are used for read, write and
+ // read-modify-write operations. Since only one operation can be active at
+ // a time, it is safe to re-use the memory in this manner.
+ //
+ union
+ {
+ //
+ // A buffer used to store the write portion of a register read.
+ //
+ uint8_t pui8Buffer[2];
+
+ //
+ // The write state used to write register values.
+ //
+ tI2CMWrite8 sWriteState;
+
+ //
+ // The read-modify-write state used to modify register values.
+ //
+ tI2CMReadModifyWrite8 sReadModifyWriteState;
+ }
+ uCommand;
+}
+tL3GD20H;
+
+//*****************************************************************************
+//
+// Function prototypes.
+//
+//*****************************************************************************
+extern uint_fast8_t L3GD20HInit(tL3GD20H *psInst, tI2CMInstance *psI2CInst,
+ uint_fast8_t ui8I2CAddr,
+ tSensorCallback *pfnCallback,
+ void *pvCallbackData);
+extern uint_fast8_t L3GD20HRead(tL3GD20H *psInst, uint_fast8_t ui8Reg,
+ uint8_t *pui8Data, uint_fast16_t ui16Count,
+ tSensorCallback *pfnCallback,
+ void *pvCallbackData);
+extern uint_fast8_t L3GD20HWrite(tL3GD20H *psInst, uint_fast8_t ui8Reg,
+ const uint8_t *pui8Data,
+ uint_fast16_t ui16Count,
+ tSensorCallback *pfnCallback,
+ void *pvCallbackData);
+extern uint_fast8_t L3GD20HReadModifyWrite(tL3GD20H *psInst,
+ uint_fast8_t ui8Reg,
+ uint_fast8_t ui8Mask,
+ uint_fast8_t ui8Value,
+ tSensorCallback *pfnCallback,
+ void *pvCallbackData);
+extern uint_fast8_t L3GD20HDataRead(tL3GD20H *psInst,
+ tSensorCallback *pfnCallback,
+ void *pvCallbackData);
+extern void L3GD20HDataGyroGetRaw(tL3GD20H *psInst, uint_fast16_t *pui16GyroX,
+ uint_fast16_t *pui16GyroY,
+ uint_fast16_t *pui16GyroZ);
+extern void L3GD20HDataGyroGetFloat(tL3GD20H *psInst, float *pfGyroX,
+ float *pfGyroY, float *pfGyroZ);
+
+//*****************************************************************************
+//
+// Mark the end of the C bindings section for C++ compilers.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __SENSORLIB_L3GD20H_H__
diff --git a/sensorlib/lsm303d.c b/sensorlib/lsm303d.c
new file mode 100644
index 0000000..e21a5b8
--- /dev/null
+++ b/sensorlib/lsm303d.c
@@ -0,0 +1,835 @@
+//*****************************************************************************
+//
+// lsm303d.c - Driver for the ST LSM303D accelerometer/magnetometer.
+//
+// Copyright (c) 2013-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
+//
+//*****************************************************************************
+
+#include <stdint.h>
+#include "sensorlib/hw_lsm303d.h"
+#include "sensorlib/i2cm_drv.h"
+#include "sensorlib/lsm303d.h"
+
+//*****************************************************************************
+//
+//! \addtogroup lsm303dlhc_api
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// The states of the LSM303D state machine.
+//
+//*****************************************************************************
+#define LSM303D_STATE_IDLE 0 // State machine is idle
+#define LSM303D_STATE_INIT 1 // Waiting for init
+#define LSM303D_STATE_READ_MAG \
+ 2 // Waiting for mag read
+#define LSM303D_STATE_READ_ACCEL \
+ 3 // Waiting for accel read
+#define LSM303D_STATE_WRITE 4 // Waiting for write
+#define LSM303D_STATE_RMW 5 // Waiting for read-modify-write
+
+//*****************************************************************************
+//
+// The factors used to convert the acceleration readings from the LSM303D
+// into floating point values in meters per second squared.
+//
+// Values are obtained by taking the g conversion factors from the data sheet
+// and multiplying by 9.81 (1 g = 9.81 m/s^2).
+//
+//*****************************************************************************
+static const float g_pfLSM303DAccelFactors[] =
+{
+ 0.00059875, // Range = +/- 2 g (16384 lsb/g)
+ 0.00119751, // Range = +/- 4 g (8192 lsb/g)
+ 0.00239502, // Range = +/- 8 g (4096 lsb/g)
+ 0.00479004 // Range = +/- 16 g (2048 lsb/g)
+};
+static const float g_pfLSM303DMagFactors[] =
+{
+ 8.0e-6f, // Range = +/- 2 (0.080 mgauss/lsb)
+ 1.6e-5f, // Range = +/- 4 (0.160 mgauss/lsb)
+ 3.2e-5f, // Range = +/- 8 (0.320 mgauss/lsb)
+ 4.79e-5f // Range = +/- 12 (0.479 mgauss/lsb)
+};
+//
+// Uninitialized values will default to zero which is what we want. 0x80 is
+// ORed into the register address so the writes auto-increment
+//
+static const uint8_t g_pui8ZeroInit[] =
+{
+ 0x80 | LSM303D_O_MAG_INT_CTRL,
+ 0xE8, // MAG_INT_CTRL
+ 0x0, // int_src (RO)
+ 0x0, // THS_LSB
+ 0x0, // THS_MSB
+ 0x0, // OFFSET_X_LSB
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0, // REF_X
+ 0x0,
+ 0x0,
+ 0x0, // CTRL0
+ 0x7,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x18, // CTRL5
+ 0x20,
+ 0x1,
+ 0x0, // status (RO)
+ 0x0, // out_x_lsb (RO)
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0, // FIFO_CTRL
+ 0x0, // fifo_src (RO)
+ 0x0, // IG_CFG1
+ 0x0, // ig_src1 (RO)
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0, // ig_src2 (RO)
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0, // clk_src (RO)
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0
+};
+
+//*****************************************************************************
+//
+// The callback function that is called when I2C transations to/from the
+// LSM303D have completed.
+//
+//*****************************************************************************
+static void
+LSM303DCallback(void *pvCallbackData, uint_fast8_t ui8Status)
+{
+ tLSM303D *psInst;
+
+ //
+ // Convert the instance data into a pointer to a tLSM303D structure.
+ //
+ psInst = pvCallbackData;
+
+ //
+ // If the I2C master driver encountered a failure, force the state machine
+ // to the idle state (which will also result in a callback to propagate the
+ // error).
+ //
+ if(ui8Status != I2CM_STATUS_SUCCESS)
+ {
+ psInst->ui8State = LSM303D_STATE_IDLE;
+ }
+
+ //
+ // Determine the current state of the LSM303D state machine.
+ //
+ switch(psInst->ui8State)
+ {
+ //
+ // All states that trivially transition to IDLE, and all unknown
+ // states.
+ //
+ default:
+ {
+ //
+ // The state machine is now idle.
+ //
+ psInst->ui8State = LSM303D_STATE_IDLE;
+
+ //
+ // Done.
+ //
+ break;
+ }
+
+ case LSM303D_STATE_READ_MAG:
+ {
+ //
+ // Move the state machine to the wait for accel data read state.
+ //
+ psInst->ui8State = LSM303D_STATE_READ_ACCEL;
+
+ //
+ // Read the accel data registers from the LSM303D.
+ //
+ psInst->pui8DataAccel[0] = LSM303D_O_STATUS | 0x80;
+ I2CMRead(psInst->psI2CInst, psInst->ui8Addr, psInst->pui8DataAccel,
+ 1, psInst->pui8DataAccel, 7, LSM303DCallback, psInst);
+
+ //
+ // Done.
+ //
+ break;
+ }
+ case LSM303D_STATE_INIT:
+ {
+ psInst->ui8State = LSM303D_STATE_IDLE;
+
+ //
+ // Done.
+ //
+ break;
+ }
+
+ //
+ // A write just completed
+ //
+ case LSM303D_STATE_WRITE:
+ {
+ //
+ // Set the accelerometer ranges to the new values. If the register
+ // was not modified, the values will be the same so this has no
+ // effect.
+ //
+ psInst->ui8AccelFSSel = psInst->ui8NewAccelFSSel;
+ psInst->ui8MagFSSel = psInst->ui8NewMagFSSel;
+
+ //
+ // The state machine is now idle.
+ //
+ psInst->ui8State = LSM303D_STATE_IDLE;
+
+ //
+ // Done.
+ //
+ break;
+ }
+
+ //
+ // A read-modify-write just completed
+ //
+ case LSM303D_STATE_RMW:
+ {
+ //
+ // See if the accel scale register was just modified.
+ //
+ if(psInst->uCommand.sReadModifyWriteState.pui8Buffer[0] ==
+ LSM303D_O_CTRL2)
+ {
+ //
+ // Extract the FS_SEL from the ACCEL_CONFIG register value.
+ //
+ psInst->ui8AccelFSSel =
+ ((psInst->uCommand.sReadModifyWriteState.pui8Buffer[1] &
+ LSM303D_CTRL2_AFS_M) >> LSM303D_CTRL2_AFS_S);
+ }
+
+ //
+ // See if the mag scale register was just modified.
+ //
+ if(psInst->uCommand.sReadModifyWriteState.pui8Buffer[0] ==
+ LSM303D_O_CTRL6)
+ {
+ //
+ // Extract the FS_SEL from the mag scale register value.
+ //
+ psInst->ui8MagFSSel =
+ ((psInst->uCommand.sReadModifyWriteState.pui8Buffer[1] &
+ LSM303D_CTRL6_MFS_M) >> LSM303D_CTRL6_MFS_S);
+
+ }
+
+ //
+ // The state machine is now idle.
+ //
+ psInst->ui8State = LSM303D_STATE_IDLE;
+
+ //
+ // Done.
+ //
+ break;
+ }
+ }
+
+ //
+ // See if the state machine is now idle and there is a callback function.
+ //
+ if((psInst->ui8State == LSM303D_STATE_IDLE) && psInst->pfnCallback)
+ {
+ //
+ // Call the application-supplied callback function.
+ //
+ psInst->pfnCallback(psInst->pvCallbackData, ui8Status);
+ }
+}
+
+//*****************************************************************************
+//
+//! Initializes the LSM303D driver.
+//!
+//! \param psInst is a pointer to the LSM303D instance data.
+//! \param psI2CInst is a pointer to the I2C master driver instance data.
+//! \param ui8I2CAddr is the I2C address of the LSM303D device.
+//! \param pfnCallback is the function to be called when the initialization has
+//! completed (can be \b NULL if a callback is not required).
+//! \param pvCallbackData is a pointer that is passed to the callback function.
+//!
+//! This function initializes the LSM303D driver, preparing it for
+//! operation.
+//!
+//! \return Returns 1 if the LSM303D driver was successfully initialized and
+//! 0 if it was not.
+//
+//*****************************************************************************
+uint_fast8_t
+LSM303DInit(tLSM303D *psInst, tI2CMInstance *psI2CInst,
+ uint_fast8_t ui8I2CAddr, tSensorCallback *pfnCallback,
+ void *pvCallbackData)
+{
+ //
+ // Initialize the LSM303D instance structure.
+ //
+ psInst->psI2CInst = psI2CInst;
+ psInst->ui8Addr = ui8I2CAddr;
+
+ //
+ // Save the callback information.
+ //
+ psInst->pfnCallback = pfnCallback;
+ psInst->pvCallbackData = pvCallbackData;
+
+ //
+ // Default range setting is +/- 2 g
+ //
+ psInst->ui8AccelFSSel = (LSM303D_CTRL2_AFS_2G >> LSM303D_CTRL2_AFS_S);
+ psInst->ui8NewAccelFSSel = (LSM303D_CTRL2_AFS_2G >> LSM303D_CTRL2_AFS_S);
+ psInst->ui8MagFSSel = (LSM303D_CTRL6_MFS_2G >> LSM303D_CTRL6_MFS_S);
+ psInst->ui8NewMagFSSel = (LSM303D_CTRL6_MFS_2G >> LSM303D_CTRL6_MFS_S);
+
+ //
+ // There is no soft reset on the LSM303. Force registers back to their
+ // spec'ed POR defaults.
+ //
+ psInst->ui8State = LSM303D_STATE_INIT;
+ if(I2CMWrite(psInst->psI2CInst, psInst->ui8Addr, g_pui8ZeroInit,
+ sizeof(g_pui8ZeroInit), LSM303DCallback, (void *)psInst) == 0)
+ {
+ psInst->ui8State = LSM303D_STATE_IDLE;
+ return(0);
+ }
+
+ //
+ // Success
+ //
+ return(1);
+}
+
+//*****************************************************************************
+//
+//! Reads data from LSM303D registers.
+//!
+//! \param psInst is a pointer to the LSM303D instance data.
+//! \param ui8Reg is the first register to read.
+//! \param pui8Data is a pointer to the location to store the data that is
+//! read.
+//! \param ui16Count is the number of data bytes to read.
+//! \param pfnCallback is the function to be called when the data has been read
+//! (can be \b NULL if a callback is not required).
+//! \param pvCallbackData is a pointer that is passed to the callback function.
+//!
+//! This function reads a sequence of data values from consecutive registers in
+//! the LSM303D.
+//!
+//! \return Returns 1 if the write was successfully started and 0 if it was
+//! not.
+//
+//*****************************************************************************
+uint_fast8_t
+LSM303DRead(tLSM303D *psInst, uint_fast8_t ui8Reg,
+ uint8_t *pui8Data, uint_fast16_t ui16Count,
+ tSensorCallback *pfnCallback, void *pvCallbackData)
+{
+ //
+ // Return a failure if the LSM303D driver is not idle (in other words,
+ // there is already an outstanding request to the LSM303D).
+ //
+ if(psInst->ui8State != LSM303D_STATE_IDLE)
+ {
+ return(0);
+ }
+
+ //
+ // Save the callback information.
+ //
+ psInst->pfnCallback = pfnCallback;
+ psInst->pvCallbackData = pvCallbackData;
+
+ //
+ // Move the state machine to the wait for read state.
+ //
+ psInst->ui8State = LSM303D_STATE_READ_MAG;
+
+ //
+ // Read the requested registers from the LSM303D.
+ //
+ psInst->uCommand.pui8Buffer[0] = ui8Reg;
+ if(I2CMRead(psInst->psI2CInst, psInst->ui8Addr,
+ psInst->uCommand.pui8Buffer, 1, pui8Data, ui16Count,
+ LSM303DCallback, psInst) == 0)
+ {
+ //
+ // The I2C write failed, so move to the idle state and return a
+ // failure.
+ //
+ psInst->ui8State = LSM303D_STATE_IDLE;
+ return(0);
+ }
+
+ //
+ // Success.
+ //
+ return(1);
+}
+
+//*****************************************************************************
+//
+//! Writes data to LSM303D registers.
+//!
+//! \param psInst is a pointer to the LSM303D instance data.
+//! \param ui8Reg is the first register to write.
+//! \param pui8Data is a pointer to the data to write.
+//! \param ui16Count is the number of data bytes to write.
+//! \param pfnCallback is the function to be called when the data has been
+//! written (can be \b NULL if a callback is not required).
+//! \param pvCallbackData is a pointer that is passed to the callback function.
+//!
+//! This function writes a sequence of data values to consecutive registers in
+//! the LSM303D. The first byte of the \e pui8Data buffer contains the
+//! value to be written into the \e ui8Reg register, the second value contains
+//! the data to be written into the next register, and so on.
+//!
+//! \return Returns 1 if the write was successfully started and 0 if it was
+//! not.
+//
+//*****************************************************************************
+uint_fast8_t
+LSM303DWrite(tLSM303D *psInst, uint_fast8_t ui8Reg,
+ const uint8_t *pui8Data, uint_fast16_t ui16Count,
+ tSensorCallback *pfnCallback, void *pvCallbackData)
+{
+ //
+ // Return a failure if the LSM303D driver is not idle (in other words,
+ // there is already an outstanding request to the LSM303D).
+ //
+ if(psInst->ui8State != LSM303D_STATE_IDLE)
+ {
+ return(0);
+ }
+
+ //
+ // Save the callback information.
+ //
+ psInst->pfnCallback = pfnCallback;
+ psInst->pvCallbackData = pvCallbackData;
+
+ //
+ // See if the accel full scale select register is being written.
+ //
+ if((ui8Reg <= LSM303D_O_CTRL2) &&
+ ((ui8Reg + ui16Count) > LSM303D_O_CTRL2))
+ {
+ //
+ // Extract the AFS_SEL from the ACCEL_CONFIG register value.
+ //
+ psInst->ui8NewAccelFSSel =
+ ((pui8Data[ui8Reg - LSM303D_O_CTRL2] &
+ LSM303D_CTRL2_AFS_M) >> LSM303D_CTRL2_AFS_S);
+ }
+
+ //
+ // See if the mag full scale select register is being written.
+ //
+ if((ui8Reg <= LSM303D_O_CTRL6) &&
+ ((ui8Reg + ui16Count) > LSM303D_O_CTRL6))
+ {
+ //
+ // Extract the AFS_SEL from the ACCEL_CONFIG register value.
+ //
+ psInst->ui8NewMagFSSel =
+ ((pui8Data[ui8Reg - LSM303D_O_CTRL6] &
+ LSM303D_CTRL6_MFS_M) >> LSM303D_CTRL6_MFS_S);
+ }
+
+ //
+ // Move the state machine to the wait for write state.
+ //
+ psInst->ui8State = LSM303D_STATE_WRITE;
+
+ //
+ // Write the requested registers to the LSM303D.
+ //
+ if(I2CMWrite8(&(psInst->uCommand.sWriteState), psInst->psI2CInst,
+ psInst->ui8Addr, ui8Reg, pui8Data, ui16Count,
+ LSM303DCallback, psInst) == 0)
+ {
+ //
+ // The I2C write failed, so move to the idle state and return a
+ // failure.
+ //
+ psInst->ui8State = LSM303D_STATE_IDLE;
+ return(0);
+ }
+
+ //
+ // Success.
+ //
+ return(1);
+}
+
+//*****************************************************************************
+//
+//! Performs a read-modify-write of a LSM303D register.
+//!
+//! \param psInst is a pointer to the LSM303D instance data.
+//! \param ui8Reg is the register to modify.
+//! \param ui8Mask is the bit mask that is ANDed with the current register
+//! value.
+//! \param ui8Value is the bit mask that is ORed with the result of the AND
+//! operation.
+//! \param pfnCallback is the function to be called when the data has been
+//! changed (can be \b NULL if a callback is not required).
+//! \param pvCallbackData is a pointer that is passed to the callback function.
+//!
+//! This function changes the value of a register in the LSM303D via a
+//! read-modify-write operation, allowing one of the fields to be changed
+//! without disturbing the other fields. The \e ui8Reg register is read, ANDed
+//! with \e ui8Mask, ORed with \e ui8Value, and then written back to the
+//! LSM303D.
+//!
+//! \return Returns 1 if the read-modify-write was successfully started and 0
+//! if it was not.
+//
+//*****************************************************************************
+uint_fast8_t
+LSM303DReadModifyWrite(tLSM303D *psInst, uint_fast8_t ui8Reg,
+ uint_fast8_t ui8Mask, uint_fast8_t ui8Value,
+ tSensorCallback *pfnCallback,
+ void *pvCallbackData)
+{
+ //
+ // Return a failure if the LSM303D driver is not idle (in other words,
+ // there is already an outstanding request to the LSM303D).
+ //
+ if(psInst->ui8State != LSM303D_STATE_IDLE)
+ {
+ return(0);
+ }
+
+ //
+ // Save the callback information.
+ //
+ psInst->pfnCallback = pfnCallback;
+ psInst->pvCallbackData = pvCallbackData;
+
+ //
+ // Move the state machine to the wait for read-modify-write state.
+ //
+ psInst->ui8State = LSM303D_STATE_RMW;
+
+ //
+ // Submit the read-modify-write request to the LSM303D.
+ //
+ if(I2CMReadModifyWrite8(&(psInst->uCommand.sReadModifyWriteState),
+ psInst->psI2CInst, psInst->ui8Addr, ui8Reg,
+ ui8Mask, ui8Value, LSM303DCallback,
+ psInst) == 0)
+ {
+ //
+ // The I2C read-modify-write failed, so move to the idle state and
+ // return a failure.
+ //
+ psInst->ui8State = LSM303D_STATE_IDLE;
+ return(0);
+ }
+
+ //
+ // Success.
+ //
+ return(1);
+}
+
+//*****************************************************************************
+//
+//! Reads the accelerometer data from the LSM303D.
+//!
+//! \param psInst is a pointer to the LSM303D instance data.
+//! \param pfnCallback is the function to be called when the data has been read
+//! (can be \b NULL if a callback is not required).
+//! \param pvCallbackData is a pointer that is passed to the callback function.
+//!
+//! This function initiates a read of the LSM303D data registers. When the
+//! read has completed (as indicated by calling the callback function), the new
+//! readings can be obtained via:
+//!
+//! - LSM303DDataAccelGetRaw()
+//! - LSM303DDataAccelGetFloat()
+//!
+//! \return Returns 1 if the read was successfully started and 0 if it was not.
+//
+//*****************************************************************************
+uint_fast8_t
+LSM303DDataRead(tLSM303D *psInst, tSensorCallback *pfnCallback,
+ void *pvCallbackData)
+{
+ //
+ // Return a failure if the LSM303D driver is not idle (in other words,
+ // there is already an outstanding request to the LSM303D).
+ //
+ if(psInst->ui8State != LSM303D_STATE_IDLE)
+ {
+ return(0);
+ }
+
+ //
+ // Save the callback information.
+ //
+ psInst->pfnCallback = pfnCallback;
+ psInst->pvCallbackData = pvCallbackData;
+
+ //
+ // Move the state machine to the wait for mag data read state.
+ //
+ psInst->ui8State = LSM303D_STATE_READ_MAG;
+
+ //
+ // Read the data registers from the LSM303D.
+ //
+ psInst->pui8DataMag[0] = LSM303D_O_MAG_STATUS | 0x80;
+ if(I2CMRead(psInst->psI2CInst, psInst->ui8Addr, psInst->pui8DataMag, 1,
+ psInst->pui8DataMag, 7, LSM303DCallback, psInst) == 0)
+ {
+ //
+ // The I2C read failed, so move to the idle state and return a failure.
+ //
+ psInst->ui8State = LSM303D_STATE_IDLE;
+ return(0);
+ }
+
+ //
+ // Success.
+ //
+ return(1);
+}
+
+//*****************************************************************************
+//
+//! Gets the raw accelerometer data from the most recent data read.
+//!
+//! \param psInst is a pointer to the LSM303D instance data.
+//! \param pui16AccelX is a pointer to the value into which the raw X-axis
+//! accelerometer data is stored.
+//! \param pui16AccelY is a pointer to the value into which the raw Y-axis
+//! accelerometer data is stored.
+//! \param pui16AccelZ is a pointer to the value into which the raw Z-axis
+//! accelerometer data is stored.
+//!
+//! This function returns the raw accelerometer data from the most recent data
+//! read. The data is not manipulated in any way by the driver. If any of the
+//! output data pointers are \b NULL, the corresponding data is not provided.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+LSM303DDataAccelGetRaw(tLSM303D *psInst,
+ uint_fast16_t *pui16AccelX,
+ uint_fast16_t *pui16AccelY,
+ uint_fast16_t *pui16AccelZ)
+{
+ //
+ // Return the raw accelerometer values.
+ //
+ if(pui16AccelX)
+ {
+ *pui16AccelX = (psInst->pui8DataAccel[2] << 8) | psInst->pui8DataAccel[1];
+ }
+ if(pui16AccelY)
+ {
+ *pui16AccelY = (psInst->pui8DataAccel[4] << 8) | psInst->pui8DataAccel[3];
+ }
+ if(pui16AccelZ)
+ {
+ *pui16AccelZ = (psInst->pui8DataAccel[6] << 8) | psInst->pui8DataAccel[5];
+ }
+}
+
+//*****************************************************************************
+//
+//! Gets the raw accelerometer data from the most recent data read.
+//!
+//! \param psInst is a pointer to the LSM303D instance data.
+//! \param pui16AccelX is a pointer to the value into which the raw X-axis
+//! accelerometer data is stored.
+//! \param pui16AccelY is a pointer to the value into which the raw Y-axis
+//! accelerometer data is stored.
+//! \param pui16AccelZ is a pointer to the value into which the raw Z-axis
+//! accelerometer data is stored.
+//!
+//! This function returns the raw accelerometer data from the most recent data
+//! read. The data is not manipulated in any way by the driver. If any of the
+//! output data pointers are \b NULL, the corresponding data is not provided.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+LSM303DDataMagnetoGetRaw(tLSM303D *psInst,
+ uint_fast16_t *pui16AccelX,
+ uint_fast16_t *pui16AccelY,
+ uint_fast16_t *pui16AccelZ)
+{
+ //
+ // Return the raw accelerometer values.
+ //
+ if(pui16AccelX)
+ {
+ *pui16AccelX = (psInst->pui8DataMag[2] << 8) | psInst->pui8DataMag[1];
+ }
+ if(pui16AccelY)
+ {
+ *pui16AccelY = (psInst->pui8DataMag[4] << 8) | psInst->pui8DataMag[3];
+ }
+ if(pui16AccelZ)
+ {
+ *pui16AccelZ = (psInst->pui8DataMag[6] << 8) | psInst->pui8DataMag[5];
+ }
+}
+
+//*****************************************************************************
+//
+//! Gets the accelerometer data from the most recent data read.
+//!
+//! \param psInst is a pointer to the LSM303D instance data.
+//! \param pfAccelX is a pointer to the value into which the X-axis
+//! accelerometer data is stored.
+//! \param pfAccelY is a pointer to the value into which the Y-axis
+//! accelerometer data is stored.
+//! \param pfAccelZ is a pointer to the value into which the Z-axis
+//! accelerometer data is stored.
+//!
+//! This function returns the accelerometer data from the most recent data
+//! read, converted into meters per second squared (m/s^2). If any of the
+//! output data pointers are \b NULL, the corresponding data is not provided.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+LSM303DDataAccelGetFloat(tLSM303D *psInst, float *pfAccelX,
+ float *pfAccelY, float *pfAccelZ)
+{
+ float fFactor;
+
+ //
+ // Get the acceleration conversion factor for the current data format.
+ //
+ fFactor = g_pfLSM303DAccelFactors[psInst->ui8AccelFSSel];
+
+ //
+ // Convert the Accelerometer values into floating-point gravity values.
+ //
+ if(pfAccelX)
+ {
+ *pfAccelX = (float)(((int16_t)((psInst->pui8DataAccel[2] << 8) |
+ psInst->pui8DataAccel[1])) * fFactor);
+ }
+ if(pfAccelY)
+ {
+ *pfAccelY = (float)(((int16_t)((psInst->pui8DataAccel[4] << 8) |
+ psInst->pui8DataAccel[3])) * fFactor);
+ }
+ if(pfAccelZ)
+ {
+ *pfAccelZ = (float)(((int16_t)((psInst->pui8DataAccel[6] << 8) |
+ psInst->pui8DataAccel[5])) * fFactor);
+ }
+}
+
+//*****************************************************************************
+//
+//! Gets the magnetometer data from the most recent data read.
+//!
+//! \param psInst is a pointer to the LSM303D instance data.
+//! \param pfMagX is a pointer to the value into which the X-axis
+//! accelerometer data is stored.
+//! \param pfMagY is a pointer to the value into which the Y-axis
+//! accelerometer data is stored.
+//! \param pfMagZ is a pointer to the value into which the Z-axis
+//! accelerometer data is stored.
+//!
+//! This function returns the magnetometer data from the most recent data
+//! read, converted into tesla. If any of the output data pointers are
+//! \b NULL, the corresponding data is not provided.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+LSM303DDataMagnetoGetFloat(tLSM303D *psInst, float *pfMagX,
+ float *pfMagY, float *pfMagZ)
+{
+ float fFactor;
+
+ //
+ // Get the magnetometer conversion factor for the current data format.
+ //
+ fFactor = g_pfLSM303DMagFactors[psInst->ui8MagFSSel];
+
+ //
+ // Convert the Accelerometer values into floating-point gravity values.
+ //
+ if(pfMagX)
+ {
+ *pfMagX = (float)(((int16_t)((psInst->pui8DataMag[2] << 8) |
+ psInst->pui8DataMag[1])) * fFactor);
+ }
+ if(pfMagY)
+ {
+ *pfMagY = (float)(((int16_t)((psInst->pui8DataMag[4] << 8) |
+ psInst->pui8DataMag[3])) * fFactor);
+ }
+ if(pfMagZ)
+ {
+ *pfMagZ = (float)(((int16_t)((psInst->pui8DataMag[6] << 8) |
+ psInst->pui8DataMag[5])) * fFactor);
+ }
+}
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
diff --git a/sensorlib/lsm303d.h b/sensorlib/lsm303d.h
new file mode 100644
index 0000000..a236e0f
--- /dev/null
+++ b/sensorlib/lsm303d.h
@@ -0,0 +1,186 @@
+//*****************************************************************************
+//
+// lsm303d.h - Driver for the ST LSM303D accelerometer/magnetometer.
+//
+// Copyright (c) 2013-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
+//
+//*****************************************************************************
+
+#ifndef __SENSORLIB_LSM303D_H__
+#define __SENSORLIB_LSM303D_H__
+
+//*****************************************************************************
+//
+// If building with a C++ compiler, make all of the definitions in this header
+// have a C binding.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+//*****************************************************************************
+//
+// The structure that defines the internal state of the LSM303DLHC driver.
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ // The pointer to the I2C master interface instance used to communicate
+ // with the LSM303DLHC.
+ //
+ tI2CMInstance *psI2CInst;
+
+ //
+ // The I2C address of the LSM303DLHC.
+ //
+ uint8_t ui8Addr;
+
+ //
+ // The state of the state machine used while accessing the LSM303DLHC.
+ //
+ uint8_t ui8State;
+
+ //
+ // The current accelerometer afs_sel setting.
+ //
+ uint8_t ui8AccelFSSel;
+
+ //
+ // The new accelerometer afs_sel setting, which is used when a register
+ // write succeeds.
+ //
+ uint8_t ui8NewAccelFSSel;
+
+ //
+ // The current accelerometer afs_sel setting.
+ //
+ uint8_t ui8MagFSSel;
+
+ //
+ // The new accelerometer afs_sel setting, which is used when a register
+ // write succeeds.
+ //
+ uint8_t ui8NewMagFSSel;
+
+ //
+ // The data buffers used for sending/receiving data to/from the LSM303DLHC.
+ //
+ uint8_t pui8DataMag[8];
+
+ //
+ // The data buffers used for sending/receiving data to/from the LSM303DLHC.
+ //
+ uint8_t pui8DataAccel[8];
+
+ //
+ // The function that is called when the current request has completed
+ // processing.
+ //
+ tSensorCallback *pfnCallback;
+
+ //
+ // The callback data provided to the callback function.
+ //
+ void *pvCallbackData;
+
+ //
+ // A union of structures that are used for read, write and
+ // read-modify-write operations. Since only one operation can be active at
+ // a time, it is safe to re-use the memory in this manner.
+ //
+ union
+ {
+ //
+ // A buffer used to store the write portion of a register read.
+ //
+ uint8_t pui8Buffer[2];
+
+ //
+ // The write state used to write register values.
+ //
+ tI2CMWrite8 sWriteState;
+
+ //
+ // The read-modify-write state used to modify register values.
+ //
+ tI2CMReadModifyWrite8 sReadModifyWriteState;
+ }
+ uCommand;
+}
+tLSM303D;
+
+//*****************************************************************************
+//
+// Function prototypes.
+//
+//*****************************************************************************
+extern uint_fast8_t LSM303DInit(tLSM303D *psInst,
+ tI2CMInstance *psI2CInst,
+ uint_fast8_t ui8I2CAddr,
+ tSensorCallback *pfnCallback,
+ void *pvCallbackData);
+extern uint_fast8_t LSM303DRead(tLSM303D *psInst,
+ uint_fast8_t ui8Reg,
+ uint8_t *pui8Data,
+ uint_fast16_t ui16Count,
+ tSensorCallback *pfnCallback,
+ void *pvCallbackData);
+extern uint_fast8_t LSM303DWrite(tLSM303D *psInst,
+ uint_fast8_t ui8Reg,
+ const uint8_t *pui8Data,
+ uint_fast16_t ui16Count,
+ tSensorCallback *pfnCallback,
+ void *pvCallbackData);
+extern uint_fast8_t LSM303DReadModifyWrite(tLSM303D *psInst,
+ uint_fast8_t ui8Reg,
+ uint_fast8_t ui8Mask,
+ uint_fast8_t ui8Value,
+ tSensorCallback *pfnCallbak,
+ void *pvCallbackData);
+extern uint_fast8_t LSM303DDataRead(tLSM303D *psInst,
+ tSensorCallback *pfnCallback,
+ void *pvCallbackData);
+extern void LSM303DDataAccelGetRaw(tLSM303D *psInst,
+ uint_fast16_t *pui16AccelX,
+ uint_fast16_t *pui16AccelY,
+ uint_fast16_t *pui16AccelZ);
+extern void LSM303DDataAccelGetFloat(tLSM303D *psInst,
+ float *pfAccelX, float *pfAccelY,
+ float *pfAccelZ);
+extern void LSM303DDataMagnetoGetRaw(tLSM303D *psInst,
+ uint_fast16_t *pui16MagX,
+ uint_fast16_t *pui16MagY,
+ uint_fast16_t *pui16MagZ);
+extern void LSM303DDataMagnetoGetFloat(tLSM303D *psInst,
+ float *pfMagX, float *pfMagY,
+ float *pfMagZ);
+
+//*****************************************************************************
+//
+// Mark the end of the C bindings section for C++ compilers.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __SENSORLIB_LSM303D_H__
diff --git a/sensorlib/lsm303dlhc_accel.c b/sensorlib/lsm303dlhc_accel.c
new file mode 100644
index 0000000..ad46b37
--- /dev/null
+++ b/sensorlib/lsm303dlhc_accel.c
@@ -0,0 +1,662 @@
+//*****************************************************************************
+//
+// lsm303dlhc.c - Driver for the ST LSM303DLHC accelerometer
+//
+// Copyright (c) 2013-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
+//
+//*****************************************************************************
+
+#include <stdint.h>
+#include "sensorlib/hw_lsm303dlhc.h"
+#include "sensorlib/i2cm_drv.h"
+#include "sensorlib/lsm303dlhc_accel.h"
+
+//*****************************************************************************
+//
+//! \addtogroup lsm303dlhc_api
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// The states of the LSM303DLHC state machine.
+//
+//*****************************************************************************
+#define LSM303DLHC_STATE_IDLE 0 // State machine is idle
+#define LSM303DLHC_STATE_INIT 1 // Waiting for init
+#define LSM303DLHC_STATE_READ 2 // Waiting for read
+#define LSM303DLHC_STATE_WRITE 3 // Waiting for write
+#define LSM303DLHC_STATE_RMW 4 // Waiting for read-modify-write
+
+//*****************************************************************************
+//
+// The factors used to convert the acceleration readings from the LSM303DLHC
+// into floating point values in meters per second squared.
+//
+// Values are obtained by taking the g conversion factors from the data sheet
+// and multiplying by 9.81 (1 g = 9.81 m/s^2).
+//
+//*****************************************************************************
+static const float g_pfLSM303DLHCAccelFactors[] =
+{
+ 0.00059875, // Range = +/- 2 g (16384 lsb/g)
+ 0.00119751, // Range = +/- 4 g (8192 lsb/g)
+ 0.00239502, // Range = +/- 8 g (4096 lsb/g)
+ 0.00479004 // Range = +/- 16 g (2048 lsb/g)
+};
+
+//
+// Uninitialized values will default to zero which is what we want. 0x80 is
+// ORed into the register address so the writes auto-increment
+//
+static const uint8_t g_pui8ZeroCtrl1[8] =
+{
+ 0x80 | LSM303DLHC_O_CTRL1
+};
+static const uint8_t g_pui8ZeroFifoCtl[14] =
+{
+ 0x80 | LSM303DLHC_O_FIFO_CTRL
+};
+
+//*****************************************************************************
+//
+// The callback function that is called when I2C transations to/from the
+// LSM303DLHC have completed.
+//
+//*****************************************************************************
+static void
+LSM303DLHCCallback(void *pvCallbackData, uint_fast8_t ui8Status)
+{
+ tLSM303DLHCAccel *psInst;
+
+ //
+ // Convert the instance data into a pointer to a tLSM303DLHC structure.
+ //
+ psInst = pvCallbackData;
+
+ //
+ // If the I2C master driver encountered a failure, force the state machine
+ // to the idle state (which will also result in a callback to propagate the
+ // error).
+ //
+ if(ui8Status != I2CM_STATUS_SUCCESS)
+ {
+ psInst->ui8State = LSM303DLHC_STATE_IDLE;
+ }
+
+ //
+ // Determine the current state of the LSM303DLHC state machine.
+ //
+ switch(psInst->ui8State)
+ {
+ //
+ // All states that trivially transition to IDLE, and all unknown
+ // states.
+ //
+ case LSM303DLHC_STATE_READ:
+ default:
+ {
+ //
+ // The state machine is now idle.
+ //
+ psInst->ui8State = LSM303DLHC_STATE_IDLE;
+
+ //
+ // Done.
+ //
+ break;
+ }
+
+ case LSM303DLHC_STATE_INIT:
+ {
+ psInst->ui8State = LSM303DLHC_STATE_IDLE;
+ I2CMWrite(psInst->psI2CInst, psInst->ui8Addr, g_pui8ZeroFifoCtl,
+ 14, LSM303DLHCCallback, pvCallbackData);
+
+ //
+ // Done.
+ //
+ break;
+ }
+
+ //
+ // A write just completed
+ //
+ case LSM303DLHC_STATE_WRITE:
+ {
+ //
+ // Set the accelerometer ranges to the new values. If the register
+ // was not modified, the values will be the same so this has no
+ // effect.
+ //
+ psInst->ui8AccelAfsSel = psInst->ui8NewAccelAfsSel;
+
+ //
+ // The state machine is now idle.
+ //
+ psInst->ui8State = LSM303DLHC_STATE_IDLE;
+
+ //
+ // Done.
+ //
+ break;
+ }
+
+ //
+ // A read-modify-write just completed
+ //
+ case LSM303DLHC_STATE_RMW:
+ {
+ //
+ // See if the ACCEL_CONFIG register was just modified.
+ //
+ if(psInst->uCommand.sReadModifyWriteState.pui8Buffer[0] ==
+ LSM303DLHC_O_CTRL4)
+ {
+ //
+ // Extract the FS_SEL from the ACCEL_CONFIG register value.
+ //
+ psInst->ui8AccelAfsSel =
+ ((psInst->uCommand.sReadModifyWriteState.pui8Buffer[1] &
+ LSM303DLHC_CTRL4_FS_M) >> LSM303DLHC_CTRL4_FS_S);
+ }
+
+ //
+ // The state machine is now idle.
+ //
+ psInst->ui8State = LSM303DLHC_STATE_IDLE;
+
+ //
+ // Done.
+ //
+ break;
+ }
+ }
+
+ //
+ // See if the state machine is now idle and there is a callback function.
+ //
+ if((psInst->ui8State == LSM303DLHC_STATE_IDLE) && psInst->pfnCallback)
+ {
+ //
+ // Call the application-supplied callback function.
+ //
+ psInst->pfnCallback(psInst->pvCallbackData, ui8Status);
+ }
+}
+
+//*****************************************************************************
+//
+//! Initializes the LSM303DLHC driver.
+//!
+//! \param psInst is a pointer to the LSM303DLHC instance data.
+//! \param psI2CInst is a pointer to the I2C master driver instance data.
+//! \param ui8I2CAddr is the I2C address of the LSM303DLHC device.
+//! \param pfnCallback is the function to be called when the initialization has
+//! completed (can be \b NULL if a callback is not required).
+//! \param pvCallbackData is a pointer that is passed to the callback function.
+//!
+//! This function initializes the LSM303DLHC driver, preparing it for
+//! operation.
+//!
+//! \return Returns 1 if the LSM303DLHC driver was successfully initialized and
+//! 0 if it was not.
+//
+//*****************************************************************************
+uint_fast8_t
+LSM303DLHCAccelInit(tLSM303DLHCAccel *psInst, tI2CMInstance *psI2CInst,
+ uint_fast8_t ui8I2CAddr, tSensorCallback *pfnCallback,
+ void *pvCallbackData)
+{
+ //
+ // Initialize the LSM303DLHC instance structure.
+ //
+ psInst->psI2CInst = psI2CInst;
+ psInst->ui8Addr = ui8I2CAddr;
+
+ //
+ // Save the callback information.
+ //
+ psInst->pfnCallback = pfnCallback;
+ psInst->pvCallbackData = pvCallbackData;
+
+ //
+ // Default range setting is +/- 2 g
+ //
+ psInst->ui8AccelAfsSel = (LSM303DLHC_CTRL4_FS_2G >> LSM303DLHC_CTRL4_FS_S);
+ psInst->ui8NewAccelAfsSel = (LSM303DLHC_CTRL4_FS_2G >> LSM303DLHC_CTRL4_FS_S);
+
+ //
+ // There is no soft reset on the LSM303. Force registers back to their
+ // spec'ed POR defaults.
+ //
+ psInst->ui8State = LSM303DLHC_STATE_INIT;
+ if(I2CMWrite(psInst->psI2CInst, psInst->ui8Addr, g_pui8ZeroCtrl1, 7,
+ LSM303DLHCCallback, (void *)psInst) == 0)
+ {
+ psInst->ui8State = LSM303DLHC_STATE_IDLE;
+ return(0);
+ }
+
+ //
+ // Success
+ //
+ return(1);
+}
+
+//*****************************************************************************
+//
+//! Reads data from LSM303DLHC registers.
+//!
+//! \param psInst is a pointer to the LSM303DLHC instance data.
+//! \param ui8Reg is the first register to read.
+//! \param pui8Data is a pointer to the location to store the data that is
+//! read.
+//! \param ui16Count is the number of data bytes to read.
+//! \param pfnCallback is the function to be called when the data has been read
+//! (can be \b NULL if a callback is not required).
+//! \param pvCallbackData is a pointer that is passed to the callback function.
+//!
+//! This function reads a sequence of data values from consecutive registers in
+//! the LSM303DLHC.
+//!
+//! \return Returns 1 if the write was successfully started and 0 if it was
+//! not.
+//
+//*****************************************************************************
+uint_fast8_t
+LSM303DLHCAccelRead(tLSM303DLHCAccel *psInst, uint_fast8_t ui8Reg,
+ uint8_t *pui8Data, uint_fast16_t ui16Count,
+ tSensorCallback *pfnCallback, void *pvCallbackData)
+{
+ //
+ // Return a failure if the LSM303DLHC driver is not idle (in other words,
+ // there is already an outstanding request to the LSM303DLHC).
+ //
+ if(psInst->ui8State != LSM303DLHC_STATE_IDLE)
+ {
+ return(0);
+ }
+
+ //
+ // Save the callback information.
+ //
+ psInst->pfnCallback = pfnCallback;
+ psInst->pvCallbackData = pvCallbackData;
+
+ //
+ // Move the state machine to the wait for read state.
+ //
+ psInst->ui8State = LSM303DLHC_STATE_READ;
+
+ //
+ // Read the requested registers from the LSM303DLHC.
+ //
+ psInst->uCommand.pui8Buffer[0] = ui8Reg;
+ if(I2CMRead(psInst->psI2CInst, psInst->ui8Addr,
+ psInst->uCommand.pui8Buffer, 1, pui8Data, ui16Count,
+ LSM303DLHCCallback, psInst) == 0)
+ {
+ //
+ // The I2C write failed, so move to the idle state and return a
+ // failure.
+ //
+ psInst->ui8State = LSM303DLHC_STATE_IDLE;
+ return(0);
+ }
+
+ //
+ // Success.
+ //
+ return(1);
+}
+
+//*****************************************************************************
+//
+//! Writes data to LSM303DLHC registers.
+//!
+//! \param psInst is a pointer to the LSM303DLHC instance data.
+//! \param ui8Reg is the first register to write.
+//! \param pui8Data is a pointer to the data to write.
+//! \param ui16Count is the number of data bytes to write.
+//! \param pfnCallback is the function to be called when the data has been
+//! written (can be \b NULL if a callback is not required).
+//! \param pvCallbackData is a pointer that is passed to the callback function.
+//!
+//! This function writes a sequence of data values to consecutive registers in
+//! the LSM303DLHC. The first byte of the \e pui8Data buffer contains the
+//! value to be written into the \e ui8Reg register, the second value contains
+//! the data to be written into the next register, and so on.
+//!
+//! \return Returns 1 if the write was successfully started and 0 if it was
+//! not.
+//
+//*****************************************************************************
+uint_fast8_t
+LSM303DLHCAccelWrite(tLSM303DLHCAccel *psInst, uint_fast8_t ui8Reg,
+ const uint8_t *pui8Data, uint_fast16_t ui16Count,
+ tSensorCallback *pfnCallback, void *pvCallbackData)
+{
+ //
+ // Return a failure if the LSM303DLHC driver is not idle (in other words,
+ // there is already an outstanding request to the LSM303DLHC).
+ //
+ if(psInst->ui8State != LSM303DLHC_STATE_IDLE)
+ {
+ return(0);
+ }
+
+ //
+ // Save the callback information.
+ //
+ psInst->pfnCallback = pfnCallback;
+ psInst->pvCallbackData = pvCallbackData;
+
+ //
+ // See if they're rebooting via CTRL5
+ //
+ if((ui8Reg <= LSM303DLHC_O_CTRL5) &&
+ ((ui8Reg + ui16Count) > LSM303DLHC_O_CTRL5))
+ {
+ //
+ // See if a soft reset is being requested.
+ //
+ if(pui8Data[ui8Reg - LSM303DLHC_O_CTRL5] & LSM303DLHC_CTRL5_REBOOTCTL_M)
+ {
+ //
+ // Default range setting is +/- 2 g.
+ //
+ psInst->ui8NewAccelAfsSel = 0;
+ }
+ }
+
+ //
+ // See if the ACCEL_CONFIG register is being written.
+ //
+ if((ui8Reg <= LSM303DLHC_O_CTRL4) &&
+ ((ui8Reg + ui16Count) > LSM303DLHC_O_CTRL4))
+ {
+ //
+ // Extract the AFS_SEL from the ACCEL_CONFIG register value.
+ //
+ psInst->ui8NewAccelAfsSel =
+ ((pui8Data[ui8Reg - LSM303DLHC_O_CTRL4] &
+ LSM303DLHC_CTRL4_FS_M) >> LSM303DLHC_CTRL4_FS_S);
+ }
+
+ //
+ // Move the state machine to the wait for write state.
+ //
+ psInst->ui8State = LSM303DLHC_STATE_WRITE;
+
+ //
+ // Write the requested registers to the LSM303DLHC.
+ //
+ if(I2CMWrite8(&(psInst->uCommand.sWriteState), psInst->psI2CInst,
+ psInst->ui8Addr, ui8Reg, pui8Data, ui16Count,
+ LSM303DLHCCallback, psInst) == 0)
+ {
+ //
+ // The I2C write failed, so move to the idle state and return a
+ // failure.
+ //
+ psInst->ui8State = LSM303DLHC_STATE_IDLE;
+ return(0);
+ }
+
+ //
+ // Success.
+ //
+ return(1);
+}
+
+//*****************************************************************************
+//
+//! Performs a read-modify-write of a LSM303DLHC register.
+//!
+//! \param psInst is a pointer to the LSM303DLHC instance data.
+//! \param ui8Reg is the register to modify.
+//! \param ui8Mask is the bit mask that is ANDed with the current register
+//! value.
+//! \param ui8Value is the bit mask that is ORed with the result of the AND
+//! operation.
+//! \param pfnCallback is the function to be called when the data has been
+//! changed (can be \b NULL if a callback is not required).
+//! \param pvCallbackData is a pointer that is passed to the callback function.
+//!
+//! This function changes the value of a register in the LSM303DLHC via a
+//! read-modify-write operation, allowing one of the fields to be changed
+//! without disturbing the other fields. The \e ui8Reg register is read, ANDed
+//! with \e ui8Mask, ORed with \e ui8Value, and then written back to the
+//! LSM303DLHC.
+//!
+//! \return Returns 1 if the read-modify-write was successfully started and 0
+//! if it was not.
+//
+//*****************************************************************************
+uint_fast8_t
+LSM303DLHCAccelReadModifyWrite(tLSM303DLHCAccel *psInst, uint_fast8_t ui8Reg,
+ uint_fast8_t ui8Mask, uint_fast8_t ui8Value,
+ tSensorCallback *pfnCallback,
+ void *pvCallbackData)
+{
+ //
+ // Return a failure if the LSM303DLHC driver is not idle (in other words,
+ // there is already an outstanding request to the LSM303DLHC).
+ //
+ if(psInst->ui8State != LSM303DLHC_STATE_IDLE)
+ {
+ return(0);
+ }
+
+ //
+ // Save the callback information.
+ //
+ psInst->pfnCallback = pfnCallback;
+ psInst->pvCallbackData = pvCallbackData;
+
+ //
+ // Move the state machine to the wait for read-modify-write state.
+ //
+ psInst->ui8State = LSM303DLHC_STATE_RMW;
+
+ //
+ // Submit the read-modify-write request to the LSM303DLHC.
+ //
+ if(I2CMReadModifyWrite8(&(psInst->uCommand.sReadModifyWriteState),
+ psInst->psI2CInst, psInst->ui8Addr, ui8Reg,
+ ui8Mask, ui8Value, LSM303DLHCCallback,
+ psInst) == 0)
+ {
+ //
+ // The I2C read-modify-write failed, so move to the idle state and
+ // return a failure.
+ //
+ psInst->ui8State = LSM303DLHC_STATE_IDLE;
+ return(0);
+ }
+
+ //
+ // Success.
+ //
+ return(1);
+}
+
+//*****************************************************************************
+//
+//! Reads the accelerometer data from the LSM303DLHC.
+//!
+//! \param psInst is a pointer to the LSM303DLHC instance data.
+//! \param pfnCallback is the function to be called when the data has been read
+//! (can be \b NULL if a callback is not required).
+//! \param pvCallbackData is a pointer that is passed to the callback function.
+//!
+//! This function initiates a read of the LSM303DLHC data registers. When the
+//! read has completed (as indicated by calling the callback function), the new
+//! readings can be obtained via:
+//!
+//! - LSM303DLHCDataAccelGetRaw()
+//! - LSM303DLHCDataAccelGetFloat()
+//!
+//! \return Returns 1 if the read was successfully started and 0 if it was not.
+//
+//*****************************************************************************
+uint_fast8_t
+LSM303DLHCAccelDataRead(tLSM303DLHCAccel *psInst, tSensorCallback *pfnCallback,
+ void *pvCallbackData)
+{
+ //
+ // Return a failure if the LSM303DLHC driver is not idle (in other words,
+ // there is already an outstanding request to the LSM303DLHC).
+ //
+ if(psInst->ui8State != LSM303DLHC_STATE_IDLE)
+ {
+ return(0);
+ }
+
+ //
+ // Save the callback information.
+ //
+ psInst->pfnCallback = pfnCallback;
+ psInst->pvCallbackData = pvCallbackData;
+
+ //
+ // Move the state machine to the wait for data read state.
+ //
+ psInst->ui8State = LSM303DLHC_STATE_READ;
+
+ //
+ // Read the data registers from the LSM303DLHC.
+ //
+ psInst->pui8Data[0] = LSM303DLHC_O_OUT_X_LSB | 0x80;
+ if(I2CMRead(psInst->psI2CInst, psInst->ui8Addr, psInst->pui8Data, 1,
+ psInst->pui8Data, 6, LSM303DLHCCallback, psInst) == 0)
+ {
+ //
+ // The I2C read failed, so move to the idle state and return a failure.
+ //
+ psInst->ui8State = LSM303DLHC_STATE_IDLE;
+ return(0);
+ }
+
+ //
+ // Success.
+ //
+ return(1);
+}
+
+//*****************************************************************************
+//
+//! Gets the raw accelerometer data from the most recent data read.
+//!
+//! \param psInst is a pointer to the LSM303DLHC instance data.
+//! \param pui16AccelX is a pointer to the value into which the raw X-axis
+//! accelerometer data is stored.
+//! \param pui16AccelY is a pointer to the value into which the raw Y-axis
+//! accelerometer data is stored.
+//! \param pui16AccelZ is a pointer to the value into which the raw Z-axis
+//! accelerometer data is stored.
+//!
+//! This function returns the raw accelerometer data from the most recent data
+//! read. The data is not manipulated in any way by the driver. If any of the
+//! output data pointers are \b NULL, the corresponding data is not provided.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+LSM303DLHCAccelDataAccelGetRaw(tLSM303DLHCAccel *psInst,
+ uint_fast16_t *pui16AccelX,
+ uint_fast16_t *pui16AccelY,
+ uint_fast16_t *pui16AccelZ)
+{
+ //
+ // Return the raw accelerometer values.
+ //
+ if(pui16AccelX)
+ {
+ *pui16AccelX = (psInst->pui8Data[1] << 8) | psInst->pui8Data[0];
+ }
+ if(pui16AccelY)
+ {
+ *pui16AccelY = (psInst->pui8Data[3] << 8) | psInst->pui8Data[2];
+ }
+ if(pui16AccelZ)
+ {
+ *pui16AccelZ = (psInst->pui8Data[5] << 8) | psInst->pui8Data[4];
+ }
+}
+
+//*****************************************************************************
+//
+//! Gets the accelerometer data from the most recent data read.
+//!
+//! \param psInst is a pointer to the LSM303DLHC instance data.
+//! \param pfAccelX is a pointer to the value into which the X-axis
+//! accelerometer data is stored.
+//! \param pfAccelY is a pointer to the value into which the Y-axis
+//! accelerometer data is stored.
+//! \param pfAccelZ is a pointer to the value into which the Z-axis
+//! accelerometer data is stored.
+//!
+//! This function returns the accelerometer data from the most recent data
+//! read, converted into meters per second squared (m/s^2). If any of the
+//! output data pointers are \b NULL, the corresponding data is not provided.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+LSM303DLHCAccelDataAccelGetFloat(tLSM303DLHCAccel *psInst, float *pfAccelX,
+ float *pfAccelY, float *pfAccelZ)
+{
+ float fFactor;
+
+ //
+ // Get the acceleration conversion factor for the current data format.
+ //
+ fFactor = g_pfLSM303DLHCAccelFactors[psInst->ui8AccelAfsSel];
+
+ //
+ // Convert the Accelerometer values into floating-point gravity values.
+ //
+ if(pfAccelX)
+ {
+ *pfAccelX = (float)(((int16_t)((psInst->pui8Data[1] << 8) |
+ psInst->pui8Data[0])) * fFactor);
+ }
+ if(pfAccelY)
+ {
+ *pfAccelY = (float)(((int16_t)((psInst->pui8Data[3] << 8) |
+ psInst->pui8Data[2])) * fFactor);
+ }
+ if(pfAccelZ)
+ {
+ *pfAccelZ = (float)(((int16_t)((psInst->pui8Data[5] << 8) |
+ psInst->pui8Data[4])) * fFactor);
+ }
+}
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
diff --git a/sensorlib/lsm303dlhc_accel.h b/sensorlib/lsm303dlhc_accel.h
new file mode 100644
index 0000000..00d72f7
--- /dev/null
+++ b/sensorlib/lsm303dlhc_accel.h
@@ -0,0 +1,163 @@
+//*****************************************************************************
+//
+// lsm303dlhc.c - Driver for the ST L3GD20H gyrometer
+//
+// Copyright (c) 2013-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
+//
+//*****************************************************************************
+
+#ifndef __SENSORLIB_LSM303DLHC_ACCEL_H__
+#define __SENSORLIB_LSM303DLHC_ACCEL_H__
+
+//*****************************************************************************
+//
+// If building with a C++ compiler, make all of the definitions in this header
+// have a C binding.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+//*****************************************************************************
+//
+// The structure that defines the internal state of the LSM303DLHC driver.
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ // The pointer to the I2C master interface instance used to communicate
+ // with the LSM303DLHC.
+ //
+ tI2CMInstance *psI2CInst;
+
+ //
+ // The I2C address of the LSM303DLHC.
+ //
+ uint8_t ui8Addr;
+
+ //
+ // The state of the state machine used while accessing the LSM303DLHC.
+ //
+ uint8_t ui8State;
+
+ //
+ // The current accelerometer afs_sel setting.
+ //
+ uint8_t ui8AccelAfsSel;
+
+ //
+ // The new accelerometer afs_sel setting, which is used when a register
+ // write succeeds.
+ //
+ uint8_t ui8NewAccelAfsSel;
+
+ //
+ // The data buffers used for sending/receiving data to/from the LSM303DLHC.
+ //
+ uint8_t pui8Data[8];
+
+ //
+ // The function that is called when the current request has completed
+ // processing.
+ //
+ tSensorCallback *pfnCallback;
+
+ //
+ // The callback data provided to the callback function.
+ //
+ void *pvCallbackData;
+
+ //
+ // A union of structures that are used for read, write and
+ // read-modify-write operations. Since only one operation can be active at
+ // a time, it is safe to re-use the memory in this manner.
+ //
+ union
+ {
+ //
+ // A buffer used to store the write portion of a register read.
+ //
+ uint8_t pui8Buffer[2];
+
+ //
+ // The write state used to write register values.
+ //
+ tI2CMWrite8 sWriteState;
+
+ //
+ // The read-modify-write state used to modify register values.
+ //
+ tI2CMReadModifyWrite8 sReadModifyWriteState;
+ }
+ uCommand;
+}
+tLSM303DLHCAccel;
+
+//*****************************************************************************
+//
+// Function prototypes.
+//
+//*****************************************************************************
+extern uint_fast8_t LSM303DLHCAccelInit(tLSM303DLHCAccel *psInst,
+ tI2CMInstance *psI2CInst,
+ uint_fast8_t ui8I2CAddr,
+ tSensorCallback *pfnCallback,
+ void *pvCallbackData);
+extern uint_fast8_t LSM303DLHCAccelRead(tLSM303DLHCAccel *psInst,
+ uint_fast8_t ui8Reg,
+ uint8_t *pui8Data,
+ uint_fast16_t ui16Count,
+ tSensorCallback *pfnCallback,
+ void *pvCallbackData);
+extern uint_fast8_t LSM303DLHCAccelWrite(tLSM303DLHCAccel *psInst,
+ uint_fast8_t ui8Reg,
+ const uint8_t *pui8Data,
+ uint_fast16_t ui16Count,
+ tSensorCallback *pfnCallback,
+ void *pvCallbackData);
+extern uint_fast8_t LSM303DLHCAccelReadModifyWrite(tLSM303DLHCAccel *psInst,
+ uint_fast8_t ui8Reg,
+ uint_fast8_t ui8Mask,
+ uint_fast8_t ui8Value,
+ tSensorCallback *pfnCallbak,
+ void *pvCallbackData);
+extern uint_fast8_t LSM303DLHCAccelDataRead(tLSM303DLHCAccel *psInst,
+ tSensorCallback *pfnCallback,
+ void *pvCallbackData);
+extern void LSM303DLHCAccelDataAccelGetRaw(tLSM303DLHCAccel *psInst,
+ uint_fast16_t *pui16AccelX,
+ uint_fast16_t *pui16AccelY,
+ uint_fast16_t *pui16AccelZ);
+extern void LSM303DLHCAccelDataAccelGetFloat(tLSM303DLHCAccel *psInst,
+ float *pfAccelX, float *pfAccelY,
+ float *pfAccelZ);
+
+//*****************************************************************************
+//
+// Mark the end of the C bindings section for C++ compilers.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __SENSORLIB_LSM303DLHC_ACCEL_H__
diff --git a/sensorlib/lsm303dlhc_mag.c b/sensorlib/lsm303dlhc_mag.c
new file mode 100644
index 0000000..d8abaa8
--- /dev/null
+++ b/sensorlib/lsm303dlhc_mag.c
@@ -0,0 +1,615 @@
+//*****************************************************************************
+//
+// lsm303dlhc.c - Driver for the ST LSM303DLHC magnetometer
+//
+// Copyright (c) 2013-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
+//
+//*****************************************************************************
+
+#include <stdint.h>
+#include "sensorlib/hw_lsm303dlhc.h"
+#include "sensorlib/i2cm_drv.h"
+#include "sensorlib/lsm303dlhc_mag.h"
+
+//*****************************************************************************
+//
+//! \addtogroup lsm303dlhc_api
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// The states of the LSM303DLHC state machine.
+//
+//*****************************************************************************
+#define LSM303DLHC_STATE_IDLE 0 // State machine is idle
+#define LSM303DLHC_STATE_READ 1 // Waiting for read
+#define LSM303DLHC_STATE_WRITE 2 // Waiting for write
+#define LSM303DLHC_STATE_RMW 3 // Waiting for read-modify-write
+
+//*****************************************************************************
+//
+// The factors used to convert the magnetometer readings from the LSM303 into
+// floating point values in tesla
+//
+//*****************************************************************************
+static const float g_pfLSM303DLHCMagnetoFactors[] =
+{
+ 0,
+ 9.09E-08f,
+ 1.17E-07f,
+ 1.49E-07f,
+ 2.22E-07f,
+ 2.50E-07f,
+ 3.03E-07f,
+ 4.35E-07f,
+};
+
+//*****************************************************************************
+//
+// The callback function that is called when I2C transations to/from the
+// LSM303DLHC have completed.
+//
+//*****************************************************************************
+static void
+LSM303DLHCCallback(void *pvCallbackData, uint_fast8_t ui8Status)
+{
+ tLSM303DLHCMag *psInst;
+
+ //
+ // Convert the instance data into a pointer to a tLSM303DLHC structure.
+ //
+ psInst = pvCallbackData;
+
+ //
+ // If the I2C master driver encountered a failure, force the state machine
+ // to the idle state (which will also result in a callback to propagate the
+ // error).
+ //
+ if(ui8Status != I2CM_STATUS_SUCCESS)
+ {
+ psInst->ui8State = LSM303DLHC_STATE_IDLE;
+ }
+
+ //
+ // Determine the current state of the LSM303DLHC state machine.
+ //
+ switch(psInst->ui8State)
+ {
+ //
+ // All states that trivially transition to IDLE, and all unknown
+ // states.
+ //
+ case LSM303DLHC_STATE_READ:
+ default:
+ {
+ //
+ // The state machine is now idle.
+ //
+ psInst->ui8State = LSM303DLHC_STATE_IDLE;
+
+ //
+ // Done.
+ //
+ break;
+ }
+
+ //
+ // A write just completed
+ //
+ case LSM303DLHC_STATE_WRITE:
+ {
+ //
+ // Set the magneto ranges to the new values. If the register was
+ // not modified, the values will be the same so this has no effect.
+ //
+ psInst->ui8MagnetoFsSel = psInst->ui8NewMagnetoFsSel;
+
+ //
+ // The state machine is now idle.
+ //
+ psInst->ui8State = LSM303DLHC_STATE_IDLE;
+
+ //
+ // Done.
+ //
+ break;
+ }
+
+ //
+ // A read-modify-write just completed
+ //
+ case LSM303DLHC_STATE_RMW:
+ {
+ //
+ // See if the MAGNETO_CONFIG register was just modified.
+ //
+ if(psInst->uCommand.sReadModifyWriteState.pui8Buffer[0] ==
+ LSM303DLHC_O_MAG_CRB)
+ {
+ //
+ // Extract the FS_SEL from the MAGNETO_CONFIG register value.
+ //
+ psInst->ui8MagnetoFsSel =
+ ((psInst->uCommand.sReadModifyWriteState.pui8Buffer[1] &
+ LSM303DLHC_MAG_CRB_GAIN_M) >> LSM303DLHC_MAG_CRB_GAIN_S);
+ }
+
+ //
+ // The state machine is now idle.
+ //
+ psInst->ui8State = LSM303DLHC_STATE_IDLE;
+
+ //
+ // Done.
+ //
+ break;
+ }
+ }
+
+ //
+ // See if the state machine is now idle and there is a callback function.
+ //
+ if((psInst->ui8State == LSM303DLHC_STATE_IDLE) && psInst->pfnCallback)
+ {
+ //
+ // Call the application-supplied callback function.
+ //
+ psInst->pfnCallback(psInst->pvCallbackData, ui8Status);
+ }
+}
+
+//*****************************************************************************
+//
+//! Initializes the LSM303DLHC driver.
+//!
+//! \param psInst is a pointer to the LSM303DLHC instance data.
+//! \param psI2CInst is a pointer to the I2C master driver instance data.
+//! \param ui8I2CAddr is the I2C address of the LSM303DLHC device.
+//! \param pfnCallback is the function to be called when the initialization has
+//! completed (can be \b NULL if a callback is not required).
+//! \param pvCallbackData is a pointer that is passed to the callback function.
+//!
+//! This function initializes the LSM303DLHC driver, preparing it for
+//! operation.
+//!
+//! \return Returns 1 if the LSM303DLHC driver was successfully initialized and
+//! 0 if it was not.
+//
+//*****************************************************************************
+uint_fast8_t
+LSM303DLHCMagInit(tLSM303DLHCMag *psInst, tI2CMInstance *psI2CInst,
+ uint_fast8_t ui8I2CAddr, tSensorCallback *pfnCallback,
+ void *pvCallbackData)
+{
+ //
+ // Initialize the LSM303DLHC instance structure.
+ //
+ psInst->psI2CInst = psI2CInst;
+ psInst->ui8Addr = ui8I2CAddr;
+
+ //
+ // Save the callback information.
+ //
+ psInst->pfnCallback = pfnCallback;
+ psInst->pvCallbackData = pvCallbackData;
+
+ //
+ // Default range setting is +/- 1.3
+ // TODO: double-check default
+ //
+ psInst->ui8MagnetoFsSel = (LSM303DLHC_MAG_CRB_GAIN_1_3GAUSS >>
+ LSM303DLHC_MAG_CRB_GAIN_S);
+ psInst->ui8NewMagnetoFsSel = (LSM303DLHC_MAG_CRB_GAIN_1_3GAUSS >>
+ LSM303DLHC_MAG_CRB_GAIN_S);
+ psInst->ui8State = LSM303DLHC_STATE_IDLE;
+
+ if(pfnCallback)
+ {
+ pfnCallback(pvCallbackData, I2CM_STATUS_SUCCESS);
+ }
+
+ //
+ // Success
+ //
+ return(1);
+}
+
+//*****************************************************************************
+//
+//! Reads data from LSM303DLHC registers.
+//!
+//! \param psInst is a pointer to the LSM303DLHC instance data.
+//! \param ui8Reg is the first register to read.
+//! \param pui8Data is a pointer to the location to store the data that is
+//! read.
+//! \param ui16Count is the number of data bytes to read.
+//! \param pfnCallback is the function to be called when the data has been read
+//! (can be \b NULL if a callback is not required).
+//! \param pvCallbackData is a pointer that is passed to the callback function.
+//!
+//! This function reads a sequence of data values from consecutive registers in
+//! the LSM303DLHC.
+//!
+//! \return Returns 1 if the write was successfully started and 0 if it was
+//! not.
+//
+//*****************************************************************************
+uint_fast8_t
+LSM303DLHCMagRead(tLSM303DLHCMag *psInst, uint_fast8_t ui8Reg,
+ uint8_t *pui8Data, uint_fast16_t ui16Count,
+ tSensorCallback *pfnCallback, void *pvCallbackData)
+{
+ //
+ // Return a failure if the LSM303DLHC driver is not idle (in other words,
+ // there is already an outstanding request to the LSM303DLHC).
+ //
+ if(psInst->ui8State != LSM303DLHC_STATE_IDLE)
+ {
+ return(0);
+ }
+
+ //
+ // Save the callback information.
+ //
+ psInst->pfnCallback = pfnCallback;
+ psInst->pvCallbackData = pvCallbackData;
+
+ //
+ // Move the state machine to the wait for read state.
+ //
+ psInst->ui8State = LSM303DLHC_STATE_READ;
+
+ //
+ // Read the requested registers from the LSM303DLHC.
+ //
+ psInst->uCommand.pui8Buffer[0] = ui8Reg;
+ if(I2CMRead(psInst->psI2CInst, psInst->ui8Addr,
+ psInst->uCommand.pui8Buffer, 1, pui8Data, ui16Count,
+ LSM303DLHCCallback, psInst) == 0)
+ {
+ //
+ // The I2C write failed, so move to the idle state and return a
+ // failure.
+ //
+ psInst->ui8State = LSM303DLHC_STATE_IDLE;
+ return(0);
+ }
+
+ //
+ // Success.
+ //
+ return(1);
+}
+
+//*****************************************************************************
+//
+//! Writes data to LSM303DLHC registers.
+//!
+//! \param psInst is a pointer to the LSM303DLHC instance data.
+//! \param ui8Reg is the first register to write.
+//! \param pui8Data is a pointer to the data to write.
+//! \param ui16Count is the number of data bytes to write.
+//! \param pfnCallback is the function to be called when the data has been
+//! written (can be \b NULL if a callback is not required).
+//! \param pvCallbackData is a pointer that is passed to the callback function.
+//!
+//! This function writes a sequence of data values to consecutive registers in
+//! the LSM303DLHC. The first byte of the \e pui8Data buffer contains the
+//! value to be written into the \e ui8Reg register, the second value contains
+//! the data to be written into the next register, and so on.
+//!
+//! \return Returns 1 if the write was successfully started and 0 if it was
+//! not.
+//
+//*****************************************************************************
+uint_fast8_t
+LSM303DLHCMagWrite(tLSM303DLHCMag *psInst, uint_fast8_t ui8Reg,
+ const uint8_t *pui8Data, uint_fast16_t ui16Count,
+ tSensorCallback *pfnCallback, void *pvCallbackData)
+{
+ //
+ // Return a failure if the LSM303DLHC driver is not idle (in other words,
+ // there is already an outstanding request to the LSM303DLHC).
+ //
+ if(psInst->ui8State != LSM303DLHC_STATE_IDLE)
+ {
+ return(0);
+ }
+
+ //
+ // Save the callback information.
+ //
+ psInst->pfnCallback = pfnCallback;
+ psInst->pvCallbackData = pvCallbackData;
+
+ //
+ // See if the MAGNETO_CONFIG register is being written.
+ //
+ if((ui8Reg <= LSM303DLHC_O_MAG_CRB) &&
+ ((ui8Reg + ui16Count) > LSM303DLHC_O_MAG_CRB))
+ {
+ //
+ // Extract the FS_SEL from the MAGNETO_CONFIG register value.
+ //
+ psInst->ui8NewMagnetoFsSel = ((pui8Data[ui8Reg - LSM303DLHC_O_MAG_CRB] &
+ LSM303DLHC_MAG_CRB_GAIN_M) >>
+ LSM303DLHC_MAG_CRB_GAIN_S);
+ }
+
+ //
+ // Move the state machine to the wait for write state.
+ //
+ psInst->ui8State = LSM303DLHC_STATE_WRITE;
+
+ //
+ // Write the requested registers to the LSM303DLHC.
+ //
+ if(I2CMWrite8(&(psInst->uCommand.sWriteState), psInst->psI2CInst,
+ psInst->ui8Addr, ui8Reg, pui8Data, ui16Count,
+ LSM303DLHCCallback, psInst) == 0)
+ {
+ //
+ // The I2C write failed, so move to the idle state and return a
+ // failure.
+ //
+ psInst->ui8State = LSM303DLHC_STATE_IDLE;
+ return(0);
+ }
+
+ //
+ // Success.
+ //
+ return(1);
+}
+
+//*****************************************************************************
+//
+//! Performs a read-modify-write of a LSM303DLHC register.
+//!
+//! \param psInst is a pointer to the LSM303DLHC instance data.
+//! \param ui8Reg is the register to modify.
+//! \param ui8Mask is the bit mask that is ANDed with the current register
+//! value.
+//! \param ui8Value is the bit mask that is ORed with the result of the AND
+//! operation.
+//! \param pfnCallback is the function to be called when the data has been
+//! changed (can be \b NULL if a callback is not required).
+//! \param pvCallbackData is a pointer that is passed to the callback function.
+//!
+//! This function changes the value of a register in the LSM303DLHC via a
+//! read-modify-write operation, allowing one of the fields to be changed
+//! without disturbing the other fields. The \e ui8Reg register is read, ANDed
+//! with \e ui8Mask, ORed with \e ui8Value, and then written back to the
+//! LSM303DLHC.
+//!
+//! \return Returns 1 if the read-modify-write was successfully started and 0
+//! if it was not.
+//
+//*****************************************************************************
+uint_fast8_t
+LSM303DLHCMagReadModifyWrite(tLSM303DLHCMag *psInst, uint_fast8_t ui8Reg,
+ uint_fast8_t ui8Mask, uint_fast8_t ui8Value,
+ tSensorCallback *pfnCallback,
+ void *pvCallbackData)
+{
+ //
+ // Return a failure if the LSM303DLHC driver is not idle (in other words,
+ // there is already an outstanding request to the LSM303DLHC).
+ //
+ if(psInst->ui8State != LSM303DLHC_STATE_IDLE)
+ {
+ return(0);
+ }
+
+ //
+ // Save the callback information.
+ //
+ psInst->pfnCallback = pfnCallback;
+ psInst->pvCallbackData = pvCallbackData;
+
+ //
+ // Move the state machine to the wait for read-modify-write state.
+ //
+ psInst->ui8State = LSM303DLHC_STATE_RMW;
+
+ //
+ // Submit the read-modify-write request to the LSM303DLHC.
+ //
+ if(I2CMReadModifyWrite8(&(psInst->uCommand.sReadModifyWriteState),
+ psInst->psI2CInst, psInst->ui8Addr, ui8Reg,
+ ui8Mask, ui8Value, LSM303DLHCCallback,
+ psInst) == 0)
+ {
+ //
+ // The I2C read-modify-write failed, so move to the idle state and
+ // return a failure.
+ //
+ psInst->ui8State = LSM303DLHC_STATE_IDLE;
+ return(0);
+ }
+
+ //
+ // Success.
+ //
+ return(1);
+}
+
+//*****************************************************************************
+//
+//! Reads the magneto data from the LSM303DLHC.
+//!
+//! \param psInst is a pointer to the LSM303DLHC instance data.
+//! \param pfnCallback is the function to be called when the data has been read
+//! (can be \b NULL if a callback is not required).
+//! \param pvCallbackData is a pointer that is passed to the callback function.
+//!
+//! This function initiates a read of the LSM303DLHC data registers. When the
+//! read has completed (as indicated by calling the callback function), the new
+//! readings can be obtained via:
+//!
+//! - LSM303DLHCDataMagnetoGetRaw()
+//! - LSM303DLHCDataMagnetoGetFloat()
+//!
+//! \return Returns 1 if the read was successfully started and 0 if it was not.
+//
+//*****************************************************************************
+uint_fast8_t
+LSM303DLHCMagDataRead(tLSM303DLHCMag *psInst, tSensorCallback *pfnCallback,
+ void *pvCallbackData)
+{
+ //
+ // Return a failure if the LSM303DLHC driver is not idle (in other words,
+ // there is already an outstanding request to the LSM303DLHC).
+ //
+ if(psInst->ui8State != LSM303DLHC_STATE_IDLE)
+ {
+ return(0);
+ }
+
+ //
+ // Save the callback information.
+ //
+ psInst->pfnCallback = pfnCallback;
+ psInst->pvCallbackData = pvCallbackData;
+
+ //
+ // Move the state machine to the wait for data read state.
+ //
+ psInst->ui8State = LSM303DLHC_STATE_READ;
+
+ //
+ // Read the data registers from the LSM303DLHC.
+ //
+ psInst->pui8Data[0] = LSM303DLHC_O_MAG_OUT_X_MSB;
+ if(I2CMRead(psInst->psI2CInst, psInst->ui8Addr, psInst->pui8Data, 1,
+ psInst->pui8Data, 7, LSM303DLHCCallback, psInst) == 0)
+ {
+ //
+ // The I2C read failed, so move to the idle state and return a failure.
+ //
+ psInst->ui8State = LSM303DLHC_STATE_IDLE;
+ return(0);
+ }
+
+ //
+ // Success.
+ //
+ return(1);
+}
+
+//*****************************************************************************
+//
+//! Gets the raw magneto data from the most recent data read.
+//!
+//! \param psInst is a pointer to the LSM303DLHC instance data.
+//! \param pui16MagnetoX is a pointer to the value into which the raw X-axis
+//! magnetometer data is stored.
+//! \param pui16MagnetoY is a pointer to the value into which the raw Y-axis
+//! magnetometer data is stored.
+//! \param pui16MagnetoZ is a pointer to the value into which the raw Z-axis
+//! magnetometer data is stored.
+//!
+//! This function returns the raw magnetometer data from the most recent data
+//! read. The data is not manipulated in any way by the driver. If any of the
+//! output data pointers are \b NULL, the corresponding data is not provided.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+LSM303DLHCMagDataMagnetoGetRaw(tLSM303DLHCMag *psInst,
+ uint_fast16_t *pui16MagnetoX,
+ uint_fast16_t *pui16MagnetoY,
+ uint_fast16_t *pui16MagnetoZ)
+{
+ //
+ // Return the raw magnetometer values.
+ //
+ if(pui16MagnetoX)
+ {
+ *pui16MagnetoX = (psInst->pui8Data[0] << 8) | psInst->pui8Data[1];
+ }
+ if(pui16MagnetoY)
+ {
+ *pui16MagnetoY = (psInst->pui8Data[2] << 8) | psInst->pui8Data[3];
+ }
+ if(pui16MagnetoZ)
+ {
+ *pui16MagnetoZ = (psInst->pui8Data[4] << 8) | psInst->pui8Data[5];
+ }
+}
+
+//*****************************************************************************
+//
+//! Gets the magnetometer data from the most recent data read.
+//!
+//! \param psInst is a pointer to the LSM303DLHC instance data.
+//! \param pfMagnetoX is a pointer to the value into which the X-axis
+//! magnetometer data is stored.
+//! \param pfMagnetoY is a pointer to the value into which the Y-axis
+//! magnetometer data is stored.
+//! \param pfMagnetoZ is a pointer to the value into which the Z-axis
+//! magnetometer data is stored.
+//!
+//! This function returns the magnetometer data from the most recent data read,
+//! converted into radians per second. If any of the output data pointers are
+//! \b NULL, the corresponding data is not provided.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+LSM303DLHCMagDataMagnetoGetFloat(tLSM303DLHCMag *psInst, float *pfMagnetoX,
+ float *pfMagnetoY, float *pfMagnetoZ)
+{
+ float fFactor;
+
+ //
+ // Get the conversion factor for the current data format.
+ //
+ fFactor = g_pfLSM303DLHCMagnetoFactors[psInst->ui8MagnetoFsSel];
+
+ //
+ // Convert the magnetometer values into rad/sec
+ //
+ if(pfMagnetoX)
+ {
+ *pfMagnetoX = (float)(((int16_t)((psInst->pui8Data[0] << 8) |
+ psInst->pui8Data[1])) * fFactor);
+ }
+ if(pfMagnetoY)
+ {
+ *pfMagnetoY = (float)(((int16_t)((psInst->pui8Data[2] << 8) |
+ psInst->pui8Data[3])) * fFactor);
+ }
+ if(pfMagnetoZ)
+ {
+ *pfMagnetoZ = (float)(((int16_t)((psInst->pui8Data[4] << 8) |
+ psInst->pui8Data[5])) * fFactor);
+ }
+}
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
diff --git a/sensorlib/lsm303dlhc_mag.h b/sensorlib/lsm303dlhc_mag.h
new file mode 100644
index 0000000..a7426c3
--- /dev/null
+++ b/sensorlib/lsm303dlhc_mag.h
@@ -0,0 +1,164 @@
+//*****************************************************************************
+//
+// lsm303dlhc.c - Driver for the ST L3GD20H gyrometer
+//
+// Copyright (c) 2013-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
+//
+//*****************************************************************************
+
+#ifndef __SENSORLIB_LSM303DLHC_MAG_H__
+#define __SENSORLIB_LSM303DLHC_MAG_H__
+
+//*****************************************************************************
+//
+// If building with a C++ compiler, make all of the definitions in this header
+// have a C binding.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+//*****************************************************************************
+//
+// The structure that defines the internal state of the LSM303DLHC driver.
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ // The pointer to the I2C master interface instance used to communicate
+ // with the LSM303DLHC.
+ //
+ tI2CMInstance *psI2CInst;
+
+ //
+ // The I2C address of the LSM303DLHC.
+ //
+ uint8_t ui8Addr;
+
+ //
+ // The state of the state machine used while accessing the LSM303DLHC.
+ //
+ uint8_t ui8State;
+
+ //
+ // The current gyroscope fs_sel setting.
+ //
+ uint8_t ui8MagnetoFsSel;
+
+ //
+ // The new gyroscope fs_sel setting, which is used when a register write
+ // succeeds.
+ //
+ uint8_t ui8NewMagnetoFsSel;
+
+ //
+ // The data buffers used for sending/receiving data to/from the LSM303DLHC.
+ //
+ uint8_t pui8Data[8];
+
+ //
+ // The function that is called when the current request has completed
+ // processing.
+ //
+ tSensorCallback *pfnCallback;
+
+ //
+ // The callback data provided to the callback function.
+ //
+ void *pvCallbackData;
+
+ //
+ // A union of structures that are used for read, write and
+ // read-modify-write operations. Since only one operation can be active at
+ // a time, it is safe to re-use the memory in this manner.
+ //
+ union
+ {
+ //
+ // A buffer used to store the write portion of a register read.
+ //
+ uint8_t pui8Buffer[2];
+
+ //
+ // The write state used to write register values.
+ //
+ tI2CMWrite8 sWriteState;
+
+ //
+ // The read-modify-write state used to modify register values.
+ //
+ tI2CMReadModifyWrite8 sReadModifyWriteState;
+ }
+ uCommand;
+}
+tLSM303DLHCMag;
+
+//*****************************************************************************
+//
+// Function prototypes.
+//
+//*****************************************************************************
+extern uint_fast8_t LSM303DLHCMagInit(tLSM303DLHCMag *psInst,
+ tI2CMInstance *psI2CInst,
+ uint_fast8_t ui8I2CAddr,
+ tSensorCallback *pfnCallback,
+ void *pvCallbackData);
+extern uint_fast8_t LSM303DLHCMagRead(tLSM303DLHCMag *psInst,
+ uint_fast8_t ui8Reg,
+ uint8_t *pui8Data,
+ uint_fast16_t ui16Count,
+ tSensorCallback *pfnCallback,
+ void *pvCallbackData);
+extern uint_fast8_t LSM303DLHCMagWrite(tLSM303DLHCMag *psInst,
+ uint_fast8_t ui8Reg,
+ const uint8_t *pui8Data,
+ uint_fast16_t ui16Count,
+ tSensorCallback *pfnCallback,
+ void *pvCallbackData);
+extern uint_fast8_t LSM303DLHCMagReadModifyWrite(tLSM303DLHCMag *psInst,
+ uint_fast8_t ui8Reg,
+ uint_fast8_t ui8Mask,
+ uint_fast8_t ui8Value,
+ tSensorCallback *pfnCallback,
+ void *pvCallbackData);
+extern uint_fast8_t LSM303DLHCMagDataRead(tLSM303DLHCMag *psInst,
+ tSensorCallback *pfnCallback,
+ void *pvCallbackData);
+extern void LSM303DLHCMagDataMagnetoGetRaw(tLSM303DLHCMag *psInst,
+ uint_fast16_t *pui16MagnetoX,
+ uint_fast16_t *pui16MagnetoY,
+ uint_fast16_t *pui16MagnetoZ);
+extern void LSM303DLHCMagDataMagnetoGetFloat(tLSM303DLHCMag *psInst,
+ float *pfMagnetoX,
+ float *pfMagnetoY,
+ float *pfMagnetoZ);
+
+//*****************************************************************************
+//
+// Mark the end of the C bindings section for C++ compilers.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __SENSORLIB_LSM303DLHC_MAG_H__
diff --git a/sensorlib/magneto.c b/sensorlib/magneto.c
new file mode 100644
index 0000000..b7f7595
--- /dev/null
+++ b/sensorlib/magneto.c
@@ -0,0 +1,248 @@
+//*****************************************************************************
+//
+// magneto.c - Functions for manipulating magnetometer readings.
+//
+// Copyright (c) 2013-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
+//
+//*****************************************************************************
+
+#include <math.h>
+#include "sensorlib/magneto.h"
+
+//*****************************************************************************
+//
+//! \addtogroup magneto_api
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+//! Initializes the magnetometer hard- and soft-iron compensation state.
+//!
+//! \param psInst is a pointer to the magnetometer compensation state
+//! structure.
+//! \param fXOffset is the hard-iron compensation for the X axis.
+//! \param fYOffset is the hard-iron compensation for the Y axis.
+//! \param fZOffset is the hard-iron compensation for the Z axis.
+//! \param fXYAngle is the amount to rotate around the Z axis prior to scaling
+//! the Y axis reading, in radians.
+//! \param fYRatio is the amount to scale the Y axis reading.
+//! \param fXZAngle is the amount to rotate around the Y axis prior to scaling
+//! the Z axis reading, in radians.
+//! \param fZRatio is the amount to scale the Z axis reading.
+//!
+//! This function initializes the magnetometer compensation state structure
+//! with the values that are used to perform hard- and soft-iron compensation
+//! of magnetometer readings.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+MagnetoCompensateInit(tMagnetoCompensation *psInst, float fXOffset,
+ float fYOffset, float fZOffset, float fXYAngle,
+ float fYRatio, float fXZAngle, float fZRatio)
+{
+ //
+ // Save the hard- and soft-iron compensation values.
+ //
+ psInst->fXOffset = fXOffset;
+ psInst->fYOffset = fYOffset;
+ psInst->fZOffset = fZOffset;
+ psInst->fXYAngle = fXYAngle;
+ psInst->fYRatio = fYRatio;
+ psInst->fXZAngle = fXZAngle;
+ psInst->fZRatio = fZRatio;
+}
+
+//*****************************************************************************
+//
+//! Performs hard- and soft-iron compensation on magnetometer readings.
+//!
+//! \param psInst is a pointer to the magnetometer compensation state
+//! structure.
+//! \param pfMagnetoX is a pointer to the magnetometer X-axis reading.
+//! \param pfMagnetoY is a pointer to the magnetometer Y-axis reading.
+//! \param pfMagnetoZ is a pointer to the magnetometer Z-axis reading.
+//!
+//! This function performs hard- and soft-iron compensation on the given
+//! magnetometer reading. Hard-iron distortions cause a fixed offset in the
+//! reading, regardless of orientation. Hard-iron compensation is performed by
+//! negating this fixed offset.
+//!
+//! Soft-iron distortion is more complicated, causing an offset that varies as
+//! the sensor rotates, which results in the sensor returning an ellipse as it
+//! rotates instead of a circle. Performing soft-iron compensation requires
+//! rotating the sensor reading such that the major axis of the ellipse is
+//! aligned with one of the magnetometer axes, scaling one of the axes, then
+//! rotating the scaled sensor reading back. This operation is performed two
+//! times; once to scale the Y axis to the same scale as the X axis, and once
+//! again to scale the Z axis to the same scale as the X axis.
+//!
+//! Hard-iron compensation is performed prior to soft-iron compensation.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+MagnetoCompensate(tMagnetoCompensation *psInst, float *pfMagnetoX,
+ float *pfMagnetoY, float *pfMagnetoZ)
+{
+ float fSin, fCos, fX, fY, fZ, fTemp;
+
+ //
+ // Get the magnetometer values.
+ //
+ fX = *pfMagnetoX;
+ fY = *pfMagnetoY;
+ fZ = *pfMagnetoZ;
+
+ //
+ // Perform hard-iron distortion compensation.
+ //
+ fX += psInst->fXOffset;
+ fY += psInst->fYOffset;
+ fZ += psInst->fZOffset;
+
+ //
+ // Perform soft-iron distortion compensation on the X-Y plane. Start by
+ // computing the sine and cosine of the rotation angle (which will be used
+ // multiple times below).
+ //
+ fSin = sinf(psInst->fXYAngle);
+ fCos = cosf(psInst->fXYAngle);
+
+ //
+ // Rotate the magnetometer reading around the Z axis.
+ //
+ fTemp = (fCos * fX) - (fSin * fY);
+ fY = (fCos * fY) + (fSin * fX);
+ fX = fTemp;
+
+ //
+ // Scale the Y-axis reading so that it has the same range as the X-axis
+ // reading.
+ //
+ fY *= psInst->fYRatio;
+
+ //
+ // Rotate the magnetometer reading around the Z axis again, this time in
+ // the opposite direction.
+ //
+ fTemp = (fCos * fX) + (fSin * fY);
+ fY = (fCos * fY) - (fSin * fX);
+ fX = fTemp;
+
+ //
+ // Perform soft-iron distortion compensation on the X-Z plane. Start by
+ // computing the sine and cosine of the rotation angle (which will be used
+ // multiple times below).
+ //
+ fSin = sinf(psInst->fXZAngle);
+ fCos = cosf(psInst->fXZAngle);
+
+ //
+ // Rotate the magnetometer reading around the Y axis.
+ //
+ fTemp = (fCos * fZ) - (fSin * fX);
+ fX = (fCos * fX) + (fSin * fZ);
+ fZ = fTemp;
+
+ //
+ // Scale the Z-axis reading so that it has the same range as the X-axis
+ // reading.
+ //
+ fZ *= psInst->fZRatio;
+
+ //
+ // Rotate the magnetometer reading around the Y axis again, this time in
+ // the opposite direction.
+ //
+ fTemp = (fCos * fZ) + (fSin * fX);
+ fX = (fCos * fX) - (fSin * fZ);
+ fZ = fTemp;
+
+ //
+ // Return the compensated magnetometer values.
+ //
+ *pfMagnetoX = fX;
+ *pfMagnetoY = fY;
+ *pfMagnetoZ = fZ;
+}
+
+//*****************************************************************************
+//
+//! Computes the compass heading from magnetometer data and roll/pitch.
+//!
+//! \param fMagnetoX is the X component of the magnetometer reading.
+//! \param fMagnetoY is the Y component of the magnetometer reading.
+//! \param fMagnetoZ is the Z component of the magnetometer reading.
+//! \param fRoll is the roll angle, in radians.
+//! \param fPitch is the pitch angle, in radians.
+//!
+//! This function computes the compass heading by performing tilt compensation
+//! on the magnetometer reading.
+//!
+//! \return Returns the compass heading, in radians.
+//
+//*****************************************************************************
+float
+MagnetoHeadingCompute(float fMagnetoX, float fMagnetoY, float fMagnetoZ,
+ float fRoll, float fPitch)
+{
+ float fSinRoll, fCosRoll, fSinPitch, fCosPitch, fX, fY, fHeading;
+
+ //
+ // Compute the sine and cosine of the roll and pitch angles.
+ //
+ fSinRoll = sinf(fRoll);
+ fCosRoll = cosf(fRoll);
+ fSinPitch = sinf(fPitch);
+ fCosPitch = cosf(fPitch);
+
+ //
+ // Rotate the magnetometer data such that it is level with the ground,
+ // based on the provided roll and pitch.
+ //
+ fX = ((fMagnetoX * fCosPitch) + (fMagnetoY * fSinRoll * fSinPitch) +
+ (fMagnetoZ * fCosRoll * fSinPitch));
+ fY = (fMagnetoY * fCosRoll) - (fMagnetoZ * fSinRoll);
+
+ //
+ // Compute the compass heading and make it positive.
+ //
+ fHeading = atan2f(-fY, fX);
+ if(fHeading < 0)
+ {
+ fHeading += 2 * 3.141592;
+ }
+
+ //
+ // Return the computed compass heading.
+ //
+ return(fHeading);
+}
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
diff --git a/sensorlib/magneto.h b/sensorlib/magneto.h
new file mode 100644
index 0000000..811491e
--- /dev/null
+++ b/sensorlib/magneto.h
@@ -0,0 +1,92 @@
+//*****************************************************************************
+//
+// magneto.h - Prototypes for the functions that manipulate magnetometer
+// readings.
+//
+// Copyright (c) 2013-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
+//
+//*****************************************************************************
+
+#ifndef __SENSORLIB_MAGNETO_H__
+#define __SENSORLIB_MAGNETO_H__
+
+//*****************************************************************************
+//
+// The structure that defines the internal state of the magnetometer hard and
+// soft iron compensation.
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ // The hard iron induced offset in the X axis of the magnetometer.
+ //
+ float fXOffset;
+
+ //
+ // The hard iron induced offset in the Y axis of the magnetometer.
+ //
+ float fYOffset;
+
+ //
+ // The hard iron induced offset in the Z axis of the magnetometer.
+ //
+ float fZOffset;
+
+ //
+ // The Z axis rotation required to align the major/minor axes of the
+ // ellipse in the X-Y plane with the X-Y axes, specified in radians.
+ //
+ float fXYAngle;
+
+ //
+ // The amount to scale the Y axis in order to turn the X-Y ellipse into a
+ // circle.
+ //
+ float fYRatio;
+
+ //
+ // The Y axis rotation required to align the major/minor axes of the
+ // ellipse in the X-Z plane with X-Z axes, specified in radians.
+ //
+ float fXZAngle;
+
+ //
+ // The amount to scale the Z axis in order to turn the X-Z ellipse into a
+ // circle.
+ //
+ float fZRatio;
+}
+tMagnetoCompensation;
+
+//*****************************************************************************
+//
+// Prototypes.
+//
+//*****************************************************************************
+extern void MagnetoCompensateInit(tMagnetoCompensation *psInst, float fXOffset,
+ float fYOffset, float fZOffset,
+ float fXYAngle, float fYRatio,
+ float fXZAngle, float fZRatio);
+extern void MagnetoCompensate(tMagnetoCompensation *psInst, float *pfMagnetoX,
+ float *pfMagnetoY, float *pfMagnetoZ);
+extern float MagnetoHeadingCompute(float fMagnetoX, float fMagnetoY,
+ float fMagnetoZ, float fRoll, float fPitch);
+
+#endif // __SENSORLIB_MAGNETO_H__
diff --git a/sensorlib/mpu6050.c b/sensorlib/mpu6050.c
new file mode 100644
index 0000000..f095e40
--- /dev/null
+++ b/sensorlib/mpu6050.c
@@ -0,0 +1,879 @@
+//*****************************************************************************
+//
+// mpu6050.c - Driver for the MPU6050 accelerometer and gyroscope.
+//
+// Copyright (c) 2013-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
+//
+//*****************************************************************************
+
+#include <stdint.h>
+#include "sensorlib/hw_mpu6050.h"
+#include "sensorlib/i2cm_drv.h"
+#include "sensorlib/mpu6050.h"
+
+//*****************************************************************************
+//
+//! \addtogroup mpu6050_api
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// The states of the MPU6050 state machine.
+//
+//*****************************************************************************
+#define MPU6050_STATE_IDLE 0 // State machine is idle
+#define MPU6050_STATE_INIT_RES 1 // Waiting for initialization
+#define MPU6050_STATE_INIT_WAIT 2 // Waiting for reset to complete
+#define MPU6050_STATE_READ 3 // Waiting for read
+#define MPU6050_STATE_WRITE 4 // Waiting for write
+#define MPU6050_STATE_RMW 5 // Waiting for read-modify-write
+
+//*****************************************************************************
+//
+// The factors used to convert the acceleration readings from the MPU6050 into
+// floating point values in meters per second squared.
+//
+// Values are obtained by taking the g conversion factors from the data sheet
+// and multiplying by 9.81 (1 g = 9.81 m/s^2).
+//
+//*****************************************************************************
+static const float g_fMPU6050AccelFactors[] =
+{
+ 0.00059875, // Range = +/- 2 g (16384 lsb/g)
+ 0.00119751, // Range = +/- 4 g (8192 lsb/g)
+ 0.00239502, // Range = +/- 8 g (4096 lsb/g)
+ 0.00479004 // Range = +/- 16 g (2048 lsb/g)
+};
+
+//*****************************************************************************
+//
+// The factors used to convert the acceleration readings from the MPU6050 into
+// floating point values in radians per second.
+//
+// Values are obtained by taking the degree per second conversion factors
+// from the data sheet and then converting to radians per sec (1 degree =
+// 0.0174532925 radians).
+//
+//*****************************************************************************
+static const float g_fMPU6050GyroFactors[] =
+{
+ 1.3323124e-4f, // Range = +/- 250 dps (131.0 LSBs/DPS)
+ 2.6646248e-4f, // Range = +/- 500 dps (65.5 LSBs/DPS)
+ 5.3211258e-4f, // Range = +/- 1000 dps (32.8 LSBs/DPS)
+ 0.0010642252f // Range = +/- 2000 dps (16.4 LSBs/DPS)
+};
+//*****************************************************************************
+//
+// The callback function that is called when I2C transations to/from the
+// MPU6050 have completed.
+//
+//*****************************************************************************
+static void
+MPU6050Callback(void *pvCallbackData, uint_fast8_t ui8Status)
+{
+ tMPU6050 *psInst;
+
+ //
+ // Convert the instance data into a pointer to a tMPU6050 structure.
+ //
+ psInst = pvCallbackData;
+
+ //
+ // If the I2C master driver encountered a failure, force the state machine
+ // to the idle state (which will also result in a callback to propagate the
+ // error). Except in the case that we are in the reset wait state and the
+ // error is an address NACK. This error is handled by the reset wait
+ // state.
+ //
+ if((ui8Status != I2CM_STATUS_SUCCESS) &&
+ !((ui8Status == I2CM_STATUS_ADDR_NACK) &&
+ (psInst->ui8State == MPU6050_STATE_INIT_WAIT)))
+ {
+ psInst->ui8State = MPU6050_STATE_IDLE;
+ }
+
+ //
+ // Determine the current state of the MPU6050 state machine.
+ //
+ switch(psInst->ui8State)
+ {
+ //
+ // All states that trivially transition to IDLE, and all unknown
+ // states.
+ //
+ case MPU6050_STATE_READ:
+ default:
+ {
+ //
+ // The state machine is now idle.
+ //
+ psInst->ui8State = MPU6050_STATE_IDLE;
+
+ //
+ // Done.
+ //
+ break;
+ }
+
+ //
+ // MPU6050 Device reset was issued
+ //
+ case MPU6050_STATE_INIT_RES:
+ {
+ //
+ // Issue a read of the status register to confirm reset is done.
+ //
+ psInst->uCommand.pui8Buffer[0] = MPU6050_O_PWR_MGMT_1;
+ I2CMRead(psInst->psI2CInst, psInst->ui8Addr,
+ psInst->uCommand.pui8Buffer, 1, psInst->pui8Data, 1,
+ MPU6050Callback, psInst);
+
+ psInst->ui8State = MPU6050_STATE_INIT_WAIT;
+ break;
+ }
+
+ //
+ // Status register was read, check if reset is done before proceeding.
+ //
+ case MPU6050_STATE_INIT_WAIT:
+ {
+ //
+ // Check the value read back from status to determine if device
+ // is still in reset or if it is ready. Reset state for this
+ // register is 0x40, which has sleep bit set. Device may also
+ // respond with an address NACK during very early stages of the its
+ // internal reset. Keep polling until we verify device is ready.
+ //
+ //
+ if((psInst->pui8Data[0] != MPU6050_PWR_MGMT_1_SLEEP) ||
+ (ui8Status == I2CM_STATUS_ADDR_NACK))
+ {
+ //
+ // Device still in reset so begin polling this register.
+ //
+ psInst->uCommand.pui8Buffer[0] = MPU6050_O_PWR_MGMT_1;
+ I2CMRead(psInst->psI2CInst, psInst->ui8Addr,
+ psInst->uCommand.pui8Buffer, 1, psInst->pui8Data, 1,
+ MPU6050Callback, psInst);
+
+ //
+ // Intentionally stay in this state to create polling effect.
+ //
+ }
+ else
+ {
+ //
+ // Device is out of reset, move to the idle state.
+ //
+ psInst->ui8State = MPU6050_STATE_IDLE;
+ }
+ break;
+ }
+
+ //
+ // A write just completed
+ //
+ case MPU6050_STATE_WRITE:
+ {
+ //
+ // Set the accelerometer and gyroscope ranges to the new values.
+ // If the register was not modified, the values will be the same so
+ // this has no effect.
+ //
+ psInst->ui8AccelAfsSel = psInst->ui8NewAccelAfsSel;
+ psInst->ui8GyroFsSel = psInst->ui8NewGyroFsSel;
+
+ //
+ // The state machine is now idle.
+ //
+ psInst->ui8State = MPU6050_STATE_IDLE;
+
+ //
+ // Done.
+ //
+ break;
+ }
+
+ //
+ // A read-modify-write just completed
+ //
+ case MPU6050_STATE_RMW:
+ {
+ //
+ // See if the PWR_MGMT_1 register was just modified.
+ //
+ if(psInst->uCommand.sReadModifyWriteState.pui8Buffer[0] ==
+ MPU6050_O_PWR_MGMT_1)
+ {
+ //
+ // See if a soft reset has been issued.
+ //
+ if(psInst->uCommand.sReadModifyWriteState.pui8Buffer[1] &
+ MPU6050_PWR_MGMT_1_DEVICE_RESET)
+ {
+ //
+ // Default range setting is +/- 2 g
+ //
+ psInst->ui8AccelAfsSel = 0;
+ psInst->ui8NewAccelAfsSel = 0;
+
+ //
+ // Default range setting is +/- 250 degrees/s
+ //
+ psInst->ui8GyroFsSel = 0;
+ psInst->ui8NewGyroFsSel = 0;
+ }
+ }
+
+ //
+ // See if the GYRO_CONFIG register was just modified.
+ //
+ if(psInst->uCommand.sReadModifyWriteState.pui8Buffer[0] ==
+ MPU6050_O_GYRO_CONFIG)
+ {
+ //
+ // Extract the FS_SEL from the GYRO_CONFIG register value.
+ //
+ psInst->ui8GyroFsSel =
+ ((psInst->uCommand.sReadModifyWriteState.pui8Buffer[1] &
+ MPU6050_GYRO_CONFIG_FS_SEL_M) >>
+ MPU6050_GYRO_CONFIG_FS_SEL_S);
+ }
+
+ //
+ // See if the ACCEL_CONFIG register was just modified.
+ //
+ if(psInst->uCommand.sReadModifyWriteState.pui8Buffer[0] ==
+ MPU6050_O_ACCEL_CONFIG)
+ {
+ //
+ // Extract the FS_SEL from the ACCEL_CONFIG register value.
+ //
+ psInst->ui8AccelAfsSel =
+ ((psInst->uCommand.sReadModifyWriteState.pui8Buffer[1] &
+ MPU6050_ACCEL_CONFIG_AFS_SEL_M) >>
+ MPU6050_ACCEL_CONFIG_AFS_SEL_S);
+ }
+
+ //
+ // The state machine is now idle.
+ //
+ psInst->ui8State = MPU6050_STATE_IDLE;
+
+ //
+ // Done.
+ //
+ break;
+ }
+ }
+
+ //
+ // See if the state machine is now idle and there is a callback function.
+ //
+ if((psInst->ui8State == MPU6050_STATE_IDLE) && psInst->pfnCallback)
+ {
+ //
+ // Call the application-supplied callback function.
+ //
+ psInst->pfnCallback(psInst->pvCallbackData, ui8Status);
+ }
+}
+
+//*****************************************************************************
+//
+//! Initializes the MPU6050 driver.
+//!
+//! \param psInst is a pointer to the MPU6050 instance data.
+//! \param psI2CInst is a pointer to the I2C master driver instance data.
+//! \param ui8I2CAddr is the I2C address of the MPU6050 device.
+//! \param pfnCallback is the function to be called when the initialization has
+//! completed (can be \b NULL if a callback is not required).
+//! \param pvCallbackData is a pointer that is passed to the callback function.
+//!
+//! This function initializes the MPU6050 driver, preparing it for operation.
+//!
+//! \return Returns 1 if the MPU6050 driver was successfully initialized and 0
+//! if it was not.
+//
+//*****************************************************************************
+uint_fast8_t
+MPU6050Init(tMPU6050 *psInst, tI2CMInstance *psI2CInst,
+ uint_fast8_t ui8I2CAddr, tSensorCallback *pfnCallback,
+ void *pvCallbackData)
+{
+ //
+ // Initialize the MPU6050 instance structure.
+ //
+ psInst->psI2CInst = psI2CInst;
+ psInst->ui8Addr = ui8I2CAddr;
+
+ //
+ // Save the callback information.
+ //
+ psInst->pfnCallback = pfnCallback;
+ psInst->pvCallbackData = pvCallbackData;
+
+ //
+ // Default range setting is +/- 2 g
+ //
+ psInst->ui8AccelAfsSel = (MPU6050_ACCEL_CONFIG_AFS_SEL_2G >>
+ MPU6050_ACCEL_CONFIG_AFS_SEL_S);
+ psInst->ui8NewAccelAfsSel = (MPU6050_ACCEL_CONFIG_AFS_SEL_2G >>
+ MPU6050_ACCEL_CONFIG_AFS_SEL_S);
+
+ //
+ // Default range setting is +/- 250 degrees/s
+ //
+ psInst->ui8GyroFsSel = (MPU6050_GYRO_CONFIG_FS_SEL_250 >>
+ MPU6050_GYRO_CONFIG_FS_SEL_S);
+ psInst->ui8NewGyroFsSel = (MPU6050_GYRO_CONFIG_FS_SEL_250 >>
+ MPU6050_GYRO_CONFIG_FS_SEL_S);
+
+ //
+ // Set the state to show we are initiating a reset.
+ //
+ psInst->ui8State = MPU6050_STATE_INIT_RES;
+
+ //
+ // Load the buffer with command to perform device reset
+ //
+ psInst->uCommand.pui8Buffer[0] = MPU6050_O_PWR_MGMT_1;
+ psInst->uCommand.pui8Buffer[1] = MPU6050_PWR_MGMT_1_DEVICE_RESET;
+ if(I2CMWrite(psInst->psI2CInst, psInst->ui8Addr,
+ psInst->uCommand.pui8Buffer, 2, MPU6050Callback, psInst) == 0)
+ {
+ psInst->ui8State = MPU6050_STATE_IDLE;
+ return(0);
+ }
+
+ //
+ // Success
+ //
+ return(1);
+}
+
+//*****************************************************************************
+//
+//! Reads data from MPU6050 registers.
+//!
+//! \param psInst is a pointer to the MPU6050 instance data.
+//! \param ui8Reg is the first register to read.
+//! \param pui8Data is a pointer to the location to store the data that is
+//! read.
+//! \param ui16Count is the number of data bytes to read.
+//! \param pfnCallback is the function to be called when the data has been read
+//! (can be \b NULL if a callback is not required).
+//! \param pvCallbackData is a pointer that is passed to the callback function.
+//!
+//! This function reads a sequence of data values from consecutive registers in
+//! the MPU6050.
+//!
+//! \return Returns 1 if the write was successfully started and 0 if it was
+//! not.
+//
+//*****************************************************************************
+uint_fast8_t
+MPU6050Read(tMPU6050 *psInst, uint_fast8_t ui8Reg, uint8_t *pui8Data,
+ uint_fast16_t ui16Count, tSensorCallback *pfnCallback,
+ void *pvCallbackData)
+{
+ //
+ // Return a failure if the MPU6050 driver is not idle (in other words,
+ // there is already an outstanding request to the MPU6050).
+ //
+ if(psInst->ui8State != MPU6050_STATE_IDLE)
+ {
+ return(0);
+ }
+
+ //
+ // Save the callback information.
+ //
+ psInst->pfnCallback = pfnCallback;
+ psInst->pvCallbackData = pvCallbackData;
+
+ //
+ // Move the state machine to the wait for read state.
+ //
+ psInst->ui8State = MPU6050_STATE_READ;
+
+ //
+ // Read the requested registers from the MPU6050.
+ //
+ psInst->uCommand.pui8Buffer[0] = ui8Reg;
+ if(I2CMRead(psInst->psI2CInst, psInst->ui8Addr,
+ psInst->uCommand.pui8Buffer, 1, pui8Data, ui16Count,
+ MPU6050Callback, psInst) == 0)
+ {
+ //
+ // The I2C write failed, so move to the idle state and return a
+ // failure.
+ //
+ psInst->ui8State = MPU6050_STATE_IDLE;
+ return(0);
+ }
+
+ //
+ // Success.
+ //
+ return(1);
+}
+
+//*****************************************************************************
+//
+//! Writes data to MPU6050 registers.
+//!
+//! \param psInst is a pointer to the MPU6050 instance data.
+//! \param ui8Reg is the first register to write.
+//! \param pui8Data is a pointer to the data to write.
+//! \param ui16Count is the number of data bytes to write.
+//! \param pfnCallback is the function to be called when the data has been
+//! written (can be \b NULL if a callback is not required).
+//! \param pvCallbackData is a pointer that is passed to the callback function.
+//!
+//! This function writes a sequence of data values to consecutive registers in
+//! the MPU6050. The first byte of the \e pui8Data buffer contains the value
+//! to be written into the \e ui8Reg register, the second value contains the
+//! data to be written into the next register, and so on.
+//!
+//! \return Returns 1 if the write was successfully started and 0 if it was
+//! not.
+//
+//*****************************************************************************
+uint_fast8_t
+MPU6050Write(tMPU6050 *psInst, uint_fast8_t ui8Reg, const uint8_t *pui8Data,
+ uint_fast16_t ui16Count, tSensorCallback *pfnCallback,
+ void *pvCallbackData)
+{
+ //
+ // Return a failure if the MPU6050 driver is not idle (in other words,
+ // there is already an outstanding request to the MPU6050).
+ //
+ if(psInst->ui8State != MPU6050_STATE_IDLE)
+ {
+ return(0);
+ }
+
+ //
+ // Save the callback information.
+ //
+ psInst->pfnCallback = pfnCallback;
+ psInst->pvCallbackData = pvCallbackData;
+
+ //
+ // See if the PWR_MGMT_1 register is being written.
+ //
+ if((ui8Reg <= MPU6050_O_PWR_MGMT_1) &&
+ ((ui8Reg + ui16Count) > MPU6050_O_PWR_MGMT_1))
+ {
+ //
+ // See if a soft reset is being requested.
+ //
+ if(pui8Data[ui8Reg - MPU6050_O_PWR_MGMT_1] &
+ MPU6050_PWR_MGMT_1_DEVICE_RESET)
+ {
+ //
+ // Default range setting is +/- 2 g.
+ //
+ psInst->ui8NewAccelAfsSel = 0;
+
+ //
+ // Default range setting is +/- 250 degrees/s.
+ //
+ psInst->ui8NewGyroFsSel = 0;
+ }
+ }
+
+ //
+ // See if the GYRO_CONFIG register is being written.
+ //
+ if((ui8Reg <= MPU6050_O_GYRO_CONFIG) &&
+ ((ui8Reg + ui16Count) > MPU6050_O_GYRO_CONFIG))
+ {
+ //
+ // Extract the FS_SEL from the GYRO_CONFIG register value.
+ //
+ psInst->ui8NewGyroFsSel = ((pui8Data[ui8Reg - MPU6050_O_GYRO_CONFIG] &
+ MPU6050_GYRO_CONFIG_FS_SEL_M) >>
+ MPU6050_GYRO_CONFIG_FS_SEL_S);
+ }
+
+ //
+ // See if the ACCEL_CONFIG register is being written.
+ //
+ if((ui8Reg <= MPU6050_O_ACCEL_CONFIG) &&
+ ((ui8Reg + ui16Count) > MPU6050_O_ACCEL_CONFIG))
+ {
+ //
+ // Extract the AFS_SEL from the ACCEL_CONFIG register value.
+ //
+ psInst->ui8NewAccelAfsSel =
+ ((pui8Data[ui8Reg - MPU6050_O_ACCEL_CONFIG] &
+ MPU6050_ACCEL_CONFIG_AFS_SEL_M) >>
+ MPU6050_ACCEL_CONFIG_AFS_SEL_S);
+ }
+
+ //
+ // Move the state machine to the wait for write state.
+ //
+ psInst->ui8State = MPU6050_STATE_WRITE;
+
+ //
+ // Write the requested registers to the MPU6050.
+ //
+ if(I2CMWrite8(&(psInst->uCommand.sWriteState), psInst->psI2CInst,
+ psInst->ui8Addr, ui8Reg, pui8Data, ui16Count,
+ MPU6050Callback, psInst) == 0)
+ {
+ //
+ // The I2C write failed, so move to the idle state and return a
+ // failure.
+ //
+ psInst->ui8State = MPU6050_STATE_IDLE;
+ return(0);
+ }
+
+ //
+ // Success.
+ //
+ return(1);
+}
+
+//*****************************************************************************
+//
+//! Performs a read-modify-write of a MPU6050 register.
+//!
+//! \param psInst is a pointer to the MPU6050 instance data.
+//! \param ui8Reg is the register to modify.
+//! \param ui8Mask is the bit mask that is ANDed with the current register
+//! value.
+//! \param ui8Value is the bit mask that is ORed with the result of the AND
+//! operation.
+//! \param pfnCallback is the function to be called when the data has been
+//! changed (can be \b NULL if a callback is not required).
+//! \param pvCallbackData is a pointer that is passed to the callback function.
+//!
+//! This function changes the value of a register in the MPU6050 via a
+//! read-modify-write operation, allowing one of the fields to be changed
+//! without disturbing the other fields. The \e ui8Reg register is read, ANDed
+//! with \e ui8Mask, ORed with \e ui8Value, and then written back to the
+//! MPU6050.
+//!
+//! \return Returns 1 if the read-modify-write was successfully started and 0
+//! if it was not.
+//
+//*****************************************************************************
+uint_fast8_t
+MPU6050ReadModifyWrite(tMPU6050 *psInst, uint_fast8_t ui8Reg,
+ uint_fast8_t ui8Mask, uint_fast8_t ui8Value,
+ tSensorCallback *pfnCallback, void *pvCallbackData)
+{
+ //
+ // Return a failure if the MPU6050 driver is not idle (in other words,
+ // there is already an outstanding request to the MPU6050).
+ //
+ if(psInst->ui8State != MPU6050_STATE_IDLE)
+ {
+ return(0);
+ }
+
+ //
+ // Save the callback information.
+ //
+ psInst->pfnCallback = pfnCallback;
+ psInst->pvCallbackData = pvCallbackData;
+
+ //
+ // Move the state machine to the wait for read-modify-write state.
+ //
+ psInst->ui8State = MPU6050_STATE_RMW;
+
+ //
+ // Submit the read-modify-write request to the MPU6050.
+ //
+ if(I2CMReadModifyWrite8(&(psInst->uCommand.sReadModifyWriteState),
+ psInst->psI2CInst, psInst->ui8Addr, ui8Reg,
+ ui8Mask, ui8Value, MPU6050Callback, psInst) == 0)
+ {
+ //
+ // The I2C read-modify-write failed, so move to the idle state and
+ // return a failure.
+ //
+ psInst->ui8State = MPU6050_STATE_IDLE;
+ return(0);
+ }
+
+ //
+ // Success.
+ //
+ return(1);
+}
+
+//*****************************************************************************
+//
+//! Reads the accelerometer and gyroscope data from the MPU6050.
+//!
+//! \param psInst is a pointer to the MPU6050 instance data.
+//! \param pfnCallback is the function to be called when the data has been read
+//! (can be \b NULL if a callback is not required).
+//! \param pvCallbackData is a pointer that is passed to the callback function.
+//!
+//! This function initiates a read of the MPU6050 data registers. When the
+//! read has completed (as indicated by calling the callback function), the new
+//! readings can be obtained via:
+//!
+//! - MPU6050DataAccelGetRaw()
+//! - MPU6050DataAccelGetFloat()
+//! - MPU6050DataGyroGetRaw()
+//! - MPU6050DataGyroGetFloat()
+//!
+//! \return Returns 1 if the read was successfully started and 0 if it was not.
+//
+//*****************************************************************************
+uint_fast8_t
+MPU6050DataRead(tMPU6050 *psInst, tSensorCallback *pfnCallback,
+ void *pvCallbackData)
+{
+ //
+ // Return a failure if the MPU6050 driver is not idle (in other words,
+ // there is already an outstanding request to the MPU6050).
+ //
+ if(psInst->ui8State != MPU6050_STATE_IDLE)
+ {
+ return(0);
+ }
+
+ //
+ // Save the callback information.
+ //
+ psInst->pfnCallback = pfnCallback;
+ psInst->pvCallbackData = pvCallbackData;
+
+ //
+ // Move the state machine to the wait for data read state.
+ //
+ psInst->ui8State = MPU6050_STATE_READ;
+
+ //
+ // Read the data registers from the MPU6050.
+ //
+ psInst->pui8Data[0] = MPU6050_O_ACCEL_XOUT_H;
+ if(I2CMRead(psInst->psI2CInst, psInst->ui8Addr, psInst->pui8Data, 1,
+ psInst->pui8Data, 14, MPU6050Callback, psInst) == 0)
+ {
+ //
+ // The I2C read failed, so move to the idle state and return a failure.
+ //
+ psInst->ui8State = MPU6050_STATE_IDLE;
+ return(0);
+ }
+
+ //
+ // Success.
+ //
+ return(1);
+}
+
+//*****************************************************************************
+//
+//! Gets the raw accelerometer data from the most recent data read.
+//!
+//! \param psInst is a pointer to the MPU6050 instance data.
+//! \param pui16AccelX is a pointer to the value into which the raw X-axis
+//! accelerometer data is stored.
+//! \param pui16AccelY is a pointer to the value into which the raw Y-axis
+//! accelerometer data is stored.
+//! \param pui16AccelZ is a pointer to the value into which the raw Z-axis
+//! accelerometer data is stored.
+//!
+//! This function returns the raw accelerometer data from the most recent data
+//! read. The data is not manipulated in any way by the driver. If any of the
+//! output data pointers are \b NULL, the corresponding data is not provided.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+MPU6050DataAccelGetRaw(tMPU6050 *psInst, uint_fast16_t *pui16AccelX,
+ uint_fast16_t *pui16AccelY, uint_fast16_t *pui16AccelZ)
+{
+ //
+ // Return the raw accelerometer values.
+ //
+ if(pui16AccelX)
+ {
+ *pui16AccelX = (psInst->pui8Data[0] << 8) | psInst->pui8Data[1];
+ }
+ if(pui16AccelY)
+ {
+ *pui16AccelY = (psInst->pui8Data[2] << 8) | psInst->pui8Data[3];
+ }
+ if(pui16AccelZ)
+ {
+ *pui16AccelZ = (psInst->pui8Data[4] << 8) | psInst->pui8Data[5];
+ }
+}
+
+//*****************************************************************************
+//
+//! Gets the accelerometer data from the most recent data read.
+//!
+//! \param psInst is a pointer to the MPU6050 instance data.
+//! \param pfAccelX is a pointer to the value into which the X-axis
+//! accelerometer data is stored.
+//! \param pfAccelY is a pointer to the value into which the Y-axis
+//! accelerometer data is stored.
+//! \param pfAccelZ is a pointer to the value into which the Z-axis
+//! accelerometer data is stored.
+//!
+//! This function returns the accelerometer data from the most recent data
+//! read, converted into meters per second squared (m/s^2). If any of the
+//! output data pointers are \b NULL, the corresponding data is not provided.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+MPU6050DataAccelGetFloat(tMPU6050 *psInst, float *pfAccelX, float *pfAccelY,
+ float *pfAccelZ)
+{
+ float fFactor;
+
+ //
+ // Get the acceleration conversion factor for the current data format.
+ //
+ fFactor = g_fMPU6050AccelFactors[psInst->ui8AccelAfsSel];
+
+ //
+ // Convert the Accelerometer values into floating-point gravity values.
+ //
+ if(pfAccelX)
+ {
+ *pfAccelX = (float)((int16_t)((psInst->pui8Data[0] << 8) |
+ psInst->pui8Data[1]) * fFactor);
+ }
+ if(pfAccelY)
+ {
+ *pfAccelY = (float)((int16_t)((psInst->pui8Data[2] << 8) |
+ psInst->pui8Data[3]) * fFactor);
+ }
+ if(pfAccelZ)
+ {
+ *pfAccelZ = (float)((int16_t)((psInst->pui8Data[4] << 8) |
+ psInst->pui8Data[5]) * fFactor);
+ }
+}
+//*****************************************************************************
+//
+//! Gets the raw gyroscope data from the most recent data read.
+//!
+//! \param psInst is a pointer to the MPU6050 instance data.
+//! \param pui16GyroX is a pointer to the value into which the raw X-axis
+//! gyroscope data is stored.
+//! \param pui16GyroY is a pointer to the value into which the raw Y-axis
+//! gyroscope data is stored.
+//! \param pui16GyroZ is a pointer to the value into which the raw Z-axis
+//! gyroscope data is stored.
+//!
+//! This function returns the raw gyroscope data from the most recent data
+//! read. The data is not manipulated in any way by the driver. If any of the
+//! output data pointers are \b NULL, the corresponding data is not provided.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+MPU6050DataGyroGetRaw(tMPU6050 *psInst, uint_fast16_t *pui16GyroX,
+ uint_fast16_t *pui16GyroY, uint_fast16_t *pui16GyroZ)
+{
+ //
+ // Return the raw gyroscope values.
+ //
+ if(pui16GyroX)
+ {
+ *pui16GyroX = (psInst->pui8Data[8] << 8) | psInst->pui8Data[9];
+ }
+ if(pui16GyroY)
+ {
+ *pui16GyroY = (psInst->pui8Data[10] << 8) | psInst->pui8Data[11];
+ }
+ if(pui16GyroZ)
+ {
+ *pui16GyroZ = (psInst->pui8Data[12] << 8) | psInst->pui8Data[13];
+ }
+}
+
+//*****************************************************************************
+//
+//! Gets the gyroscope data from the most recent data read.
+//!
+//! \param psInst is a pointer to the MPU6050 instance data.
+//! \param pfGyroX is a pointer to the value into which the X-axis
+//! gyroscope data is stored.
+//! \param pfGyroY is a pointer to the value into which the Y-axis
+//! gyroscope data is stored.
+//! \param pfGyroZ is a pointer to the value into which the Z-axis
+//! gyroscope data is stored.
+//!
+//! This function returns the gyroscope data from the most recent data read,
+//! converted into radians per second. If any of the output data pointers are
+//! \b NULL, the corresponding data is not provided.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+MPU6050DataGyroGetFloat(tMPU6050 *psInst, float *pfGyroX, float *pfGyroY,
+ float *pfGyroZ)
+{
+ float fFactor;
+
+ //
+ // Get the conversion factor for the current data format.
+ //
+ fFactor = g_fMPU6050GyroFactors[psInst->ui8GyroFsSel];
+
+ //
+ // Convert the gyroscope values into rad/sec
+ //
+ if(pfGyroX)
+ {
+ *pfGyroX = ((float)(int16_t)((psInst->pui8Data[8] << 8) |
+ psInst->pui8Data[9]) * fFactor);
+ }
+ if(pfGyroY)
+ {
+ *pfGyroY = ((float)(int16_t)((psInst->pui8Data[10] << 8) |
+ psInst->pui8Data[11]) * fFactor);
+ }
+ if(pfGyroZ)
+ {
+ *pfGyroZ = ((float)(int16_t)((psInst->pui8Data[12] << 8) |
+ psInst->pui8Data[13]) * fFactor);
+ }
+}
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
diff --git a/sensorlib/mpu6050.h b/sensorlib/mpu6050.h
new file mode 100644
index 0000000..ec11ab8
--- /dev/null
+++ b/sensorlib/mpu6050.h
@@ -0,0 +1,174 @@
+//*****************************************************************************
+//
+// mpu6050.h - Prototypes for the MPU6050 accelerometer and gyroscope driver.
+//
+// Copyright (c) 2013-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
+//
+//*****************************************************************************
+
+#ifndef __SENSORLIB_MPU6050_H__
+#define __SENSORLIB_MPU6050_H__
+
+//*****************************************************************************
+//
+// If building with a C++ compiler, make all of the definitions in this header
+// have a C binding.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+//*****************************************************************************
+//
+// The structure that defines the internal state of the MPU6050 driver.
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ // The pointer to the I2C master interface instance used to communicate
+ // with the MPU6050.
+ //
+ tI2CMInstance *psI2CInst;
+
+ //
+ // The I2C address of the MPU6050.
+ //
+ uint8_t ui8Addr;
+
+ //
+ // The state of the state machine used while accessing the MPU6050.
+ //
+ uint8_t ui8State;
+
+ //
+ // The current accelerometer afs_sel setting.
+ //
+ uint8_t ui8AccelAfsSel;
+
+ //
+ // The new accelerometer afs_sel setting, which is used when a register
+ // write succeeds.
+ //
+ uint8_t ui8NewAccelAfsSel;
+
+ //
+ // The current gyroscope fs_sel setting.
+ //
+ uint8_t ui8GyroFsSel;
+
+ //
+ // The new gyroscope fs_sel setting, which is used when a register write
+ // succeeds.
+ //
+ uint8_t ui8NewGyroFsSel;
+
+ //
+ // The data buffer used for sending/receiving data to/from the MPU6050.
+ //
+ uint8_t pui8Data[16];
+
+ //
+ // The function that is called when the current request has completed
+ // processing.
+ //
+ tSensorCallback *pfnCallback;
+
+ //
+ // The callback data provided to the callback function.
+ //
+ void *pvCallbackData;
+
+ //
+ // A union of structures that are used for read, write and
+ // read-modify-write operations. Since only one operation can be active at
+ // a time, it is safe to re-use the memory in this manner.
+ //
+ union
+ {
+ //
+ // A buffer used to store the write portion of a register read.
+ //
+ uint8_t pui8Buffer[2];
+
+ //
+ // The write state used to write register values.
+ //
+ tI2CMWrite8 sWriteState;
+
+ //
+ // The read-modify-write state used to modify register values.
+ //
+ tI2CMReadModifyWrite8 sReadModifyWriteState;
+ }
+ uCommand;
+}
+tMPU6050;
+
+//*****************************************************************************
+//
+// Function prototypes.
+//
+//*****************************************************************************
+extern uint_fast8_t MPU6050Init(tMPU6050 *psInst, tI2CMInstance *psI2CInst,
+ uint_fast8_t ui8I2CAddr,
+ tSensorCallback *pfnCallback,
+ void *pvCallbackData);
+extern uint_fast8_t MPU6050Read(tMPU6050 *psInst, uint_fast8_t ui8Reg,
+ uint8_t *pui8Data, uint_fast16_t ui16Count,
+ tSensorCallback *pfnCallback,
+ void *pvCallbackData);
+extern uint_fast8_t MPU6050Write(tMPU6050 *psInst, uint_fast8_t ui8Reg,
+ const uint8_t *pui8Data,
+ uint_fast16_t ui16Count,
+ tSensorCallback *pfnCallback,
+ void *pvCallbackData);
+extern uint_fast8_t MPU6050ReadModifyWrite(tMPU6050 *psInst,
+ uint_fast8_t ui8Reg,
+ uint_fast8_t ui8Mask,
+ uint_fast8_t ui8Value,
+ tSensorCallback *pfnCallback,
+ void *pvCallbackData);
+extern uint_fast8_t MPU6050DataRead(tMPU6050 *psInst,
+ tSensorCallback *pfnCallback,
+ void *pvCallbackData);
+extern void MPU6050DataAccelGetRaw(tMPU6050 *psInst,
+ uint_fast16_t *pui16AccelX,
+ uint_fast16_t *pui16AccelY,
+ uint_fast16_t *pui16AccelZ);
+extern void MPU6050DataAccelGetFloat(tMPU6050 *psInst, float *pfAccelX,
+ float *pfAccelY, float *pfAccelZ);
+extern void MPU6050DataGyroGetRaw(tMPU6050 *psInst, uint_fast16_t *pui16GyroX,
+ uint_fast16_t *pui16GyroY,
+ uint_fast16_t *pui16GyroZ);
+extern void MPU6050DataGyroGetFloat(tMPU6050 *psInst, float *pfGyroX,
+ float *pfGyroY, float *pfGyroZ);
+
+//*****************************************************************************
+//
+// Mark the end of the C bindings section for C++ compilers.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __SENSORLIB_MPU6050_H__
diff --git a/sensorlib/mpu9150.c b/sensorlib/mpu9150.c
new file mode 100644
index 0000000..a1515e2
--- /dev/null
+++ b/sensorlib/mpu9150.c
@@ -0,0 +1,1180 @@
+//*****************************************************************************
+//
+// mpu9150.c - Driver for the MPU9150 accelerometer, gyroscope, and
+// magnetometer.
+//
+// Copyright (c) 2013-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
+//
+//*****************************************************************************
+
+#include <stdint.h>
+#include "sensorlib/hw_ak8975.h"
+#include "sensorlib/hw_mpu9150.h"
+#include "sensorlib/i2cm_drv.h"
+#include "sensorlib/ak8975.h"
+#include "sensorlib/mpu9150.h"
+
+//*****************************************************************************
+//
+//! \addtogroup mpu9150_api
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// The states of the MPU9150 state machine.
+//
+//*****************************************************************************
+#define MPU9150_STATE_IDLE 0 // State machine is idle
+#define MPU9150_STATE_LAST 1 // Last step in a sequence
+#define MPU9150_STATE_READ 2 // Waiting for read
+#define MPU9150_STATE_WRITE 3 // Waiting for write
+#define MPU9150_STATE_RMW 4 // Waiting for read modify write
+#define MPU9150_STATE_INIT_RESET \
+ 5 // reset request issued.
+#define MPU9150_STATE_INIT_RESET_WAIT \
+ 6 // polling wait for reset complete
+#define MPU9150_STATE_INIT_PWR_MGMT \
+ 7 // wake up the device.
+#define MPU9150_STATE_INIT_USER_CTRL \
+ 8 // init user control
+#define MPU9150_STATE_INIT_SAMPLE_RATE_CFG \
+ 9 // init the sensors and filters
+#define MPU9150_STATE_INIT_I2C_SLAVE_DLY \
+ 10 // set the ak8975 polling delay
+#define MPU9150_STATE_INIT_I2C_SLAVE_0 \
+ 11 // config ak8975 automatic read
+#define MPU9150_STATE_RD_DATA 12 // Waiting for data read
+
+//*****************************************************************************
+//
+// The factors used to convert the acceleration readings from the MPU9150 into
+// floating point values in meters per second squared.
+//
+// Values are obtained by taking the g conversion factors from the data sheet
+// and multiplying by 9.81 (1 g = 9.81 m/s^2).
+//
+//*****************************************************************************
+static const float g_fMPU9150AccelFactors[] =
+{
+ 0.0005985482, // Range = +/- 2 g (16384 lsb/g)
+ 0.0011970964, // Range = +/- 4 g (8192 lsb/g)
+ 0.0023941928, // Range = +/- 8 g (4096 lsb/g)
+ 0.0047883855 // Range = +/- 16 g (2048 lsb/g)
+};
+
+//*****************************************************************************
+//
+// The factors used to convert the acceleration readings from the MPU9150 into
+// floating point values in radians per second.
+//
+// Values are obtained by taking the degree per second conversion factors
+// from the data sheet and then converting to radians per sec (1 degree =
+// 0.0174532925 radians).
+//
+//*****************************************************************************
+static const float g_fMPU9150GyroFactors[] =
+{
+ 1.3323124e-4, // Range = +/- 250 dps (131.0)
+ 2.6646248e-4, // Range = +/- 500 dps (65.5)
+ 5.3211258e-4, // Range = +/- 1000 dps (32.8)
+ 0.0010642252 // Range = +/- 2000 dps (16.4)
+};
+
+//*****************************************************************************
+//
+// Converting sensor data to tesla (0.3 uT per LSB)
+//
+//*****************************************************************************
+#define CONVERT_TO_TESLA 0.0000003
+
+//*****************************************************************************
+//
+// The callback function that is called when I2C transations to/from the
+// MPU9150 have completed.
+//
+//*****************************************************************************
+static void
+MPU9150Callback(void *pvCallbackData, uint_fast8_t ui8Status)
+{
+ tMPU9150 *psInst;
+
+ //
+ // Convert the instance data into a pointer to a tMPU9150 structure.
+ //
+ psInst = pvCallbackData;
+
+ //
+ // If the I2C master driver encountered a failure, force the state machine
+ // to the idle state (which will also result in a callback to propagate the
+ // error). Except in the case that we are in the reset wait state and the
+ // error is an address NACK. This error is handled by the reset wait
+ // state.
+ //
+ if((ui8Status != I2CM_STATUS_SUCCESS) &&
+ !((ui8Status == I2CM_STATUS_ADDR_NACK) &&
+ (psInst->ui8State == MPU9150_STATE_INIT_RESET_WAIT)))
+ {
+ psInst->ui8State = MPU9150_STATE_IDLE;
+ }
+
+ //
+ // Determine the current state of the MPU9150 state machine.
+ //
+ switch(psInst->ui8State)
+ {
+ //
+ // All states that trivially transition to IDLE, and all unknown
+ // states.
+ //
+ case MPU9150_STATE_READ:
+ case MPU9150_STATE_LAST:
+ case MPU9150_STATE_RD_DATA:
+ default:
+ {
+ //
+ // The state machine is now idle.
+ //
+ psInst->ui8State = MPU9150_STATE_IDLE;
+
+ //
+ // Done.
+ //
+ break;
+ }
+
+ //
+ // MPU9150 Device reset was issued
+ //
+ case MPU9150_STATE_INIT_RESET:
+ {
+ //
+ // Issue a read of the status register to confirm reset is done.
+ //
+ psInst->uCommand.pui8Buffer[0] = MPU9150_O_PWR_MGMT_1;
+ I2CMRead(psInst->psI2CInst, psInst->ui8Addr,
+ psInst->uCommand.pui8Buffer, 1, psInst->pui8Data, 1,
+ MPU9150Callback, psInst);
+
+ psInst->ui8State = MPU9150_STATE_INIT_RESET_WAIT;
+ break;
+ }
+
+ //
+ // Status register was read, check if reset is done before proceeding.
+ //
+ case MPU9150_STATE_INIT_RESET_WAIT:
+ {
+ //
+ // Check the value read back from status to determine if device
+ // is still in reset or if it is ready. Reset state for this
+ // register is 0x40, which has sleep bit set. Device may also
+ // respond with an address NACK during very early stages of the
+ // its internal reset. Keep polling until we verify device is
+ // ready.
+ //
+ if((psInst->pui8Data[0] != MPU9150_PWR_MGMT_1_SLEEP) ||
+ (ui8Status == I2CM_STATUS_ADDR_NACK))
+ {
+ //
+ // Device still in reset so begin polling this register.
+ //
+ psInst->uCommand.pui8Buffer[0] = MPU9150_O_PWR_MGMT_1;
+ I2CMRead(psInst->psI2CInst, psInst->ui8Addr,
+ psInst->uCommand.pui8Buffer, 1, psInst->pui8Data, 1,
+ MPU9150Callback, psInst);
+
+ //
+ // Intentionally stay in this state to create polling effect.
+ //
+ }
+ else
+ {
+ //
+ // Device is out of reset, bring it out of sleep mode.
+ //
+ psInst->uCommand.pui8Buffer[0] = MPU9150_O_PWR_MGMT_1;
+ psInst->uCommand.pui8Buffer[1] = MPU9150_PWR_MGMT_1_CLKSEL_XG;
+ I2CMWrite(psInst->psI2CInst, psInst->ui8Addr,
+ psInst->uCommand.pui8Buffer, 2, MPU9150Callback,
+ psInst);
+
+ //
+ // Update state to show we are modifing user control and
+ // power management 1 regs.
+ //
+ psInst->ui8State = MPU9150_STATE_INIT_PWR_MGMT;
+ }
+ break;
+ }
+
+ //
+ // Reset complete now take device out of sleep mode.
+ //
+ case MPU9150_STATE_INIT_PWR_MGMT:
+ {
+ psInst->uCommand.pui8Buffer[0] = MPU9150_O_USER_CTRL;
+ psInst->uCommand.pui8Buffer[1] = MPU9150_USER_CTRL_I2C_MST_EN;
+ I2CMWrite(psInst->psI2CInst, psInst->ui8Addr,
+ psInst->uCommand.pui8Buffer, 2, MPU9150Callback,
+ psInst);
+
+ //
+ // Update state to show we are modifing user control and
+ // power management 1 regs.
+ //
+ psInst->ui8State = MPU9150_STATE_INIT_USER_CTRL;
+
+ break;
+ }
+
+ //
+ // Change to power mode complete, device is ready for configuration.
+ //
+ case MPU9150_STATE_INIT_USER_CTRL:
+ {
+ //
+ // Load index 0 with the sample rate register number.
+ //
+ psInst->uCommand.pui8Buffer[0] = MPU9150_O_SMPLRT_DIV;
+
+ //
+ // Set sample rate to 50 hertz. 1000 hz / (1 + 19)
+ //
+ psInst->uCommand.pui8Buffer[1] = 19;
+
+ I2CMWrite(psInst->psI2CInst, psInst->ui8Addr,
+ psInst->uCommand.pui8Buffer, 2, MPU9150Callback, psInst);
+
+ //
+ // update state to show are in process of configuring sensors.
+ //
+ psInst->ui8State = MPU9150_STATE_INIT_SAMPLE_RATE_CFG;
+ break;
+ }
+
+ //
+ // Sensor configuration is complete.
+ //
+ case MPU9150_STATE_INIT_SAMPLE_RATE_CFG:
+ {
+ //
+ // Write the I2C Master delay control so we only sample the AK
+ // every 5th time that we sample accel/gyro. Delay Count itself
+ // handled in next state.
+ //
+ psInst->uCommand.pui8Buffer[0] = MPU9150_O_I2C_MST_DELAY_CTRL;
+ psInst->uCommand.pui8Buffer[1] =
+ (MPU9150_I2C_MST_DELAY_CTRL_I2C_SLV0_DLY_EN |
+ MPU9150_I2C_MST_DELAY_CTRL_I2C_SLV4_DLY_EN);
+ I2CMWrite(psInst->psI2CInst, psInst->ui8Addr,
+ psInst->uCommand.pui8Buffer, 2, MPU9150Callback, psInst);
+
+ //
+ // Update state to show we are configuring i2c slave delay between
+ // slave events. Slave 0 and Slave 4 transaction only occur every
+ // 5th sample cycle.
+ //
+ psInst->ui8State = MPU9150_STATE_INIT_I2C_SLAVE_DLY;
+ break;
+ }
+
+ //
+ // Master slave delay configuration complete.
+ //
+ case MPU9150_STATE_INIT_I2C_SLAVE_DLY:
+ {
+ //
+ // Write the configuration for I2C master control clock 400khz
+ // and wait for external sensor before asserting data ready
+ //
+ psInst->uCommand.pui8Buffer[0] = MPU9150_O_I2C_MST_CTRL;
+ psInst->uCommand.pui8Buffer[1] =
+ (MPU9150_I2C_MST_CTRL_I2C_MST_CLK_400 |
+ MPU9150_I2C_MST_CTRL_WAIT_FOR_ES);
+
+ //
+ // Configure I2C Slave 0 for read of AK8975 (I2C Address 0x0C)
+ // Start at AK8975 register status 1
+ // Read 8 bytes and enable this slave transaction
+ //
+ psInst->uCommand.pui8Buffer[2] = MPU9150_I2C_SLV0_ADDR_RW | 0x0C;
+ psInst->uCommand.pui8Buffer[3] = AK8975_O_ST1;
+ psInst->uCommand.pui8Buffer[4] = MPU9150_I2C_SLV0_CTRL_EN | 0x08;
+ I2CMWrite(psInst->psI2CInst, psInst->ui8Addr,
+ psInst->uCommand.pui8Buffer, 5, MPU9150Callback, psInst);
+
+ //
+ // Update state. Now in process of configuring slave 0.
+ //
+ psInst->ui8State = MPU9150_STATE_INIT_I2C_SLAVE_0;
+ break;
+ }
+
+ //
+ // I2C slave 0 init complete.
+ //
+ case MPU9150_STATE_INIT_I2C_SLAVE_0:
+ {
+ //
+ // Write the configuration for I2C Slave 4 transaction to AK8975
+ // 0x0c is the AK8975 address on i2c bus.
+ // we want to write the control register with the value for a
+ // starting a single measurement.
+ //
+ psInst->uCommand.pui8Buffer[0] = MPU9150_O_I2C_SLV4_ADDR;
+ psInst->uCommand.pui8Buffer[1] = 0x0C;
+ psInst->uCommand.pui8Buffer[2] = AK8975_O_CNTL;
+ psInst->uCommand.pui8Buffer[3] = AK8975_CNTL_MODE_SINGLE;
+
+ //
+ // Enable the SLV4 transaction and set the master delay to
+ // 0x04 + 1. This means the slave transactions with delay enabled
+ // will run every fifth accel/gyro sample.
+ //
+ psInst->uCommand.pui8Buffer[4] = MPU9150_I2C_SLV4_CTRL_EN | 0x04;
+ I2CMWrite(psInst->psI2CInst, psInst->ui8Addr,
+ psInst->uCommand.pui8Buffer, 5, MPU9150Callback, psInst);
+
+ //
+ // Update state. Now in the final init state.
+ //
+ psInst->ui8State = MPU9150_STATE_LAST;
+ break;
+ }
+
+ //
+ // A write just completed
+ //
+ case MPU9150_STATE_WRITE:
+ {
+ //
+ // Set the accelerometer and gyroscope ranges to the new values.
+ // If the register was not modified, the values will be the same so
+ // this has no effect.
+ //
+ psInst->ui8AccelAfsSel = psInst->ui8NewAccelAfsSel;
+ psInst->ui8GyroFsSel = psInst->ui8NewGyroFsSel;
+
+ //
+ // The state machine is now idle.
+ //
+ psInst->ui8State = MPU9150_STATE_IDLE;
+
+ //
+ // Done.
+ //
+ break;
+ }
+
+ //
+ // A read-modify-write just completed
+ //
+ case MPU9150_STATE_RMW:
+ {
+ //
+ // See if the PWR_MGMT_1 register was just modified.
+ //
+ if(psInst->uCommand.sReadModifyWriteState.pui8Buffer[0] ==
+ MPU9150_O_PWR_MGMT_1)
+ {
+ //
+ // See if a soft reset has been issued.
+ //
+ if(psInst->uCommand.sReadModifyWriteState.pui8Buffer[1] &
+ MPU9150_PWR_MGMT_1_DEVICE_RESET)
+ {
+ //
+ // Default range setting is +/- 2 g
+ //
+ psInst->ui8AccelAfsSel = 0;
+ psInst->ui8NewAccelAfsSel = 0;
+
+ //
+ // Default range setting is +/- 250 degrees/s
+ //
+ psInst->ui8GyroFsSel = 0;
+ psInst->ui8NewGyroFsSel = 0;
+ }
+ }
+
+ //
+ // See if the GYRO_CONFIG register was just modified.
+ //
+ if(psInst->uCommand.sReadModifyWriteState.pui8Buffer[0] ==
+ MPU9150_O_GYRO_CONFIG)
+ {
+ //
+ // Extract the FS_SEL from the GYRO_CONFIG register value.
+ //
+ psInst->ui8GyroFsSel =
+ ((psInst->uCommand.sReadModifyWriteState.pui8Buffer[1] &
+ MPU9150_GYRO_CONFIG_FS_SEL_M) >>
+ MPU9150_GYRO_CONFIG_FS_SEL_S);
+ }
+
+ //
+ // See if the ACCEL_CONFIG register was just modified.
+ //
+ if(psInst->uCommand.sReadModifyWriteState.pui8Buffer[0] ==
+ MPU9150_O_ACCEL_CONFIG)
+ {
+ //
+ // Extract the FS_SEL from the ACCEL_CONFIG register value.
+ //
+ psInst->ui8AccelAfsSel =
+ ((psInst->uCommand.sReadModifyWriteState.pui8Buffer[1] &
+ MPU9150_ACCEL_CONFIG_AFS_SEL_M) >>
+ MPU9150_ACCEL_CONFIG_AFS_SEL_S);
+ }
+
+ //
+ // The state machine is now idle.
+ //
+ psInst->ui8State = MPU9150_STATE_IDLE;
+
+ //
+ // Done.
+ //
+ break;
+ }
+ }
+
+ //
+ // See if the state machine is now idle and there is a callback function.
+ //
+ if((psInst->ui8State == MPU9150_STATE_IDLE) && psInst->pfnCallback)
+ {
+ //
+ // Call the application-supplied callback function.
+ //
+ psInst->pfnCallback(psInst->pvCallbackData, ui8Status);
+ }
+}
+
+//*****************************************************************************
+//
+//! Initializes the MPU9150 driver.
+//!
+//! \param psInst is a pointer to the MPU9150 instance data.
+//! \param psI2CInst is a pointer to the I2C master driver instance data.
+//! \param ui8I2CAddr is the I2C address of the MPU9150 device.
+//! \param pfnCallback is the function to be called when the initialization has
+//! completed (can be \b NULL if a callback is not required).
+//! \param pvCallbackData is a pointer that is passed to the callback function.
+//!
+//! This function initializes the MPU9150 driver, preparing it for operation.
+//!
+//! \return Returns 1 if the MPU9150 driver was successfully initialized and 0
+//! if it was not.
+//
+//*****************************************************************************
+uint_fast8_t
+MPU9150Init(tMPU9150 *psInst, tI2CMInstance *psI2CInst,
+ uint_fast8_t ui8I2CAddr, tSensorCallback *pfnCallback,
+ void *pvCallbackData)
+{
+ //
+ // Initialize the MPU9150 instance structure.
+ //
+ psInst->psI2CInst = psI2CInst;
+ psInst->ui8Addr = ui8I2CAddr;
+
+ //
+ // Save the callback information.
+ //
+ psInst->pfnCallback = pfnCallback;
+ psInst->pvCallbackData = pvCallbackData;
+
+ //
+ // Default range setting is +/- 2 g
+ //
+ psInst->ui8AccelAfsSel = (MPU9150_ACCEL_CONFIG_AFS_SEL_2G >>
+ MPU9150_ACCEL_CONFIG_AFS_SEL_S);
+ psInst->ui8NewAccelAfsSel = (MPU9150_ACCEL_CONFIG_AFS_SEL_2G >>
+ MPU9150_ACCEL_CONFIG_AFS_SEL_S);
+
+ //
+ // Default range setting is +/- 250 degrees/s
+ //
+ psInst->ui8GyroFsSel = (MPU9150_GYRO_CONFIG_FS_SEL_250 >>
+ MPU9150_GYRO_CONFIG_FS_SEL_S);
+ psInst->ui8NewGyroFsSel = (MPU9150_GYRO_CONFIG_FS_SEL_250 >>
+ MPU9150_GYRO_CONFIG_FS_SEL_S);
+
+ //
+ // Set the state to show we are initiating a reset.
+ //
+ psInst->ui8State = MPU9150_STATE_INIT_RESET;
+
+ //
+ // Load the buffer with command to perform device reset
+ //
+ psInst->uCommand.pui8Buffer[0] = MPU9150_O_PWR_MGMT_1;
+ psInst->uCommand.pui8Buffer[1] = MPU9150_PWR_MGMT_1_DEVICE_RESET;
+ if(I2CMWrite(psInst->psI2CInst, psInst->ui8Addr,
+ psInst->uCommand.pui8Buffer, 2, MPU9150Callback, psInst) == 0)
+ {
+ psInst->ui8State = MPU9150_STATE_IDLE;
+ return(0);
+ }
+
+ //
+ // Success
+ //
+ return(1);
+}
+
+//*****************************************************************************
+//
+//! Returns the pointer to the tAK8975 object
+//!
+//! \param psInst is a pointer to the MPU9150 instance data.
+//!
+//! The MPU9150 contains in internal AK8975 magnetometer. To access data from
+//! that sensor, application should use this function to get a pointer to the
+//! tAK8975 object, and then use the AK8975 APIs.
+//!
+//! \return Returns the pointer to the tAK8975 object
+//
+//*****************************************************************************
+tAK8975 *
+MPU9150MagnetoInstGet(tMPU9150 *psInst)
+{
+ return(&(psInst->sAK8975Inst));
+}
+
+//*****************************************************************************
+//
+//! Reads data from MPU9150 registers.
+//!
+//! \param psInst is a pointer to the MPU9150 instance data.
+//! \param ui8Reg is the first register to read.
+//! \param pui8Data is a pointer to the location to store the data that is
+//! read.
+//! \param ui16Count is the number of data bytes to read.
+//! \param pfnCallback is the function to be called when the data has been read
+//! (can be \b NULL if a callback is not required).
+//! \param pvCallbackData is a pointer that is passed to the callback function.
+//!
+//! This function reads a sequence of data values from consecutive registers in
+//! the MPU9150.
+//!
+//! \return Returns 1 if the write was successfully started and 0 if it was
+//! not.
+//
+//*****************************************************************************
+uint_fast8_t
+MPU9150Read(tMPU9150 *psInst, uint_fast8_t ui8Reg, uint8_t *pui8Data,
+ uint_fast16_t ui16Count, tSensorCallback *pfnCallback,
+ void *pvCallbackData)
+{
+ //
+ // Return a failure if the MPU9150 driver is not idle (in other words,
+ // there is already an outstanding request to the MPU9150).
+ //
+ if(psInst->ui8State != MPU9150_STATE_IDLE)
+ {
+ return(0);
+ }
+
+ //
+ // Save the callback information.
+ //
+ psInst->pfnCallback = pfnCallback;
+ psInst->pvCallbackData = pvCallbackData;
+
+ //
+ // Move the state machine to the wait for read state.
+ //
+ psInst->ui8State = MPU9150_STATE_READ;
+
+ //
+ // Read the requested registers from the MPU9150.
+ //
+ psInst->uCommand.pui8Buffer[0] = ui8Reg;
+ if(I2CMRead(psInst->psI2CInst, psInst->ui8Addr,
+ psInst->uCommand.pui8Buffer, 1, pui8Data, ui16Count,
+ MPU9150Callback, psInst) == 0)
+ {
+ //
+ // The I2C write failed, so move to the idle state and return a
+ // failure.
+ //
+ psInst->ui8State = MPU9150_STATE_IDLE;
+ return(0);
+ }
+
+ //
+ // Success.
+ //
+ return(1);
+}
+
+//*****************************************************************************
+//
+//! Writes data to MPU9150 registers.
+//!
+//! \param psInst is a pointer to the MPU9150 instance data.
+//! \param ui8Reg is the first register to write.
+//! \param pui8Data is a pointer to the data to write.
+//! \param ui16Count is the number of data bytes to write.
+//! \param pfnCallback is the function to be called when the data has been
+//! written (can be \b NULL if a callback is not required).
+//! \param pvCallbackData is a pointer that is passed to the callback function.
+//!
+//! This function writes a sequence of data values to consecutive registers in
+//! the MPU9150. The first byte of the \e pui8Data buffer contains the value
+//! to be written into the \e ui8Reg register, the second value contains the
+//! data to be written into the next register, and so on.
+//!
+//! \return Returns 1 if the write was successfully started and 0 if it was
+//! not.
+//
+//*****************************************************************************
+uint_fast8_t
+MPU9150Write(tMPU9150 *psInst, uint_fast8_t ui8Reg, const uint8_t *pui8Data,
+ uint_fast16_t ui16Count, tSensorCallback *pfnCallback,
+ void *pvCallbackData)
+{
+ //
+ // Return a failure if the MPU9150 driver is not idle (in other words,
+ // there is already an outstanding request to the MPU9150).
+ //
+ if(psInst->ui8State != MPU9150_STATE_IDLE)
+ {
+ return(0);
+ }
+
+ //
+ // Save the callback information.
+ //
+ psInst->pfnCallback = pfnCallback;
+ psInst->pvCallbackData = pvCallbackData;
+
+ //
+ // See if the PWR_MGMT_1 register is being written.
+ //
+ if((ui8Reg <= MPU9150_O_PWR_MGMT_1) &&
+ ((ui8Reg + ui16Count) > MPU9150_O_PWR_MGMT_1))
+ {
+ //
+ // See if a soft reset is being requested.
+ //
+ if(pui8Data[ui8Reg - MPU9150_O_PWR_MGMT_1] &
+ MPU9150_PWR_MGMT_1_DEVICE_RESET)
+ {
+ //
+ // Default range setting is +/- 2 g.
+ //
+ psInst->ui8NewAccelAfsSel = 0;
+
+ //
+ // Default range setting is +/- 250 degrees/s.
+ //
+ psInst->ui8NewGyroFsSel = 0;
+ }
+ }
+
+ //
+ // See if the GYRO_CONFIG register is being written.
+ //
+ if((ui8Reg <= MPU9150_O_GYRO_CONFIG) &&
+ ((ui8Reg + ui16Count) > MPU9150_O_GYRO_CONFIG))
+ {
+ //
+ // Extract the FS_SEL from the GYRO_CONFIG register value.
+ //
+ psInst->ui8NewGyroFsSel = ((pui8Data[ui8Reg - MPU9150_O_GYRO_CONFIG] &
+ MPU9150_GYRO_CONFIG_FS_SEL_M) >>
+ MPU9150_GYRO_CONFIG_FS_SEL_S);
+ }
+
+ //
+ // See if the ACCEL_CONFIG register is being written.
+ //
+ if((ui8Reg <= MPU9150_O_ACCEL_CONFIG) &&
+ ((ui8Reg + ui16Count) > MPU9150_O_ACCEL_CONFIG))
+ {
+ //
+ // Extract the AFS_SEL from the ACCEL_CONFIG register value.
+ //
+ psInst->ui8NewAccelAfsSel =
+ ((pui8Data[ui8Reg - MPU9150_O_ACCEL_CONFIG] &
+ MPU9150_ACCEL_CONFIG_AFS_SEL_M) >>
+ MPU9150_ACCEL_CONFIG_AFS_SEL_S);
+ }
+
+ //
+ // Move the state machine to the wait for write state.
+ //
+ psInst->ui8State = MPU9150_STATE_WRITE;
+
+ //
+ // Write the requested registers to the MPU9150.
+ //
+ if(I2CMWrite8(&(psInst->uCommand.sWriteState), psInst->psI2CInst,
+ psInst->ui8Addr, ui8Reg, pui8Data, ui16Count,
+ MPU9150Callback, psInst) == 0)
+ {
+ //
+ // The I2C write failed, so move to the idle state and return a
+ // failure.
+ //
+ psInst->ui8State = MPU9150_STATE_IDLE;
+ return(0);
+ }
+
+ //
+ // Success.
+ //
+ return(1);
+}
+
+//*****************************************************************************
+//
+//! Performs a read-modify-write of a MPU9150 register.
+//!
+//! \param psInst is a pointer to the MPU9150 instance data.
+//! \param ui8Reg is the register to modify.
+//! \param ui8Mask is the bit mask that is ANDed with the current register
+//! value.
+//! \param ui8Value is the bit mask that is ORed with the result of the AND
+//! operation.
+//! \param pfnCallback is the function to be called when the data has been
+//! changed (can be \b NULL if a callback is not required).
+//! \param pvCallbackData is a pointer that is passed to the callback function.
+//!
+//! This function changes the value of a register in the MPU9150 via a
+//! read-modify-write operation, allowing one of the fields to be changed
+//! without disturbing the other fields. The \e ui8Reg register is read, ANDed
+//! with \e ui8Mask, ORed with \e ui8Value, and then written back to the
+//! MPU9150.
+//!
+//! \return Returns 1 if the read-modify-write was successfully started and 0
+//! if it was not.
+//
+//*****************************************************************************
+uint_fast8_t
+MPU9150ReadModifyWrite(tMPU9150 *psInst, uint_fast8_t ui8Reg,
+ uint_fast8_t ui8Mask, uint_fast8_t ui8Value,
+ tSensorCallback *pfnCallback, void *pvCallbackData)
+{
+ //
+ // Return a failure if the MPU9150 driver is not idle (in other words,
+ // there is already an outstanding request to the MPU9150).
+ //
+ if(psInst->ui8State != MPU9150_STATE_IDLE)
+ {
+ return(0);
+ }
+
+ //
+ // Save the callback information.
+ //
+ psInst->pfnCallback = pfnCallback;
+ psInst->pvCallbackData = pvCallbackData;
+
+ //
+ // Move the state machine to the wait for read-modify-write state.
+ //
+ psInst->ui8State = MPU9150_STATE_RMW;
+
+ //
+ // Submit the read-modify-write request to the MPU9150.
+ //
+ if(I2CMReadModifyWrite8(&(psInst->uCommand.sReadModifyWriteState),
+ psInst->psI2CInst, psInst->ui8Addr, ui8Reg,
+ ui8Mask, ui8Value, MPU9150Callback, psInst) == 0)
+ {
+ //
+ // The I2C read-modify-write failed, so move to the idle state and
+ // return a failure.
+ //
+ psInst->ui8State = MPU9150_STATE_IDLE;
+ return(0);
+ }
+
+ //
+ // Success.
+ //
+ return(1);
+}
+
+//*****************************************************************************
+//
+//! Reads the accelerometer and gyroscope data from the MPU9150 and the
+//! magnetometer data from the on-chip aK8975.
+//!
+//! \param psInst is a pointer to the MPU9150 instance data.
+//! \param pfnCallback is the function to be called when the data has been read
+//! (can be \b NULL if a callback is not required).
+//! \param pvCallbackData is a pointer that is passed to the callback function.
+//!
+//! This function initiates a read of the MPU9150 data registers. When the
+//! read has completed (as indicated by calling the callback function), the new
+//! readings can be obtained via:
+//!
+//! - MPU9150DataAccelGetRaw()
+//! - MPU9150DataAccelGetFloat()
+//! - MPU9150DataGyroGetRaw()
+//! - MPU9150DataGyroGetFloat()
+//! - MPU9150DataMagnetoGetRaw()
+//! - MPU9150DataMagnetoGetFloat()
+//!
+//! \return Returns 1 if the read was successfully started and 0 if it was not.
+//
+//*****************************************************************************
+uint_fast8_t
+MPU9150DataRead(tMPU9150 *psInst, tSensorCallback *pfnCallback,
+ void *pvCallbackData)
+{
+ //
+ // Return a failure if the MPU9150 driver is not idle (in other words,
+ // there is already an outstanding request to the MPU9150).
+ //
+ if(psInst->ui8State != MPU9150_STATE_IDLE)
+ {
+ return(0);
+ }
+
+ //
+ // Save the callback information.
+ //
+ psInst->pfnCallback = pfnCallback;
+ psInst->pvCallbackData = pvCallbackData;
+
+ //
+ // Move the state machine to the wait for data read state.
+ //
+ psInst->ui8State = MPU9150_STATE_RD_DATA;
+
+ //
+ // Read the data registers from the MPU9150.
+ //
+ // (ACCEL_XOUT_H(0x3B) -> GYRO_ZOUT_L(0x48) = 14 bytes
+ // Grab Ext Sens Data as well for another 8 bytes. ST1 + Mag Data + ST2
+ //
+ psInst->uCommand.pui8Buffer[0] = MPU9150_O_ACCEL_XOUT_H;
+ if(I2CMRead(psInst->psI2CInst, psInst->ui8Addr,
+ psInst->uCommand.pui8Buffer, 1, psInst->pui8Data, 22,
+ MPU9150Callback, psInst) == 0)
+ {
+ //
+ // The I2C read failed, so move to the idle state and return a failure.
+ //
+ psInst->ui8State = MPU9150_STATE_IDLE;
+ return(0);
+ }
+
+ //
+ // Success.
+ //
+ return(1);
+}
+
+//*****************************************************************************
+//
+//! Gets the raw accelerometer data from the most recent data read.
+//!
+//! \param psInst is a pointer to the MPU9150 instance data.
+//! \param pui16AccelX is a pointer to the value into which the raw X-axis
+//! accelerometer data is stored.
+//! \param pui16AccelY is a pointer to the value into which the raw Y-axis
+//! accelerometer data is stored.
+//! \param pui16AccelZ is a pointer to the value into which the raw Z-axis
+//! accelerometer data is stored.
+//!
+//! This function returns the raw accelerometer data from the most recent data
+//! read. The data is not manipulated in any way by the driver. If any of the
+//! output data pointers are \b NULL, the corresponding data is not provided.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+MPU9150DataAccelGetRaw(tMPU9150 *psInst, uint_fast16_t *pui16AccelX,
+ uint_fast16_t *pui16AccelY, uint_fast16_t *pui16AccelZ)
+{
+ //
+ // Return the raw accelerometer values.
+ //
+ if(pui16AccelX)
+ {
+ *pui16AccelX = (psInst->pui8Data[0] << 8) | psInst->pui8Data[1];
+ }
+ if(pui16AccelY)
+ {
+ *pui16AccelY = (psInst->pui8Data[2] << 8) | psInst->pui8Data[3];
+ }
+ if(pui16AccelZ)
+ {
+ *pui16AccelZ = (psInst->pui8Data[4] << 8) | psInst->pui8Data[5];
+ }
+}
+
+//*****************************************************************************
+//
+//! Gets the accelerometer data from the most recent data read.
+//!
+//! \param psInst is a pointer to the MPU9150 instance data.
+//! \param pfAccelX is a pointer to the value into which the X-axis
+//! accelerometer data is stored.
+//! \param pfAccelY is a pointer to the value into which the Y-axis
+//! accelerometer data is stored.
+//! \param pfAccelZ is a pointer to the value into which the Z-axis
+//! accelerometer data is stored.
+//!
+//! This function returns the accelerometer data from the most recent data
+//! read, converted into meters per second squared (m/s^2). If any of the
+//! output data pointers are \b NULL, the corresponding data is not provided.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+MPU9150DataAccelGetFloat(tMPU9150 *psInst, float *pfAccelX, float *pfAccelY,
+ float *pfAccelZ)
+{
+ float fFactor;
+
+ //
+ // Get the acceleration conversion factor for the current data format.
+ //
+ fFactor = g_fMPU9150AccelFactors[psInst->ui8AccelAfsSel];
+
+ //
+ // Convert the accelerometer values into m/sec^2
+ //
+ if(pfAccelX)
+ {
+ *pfAccelX = ((float)(int16_t)((psInst->pui8Data[0] << 8) |
+ psInst->pui8Data[1]) * fFactor);
+ }
+ if(pfAccelY)
+ {
+ *pfAccelY = ((float)(int16_t)((psInst->pui8Data[2] << 8) |
+ psInst->pui8Data[3]) * fFactor);
+ }
+ if(pfAccelZ)
+ {
+ *pfAccelZ = ((float)(int16_t)((psInst->pui8Data[4] << 8) |
+ psInst->pui8Data[5]) * fFactor);
+ }
+}
+
+//*****************************************************************************
+//
+//! Gets the raw gyroscope data from the most recent data read.
+//!
+//! \param psInst is a pointer to the MPU9150 instance data.
+//! \param pui16GyroX is a pointer to the value into which the raw X-axis
+//! gyroscope data is stored.
+//! \param pui16GyroY is a pointer to the value into which the raw Y-axis
+//! gyroscope data is stored.
+//! \param pui16GyroZ is a pointer to the value into which the raw Z-axis
+//! gyroscope data is stored.
+//!
+//! This function returns the raw gyroscope data from the most recent data
+//! read. The data is not manipulated in any way by the driver. If any of the
+//! output data pointers are \b NULL, the corresponding data is not provided.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+MPU9150DataGyroGetRaw(tMPU9150 *psInst, uint_fast16_t *pui16GyroX,
+ uint_fast16_t *pui16GyroY, uint_fast16_t *pui16GyroZ)
+{
+ //
+ // Return the raw gyroscope values.
+ //
+ if(pui16GyroX)
+ {
+ *pui16GyroX = (psInst->pui8Data[8] << 8) | psInst->pui8Data[9];
+ }
+ if(pui16GyroY)
+ {
+ *pui16GyroY = (psInst->pui8Data[10] << 8) | psInst->pui8Data[11];
+ }
+ if(pui16GyroZ)
+ {
+ *pui16GyroZ = (psInst->pui8Data[12] << 8) | psInst->pui8Data[13];
+ }
+}
+
+//*****************************************************************************
+//
+//! Gets the gyroscope data from the most recent data read.
+//!
+//! \param psInst is a pointer to the MPU9150 instance data.
+//! \param pfGyroX is a pointer to the value into which the X-axis
+//! gyroscope data is stored.
+//! \param pfGyroY is a pointer to the value into which the Y-axis
+//! gyroscope data is stored.
+//! \param pfGyroZ is a pointer to the value into which the Z-axis
+//! gyroscope data is stored.
+//!
+//! This function returns the gyroscope data from the most recent data read,
+//! converted into radians per second. If any of the output data pointers are
+//! \b NULL, the corresponding data is not provided.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+MPU9150DataGyroGetFloat(tMPU9150 *psInst, float *pfGyroX, float *pfGyroY,
+ float *pfGyroZ)
+{
+ float fFactor;
+ int16_t i16Temp;
+
+ //
+ // Get the gyroscope conversion factor for the current data format.
+ //
+ fFactor = g_fMPU9150GyroFactors[psInst->ui8GyroFsSel];
+
+ //
+ // Convert the gyroscope values into rad/sec
+ //
+ if(pfGyroX)
+ {
+ i16Temp = (int16_t)psInst->pui8Data[8];
+ i16Temp <<= 8;
+ i16Temp += psInst->pui8Data[9];
+ *pfGyroX = (float)i16Temp;
+ *pfGyroX *= fFactor;
+ }
+ if(pfGyroY)
+ {
+ i16Temp = (int16_t)psInst->pui8Data[10];
+ i16Temp <<= 8;
+ i16Temp += psInst->pui8Data[11];
+ *pfGyroY = (float)i16Temp;
+ *pfGyroY *= fFactor;
+ }
+ if(pfGyroZ)
+ {
+ i16Temp = (int16_t)psInst->pui8Data[12];
+ i16Temp <<= 8;
+ i16Temp += psInst->pui8Data[13];
+ *pfGyroZ = (float)i16Temp;
+ *pfGyroZ *= fFactor;
+ }
+}
+
+//*****************************************************************************
+//
+//! Gets the raw magnetometer data from the most recent data read.
+//!
+//! \param psInst is a pointer to the MPU9150 instance data.
+//! \param pui16MagnetoX is a pointer to the value into which the raw X-axis
+//! magnetometer data is stored.
+//! \param pui16MagnetoY is a pointer to the value into which the raw Y-axis
+//! magnetometer data is stored.
+//! \param pui16MagnetoZ is a pointer to the value into which the raw Z-axis
+//! magnetometer data is stored.
+//!
+//! This function returns the raw magnetometer data from the most recent data
+//! read. The data is not manipulated in any way by the driver. If any of the
+//! output data pointers are \b NULL, the corresponding data is not provided.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+MPU9150DataMagnetoGetRaw(tMPU9150 *psInst, uint_fast16_t *pui16MagnetoX,
+ uint_fast16_t *pui16MagnetoY,
+ uint_fast16_t *pui16MagnetoZ)
+{
+ uint8_t *pui8ExtSensData;
+
+ pui8ExtSensData = &(psInst->pui8Data[14]);
+
+ //
+ // Return the raw magnetometer values.
+ //
+ if(pui16MagnetoX)
+ {
+ *pui16MagnetoX = (pui8ExtSensData[2] << 8) | pui8ExtSensData[1];
+ }
+ if(pui16MagnetoY)
+ {
+ *pui16MagnetoY = (pui8ExtSensData[4] << 8) | pui8ExtSensData[3];
+ }
+ if(pui16MagnetoZ)
+ {
+ *pui16MagnetoZ = (pui8ExtSensData[6] << 8) | pui8ExtSensData[5];
+ }
+}
+
+//*****************************************************************************
+//
+//! Gets the magnetometer data from the most recent data read.
+//!
+//! \param psInst is a pointer to the MPU9150 instance data.
+//! \param pfMagnetoX is a pointer to the value into which the X-axis
+//! magnetometer data is stored.
+//! \param pfMagnetoY is a pointer to the value into which the Y-axis
+//! magnetometer data is stored.
+//! \param pfMagnetoZ is a pointer to the value into which the Z-axis
+//! magnetometer data is stored.
+//!
+//! This function returns the magnetometer data from the most recent data read,
+//! converted into tesla. If any of the output data pointers are
+//! \b NULL, the corresponding data is not provided.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+MPU9150DataMagnetoGetFloat(tMPU9150 *psInst, float *pfMagnetoX,
+ float *pfMagnetoY, float *pfMagnetoZ)
+{
+ int16_t *pi16Data;
+
+ pi16Data = (int16_t *)(psInst->pui8Data + 15);
+
+ //
+ // Convert the magnetometer values into floating-point tesla values.
+ //
+ if(pfMagnetoX)
+ {
+ *pfMagnetoX = (float)pi16Data[0];
+ *pfMagnetoX *= CONVERT_TO_TESLA;
+ }
+ if(pfMagnetoY)
+ {
+ *pfMagnetoY = (float)pi16Data[1];
+ *pfMagnetoY *= CONVERT_TO_TESLA;
+ }
+ if(pfMagnetoZ)
+ {
+ *pfMagnetoZ = (float)pi16Data[2];
+ *pfMagnetoZ *= CONVERT_TO_TESLA;
+ }
+}
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
diff --git a/sensorlib/mpu9150.h b/sensorlib/mpu9150.h
new file mode 100644
index 0000000..459d6ca
--- /dev/null
+++ b/sensorlib/mpu9150.h
@@ -0,0 +1,187 @@
+//*****************************************************************************
+//
+// mpu9150.h - Prototypes for the MPU9150 accelerometer, gyroscope, and
+// magnetometer driver.
+//
+// Copyright (c) 2013-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
+//
+//*****************************************************************************
+
+#ifndef __SENSORLIB_MPU9150_H__
+#define __SENSORLIB_MPU9150_H__
+
+//*****************************************************************************
+//
+// If building with a C++ compiler, make all of the definitions in this header
+// have a C binding.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+//*****************************************************************************
+//
+// The structure that defines the internal state of the MPU9150 driver.
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ // The pointer to the I2C master interface instance used to communicate
+ // with the MPU9150.
+ //
+ tI2CMInstance *psI2CInst;
+
+ //
+ // The AK8975 inst that used to access the on-chip AK8975 magnetometer
+ //
+ tAK8975 sAK8975Inst;
+
+ //
+ // The I2C address of the MPU9150.
+ //
+ uint8_t ui8Addr;
+
+ //
+ // The state of the state machine used while accessing the MPU9150.
+ //
+ uint8_t ui8State;
+
+ //
+ // The current accelerometer afs_sel setting
+ //
+ uint8_t ui8AccelAfsSel;
+
+ //
+ // The new accelerometer afs_sel setting, which is used when a register
+ // write succeeds.
+ //
+ uint8_t ui8NewAccelAfsSel;
+
+ //
+ // The current gyroscope fs_sel setting
+ //
+ uint8_t ui8GyroFsSel;
+
+ //
+ // The new gyroscope fs_sel setting, which is used when a register write
+ // succeeds.
+ //
+ uint8_t ui8NewGyroFsSel;
+
+ //
+ // The data buffer used for sending/receiving data to/from the MPU9150.
+ //
+ uint8_t pui8Data[24];
+
+ //
+ // The function that is called when the current request has completed
+ // processing.
+ //
+ tSensorCallback *pfnCallback;
+
+ //
+ // The callback data provided to the callback function.
+ //
+ void *pvCallbackData;
+
+ //
+ // A union of structures that are used for read, write and
+ // read-modify-write operations. Since only one operation can be active at
+ // a time, it is safe to re-use the memory in this manner.
+ //
+ union
+ {
+ //
+ // A buffer used to store the write portion of a register read.
+ //
+ uint8_t pui8Buffer[6];
+
+ //
+ // The write state used to write register values.
+ //
+ tI2CMWrite8 sWriteState;
+
+ //
+ // The read-modify-write state used to modify register values.
+ //
+ tI2CMReadModifyWrite8 sReadModifyWriteState;
+ }
+ uCommand;
+}
+tMPU9150;
+
+//*****************************************************************************
+//
+// Function prototypes.
+//
+//*****************************************************************************
+extern uint_fast8_t MPU9150Init(tMPU9150 *psInst, tI2CMInstance *psI2CInst,
+ uint_fast8_t ui8I2CAddr,
+ tSensorCallback *pfnCallback,
+ void *pvCallbackData);
+extern tAK8975 *MPU9150InstAK8975Get(tMPU9150 *psInst);
+extern uint_fast8_t MPU9150Read(tMPU9150 *psInst, uint_fast8_t ui8Reg,
+ uint8_t *pui8Data, uint_fast16_t ui16Count,
+ tSensorCallback *pfnCallback,
+ void *pvCallbackData);
+extern uint_fast8_t MPU9150Write(tMPU9150 *psInst, uint_fast8_t ui8Reg,
+ const uint8_t *pui8Data,
+ uint_fast16_t ui16Count,
+ tSensorCallback *pfnCallback,
+ void *pvCallbackData);
+extern uint_fast8_t MPU9150ReadModifyWrite(tMPU9150 *psInst,
+ uint_fast8_t ui8Reg,
+ uint_fast8_t ui8Mask,
+ uint_fast8_t ui8Value,
+ tSensorCallback *pfnCallback,
+ void *pvCallbackData);
+extern uint_fast8_t MPU9150DataRead(tMPU9150 *psInst,
+ tSensorCallback *pfnCallback,
+ void *pvCallbackData);
+extern void MPU9150DataAccelGetRaw(tMPU9150 *psInst,
+ uint_fast16_t *pui16AccelX,
+ uint_fast16_t *pui16AccelY,
+ uint_fast16_t *pui16AccelZ);
+extern void MPU9150DataAccelGetFloat(tMPU9150 *psInst, float *pfAccelX,
+ float *pfAccelY, float *pfAccelZ);
+extern void MPU9150DataGyroGetRaw(tMPU9150 *psInst, uint_fast16_t *pui16GyroX,
+ uint_fast16_t *pui16GyroY,
+ uint_fast16_t *pui16GyroZ);
+extern void MPU9150DataGyroGetFloat(tMPU9150 *psInst, float *pfGyroX,
+ float *pfGyroY, float *pfGyroZ);
+extern void MPU9150DataMagnetoGetRaw(tMPU9150 *psInst,
+ uint_fast16_t *pui16MagnetoX,
+ uint_fast16_t *pui16MagnetoY,
+ uint_fast16_t *pui16MagnetoZ);
+extern void MPU9150DataMagnetoGetFloat(tMPU9150 *psInst, float *pfMagnetoX,
+ float *pfMagnetoY, float *pfMagnetoZ);
+
+//*****************************************************************************
+//
+// Mark the end of the C bindings section for C++ compilers.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __SENSORLIB_MPU9150_H__
diff --git a/sensorlib/quaternion.c b/sensorlib/quaternion.c
new file mode 100644
index 0000000..78296aa
--- /dev/null
+++ b/sensorlib/quaternion.c
@@ -0,0 +1,286 @@
+//*****************************************************************************
+//
+// quaternion.c - Functions for performing quaternion operations.
+//
+// Copyright (c) 2013-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
+//
+//*****************************************************************************
+
+#include <math.h>
+#include "sensorlib/quaternion.h"
+
+//*****************************************************************************
+//
+//! \addtogroup quaternion_api
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// If M_PI has not been defined by the system headers, define it here.
+//
+//*****************************************************************************
+#ifndef M_PI
+#define M_PI 3.14159265358979323846
+#endif
+
+//*****************************************************************************
+//
+//! Computes a quaternion from a set of eueler angles specified in degrees
+//!
+//! \param pfQOut is the inverted quaternion in W,X,Y,Z form
+//! \param fRollDeg is roll in degrees
+//! \param fPitchDeg is pitch in degrees
+//! \param fYawDeg is yaw in degrees
+//!
+//! This function computes a quaternion from a set of euler angles specified
+//! in degrees
+//!
+//! \return Returns a quaternion representing the provided eulers
+//
+//*****************************************************************************
+void
+QuaternionFromEuler(float pfQOut[4], float fRollDeg, float fPitchDeg,
+ float fYawDeg)
+{
+ float fRoll, fPitch, fYaw;
+ float fCOSY, fCOSP, fCOSR;
+ float fSINY, fSINP, fSINR;
+
+ //
+ // Convert roll, pitch, and yaw from degrees into radians
+ //
+ fRoll = fRollDeg * M_PI / 180.0;
+ fPitch = fPitchDeg * M_PI / 180.0;
+ fYaw = fYawDeg * M_PI / 180.0;
+
+ //
+ // Pre-calculate the cosine of (yaw, pitch, roll divided by 2)
+ //
+ fCOSY = cosf(fYaw / 2.0);
+ fCOSP = cosf(fPitch / 2.0);
+ fCOSR = cosf(fRoll / 2.0);
+
+ //
+ // Pre-calculate the sine of (yaw, pitch, roll divided by 2)
+ //
+ fSINY = sinf(fYaw / 2.0);
+ fSINP = sinf(fPitch / 2.0);
+ fSINR = sinf(fRoll / 2.0);
+
+ //
+ // The W component
+ //
+ pfQOut[Q_W] = fCOSY * fCOSP * fCOSR - fSINY * fSINP * fSINR;
+
+ //
+ // The X component
+ //
+ pfQOut[Q_X] = fSINY * fSINP * fCOSR + fCOSY * fCOSP * fSINR;
+
+ //
+ // The Y component
+ //
+ pfQOut[Q_Y] = fCOSY * fSINP * fCOSR - fSINY * fCOSP * fSINR;
+
+ //
+ // The Z component
+ //
+ pfQOut[Q_Z] = fSINY * fCOSP * fCOSR + fCOSY * fSINP * fSINR;
+}
+
+//*****************************************************************************
+//
+//! Computes the magnitude of a quaternion.
+//!
+//! \param pfQIn is the source quaternion in W,X,Y,Z form
+//!
+//! This function computes the magnitude of a quaternion by summing the square
+//! of each of the quatnerion components.
+//!
+//! \return Returns the scalar magnitude of the quaternion
+//
+//*****************************************************************************
+float
+QuaternionMagnitude(float pfQIn[4])
+{
+ float fSumSq;
+
+ //
+ // Calculate the magnitude of the quaternion by finding the sum of the
+ // squares of each component.
+ //
+ fSumSq = ((pfQIn[Q_W] * pfQIn[Q_W]) + (pfQIn[Q_X] * pfQIn[Q_X]) +
+ (pfQIn[Q_Y] * pfQIn[Q_Y]) + (pfQIn[Q_Z] * pfQIn[Q_Z]));
+
+ return(fSumSq);
+}
+
+//*****************************************************************************
+//
+//! Computes the inverse of a quaternion.
+//!
+//! \param pfQOut is the inverted quaternion in W,X,Y,Z form
+//! \param pfQIn is the source quaternion in W,X,Y,Z form
+//!
+//! This function computes the inverse of a quaternion. The inverse of a
+//! quaternion produces a rotation opposite to the source quaternion. This
+//! can be achieved by simply changing the signs of the imaginary components
+//! of a quaternion when the quatnerion is a unit quaternion.
+//!
+//! \return Returns the inverse of a quaternion.
+//
+//*****************************************************************************
+void
+QuaternionInverse(float pfQOut[4], float pfQIn[4])
+{
+ float fMag;
+
+ //
+ // Find magnitude of the quaternion. This will be used to normalize the
+ // source quaternion if it's not already. If it is a unit quaternion then
+ // the magnitude should be nearly equal to 1.0 and dividing by the
+ // magnitude has no mathemtical effect.
+ //
+ fMag = QuaternionMagnitude(pfQIn);
+
+ //
+ // Normalize the W component
+ //
+ pfQOut[Q_W] = pfQIn[Q_W] / fMag;
+
+ //
+ // Invert and normalize the X component
+ //
+ pfQOut[Q_X] = -pfQIn[Q_X] / fMag;
+
+ //
+ // Invert and normalize the Y component
+ //
+ pfQOut[Q_Y] = -pfQIn[Q_Y] / fMag;
+
+ //
+ // Invert and normalize the Z component
+ //
+ pfQOut[Q_Z] = -pfQIn[Q_Z] / fMag;
+}
+
+//*****************************************************************************
+//
+//! Computes the product of two quaternions.
+//!
+//! \param pfQOut is the product of In1 X In2
+//! \param pfQIn1 is the source quaternion in W,X,Y,Z form
+//! \param pfQIn2 is the source quaternion in W,X,Y,Z form
+//!
+//! This function computes the cross product of two quaternions.
+//!
+//! \return Returns the cross product of the two quaternions.
+//
+//*****************************************************************************
+void
+QuaternionMult(float pfQOut[4], float pfQIn1[4], float pfQIn2[4])
+{
+ //
+ // Let Q1 and Q2 be two quaternions with components w,x,y,z
+ // Let Qp be the cross product Q1 x Q2. The components of Qp can be
+ // calculated as follows:
+ //
+ // Qp.w = (Q1w Q2w) - (Q1x Q2x) - (Q1y Q2y) - (Q1z Q2z)
+ // Qp.x = (Q1w Q2x) + (Q1x Q2w) - (Q1z Q2y) + (Q1y Q2z)
+ // Qp.y = (Q1y Q2w) + (Q1z Q2x) + (Q1w Q2y) - (Q1x Q2z)
+ // Qp.z = (Q1z Q2w) - (Q1y Q2x) + (Q1x Q2y) + (Q1w Q2z)
+ //
+
+ //
+ // Calculate the W term
+ //
+ pfQOut[Q_W] = ((pfQIn2[Q_W] * pfQIn1[Q_W]) - (pfQIn2[Q_X] * pfQIn1[Q_X]) -
+ (pfQIn2[Q_Y] * pfQIn1[Q_Y]) - (pfQIn2[Q_Z] * pfQIn1[Q_Z]));
+
+ //
+ // Calculate the X term
+ //
+ pfQOut[Q_X]= ((pfQIn2[Q_X] * pfQIn1[Q_W]) + (pfQIn2[Q_W] * pfQIn1[Q_X]) -
+ (pfQIn2[Q_Y] * pfQIn1[Q_Z]) + (pfQIn2[Q_Z] * pfQIn1[Q_Y]));
+
+ //
+ // Calculate the Y term
+ //
+ pfQOut[Q_Y]= ((pfQIn2[Q_W] * pfQIn1[Q_Y]) + (pfQIn2[Q_X] * pfQIn1[Q_Z]) -
+ (pfQIn2[Q_Y] * pfQIn1[Q_W]) - (pfQIn2[Q_Z] * pfQIn1[Q_X]));
+
+ //
+ // Calculate the Z term
+ //
+ pfQOut[Q_Z] = ((pfQIn2[Q_W] * pfQIn1[Q_Z]) - (pfQIn2[Q_X] * pfQIn1[Q_Y]) -
+ (pfQIn2[Q_Y] * pfQIn1[Q_X]) + (pfQIn2[Q_Z] * pfQIn1[Q_W]));
+}
+
+//*****************************************************************************
+//
+//! Computes the angle between two quaternions
+//!
+//! \param pfQIn1 is a source quaternion in W,X,Y,Z form
+//! \param pfQIn2 is a source quaternion in W,X,Y,Z form
+//!
+//! This function computes the angle between two quaternions.
+//!
+//! \return Returns the angle, in radians, between the two quaternions.
+//
+//*****************************************************************************
+float
+QuaternionAngle(float pfQIn1[4], float pfQIn2[4])
+{
+ float pfQInv[4];
+ float pfQProd[4];
+
+ //
+ // Let Q1 and Q2 be two quaternions having components w,x,y,z. The angle
+ // between the orientations represented by Q1 and Q2 can be calculated
+ // with:
+ //
+ // angle = arccos( (Q2 * Q1').w ) * 2.0;
+ //
+ // where Q1' is the inverse of Q1
+ //
+
+ //
+ // Calculate the inverse of Q1
+ //
+ QuaternionInverse(pfQInv, pfQIn1);
+
+ //
+ // Find the product of Q2 x Q1`
+ //
+ QuaternionMult(pfQProd, pfQIn2, pfQInv);
+
+ //
+ // calculate the arccos of the w component of the previous product.
+ //
+ return(acosf(pfQProd[Q_W]) * 2.0);
+}
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
diff --git a/sensorlib/quaternion.h b/sensorlib/quaternion.h
new file mode 100644
index 0000000..79f9270
--- /dev/null
+++ b/sensorlib/quaternion.h
@@ -0,0 +1,70 @@
+//*****************************************************************************
+//
+// quaternion.h - Prototypes for the quaternion functions.
+//
+// Copyright (c) 2013-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
+//
+//*****************************************************************************
+
+#ifndef __SENSORLIB_QUATERNION_H__
+#define __SENSORLIB_QUATERNION_H__
+
+//*****************************************************************************
+//
+// If building with a C++ compiler, make all of the definitions in this header
+// have a C binding.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+//*****************************************************************************
+//
+// The index of the components in a quaternion vector.
+//
+//*****************************************************************************
+#define Q_W 0
+#define Q_X 1
+#define Q_Y 2
+#define Q_Z 3
+
+//*****************************************************************************
+//
+// Prototypes.
+//
+//*****************************************************************************
+extern void QuaternionFromEuler(float pfQOut[4], float fRollDeg,
+ float fPitchDeg, float fYawDeg);
+extern float QuaternionMagnitude(float pfQIn[4]);
+extern void QuaternionInverse(float pfQOut[4], float pfQIn[4]);
+extern void QuaternionMult(float pfQOut[4], float pfQIn1[4], float pfQIn2[4]);
+extern float QuaternionAngle(float pfQIn1[4], float pfQIn2[4]);
+
+//*****************************************************************************
+//
+// Mark the end of the C bindings section for C++ compilers.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __SENSORLIB_QUATERNION_H__
diff --git a/sensorlib/readme.txt b/sensorlib/readme.txt
new file mode 100644
index 0000000..209ec0c
--- /dev/null
+++ b/sensorlib/readme.txt
@@ -0,0 +1,21 @@
+This project will build the Texas Instruments Sensor Library.
+
+-------------------------------------------------------------------------------
+
+Copyright (c) 2013-2014 Texas Instruments Incorporated. All rights reserved.
+Software License Agreement
+
+Texas Instruments (TI) is supplying this software for use solely and
+exclusively on TI's microcontroller products. The software is owned by
+TI and/or its suppliers, and is protected under applicable copyright
+laws. You may not combine this software with "viral" open-source
+software in order to form a larger program.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+DAMAGES, FOR ANY REASON WHATSOEVER.
+
+This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
diff --git a/sensorlib/rvmdk/sensorlib.lib b/sensorlib/rvmdk/sensorlib.lib
new file mode 100644
index 0000000..582e01b
--- /dev/null
+++ b/sensorlib/rvmdk/sensorlib.lib
Binary files differ
diff --git a/sensorlib/sensorlib.ewp b/sensorlib/sensorlib.ewp
new file mode 100644
index 0000000..9504f35
--- /dev/null
+++ b/sensorlib/sensorlib.ewp
@@ -0,0 +1,833 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+
+<project>
+ <fileVersion>1</fileVersion>
+ <configuration>
+ <name>Debug</name>
+ <toolchain>
+ <name>ARM</name>
+ </toolchain>
+ <debug>1</debug>
+ <settings>
+ <name>General</name>
+ <archiveVersion>3</archiveVersion>
+ <data>
+ <version>14</version>
+ <wantNonLocal>1</wantNonLocal>
+ <debug>1</debug>
+ <option>
+ <name>ExePath</name>
+ <state>ewarm\Exe</state>
+ </option>
+ <option>
+ <name>ObjPath</name>
+ <state>ewarm\Obj</state>
+ </option>
+ <option>
+ <name>ListPath</name>
+ <state>ewarm\List</state>
+ </option>
+ <option>
+ <name>Variant</name>
+ <version>19</version>
+ <state>39</state>
+ </option>
+ <option>
+ <name>GEndianMode</name>
+ <state>0</state>
+ </option>
+ <option>
+ <name>Input variant</name>
+ <version>1</version>
+ <state>0</state>
+ </option>
+ <option>
+ <name>Input description</name>
+ <state>Full formatting.</state>
+ </option>
+ <option>
+ <name>Output variant</name>
+ <version>0</version>
+ <state>0</state>
+ </option>
+ <option>
+ <name>Output description</name>
+ <state>Full formatting.</state>
+ </option>
+ <option>
+ <name>GOutputBinary</name>
+ <state>1</state>
+ </option>
+ <option>
+ <name>FPU</name>
+ <version>2</version>
+ <state>5</state>
+ </option>
+ <option>
+ <name>OGCoreOrChip</name>
+ <state>1</state>
+ </option>
+ <option>
+ <name>GRuntimeLibSelect</name>
+ <version>0</version>
+ <state>1</state>
+ </option>
+ <option>
+ <name>GRuntimeLibSelectSlave</name>
+ <version>0</version>
+ <state>1</state>
+ </option>
+ <option>
+ <name>RTDescription</name>
+ <state>To be used with the normal configuration of the C/C++ runtime library. No locale interface, C locale, no file descriptor support, no multibytes in printf and scanf, and no hex floats in strtod.</state>
+ </option>
+ <option>
+ <name>RTConfigPath</name>
+ <state>$TOOLKIT_DIR$\INC\DLib_Config_Normal.h</state>
+ </option>
+ <option>
+ <name>OGProductVersion</name>
+ <state>5.11.0.50579</state>
+ </option>
+ <option>
+ <name>OGLastSavedByProductVersion</name>
+ <state>5.11.0.50579</state>
+ </option>
+ <option>
+ <name>GeneralMisraRules</name>
+ <version>0</version>
+ <state>1000111110110101101110011100111111101110011011000101110111101101100111111111111100110011111001110111001111111111111111111111111</state>
+ </option>
+ <option>
+ <name>GeneralEnableMisra</name>
+ <state>0</state>
+ </option>
+ <option>
+ <name>GeneralMisraVerbose</name>
+ <state>0</state>
+ </option>
+ <option>
+ <name>OGChipSelectEditMenu</name>
+ <state>TM4C1230C3PM TexasInstruments TM4C1230C3PM</state>
+ </option>
+ <option>
+ <name>GenLowLevelInterface</name>
+ <state>1</state>
+ </option>
+ <option>
+ <name>GEndianModeBE</name>
+ <state>1</state>
+ </option>
+ <option>
+ <name>OGBufferedTerminalOutput</name>
+ <state>0</state>
+ </option>
+ </data>
+ </settings>
+ <settings>
+ <name>ICCARM</name>
+ <archiveVersion>2</archiveVersion>
+ <data>
+ <version>19</version>
+ <wantNonLocal>1</wantNonLocal>
+ <debug>1</debug>
+ <option>
+ <name>CCDefines</name>
+ <state>ewarm</state>
+ </option>
+ <option>
+ <name>CCPreprocFile</name>
+ <state>0</state>
+ </option>
+ <option>
+ <name>CCPreprocComments</name>
+ <state>0</state>
+ </option>
+ <option>
+ <name>CCPreprocLine</name>
+ <state>0</state>
+ </option>
+ <option>
+ <name>CCListCFile</name>
+ <state>0</state>
+ </option>
+ <option>
+ <name>CCListCMnemonics</name>
+ <state>0</state>
+ </option>
+ <option>
+ <name>CCListCMessages</name>
+ <state>0</state>
+ </option>
+ <option>
+ <name>CCListAssFile</name>
+ <state>0</state>
+ </option>
+ <option>
+ <name>CCListAssSource</name>
+ <state>0</state>
+ </option>
+ <option>
+ <name>CCEnableRemarks</name>
+ <state>0</state>
+ </option>
+ <option>
+ <name>CCDiagSuppress</name>
+ <state>Pa050</state>
+ </option>
+ <option>
+ <name>CCDiagRemark</name>
+ <state></state>
+ </option>
+ <option>
+ <name>CCDiagWarning</name>
+ <state></state>
+ </option>
+ <option>
+ <name>CCDiagError</name>
+ <state></state>
+ </option>
+ <option>
+ <name>CCObjPrefix</name>
+ <state>1</state>
+ </option>
+ <option>
+ <name>CCAllowList</name>
+ <version>1</version>
+ <state>1111111</state>
+ </option>
+ <option>
+ <name>CCDebugInfo</name>
+ <state>1</state>
+ </option>
+ <option>
+ <name>IEndianMode</name>
+ <state>1</state>
+ </option>
+ <option>
+ <name>IProcessor</name>
+ <state>1</state>
+ </option>
+ <option>
+ <name>IExtraOptionsCheck</name>
+ <state>0</state>
+ </option>
+ <option>
+ <name>IExtraOptions</name>
+ <state></state>
+ </option>
+ <option>
+ <name>CCLangConformance</name>
+ <state>0</state>
+ </option>
+ <option>
+ <name>CCSignedPlainChar</name>
+ <state>1</state>
+ </option>
+ <option>
+ <name>CCRequirePrototypes</name>
+ <state>0</state>
+ </option>
+ <option>
+ <name>CCMultibyteSupport</name>
+ <state>0</state>
+ </option>
+ <option>
+ <name>CCDiagWarnAreErr</name>
+ <state>0</state>
+ </option>
+ <option>
+ <name>CCCompilerRuntimeInfo</name>
+ <state>0</state>
+ </option>
+ <option>
+ <name>IFpuProcessor</name>
+ <state>1</state>
+ </option>
+ <option>
+ <name>OutputFile</name>
+ <state>$FILE_BNAME$.o</state>
+ </option>
+ <option>
+ <name>CCLangSelect</name>
+ <state>0</state>
+ </option>
+ <option>
+ <name>CCLibConfigHeader</name>
+ <state>1</state>
+ </option>
+ <option>
+ <name>PreInclude</name>
+ <state></state>
+ </option>
+ <option>
+ <name>CompilerMisraRules</name>
+ <version>0</version>
+ <state>1000111110110101101110011100111111101110011011000101110111101101100111111111111100110011111001110111001111111111111111111111111</state>
+ </option>
+ <option>
+ <name>CompilerMisraOverride</name>
+ <state>0</state>
+ </option>
+ <option>
+ <name>CCIncludePath2</name>
+ <state>$PROJ_DIR$\..</state>
+ </option>
+ <option>
+ <name>CCStdIncCheck</name>
+ <state>0</state>
+ </option>
+ <option>
+ <name>CCStdIncludePath</name>
+ <state>$TOOLKIT_DIR$\INC\</state>
+ </option>
+ <option>
+ <name>CCCodeSection</name>
+ <state>.text</state>
+ </option>
+ <option>
+ <name>IInterwork2</name>
+ <state>0</state>
+ </option>
+ <option>
+ <name>IProcessorMode2</name>
+ <state>1</state>
+ </option>
+ <option>
+ <name>CCOptLevel</name>
+ <state>3</state>
+ </option>
+ <option>
+ <name>CCOptStrategy</name>
+ <version>0</version>
+ <state>1</state>
+ </option>
+ <option>
+ <name>CCOptLevelSlave</name>
+ <state>3</state>
+ </option>
+ </data>
+ </settings>
+ <settings>
+ <name>AARM</name>
+ <archiveVersion>2</archiveVersion>
+ <data>
+ <version>7</version>
+ <wantNonLocal>1</wantNonLocal>
+ <debug>1</debug>
+ <option>
+ <name>AObjPrefix</name>
+ <state>1</state>
+ </option>
+ <option>
+ <name>AEndian</name>
+ <state>1</state>
+ </option>
+ <option>
+ <name>ACaseSensitivity</name>
+ <state>1</state>
+ </option>
+ <option>
+ <name>MacroChars</name>
+ <version>0</version>
+ <state>0</state>
+ </option>
+ <option>
+ <name>AWarnEnable</name>
+ <state>0</state>
+ </option>
+ <option>
+ <name>AWarnWhat</name>
+ <state>0</state>
+ </option>
+ <option>
+ <name>AWarnOne</name>
+ <state></state>
+ </option>
+ <option>
+ <name>AWarnRange1</name>
+ <state></state>
+ </option>
+ <option>
+ <name>AWarnRange2</name>
+ <state></state>
+ </option>
+ <option>
+ <name>ADebug</name>
+ <state>1</state>
+ </option>
+ <option>
+ <name>AltRegisterNames</name>
+ <state>0</state>
+ </option>
+ <option>
+ <name>ADefines</name>
+ <state>ewarm</state>
+ </option>
+ <option>
+ <name>AList</name>
+ <state>0</state>
+ </option>
+ <option>
+ <name>AListHeader</name>
+ <state>1</state>
+ </option>
+ <option>
+ <name>AListing</name>
+ <state>1</state>
+ </option>
+ <option>
+ <name>Includes</name>
+ <state>0</state>
+ </option>
+ <option>
+ <name>MacDefs</name>
+ <state>0</state>
+ </option>
+ <option>
+ <name>MacExps</name>
+ <state>1</state>
+ </option>
+ <option>
+ <name>MacExec</name>
+ <state>0</state>
+ </option>
+ <option>
+ <name>OnlyAssed</name>
+ <state>0</state>
+ </option>
+ <option>
+ <name>MultiLine</name>
+ <state>0</state>
+ </option>
+ <option>
+ <name>PageLengthCheck</name>
+ <state>0</state>
+ </option>
+ <option>
+ <name>PageLength</name>
+ <state>80</state>
+ </option>
+ <option>
+ <name>TabSpacing</name>
+ <state>8</state>
+ </option>
+ <option>
+ <name>AXRef</name>
+ <state>0</state>
+ </option>
+ <option>
+ <name>AXRefDefines</name>
+ <state>0</state>
+ </option>
+ <option>
+ <name>AXRefInternal</name>
+ <state>0</state>
+ </option>
+ <option>
+ <name>AXRefDual</name>
+ <state>0</state>
+ </option>
+ <option>
+ <name>AProcessor</name>
+ <state>1</state>
+ </option>
+ <option>
+ <name>AFpuProcessor</name>
+ <state>1</state>
+ </option>
+ <option>
+ <name>AOutputFile</name>
+ <state>$FILE_BNAME$.o</state>
+ </option>
+ <option>
+ <name>AMultibyteSupport</name>
+ <state>0</state>
+ </option>
+ <option>
+ <name>ALimitErrorsCheck</name>
+ <state>0</state>
+ </option>
+ <option>
+ <name>ALimitErrorsEdit</name>
+ <state>100</state>
+ </option>
+ <option>
+ <name>AIgnoreStdInclude</name>
+ <state>0</state>
+ </option>
+ <option>
+ <name>AStdIncludes</name>
+ <state>$TOOLKIT_DIR$\INC\</state>
+ </option>
+ <option>
+ <name>AUserIncludes</name>
+ <state></state>
+ </option>
+ <option>
+ <name>AExtraOptionsCheckV2</name>
+ <state>0</state>
+ </option>
+ <option>
+ <name>AExtraOptionsV2</name>
+ <state></state>
+ </option>
+ </data>
+ </settings>
+ <settings>
+ <name>OBJCOPY</name>
+ <archiveVersion>0</archiveVersion>
+ <data>
+ <version>1</version>
+ <wantNonLocal>1</wantNonLocal>
+ <debug>1</debug>
+ <option>
+ <name>OOCOutputFormat</name>
+ <version>1</version>
+ <state>0</state>
+ </option>
+ <option>
+ <name>OCOutputOverride</name>
+ <state>0</state>
+ </option>
+ <option>
+ <name>OOCOutputFile</name>
+ <state>sensorlib.srec</state>
+ </option>
+ <option>
+ <name>OOCCommandLineProducer</name>
+ <state>1</state>
+ </option>
+ <option>
+ <name>OOCObjCopyEnable</name>
+ <state>0</state>
+ </option>
+ </data>
+ </settings>
+ <settings>
+ <name>CUSTOM</name>
+ <archiveVersion>3</archiveVersion>
+ <data>
+ <extensions></extensions>
+ <cmdline></cmdline>
+ </data>
+ </settings>
+ <settings>
+ <name>BICOMP</name>
+ <archiveVersion>0</archiveVersion>
+ <data/>
+ </settings>
+ <settings>
+ <name>BUILDACTION</name>
+ <archiveVersion>1</archiveVersion>
+ <data>
+ <prebuild></prebuild>
+ <postbuild></postbuild>
+ </data>
+ </settings>
+ <settings>
+ <name>ILINK</name>
+ <archiveVersion>0</archiveVersion>
+ <data>
+ <version>5</version>
+ <wantNonLocal>1</wantNonLocal>
+ <debug>1</debug>
+ <option>
+ <name>IlinkLibIOConfig</name>
+ <state>1</state>
+ </option>
+ <option>
+ <name>XLinkMisraHandler</name>
+ <state>0</state>
+ </option>
+ <option>
+ <name>IlinkInputFileSlave</name>
+ <state>0</state>
+ </option>
+ <option>
+ <name>IlinkOutputFile</name>
+ <state>sensorlib.out</state>
+ </option>
+ <option>
+ <name>IlinkDebugInfoEnable</name>
+ <state>1</state>
+ </option>
+ <option>
+ <name>IlinkKeepSymbols</name>
+ <state></state>
+ </option>
+ <option>
+ <name>IlinkRawBinaryFile</name>
+ <state></state>
+ </option>
+ <option>
+ <name>IlinkRawBinarySymbol</name>
+ <state></state>
+ </option>
+ <option>
+ <name>IlinkRawBinarySegment</name>
+ <state></state>
+ </option>
+ <option>
+ <name>IlinkRawBinaryAlign</name>
+ <state></state>
+ </option>
+ <option>
+ <name>IlinkDefines</name>
+ <state></state>
+ </option>
+ <option>
+ <name>IlinkConfigDefines</name>
+ <state></state>
+ </option>
+ <option>
+ <name>IlinkMapFile</name>
+ <state>0</state>
+ </option>
+ <option>
+ <name>IlinkLogFile</name>
+ <state>0</state>
+ </option>
+ <option>
+ <name>IlinkLogInitialization</name>
+ <state>0</state>
+ </option>
+ <option>
+ <name>IlinkLogModule</name>
+ <state>0</state>
+ </option>
+ <option>
+ <name>IlinkLogSection</name>
+ <state>0</state>
+ </option>
+ <option>
+ <name>IlinkLogVeneer</name>
+ <state>0</state>
+ </option>
+ <option>
+ <name>IlinkIcfOverride</name>
+ <state>0</state>
+ </option>
+ <option>
+ <name>IlinkIcfFile</name>
+ <state>lnk0t.icf</state>
+ </option>
+ <option>
+ <name>IlinkIcfFileSlave</name>
+ <state></state>
+ </option>
+ <option>
+ <name>IlinkEnableRemarks</name>
+ <state>0</state>
+ </option>
+ <option>
+ <name>IlinkSuppressDiags</name>
+ <state></state>
+ </option>
+ <option>
+ <name>IlinkTreatAsRem</name>
+ <state></state>
+ </option>
+ <option>
+ <name>IlinkTreatAsWarn</name>
+ <state></state>
+ </option>
+ <option>
+ <name>IlinkTreatAsErr</name>
+ <state></state>
+ </option>
+ <option>
+ <name>IlinkWarningsAreErrors</name>
+ <state>0</state>
+ </option>
+ <option>
+ <name>IlinkUseExtraOptions</name>
+ <state>0</state>
+ </option>
+ <option>
+ <name>IlinkExtraOptions</name>
+ <state></state>
+ </option>
+ <option>
+ <name>IlinkLowLevelInterfaceSlave</name>
+ <state>1</state>
+ </option>
+ <option>
+ <name>IlinkAutoLibEnable</name>
+ <state>1</state>
+ </option>
+ <option>
+ <name>IlinkAdditionalLibs</name>
+ <state></state>
+ </option>
+ <option>
+ <name>IlinkOverrideProgramEntryLabel</name>
+ <state>0</state>
+ </option>
+ <option>
+ <name>IlinkProgramEntryLabelSelect</name>
+ <state>0</state>
+ </option>
+ <option>
+ <name>IlinkProgramEntryLabel</name>
+ <state></state>
+ </option>
+ <option>
+ <name>IlinkNXPLPCChecksum</name>
+ <state>0</state>
+ </option>
+ <option>
+ <name>DoFill</name>
+ <state>0</state>
+ </option>
+ <option>
+ <name>FillerByte</name>
+ <state>0xFF</state>
+ </option>
+ <option>
+ <name>FillerStart</name>
+ <state>0x0</state>
+ </option>
+ <option>
+ <name>FillerEnd</name>
+ <state>0x0</state>
+ </option>
+ <option>
+ <name>CrcSize</name>
+ <version>0</version>
+ <state>1</state>
+ </option>
+ <option>
+ <name>CrcAlign</name>
+ <state>1</state>
+ </option>
+ <option>
+ <name>CrcAlgo</name>
+ <state>1</state>
+ </option>
+ <option>
+ <name>CrcPoly</name>
+ <state>0x11021</state>
+ </option>
+ <option>
+ <name>CrcCompl</name>
+ <version>0</version>
+ <state>0</state>
+ </option>
+ <option>
+ <name>CrcBitOrder</name>
+ <version>0</version>
+ <state>0</state>
+ </option>
+ <option>
+ <name>CrcInitialValue</name>
+ <state>0x0</state>
+ </option>
+ <option>
+ <name>DoCrc</name>
+ <state>0</state>
+ </option>
+ <option>
+ <name>IlinkBE8Slave</name>
+ <state>1</state>
+ </option>
+ <option>
+ <name>IlinkBufferedTerminalOutput</name>
+ <state>1</state>
+ </option>
+ </data>
+ </settings>
+ <settings>
+ <name>IARCHIVE</name>
+ <archiveVersion>0</archiveVersion>
+ <data>
+ <version>0</version>
+ <wantNonLocal>1</wantNonLocal>
+ <debug>1</debug>
+ <option>
+ <name>IarchiveInputs</name>
+ <state></state>
+ </option>
+ <option>
+ <name>IarchiveOverride</name>
+ <state>0</state>
+ </option>
+ <option>
+ <name>IarchiveOutput</name>
+ <state>$PROJ_DIR$\ewarm\Exe\sensorlib.a</state>
+ </option>
+ </data>
+ </settings>
+ <settings>
+ <name>BILINK</name>
+ <archiveVersion>0</archiveVersion>
+ <data/>
+ </settings>
+ </configuration>
+ <group>
+ <name>Source</name>
+ <file>
+ <name>$PROJ_DIR$\ak8963.c</name>
+ </file>
+ <file>
+ <name>$PROJ_DIR$\ak8975.c</name>
+ </file>
+ <file>
+ <name>$PROJ_DIR$\bmp180.c</name>
+ </file>
+ <file>
+ <name>$PROJ_DIR$\bq27510g3.c</name>
+ </file>
+ <file>
+ <name>$PROJ_DIR$\cm3218.c</name>
+ </file>
+ <file>
+ <name>$PROJ_DIR$\comp_dcm.c</name>
+ </file>
+ <file>
+ <name>$PROJ_DIR$\i2cm_drv.c</name>
+ </file>
+ <file>
+ <name>$PROJ_DIR$\isl29023.c</name>
+ </file>
+ <file>
+ <name>$PROJ_DIR$\kxti9.c</name>
+ </file>
+ <file>
+ <name>$PROJ_DIR$\l3gd20h.c</name>
+ </file>
+ <file>
+ <name>$PROJ_DIR$\lsm303d.c</name>
+ </file>
+ <file>
+ <name>$PROJ_DIR$\lsm303dlhc_accel.c</name>
+ </file>
+ <file>
+ <name>$PROJ_DIR$\lsm303dlhc_mag.c</name>
+ </file>
+ <file>
+ <name>$PROJ_DIR$\magneto.c</name>
+ </file>
+ <file>
+ <name>$PROJ_DIR$\mpu6050.c</name>
+ </file>
+ <file>
+ <name>$PROJ_DIR$\mpu9150.c</name>
+ </file>
+ <file>
+ <name>$PROJ_DIR$\quaternion.c</name>
+ </file>
+ <file>
+ <name>$PROJ_DIR$\sht21.c</name>
+ </file>
+ <file>
+ <name>$PROJ_DIR$\tmp006.c</name>
+ </file>
+ <file>
+ <name>$PROJ_DIR$\tmp100.c</name>
+ </file>
+ <file>
+ <name>$PROJ_DIR$\vector.c</name>
+ </file>
+ </group>
+</project>
diff --git a/sensorlib/sensorlib.uvopt b/sensorlib/sensorlib.uvopt
new file mode 100644
index 0000000..2d5838b
--- /dev/null
+++ b/sensorlib/sensorlib.uvopt
@@ -0,0 +1,524 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
+<ProjectOpt xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="project_opt.xsd">
+
+ <SchemaVersion>1.0</SchemaVersion>
+
+ <Header>### uVision Project, (C) Keil Software</Header>
+
+ <Extensions>
+ <cExt>*.c</cExt>
+ <aExt>*.s*; *.src; *.a*</aExt>
+ <oExt>*.obj</oExt>
+ <lExt>*.lib</lExt>
+ <tExt>*.txt; *.h; *.inc</tExt>
+ <pExt>*.plm</pExt>
+ <CppX>*.cpp</CppX>
+ </Extensions>
+
+ <DaveTm>
+ <dwLowDateTime>0</dwLowDateTime>
+ <dwHighDateTime>0</dwHighDateTime>
+ </DaveTm>
+
+ <Target>
+ <TargetName>sensorlib</TargetName>
+ <ToolsetNumber>0x4</ToolsetNumber>
+ <ToolsetName>ARM-ADS</ToolsetName>
+ <TargetOption>
+ <CLKADS>8000000</CLKADS>
+ <OPTTT>
+ <gFlags>1</gFlags>
+ <BeepAtEnd>1</BeepAtEnd>
+ <RunSim>1</RunSim>
+ <RunTarget>0</RunTarget>
+ </OPTTT>
+ <OPTHX>
+ <HexSelection>1</HexSelection>
+ <FlashByte>65535</FlashByte>
+ <HexRangeLowAddress>0</HexRangeLowAddress>
+ <HexRangeHighAddress>0</HexRangeHighAddress>
+ <HexOffset>0</HexOffset>
+ </OPTHX>
+ <OPTLEX>
+ <PageWidth>79</PageWidth>
+ <PageLength>66</PageLength>
+ <TabStop>8</TabStop>
+ <ListingPath>.\rvmdk\</ListingPath>
+ </OPTLEX>
+ <ListingPage>
+ <CreateCListing>1</CreateCListing>
+ <CreateAListing>1</CreateAListing>
+ <CreateLListing>1</CreateLListing>
+ <CreateIListing>0</CreateIListing>
+ <AsmCond>1</AsmCond>
+ <AsmSymb>1</AsmSymb>
+ <AsmXref>0</AsmXref>
+ <CCond>1</CCond>
+ <CCode>0</CCode>
+ <CListInc>0</CListInc>
+ <CSymb>0</CSymb>
+ <LinkerCodeListing>0</LinkerCodeListing>
+ </ListingPage>
+ <OPTXL>
+ <LMap>1</LMap>
+ <LComments>1</LComments>
+ <LGenerateSymbols>1</LGenerateSymbols>
+ <LLibSym>1</LLibSym>
+ <LLines>1</LLines>
+ <LLocSym>1</LLocSym>
+ <LPubSym>1</LPubSym>
+ <LXref>0</LXref>
+ <LExpSel>0</LExpSel>
+ </OPTXL>
+ <OPTFL>
+ <tvExp>1</tvExp>
+ <tvExpOptDlg>0</tvExpOptDlg>
+ <IsCurrentTarget>1</IsCurrentTarget>
+ </OPTFL>
+ <CpuCode>255</CpuCode>
+ <Books>
+ <Book>
+ <Number>0</Number>
+ <Title>Data Sheet</Title>
+ <Path>DATASHTS\Luminary\TM4C1230C3PM.PDF</Path>
+ </Book>
+ </Books>
+ <DllOpt>
+ <SimDllName>SARMCM3.DLL</SimDllName>
+ <SimDllArguments>-MPU</SimDllArguments>
+ <SimDlgDllName>DCM.DLL</SimDlgDllName>
+ <SimDlgDllArguments>-pCM4</SimDlgDllArguments>
+ <TargetDllName>SARMCM3.DLL</TargetDllName>
+ <TargetDllArguments>-MPU</TargetDllArguments>
+ <TargetDlgDllName>TCM.DLL</TargetDlgDllName>
+ <TargetDlgDllArguments>-pCM4</TargetDlgDllArguments>
+ </DllOpt>
+ <DebugOpt>
+ <uSim>1</uSim>
+ <uTrg>0</uTrg>
+ <sLdApp>1</sLdApp>
+ <sGomain>1</sGomain>
+ <sRbreak>1</sRbreak>
+ <sRwatch>1</sRwatch>
+ <sRmem>1</sRmem>
+ <sRfunc>1</sRfunc>
+ <sRbox>1</sRbox>
+ <tLdApp>1</tLdApp>
+ <tGomain>0</tGomain>
+ <tRbreak>1</tRbreak>
+ <tRwatch>1</tRwatch>
+ <tRmem>1</tRmem>
+ <tRfunc>0</tRfunc>
+ <tRbox>1</tRbox>
+ <sRunDeb>0</sRunDeb>
+ <sLrtime>0</sLrtime>
+ <nTsel>3</nTsel>
+ <sDll></sDll>
+ <sDllPa></sDllPa>
+ <sDlgDll></sDlgDll>
+ <sDlgPa></sDlgPa>
+ <sIfile></sIfile>
+ <tDll></tDll>
+ <tDllPa></tDllPa>
+ <tDlgDll></tDlgDll>
+ <tDlgPa></tDlgPa>
+ <tIfile></tIfile>
+ <pMon>BIN\lmidk-agdi.dll</pMon>
+ </DebugOpt>
+ <TargetDriverDllRegistry>
+ <SetRegEntry>
+ <Number>0</Number>
+ <Key>lmidk-agdi</Key>
+ <Name>-O4622 -S3 -FO29</Name>
+ </SetRegEntry>
+ </TargetDriverDllRegistry>
+ <DebugFlag>
+ <trace>0</trace>
+ <periodic>1</periodic>
+ <aLwin>0</aLwin>
+ <aCover>0</aCover>
+ <aSer1>0</aSer1>
+ <aSer2>0</aSer2>
+ <aPa>0</aPa>
+ <viewmode>0</viewmode>
+ <vrSel>0</vrSel>
+ <aSym>0</aSym>
+ <aTbox>0</aTbox>
+ <AscS1>0</AscS1>
+ <AscS2>0</AscS2>
+ <AscS3>0</AscS3>
+ <aSer3>0</aSer3>
+ <eProf>0</eProf>
+ <aLa>0</aLa>
+ <aPa1>0</aPa1>
+ <AscS4>0</AscS4>
+ <aSer4>0</aSer4>
+ <StkLoc>0</StkLoc>
+ <TrcWin>0</TrcWin>
+ <newCpu>0</newCpu>
+ <uProt>0</uProt>
+ </DebugFlag>
+ <LintExecutable></LintExecutable>
+ <LintConfigFile></LintConfigFile>
+ </TargetOption>
+ </Target>
+
+ <Group>
+ <GroupName>Source</GroupName>
+ <tvExp>1</tvExp>
+ <tvExpOptDlg>0</tvExpOptDlg>
+ <cbSel>0</cbSel>
+ <File>
+ <GroupNumber>1</GroupNumber>
+ <FileNumber>1</FileNumber>
+ <FileType>1</FileType>
+ <tvExp>0</tvExp>
+ <Focus>0</Focus>
+ <ColumnNumber>0</ColumnNumber>
+ <tvExpOptDlg>0</tvExpOptDlg>
+ <TopLine>0</TopLine>
+ <CurrentLine>0</CurrentLine>
+ <bDave2>0</bDave2>
+ <PathWithFileName>.\ak8963.c</PathWithFileName>
+ <FilenameWithoutPath>ak8963.c</FilenameWithoutPath>
+ </File>
+ <File>
+ <GroupNumber>1</GroupNumber>
+ <FileNumber>2</FileNumber>
+ <FileType>1</FileType>
+ <tvExp>0</tvExp>
+ <Focus>0</Focus>
+ <ColumnNumber>0</ColumnNumber>
+ <tvExpOptDlg>0</tvExpOptDlg>
+ <TopLine>0</TopLine>
+ <CurrentLine>0</CurrentLine>
+ <bDave2>0</bDave2>
+ <PathWithFileName>.\ak8975.c</PathWithFileName>
+ <FilenameWithoutPath>ak8975.c</FilenameWithoutPath>
+ </File>
+ <File>
+ <GroupNumber>1</GroupNumber>
+ <FileNumber>3</FileNumber>
+ <FileType>1</FileType>
+ <tvExp>0</tvExp>
+ <Focus>0</Focus>
+ <ColumnNumber>0</ColumnNumber>
+ <tvExpOptDlg>0</tvExpOptDlg>
+ <TopLine>0</TopLine>
+ <CurrentLine>0</CurrentLine>
+ <bDave2>0</bDave2>
+ <PathWithFileName>.\bmp180.c</PathWithFileName>
+ <FilenameWithoutPath>bmp180.c</FilenameWithoutPath>
+ </File>
+ <File>
+ <GroupNumber>1</GroupNumber>
+ <FileNumber>4</FileNumber>
+ <FileType>1</FileType>
+ <tvExp>0</tvExp>
+ <Focus>0</Focus>
+ <ColumnNumber>0</ColumnNumber>
+ <tvExpOptDlg>0</tvExpOptDlg>
+ <TopLine>0</TopLine>
+ <CurrentLine>0</CurrentLine>
+ <bDave2>0</bDave2>
+ <PathWithFileName>.\bq27510g3.c</PathWithFileName>
+ <FilenameWithoutPath>bq27510g3.c</FilenameWithoutPath>
+ </File>
+ <File>
+ <GroupNumber>1</GroupNumber>
+ <FileNumber>5</FileNumber>
+ <FileType>1</FileType>
+ <tvExp>0</tvExp>
+ <Focus>0</Focus>
+ <ColumnNumber>0</ColumnNumber>
+ <tvExpOptDlg>0</tvExpOptDlg>
+ <TopLine>0</TopLine>
+ <CurrentLine>0</CurrentLine>
+ <bDave2>0</bDave2>
+ <PathWithFileName>.\cm3218.c</PathWithFileName>
+ <FilenameWithoutPath>cm3218.c</FilenameWithoutPath>
+ </File>
+ <File>
+ <GroupNumber>1</GroupNumber>
+ <FileNumber>6</FileNumber>
+ <FileType>1</FileType>
+ <tvExp>0</tvExp>
+ <Focus>0</Focus>
+ <ColumnNumber>0</ColumnNumber>
+ <tvExpOptDlg>0</tvExpOptDlg>
+ <TopLine>0</TopLine>
+ <CurrentLine>0</CurrentLine>
+ <bDave2>0</bDave2>
+ <PathWithFileName>.\comp_dcm.c</PathWithFileName>
+ <FilenameWithoutPath>comp_dcm.c</FilenameWithoutPath>
+ </File>
+ <File>
+ <GroupNumber>1</GroupNumber>
+ <FileNumber>7</FileNumber>
+ <FileType>1</FileType>
+ <tvExp>0</tvExp>
+ <Focus>0</Focus>
+ <ColumnNumber>0</ColumnNumber>
+ <tvExpOptDlg>0</tvExpOptDlg>
+ <TopLine>0</TopLine>
+ <CurrentLine>0</CurrentLine>
+ <bDave2>0</bDave2>
+ <PathWithFileName>.\i2cm_drv.c</PathWithFileName>
+ <FilenameWithoutPath>i2cm_drv.c</FilenameWithoutPath>
+ </File>
+ <File>
+ <GroupNumber>1</GroupNumber>
+ <FileNumber>8</FileNumber>
+ <FileType>1</FileType>
+ <tvExp>0</tvExp>
+ <Focus>0</Focus>
+ <ColumnNumber>0</ColumnNumber>
+ <tvExpOptDlg>0</tvExpOptDlg>
+ <TopLine>0</TopLine>
+ <CurrentLine>0</CurrentLine>
+ <bDave2>0</bDave2>
+ <PathWithFileName>.\isl29023.c</PathWithFileName>
+ <FilenameWithoutPath>isl29023.c</FilenameWithoutPath>
+ </File>
+ <File>
+ <GroupNumber>1</GroupNumber>
+ <FileNumber>9</FileNumber>
+ <FileType>1</FileType>
+ <tvExp>0</tvExp>
+ <Focus>0</Focus>
+ <ColumnNumber>0</ColumnNumber>
+ <tvExpOptDlg>0</tvExpOptDlg>
+ <TopLine>0</TopLine>
+ <CurrentLine>0</CurrentLine>
+ <bDave2>0</bDave2>
+ <PathWithFileName>.\kxti9.c</PathWithFileName>
+ <FilenameWithoutPath>kxti9.c</FilenameWithoutPath>
+ </File>
+ <File>
+ <GroupNumber>1</GroupNumber>
+ <FileNumber>10</FileNumber>
+ <FileType>1</FileType>
+ <tvExp>0</tvExp>
+ <Focus>0</Focus>
+ <ColumnNumber>0</ColumnNumber>
+ <tvExpOptDlg>0</tvExpOptDlg>
+ <TopLine>0</TopLine>
+ <CurrentLine>0</CurrentLine>
+ <bDave2>0</bDave2>
+ <PathWithFileName>.\l3gd20h.c</PathWithFileName>
+ <FilenameWithoutPath>l3gd20h.c</FilenameWithoutPath>
+ </File>
+ <File>
+ <GroupNumber>1</GroupNumber>
+ <FileNumber>11</FileNumber>
+ <FileType>1</FileType>
+ <tvExp>0</tvExp>
+ <Focus>0</Focus>
+ <ColumnNumber>0</ColumnNumber>
+ <tvExpOptDlg>0</tvExpOptDlg>
+ <TopLine>0</TopLine>
+ <CurrentLine>0</CurrentLine>
+ <bDave2>0</bDave2>
+ <PathWithFileName>.\lsm303d.c</PathWithFileName>
+ <FilenameWithoutPath>lsm303d.c</FilenameWithoutPath>
+ </File>
+ <File>
+ <GroupNumber>1</GroupNumber>
+ <FileNumber>12</FileNumber>
+ <FileType>1</FileType>
+ <tvExp>0</tvExp>
+ <Focus>0</Focus>
+ <ColumnNumber>0</ColumnNumber>
+ <tvExpOptDlg>0</tvExpOptDlg>
+ <TopLine>0</TopLine>
+ <CurrentLine>0</CurrentLine>
+ <bDave2>0</bDave2>
+ <PathWithFileName>.\lsm303dlhc_accel.c</PathWithFileName>
+ <FilenameWithoutPath>lsm303dlhc_accel.c</FilenameWithoutPath>
+ </File>
+ <File>
+ <GroupNumber>1</GroupNumber>
+ <FileNumber>13</FileNumber>
+ <FileType>1</FileType>
+ <tvExp>0</tvExp>
+ <Focus>0</Focus>
+ <ColumnNumber>0</ColumnNumber>
+ <tvExpOptDlg>0</tvExpOptDlg>
+ <TopLine>0</TopLine>
+ <CurrentLine>0</CurrentLine>
+ <bDave2>0</bDave2>
+ <PathWithFileName>.\lsm303dlhc_mag.c</PathWithFileName>
+ <FilenameWithoutPath>lsm303dlhc_mag.c</FilenameWithoutPath>
+ </File>
+ <File>
+ <GroupNumber>1</GroupNumber>
+ <FileNumber>14</FileNumber>
+ <FileType>1</FileType>
+ <tvExp>0</tvExp>
+ <Focus>0</Focus>
+ <ColumnNumber>0</ColumnNumber>
+ <tvExpOptDlg>0</tvExpOptDlg>
+ <TopLine>0</TopLine>
+ <CurrentLine>0</CurrentLine>
+ <bDave2>0</bDave2>
+ <PathWithFileName>.\magneto.c</PathWithFileName>
+ <FilenameWithoutPath>magneto.c</FilenameWithoutPath>
+ </File>
+ <File>
+ <GroupNumber>1</GroupNumber>
+ <FileNumber>15</FileNumber>
+ <FileType>1</FileType>
+ <tvExp>0</tvExp>
+ <Focus>0</Focus>
+ <ColumnNumber>0</ColumnNumber>
+ <tvExpOptDlg>0</tvExpOptDlg>
+ <TopLine>0</TopLine>
+ <CurrentLine>0</CurrentLine>
+ <bDave2>0</bDave2>
+ <PathWithFileName>.\mpu6050.c</PathWithFileName>
+ <FilenameWithoutPath>mpu6050.c</FilenameWithoutPath>
+ </File>
+ <File>
+ <GroupNumber>1</GroupNumber>
+ <FileNumber>16</FileNumber>
+ <FileType>1</FileType>
+ <tvExp>0</tvExp>
+ <Focus>0</Focus>
+ <ColumnNumber>0</ColumnNumber>
+ <tvExpOptDlg>0</tvExpOptDlg>
+ <TopLine>0</TopLine>
+ <CurrentLine>0</CurrentLine>
+ <bDave2>0</bDave2>
+ <PathWithFileName>.\mpu9150.c</PathWithFileName>
+ <FilenameWithoutPath>mpu9150.c</FilenameWithoutPath>
+ </File>
+ <File>
+ <GroupNumber>1</GroupNumber>
+ <FileNumber>17</FileNumber>
+ <FileType>1</FileType>
+ <tvExp>0</tvExp>
+ <Focus>0</Focus>
+ <ColumnNumber>0</ColumnNumber>
+ <tvExpOptDlg>0</tvExpOptDlg>
+ <TopLine>0</TopLine>
+ <CurrentLine>0</CurrentLine>
+ <bDave2>0</bDave2>
+ <PathWithFileName>.\quaternion.c</PathWithFileName>
+ <FilenameWithoutPath>quaternion.c</FilenameWithoutPath>
+ </File>
+ <File>
+ <GroupNumber>1</GroupNumber>
+ <FileNumber>18</FileNumber>
+ <FileType>1</FileType>
+ <tvExp>0</tvExp>
+ <Focus>0</Focus>
+ <ColumnNumber>0</ColumnNumber>
+ <tvExpOptDlg>0</tvExpOptDlg>
+ <TopLine>0</TopLine>
+ <CurrentLine>0</CurrentLine>
+ <bDave2>0</bDave2>
+ <PathWithFileName>.\sht21.c</PathWithFileName>
+ <FilenameWithoutPath>sht21.c</FilenameWithoutPath>
+ </File>
+ <File>
+ <GroupNumber>1</GroupNumber>
+ <FileNumber>19</FileNumber>
+ <FileType>1</FileType>
+ <tvExp>0</tvExp>
+ <Focus>0</Focus>
+ <ColumnNumber>0</ColumnNumber>
+ <tvExpOptDlg>0</tvExpOptDlg>
+ <TopLine>0</TopLine>
+ <CurrentLine>0</CurrentLine>
+ <bDave2>0</bDave2>
+ <PathWithFileName>.\tmp006.c</PathWithFileName>
+ <FilenameWithoutPath>tmp006.c</FilenameWithoutPath>
+ </File>
+ <File>
+ <GroupNumber>1</GroupNumber>
+ <FileNumber>20</FileNumber>
+ <FileType>1</FileType>
+ <tvExp>0</tvExp>
+ <Focus>0</Focus>
+ <ColumnNumber>0</ColumnNumber>
+ <tvExpOptDlg>0</tvExpOptDlg>
+ <TopLine>0</TopLine>
+ <CurrentLine>0</CurrentLine>
+ <bDave2>0</bDave2>
+ <PathWithFileName>.\tmp100.c</PathWithFileName>
+ <FilenameWithoutPath>tmp100.c</FilenameWithoutPath>
+ </File>
+ <File>
+ <GroupNumber>1</GroupNumber>
+ <FileNumber>21</FileNumber>
+ <FileType>1</FileType>
+ <tvExp>0</tvExp>
+ <Focus>0</Focus>
+ <ColumnNumber>0</ColumnNumber>
+ <tvExpOptDlg>0</tvExpOptDlg>
+ <TopLine>0</TopLine>
+ <CurrentLine>0</CurrentLine>
+ <bDave2>0</bDave2>
+ <PathWithFileName>.\vector.c</PathWithFileName>
+ <FilenameWithoutPath>vector.c</FilenameWithoutPath>
+ </File>
+ </Group>
+
+ <Group>
+ <GroupName>Documentation</GroupName>
+ <tvExp>1</tvExp>
+ <tvExpOptDlg>0</tvExpOptDlg>
+ <cbSel>0</cbSel>
+ <File>
+ <GroupNumber>2</GroupNumber>
+ <FileNumber>22</FileNumber>
+ <FileType>5</FileType>
+ <tvExp>0</tvExp>
+ <Focus>1</Focus>
+ <ColumnNumber>0</ColumnNumber>
+ <tvExpOptDlg>0</tvExpOptDlg>
+ <TopLine>1</TopLine>
+ <CurrentLine>1</CurrentLine>
+ <bDave2>0</bDave2>
+ <PathWithFileName>.\readme.txt</PathWithFileName>
+ <FilenameWithoutPath>readme.txt</FilenameWithoutPath>
+ <WindowPosition>
+ <length>44</length>
+ <flags>0</flags>
+ <showCmd>1</showCmd>
+ <MinPosition>
+ <xPos>-1</xPos>
+ <yPos>-1</yPos>
+ </MinPosition>
+ <MaxPosition>
+ <xPos>-1</xPos>
+ <yPos>-1</yPos>
+ </MaxPosition>
+ <NormalPosition>
+ <Top>0</Top>
+ <Left>0</Left>
+ <Right>729</Right>
+ <Bottom>300</Bottom>
+ </NormalPosition>
+ </WindowPosition>
+ </File>
+ </Group>
+
+ <MDIGroups>
+ <Orientation>1</Orientation>
+ <ActiveMDIGroup>0</ActiveMDIGroup>
+ <MDIGroup>
+ <Size>100</Size>
+ <ActiveTab>0</ActiveTab>
+ <Documents>
+ <Doc>
+ <Name>.\readme.txt</Name>
+ <ColumnNumber>0</ColumnNumber>
+ <TopLine>1</TopLine>
+ <CurrentLine>1</CurrentLine>
+ </Doc>
+ </Documents>
+ </MDIGroup>
+ </MDIGroups>
+
+</ProjectOpt>
diff --git a/sensorlib/sensorlib.uvproj b/sensorlib/sensorlib.uvproj
new file mode 100644
index 0000000..7d88e4c
--- /dev/null
+++ b/sensorlib/sensorlib.uvproj
@@ -0,0 +1,510 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
+<Project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="project_proj.xsd">
+
+ <SchemaVersion>1.1</SchemaVersion>
+
+ <Header>### uVision Project, (C) Keil Software</Header>
+
+ <Targets>
+ <Target>
+ <TargetName>sensorlib</TargetName>
+ <ToolsetNumber>0x4</ToolsetNumber>
+ <ToolsetName>ARM-ADS</ToolsetName>
+ <TargetOption>
+ <TargetCommonOption>
+ <Device>TM4C1230C3PM</Device>
+ <Vendor>Texas Instruments</Vendor>
+ <Cpu>IRAM(0x20000000-0x20002FFF) IROM(0-0x7FFF) CLOCK(8000000) CPUTYPE("Cortex-M4") FPU2</Cpu>
+ <FlashUtilSpec></FlashUtilSpec>
+ <StartupFile>"STARTUP\Luminary\Startup.s" ("Luminary Startup Code")</StartupFile>
+ <FlashDriverDll>UL2CM3(-O207 -S0 -C0 -FO7 -FD20000000 -FC800 -FN1 -FF0LM4F_32 -FS00 -FL08000)</FlashDriverDll>
+ <DeviceId>5919</DeviceId>
+ <RegisterFile>LM4Fxxxx.H</RegisterFile>
+ <MemoryEnv></MemoryEnv>
+ <Cmp></Cmp>
+ <Asm></Asm>
+ <Linker></Linker>
+ <OHString></OHString>
+ <InfinionOptionDll></InfinionOptionDll>
+ <SLE66CMisc></SLE66CMisc>
+ <SLE66AMisc></SLE66AMisc>
+ <SLE66LinkerMisc></SLE66LinkerMisc>
+ <SFDFile>SFD\Luminary\TM4C1230C3PM.SFR</SFDFile>
+ <UseEnv>0</UseEnv>
+ <BinPath></BinPath>
+ <IncludePath></IncludePath>
+ <LibPath></LibPath>
+ <RegisterFilePath>Luminary\</RegisterFilePath>
+ <DBRegisterFilePath>Luminary\</DBRegisterFilePath>
+ <TargetStatus>
+ <Error>0</Error>
+ <ExitCodeStop>0</ExitCodeStop>
+ <ButtonStop>0</ButtonStop>
+ <NotGenerated>0</NotGenerated>
+ <InvalidFlash>1</InvalidFlash>
+ </TargetStatus>
+ <OutputDirectory>.\rvmdk\</OutputDirectory>
+ <OutputName>sensorlib</OutputName>
+ <CreateExecutable>0</CreateExecutable>
+ <CreateLib>1</CreateLib>
+ <CreateHexFile>0</CreateHexFile>
+ <DebugInformation>1</DebugInformation>
+ <BrowseInformation>1</BrowseInformation>
+ <ListingPath>.\rvmdk\</ListingPath>
+ <HexFormatSelection>1</HexFormatSelection>
+ <Merge32K>0</Merge32K>
+ <CreateBatchFile>0</CreateBatchFile>
+ <BeforeCompile>
+ <RunUserProg1>0</RunUserProg1>
+ <RunUserProg2>0</RunUserProg2>
+ <UserProg1Name></UserProg1Name>
+ <UserProg2Name></UserProg2Name>
+ <UserProg1Dos16Mode>0</UserProg1Dos16Mode>
+ <UserProg2Dos16Mode>0</UserProg2Dos16Mode>
+ </BeforeCompile>
+ <BeforeMake>
+ <RunUserProg1>0</RunUserProg1>
+ <RunUserProg2>0</RunUserProg2>
+ <UserProg1Name></UserProg1Name>
+ <UserProg2Name></UserProg2Name>
+ <UserProg1Dos16Mode>0</UserProg1Dos16Mode>
+ <UserProg2Dos16Mode>0</UserProg2Dos16Mode>
+ </BeforeMake>
+ <AfterMake>
+ <RunUserProg1>0</RunUserProg1>
+ <RunUserProg2>0</RunUserProg2>
+ <UserProg1Name></UserProg1Name>
+ <UserProg2Name></UserProg2Name>
+ <UserProg1Dos16Mode>0</UserProg1Dos16Mode>
+ <UserProg2Dos16Mode>0</UserProg2Dos16Mode>
+ </AfterMake>
+ <SelectedForBatchBuild>0</SelectedForBatchBuild>
+ <SVCSIdString></SVCSIdString>
+ </TargetCommonOption>
+ <CommonProperty>
+ <UseCPPCompiler>0</UseCPPCompiler>
+ <RVCTCodeConst>0</RVCTCodeConst>
+ <RVCTZI>0</RVCTZI>
+ <RVCTOtherData>0</RVCTOtherData>
+ <ModuleSelection>0</ModuleSelection>
+ <IncludeInBuild>1</IncludeInBuild>
+ <AlwaysBuild>0</AlwaysBuild>
+ <GenerateAssemblyFile>0</GenerateAssemblyFile>
+ <AssembleAssemblyFile>0</AssembleAssemblyFile>
+ <PublicsOnly>0</PublicsOnly>
+ <StopOnExitCode>3</StopOnExitCode>
+ <CustomArgument></CustomArgument>
+ <IncludeLibraryModules></IncludeLibraryModules>
+ </CommonProperty>
+ <DllOption>
+ <SimDllName>SARMCM3.DLL</SimDllName>
+ <SimDllArguments>-MPU</SimDllArguments>
+ <SimDlgDll>DCM.DLL</SimDlgDll>
+ <SimDlgDllArguments>-pCM4</SimDlgDllArguments>
+ <TargetDllName>SARMCM3.DLL</TargetDllName>
+ <TargetDllArguments>-MPU</TargetDllArguments>
+ <TargetDlgDll>TCM.DLL</TargetDlgDll>
+ <TargetDlgDllArguments>-pCM4</TargetDlgDllArguments>
+ </DllOption>
+ <DebugOption>
+ <OPTHX>
+ <HexSelection>1</HexSelection>
+ <HexRangeLowAddress>0</HexRangeLowAddress>
+ <HexRangeHighAddress>0</HexRangeHighAddress>
+ <HexOffset>0</HexOffset>
+ <Oh166RecLen>16</Oh166RecLen>
+ </OPTHX>
+ <Simulator>
+ <UseSimulator>1</UseSimulator>
+ <LoadApplicationAtStartup>1</LoadApplicationAtStartup>
+ <RunToMain>1</RunToMain>
+ <RestoreBreakpoints>1</RestoreBreakpoints>
+ <RestoreWatchpoints>1</RestoreWatchpoints>
+ <RestoreMemoryDisplay>1</RestoreMemoryDisplay>
+ <RestoreFunctions>1</RestoreFunctions>
+ <RestoreToolbox>1</RestoreToolbox>
+ <LimitSpeedToRealTime>0</LimitSpeedToRealTime>
+ </Simulator>
+ <Target>
+ <UseTarget>0</UseTarget>
+ <LoadApplicationAtStartup>1</LoadApplicationAtStartup>
+ <RunToMain>0</RunToMain>
+ <RestoreBreakpoints>1</RestoreBreakpoints>
+ <RestoreWatchpoints>1</RestoreWatchpoints>
+ <RestoreMemoryDisplay>1</RestoreMemoryDisplay>
+ <RestoreFunctions>0</RestoreFunctions>
+ <RestoreToolbox>1</RestoreToolbox>
+ </Target>
+ <RunDebugAfterBuild>0</RunDebugAfterBuild>
+ <TargetSelection>3</TargetSelection>
+ <SimDlls>
+ <CpuDll></CpuDll>
+ <CpuDllArguments></CpuDllArguments>
+ <PeripheralDll></PeripheralDll>
+ <PeripheralDllArguments></PeripheralDllArguments>
+ <InitializationFile></InitializationFile>
+ </SimDlls>
+ <TargetDlls>
+ <CpuDll></CpuDll>
+ <CpuDllArguments></CpuDllArguments>
+ <PeripheralDll></PeripheralDll>
+ <PeripheralDllArguments></PeripheralDllArguments>
+ <InitializationFile></InitializationFile>
+ <Driver>BIN\lmidk-agdi.dll</Driver>
+ </TargetDlls>
+ </DebugOption>
+ <Utilities>
+ <Flash1>
+ <UseTargetDll>1</UseTargetDll>
+ <UseExternalTool>0</UseExternalTool>
+ <RunIndependent>0</RunIndependent>
+ <UpdateFlashBeforeDebugging>0</UpdateFlashBeforeDebugging>
+ <Capability>1</Capability>
+ <DriverSelection>4097</DriverSelection>
+ </Flash1>
+ <Flash2>BIN\lmidk-agdi.dll</Flash2>
+ <Flash3></Flash3>
+ <Flash4></Flash4>
+ </Utilities>
+ <TargetArmAds>
+ <ArmAdsMisc>
+ <GenerateListings>0</GenerateListings>
+ <asHll>1</asHll>
+ <asAsm>1</asAsm>
+ <asMacX>1</asMacX>
+ <asSyms>1</asSyms>
+ <asFals>1</asFals>
+ <asDbgD>1</asDbgD>
+ <asForm>1</asForm>
+ <ldLst>0</ldLst>
+ <ldmm>1</ldmm>
+ <ldXref>1</ldXref>
+ <BigEnd>0</BigEnd>
+ <AdsALst>0</AdsALst>
+ <AdsACrf>0</AdsACrf>
+ <AdsANop>0</AdsANop>
+ <AdsANot>0</AdsANot>
+ <AdsLLst>0</AdsLLst>
+ <AdsLmap>0</AdsLmap>
+ <AdsLcgr>0</AdsLcgr>
+ <AdsLsym>0</AdsLsym>
+ <AdsLszi>0</AdsLszi>
+ <AdsLtoi>0</AdsLtoi>
+ <AdsLsun>0</AdsLsun>
+ <AdsLven>0</AdsLven>
+ <AdsLsxf>0</AdsLsxf>
+ <RvctClst>0</RvctClst>
+ <GenPPlst>0</GenPPlst>
+ <AdsCpuType>"Cortex-M4"</AdsCpuType>
+ <RvctDeviceName></RvctDeviceName>
+ <mOS>0</mOS>
+ <uocRom>0</uocRom>
+ <uocRam>0</uocRam>
+ <hadIROM>1</hadIROM>
+ <hadIRAM>1</hadIRAM>
+ <hadXRAM>0</hadXRAM>
+ <uocXRam>0</uocXRam>
+ <RvdsVP>2</RvdsVP>
+ <hadIRAM2>0</hadIRAM2>
+ <hadIROM2>0</hadIROM2>
+ <StupSel>8</StupSel>
+ <useUlib>1</useUlib>
+ <EndSel>0</EndSel>
+ <uLtcg>0</uLtcg>
+ <RoSelD>3</RoSelD>
+ <RwSelD>3</RwSelD>
+ <CodeSel>0</CodeSel>
+ <OptFeed>0</OptFeed>
+ <NoZi1>0</NoZi1>
+ <NoZi2>0</NoZi2>
+ <NoZi3>0</NoZi3>
+ <NoZi4>0</NoZi4>
+ <NoZi5>0</NoZi5>
+ <Ro1Chk>0</Ro1Chk>
+ <Ro2Chk>0</Ro2Chk>
+ <Ro3Chk>0</Ro3Chk>
+ <Ir1Chk>1</Ir1Chk>
+ <Ir2Chk>0</Ir2Chk>
+ <Ra1Chk>0</Ra1Chk>
+ <Ra2Chk>0</Ra2Chk>
+ <Ra3Chk>0</Ra3Chk>
+ <Im1Chk>1</Im1Chk>
+ <Im2Chk>0</Im2Chk>
+ <OnChipMemories>
+ <Ocm1>
+ <Type>0</Type>
+ <StartAddress>0x0</StartAddress>
+ <Size>0x0</Size>
+ </Ocm1>
+ <Ocm2>
+ <Type>0</Type>
+ <StartAddress>0x0</StartAddress>
+ <Size>0x0</Size>
+ </Ocm2>
+ <Ocm3>
+ <Type>0</Type>
+ <StartAddress>0x0</StartAddress>
+ <Size>0x0</Size>
+ </Ocm3>
+ <Ocm4>
+ <Type>0</Type>
+ <StartAddress>0x0</StartAddress>
+ <Size>0x0</Size>
+ </Ocm4>
+ <Ocm5>
+ <Type>0</Type>
+ <StartAddress>0x0</StartAddress>
+ <Size>0x0</Size>
+ </Ocm5>
+ <Ocm6>
+ <Type>0</Type>
+ <StartAddress>0x0</StartAddress>
+ <Size>0x0</Size>
+ </Ocm6>
+ <IRAM>
+ <Type>0</Type>
+ <StartAddress>0x20000000</StartAddress>
+ <Size>0x3000</Size>
+ </IRAM>
+ <IROM>
+ <Type>1</Type>
+ <StartAddress>0x0</StartAddress>
+ <Size>0x8000</Size>
+ </IROM>
+ <XRAM>
+ <Type>0</Type>
+ <StartAddress>0x0</StartAddress>
+ <Size>0x0</Size>
+ </XRAM>
+ <OCR_RVCT1>
+ <Type>1</Type>
+ <StartAddress>0x0</StartAddress>
+ <Size>0x0</Size>
+ </OCR_RVCT1>
+ <OCR_RVCT2>
+ <Type>1</Type>
+ <StartAddress>0x0</StartAddress>
+ <Size>0x0</Size>
+ </OCR_RVCT2>
+ <OCR_RVCT3>
+ <Type>1</Type>
+ <StartAddress>0x0</StartAddress>
+ <Size>0x0</Size>
+ </OCR_RVCT3>
+ <OCR_RVCT4>
+ <Type>1</Type>
+ <StartAddress>0x0</StartAddress>
+ <Size>0x8000</Size>
+ </OCR_RVCT4>
+ <OCR_RVCT5>
+ <Type>1</Type>
+ <StartAddress>0x0</StartAddress>
+ <Size>0x0</Size>
+ </OCR_RVCT5>
+ <OCR_RVCT6>
+ <Type>0</Type>
+ <StartAddress>0x0</StartAddress>
+ <Size>0x0</Size>
+ </OCR_RVCT6>
+ <OCR_RVCT7>
+ <Type>0</Type>
+ <StartAddress>0x0</StartAddress>
+ <Size>0x0</Size>
+ </OCR_RVCT7>
+ <OCR_RVCT8>
+ <Type>0</Type>
+ <StartAddress>0x0</StartAddress>
+ <Size>0x0</Size>
+ </OCR_RVCT8>
+ <OCR_RVCT9>
+ <Type>0</Type>
+ <StartAddress>0x20000000</StartAddress>
+ <Size>0x3000</Size>
+ </OCR_RVCT9>
+ <OCR_RVCT10>
+ <Type>0</Type>
+ <StartAddress>0x0</StartAddress>
+ <Size>0x0</Size>
+ </OCR_RVCT10>
+ </OnChipMemories>
+ <RvctStartVector></RvctStartVector>
+ </ArmAdsMisc>
+ <Cads>
+ <interw>0</interw>
+ <Optim>3</Optim>
+ <oTime>1</oTime>
+ <SplitLS>0</SplitLS>
+ <OneElfS>1</OneElfS>
+ <Strict>0</Strict>
+ <EnumInt>0</EnumInt>
+ <PlainCh>0</PlainCh>
+ <Ropi>0</Ropi>
+ <Rwpi>0</Rwpi>
+ <wLevel>2</wLevel>
+ <uThumb>0</uThumb>
+ <VariousControls>
+ <MiscControls>--c99</MiscControls>
+ <Define>rvmdk </Define>
+ <Undefine></Undefine>
+ <IncludePath>..;</IncludePath>
+ </VariousControls>
+ </Cads>
+ <Aads>
+ <interw>1</interw>
+ <Ropi>0</Ropi>
+ <Rwpi>0</Rwpi>
+ <thumb>0</thumb>
+ <SplitLS>0</SplitLS>
+ <SwStkChk>0</SwStkChk>
+ <NoWarn>0</NoWarn>
+ <VariousControls>
+ <MiscControls></MiscControls>
+ <Define></Define>
+ <Undefine></Undefine>
+ <IncludePath></IncludePath>
+ </VariousControls>
+ </Aads>
+ <LDads>
+ <umfTarg>0</umfTarg>
+ <Ropi>0</Ropi>
+ <Rwpi>0</Rwpi>
+ <noStLib>0</noStLib>
+ <RepFail>1</RepFail>
+ <useFile>0</useFile>
+ <TextAddressRange>0x00000000</TextAddressRange>
+ <DataAddressRange>0x20000000</DataAddressRange>
+ <ScatterFile></ScatterFile>
+ <IncludeLibs></IncludeLibs>
+ <IncludeLibsPath></IncludeLibsPath>
+ <Misc></Misc>
+ <LinkerInputFile></LinkerInputFile>
+ <DisabledWarnings></DisabledWarnings>
+ </LDads>
+ </TargetArmAds>
+ </TargetOption>
+ <Groups>
+ <Group>
+ <GroupName>Source</GroupName>
+ <Files>
+ <File>
+ <FileName>ak8963.c</FileName>
+ <FileType>1</FileType>
+ <FilePath>.\ak8963.c</FilePath>
+ </File>
+ <File>
+ <FileName>ak8975.c</FileName>
+ <FileType>1</FileType>
+ <FilePath>.\ak8975.c</FilePath>
+ </File>
+ <File>
+ <FileName>bmp180.c</FileName>
+ <FileType>1</FileType>
+ <FilePath>.\bmp180.c</FilePath>
+ </File>
+ <File>
+ <FileName>bq27510g3.c</FileName>
+ <FileType>1</FileType>
+ <FilePath>.\bq27510g3.c</FilePath>
+ </File>
+ <File>
+ <FileName>cm3218.c</FileName>
+ <FileType>1</FileType>
+ <FilePath>.\cm3218.c</FilePath>
+ </File>
+ <File>
+ <FileName>comp_dcm.c</FileName>
+ <FileType>1</FileType>
+ <FilePath>.\comp_dcm.c</FilePath>
+ </File>
+ <File>
+ <FileName>i2cm_drv.c</FileName>
+ <FileType>1</FileType>
+ <FilePath>.\i2cm_drv.c</FilePath>
+ </File>
+ <File>
+ <FileName>isl29023.c</FileName>
+ <FileType>1</FileType>
+ <FilePath>.\isl29023.c</FilePath>
+ </File>
+ <File>
+ <FileName>kxti9.c</FileName>
+ <FileType>1</FileType>
+ <FilePath>.\kxti9.c</FilePath>
+ </File>
+ <File>
+ <FileName>l3gd20h.c</FileName>
+ <FileType>1</FileType>
+ <FilePath>.\l3gd20h.c</FilePath>
+ </File>
+ <File>
+ <FileName>lsm303d.c</FileName>
+ <FileType>1</FileType>
+ <FilePath>.\lsm303d.c</FilePath>
+ </File>
+ <File>
+ <FileName>lsm303dlhc_accel.c</FileName>
+ <FileType>1</FileType>
+ <FilePath>.\lsm303dlhc_accel.c</FilePath>
+ </File>
+ <File>
+ <FileName>lsm303dlhc_mag.c</FileName>
+ <FileType>1</FileType>
+ <FilePath>.\lsm303dlhc_mag.c</FilePath>
+ </File>
+ <File>
+ <FileName>magneto.c</FileName>
+ <FileType>1</FileType>
+ <FilePath>.\magneto.c</FilePath>
+ </File>
+ <File>
+ <FileName>mpu6050.c</FileName>
+ <FileType>1</FileType>
+ <FilePath>.\mpu6050.c</FilePath>
+ </File>
+ <File>
+ <FileName>mpu9150.c</FileName>
+ <FileType>1</FileType>
+ <FilePath>.\mpu9150.c</FilePath>
+ </File>
+ <File>
+ <FileName>quaternion.c</FileName>
+ <FileType>1</FileType>
+ <FilePath>.\quaternion.c</FilePath>
+ </File>
+ <File>
+ <FileName>sht21.c</FileName>
+ <FileType>1</FileType>
+ <FilePath>.\sht21.c</FilePath>
+ </File>
+ <File>
+ <FileName>tmp006.c</FileName>
+ <FileType>1</FileType>
+ <FilePath>.\tmp006.c</FilePath>
+ </File>
+ <File>
+ <FileName>tmp100.c</FileName>
+ <FileType>1</FileType>
+ <FilePath>.\tmp100.c</FilePath>
+ </File>
+ <File>
+ <FileName>vector.c</FileName>
+ <FileType>1</FileType>
+ <FilePath>.\vector.c</FilePath>
+ </File>
+ </Files>
+ </Group>
+ <Group>
+ <GroupName>Documentation</GroupName>
+ <Files>
+ <File>
+ <FileName>readme.txt</FileName>
+ <FileType>5</FileType>
+ <FilePath>.\readme.txt</FilePath>
+ </File>
+ </Files>
+ </Group>
+ </Groups>
+ </Target>
+ </Targets>
+
+</Project>
diff --git a/sensorlib/sht21.c b/sensorlib/sht21.c
new file mode 100644
index 0000000..0698593
--- /dev/null
+++ b/sensorlib/sht21.c
@@ -0,0 +1,564 @@
+//*****************************************************************************
+//
+// sht21.c - Driver for the SHT21 accelerometer.
+//
+// Copyright (c) 2013-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
+//
+//*****************************************************************************
+
+#include <stdint.h>
+#include "sensorlib/hw_sht21.h"
+#include "sensorlib/i2cm_drv.h"
+#include "sensorlib/sht21.h"
+
+//*****************************************************************************
+//
+//! \addtogroup sht21_api
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// The states of the SHT21 state machine.
+//
+//*****************************************************************************
+#define SHT21_STATE_IDLE 0 // State machine is idle
+#define SHT21_STATE_INIT 1 // Waiting for initialization
+#define SHT21_STATE_READ 2 // Waiting for register read
+#define SHT21_STATE_WRITE 3 // Waiting for register write
+#define SHT21_STATE_RMW 4
+#define SHT21_STATE_READ_DATA 5 // Waiting for temperature or
+ // humidity data
+
+//*****************************************************************************
+//
+// The callback function that is called when I2C transactions to/from the
+// SHT21 have completed.
+//
+//*****************************************************************************
+static void
+SHT21Callback(void *pvCallbackData, uint_fast8_t ui8Status)
+{
+ tSHT21 *psInst;
+
+ //
+ // Convert the instance data into a pointer to a tSHT221 structure.
+ //
+ psInst = (tSHT21 *)pvCallbackData;
+
+ //
+ // If the I2C master driver encountered a failure, force the state machine
+ // to the idle state (which will also result in a callback to propagate the
+ // error).
+ //
+ if(ui8Status != I2CM_STATUS_SUCCESS)
+ {
+ psInst->ui8State = SHT21_STATE_IDLE;
+ }
+
+ //
+ // Determine the current state of the SHT21 state machine.
+ //
+ switch(psInst->ui8State)
+ {
+ //
+ // All states that trivially transition to IDLE, and all unknown
+ // states.
+ //
+ case SHT21_STATE_INIT:
+ case SHT21_STATE_READ:
+ case SHT21_STATE_WRITE:
+ case SHT21_STATE_READ_DATA:
+ case SHT21_STATE_RMW:
+ default:
+ {
+ //
+ // The state machine is now idle.
+ //
+ psInst->ui8State = SHT21_STATE_IDLE;
+
+ //
+ // Done.
+ //
+ break;
+ }
+ }
+
+ //
+ // See if the state machine is now idle and there is a callback function.
+ //
+ if((psInst->ui8State == SHT21_STATE_IDLE) && psInst->pfnCallback)
+ {
+ //
+ // Call the application-supplied callback function.
+ //
+ psInst->pfnCallback(psInst->pvCallbackData, ui8Status);
+ }
+}
+
+//*****************************************************************************
+//
+//! Initializes the SHT21 driver.
+//!
+//! \param psInst is a pointer to the SHT21 instance data.
+//! \param psI2CInst is a pointer to the I2C driver instance data.
+//! \param ui8I2CAddr is the I2C address of the SHT21 device.
+//! \param pfnCallback is the function to be called when the initialization has
+//! completed (can be \b NULL if a callback is not required).
+//! \param pvCallbackData is a pointer that is passed to the callback function.
+//!
+//! This function initializes the SHT21 driver, preparing it for operation, and
+//! initiates a reset of the SHT21 device, clearing any previous configuration
+//! data.
+//!
+//! \return Returns 1 if the SHT21 driver was successfully initialized and 0 if
+//! it was not.
+//
+//*****************************************************************************
+uint_fast8_t
+SHT21Init(tSHT21 *psInst, tI2CMInstance *psI2CInst, uint_fast8_t ui8I2CAddr,
+ tSensorCallback *pfnCallback, void *pvCallbackData)
+{
+ //
+ // Initialize the SHT21 instance structure.
+ //
+ psInst->psI2CInst = psI2CInst;
+ psInst->ui8Addr = ui8I2CAddr;
+ psInst->ui8State = SHT21_STATE_INIT;
+
+ //
+ // Save the callback information.
+ //
+ psInst->pfnCallback = pfnCallback;
+ psInst->pvCallbackData = pvCallbackData;
+
+ //
+ // Perform a soft reset of the SHT21.
+ //
+ psInst->pui8Data[0] = SHT21_CMD_SOFT_RESET;
+ if(I2CMWrite(psInst->psI2CInst, ui8I2CAddr, psInst->pui8Data, 1,
+ SHT21Callback, psInst) == 0)
+ {
+ //
+ // The I2C write failed, so move to the idle state and return a
+ // failure.
+ //
+ psInst->ui8State = SHT21_STATE_IDLE;
+ return(0);
+ }
+
+ //
+ // Success
+ //
+ return(1);
+}
+
+//*****************************************************************************
+//
+//! Reads data from SHT21 registers.
+//!
+//! \param psInst is a pointer to the SHT21 instance data.
+//! \param ui8Reg is the first register to read.
+//! \param pui8Data is a pointer to the location to store the data that is
+//! read.
+//! \param ui16Count the number of data bytes to read.
+//! \param pfnCallback is the function to be called when the data has been read
+//! (can be \b NULL if a callback is not required).
+//! \param pvCallbackData pointer that is passed to the callback function.
+//!
+//! This function reads a sequence of data values from consecutive registers in
+//! the SHT21.
+//!
+//! \return Returns 1 if the read was successfully started and 0 if it was not.
+//
+//*****************************************************************************
+uint_fast8_t
+SHT21Read(tSHT21 *psInst, uint_fast8_t ui8Reg, uint8_t *pui8Data,
+ uint_fast16_t ui16Count, tSensorCallback *pfnCallback,
+ void *pvCallbackData)
+{
+ //
+ // Return a failure if the SHT21 driver is not idle (in other words, there
+ // is already an outstanding request to the SHT21).
+ //
+ if(psInst->ui8State != SHT21_STATE_IDLE)
+ {
+ return(0);
+ }
+
+ //
+ // Save the callback information.
+ //
+ psInst->pfnCallback = pfnCallback;
+ psInst->pvCallbackData = pvCallbackData;
+
+ //
+ // Move the state machine to the wait for read state.
+ //
+ psInst->ui8State = SHT21_STATE_READ;
+
+ //
+ // Read the requested registers from the SHT21.
+ //
+ psInst->uCommand.pui8Buffer[0] = ui8Reg;
+ if(I2CMRead(psInst->psI2CInst, psInst->ui8Addr,
+ psInst->uCommand.pui8Buffer, 1, pui8Data, ui16Count,
+ SHT21Callback, (void *)psInst) == 0)
+ {
+ //
+ // The I2C write failed, so move to the idle state and return a
+ // failure.
+ //
+ psInst->ui8State = SHT21_STATE_IDLE;
+ return(0);
+ }
+
+ //
+ // Success.
+ //
+ return(1);
+}
+
+//*****************************************************************************
+//
+//! Writes data to SHT21 registers.
+//!
+//! \param psInst is a pointer to the SHT21 instance data.
+//! \param ui8Reg is the register offset to be written.
+//! \param pui8Data is the data buffer bytes to write.
+//! \param ui16Count is the number of bytes to write.
+//! \param pfnCallback is the function to be called when the data has been
+//! written (can be \b NULL if a callback is not required).
+//! \param pvCallbackData is a pointer that is passed to the callback function.
+//!
+//! This function writes a sequence of data values to consecutive registers in
+//! the SHT21. The first byte of the \e pui8Data buffer contains the value to
+//! be written into the \e ui8Reg register, the second value contains the data
+//! to be written into the next register, and so on.
+//!
+//! \return Returns 1 if the write was successfully started and 0 if it was
+//! not.
+//
+//*****************************************************************************
+uint_fast8_t
+SHT21Write(tSHT21 *psInst, uint_fast8_t ui8Reg, const uint8_t *pui8Data,
+ uint_fast16_t ui16Count, tSensorCallback *pfnCallback,
+ void *pvCallbackData)
+{
+ //
+ // Return a failure if the SHT21 driver is not idle (in other words, there
+ // is already an outstanding request to the SHT21).
+ //
+ if(psInst->ui8State != SHT21_STATE_IDLE)
+ {
+ return(0);
+ }
+
+ //
+ // Save the callback information.
+ //
+ psInst->pfnCallback = pfnCallback;
+ psInst->pvCallbackData = pvCallbackData;
+
+ //
+ // Move the state machine to the wait for write state.
+ //
+ psInst->ui8State = SHT21_STATE_WRITE;
+
+ //
+ // Write the requested registers to the SHT21.
+ //
+ if(I2CMWrite8(&(psInst->uCommand.sWriteState), psInst->psI2CInst,
+ psInst->ui8Addr, ui8Reg, pui8Data, ui16Count, SHT21Callback,
+ psInst) == 0)
+ {
+ //
+ // The I2C write failed, so move to the idle state and return a
+ // failure.
+ //
+ psInst->ui8State = SHT21_STATE_IDLE;
+ return(0);
+ }
+
+ //
+ // Success.
+ //
+ return(1);
+}
+
+//*****************************************************************************
+//
+//! Performs a read-modify-write of a SHT21 register.
+//!
+//! \param psInst is a pointer to the SHT21 instance data.
+//! \param ui8Reg is the register to modify.
+//! \param ui8Mask is the bit mask that is ANDed with the current register
+//! value.
+//! \param ui8Value is the bit mask that is ORed with the result of the AND
+//! operation.
+//! \param pfnCallback is the function to be called when the data has been
+//! changed (can be \b NULL if a callback is not required).
+//! \param pvCallbackData is a pointer that is passed to the callback function.
+//!
+//! This function changes the value of a register in the SHT21 via a
+//! read-modify-write operation, allowing one of the fields to be changed
+//! without disturbing the other fields. The \e ui8Reg register is read, ANDed
+//! with \e ui8Mask, ORed with \e ui8Value, and then written back to the SHT21.
+//!
+//! \return Returns 1 if the read-modify-write was successfully started and 0
+//! if it was not.
+//
+//*****************************************************************************
+uint_fast8_t
+SHT21ReadModifyWrite(tSHT21 *psInst, uint_fast8_t ui8Reg, uint_fast8_t ui8Mask,
+ uint_fast8_t ui8Value, tSensorCallback *pfnCallback,
+ void *pvCallbackData)
+{
+ //
+ // Return a failure if the SHT21 driver is not idle (in other words, there
+ // is already an outstanding request to the SHT21).
+ //
+ if(psInst->ui8State != SHT21_STATE_IDLE)
+ {
+ return(0);
+ }
+
+ //
+ // Save the callback information.
+ //
+ psInst->pfnCallback = pfnCallback;
+ psInst->pvCallbackData = pvCallbackData;
+
+ //
+ // Move the state machine to the wait for read-modify-write state.
+ //
+ psInst->ui8State = SHT21_STATE_RMW;
+
+ //
+ // Submit the read-modify-write request to the TMP006.
+ //
+ if(I2CMReadModifyWrite8(&(psInst->uCommand.sReadModifyWriteState),
+ psInst->psI2CInst, psInst->ui8Addr, ui8Reg,
+ ui8Mask, ui8Value, SHT21Callback, psInst) == 0)
+ {
+ //
+ // The I2C read-modify-write failed, so move to the idle state and
+ // return a failure.
+ //
+ psInst->ui8State = SHT21_STATE_IDLE;
+ return(0);
+ }
+
+ //
+ // Success.
+ //
+ return(1);
+}
+
+//*****************************************************************************
+//
+//! Reads the temperature and humidity data from the SHT21.
+//!
+//! \param psInst is a pointer to the SHT21 instance data
+//! \param pfnCallback is the function to be called when the data has been read
+//! (can be \b NULL if a callback is not required).
+//! \param pvCallbackData is a pointer that is passed to the callback function.
+//!
+//! This function initiates a read of the SHT21 data registers. The user must
+//! first initiate a measurement by using the SHT21Write() function configured
+//! to write the command for a humidity or temperature measurement. In the
+//! case of a measurement with I2C bus hold, this function is not needed. When
+//! the read has completed (as indicated by callback function), the new
+//! readings can be obtained via:
+//!
+//! - SHT21DataTemperatureGetRaw()
+//! - SHT21DataTemperatureGetFloat()
+//! - SHT21DataHumidityGetRaw()
+//! - SHT21DataHumidityGetFloat()
+//!
+//! \return Returns 1 if the read was successfully started and 0 if it was not.
+//
+//*****************************************************************************
+uint_fast8_t
+SHT21DataRead(tSHT21 *psInst, tSensorCallback *pfnCallback,
+ void *pvCallbackData)
+{
+ //
+ // Return a failure if the SHT21 driver is not idle (in other words, there
+ // is already an outstanding request to the SHT21).
+ //
+ if(psInst->ui8State != SHT21_STATE_IDLE)
+ {
+ return(0);
+ }
+
+ //
+ // Save the callback information.
+ //
+ psInst->pfnCallback = pfnCallback;
+ psInst->pvCallbackData = pvCallbackData;
+
+ //
+ // Move the state machine to the wait for data read state.
+ //
+ psInst->ui8State = SHT21_STATE_READ_DATA;
+
+ //
+ // Read the data registers from the SHT21.
+ //
+ if(I2CMRead(psInst->psI2CInst, psInst->ui8Addr, 0, 0, psInst->pui8Data, 2,
+ SHT21Callback, psInst) == 0)
+ {
+ psInst->ui8State = SHT21_STATE_IDLE;
+ return(0);
+ }
+
+ //
+ // Success.
+ //
+ return(1);
+}
+
+//*****************************************************************************
+//
+//! Returns the raw temperature measurement as received from the SHT21.
+//!
+//! \param psInst is a pointer to the SHT21 instance data.
+//! \param pui16Temperature is a pointer to the value into which the raw
+//! temperature data is stored.
+//!
+//! This function returns the raw temperature data from the most recent data
+//! read. The data is not manipulated in any way by the driver.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SHT21DataTemperatureGetRaw(tSHT21 *psInst, uint16_t *pui16Temperature)
+{
+ //
+ // Return the raw temperature value.
+ //
+ *pui16Temperature = ((((uint16_t)psInst->pui8Data[0]) << 8) |
+ (uint16_t)psInst->pui8Data[1]);
+}
+
+//*****************************************************************************
+//
+//! Returns the most recent temperature measurement in floating point degrees
+//! Celsius.
+//!
+//! \param psInst is a pointer to the SHT21 instance data.
+//! \param pfTemperature is a pointer to the value into which the temperature
+//! data is stored.
+//!
+//! This function converts the raw temperature measurement data into floating
+//! point degrees Celsius and returns the result. See the SHT21 datasheet
+//! section 6.2 for more information about the conversion formula used.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SHT21DataTemperatureGetFloat(tSHT21 *psInst, float *pfTemperature)
+{
+ uint16_t ui16TemperatureRaw;
+
+ //
+ // Get the raw temperature into a floating point variable
+ //
+ SHT21DataTemperatureGetRaw(psInst, &ui16TemperatureRaw);
+ *pfTemperature = (float)(ui16TemperatureRaw & 0xFFFC);
+
+ //
+ // Equation from SHT21 datasheet for raw to Celsius conversion.
+ //
+ *pfTemperature = -46.85 + 175.72 * (*pfTemperature / 65536.0);
+}
+
+//*****************************************************************************
+//
+//! Returns the raw humidity measurement from the SHT21.
+//!
+//! \param psInst is a pointer to the SHT21 instance data.
+//! \param pui16Humidity is a pointer to the value into which the raw humidity
+//! data is stored.
+//!
+//! This function returns the raw humidity data from the most recent data read.
+//! The data is not manipulated in any way by the driver.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SHT21DataHumidityGetRaw(tSHT21 *psInst, uint16_t *pui16Humidity)
+{
+ //
+ // Return the raw humidity value.
+ //
+ *pui16Humidity = ((((uint16_t)psInst->pui8Data[0]) << 8) |
+ (uint16_t)psInst->pui8Data[1]);
+}
+
+//*****************************************************************************
+//
+//! Returns the relative humidity measurement as a floating point percentage.
+//!
+//! \param psInst pointer to the SHT21 instance data.
+//! \param pfHumidity is a pointer to the value into which the humidity data
+//! is stored.
+//!
+//! This function converts the raw humidity measurement to
+//! floating-point-percentage relative humidity over water. For more
+//! information on the conversion algorithm see the SHT21 datasheet section
+//! 6.1.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SHT21DataHumidityGetFloat(tSHT21 *psInst, float *pfHumidity)
+{
+ uint16_t ui16HumidityRaw;
+
+ //
+ // Convert the raw measure to float for later math.
+ //
+ SHT21DataHumidityGetRaw(psInst, &ui16HumidityRaw);
+ *pfHumidity = (float)(ui16HumidityRaw & 0xFFFC);
+
+ //
+ // Convert from raw measurement to percent relative humidity over water
+ // per the datasheet formula.
+ //
+ *pfHumidity = -6.0 + 125.0 * (*pfHumidity / 65536.0);
+
+ //
+ // Convert to a number from 0 to 1.0 instead of 0 to 100%.
+ //
+ *pfHumidity /= 100.0;
+}
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
diff --git a/sensorlib/sht21.h b/sensorlib/sht21.h
new file mode 100644
index 0000000..7956b0e
--- /dev/null
+++ b/sensorlib/sht21.h
@@ -0,0 +1,156 @@
+//*****************************************************************************
+//
+// sht21.h - Prototypes for the SHT21 accelerometer driver.
+//
+// Copyright (c) 2013-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
+//
+//*****************************************************************************
+
+#ifndef __SENSORLIB_SHT21_H__
+#define __SENSORLIB_SHT21_H__
+
+//*****************************************************************************
+//
+// If building with a C++ compiler, make all of the definitions in this header
+// have a C binding.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+//*****************************************************************************
+//
+// The structure that defines the internal state of the SHT21 driver.
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ // The pointer to the I2C master interface instance used to communicate
+ // with the SHT21.
+ //
+ tI2CMInstance *psI2CInst;
+
+ //
+ // the I2C address of the SHT21.
+ //
+ uint8_t ui8Addr;
+
+ //
+ // the state of the state machine used while accessing the
+ // SHT21.
+ //
+ uint8_t ui8State;
+
+ //
+ // the data buffer used for sending/receiving data to/from the
+ // SHT21.
+ //
+ uint8_t pui8Data[5];
+
+ //
+ // the 16 bit raw temperature reading
+ //
+ uint16_t ui16Temperature;
+
+ //
+ // the 16 bit raw humidity reading
+ //
+ uint16_t ui16Humidity;
+
+ //
+ // the function that is called when the current request has
+ // completed processing.
+ //
+ tSensorCallback *pfnCallback;
+
+ //
+ // the callback data provided to the callback function.
+ //
+ void *pvCallbackData;
+
+ //
+ // A union of structures that are used for read, write and
+ // read-modify-write operations. Since only one operation can be active at
+ // a time, it is safe to re-use the memory in this manner.
+ //
+ union
+ {
+ //
+ // A buffer used to store the write portion of a register read.
+ //
+ uint8_t pui8Buffer[2];
+
+ //
+ // The write state used to write register values.
+ //
+ tI2CMWrite8 sWriteState;
+
+ //
+ // The read-modify-write state used to modify register values.
+ //
+ tI2CMReadModifyWrite8 sReadModifyWriteState;
+ }
+ uCommand;
+}
+tSHT21;
+
+//*****************************************************************************
+//
+// Function prototypes.
+//
+//*****************************************************************************
+extern uint_fast8_t SHT21Init(tSHT21 *psInst, tI2CMInstance *psI2CInst,
+ uint_fast8_t ui8I2CAddr,
+ tSensorCallback *pfnCallback,
+ void *pvCallbackData);
+extern uint_fast8_t SHT21Read(tSHT21 *psInst, uint_fast8_t ui8Reg,
+ uint8_t *pui8Data, uint_fast16_t ui16Count,
+ tSensorCallback *pfnCallback,
+ void *pvCallbackData);
+extern uint_fast8_t SHT21Write(tSHT21 *psInst, uint_fast8_t ui8Reg,
+ const uint8_t *pui8Data,
+ uint_fast16_t ui16Count,
+ tSensorCallback *pfnCallback,
+ void *pvCallbackData);
+extern uint_fast8_t SHT21ReadModifyWrite(tSHT21 *psInst, uint_fast8_t ui8Reg,
+ uint_fast8_t ui8Mask,
+ uint_fast8_t ui8Value,
+ tSensorCallback *pfnCallback,
+ void *pvCallbackData);
+extern uint_fast8_t SHT21DataRead(tSHT21 *psInst, tSensorCallback *pfnCallback,
+ void *pvCallbackData);
+extern void SHT21DataTemperatureGetRaw(tSHT21 *psInst,
+ uint16_t *pui16Temperature);
+extern void SHT21DataTemperatureGetFloat(tSHT21 *psInst, float *pfTemperature);
+extern void SHT21DataHumidityGetRaw(tSHT21 *psInst, uint16_t *pui16Humidity);
+extern void SHT21DataHumidityGetFloat(tSHT21 *psInst, float *pfHumidity);
+
+//*****************************************************************************
+//
+// Mark the end of the C bindings section for C++ compilers.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __SENSORLIB_SHT21_H__
diff --git a/sensorlib/tmp006.c b/sensorlib/tmp006.c
new file mode 100644
index 0000000..e29900a
--- /dev/null
+++ b/sensorlib/tmp006.c
@@ -0,0 +1,606 @@
+//*****************************************************************************
+//
+// tmp006.c - Driver for the TI TMP006 Temperature Sensor
+//
+// Copyright (c) 2013-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
+//
+//*****************************************************************************
+
+#include <math.h>
+#include <stdint.h>
+#include "sensorlib/hw_tmp006.h"
+#include "sensorlib/i2cm_drv.h"
+#include "sensorlib/tmp006.h"
+
+//*****************************************************************************
+//
+//! \addtogroup tmp006_api
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// The states of the TMP006 state machine.
+//
+//*****************************************************************************
+#define TMP006_STATE_IDLE 0
+#define TMP006_STATE_INIT 1
+#define TMP006_STATE_READ 2
+#define TMP006_STATE_WRITE 3
+#define TMP006_STATE_RMW 4
+#define TMP006_STATE_READ_AMB 5
+#define TMP006_STATE_READ_OBJ 6
+
+//*****************************************************************************
+//
+// The constants used to calculate object temperature.
+//
+//*****************************************************************************
+#define T_REF 298.15
+#define A1 1.75e-03
+#define A2 -1.678e-05
+#define B0 -2.94e-05
+#define B1 -5.70e-07
+#define B2 4.63e-09
+#define C2 13.4
+
+//*****************************************************************************
+//
+// The callback function that is called when I2C transations to/from the TMP006
+// have completed.
+//
+//*****************************************************************************
+static void
+TMP006Callback(void *pvCallbackData, uint_fast8_t ui8Status)
+{
+ tTMP006 *psInst;
+
+ //
+ // Convert the instance data into a pointer to a tTMP006 structure.
+ //
+ psInst = pvCallbackData;
+
+ //
+ // If the I2C master driver encountered a failure, force the state machine
+ // to the idle state (which will also result in a callback to propagate the
+ // error).
+ //
+ if(ui8Status != I2CM_STATUS_SUCCESS)
+ {
+ psInst->ui8State = TMP006_STATE_IDLE;
+ }
+
+ //
+ // Determine the current state of the TMP006 state machine.
+ //
+ switch(psInst->ui8State)
+ {
+ //
+ // All states that trivially transition to IDLE, and all unknown
+ // states.
+ //
+ case TMP006_STATE_INIT:
+ case TMP006_STATE_READ:
+ case TMP006_STATE_WRITE:
+ case TMP006_STATE_RMW:
+ case TMP006_STATE_READ_OBJ:
+ default:
+ {
+ //
+ // The state machine is now idle.
+ //
+ psInst->ui8State = TMP006_STATE_IDLE;
+
+ //
+ // Done.
+ //
+ break;
+ }
+
+ //
+ // The ambient temperature was just read.
+ //
+ case TMP006_STATE_READ_AMB:
+ {
+ //
+ // Move to the read object temperature state.
+ //
+ psInst->ui8State = TMP006_STATE_READ_OBJ;
+
+ //
+ // Start a read of the object temperature now that this read is
+ // complete.
+ //
+ psInst->uCommand.pui8Buffer[0] = TMP006_O_VOBJECT;
+ I2CMRead(psInst->psI2CInst, psInst->ui8Addr,
+ psInst->uCommand.pui8Buffer, 1, psInst->pui8Data + 2, 2,
+ TMP006Callback, psInst);
+
+ //
+ // Done.
+ //
+ break;
+ }
+ }
+
+ //
+ // See if the state machine is now idle and there is a callback function.
+ //
+ if((psInst->ui8State == TMP006_STATE_IDLE) && psInst->pfnCallback)
+ {
+ //
+ // Call the application-supplied callback function.
+ //
+ psInst->pfnCallback(psInst->pvCallbackData, ui8Status);
+ }
+}
+
+//*****************************************************************************
+//
+//! Initializes the TMP006 driver.
+//!
+//! \param psInst is a pointer to the TMP006 instance data.
+//! \param psI2CInst is a pointer to the I2C driver instance data.
+//! \param ui8I2CAddr is the I2C address of the TMP006 device.
+//! \param pfnCallback is the function to be called when the initialization has
+//! completed (can be \b NULL if a callback is not required).
+//! \param pvCallbackData is a pointer that is passed to the callback function.
+//!
+//! This function initializes the TMP006 driver, preparing it for operation,
+//! and initiates a reset of the TMP006 device, clearing any previous
+//! configuration data.
+//!
+//! \return Returns 1 if the TMP006 driver was successfully initialized and 0
+//! if it was not.
+//
+//*****************************************************************************
+uint_fast8_t
+TMP006Init(tTMP006 *psInst, tI2CMInstance *psI2CInst, uint_fast8_t ui8I2CAddr,
+ tSensorCallback *pfnCallback, void *pvCallbackData)
+{
+ //
+ // Initialize the TMP006 instance structure
+ //
+ psInst->psI2CInst = psI2CInst;
+ psInst->ui8Addr = ui8I2CAddr;
+ psInst->ui8State = TMP006_STATE_INIT;
+
+ //
+ // Save the callback information.
+ //
+ psInst->pfnCallback = pfnCallback;
+ psInst->pvCallbackData = pvCallbackData;
+
+ //
+ // Set the calibration factor to a reasonable estimate, applications
+ // should perform a calibration in their environment and directly overwrite
+ // this value after calling TMP006Init with the system specific value.
+ //
+ psInst->fCalibrationFactor = 6.40e-14;
+
+ //
+ // Load the data buffer to write the reset sequence
+ //
+ psInst->pui8Data[0] = TMP006_O_CONFIG;
+ psInst->pui8Data[1] = (uint8_t)(TMP006_CONFIG_RESET_ASSERT >> 8);
+ psInst->pui8Data[2] = (uint8_t)(TMP006_CONFIG_RESET_ASSERT & 0x00FF);
+
+ //
+ // Write the reset bit and issue a callback when finished.
+ //
+ if(I2CMWrite(psInst->psI2CInst, ui8I2CAddr, psInst->pui8Data, 3,
+ TMP006Callback, psInst) == 0)
+ {
+ //
+ // I2CMWrite failed so reset TMP006 state and return zero to indicate
+ // failure.
+ //
+ psInst->ui8State = TMP006_STATE_IDLE;
+ return(0);
+ }
+
+ //
+ // Success
+ //
+ return(1);
+}
+
+//*****************************************************************************
+//
+//! Reads data from TMP006 registers.
+//!
+//! \param psInst is a pointer to the TMP006 instance data.
+//! \param ui8Reg is the first register to read.
+//! \param pui16Data is a pointer to the location to store the data that is
+//! read.
+//! \param ui16Count the number of register values to read.
+//! \param pfnCallback is the function to be called when data read is complete
+//! (can be \b NULL if a callback is not required).
+//! \param pvCallbackData is a pointer that is passed to the callback function.
+//!
+//! This function reads a sequence of data values from consecutive registers in
+//! the TMP006.
+//!
+//! \note The TMP006 does not auto-increment the register pointer, so reads of
+//! more than one value returns garbage for the subsequent values.
+//!
+//! \return Returns 1 if the write was successfully started and 0 if it was
+//! not.
+//
+//*****************************************************************************
+uint_fast8_t
+TMP006Read(tTMP006 *psInst, uint_fast8_t ui8Reg, uint16_t *pui16Data,
+ uint_fast16_t ui16Count, tSensorCallback *pfnCallback,
+ void *pvCallbackData)
+{
+ //
+ // Return a failure if the TMP006 driver is not idle (in other words, there
+ // is already an outstanding request to the TMP006).
+ //
+ if(psInst->ui8State != TMP006_STATE_IDLE)
+ {
+ return(0);
+ }
+
+ //
+ // Save the callback information.
+ //
+ psInst->pfnCallback = pfnCallback;
+ psInst->pvCallbackData = pvCallbackData;
+
+ //
+ // Move the state machine to the wait for read state.
+ //
+ psInst->ui8State = TMP006_STATE_READ;
+
+ //
+ // Read the requested registers from the TMP006.
+ //
+ if(I2CMRead16BE(&(psInst->uCommand.sReadState), psInst->psI2CInst,
+ psInst->ui8Addr, ui8Reg, pui16Data, ui16Count,
+ TMP006Callback, psInst) == 0)
+ {
+ //
+ // The I2C write failed, so move to the idle state and return a
+ // failure.
+ //
+ psInst->ui8State = TMP006_STATE_IDLE;
+ return(0);
+ }
+
+ //
+ // Success.
+ //
+ return(1);
+}
+
+//*****************************************************************************
+//
+//! Writes data to TMP006 registers.
+//!
+//! \param psInst is a pointer to the TMP006 instance data.
+//! \param ui8Reg is the first register to write.
+//! \param pui16Data is a pointer to the 16-bit register data to write.
+//! \param ui16Count is the number of 16-bit registers to write.
+//! \param pfnCallback is the function to be called when the data has been
+//! written (can be \b NULL if a callback is not required).
+//! \param pvCallbackData is a pointer that is passed to the callback function.
+//!
+//! This function writes a sequence of data values to consecutive registers in
+//! the TMP006. The first value in the \e pui16Data buffer contains the data
+//! to be written into the \e ui8Reg register, the second value contains the
+//! data to be written into the next register, and so on.
+//!
+//! \note The TMP006 does not auto-increment the register pointer, so writes of
+//! more than one register are rejected by the TMP006.
+//!
+//! \return Returns 1 if the write was successfully started and 0 if it was
+//! not.
+//
+//*****************************************************************************
+uint_fast8_t
+TMP006Write(tTMP006 *psInst, uint_fast8_t ui8Reg, const uint16_t *pui16Data,
+ uint_fast16_t ui16Count, tSensorCallback *pfnCallback,
+ void *pvCallbackData)
+{
+ //
+ // Return a failure if the TMP006 driver is not idle (in other words, there
+ // is already an outstanding request to the TMP006).
+ //
+ if(psInst->ui8State != TMP006_STATE_IDLE)
+ {
+ return(0);
+ }
+
+ //
+ // Save the callback information.
+ //
+ psInst->pfnCallback = pfnCallback;
+ psInst->pvCallbackData = pvCallbackData;
+
+ //
+ // Move the state machine to the wait for write state.
+ //
+ psInst->ui8State = TMP006_STATE_WRITE;
+
+ //
+ // Write the requested registers to the TMP006.
+ //
+ if(I2CMWrite16BE(&(psInst->uCommand.sWriteState), psInst->psI2CInst,
+ psInst->ui8Addr, ui8Reg, pui16Data, ui16Count,
+ TMP006Callback, psInst) == 0)
+ {
+ //
+ // The I2C write failed, so move to the idle state and return a
+ // failure.
+ //
+ psInst->ui8State = TMP006_STATE_IDLE;
+ return(0);
+ }
+
+ //
+ // Success.
+ //
+ return(1);
+}
+
+//*****************************************************************************
+//
+//! Performs a read-modify-write of a TMP006 register.
+//!
+//! \param psInst is a pointer to the TMP006 instance data.
+//! \param ui8Reg is the register offset to read modify and write
+//! \param ui16Mask is the bit mask that is ANDed with the current register
+//! value.
+//! \param ui16Value is the bit mask that is ORed with the result of the AND
+//! operation.
+//! \param pfnCallback is the function to be called when the data has been
+//! changed (can be \b NULL if a callback is not required).
+//! \param pvCallbackData is a pointer that is passed to the callback function.
+//!
+//! This function changes the value of a register in the TMP006 via a
+//! read-modify-write operation, allowing one of the fields to be changed
+//! without disturbing the other fields. The \e ui8Reg register is read, ANDed
+//! with \e ui16Mask, ORed with \e ui16Value, and then written back to the
+//! TMP006.
+//!
+//! \return Returns 1 if the read-modify-write was successfully started and 0
+//! if it was not.
+//
+//*****************************************************************************
+uint_fast8_t
+TMP006ReadModifyWrite(tTMP006 *psInst, uint_fast8_t ui8Reg,
+ uint_fast16_t ui16Mask, uint_fast16_t ui16Value,
+ tSensorCallback *pfnCallback, void *pvCallbackData)
+{
+ //
+ // Return a failure if the TMP006 driver is not idle (in other words, there
+ // is already an outstanding request to the TMP006).
+ //
+ if(psInst->ui8State != TMP006_STATE_IDLE)
+ {
+ return(0);
+ }
+
+ //
+ // Save the callback information.
+ //
+ psInst->pfnCallback = pfnCallback;
+ psInst->pvCallbackData = pvCallbackData;
+
+ //
+ // Move the state machine to the wait for read-modify-write state.
+ //
+ psInst->ui8State = TMP006_STATE_RMW;
+
+ //
+ // Submit the read-modify-write request to the TMP006.
+ //
+ if(I2CMReadModifyWrite16BE(&(psInst->uCommand.sReadModifyWriteState),
+ psInst->psI2CInst, psInst->ui8Addr, ui8Reg,
+ ui16Mask, ui16Value, TMP006Callback,
+ psInst) == 0)
+ {
+ //
+ // The I2C read-modify-write failed, so move to the idle state and
+ // return a failure.
+ //
+ psInst->ui8State = TMP006_STATE_IDLE;
+ return(0);
+ }
+
+ //
+ // Success.
+ //
+ return(1);
+}
+
+//*****************************************************************************
+//
+//! Reads the temperature data from the TMP006.
+//!
+//! \param psInst is a pointer to the TMP006 instance data.
+//! \param pfnCallback is the function to be called when the data has been read
+//! (can be \b NULL if a callback is not required).
+//! \param pvCallbackData is a pointer that is passed to the callback function.
+//!
+//! This function initiates a read of the TMP006 data registers. When the read
+//! has completed (as indicated by calling the callback function), the new
+//! readings can be obtained via:
+//!
+//! - TMP006DataTemperatureGetRaw()
+//! - TMP006DataTemperatureGetFloat()
+//!
+//! \return Returns 1 if the read was successfully started and 0 if it was not.
+//
+//*****************************************************************************
+uint_fast8_t
+TMP006DataRead(tTMP006 *psInst, tSensorCallback *pfnCallback,
+ void *pvCallbackData)
+{
+ //
+ // Return a failure if the TMP006 driver is not idle (in other words, there
+ // is already an outstanding request to the TMP006).
+ //
+ if(psInst->ui8State != TMP006_STATE_IDLE)
+ {
+ return(0);
+ }
+
+ //
+ // Save the callback information.
+ //
+ psInst->pfnCallback = pfnCallback;
+ psInst->pvCallbackData = pvCallbackData;
+
+ //
+ // Move the state machine to the wait for ambient data read state.
+ //
+ psInst->ui8State = TMP006_STATE_READ_AMB;
+
+ //
+ // Read the ambient temperature data from the TMP006.
+ //
+ psInst->uCommand.pui8Buffer[0] = TMP006_O_TAMBIENT;
+ if(I2CMRead(psInst->psI2CInst, psInst->ui8Addr,
+ psInst->uCommand.pui8Buffer, 1, psInst->pui8Data, 2,
+ TMP006Callback, psInst) == 0)
+ {
+ //
+ // The I2C read failed, so move to the idle state and return a failure.
+ //
+ psInst->ui8State = TMP006_STATE_IDLE;
+ return(0);
+ }
+
+ //
+ // Success.
+ //
+ return(1);
+}
+
+//*****************************************************************************
+//
+//! Gets the raw measurement data from the most recent data read.
+//!
+//! \param psInst is a pointer to the TMP006 instance data.
+//! \param pi16Ambient is a pointer to the value into which the raw ambient
+//! temperature data is stored.
+//! \param pi16Object is a pointer to the value into which the raw object
+//! temperature data is stored.
+//!
+//! This function returns the raw measurement data from the most recent data
+//! read. The data is not manipulated in any way by the driver.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+TMP006DataTemperatureGetRaw(tTMP006 *psInst, int16_t *pi16Ambient,
+ int16_t *pi16Object)
+{
+ //
+ // Return the raw temperature value.
+ //
+ *pi16Ambient = ((int16_t)psInst->pui8Data[0] << 8) | psInst->pui8Data[1];
+ *pi16Object = ((int16_t)psInst->pui8Data[2] << 8) | psInst->pui8Data[3];
+}
+
+//*****************************************************************************
+//
+//! Gets the measurement data from the most recent data read.
+//!
+//! \param psInst is a pointer to the TMP006 instance data.
+//! \param pfAmbient is a pointer to the value into which the ambient
+//! temperature data is stored as floating point degrees Celsius.
+//! \param pfObject is a pointer to the value into which the object temperature
+//! data is stored as floating point degrees Celsius.
+//!
+//! This function returns the temperature data from the most recent data read,
+//! converted into Celsius.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+TMP006DataTemperatureGetFloat(tTMP006 *psInst, float *pfAmbient,
+ float *pfObject)
+{
+ float fTdie2, fS, fVo, fVx, fObj;
+ int16_t i16Ambient;
+ int16_t i16Object;
+
+ //
+ // Get the raw readings.
+ //
+ TMP006DataTemperatureGetRaw(psInst, &i16Ambient, &i16Object);
+
+ //
+ // The bottom two bits are not temperature data, so discard them but keep
+ // the sign information.
+ //
+ *pfAmbient = (float)(i16Ambient / 4);
+
+ //
+ // Divide by 32 to get unit scaling correct.
+ //
+ *pfAmbient = *pfAmbient / 32.0;
+
+ //
+ // fTdie2 is measured ambient temperature in degrees Kelvin.
+ //
+ fTdie2 = *pfAmbient + T_REF;
+
+ //
+ // S is the sensitivity.
+ //
+ fS = psInst->fCalibrationFactor * (1.0f + (A1 * (*pfAmbient)) +
+ (A2 * ((*pfAmbient) * (*pfAmbient))));
+
+ //
+ // Vos is the offset voltage.
+ //
+ fVo = B0 + (B1 * (*pfAmbient)) + (B2 * ((*pfAmbient) * (*pfAmbient)));
+
+ //
+ // Vx is the difference between raw object voltage and Vos
+ // 156.25e-9 is nanovolts per least significant bit from the voltage
+ // register.
+ //
+ fVx = (((float) i16Object) * 156.25e-9) - fVo;
+
+ //
+ // fObj is the feedback coefficient.
+ //
+ fObj = fVx + C2 * (fVx * fVx);
+
+ //
+ // Finally calculate the object temperature.
+ //
+ *pfObject = (sqrtf(sqrtf((fTdie2 * fTdie2 * fTdie2 * fTdie2) +
+ (fObj / fS))) - T_REF);
+}
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
diff --git a/sensorlib/tmp006.h b/sensorlib/tmp006.h
new file mode 100644
index 0000000..e22e410
--- /dev/null
+++ b/sensorlib/tmp006.h
@@ -0,0 +1,157 @@
+//*****************************************************************************
+//
+// tmp006.h - Prototypes for the Texas Instruments TMP006 temperature sensor
+// driver.
+//
+// Copyright (c) 2013-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
+//
+//*****************************************************************************
+
+#ifndef __SENSORLIB_TMP006_H__
+#define __SENSORLIB_TMP006_H__
+
+//*****************************************************************************
+//
+// If building with a C++ compiler, make all of the definitions in this header
+// have a C binding.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+//*****************************************************************************
+//
+// The structure that defines the internal state of the TMP006 driver.
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ // The pointer to the I2C master interface instance used to communicate
+ // with the TMP006.
+ //
+ tI2CMInstance *psI2CInst;
+
+ //
+ // The I2C address of the TMP006.
+ //
+ uint8_t ui8Addr;
+
+ //
+ // The state of the state machine used while accessing the TMP006.
+ //
+ uint8_t ui8State;
+
+ //
+ // The data buffer used for sending/receiving data to/from the TMP006.
+ //
+ uint8_t pui8Data[4];
+
+ //
+ // Calibration factor. Left to application to implement calibration
+ // See term S0 in http://www.ti.com/lit/ug/sbou107/sbou107.pdf
+ //
+ float fCalibrationFactor;
+
+ //
+ // The function that is called when the current request has completed
+ // processing.
+ //
+ tSensorCallback *pfnCallback;
+
+ //
+ // The pointer provided to the callback function.
+ //
+ void *pvCallbackData;
+
+ //
+ // A union of structures that are used for read, write and
+ // read-modify-write operations. Since only one operation can be active at
+ // a time, it is safe to re-use the memory in this manner.
+ //
+ union
+ {
+ //
+ // A buffer used to store the write portion of a register read.
+ //
+ uint8_t pui8Buffer[2];
+
+ //
+ // The read state used to read register values.
+ //
+ tI2CMRead16BE sReadState;
+
+ //
+ // The write state used to write register values.
+ //
+ tI2CMWrite16BE sWriteState;
+
+ //
+ // The read-modify-write state used to modify register values.
+ //
+ tI2CMReadModifyWrite16 sReadModifyWriteState;
+ }
+ uCommand;
+}
+tTMP006;
+
+//*****************************************************************************
+//
+// Function prototypes.
+//
+//*****************************************************************************
+extern uint_fast8_t TMP006Init(tTMP006 *psInst, tI2CMInstance *psI2CInst,
+ uint_fast8_t ui8I2CAddr,
+ tSensorCallback *pfnCallback,
+ void *pvCallbackData);
+extern uint_fast8_t TMP006Read(tTMP006 *psInst, uint_fast8_t ui8Reg,
+ uint16_t *pui16Data, uint_fast16_t ui16Count,
+ tSensorCallback *pfnCallback,
+ void *pvCallbackData);
+extern uint_fast8_t TMP006Write(tTMP006 *psInst, uint_fast8_t ui8Reg,
+ const uint16_t *pui16Data,
+ uint_fast16_t ui16Count,
+ tSensorCallback *pfnCallback,
+ void *pvCallbackData);
+extern uint_fast8_t TMP006ReadModifyWrite(tTMP006 *psInst, uint_fast8_t ui8Reg,
+ uint_fast16_t ui16Mask,
+ uint_fast16_t ui16Value,
+ tSensorCallback *pfnCallback,
+ void *pvCallbackData);
+extern uint_fast8_t TMP006DataRead(tTMP006 *psInst,
+ tSensorCallback *pfnCallback,
+ void *pvCallbackData);
+extern void TMP006DataTemperatureGetRaw(tTMP006 *psInst, int16_t *pui16Ambient,
+ int16_t *pui16Object);
+extern void TMP006DataTemperatureGetFloat(tTMP006 *psInst, float *pfAmbient,
+ float *pfObject);
+
+//*****************************************************************************
+//
+// Mark the end of the C bindings section for C++ compilers.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __SENSORLIB_TMP006_H__
+
diff --git a/sensorlib/tmp100.c b/sensorlib/tmp100.c
new file mode 100644
index 0000000..d4cc3a8
--- /dev/null
+++ b/sensorlib/tmp100.c
@@ -0,0 +1,582 @@
+//*****************************************************************************
+//
+// tmp100.c - Driver for the TI TMP100 Temperature Sensor
+//
+// Copyright (c) 2013-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
+//
+//*****************************************************************************
+
+#include <math.h>
+#include <stdint.h>
+#include "sensorlib/hw_tmp100.h"
+#include "sensorlib/i2cm_drv.h"
+#include "sensorlib/tmp100.h"
+
+//*****************************************************************************
+//
+//! \addtogroup tmp100_api
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// The states of the TMP100 state machine.
+//
+//*****************************************************************************
+#define TMP100_STATE_IDLE 0
+#define TMP100_STATE_INIT 1
+#define TMP100_STATE_READ 2
+#define TMP100_STATE_WRITE 3
+#define TMP100_STATE_RMW 4
+
+//*****************************************************************************
+//
+// The callback function that is called when I2C transations to/from the TMP100
+// have completed.
+//
+//*****************************************************************************
+static void
+TMP100Callback(void *pvCallbackData, uint_fast8_t ui8Status)
+{
+ tTMP100 *psInst;
+
+ //
+ // Convert the instance data into a pointer to a tTMP100 structure.
+ //
+ psInst = pvCallbackData;
+
+ //
+ // If the I2C master driver encountered a failure, force the state machine
+ // to the idle state (which will also result in a callback to propagate the
+ // error).
+ //
+ if(ui8Status != I2CM_STATUS_SUCCESS)
+ {
+ psInst->ui8State = TMP100_STATE_IDLE;
+ }
+
+ //
+ // Determine the current state of the TMP100 state machine.
+ //
+ switch(psInst->ui8State)
+ {
+ //
+ // All states that trivially transition to IDLE, and all unknown
+ // states.
+ //
+ case TMP100_STATE_INIT:
+ case TMP100_STATE_READ:
+ case TMP100_STATE_WRITE:
+ case TMP100_STATE_RMW:
+ default:
+ {
+ //
+ // The state machine is now idle.
+ //
+ psInst->ui8State = TMP100_STATE_IDLE;
+
+ //
+ // Done.
+ //
+ break;
+ }
+ }
+
+ //
+ // See if the state machine is now idle and there is a callback function.
+ //
+ if((psInst->ui8State == TMP100_STATE_IDLE) && psInst->pfnCallback)
+ {
+ //
+ // Call the application-supplied callback function.
+ //
+ psInst->pfnCallback(psInst->pvCallbackData, ui8Status);
+ }
+}
+
+//*****************************************************************************
+//
+//! Initializes the TMP100 driver.
+//!
+//! \param psInst is a pointer to the TMP100 instance data.
+//! \param psI2CInst is a pointer to the I2C driver instance data.
+//! \param ui8I2CAddr is the I2C address of the TMP100 device.
+//! \param pfnCallback is the function to be called when the initialization has
+//! completed (can be \b NULL if a callback is not required).
+//! \param pvCallbackData is a pointer that is passed to the callback function.
+//!
+//! This function initializes the TMP100 driver, preparing it for operation,
+//! and initiates a reset of the TMP100 device, clearing any previous
+//! configuration data.
+//!
+//! \return Returns 1 if the TMP100 driver was successfully initialized and 0
+//! if it was not.
+//
+//*****************************************************************************
+uint_fast8_t
+TMP100Init(tTMP100 *psInst, tI2CMInstance *psI2CInst, uint_fast8_t ui8I2CAddr,
+ tSensorCallback *pfnCallback, void *pvCallbackData)
+{
+ //
+ // Initialize the TMP100 instance structure
+ //
+ psInst->psI2CInst = psI2CInst;
+ psInst->ui8Addr = ui8I2CAddr;
+ psInst->ui8State = TMP100_STATE_INIT;
+
+ //
+ // Save the callback information.
+ //
+ psInst->pfnCallback = pfnCallback;
+ psInst->pvCallbackData = pvCallbackData;
+
+ //
+ // Write the configuration register to its default value.
+ //
+ psInst->pui8Data[0] = TMP100_O_CONFIG;
+ psInst->pui8Data[1] = 0x00;
+
+ //
+ // Write the reset bit and issue a callback when finished.
+ //
+ if(I2CMWrite(psInst->psI2CInst, ui8I2CAddr, psInst->pui8Data, 2,
+ TMP100Callback, psInst) == 0)
+ {
+ //
+ // I2CMWrite failed so reset TMP100 state and return zero to indicate
+ // failure.
+ //
+ psInst->ui8State = TMP100_STATE_IDLE;
+ return(0);
+ }
+
+ //
+ // Success
+ //
+ return(1);
+}
+
+//*****************************************************************************
+//
+//! Reads data from TMP100 registers.
+//!
+//! \param psInst is a pointer to the TMP100 instance data.
+//! \param ui8Reg is the first register to read.
+//! \param pui16Data is a pointer to the location to store the data that is
+//! read.
+//! \param ui16Count the number of register values to read.
+//! \param pfnCallback is the function to be called when data read is complete
+//! (can be \b NULL if a callback is not required).
+//! \param pvCallbackData is a pointer that is passed to the callback function.
+//!
+//! This function reads a sequence of data values from consecutive registers in
+//! the TMP100.
+//!
+//! \note The TMP100 does not auto-increment the register pointer, so reads of
+//! more than one value returns garbage for the subsequent values.
+//!
+//! \return Returns 1 if the write was successfully started and 0 if it was
+//! not.
+//
+//*****************************************************************************
+uint_fast8_t
+TMP100Read(tTMP100 *psInst, uint_fast8_t ui8Reg, uint16_t *pui16Data,
+ uint_fast16_t ui16Count, tSensorCallback *pfnCallback,
+ void *pvCallbackData)
+{
+ //
+ // Return a failure if the TMP100 driver is not idle (in other words, there
+ // is already an outstanding request to the TMP100).
+ //
+ if(psInst->ui8State != TMP100_STATE_IDLE)
+ {
+ return(0);
+ }
+
+ //
+ // Save the callback information.
+ //
+ psInst->pfnCallback = pfnCallback;
+ psInst->pvCallbackData = pvCallbackData;
+
+ //
+ // Move the state machine to the wait for read state.
+ //
+ psInst->ui8State = TMP100_STATE_READ;
+
+ //
+ // Read the requested registers from the TMP100.
+ //
+ if(ui8Reg == TMP100_O_CONFIG)
+ {
+ //
+ // The configuration register is only one byte, so only a single byte
+ // read is necessary and no endian swapping is required.
+ //
+ psInst->uCommand.pui8Buffer[0] = ui8Reg;
+ if(I2CMRead(psInst->psI2CInst, psInst->ui8Addr,
+ psInst->uCommand.pui8Buffer, 1, (uint8_t *)pui16Data, 1,
+ TMP100Callback, psInst) == 0)
+ {
+ //
+ // The I2C write failed, so move to the idle state and return a
+ // failure.
+ //
+ psInst->ui8State = TMP100_STATE_IDLE;
+ return(0);
+ }
+ }
+ else
+ {
+ //
+ // This is one of the temperature registers, which are 16-bit
+ // big-endian registers.
+ //
+ if(I2CMRead16BE(&(psInst->uCommand.sReadState), psInst->psI2CInst,
+ psInst->ui8Addr, ui8Reg, pui16Data, ui16Count,
+ TMP100Callback, psInst) == 0)
+ {
+ //
+ // The I2C write failed, so move to the idle state and return a
+ // failure.
+ //
+ psInst->ui8State = TMP100_STATE_IDLE;
+ return(0);
+ }
+ }
+
+ //
+ // Success.
+ //
+ return(1);
+}
+
+//*****************************************************************************
+//
+//! Writes data to TMP100 registers.
+//!
+//! \param psInst is a pointer to the TMP100 instance data.
+//! \param ui8Reg is the first register to write.
+//! \param pui16Data is a pointer to the 16-bit register data to write.
+//! \param ui16Count is the number of 16-bit registers to write.
+//! \param pfnCallback is the function to be called when the data has been
+//! written (can be \b NULL if a callback is not required).
+//! \param pvCallbackData is a pointer that is passed to the callback function.
+//!
+//! This function writes a sequence of data values to consecutive registers in
+//! the TMP100. The first value in the \e pui16Data buffer contains the data
+//! to be written into the \e ui8Reg register, the second value contains the
+//! data to be written into the next register, and so on.
+//!
+//! \note The TMP100 does not auto-increment the register pointer, so writes of
+//! more than one register are rejected by the TMP100.
+//!
+//! \return Returns 1 if the write was successfully started and 0 if it was
+//! not.
+//
+//*****************************************************************************
+uint_fast8_t
+TMP100Write(tTMP100 *psInst, uint_fast8_t ui8Reg, const uint16_t *pui16Data,
+ uint_fast16_t ui16Count, tSensorCallback *pfnCallback,
+ void *pvCallbackData)
+{
+ //
+ // Return a failure if the TMP100 driver is not idle (in other words, there
+ // is already an outstanding request to the TMP100).
+ //
+ if(psInst->ui8State != TMP100_STATE_IDLE)
+ {
+ return(0);
+ }
+
+ //
+ // Save the callback information.
+ //
+ psInst->pfnCallback = pfnCallback;
+ psInst->pvCallbackData = pvCallbackData;
+
+ //
+ // Move the state machine to the wait for write state.
+ //
+ psInst->ui8State = TMP100_STATE_WRITE;
+
+ //
+ // Write the requested registers to the TMP100.
+ //
+ if(ui8Reg == TMP100_O_CONFIG)
+ {
+ //
+ // The configuration register is only one byte, so only a single byte
+ // write is necessary and no endian swapping is required.
+ //
+ psInst->uCommand.pui8Buffer[0] = ui8Reg;
+ psInst->uCommand.pui8Buffer[1] = *pui16Data & 0xff;
+ if(I2CMWrite(psInst->psI2CInst, psInst->ui8Addr,
+ psInst->uCommand.pui8Buffer, 2, TMP100Callback,
+ psInst) == 0)
+ {
+ //
+ // The I2C write failed, so move to the idle state and return a
+ // failure.
+ //
+ psInst->ui8State = TMP100_STATE_IDLE;
+ return(0);
+ }
+ }
+ else
+ {
+ //
+ // This is one of the temperature registers, which are 16-bit
+ // big-endian registers.
+ //
+ if(I2CMWrite16BE(&(psInst->uCommand.sWriteState), psInst->psI2CInst,
+ psInst->ui8Addr, ui8Reg, pui16Data, ui16Count,
+ TMP100Callback, psInst) == 0)
+ {
+ //
+ // The I2C write failed, so move to the idle state and return a
+ // failure.
+ //
+ psInst->ui8State = TMP100_STATE_IDLE;
+ return(0);
+ }
+ }
+
+ //
+ // Success.
+ //
+ return(1);
+}
+
+//*****************************************************************************
+//
+//! Performs a read-modify-write of a TMP100 register.
+//!
+//! \param psInst is a pointer to the TMP100 instance data.
+//! \param ui8Reg is the register offset to read modify and write
+//! \param ui16Mask is the bit mask that is ANDed with the current register
+//! value.
+//! \param ui16Value is the bit mask that is ORed with the result of the AND
+//! operation.
+//! \param pfnCallback is the function to be called when the data has been
+//! changed (can be \b NULL if a callback is not required).
+//! \param pvCallbackData is a pointer that is passed to the callback function.
+//!
+//! This function changes the value of a register in the TMP100 via a
+//! read-modify-write operation, allowing one of the fields to be changed
+//! without disturbing the other fields. The \e ui8Reg register is read, ANDed
+//! with \e ui16Mask, ORed with \e ui16Value, and then written back to the
+//! TMP100.
+//!
+//! \return Returns 1 if the read-modify-write was successfully started and 0
+//! if it was not.
+//
+//*****************************************************************************
+uint_fast8_t
+TMP100ReadModifyWrite(tTMP100 *psInst, uint_fast8_t ui8Reg,
+ uint_fast16_t ui16Mask, uint_fast16_t ui16Value,
+ tSensorCallback *pfnCallback, void *pvCallbackData)
+{
+ //
+ // Return a failure if the TMP100 driver is not idle (in other words, there
+ // is already an outstanding request to the TMP100).
+ //
+ if(psInst->ui8State != TMP100_STATE_IDLE)
+ {
+ return(0);
+ }
+
+ //
+ // Save the callback information.
+ //
+ psInst->pfnCallback = pfnCallback;
+ psInst->pvCallbackData = pvCallbackData;
+
+ //
+ // Move the state machine to the wait for read-modify-write state.
+ //
+ psInst->ui8State = TMP100_STATE_RMW;
+
+ //
+ // Submit the read-modify-write request to the TMP100.
+ //
+ if(ui8Reg == TMP100_O_CONFIG)
+ {
+ //
+ // The configuration register is only one byte, so only a single byte
+ // read-modify-write is necessary and no endian swapping is required.
+ //
+ if(I2CMReadModifyWrite8(&(psInst->uCommand.sReadModifyWriteState8),
+ psInst->psI2CInst, psInst->ui8Addr, ui8Reg,
+ ui16Mask & 0xff, ui16Value & 0xff,
+ TMP100Callback, psInst) == 0)
+ {
+ //
+ // The I2C read-modify-write failed, so move to the idle state and
+ // return a failure.
+ //
+ psInst->ui8State = TMP100_STATE_IDLE;
+ return(0);
+ }
+ }
+ else
+ {
+ //
+ // This is one of the temperature registers, which are 16-bit
+ // big-endian registers.
+ //
+ if(I2CMReadModifyWrite16BE(&(psInst->uCommand.sReadModifyWriteState16),
+ psInst->psI2CInst, psInst->ui8Addr, ui8Reg,
+ ui16Mask, ui16Value, TMP100Callback,
+ psInst) == 0)
+ {
+ //
+ // The I2C read-modify-write failed, so move to the idle state and
+ // return a failure.
+ //
+ psInst->ui8State = TMP100_STATE_IDLE;
+ return(0);
+ }
+ }
+
+ //
+ // Success.
+ //
+ return(1);
+}
+
+//*****************************************************************************
+//
+//! Reads the temperature data from the TMP100.
+//!
+//! \param psInst is a pointer to the TMP100 instance data.
+//! \param pfnCallback is the function to be called when the data has been read
+//! (can be \b NULL if a callback is not required).
+//! \param pvCallbackData is a pointer that is passed to the callback function.
+//!
+//! This function initiates a read of the TMP100 data registers. When the read
+//! has completed (as indicated by calling the callback function), the new
+//! readings can be obtained via:
+//!
+//! - TMP100DataTemperatureGetRaw()
+//! - TMP100DataTemperatureGetFloat()
+//!
+//! \return Returns 1 if the read was successfully started and 0 if it was not.
+//
+//*****************************************************************************
+uint_fast8_t
+TMP100DataRead(tTMP100 *psInst, tSensorCallback *pfnCallback,
+ void *pvCallbackData)
+{
+ //
+ // Return a failure if the TMP100 driver is not idle (in other words, there
+ // is already an outstanding request to the TMP100).
+ //
+ if(psInst->ui8State != TMP100_STATE_IDLE)
+ {
+ return(0);
+ }
+
+ //
+ // Save the callback information.
+ //
+ psInst->pfnCallback = pfnCallback;
+ psInst->pvCallbackData = pvCallbackData;
+
+ //
+ // Move the state machine to the wait for data read state.
+ //
+ psInst->ui8State = TMP100_STATE_READ;
+
+ //
+ // Read the temperature data from the TMP100.
+ //
+ psInst->uCommand.pui8Buffer[0] = TMP100_O_TEMP;
+ if(I2CMRead(psInst->psI2CInst, psInst->ui8Addr,
+ psInst->uCommand.pui8Buffer, 1, psInst->pui8Data, 2,
+ TMP100Callback, psInst) == 0)
+ {
+ //
+ // The I2C read failed, so move to the idle state and return a failure.
+ //
+ psInst->ui8State = TMP100_STATE_IDLE;
+ return(0);
+ }
+
+ //
+ // Success.
+ //
+ return(1);
+}
+
+//*****************************************************************************
+//
+//! Gets the raw measurement data from the most recent data read.
+//!
+//! \param psInst is a pointer to the TMP100 instance data.
+//! \param pi16Temperature is a pointer to the value into which the raw
+//! temperature data is stored.
+//!
+//! This function returns the raw measurement data from the most recent data
+//! read. The data is not manipulated in any way by the driver.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+TMP100DataTemperatureGetRaw(tTMP100 *psInst, int16_t *pi16Temperature)
+{
+ //
+ // Return the raw temperature value.
+ //
+ *pi16Temperature =
+ ((int16_t)psInst->pui8Data[0] << 8) | psInst->pui8Data[1];
+}
+
+//*****************************************************************************
+//
+//! Gets the measurement data from the most recent data read.
+//!
+//! \param psInst is a pointer to the TMP100 instance data.
+//! \param pfTemperature is a pointer to the value into which the temperature
+//! data is stored as floating point degrees Celsius.
+//!
+//! This function returns the temperature data from the most recent data read,
+//! converted into Celsius.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+TMP100DataTemperatureGetFloat(tTMP100 *psInst, float *pfTemperature)
+{
+ //
+ // Convert the temperature reading into Celcius.
+ //
+ *pfTemperature = ((float)(((int16_t)psInst->pui8Data[0] << 8) |
+ psInst->pui8Data[1]) / 256.0);
+}
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
diff --git a/sensorlib/tmp100.h b/sensorlib/tmp100.h
new file mode 100644
index 0000000..bbb923c
--- /dev/null
+++ b/sensorlib/tmp100.h
@@ -0,0 +1,156 @@
+//*****************************************************************************
+//
+// tmp100.h - Prototypes for the Texas Instruments TMP100 temperature sensor
+// driver.
+//
+// Copyright (c) 2013-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
+//
+//*****************************************************************************
+
+#ifndef __SENSORLIB_TMP100_H__
+#define __SENSORLIB_TMP100_H__
+
+//*****************************************************************************
+//
+// If building with a C++ compiler, make all of the definitions in this header
+// have a C binding.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+//*****************************************************************************
+//
+// The structure that defines the internal state of the TMP100 driver.
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ // The pointer to the I2C master interface instance used to communicate
+ // with the TMP100.
+ //
+ tI2CMInstance *psI2CInst;
+
+ //
+ // The I2C address of the TMP100.
+ //
+ uint8_t ui8Addr;
+
+ //
+ // The state of the state machine used while accessing the TMP100.
+ //
+ uint8_t ui8State;
+
+ //
+ // The data buffer used for sending/receiving data to/from the TMP100.
+ //
+ uint8_t pui8Data[4];
+
+ //
+ // The function that is called when the current request has completed
+ // processing.
+ //
+ tSensorCallback *pfnCallback;
+
+ //
+ // The pointer provided to the callback function.
+ //
+ void *pvCallbackData;
+
+ //
+ // A union of structures that are used for read, write and
+ // read-modify-write operations. Since only one operation can be active at
+ // a time, it is safe to re-use the memory in this manner.
+ //
+ union
+ {
+ //
+ // A buffer used to store the write portion of a register read.
+ //
+ uint8_t pui8Buffer[2];
+
+ //
+ // The read state used to read register values.
+ //
+ tI2CMRead16BE sReadState;
+
+ //
+ // The write state used to write register values.
+ //
+ tI2CMWrite16BE sWriteState;
+
+ //
+ // The read-modify-write state used to modify 8-bit register values.
+ //
+ tI2CMReadModifyWrite8 sReadModifyWriteState8;
+
+ //
+ // The read-modify-write state used to modify 16-bit register values.
+ //
+ tI2CMReadModifyWrite16 sReadModifyWriteState16;
+ }
+ uCommand;
+}
+tTMP100;
+
+//*****************************************************************************
+//
+// Function prototypes.
+//
+//*****************************************************************************
+extern uint_fast8_t TMP100Init(tTMP100 *psInst, tI2CMInstance *psI2CInst,
+ uint_fast8_t ui8I2CAddr,
+ tSensorCallback *pfnCallback,
+ void *pvCallbackData);
+extern uint_fast8_t TMP100Read(tTMP100 *psInst, uint_fast8_t ui8Reg,
+ uint16_t *pui16Data, uint_fast16_t ui16Count,
+ tSensorCallback *pfnCallback,
+ void *pvCallbackData);
+extern uint_fast8_t TMP100Write(tTMP100 *psInst, uint_fast8_t ui8Reg,
+ const uint16_t *pui16Data,
+ uint_fast16_t ui16Count,
+ tSensorCallback *pfnCallback,
+ void *pvCallbackData);
+extern uint_fast8_t TMP100ReadModifyWrite(tTMP100 *psInst, uint_fast8_t ui8Reg,
+ uint_fast16_t ui16Mask,
+ uint_fast16_t ui16Value,
+ tSensorCallback *pfnCallback,
+ void *pvCallbackData);
+extern uint_fast8_t TMP100DataRead(tTMP100 *psInst,
+ tSensorCallback *pfnCallback,
+ void *pvCallbackData);
+extern void TMP100DataTemperatureGetRaw(tTMP100 *psInst,
+ int16_t *pui16Temperature);
+extern void TMP100DataTemperatureGetFloat(tTMP100 *psInst,
+ float *pfTemperature);
+
+//*****************************************************************************
+//
+// Mark the end of the C bindings section for C++ compilers.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __SENSORLIB_TMP100_H__
+
diff --git a/sensorlib/vector.c b/sensorlib/vector.c
new file mode 100644
index 0000000..208b671
--- /dev/null
+++ b/sensorlib/vector.c
@@ -0,0 +1,139 @@
+//*****************************************************************************
+//
+// vector.c - Functions for performing vector operations.
+//
+// Copyright (c) 2012-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
+//
+//*****************************************************************************
+
+#include "sensorlib/vector.h"
+
+//*****************************************************************************
+//
+//! \addtogroup vector_api
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+//! Computes the dot product of two vectors.
+//!
+//! \param pfVectorIn1 is the first vector.
+//! \param pfVectorIn2 is the second vector.
+//!
+//! This function computes the dot product of two 3-dimensional vector.
+//!
+//! \return Returns the dot product of the two vectors.
+//
+//*****************************************************************************
+float
+VectorDotProduct(float pfVectorIn1[3], float pfVectorIn2[3])
+{
+ //
+ // Compute and return the vector dot product.
+ //
+ return((pfVectorIn1[0] * pfVectorIn2[0]) +
+ (pfVectorIn1[1] * pfVectorIn2[1]) +
+ (pfVectorIn1[2] * pfVectorIn2[2]));
+}
+
+//*****************************************************************************
+//
+//! Computes the cross product of two vectors.
+//!
+//! \param pfVectorOut is the output vector.
+//! \param pfVectorIn1 is the first vector.
+//! \param pfVectorIn2 is the second vector.
+//!
+//! This function computes the cross product of two 3-dimensional vectors.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+VectorCrossProduct(float pfVectorOut[3], float pfVectorIn1[3],
+ float pfVectorIn2[3])
+{
+ //
+ // Compute the cross product of the input vectors.
+ //
+ pfVectorOut[0] = ((pfVectorIn1[1] * pfVectorIn2[2]) -
+ (pfVectorIn1[2] * pfVectorIn2[1]));
+ pfVectorOut[1] = ((pfVectorIn1[2] * pfVectorIn2[0]) -
+ (pfVectorIn1[0] * pfVectorIn2[2]));
+ pfVectorOut[2] = ((pfVectorIn1[0] * pfVectorIn2[1]) -
+ (pfVectorIn1[1] * pfVectorIn2[0]));
+}
+
+//*****************************************************************************
+//
+//! Scales a vector.
+//!
+//! \param pfVectorOut is the output vector.
+//! \param pfVectorIn is the input vector.
+//! \param fScale is the scale factor.
+//!
+//! This function scales a 3-dimensional vector by multiplying each of its
+//! components by the scale factor.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+VectorScale(float pfVectorOut[3], float pfVectorIn[3], float fScale)
+{
+ //
+ // Scale each component of the vector by the scale factor.
+ //
+ pfVectorOut[0] = pfVectorIn[0] * fScale;
+ pfVectorOut[1] = pfVectorIn[1] * fScale;
+ pfVectorOut[2] = pfVectorIn[2] * fScale;
+}
+
+//*****************************************************************************
+//
+//! Adds two vectors.
+//!
+//! \param pfVectorOut is the output vector.
+//! \param pfVectorIn1 is the first vector.
+//! \param pfVectorIn2 is the second vector.
+//!
+//! This function adds two 3-dimensional vectors.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+VectorAdd(float pfVectorOut[3], float pfVectorIn1[3], float pfVectorIn2[3])
+{
+ //
+ // Add the components of the two vectors.
+ //
+ pfVectorOut[0] = pfVectorIn1[0] + pfVectorIn2[0];
+ pfVectorOut[1] = pfVectorIn1[1] + pfVectorIn2[1];
+ pfVectorOut[2] = pfVectorIn1[2] + pfVectorIn2[2];
+}
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
diff --git a/sensorlib/vector.h b/sensorlib/vector.h
new file mode 100644
index 0000000..d18b1e2
--- /dev/null
+++ b/sensorlib/vector.h
@@ -0,0 +1,61 @@
+//*****************************************************************************
+//
+// vector.h - Prototypes for the vector functions.
+//
+// Copyright (c) 2012-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
+//
+//*****************************************************************************
+
+#ifndef __SENSORLIB_VECTOR_H__
+#define __SENSORLIB_VECTOR_H__
+
+//*****************************************************************************
+//
+// If building with a C++ compiler, make all of the definitions in this header
+// have a C binding.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+//*****************************************************************************
+//
+// Prototypes.
+//
+//*****************************************************************************
+extern float VectorDotProduct(float pfVectorIn1[3], float pfVectorIn2[3]);
+extern void VectorCrossProduct(float pfVectorOut[3], float pfVectorIn1[3],
+ float pfVectorIn2[3]);
+extern void VectorScale(float pfVectorOut[3], float pfVectorIn[3],
+ float fScale);
+extern void VectorAdd(float pfVectorOut[3], float pfVectorIn1[3],
+ float pfVectorIn2[3]);
+
+//*****************************************************************************
+//
+// Mark the end of the C bindings section for C++ compilers.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __SENSORLIB_VECTOR_H__