## @file  SensorDemo_Central.py
## @brief This script implements a basic version of the BlueNRG/BlueNRG-MS Sensor Profile Central role which emulates the BlueNRG/BlueNRG-MS Sensor Demo applications available for smartphones (iOS and android). This script configures a BlueNRG/BlueNRG-MS device as a BlueNRG/BlueNRG-MS Sensor device, Central role which is able to find, connect and properly configure the free fall, acceleration and environment sensors characteristics provided by a BlueNRG/BlueNRG-MS development platform  configured as a BlueNRG/BlueNRG-MS Sensor device, Peripheral role. 
## @li The script is implemented using the new BlueNRG GUI language scripts based on the BlueNRG/BlueNRG-MS ACI APIs. The BlueNRG GUI with script engine is delivered within BlueNRG DK 1.7.0 SW package and coming next versions.
## @li A PC running Windows Vista/7 operating systems (64 and 32 bit version) or Windows XP operating systems (32 bit edition), with available USB ports is required for installing the BlueNRG/BlueNRG-MS DK SW package.
##
## <!-- Copyright 2015 by STMicroelectronics.  All rights reserved.       *80*-->
##
##  @section S2 SensorDemo_Central.py script, preliminary setup steps: configure a BlueNRG/BlueNRG-MS platform as a BlueNRG/BlueNRG-MS Sensor device, Peripheral role. 
##
##  @li Connect a BlueNRG/BlueNRG-MS development platform (order code: STEVAL-IDB002V1) to a PC USB port
##  @li Open the Embedded Workbench for ARM.
##  @li From the File->Open->Workspace menu, open the IAR workspace available on BlueNRG/BlueNRG-MS DK SW package: "Projects\Project\SensorDemo\EWARM\SensorDemo.eww"
##  @li Select desired configuration to build
##  @li Select Project->Rebuild All. This will recompile and link the entire application
##  @li To download the binary image on the BlueNRG/BlueNRG-MS development platform, please connect STLink to JTAG connector  in your board
##  @li Select Project->Download and Debug to download the related binary image
##  @li Alternatively, open the BlueNRG GUI, put the board in DFU mode and download the built binary image
##  @li NOTE: BlueNRG/BlueNRG-MS Sensor Demo, Peripheral role prebuilt binary image is also available on BlueNRG/BlueNRG-MS DK SW package: "Firmware\STM32L1_prebuilt_images\BlueNRG\BlueNRG_SensorDemo.hex, Firmware\STM32L1_prebuilt_images\BlueNRG-MS\BlueNRG-MS_SensorDemo.hex "
##
##  @section S21 SensorDemo_Central.py script execution steps through BlueNRG GUI Script Engine
##
##  @li Open BlueNRG GUI available within BlueNRG DK 1.7.0 SW package (and coming next versions)
##  @li Connect a BlueNRG/BlueNRG-MS platform to a PC USB port
##  @li Put the BlueNRG/BlueNRG-MS platform in DFU mode and download the "C:\Program Files (x86)\STMicroelectronics\BlueNRG DK 1.x.0\Firmware\STM32L1_prebuilt_images\BlueNRG_VCOM_1_x.hex" using the BlueNRG GUI, Tools, Flash Motherboard FW... utility
##  @li On BlueNRG GUI, open the USB Port associated to the plugged BlueNRG/BlueNRG-MS platform
##  @li On BlueNRG GUI, select the Scripts window 
##  @li On BlueNRG GUI, Scripts window, Scripts Engine section, click on ... tab and browse to the script location and select  it
##  @li On BlueNRG GUI, click on  Run Script tab for running the selected script
##  @li BlueNRG/BlueNRG-MS SensorDemo, Central device will look for BlueNRG/BlueNRG-MS advertising devices. Then it will connect to first discovered BlueNRG/BlueNRG-MS Sensor Demo, Peripheral device and it will enable the related characteristic notifications
##  @li BlueNRG/BlueNRG-MS SensorDemo, Central device reads three times the temperature characteristic  and it receives back the related  values (EVT-BLUE_ATT_READ_RESP) from the BlueNRG/BlueNRG-MS Sensor, Peripheral device (temperature value is printed on GUI "Sent/Received Packets" section)
##  @li Once the acceleration characteristic notification is enabled from the BlueNRG/BlueNRG-MS SensorDemo, Central device, the associated ACI_GATT_NOTIFICATION_EVENT events are received and the acceleration values on the threee axis (x,y,z) are displayed on GUI "Sent/Received Packets" section (further the free fall condition is detected)
##  @li For terminating the script (and closing the current active BLE connection), click on "Terminate Script" tab
##
##  @section S22 Supported BlueNRG/BlueNRG-MS platforms
##
##  @li BlueNRG development platform (order code: STEVAL-IDB002V1)
##  @li BlueNRG USB dongle (order code: STEVAL-IDB003V1)
##  @li BlueNRG-MS development platform (order code: STEVAL-IDB005V1) 
##  @li BlueNRG-MS Daughter Board (order code: STEVAL-IDB005V1D)
##  @li BlueNRG-MS USB dongle (order code: STEVAL-IDB006V1)
## 
##  @section S23 Supported BLE devices and stack versions
##
##  @li BlueNRG stack v6.4
##  @li BlueNRG-MS stack v7.x
##

