## @file  Multiple_Connection_Master_Role.py
## @brief This script implements a multiple connection scenario: one Bluetooth Low Energy (BLE) Master connected to up 8 BLE Slaves devices. This script implements the Master role which configures a BLE device as Central, Mode 3. Then it  look for BLE Slave devices and connect to each of them. Once connected, Master device enables characteristic notification on each Slave device and it receives related characteristics notifications. 
## @li The script is implemented using the new BlueNRG GUI language scripts based on the BLE ACI APIs. The BlueNRG GUI with script engine is delivered within BlueNRG GUI SW package.
## @li The script can also be run using the script launcher standalone utility available within BlueNRG GUI SW package.
## @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 GUI  SW package.
##
## <!-- Copyright 2016 by STMicroelectronics.  All rights reserved.       *80*-->
##
##  @section S3 Multiple_Connection_Master_Role script, preliminary setup steps: configure up to 8 BLE devices as slaves by using the Multiple_Connection_Slave_Role.py script
##
##  @li Open BlueNRG GUI 
##  @li <b>BlueNRG/BlueNRG-MS platform configuration steps</b>: <ol>
##  <li> Connect the selected platform to a PC USB port
##  <li> Put selected platform in DFU mode and download the "C:\Program Files (x86)\STMicroelectronics\BlueNRG GUI\Firmware\STM32L1_prebuilt_images\BlueNRG_VCOM_x_x.hex" using the BlueNRG GUI, Tools, Flash Motherboard FW... utility </ol>
##  @li <b>BlueNRG-1 platform configuration steps</b>: <ol>
##  <li> Connect the selected platform to a PC USB port
##  <li> Download the "C:\Program Files (x86)\STMicroelectronics\BlueNRG GUI x.x.x\Firmware\BlueNRG1\DTM\DTM_UART_16MHz.hex or DTM_SPI.hex" file on the BlueNRG-1 platform using the BlueNRG Flasher utility available on  BlueNRG-1 DK SW package (STSW-BLUENRG1-DK) <ul>
##  <li> <b> NOTES</b>: SPI Network coprocessor configuration file (DTM_SPI.hex) requires some HW changes to be applied to the BlueNRG-1 development platform. Refer to STSW-BNRGUI user manual UM2058. </ul></ol>
##  @li On BlueNRG GUI, open the USB Port associated to the plugged 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 Multiple_Connection_Slave_Role.py script location and select  it
##  @li On BlueNRG GUI, click on  Run Script tab for running the selected script
##  @li BLE Slave device adds a service with a characteristic and it enters in discoverable mode. When connected, it continuosly notifies the added characteristic value
##
##  @li NOTE: Repeat previous steps in order to configure another BlueNRG/BlueNRG-MS device as Slave (up to 8 connections are supported from a BlueNRG/BlueNRG-MS Master device, Mode 3). 
##
##  @section S31 Multiple_Connection_Master_Role.py script execution steps through BlueNRG GUI Script Engine
##
##  @li Open BlueNRG GUI 
##  @li <b>BlueNRG/BlueNRG-MS platform configuration steps</b>: <ol>
##  <li> Connect the selected platform to a PC USB port
##  <li> Put selected platform in DFU mode and download the "C:\Program Files (x86)\STMicroelectronics\BlueNRG GUI x.x.x\Firmware\STM32L1_prebuilt_images\BlueNRG_VCOM_x_x.hex" using the BlueNRG GUI, Tools, Flash Motherboard FW... utility </ol>
##  @li <b>BlueNRG-1 platform configuration steps</b>: <ol>
##  <li> Connect the selected platform to a PC USB port
##  <li> Download the "C:\Program Files (x86)\STMicroelectronics\BlueNRG GUI x.x.x\Firmware\BlueNRG1\DTM\DTM_UART_16MHz.hex or DTM_SPI.hex" file on the BlueNRG-1 platform using the BlueNRG Flasher utility available on  BlueNRG-1 DK SW package (STSW-BLUENRG1-DK) <ul>
##  <li> <b> NOTES</b>: SPI Network coprocessor configuration file (DTM_SPI.hex) requires some HW changes to be applied to the BlueNRG-1 development platform. Refer to STSW-BNRGUI user manual UM2058. </ul></ol>
##  @li On BlueNRG GUI, open the USB Port associated to the plugged 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 Multiple_Connection_Master_Role.py script location and select  it
##  @li On BlueNRG GUI, click on  Run Script tab for running the selected script
##  @li BLE Master device will look for BLE advertising devices. Then it will connect to each discovered BLE Slave device and it will enable the related characteristic notification
##  @li At this stage, BLE Master device receive the characteristic value notification from each Slave device and it displays each of them
##  @li For terminating the script (and closing the current active BLE connections), click on "Terminate Script" tab
##
##  @section S32 Supported platforms
##
##  @li BlueNRG-1 development platform (order code: STEVAL-IDB007V1)
##  @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)
##  @li BlueNRG development platform (order code: STEVAL-IDB002V1)
##  @li BlueNRG USB dongle (order code: STEVAL-IDB003V1)
## 
##  @section S33 Supported BLE devices and stack versions
##
##  @li BlueNRG-1 stack v1.x
##  @li BlueNRG-MS stack v7.2x
##  @li BlueNRG stack v6.4x
##

