@@ -150,6 +150,8 @@
 //Default connection handle which is set when group member is created
 #define GROUP_INITIALIZED_CONNECTION_HANDLE  0xFFFF
 
+// Hard coded PSM for passing data between central and peripheral
+#define SBC_PSM             0x0080
 
 /*********************************************************************
  * TYPEDEFS
@@ -337,6 +339,9 @@ static uint8_t numGroupMembers = 0;
 //Connection in progress to avoid double initiate
 static groupListElem_t *memberInProg;
 
+// Unique CoC CID
+uint16_t cocCID;
+
 /*********************************************************************
  * LOCAL FUNCTIONS
  */
@@ -388,6 +393,11 @@ static void SimpleCentral_scanCb(uint32_t evt, void* msg, uintptr_t arg);
 static void SimpleCentral_menuSwitchCb(tbmMenuObj_t* pMenuObjCurr,
                                        tbmMenuObj_t* pMenuObjNext);
 
+static bStatus_t SimpleCentral_openL2CAPChanCoc(uint16_t psm_id);
+static void SimpleCentral_processL2CAPDataEvent(l2capDataEvent_t *pMsg);
+static void SimpleCentral_processL2CAPSignalEvent(l2capSignalEvent_t *pMsg);
+static void SimpleCentral_sendL2CAPData(uint8_t *params, uint16_t paramLen);
+
 /*********************************************************************
  * EXTERN FUNCTIONS
  */
@@ -789,7 +799,11 @@ static uint8_t SimpleCentral_processStackMsg(ICall_Hdr *pMsg)
     }
 
     case L2CAP_SIGNAL_EVENT:
-      // place holder for L2CAP Connection Parameter Reply
+      SimpleCentral_processL2CAPSignalEvent((l2capSignalEvent_t *)pMsg);
+      break;
+
+    case L2CAP_DATA_EVENT:
+      SimpleCentral_processL2CAPDataEvent((l2capDataEvent_t *)pMsg);
       break;
 
     default:
@@ -1501,6 +1515,8 @@ static void SimpleCentral_handleKeys(uint8_t keys)
  */
 static void SimpleCentral_processGATTMsg(gattMsgEvent_t *pMsg)
 {
+  static bool l2capChannelOpen = false;
+
   if (linkDB_Up(pMsg->connHandle))
   {
     // See if GATT server was unable to transmit an ATT response
@@ -1522,9 +1538,25 @@ static void SimpleCentral_processGATTMsg(gattMsgEvent_t *pMsg)
       }
       else
       {
-        // After a successful read, display the read value
-        Display_printf(dispHandle, SC_ROW_CUR_CONN, 0,
-                       "Read rsp: 0x%02x", pMsg->msg.readRsp.pValue[0]);
+          uint16_t psm = 0x0080; // Should be the value set for SBP_PSM in simple_peripheral
+
+           // Print the L2CAP PSM read from GATT
+           Display_print1(dispHandle, 16, 0, "L2CAP PSM: %d", psm);
+
+           if(!l2capChannelOpen)
+           {
+             bStatus_t stat = SimpleCentral_openL2CAPChanCoc(psm);
+             if(stat != SUCCESS)
+             {
+               Display_printf(dispHandle, 17, 0, "L2CAP err: %d", stat);
+             }
+             else
+             {
+               l2capChannelOpen = true;
+               Display_printf(dispHandle, 17, 0, "L2CAP CoC opened with PSM: %d",
+                               psm);
+             }
+           }
       }
     }
     else if ((pMsg->method == ATT_WRITE_RSP)  ||
@@ -2840,6 +2872,139 @@ static void SimpleCentral_menuSwitchCb(tbmMenuObj_t* pMenuObjCurr,
   }
 }
 