## \addtogroup BlueNRG_and_BlueNRG_MS_scripts
## @{
## \see SensorDemo_Central.py for documentation.
## 
## @} 

## @cond DOXYGEN_SHOULD_SKIP_THIS

### NOTE:
## For Services & Characteristics handles values refer to BlueNRG/BlueNRG-MS sensor demo GATT database
## Figure on BlueNRG/BlueNRG-MS Development Kit User Manual UM1686.

#Device Name Characteristic UUID
DEVICE_NAME_CHAR_UUID= 0x2A00


# Acceleration service 128 bits UUID
ACCELERATION_SERVICE_UUID=[0x1B,0xC5,0xD5,0xA5,0x02,0x00,0xB4,0x9A,0xE1,0x11,0x3A,0xCF,0x80,0x6E,0x36,0x02]
# Free Fall characteristic 128 bits UUID
FREE_FALL_CHAR_UUID = [0x1B,0xC5,0xD5,0xA5,0x02,0x00,0xFC,0x8F,0xE1,0x11,0x4A,0xCF,0xA0,0x78,0x3E,0xE2]
# Acceleration characteristic 128 bits UUID
ACCELERATION_CHAR_UUID = [0x1B,0xC5,0xD5,0xA5,0x02,0x00,0x36,0xAC,0xE1,0x11,0x4B,0xCF,0x80,0x1B,0x0A,0x34]


# Environmental service 128 bits UUID
ENVIRONMENTAL_SERVICE_UUID=[0x1B,0xC5,0xD5,0xA5,0x02,0x00,0xD0,0x82,0xE2,0x11,0x77,0xE4,0x40,0x1A,0x82,0x42]
#Temperature characteristic
TEMPERATURE_CHAR_UUID =[0x1B,0xC5,0xD5,0xA5,0x02,0x00,0xE3,0xA9,0xE2,0x11,0x77,0xE4,0x20,0x55,0x2E,0xA3]         

   
#HW Reset and Address configuration
HW_RESET()

status = SET_PUBLIC_ADDRESS()
if status!=0x00:
    ERROR('SET_PUBLIC_ADDRESS FAILED')

#Set TX Power
status = ACI_HAL_SET_TX_POWER_LEVEL(En_High_Power=0x01,PA_Level=0x4)
if status!=0x00:
    ERROR('ACI_HAL_SET_TX_POWER_LEVEL FAILED')


#  ACI_GATT_INIT 
if  ACI_GATT_INIT()!=0x00:
    ERROR('ACI_GATT_INIT FAILED')

## ACI_GAP_INIT returns four parameters (refer to UM1755 for detailed API description)
status,_,_,_=  ACI_GAP_INIT(Role=CENTRAL)
if status !=0x00:
    ERROR('ACI_GAP_INIT CALL FAILED')

# Clear Security Database
status= ACI_GAP_CLEAR_SECURITY_DB()
if status!=0x00:
    ERROR('ACI_GAP_CLEAR_SECURITY_DB FAILED')

status=ACI_GAP_START_GENERAL_DISCOVERY_PROC()

if status!=0x00:
    ERROR('ACI_GAP_START_GENERAL_DISCOVERY_PROC FAILED')