## \addtogroup BLE_scripts
## @{
## \see Multiple_Connection_Master_Role.py for documentation.
## 
## @} 

## @cond DOXYGEN_SHOULD_SKIP_THIS


RESET()
if (IS_BlueNRG() or IS_BlueNRG_MS()):
    SET_MODE(3)
SET_PUBLIC_ADDRESS()
ACI_HAL_SET_TX_POWER_LEVEL(En_High_Power=1,PA_Level = 4)

ACI_GATT_INIT()

status,_,_,_=  ACI_GAP_INIT(Role=CENTRAL)
if status !=0x00:
    ERROR('ACI_GAP_INIT CALL FAILED')

## Start general discovery procedure
Status =  ACI_GAP_START_GENERAL_DISCOVERY_PROC(LE_Scan_Interval=0x10,
                                      LE_Scan_Window=0x10)
if Status !=0x00:
    ERROR('ACI_GAP_START_GENERAL_DISCOVERY_PROC CALL FAILED')    

## Wait for device found event and store the devices addresses and types:
## Expected advertising device name is "test": refer to serverScript.py

listOfDeviceInADV=[]
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=='test':
                #type_address, address = GET_ADDRESS(event.get_param('Data').val)               
                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=='test':               
            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])
        
conn_handle=[]
PRINT('Nun. Device in ADV= ' + str(len(listOfDeviceInADV)))

#A master can establish a connection until up 8 slaves, therefore at most 8 connections
for i in range (0,min(8,len(listOfDeviceInADV))) :
    status=ACI_GAP_CREATE_CONNECTION(LE_Scan_Interval=0x0010,
                                     LE_Scan_Window=0x0010,
                                     Peer_Address_Type=listOfDeviceInADV[i][0],
                                     Peer_Address=listOfDeviceInADV[i][1],
                                     Conn_Interval_Min=0x6c,
                                     Conn_Interval_Max=0x6c,
                                     Conn_Latency=0x00,
                                     Supervision_Timeout=0xc80,
                                     Minimum_CE_Length=0x000c,
                                     Maximum_CE_Length=0x000c)
    if Status !=0x00:
        ERROR('ACI_GAP_CREATE_CONNECTION CALL FAILED') 
    
    WAIT_EVENT(HCI_VENDOR_EVENT,Ecode=ACI_GAP_PROC_COMPLETE_EVENT )

    event = WAIT_EVENT(HCI_LE_META_EVENT,Subevent_Code=HCI_LE_CONNECTION_COMPLETE_EVENT )
    if event.get_param('Status').val==0x00:
        conn_handle.insert(0, event.get_param('Connection_Handle').val)


App_Start_Handle=[]

#For each connection, identify the handle of attribute to enable notification
for i in range (0,len(conn_handle) ) :     
    #DISCOVERY OF GAP SERVICE   IN ORDER TO UNDERSTAND THE FIRST ATTRIBUTE HANDLE AVAILABLE
    status=ACI_GATT_DISC_PRIMARY_SERVICE_BY_UUID(Connection_Handle=conn_handle[i], UUID_Type=0x01, UUID_16=0x1800)
    if (status != 0x00):
        ERROR('DISCOVERY GAP SERVICE 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_ERROR_RESP_EVENT):
            App_Start_Handle.insert(i, e.get_param('Attribute_Handle').val) 

    
 #Enable Notification for each connection
for i in range (0,len(conn_handle) ) :   
    Status = ACI_GATT_WRITE_CHAR_DESC(Connection_Handle= conn_handle[i],Attr_Handle = App_Start_Handle[i] + 0x03,
                                              Attribute_Val_Length=0x02,Attribute_Val=0x0001 )
    if Status !=0x00:
        ERROR('ACI_GATT_WRITE_CHAR_DESC CALL FAILED') 
       
#Receive Notification
while(True):
    e = WAIT_EVENT(HCI_VENDOR_EVENT) 
    eCode = e.get_param('Ecode').val
    if (eCode == ACI_GATT_NOTIFICATION_EVENT):
        PRINT('Notification from connection: ' + str(e.get_param('Connection_Handle').val))
  

## @endcond

            
