First Revision of sample code for interfacing ROHM Multi-Sensor Shield board with Nordic Semiconductor's nRF51-DK Development Kit Host BTLE Board

Dependencies:   BLE_API mbed nRF51822 Nordic_UART_TEMPLATE_ROHM

Dependents:   Nordic_UART_TEMPLATE_ROHM

Fork of UART_TEMPLATE by daniel veilleux

Code Example for ROHM Multi-Sensor Shield on the Nordic Semiconductor nRF51-DK

This code was written to be used with the Nordic Semiconductor nRF51-DK.

This is the basic example code for interfacing ROHM's Multi-sensor Shield Board onto this board.

Additional information about the ROHM MultiSensor Shield Board can be found at the following link: https://github.com/ROHMUSDC/ROHM_SensorPlatform_Multi-Sensor-Shield

For code example for the ROHM SENSORSHLD1-EVK-101, please see the following link: https://developer.mbed.org/teams/ROHMUSDC/code/Nordic_UART_TEMPLATE_ROHM_SHLD1Update/

Operation

Ultimately, this code will initialize all the sensors on the Multi-sensor shield board and then poll the sensors. The sensor data will then be returned to the BTLE COM port link and will be view-able on any BTLE enabled phone that can connect to the Nordic UART Application.

Supported ROHM Sensor Devices

  • BDE0600G Temperature Sensor
  • BM1383GLV Pressure Sensor
  • BU52014 Hall Sensor
  • ML8511 UV Sensor
  • RPR-0521 ALS/PROX Sensor
  • BH1745NUC Color Sensor
  • KMX62 Accel/Mag Sensor
  • KX122 Accel Sensor
  • KXG03 Gyro/Accel Sensor

Sensor Applicable Code Sections

  • Added a Section in "Main" to act as initialization
  • Added to the "Periodic Callback" to read sensor data and return to Phone/Host

Questions/Feedback

Please feel free to let us know any questions/feedback/comments/concerns on the shield implementation by contacting the following e-mail:

Revision:
5:d39ffc5638a3
Parent:
4:eabae2996ecc
Child:
6:6860e53dc7ae
--- a/main.cpp	Thu Aug 13 18:24:14 2015 +0000
+++ b/main.cpp	Thu Sep 24 22:23:31 2015 +0000
@@ -15,7 +15,7 @@
  */
  
  /*
- *  Added Functions for ROHM's Multi-Sensor Shield Board
+ *  Added Functions for interfacing with ROHM's Multi-Sensor Shield Board
  *  Supports the following Sensor Devices
  *      > BDE0600G Temperature Sensor
  *      > BM1383GLV Pressure Sensor
@@ -27,9 +27,15 @@
  *      > KX122 Accel Sensor
  *      > KXG03 Gyro (Currently Unavailable as IC hasn't docked yet)
  *
+ *
+ *  Last Upadtaed: 9/11/15
+ *
  *  New Code: 
  *      Added a Section in "Main" to act as initialization
  *      Added to the "Periodic Callback" to read sensor data and return to Phone/Host
+ *  
+ *  Additional information about the ROHM MultiSensor Shield Board can be found at the following link:
+ *      https://github.com/ROHMUSDC/ROHM_SensorPlatform_Multi-Sensor-Shield
  */ 
  
 
@@ -38,15 +44,12 @@
 #define AnalogUV    //ML8511
 #define HallSensor  //BU52011    //Change 1: Change to use GPIO for BU52014
 #define RPR0521     //RPR0521    //Change 2: Remove This and add in the RPR-0521
-#define KMX62                    //Change 3: Add Code For BH1745, KX022, BM1383GLV, KMX62
-                                
-//Devices To Add
-// PRessure Sensor
-// Accel Only - KX122
-// Check Functions for KMX62
-// Color Sensor
+#define KMX62                    //Change 3: Add Code For -BH1745-, -KX022, BM1383GLV, -KMX62-
+#define color
+#define KX022
+#define Pressure
 
-// Gyro last...
+
 
 
 #include "mbed.h"
@@ -55,8 +58,9 @@
 #include "nrf_temp.h"
 #include "I2C.h"
 
+
 #define MAX_REPLY_LEN           (UARTService::BLE_UART_SERVICE_MAX_DATA_LEN)    //Actually equal to 20