listOfDeviceInADV=[]  #List of Device in Advertising with Name = 'BlueNRG'
while (True):
    event = WAIT_EVENT()
   
    if event.event_code==HCI_VENDOR_EVENT and event.get_param('Ecode').val==ACI_GAP_PROC_COMPLETE_EVENT:
        break
    elif (event.event_code==HCI_VENDOR_EVENT and event.get_param('Ecode').val==ACI_GAP_DEVICE_FOUND_EVENT and event.get_param('Event_Type').val != 0x4) :  #SCAN_RSP    :
            name=GET_NAME(event.get_param('Data').val)
            if name==None:
                continue

            #Check Device name in advertising message
            if name=='BlueNRG':             
                type_address =event.get_param('Address_Type').val
                address =event.get_param('Address').val                
                if type_address!=None and address!=None:
                    #If the device is not already inserted, insert it in the list of device in advertising
                    if ([type_address,address] in listOfDeviceInADV)==False:
                        listOfDeviceInADV.insert(0,[type_address,address])
                        
    elif event.event_code==HCI_LE_META_EVENT and event.get_param('Subevent_Code').val==HCI_LE_ADVERTISING_REPORT_EVENT and event.get_param('Event_Type').val[0] != 0x4:  #SCAN_RSP    :
        name=GET_NAME(event.get_param('Data').val[0])
        if name==None:
            continue

        #Check Device name in advertising message
        if name=='BlueNRG':               
            type_address =event.get_param('Address_Type').val[0]
            address =event.get_param('Address').val[0]              
            if type_address!=None and address!=None:
                #If the device is not already inserted, insert it in the list of device in advertising
                if ([type_address,address] in listOfDeviceInADV)==False:
                    listOfDeviceInADV.insert(0,[type_address,address])
        
           
# Check if no device has been discovered 
if (listOfDeviceInADV ==[]):
    ERROR('FAILURE: No BlueNRG SensorDemo discovered')

# Connect to first detected BlueNRG/BlueNRG-MS Sensor Demo device 
status=ACI_GAP_CREATE_CONNECTION(Peer_Address_Type=listOfDeviceInADV[0][0],
                                  Peer_Address=listOfDeviceInADV[0][1])

if status!=0x00:
    ERROR('ACI_GAP_CREATE_CONNECTION FAILED')
    
WAIT_EVENT(HCI_VENDOR_EVENT,Ecode=ACI_GAP_PROC_COMPLETE_EVENT )
event = WAIT_EVENT(HCI_LE_META_EVENT, timeout=30, Subevent_Code=HCI_LE_CONNECTION_COMPLETE_EVENT )
if event.get_param('Status').val==0x00:
    conn_handle= event.get_param('Connection_Handle').val
else:
    ERROR('NO CONNECTION ESTABLISHED')

#DISCOVERY OF ALL SERVICES   
#Search ACCELERATION Service
found=False
status=ACI_GATT_DISC_PRIMARY_SERVICE_BY_UUID(Connection_Handle=conn_handle, UUID_Type=0x02, UUID_128=ACCELERATION_SERVICE_UUID)
if (status != 0x00):
    ERROR('DISCOVERY PRIMARY SERVICE (ACCELERATION SERIVCE) FAILED')
                                             
eCode = ACI_GATT_DISC_READ_CHAR_BY_UUID_RESP_EVENT
while (eCode != ACI_GATT_PROC_COMPLETE_EVENT):
    e = WAIT_EVENT(HCI_VENDOR_EVENT, timeout=30)
    eCode = e.get_param('Ecode').val
    if (eCode == ACI_ATT_FIND_BY_TYPE_VALUE_RESP_EVENT):
        found=True
    elif (eCode == ACI_GATT_ERROR_RESP_EVENT):
        if not found:
            ERROR('ACCELERATION SERVICE NOT FOUND')
            
found=False
###Read ENVIRONMENTAL Services
status=ACI_GATT_DISC_PRIMARY_SERVICE_BY_UUID(Connection_Handle=conn_handle, UUID_Type=0x02, UUID_128=ENVIRONMENTAL_SERVICE_UUID)
if (status != 0x00):
    ERROR('DISCOVERY PRIMARY SERVICE (ENVIRONMENTAL SERIVCE) FAILED')
                                             
eCode = ACI_GATT_DISC_READ_CHAR_BY_UUID_RESP_EVENT
while (eCode != ACI_GATT_PROC_COMPLETE_EVENT):
    e = WAIT_EVENT(HCI_VENDOR_EVENT, timeout=30)
    eCode = e.get_param('Ecode').val
    if (eCode == ACI_ATT_FIND_BY_TYPE_VALUE_RESP_EVENT):
        found=True
    elif (eCode == ACI_GATT_ERROR_RESP_EVENT):
        if not found:
            ERROR('ENVIRONMENTAL SERVICE NOT FOUND')

#Read Device Name with UUID 0x2A00 on Service 0x1800 (GAP Profile Service)
status= ACI_GATT_READ_USING_CHAR_UUID(Connection_Handle=conn_handle,
                   Start_Handle=0x0001, End_Handle=0xffff, UUID_Type=0x01, UUID_16=DEVICE_NAME_CHAR_UUID)  