+/*********************************************************************
+ * @fn      SimpleCentral_openL2CAPChanCoc
+ *
+ * @brief   Opens a communication channel between Master/Slave
+ *
+ * @return  none
+ */
+static bStatus_t SimpleCentral_openL2CAPChanCoc(uint16_t psm_id)
+{
+  l2capPsm_t psm;
+  bStatus_t ret;
+
+  psm.initPeerCredits = 0xFFFF;
+  psm.maxNumChannels = 1;
+  psm.mtu = MAX_PDU_SIZE;
+  psm.peerCreditThreshold = 0;
+  psm.pfnVerifySecCB = NULL;
+  psm.psm = psm_id;
+  psm.taskId = ICall_getLocalMsgEntityId(ICALL_SERVICE_CLASS_BLE_MSG, selfEntity);
+
+  ret = L2CAP_RegisterPsm(&psm);
+
+  if (ret == SUCCESS)
+  {
+    L2CAP_ConnectReq(scConnHandle, SBC_PSM, SBC_PSM);
+  }
+
+  return (ret);
+}
+
+
+/*********************************************************************
+ * @fn      SimpleCentral_processL2CAPSignalEvent
+ *
+ * @brief   Handle L2CAP signal events
+ *
+ * @param   pMsg - pointer to the signal that was received
+ *
+ * @return  none
+ */
+static void SimpleCentral_processL2CAPSignalEvent(l2capSignalEvent_t *pMsg)
+{
+    switch (pMsg->opcode)
+    {
+        case L2CAP_CHANNEL_ESTABLISHED_EVT:
+        {
+          l2capChannelEstEvt_t *pEstEvt = &(pMsg->cmd.channelEstEvt);
+
+          cocCID = pEstEvt->CID;
+
+          // Give max credits to the other side
+          L2CAP_FlowCtrlCredit(pEstEvt->CID, 0xFFFF);
+        }
+        break;
+
+        case L2CAP_SEND_SDU_DONE_EVT:
+        {
+            if (pMsg->hdr.status == SUCCESS)
+            {
+              // Handle Success
+              Display_printf(dispHandle, 20, 0, "SDU sent");
+            }
+            else
+            {
+              // Handle fail
+              Display_printf(dispHandle, 20, 0, "SDU send failed");
+            }
+        }
+        break;
+    }
+}
+
+/*********************************************************************
+ * @fn      SimpleCentral_sendL2CAPData
+ *
+ * @brief   Send L2CAP data to the peer
+ *
+ * @param   params - data to send
+ * @param   paramLen - len of data
+ *
+ * @return  none
+ */
+static void SimpleCentral_sendL2CAPData(uint8_t *params, uint16_t paramLen)
+{
+  l2capPacket_t pkt;
+  bStatus_t stat;
+
+  if (cocCID)
+  {
+    pkt.CID = cocCID;
+    pkt.pPayload = params;
+    pkt.len = paramLen;
+
+    stat = L2CAP_SendSDU(&pkt);
+    if(stat != SUCCESS)
+    {
+      Display_printf(dispHandle, 19, 0, "L2CAP Data send error: %d", stat);
+    }
+  }
+}
+
+/*********************************************************************
+ * @fn      SimpleCentral_processL2CAPDataEvent
+ *
+ * @brief   Handles incoming L2CAP data
+ *
+ * @param   pMsg - pointer to the signal that was received
+ *
+ * @return  none
+ */
+static void SimpleCentral_processL2CAPDataEvent(l2capDataEvent_t *pMsg)
+{
+  static uint32_t cocDummyInfo = 0xFFFFFFFF;
+  // This application doesn't care about other L2CAP data events other than CoC
+  // It is possible to expand this function to support multiple COC CID's
+  if (pMsg->pkt.CID == cocCID)
+  {
+    // Clear RX data lines before printing
+    Display_clearLines(dispHandle, 7,9);
+
+    uint32_t rxData = BUILD_UINT32(pMsg->pkt.pPayload[0],
+                                   pMsg->pkt.pPayload[1],
+                                   pMsg->pkt.pPayload[2],
+                                   pMsg->pkt.pPayload[3]);
+
+    // Process data
+    Display_printf(dispHandle, 18, 0, "L2CAP RX: %d", rxData);
+
+    // Send a response, to show bidirectional L2CAP activity
+    SimpleCentral_sendL2CAPData((uint8_t *)(&cocDummyInfo), sizeof(cocDummyInfo));
+    cocDummyInfo--;
+  }
+}
 
 /*********************************************************************
 *********************************************************************/