-#define SENSOR_READ_INTERVAL_S  (10.0F) 
+#define SENSOR_READ_INTERVAL_S  (5.0F) 
 #define ADV_INTERVAL_MS         (1000UL)
 #define UART_BAUD_RATE          (19200UL)
 #define DEVICE_NAME             ("DEMO SENSOR") // This can be read AFTER connecting to the device.
@@ -100,7 +104,10 @@
 bool        RepStart = true;
 bool        NoRepStart = false;
 
-#ifdef RPR0521
+int i=1;
+
+
+#ifdef RPR0521     //als digital
 int         RPR0521_addr_w = 0x70;          //7bit addr = 0x38, with write bit 0
 int         RPR0521_addr_r = 0x71;          //7bit addr = 0x38, with read bit 1
 
@@ -128,20 +135,93 @@
 char        KMX62_Addr_Mag_ReadData = 0x10;
 char        KMX62_Content_Mag_ReadData[6];
 
-int         MEMS_Accel_Xout = 0;
-int         MEMS_Accel_Yout = 0;
-int         MEMS_Accel_Zout = 0;
-float       MEMS_Accel_Conv_Xout = 0;
-float       MEMS_Accel_Conv_Yout = 0;
-float       MEMS_Accel_Conv_Zout = 0;
-int         MEMS_Mag_Xout = 0;
-int         MEMS_Mag_Yout = 0;
-int         MEMS_Mag_Zout = 0;
+short int         MEMS_Accel_Xout = 0;
+short int         MEMS_Accel_Yout = 0;
+short int         MEMS_Accel_Zout = 0;
+double       MEMS_Accel_Conv_Xout = 0;
+double       MEMS_Accel_Conv_Yout = 0;
+double       MEMS_Accel_Conv_Zout = 0;
+short int         MEMS_Mag_Xout = 0;
+short int         MEMS_Mag_Yout = 0;
+short int         MEMS_Mag_Zout = 0;
 float       MEMS_Mag_Conv_Xout = 0;
 float       MEMS_Mag_Conv_Yout = 0;
 float       MEMS_Mag_Conv_Zout = 0;
 #endif
 
+#ifdef color
+int         BH1745_addr_w = 0x72;   //write 
+int         BH1745_addr_r = 0x73;   //read 
+
+char        BH1745_persistence[2] = {0x61, 0x03};
+char        BH1745_mode1[2] = {0x41, 0x00};
+char        BH1745_mode2[2] = {0x42, 0x92};
+char        BH1745_mode3[2] = {0x43, 0x02};
+
+char        BH1745_Content_ReadData[6];
+char        BH1745_Addr_color_ReadData = 0x50;
+
+int        BH1745_Red;
+int        BH1745_Blue;
+int        BH1745_Green;
+
+#endif
+
+#ifdef KX022
+int         KX022_addr_w = 0x3C;   //write 
+int         KX022_addr_r = 0x3D;   //read 
+
+char        KX022_Accel_CNTL1[2] = {0x18, 0x41};
+char        KX022_Accel_ODCNTL[2] = {0x1B, 0x02};
+char        KX022_Accel_CNTL3[2] = {0x1A, 0xD8};
+char        KX022_Accel_TILT_TIMER[2] = {0x22, 0x01};
+char        KX022_Accel_CNTL2[2] = {0x18, 0xC1};
+
+char        KX022_Content_ReadData[6];
+char        KX022_Addr_Accel_ReadData = 0x06;           
+
+float        KX022_Accel_X;
+float        KX022_Accel_Y;                               
+float        KX022_Accel_Z;
+
+short int KX022_Accel_X_RawOUT = 0;
+short int KX022_Accel_Y_RawOUT = 0;
+short int KX022_Accel_Z_RawOUT = 0;
+
+int KX022_Accel_X_LB = 0;
+int KX022_Accel_X_HB = 0;
+int KX022_Accel_Y_LB = 0;
+int KX022_Accel_Y_HB = 0;
+int KX022_Accel_Z_LB = 0;
+int KX022_Accel_Z_HB = 0;
+
+#endif
+
+#ifdef Pressure
+int         Press_addr_w = 0xBA;   //write 
+int         Press_addr_r = 0xBB;   //read 
+
+char        PWR_DOWN[2] = {0x12, 0x01};
+char        SLEEP[2] = {0x13, 0x01};
+char        Mode_Control[2] = {0x14, 0xC4};
+
+char        Press_Content_ReadData[6];
+char        Press_Addr_ReadData =0x1A;
+
+int         BM1383_Temp_highByte;
+int         BM1383_Temp_lowByte;
+int         BM1383_Pres_highByte;
+int         BM1383_Pres_lowByte;
+int         BM1383_Pres_leastByte; 
+
+float       BM1383_Temp_Out;
+float       BM1383_Temp_Conv_Out;
+float       BM1383_Pres_Conv_Out;
+
+float       BM1383_Var;
+float       BM1383_Deci;
+#endif
+
 /**
  * This callback is used whenever a disconnection occurs.
  */