if (status != 0x00):
    ERROR  ('READ DEVICE NAME CHARACTERISTIC FAILED')

# Check expected device name: BlueNRG [0x42,0x6C,0x75,0x65,0x4E,0x52,0x47]
eCode = ACI_GATT_DISC_READ_CHAR_BY_UUID_RESP_EVENT
deviceName =[0x42,0x6C,0x75,0x65,0x4E,0x52,0x47]  #BlueNRG
while (eCode != ACI_GATT_PROC_COMPLETE_EVENT):
    e = WAIT_EVENT(HCI_VENDOR_EVENT, timeout=30)
    eCode = e.get_param('Ecode').val
    if (eCode == ACI_GATT_DISC_READ_CHAR_BY_UUID_RESP_EVENT):
        if (e.get_param('Attribute_Value').val  != deviceName):
            ERROR ('DEVICE NAME IS NOT BlueNRG!')

###Discovery all characteristics of Service Changed  
status =  ACI_GATT_DISC_ALL_CHAR_OF_SERVICE( Connection_Handle=conn_handle,Start_Handle=1, End_Handle=4)
if (status != 0x00):
    ERROR('SERVICE CHANGED FAILED')

eCode = ACI_ATT_READ_BY_TYPE_RESP_EVENT
#servChanged = [0x08,0x07,0x02,0x00,0x20,0x03,0x00,0x05,0x2A]
while (eCode != ACI_GATT_PROC_COMPLETE_EVENT):
    e = WAIT_EVENT(HCI_VENDOR_EVENT, timeout=30)
    eCode = e.get_param('Ecode').val
    if (eCode == ACI_ATT_READ_BY_TYPE_RESP_EVENT):
        if ( e.get_param('Attribute_Handles').val == 0x0002) and  (e.get_param('Attribute_Values').val[0] !=[0x03,0x00,0x05,0x2A]):
            ERROR ('READ SERVICE CHANGED FAILED')

# Enable indication for  Service Changed Characteristic 
status =  ACI_GATT_WRITE_CHAR_VALUE(Connection_Handle=conn_handle, Attr_Handle=0x0004, Attribute_Val_Length=2, Attribute_Val=0x0002)
if (status!= 0x00):
    ERROR('ENABLE INDICATION SERVICE CHANGED FAILED')

e = WAIT_EVENT(HCI_VENDOR_EVENT, timeout=30, Ecode=ACI_GATT_PROC_COMPLETE_EVENT)


############################################
#Discovery Sensor Demo Characteristics
############################################

##Discovery Acceleration Service Characteristic

##Free Fall  characteristic
found=False
status= ACI_GATT_DISC_CHAR_BY_UUID(Connection_Handle=conn_handle, Start_Handle=0x0001, End_Handle=0xffff, UUID_Type=0x02, UUID_128=FREE_FALL_CHAR_UUID)
if (status != 0x00):
    ERROR('DISCOVERY FREE FALL ACCELERATION CHARACTERISTIC FAILED')
    
eCode = ACI_GATT_DISC_READ_CHAR_BY_UUID_RESP_EVENT
while (eCode != ACI_GATT_PROC_COMPLETE_EVENT):
    e = WAIT_EVENT(HCI_VENDOR_EVENT, timeout=30)
    eCode = e.get_param('Ecode').val
    if (eCode == ACI_GATT_DISC_READ_CHAR_BY_UUID_RESP_EVENT): 
        freeFall_attr_handle =e.get_param('Attribute_Handle').val    
        found=True
    elif (eCode == ACI_GATT_ERROR_RESP_EVENT):
        if not found:
            ERROR('FREE FALL CHARACTERISTIC NOT FOUND')
 
            
##Acceleration characteristic
found=False
status= ACI_GATT_DISC_CHAR_BY_UUID(Connection_Handle=conn_handle, Start_Handle=0x0001, End_Handle=0xffff, UUID_Type=0x02, UUID_128=ACCELERATION_CHAR_UUID)
if (status != 0x00):
    ERROR('DISCOVERY ACCELERATION CHARACTERISTIC FAILED')
    
