## @file Simultaneous_Mode_Master_Slave.py
## @brief This script is used as component for testing a BlueNRG-MS simultaneously Master & Slave scenario. One BlueNRG-MS device (Master&Slave) is configured as Central & Peripheral, with a service and one characteristic and it performs two connections procedures (as Central) for connecting, respectively, to two BlueNRG-MS Peripheral devices (Slave_A, Slave_B) which have defined the same service and characteristic. Then BlueNRG-MS Master&Slave device  enables the characteristics notification on both of them. At this stage, BlueNRG-MS Master&Slave device enters in discovery mode (acting as Peripheral)  and it waits for connection request coming from another BlueNRG-MS device configured as Central (Master). Once this connection is performed, BlueNRG-MS Master&Slave device receives characteristics notifications from both BlueNRG-MS Slave_A, Slave_B devices and it notifies these characteristics (as Peripheral)  to the BlueNRG-MS Master device which displays the related values.
## @li The script is implemented using the new BlueNRG GUI language scripts based on the BlueNRG-MS 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 GUISW package.
##
## <!-- Copyright 2016 by STMicroelectronics.  All rights reserved.       *80*-->
##
##  @section S7 Simultaneous_Mode_Master&Slave.py script, preliminary setup steps: configure two GAP Peripheral devices Slave_A, Slave_B  using the Simultaneous_Mode_Slave.py script
##
##  @li Open BlueNRG GUI available
##  @li <b>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 Simultaneous_Mode_Slave.py script location and select it
##  @li On BlueNRG GUI, click on  Run Script tab for running the selected script
##  @li   device Slave_A enters in discovery mode.
##  @li Repeat same steps for configuring a  Device Slave_B using the Simultaneous_Mode_Slave.py script
##
##  @section S71 Simultaneous_Mode_Master&Slave.py script execution steps through BlueNRG GUI Script Engine
##
##  @li Open BlueNRG GUI available
##  @li <b>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 Simultaneous_Mode_Master&Slave.py script location and select  it
##  @li On BlueNRG GUI, click on  Run Script tab for running the selected script
##  @li  Master&Slave device is configured as Central & Peripheral, with a service and one characteristic and it performs two connections procedures (as Central) for connecting, respectively, to two  Peripheral devices (Slave_A, Slave_B)
## @li Then  Master&Slave device  enables the characteristics notification on both of Slave_A, Slave_B devices.
## @li Then  Master&Slave device  enables the characteristics notification on both of them. At this stage,  Master&Slave device enters in discovery mode (acting as Peripheral)  and it waits for connection request coming from another  device configured as Central (Master).
## @li At this stage,  Master&Slave device enters in discovery mode (acting as Peripheral)  and it waits for connection request coming from another  device configured as Central (Master) using the Simultaneous_Mode_Master.py
## @li Once this connection is performed,  Master&Slave receives characteristics notifications from both  Slave_A, Slave_B devices (as Central) and it notifies these characteristics (as Peripheral)  to the  Master device which displays the related values.
##
##  @section S72 Simultaneous_Mode_Master.py script execution steps through BlueNRG GUI Script Engine
##
##  @li Open BlueNRG GUI available
##  @li <b>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 Simultaneous_Mode_Master.py script location and select  it
##  @li On BlueNRG GUI, click on  Run Script tab for running the selected script
##  @li  Master device is configured as Central and it performs a connection procedure for connecting to the  Master&Slave device. 
##  @li Then  Master  device  enables the characteristic notification on  Master&Slave device.
##  @li At this stage,  Master receives and displays the received characteristics values with information sender identity (Slave_A or Slave_B).
##
##  @section S73 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)
## 
##  @section S74 Supported BLE devices and stack versions
##
##  @li BlueNRG-1 stack v1.x
##  @li BlueNRG-MS stack v7.2x
##

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

## @cond DOXYGEN_SHOULD_SKIP_THIS

#Master and Slave role


RESET()

if (IS_BlueNRG()):
  ERROR('BlueNRG device is not supported from this script')
if (IS_BlueNRG_MS()):
  SET_MODE(3)  
SET_PUBLIC_ADDRESS(0x0280E100AAAA)
ACI_HAL_SET_TX_POWER_LEVEL(En_High_Power=1,PA_Level = 4)
ACI_GATT_INIT()
ACI_GAP_INIT(Role=PERIPHERAL|CENTRAL) #Central Role (04) or Peripheral Role(01)