@@ -226,18 +306,50 @@
     uint32_t len = 0;
     
 
-/*    
+if(i==1)
+{
+/*
 #ifdef AnalogALS
     if (m_ble.getGapState().connected) {
         BH1620_ALS_value = BH1620_ALS.read_u16();
         BH1620_output = (float)BH1620_ALS_value * 1.543;
         
-        len = snprintf((char*) buf, MAX_REPLY_LEN, "ALS = %.2f lx", BH1620_output);
+        len = snprintf((char*) buf, MAX_REPLY_LEN, "Analog ALS = %.2f lx", BH1620_output);
         m_ble.updateCharacteristicValue(m_uart_service_ptr->getRXCharacteristicHandle(), buf, len);
     }
 #endif
 */
 
+#ifdef color
+if (m_ble.getGapState().connected) {
+        //Read color Portion from the IC
+        i2c.write(BH1745_addr_w, &BH1745_Addr_color_ReadData, 1, RepStart);
+        i2c.read(BH1745_addr_r, &BH1745_Content_ReadData[0], 6, NoRepStart);
+        
+        //separate all data read into colors
+        
+        BH1745_Red = (BH1745_Content_ReadData[1]<<8) | (BH1745_Content_ReadData[0]);
+        BH1745_Green = (BH1745_Content_ReadData[3]<<8) | (BH1745_Content_ReadData[2]);
+        BH1745_Blue = (BH1745_Content_ReadData[5]<<8) | (BH1745_Content_ReadData[4]);
+    
+        
+        //transmit data 
+        len = snprintf((char*) buf, MAX_REPLY_LEN, "Red= %d", BH1745_Red);
+        m_ble.updateCharacteristicValue(m_uart_service_ptr->getRXCharacteristicHandle(), buf, len);
+         wait_ms(25);
+       
+        
+        len = snprintf((char*) buf, MAX_REPLY_LEN, "Green= %d", BH1745_Green);
+        m_ble.updateCharacteristicValue(m_uart_service_ptr->getRXCharacteristicHandle(), buf, len);
+        wait_ms(25);
+        
+        len = snprintf((char*) buf, MAX_REPLY_LEN, "Blue= %d", BH1745_Blue);
+        m_ble.updateCharacteristicValue(m_uart_service_ptr->getRXCharacteristicHandle(), buf, len);
+        wait_ms(25);   
+                     
+}
+#endif
+
 #ifdef AnalogTemp
     if (m_ble.getGapState().connected) {
         BDE0600_Temp_value = BDE0600_Temp.read_u16();
@@ -252,8 +364,8 @@
 #ifdef AnalogUV
     if (m_ble.getGapState().connected) {
         ML8511_UV_value = ML8511_UV.read_u16();
-        ML8511_output = (float)ML8511_UV_value * 0.00283; //(value * (2.9V/1024))   //Note to self: when playing with this, a negative value is seen... Honestly, I think this has to do with my ADC converstion...
-        ML8511_output = (ML8511_output-2.2)/(0.129) + 15;                           // Added +5 to the offset so when inside (aka, no UV, readings show 0)... this is the wrong approach... and the readings don't make sense... Fix this.
+        ML8511_output = (float)ML8511_UV_value * 0.0029; //(value * (2.9V/1024))   //Note to self: when playing with this, a negative value is seen... Honestly, I think this has to do with my ADC converstion...
+        ML8511_output = (ML8511_output-2.2)/(0.129) + 10;                           // Added +5 to the offset so when inside (aka, no UV, readings show 0)... this is the wrong approach... and the readings don't make sense... Fix this.
         
         len = snprintf((char*) buf, MAX_REPLY_LEN, "UV = %.1f mW/cm2", ML8511_output);
         m_ble.updateCharacteristicValue(m_uart_service_ptr->getRXCharacteristicHandle(), buf, len);
@@ -276,12 +388,12 @@
         ALS_Return = (ALS_ReturnData_raw[0]<<8) | ALS_ReturnData_raw[1];
         ALS_Return = ALS_Return/1.2;
         
-        len = snprintf((char*) buf, MAX_REPLY_LEN, "DALS= %0.2f lx", ALS_Return);
+        len = snprintf((char*) buf, MAX_REPLY_LEN, "DAL1= %0.2f lx", ALS_Return);
         m_ble.updateCharacteristicValue(m_uart_service_ptr->getRXCharacteristicHandle(), buf, len);
     }
 #endif
 
-#ifdef RPR0521
+#ifdef RPR0521       //als digital
     if (m_ble.getGapState().connected) {
         
         i2c.write(RPR0521_addr_w, &RPR0521_Addr_ReadData, 1, RepStart);
@@ -310,9 +422,17 @@
         
         len = snprintf((char*) buf, MAX_REPLY_LEN, "DALS= %0.2f lx", RPR0521_ALS_OUT);
         m_ble.updateCharacteristicValue(m_uart_service_ptr->getRXCharacteristicHandle(), buf, len);
+       
     }
 #endif
 
+i++;
+
+}
+
+else if(i==2)
+{
+
 #ifdef KMX62
     if (m_ble.getGapState().connected) {
         //Read Accel Portion from the IC
@@ -328,10 +448,10 @@
         //Note: Conversion to G is as follows:
         //      Axis_ValueInG = MEMS_Accel_axis / 1024
         //      However, since we did not remove the LSB previously, we need to divide by 4 again
-        //      Thus, we will divide the output by 4095 (1024*4) to convert and cancel out the LSB
-        MEMS_Accel_Conv_Xout = (float)MEMS_Accel_Xout/4096/2;
-        MEMS_Accel_Conv_Yout = (float)MEMS_Accel_Yout/4096/2;
-        MEMS_Accel_Conv_Zout = (float)MEMS_Accel_Zout/4096/2;
+        //      Thus, we will divide the output by 4096 (1024*4) to convert and cancel out the LSB
+        MEMS_Accel_Conv_Xout = ((float)MEMS_Accel_Xout/4096/2);
+        MEMS_Accel_Conv_Yout = ((float)MEMS_Accel_Yout/4096/2);
+        MEMS_Accel_Conv_Zout = ((float)MEMS_Accel_Zout/4096/2);
 
         //Read MAg portion from the IC
         i2c.write(KMX62_addr_w, &KMX62_Addr_Mag_ReadData, 1, RepStart);
@@ -347,47 +467,126 @@
         //      Axis_ValueInG = MEMS_Accel_axis / 1024
         //      However, since we did not remove the LSB previously, we need to divide by 4 again
         //      Thus, we will divide the output by 4095 (1024*4) to convert and cancel out the LSB
-        MEMS_Mag_Conv_Xout = (float)MEMS_Mag_Xout*0.146;
-        MEMS_Mag_Conv_Yout = (float)MEMS_Mag_Yout*0.146;
-        MEMS_Mag_Conv_Zout = (float)MEMS_Mag_Zout*0.146;
+        MEMS_Mag_Conv_Xout = (float)MEMS_Mag_Xout/4096*0.146;
+        MEMS_Mag_Conv_Yout = (float)MEMS_Mag_Yout/4096*0.146;
+        MEMS_Mag_Conv_Zout = (float)MEMS_Mag_Zout/4096*0.146; 
+
+        // transmit data
+        
 
         len = snprintf((char*) buf, MAX_REPLY_LEN, "KMX61SensorData:");
         m_ble.updateCharacteristicValue(m_uart_service_ptr->getRXCharacteristicHandle(), buf, len);
-        wait_ms(1000);
+        wait_ms(20);
 
         len = snprintf((char*) buf, MAX_REPLY_LEN, " AccX= %0.2f g", MEMS_Accel_Conv_Xout);
         m_ble.updateCharacteristicValue(m_uart_service_ptr->getRXCharacteristicHandle(), buf, len);
-        wait_ms(1000);
+        wait_ms(20);
         
         len = snprintf((char*) buf, MAX_REPLY_LEN, " AccY= %0.2f g", MEMS_Accel_Conv_Yout);
         m_ble.updateCharacteristicValue(m_uart_service_ptr->getRXCharacteristicHandle(), buf, len);
-        wait_ms(1000);
+        wait_ms(20);
         
         len = snprintf((char*) buf, MAX_REPLY_LEN, " AccZ= %0.2f g", MEMS_Accel_Conv_Zout);
         m_ble.updateCharacteristicValue(m_uart_service_ptr->getRXCharacteristicHandle(), buf, len);
-        wait_ms(1000);
+        wait_ms(20);
         
         len = snprintf((char*) buf, MAX_REPLY_LEN, " MagX= %0.2f g", MEMS_Mag_Conv_Xout);
         m_ble.updateCharacteristicValue(m_uart_service_ptr->getRXCharacteristicHandle(), buf, len);
-        wait_ms(1000);
+        wait_ms(20);
         
         len = snprintf((char*) buf, MAX_REPLY_LEN, " MagY= %0.2f g", MEMS_Mag_Conv_Yout);
         m_ble.updateCharacteristicValue(m_uart_service_ptr->getRXCharacteristicHandle(), buf, len);
-        wait_ms(1000);
+        wait_ms(20);
         
         len = snprintf((char*) buf, MAX_REPLY_LEN, " MagZ= %0.2f g", MEMS_Mag_Conv_Zout);
         m_ble.updateCharacteristicValue(m_uart_service_ptr->getRXCharacteristicHandle(), buf, len);
-        wait_ms(1000);
+        wait_ms(20); 
+        
     }
 #endif
 
-    if (m_ble.getGapState().connected) {
-        len = snprintf((char*) buf, MAX_REPLY_LEN, "               ");         //Print and Extra Line to show new data
-        m_ble.updateCharacteristicValue(m_uart_service_ptr->getRXCharacteristicHandle(), buf, len);
-    }
+i++;
+
 }
 
 