eCode = ACI_GATT_DISC_READ_CHAR_BY_UUID_RESP_EVENT
while (eCode != ACI_GATT_PROC_COMPLETE_EVENT):
    e = WAIT_EVENT(HCI_VENDOR_EVENT, timeout=30)
    eCode = e.get_param('Ecode').val
    if (eCode == ACI_GATT_DISC_READ_CHAR_BY_UUID_RESP_EVENT):
        acc_attr_handle =e.get_param('Attribute_Handle').val   
        found=True
    elif (eCode == ACI_GATT_ERROR_RESP_EVENT):
        if not found:
            ERROR('ACCELERATION CHARACTERISTIC NOT FOUND')
        
##Discovery  Environmental Sensor  Characteristic: only temperature characteristic (no expansion board is considered)
##Temperature characteristic
found=False
status= ACI_GATT_DISC_CHAR_BY_UUID(Connection_Handle=conn_handle, Start_Handle=0x0001, End_Handle=0xffff, UUID_Type=0x02, UUID_128=TEMPERATURE_CHAR_UUID)
if (status != 0x00):
    ERROR('DISCOVERY TEMPERATURE CHARACTERISTIC FAILED')
    
eCode = ACI_GATT_DISC_READ_CHAR_BY_UUID_RESP_EVENT
while (eCode != ACI_GATT_PROC_COMPLETE_EVENT):
    e = WAIT_EVENT(HCI_VENDOR_EVENT, timeout=30)
    eCode = e.get_param('Ecode').val
    if (eCode == ACI_GATT_DISC_READ_CHAR_BY_UUID_RESP_EVENT):
        temp_attr_handle =e.get_param('Attribute_Handle').val 
        found=True
    elif (eCode == ACI_GATT_ERROR_RESP_EVENT):
        if not found:
            ERROR('TEMPERATURE CHARACTERISTICS NOT FOUND')
        
            
# Enable Notification for Free Fall Characteristic
#The handle of descriptor is equal to freeFall_attr_handle+2 
status =  ACI_GATT_WRITE_CHAR_VALUE( Connection_Handle=conn_handle,
                   Attr_Handle=freeFall_attr_handle+2, Attribute_Val_Length=2, Attribute_Val=0x0001)
if (status != 0x00):
    ERROR ('ENABLE NOTIFICATION FOR FREE FALL CHARACTERISTIC FAILED')

e = WAIT_EVENT( HCI_VENDOR_EVENT, timeout=30, Ecode=ACI_GATT_PROC_COMPLETE_EVENT)


# Enable Notification for Acceleration Characteristic
#The handle of descriptor is equal to acc_attr_handle+2 
status=  ACI_GATT_WRITE_CHAR_VALUE(Connection_Handle=conn_handle, Attr_Handle=acc_attr_handle+2, Attribute_Val_Length=2, Attribute_Val=0x0001) 
if (status != 0x00):
    ERROR( 'ENABLE NOTIFICATION FOR ACCELERATION CHARACTERISTIC FAILED')

e = WAIT_EVENT(HCI_VENDOR_EVENT, timeout=30, Ecode=ACI_GATT_PROC_COMPLETE_EVENT)


#Read the Temperature Characteristic for 3 times
for i in range (0,4):
    status=  ACI_GATT_READ_CHAR_VALUE(Connection_Handle=conn_handle,Attr_Handle=temp_attr_handle+1) 
    if (status != 0x00):
        ERROR( "READ TEMPERATURE CHARACTERISTIC FAILED (TIME %d)" %(i+1))

    while (True):
        e = WAIT_EVENT(HCI_VENDOR_EVENT)
        if (e.get_param('Ecode').val == ACI_ATT_READ_RESP_EVENT):
            PRINT ( "READ TEMPERATURE CHARAC (TIME %d) -> " %(i+1) + str(SENSORDEMO_GET_TEMPERATURE(e.get_param('Attribute_Value').val)))
        elif (e.get_param('Ecode').val == ACI_GATT_PROC_COMPLETE_EVENT):
            break           
    SLEEP(1)  #Read Temperature Characteristic each 1 sec.


#Receive Notifications
while(True):
    e = WAIT_EVENT(HCI_VENDOR_EVENT) 
    eCode = e.get_param('Ecode').val
    if (eCode == ACI_GATT_NOTIFICATION_EVENT):
        if e.get_param('Attribute_Handle').val == freeFall_attr_handle+1:
            PRINT('---FREE FALL---')
        elif e.get_param('Attribute_Handle').val == acc_attr_handle+1:
            x,y,z = SENSORDEMO_GET_ACCELERATION(e.get_param('Attribute_Value').val)  
            ## Print acceleration value
            PRINT('Acc -> X: '+ str(x) + ',Y: ' + str(y) + ',Z: ' +str(z))

## @endcond