#Add a Services
Status,ServHandle=ACI_GATT_ADD_SERVICE(Service_UUID_Type=0x01, Service_UUID_16=0xA001,Service_Type=1,Max_Attribute_Records=5)      
if Status !=0x00:
    ERROR('ACI_GATT_ADD_SERVICE CALL FAILED')    

#Add a Characteristic (Notify properties)
Status,CharHandle=ACI_GATT_ADD_CHAR(Service_Handle =ServHandle,
                                    Char_UUID_Type=0x01,
                                    Char_UUID_16= 0xA002,
                                    Char_Value_Length=20, 
                                    Char_Properties=0x10, #Only Notification
                                    Security_Permissions=0x00,   
                                    GATT_Evt_Mask=0x01,
                                    Enc_Key_Size=0x07,
                                    Is_Variable=0x01)      
if Status !=0x00:
    ERROR('ACI_GATT_ADD_CHAR CALL FAILED')


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 FAILED')


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
    else:
        if 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    :
            #read name device
            name=GET_NAME(event.get_param('Data').val[0])
            if name==None:
                continue
            
            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
                    if ([type_address,address] in listOfDeviceInADV)==False:
                        listOfDeviceInADV.insert(0,[type_address,address])
            
conn_handle=[]
PRINT('Nun. Device in ADV= ' + str(len(listOfDeviceInADV)))

ACI_HAL_READ_CONFIG_DATA()

#-----------------------------------------CONNECTION TO A SLAVE ---------------------------  
#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 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)

   
#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 = 0x0f,
                        Attribute_Val_Length=0x02,
                        Attribute_Val=0x0001)
    if status==0x00:
        PRINT ('ENABLE NOTIFICATION FROM SLAVE ' + chr(ord('A')+i))
    else:
        PRINT ('FAILED ENABLE NOTIFICATION FROM SLAVE ' + chr(ord('A')+i))
        

 
#-----------------------------------------SWITCH TO SLAVE---------------------------------------
#ACI_HAL_READ_CONFIG_DATA()

Status = HCI_LE_SET_SCAN_RESPONSE_DATA(Scan_Response_Data_Length = 0,Scan_Response_Data = 0) ## Set Scan Response to 0  
if Status!=0x00:
    ERROR('HCI_LE_SET_SCAN_RESPONSE_DATA CALL FAILED')

#Put in Discoverable Mode with Name = 'Test' = [0x08,0x74,0x65,0x73,0x74](Add prefix 0x08 to indicate the AD type Name)
Status =ACI_GAP_SET_DISCOVERABLE(Advertising_Type= 0x00,
                                 Advertising_Interval_Min=0x20,
                                 Advertising_Interval_Max=0x100,
                                 Local_Name_Length=0x05,
                                 Local_Name=[0x08,0x74,0x65,0x73,0x74],
                                 Slave_Conn_Interval_Min = 0x0006,
                                 Slave_Conn_Interval_Max = 0x0008) 

if Status !=0x00:
    ERROR('ACI_GAP_SET_DISCOVERABLE CALL FAILED')

   
while(True):

    e = WAIT_EVENT()    #Wait Event
    if e.event_code == HCI_LE_META_EVENT:      #Wait Connection Complete event to established the connection with a Master
        if e.get_param('Status').val==0x00:
            PRINT ('CONNECTED AS SLAVE')
    elif e.event_code==HCI_VENDOR_EVENT: 
        eCode = e.get_param('Ecode').val
        if (eCode == ACI_GATT_NOTIFICATION_EVENT):
            #Receive Notifications from Slaves and send them to the Master
            #When receives a notifification, controls the Slave and add the slave name during the update char (add 1 byte for slave name)  
            conn=e.get_param('Connection_Handle').val       
            if conn in conn_handle:
                ind= conn_handle.index(conn) 
                PRINT('Notification from Slave ' + chr(ord('A')+ind) + ' value: ' + str(GET_VALUE(e.get_param('Attribute_Value').val)))
                #Read the value form Slave i and modify the char with the value, in order to send a notification to Master       
                value=e.get_param('Attribute_Value').val + [ord('A')+ind]
                status=ACI_GATT_UPDATE_CHAR_VALUE(Service_Handle=ServHandle,Char_Handle=CharHandle,Val_Offset=0x00,Char_Value_Length = 20,Char_Value=value)
                if status!=0x00:
                    ERROR('ACI_GATT_UPDATE_CHAR_VALUE FAILED')
            else: 
                PRINT('Notification from unknown Slave')
## @endcond
