This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

CC2652RB: Simple Serial Socket Example on Github (Serial Port Profile)

Part Number: CC2652RB
Other Parts Discussed in Thread: CC2650

My problem relates to the Simple Serial Socket example that I luckily found on Github. I would be very grateful to get some help here.

github.com/.../ble5apps

Since it is important for me to get a useful answer, here is a brief description of my situation and what it is about:

I have accepted a project assignment that involves a sensor that is activated from time to time and communicates with a mobile phone via BLE. After a measurement is completed, the sensor is supposed to connect to a mobile phone. If no connection can be established, the BLE module is switched off after a timeout and the sensor processor also goes to sleep again. The data is stored in the sensor processor for later transmission.

Originally, it was planned to use a TI processor for the sensor evaluation and the query of a touch surface. A ready-to-use BLE module should be connected to the processor via UART interface. The BLE module would only have to be configured accordingly and otherwise no BLE-specific tasks would have had to be done. A nice little project for in between without major difficulties. Unfortunately, due to the component crisis, no corresponding modules are available within a reasonable period of time. Therefore, the customer decided to use a CC6650 module and to use it for the sensor part as well, since it was available in sufficient quantities. The modules were ordered immediately.

At that time, I was still working on another project and was not able to take a closer look at TI's software support. However, I saw that there were plenty of tutorials and examples on BLE. I therefore assumed that I would quickly find something that would enable BLE communication via a simple interface with a few functions and some configuration, similar to the external module, but only in software.

I first implemented the sensor functionalities. This was relatively easy after I chose a CC2652RB board for development, as the CC2650 is no longer supported in Resource Explorer. Porting to the CC2650 is planned after development is complete.

All was well until I turned to the BLE side of the project. I found out that TI does not have something similar to the external BLE module, but as a pure software component. Instead, in order to use the BLE stack together with TI-RTOS, it is necessary to have quite a lot of BLE knowledge and also to know TI-RTOS. The only connection I have had to BLE so far was to connect my head set to my cell phone. Besides, I usually work on bare-matel projects without an operating system. I then also tried to build up the necessary knowledge as quickly as possible via the SimpleLink Academy. However, I quickly realised that this knowledge is too great for either BLE or TI-RTOS to be absorbed and applied in a short time. This simply requires a certain period of practice, which cannot be shortened.

I have therefore tried to find something that I could quickly adapt without in-depth knowledge. Unfortunately, I did not find what I was looking for in the SimpleLink examples in the Resource Explorer. What I had to find out after a few futile attempts.

After a lot of searching I found the Simple Serial Socket example on Github through a link in a forum post. It's a great useful BLE example and I'm wondering why it's not listed in the SimpleLink examples in the Resource Explorer. It's just the application that many developers might need, coming from projects that haven't used BLE before and just need a quick simple connection to a PC or mobile phone.

I transferred that CC26X2R1_LAUNCHXL project to the CC2652RB board, which worked quite easily. I also integrated my sensor application and everything is working fine so far.

The only problem that remains now is to selectively set up and tear down the BLE communication and send the ARM core to sleep the rest of the time. (The sensor controller should then only be woken up at 5s intervals to query the touch sensor and start the measurement if applicable, in order to then wake up the arm core again for BLE communication. And so on ...)


I urgently need advice on where I can begin to specifically set up and shut down the BLE communication and how this can best be combined with the sleep mode.

Unfortunately, I lost a lot of time trying to reach my goal quickly via the SimpleLink Academy until I found the well-hidden serial socket example. In the meantime I am running out of time. It was only supposed to be a short project without deep BLE knowledge. The dead line is getting closer. Although I'm sure there's not much left, I'm not making enough progress because I don't have enough experience with BLE and the TI-RTOS.

I would therefore be extremely grateful for quick and fitting help.