+else if(i==3)
+{
+
+
+
+#ifdef KX022
+if (m_ble.getGapState().connected) {
+        //Read KX022 Portion from the IC
+        i2c.write(KX022_addr_w, &KX022_Addr_Accel_ReadData, 1, RepStart);
+        i2c.read(KX022_addr_r, &KX022_Content_ReadData[0], 6, NoRepStart);
+        
+            
+        //reconfigure the data (taken from arduino code)
+        KX022_Accel_X_RawOUT = (KX022_Content_ReadData[1]<<8) | (KX022_Content_ReadData[0]);
+        KX022_Accel_Y_RawOUT = (KX022_Content_ReadData[3]<<8) | (KX022_Content_ReadData[2]);
+        KX022_Accel_Z_RawOUT = (KX022_Content_ReadData[5]<<8) | (KX022_Content_ReadData[4]);       
+
+        //apply needed changes (taken from arduino code)
+        KX022_Accel_X = (float)KX022_Accel_X_RawOUT / 16384;
+        KX022_Accel_Y = (float)KX022_Accel_Y_RawOUT / 16384;
+        KX022_Accel_Z = (float)KX022_Accel_Z_RawOUT / 16384;
+        
+        
+        
+        //transmit the data
+        len = snprintf((char*) buf, MAX_REPLY_LEN, "KX022-X= %0.2f", KX022_Accel_X);
+        m_ble.updateCharacteristicValue(m_uart_service_ptr->getRXCharacteristicHandle(), buf, len);
+        wait_ms(25);
+        
+        len = snprintf((char*) buf, MAX_REPLY_LEN, "KX022-Y= %0.2f", KX022_Accel_Y);
+        m_ble.updateCharacteristicValue(m_uart_service_ptr->getRXCharacteristicHandle(), buf, len);
+        wait_ms(25);
+        
+        len = snprintf((char*) buf, MAX_REPLY_LEN, "KX022-Z= %0.2f", KX022_Accel_Z);
+        m_ble.updateCharacteristicValue(m_uart_service_ptr->getRXCharacteristicHandle(), buf, len);
+        wait_ms(25);
+        
+ }   
+#endif
+
+#ifdef Pressure
+if (m_ble.getGapState().connected) {
+        //Read color Portion from the IC
+        i2c.write(Press_addr_w, &Press_Addr_ReadData, 1, RepStart);
+        i2c.read(Press_addr_r, &Press_Content_ReadData[0], 6, NoRepStart);
+        
+       
+        
+        BM1383_Temp_Out = (Press_Content_ReadData[1]<<8) | (Press_Content_ReadData[0]);
+        BM1383_Temp_Conv_Out = (float)BM1383_Temp_Out/32;
+        
+        BM1383_Var  = (Press_Content_ReadData[2]<<3) | (Press_Content_ReadData[3] >> 5);
+        BM1383_Deci = ((Press_Content_ReadData[3] & 0x1f) << 6 | ((Press_Content_ReadData[4] >> 2)));
+        BM1383_Deci = (float)BM1383_Deci* 0.00048828125;  //0.00048828125 = 2^-11
+        BM1383_Pres_Conv_Out = (BM1383_Var + BM1383_Deci);   //question pending here...
+        
+         len = snprintf((char*) buf, MAX_REPLY_LEN, "Temp_out= %0.2f", BM1383_Temp_Out);
+         m_ble.updateCharacteristicValue(m_uart_service_ptr->getRXCharacteristicHandle(), buf, len);
+         wait_ms(25);
+        
+         len = snprintf((char*) buf, MAX_REPLY_LEN, "Temp_conv= %0.2f", BM1383_Temp_Conv_Out);
+         m_ble.updateCharacteristicValue(m_uart_service_ptr->getRXCharacteristicHandle(), buf, len);
+         wait_ms(25);
+        
+         len = snprintf((char*) buf, MAX_REPLY_LEN, "Press_conv= %0.2f", BM1383_Pres_Conv_Out);
+         m_ble.updateCharacteristicValue(m_uart_service_ptr->getRXCharacteristicHandle(), buf, len);
+         wait_ms(25);
+}        
+#endif  
+      
+i=1;
+
+}
+
+
+
+}
 void error(ble_error_t err, uint32_t line)
 {
     m_error_led = 1;
@@ -430,7 +629,7 @@
 
     sw4Press.fall(&PBTrigger);
 
-#ifdef RPR0521
+#ifdef RPR0521       //als digital
   // 1. Mode Control (0x41), write (0xC6): ALS EN, PS EN, 100ms measurement for ALS and PS, PS_PULSE=1
   // 2. ALS_PS_CONTROL (0x42), write (0x03): LED Current = 200mA
   // 3. PERSIST (0x43), write (0x20): PS Gain x4  
@@ -444,6 +643,32 @@
     i2c.write(KMX62_addr_w, &KMX62_CNTL2[0], 2, false);
 #endif
 
+#ifdef color
+  // 1. CNTL2 (0x3A), write (0x5F): 4g, Max RES, EN temp mag and accel
+    i2c.write(BH1745_addr_w, &BH1745_persistence[0], 2, false);
+    i2c.write(BH1745_addr_w, &BH1745_mode1[0], 2, false);
+    i2c.write(BH1745_addr_w, &BH1745_mode2[0], 2, false);
+    i2c.write(BH1745_addr_w, &BH1745_mode3[0], 2, false);
+#endif
+
+#ifdef KX022
+
+i2c.write(KX022_addr_w, &KX022_Accel_CNTL1[0], 2, false);
+i2c.write(KX022_addr_w, &KX022_Accel_ODCNTL[0], 2, false);
+i2c.write(KX022_addr_w, &KX022_Accel_CNTL3[0], 2, false);
+i2c.write(KX022_addr_w, &KX022_Accel_TILT_TIMER[0], 2, false);
+i2c.write(KX022_addr_w, &KX022_Accel_CNTL2[0], 2, false);
+
+#endif
+
+#ifdef Pressure
+
+i2c.write(Press_addr_w, &PWR_DOWN[0], 2, false);
+i2c.write(Press_addr_w, &SLEEP[0], 2, false);
+i2c.write(Press_addr_w, &Mode_Control[0], 2, false);
+
+#endif
+
 //Start BTLE Initialization Section
     m_ble.init();
     m_ble.onDisconnection(disconnectionCallback);
@@ -494,4 +719,4 @@
     while (true) {
         m_ble.waitForEvent();
     }
-}
+}
\ No newline at end of file