Regards
Rainer

  • HI Rainer,

    Thank you for all the details provided.

    The only problem that remains now is to selectively set up and tear down the BLE communication and send the ARM core to sleep the rest of the time.

    I would recommend to look at the way connection establishment / connection ending is handled in the examples simple_preipheral and simple_central. You may also want to review our SimpleLink Academy labs.To save you time, here is a summary:

    - first of all the peripheral must be advertising and the central scanning (see this lab and this one).

    - based on the scan responses found, the central should chose a device and initiate a connection (see function GapInit_connect)

    - when the connection is established, the event "GAP_LINK_ESTABLISHED_EVENT" is passed to the application (same for peripheral and central)

    - for disconnection, one of the two devices should execute the function GAP_TerminateLinkReq

    - this will lead to the applications to receive the event "GAP_LINK_TERMINATED_EVENT"


    When it comes to set the main core in sleep mode, you don't need to handle this by your self. The power driver already handles this for you.

    I hope this will help,

    Best regards,

  • Hello Clément,
    Thank you very much for your really quick answer. However, it more or less describes the way I have tried to reach my goal so far. And I have already found that I don't have the time to build up the necessary knowledge quickly enough.

    For example, if I start from the mentioned GapInit_connect function and follow the call path upwards to find out how this function is triggered in the Simple Serial Socket example, I end up in the main task with a message that I don't know where it comes from. I've already been that far and got no further. But if I want to control the connection setup with GapInit_connect, I have to know where I have to intervene in advance in order to start the whole sequence only when needed. It looks similar with your other hints. If I start there, there comes a point where more knowledge about the overall system BLE/BLE stack in TI-RTOS is needed.

    I want to describe again in more detail what I need to reach my goal. And we will see if it is possible you can help me get there.

    Looking at the original planning of my project with two separate controllers, the Simple Serial Socket example would give me almost exactly the Software for the BLE-only module, which I would switch on and off from the main controller as needed and communicate with via the UART. Since now in this project the second controller is replaced by the sensor controller in the CC2652/CC2650, the switching on and off is no longer so simple. I now have to do this within the same software.

    Therefore, ideally I would have liked to find at TI some kind of library with an interface like for the external UART communication. (Or I would have expected it):

    - Initialisation function for a few basic parameters such as UUID, etc.
    - Function for establishing communication with call-back Function for status: timnout or successful
    - Send function for data
    - Call-back function for received data
    - Function for connection termination
    - Call-back function for connection status.

    Much more would not be necessary and should not be necessary. The whole thing should work without the need to know anything about BLE, except some basic knowledge of connection types to initialise the whole thing.

    Since this interface presumably does not exist, I can only convert the Simple Serial Socket example. It is actually quite close. I'm just missing more specific information on this, which are:

    - Where does the BLE initialisation code run to before starting the communication setup?  So where is the point where I can send the main processor to sleep for now?(From then on, the built-in sensor controller would take over and wake up the main processor via fwGenAlertInterrupt only when communication is needed).
    - Of course, the following functions must then be called somewhere else in the code. But can I then simply continue with these same functions to establish the connection? Or what do I possibly have to do differently if the processor was previously in sleep mode?
    - What do I have to wait for until I can send my data. (Sending already works for me now, but the connection is always there).
    - How and at which point do I initiate the connection termination and where do I then send the processor to sleep again so that it is ready for a new connection setup after waking up?
    If I had this information about the Simple Serial Socket, I could quickly implement something there that would correspond to the overall function according to my "desired interface" above.  This especially without having to get deeper into BLE. It is surely easy for the author of the example to provide this information. Perhaps you can contact him.

    I would like to point out again: I have no deeper BLE knowledge. If I had 3 or 4 months, I could certainly work all this out without direct colleagues who are already familiar with everything and could accompany me directly. In the time available and all by myself, I cannot achieve this.

    If the interface I described above does exist, I would of course be very happy with a corresponding link. If not, I would strongly encourage the creation of one. It seems that with all the effort TI has put into the SimpleLink examples and the SimpleLink Academy, it has been overlooked that there are many developers who do not have the time or the need to go deep into BLE in their projects. Not everyone who wants/must to use BLE has/wants to become an expert. But it would still be nice to be able to use the Ti chips. I don't understand why this is made so difficult. Perhaps you could pass on this advice to your superiors. Even if it would not be of any use for my current project.

    Regards
    Rainer

  • Hi Rainer,

    - Where does the BLE initialisation code run to before starting the communication setup?  So where is the point where I can send the main processor to sleep for now?(From then on, the built-in sensor controller would take over and wake up the main processor via fwGenAlertInterrupt only when communication is needed).

    Once again, you don't need to handle the power mode of the main core. This is handled by the power driver.

    - Of course, the following functions must then be called somewhere else in the code. But can I then simply continue with these same functions to establish the connection? Or what do I possibly have to do differently if the processor was previously in sleep mode?

    The application code is meant to be "event driven". It means the processor will remain in sleep mode until an event is raised. The events can be raised by the blestack, by the buttons (see the two-button menu in the simple_peripheral example), by any driver or by some clocks (see the simple_peripheral example for this too).

    Here again, the power driver will handle waking up the processor and make it ready when needed.

    - What do I have to wait for until I can send my data. (Sending already works for me now, but the connection is always there).

    The connection establishment, i.e. the reception of the event  "GAP_LINK_ESTABLISHED_EVENT". As a side note, the simple_socket example is already configured to do so.

    - How and at which point do I initiate the connection termination and where do I then send the processor to sleep again so that it is ready for a new connection setup after waking up?

    I guess you are the only one to know when the connection termination should be triggered - I guess you have some requirements I am not aware for this. (The processor will go to sleep mode if the power driver decides it is relevant), The disconnection is done once you receive the event "GAP_LINK_TERMINATED_EVENT". As a side note, the example is already configured to warn the user of this (by lighting up a LED) and to be back in advertising mode. You can of course change this and instead fire a clock and turn back on advertising when the clock expires.

    It is surely easy for the author of the example to provide this information. Perhaps you can contact him.

    It looks like you have already found the author of the example Wink

    For the rest, I appreciate your honest feedback. Our team is exclusively composed of experienced BLE experts and sometimes we may forget that some things may be "easy" for us but not for people who are discovering the protocol.

    I hope my answer will help. I think the most important is to understand the way the stack works (i.e. this event driven structure), Then it should not require deep knowledge of the protocol - at least not more than understanding the concepts or advertisements, scanning, connection.

    Best regards,

  • Hello Clément
    Your hints have not really brought me any further. Perhaps our worlds are still so far apart that it is difficult to put oneself deep enough into the other's shoes. It seems to me that we do not yet have the right common understanding and that we are talking past each other. I will therefore try to solve the problem with the appropriate clarity and openness in this post. I apologise in advance if my words seem impolite. They are not meant to be rude, but honest feedback and are intended to help find common ground quickly or to quickly identify that I may have false expectations.

    It has already been expressed in the previous post that I am actually very disappointed not to have found a simple ready-to-use BLE interface at TI. And it's still not clear to me why this is so. This question is possibly the cause in the apparently very different ideas about what I expect from you and what you possibly believe I want from you. Therefore, I will now go into more detail.

    About 20 years ago, one of my projects needed a USB interface and I had to decide: Do I use an FTDI chip or do I use a USB interface that can meanwhile be found in uC? There was not much time pressure and I decided to use a NXP controller (or was NXP still Philips at that time) with USB interface. "It can't hurt to get to know USB a little better". That was a serious mistake. A hell of a ride, not least because of errors in the MS-usbserial driver. In the next project with USB, one likes to go back to FTDI. It was time-consuming, but in the end, with a lot of help from the FAE, it could be solved to some extent (at that time, you could actually still have long conversations with FAEs on the phone and discuss the code together). In any case, the situation back then seems less hopeless to me now than it does today with BLE.

    In the meantime, the semiconductor manufacturers have learned their lesson when it comes to USB. They didn't want to sit on their expensively developed USB uC and leave the business to FTDI alone. Meanwhile (probably?) all manufacturers have a ready-made USB library with which it is possible to completely integrate a simple COM port profile into one's application in a few hours, even as a newcomer. (But I haven't worked with a TI USB interface yet).

    Maybe I'm wrong and with BLE everything is completely different and it's not as easy as with USB. However, the fact that I can integrate ready-made BLE modules quickly and easily without knowing much about BLE speaks against this. And on a side note: I can use them without having to marry a whole RTOS. I'm sorry, but this bride is actually much too fat for my small, simple application that could easily do without her. But the OS on its own wouldn't be that bad.

    Even though I firmly believe that TI should offer such an interface to its customers, it doesn't exist. So what next?

    I understand from my own experience that when you are a team of experts in your field, you like to take everyone with you and share the experience you have worked hard to gain. It is in this spirit, with the appropriate effort, that the support in Resource Explorer is built. This is especially true for the BLE stack. Your replies to my posts also went in this direction. I don't want to disrespect this effort, but it doesn't help me right now.

    I dare to say it as brutally as it is: I am not interested in any of this at the moment. No one is paying me to build up great BLE knowledge or to master TI-RTOS while sleeping ;-) When it comes to BLE, I am only paid for the fact that within a reasonable period of time (comparable to an external BLE module) I can establish a BLE communication .

    I am certainly not the only one who would see it that way. This is certainly true for many freelancers or small companies who, with only a few developers, cannot afford to employ one or two of them for a longer period of time to build up knowledge that is otherwise of little use beyond the small part of a project. You, TI, just don't get to hear about these many, because they probably first take a closer look at what awaits them at TI. They turn back immediately if they don't find a quick solution for their BLE communication at TI and either go back to the ready-made BLE module or continue their search at another manufacturer. (You can see this, for example, in some forum threads that end abruptly).

    I am responsible for the fact that I did not immediately check exactly what TI has to offer. If I had spent more time with TI's software resources at that time, I would have realised that an implementation with a TI controller would not be that easy and would have strongly advised against using it.

    I have fallen into this trap myself and the question is whether you can or may really help me out of it. We would have to go from my current state of the simple serial socket example down to source code level (in this example not in the related examples from the Resource Explorer). I am still convinced that only a few changes will be necessary. For you as an author (?) it should be easy to identify these few places and advise me on the necessary adjustments. For TI, this would also have the side effect of providing a basis for the simple BLE interface I have been missing. They could then extend, generalise and document the whole thing a little further and it would be just as easy for others like me to use. Developers with the corresponding needs and expectations would no longer have to turn back at the TI door.

    If such specific help is not possible, however, I would rather thank you here for your patience so far and suggest it would be better to break off so as not to lose any more time. I would then urgently need to discuss possible options with my client.

    If it is possible to continue with the help in the form I need, here are more details and my comments on your answers.

    As already known, I use the Simple Serial Socket Client example. This establishes a connection to the server as soon as possible after switching on. This connection remains established as long as a server can be reached. I have added my application in the sensor controller and built its initialisation into the SimpleSerialSocketClient_init function accordingly. A Call Back function is also stored for the Alert. This Call Back function sends the measurement data on with SimpleSerialSocketClient_enqueueMsg and its own event for processing. I have replaced the SSSC_EVT_OUTGOING_DATA event in SimpleSerialSocketClient_processAppMsg (but both events also work in parallel). Here I pass on the measurement data buffer with SimpleStreamClient_sendData for sending via BLE. A call similar to the UART call in the SSSC_EVT_OUTGOING_DATA event is unnecessary, as the sensor controller reports completely independently via the alert when there is new data.

    This was actually quite simple and works very well as long as the connection to the server is established. That was the status before I asked my questions in the forum. What I need now, however, is a main core that goes to sleep immediately after initialisation and only tries to establish a connection and transmit the measurement data for a certain time after an alert, possibly accepts a few commands via BLE and then goes to sleep again. Further waking is again and exclusively done by the sensor controller alert.

    Now I simply lack the overview and knowledge of the overall system and the interaction of the components. I have no concept of it in my brain. It is clear to me that the OS puts the core to sleep when there is nothing to do. But obviously there is always something to do, namely to maintain the connection to the server or to establish a new one if there is none. In other words, the core is definitely not permanently asleep. I have no idea where to force the necessary idle state. This raises the question: What is the best way to force the idle state? I could probably answer that myself with a little trial and error. But maybe we can also answer this question right away. There are a number of possibilities, for example a semaphore.

    My comments are brief:

    1) I know, see also above. But where and how do I ensure an undisturbed idle state?

    2) Yes, I know that the application is event-driven. But in such an application you have to know which events can occur and when. This is very difficult or impossible to determine from the code. And that makes it practically impossible to analyse such a system from the code. At some stage you reach a point where you can no longer understand what happens when. You would then have to know more about the event sources. What could help a little here would be a diagram in which you could track the sources/causes and goals/actions of events in an overview.

    3) Yes, the question was a bit unnecessary. I am rather lacking ideas on how to process this information in the right place. But perhaps that will come about on its own once the other points have been clarified.

    4) yes, I know when the connection has to be terminated (see above). But the connection can also be interrupted by the server or simply break off. The main question remains where in the code and how best to enforce a permanent idle state (see again above).

    I would like to clearly contradict your last paragraph. I know that the system is event-driven (see above). And that is the problem. Whereas I can otherwise answer most questions via the code alone, this is practically impossible with an event-driven system. I have to know a lot about the events and the system that generates these events, which is hidden from me. For you, this is implicit knowledge that you use without thinking about it. I lack this knowledge. Under these circumstances, try looking at the code. Everywhere an event appears, you have no idea when, under which circumstances this event comes from where. You can only follow the events to a limited extent. If they come from the BLE stack, for example, it is over.

    Kind regards, oh, and sorry that I just have written so much again

    Rainer


  • Hi Rainer,

    Once again, thank you for your detailed feedback.

    I think a basic knowledge of Bluetooth LE and of RF communication is always required to achieve this kind of project - no matter the IC vendor. If you haven't yet review this lab, please do so. Then see this piece of documentation.

    Generally speaking:

    • one of your devices will act as scanner/central (simple_serial_socket_client by default) while the other will act as advertiser/peripheral (simple_serial_socket_server by default)
    • the scanner/central can be in three modes: idle, scanning, connected. The only moment communication is possible is while connected. When in scanning mode, the device is looking for advertiser to connect. When not in a connection nor in scanning mode, the device can be considered in a non-disturbed idle mode.
    • similarly, the advertiser/peripheral cab be in three mode: idle, advertising, connected. The only moment communication is possible is while connected. When advertising, the device sends out small RF packets allowing it to be detected by a scanner. If no advertising are sent, then no scanner can detect the device and no connection can be established (advertising can be disabled once the connection is formed). When not in a connection and not advertising, the device can be considered in undisturbed idle. 
    • there are also a lot of intermediate states that are not required in a first time
    • every time a device enters/leaves a state (like entering a connection, leaving a connection, etc.) a specific event is fired. I guess I have already provided you the name of the events you need, but tell me (or look in the documentation I have pointed to) if you are missing some events.
    • the easiest way to modify the project to suit your needs is to identify the code executed in response to each event and tune it. For example, if you don't want anymore to start advertising as soon as the device is initialized, in the simple_serial_socket_server.c file, find the code executed when the event "GAP_DEVICE_INIT_DONE_EVENT" is triggered (should be the following)
          case GAP_DEVICE_INIT_DONE_EVENT:
          {
            bStatus_t status = FAILURE;
      
            gapDeviceInitDoneEvent_t *pPkt = (gapDeviceInitDoneEvent_t *)pMsg;
      
            if(pPkt->hdr.status == SUCCESS)
            {
              // Store the system ID
              uint8_t systemId[DEVINFO_SYSTEM_ID_LEN];
      
              // use 6 bytes of device address for 8 bytes of system ID value
              systemId[0] = pPkt->devAddr[0];
              systemId[1] = pPkt->devAddr[1];
              systemId[2] = pPkt->devAddr[2];
      
              // set middle bytes to zero
              systemId[4] = 0x00;
              systemId[3] = 0x00;
      
              // shift three bytes up
              systemId[7] = pPkt->devAddr[5];
              systemId[6] = pPkt->devAddr[4];
              systemId[5] = pPkt->devAddr[3];
      
              // Set Device Info Service Parameter
              DevInfo_SetParameter(DEVINFO_SYSTEM_ID, DEVINFO_SYSTEM_ID_LEN, systemId);
      
              // Setup and start Advertising
              // For more information, see the GAP section in the User's Guide:
              // http://software-dl.ti.com/lprf/ble5stack-latest/
      
      
              // Create Advertisement set #1 and assign handle
              status = GapAdv_create(&SimpleSerialSocketServer_advCB, &advParams1 ,
                                     &advHandleLegacy);
              SimpleSerialSocketServer_ASSERT(status == SUCCESS);
      
              // Load advertising data for set #1 that is statically allocated by the app
              status = GapAdv_loadByHandle(advHandleLegacy, GAP_ADV_DATA_TYPE_ADV,
                                           sizeof(advData1), advData1);
              SimpleSerialSocketServer_ASSERT(status == SUCCESS);
      
              // Load scan response data for set #1 that is statically allocated by the app
              status = GapAdv_loadByHandle(advHandleLegacy, GAP_ADV_DATA_TYPE_SCAN_RSP,
                                           sizeof(scanResData1), scanResData1);
              SimpleSerialSocketServer_ASSERT(status == SUCCESS);
      
              // Set event mask for set #1
              status = GapAdv_setEventMask(advHandleLegacy,
                                           GAP_ADV_EVT_MASK_START_AFTER_ENABLE |
                                           GAP_ADV_EVT_MASK_END_AFTER_DISABLE |
                                           GAP_ADV_EVT_MASK_SET_TERMINATED);
      
              // Enable legacy advertising for set #1
              status = GapAdv_enable(advHandleLegacy, GAP_ADV_ENABLE_OPTIONS_USE_MAX , 0);
              SimpleSerialSocketServer_ASSERT(status == SUCCESS);
      
              // Create Advertisement set #2 and assign handle
              status = GapAdv_create(&SimpleSerialSocketServer_advCB, &advParams2,
                                     &advHandleLongRange);
              SimpleSerialSocketServer_ASSERT(status == SUCCESS);
      
              // Load advertising data for set #2 that is statically allocated by the app
              status = GapAdv_loadByHandle(advHandleLongRange, GAP_ADV_DATA_TYPE_ADV,
                                           sizeof(advData2), advData2);
              SimpleSerialSocketServer_ASSERT(status == SUCCESS);
      
              // Set event mask for set #2
              status = GapAdv_setEventMask(advHandleLongRange,
                                           GAP_ADV_EVT_MASK_START_AFTER_ENABLE |
                                           GAP_ADV_EVT_MASK_END_AFTER_DISABLE |
                                           GAP_ADV_EVT_MASK_SET_TERMINATED);
      
              // Enable long range advertising for set #2
              status = GapAdv_enable(advHandleLongRange, GAP_ADV_ENABLE_OPTIONS_USE_MAX , 0);
              SimpleSerialSocketServer_ASSERT(status == SUCCESS);
              UART_write(uartHandle, "Info: Done Initializing\n\r", 25);
            }

      Then remove the code related to start advertising (note: this example enables two types of advertising, called legacy and long range - you may decide that the long range advertisement is not required and remove it. I do not recommend to remove the legacy advertising as it may cause compatibility issues with older devices):
              // Enable legacy advertising for set #1
              status = GapAdv_enable(advHandleLegacy, GAP_ADV_ENABLE_OPTIONS_USE_MAX , 0);
              SimpleSerialSocketServer_ASSERT(status == SUCCESS);

      and:
              // Enable long range advertising for set #2
              status = GapAdv_enable(advHandleLongRange, GAP_ADV_ENABLE_OPTIONS_USE_MAX , 0);
              SimpleSerialSocketServer_ASSERT(status == SUCCESS);

      Now, based on your requirements, move this code to the place you want (e.g. in reaction to a button press or something else). That way the device will start advertising when you want (i.e. will be discoverable). The same can be done for scanning.

    I hope it will help,

    Best regards,