SparkFun Forums 

Where electronics enthusiasts find answers.

Everything with the AmbiqSuite SDK tools and software are welcome here.
User avatar
By mysparkfun71451
#212866
I have SparkFun_Apollo3_AmbiqSuite_BSP examples "ble_freertos_amdtps" and "ble_freertos_amdtpc" compiled, using AmbiqMicroSDK Rel2.2.0, and running on each of two Redboard Artemis boards. The client (amdtpc) retrieves the MAC address of the server (amdtps) and displays it under the menu options "Show Scan Results" and "Create Connection". I want to also display the friendly name, which is set to "Amdtp" in "amdtp_main.c" for the server. The scan results retrieved by the client with the function "AppScanGetResult()" in file "ble_menu.c" do not include the friendly name (it is not part of the "appDevInfo_t" structure). I have been trying to find a function that the client can use to retrieve the friendly name, but have been unsuccessful. I know the server broadcasts its name because the "Nrf Connect App", running on an Android phone, sees and displays it prior to connecting. I did find the function "AppDbGetDevName()" in the "App_Framwork_API.pdf" document but there is no way to specify a handle or device ID to indicate which of the responding devices I want the name for. Regardless the function does not return anything when called from the client. Does anyone know how to retrieve the friendly name?
User avatar
By KHE
#212876
amddtpc_main.c function = amdtpcProcMsg

switch(pMsg->hdr.event)
case DM_SCAN_REPORT_IND:
#ifdef BLE_MENU
if ( pMsg->connOpen.peerRpa[0] > 1 && pMsg->connOpen.peerRpa[0] < 20) {
for (int i = 1 ; i < (pMsg->connOpen.peerRpa[0] -3); i++){
am_menu_printf("%c",pMsg->connOpen.peerRpa);
}
am_menu_printf(" = scan result\r\n");
}
#endif


Scan fills pMsg with possible connections. peerRpa array holds name. If it is a real chip, position [0] is the length of the name + 3, so... [0] = length, [1],[2].[3].etc to length - 3 will be the name. I specified length > 0 and < 20 in above statement. Worked for me and even found two chips with 2 different names. Have fun.
User avatar
By mysparkfun71451
#212878
Hi Kerry,

I did figure out that dmEvt_t *pMsg was a pointer to the mother load of scan results, including the bd_addr and any friendly names. I passed the pointer to the ble_menu.c function "BleMenuInit()" function so that I could use it in the "showScanResults()" function. I've been trying to use the function DmFindAdType(), as per the example "SDK/third_party/exactle/sw/apps/watch/watch_main.c", to locate the friendly name in pMsg->scanReport.pData but it isn't finding it even though I can see it in the debugger memory display. Maybe I'll have better luck with the code you are suggesting.
Randy
User avatar
By mysparkfun71451
#212889
Kerry,
Damn you're good! After getting nowhere with my approach, I finally tried yours. With a few corrections to your code, voila I had the friendly name. First off, the function "amdtpcProcMsg" is in the file "amdtp_ main.c" not "amdtpc_main.c". Then the line "am_menu_printf("%c",pMsg->connOpen.peerRpa);" needs [ i ] appended to "peerRpa". The problem that I have with your approach is that I don't get the bd_addr that is associated with the friendly name, which I need later when selecting which device to connect to in the BLE_MENU. With my approach I found that the friendly name and bd_addr show up together in memory just beyond the scope of scanReport.pData so they are apparently not part of the scanResults at the point in the program when the BLE_MENU is being written. I still don't know how to access them at that point but there must be a way. I'll keep trying.
Randy
User avatar
By mysparkfun71451
#212890
Kerry,
Update to my previous reply: I found that I could get the bd_addr from pMsg->scanReport.addr[0] thru [5], and like you I found that I got two different addresses for the same friendly name. One was addrType 0 (random) the other addrType 1 (public).
Randy
User avatar
By KHE
#212891
beautiful. You've got it!

I'm trying to trace:

ble_menu.c case GAP_MENUID_SCAN_START calls
amdtp.main.c AmdtpScanStart which calls
app_master_leg.c AppScanStart which calls
dm_scan.c dmScanStart which sends a message of DM_SCAN_MSG_API_START to
DM SCAN EVENT HANDLER???????????

Should you happen to stumble across the file / function which is called when that message fires, I would love to know. So...which file with which function handles the DM SCAN EVENT. I'll get it eventually by loading all possible files in Ozone and setting breakpoints everywhere 'till I catch the sucker.

I'm losing it in the messaging and can't find the messages destination as of yet. It's getting tied up in the freertos tasking/messaging. I'm trying to convert the client amdtpc to Arduino losing the freertos.

I've re-written the uart to use Serial.printf and things are working up to the DM_SCAN_MSG_API_START at which time it goes ga ga due to no freertos task/messaging. Server works great in Arduino minus the freertos. Maybe I should just try to get freertos Arduino working? No big deal, just curious.
User avatar
By mysparkfun71451
#212924
Kerry,
It does appear to be necessary to parse the friendly names from the "case DM_SCAN_REPORT_IND:" point in the code as per your approach. The code apparently loops through the responding devices and replaces the contents of the pMsg data with each pass. By the time one gets to the BLE_MENU this data is no longer in scope and I haven't found any function to retrieve them at that point. I could save them in my own data structure and pass a pointer to it to BLE_MENU for later retrieval but for now it suffices to just display it before the BLE_MENU connect option 4. One thing I did find is that the byte just before &peerRpa[0] contains the length = len + type + friendly name. So your upper limit of i < (pMsg->connOpen.peerRpa[0] -3) can be replaced with that value and will then handle variable length names which are not 5 characters long. There does appear to be a problem with how the names get written to memory. Some of the characters get values that are not within the ascii range. For instance I detect a device called "Maggie's Room" that has values of 0xe2 0x80 0x99 at the location of the [']. When I run the Nrf Connect App on my android phone I see the name displayed correctly so I assume the problem lies with the code in the SDK. Also, the name at location peerRpa[0] may not be the DM_ADV_TYPE_LOCAL_NAME (value 0x9). I have a Sphero device that has a local name of BB-7BBA (which is how the Nrf Connect displays it), but the name at peerRpa[0] is 'Sphero-Tu******ot" (with a type value of 0x7), where the **** are more of those non-ascii bytes. The local name follows this name. For now, however, I am able to differentiate which device I want to connect to.
With regard to your problem with DM_SCAN_MSG_API_START are you working with SDK 2.4.0? I looked at the dmScanStart function in SDK 2.2.0 and 2.3.0 and find an HCI_**** message in that function rather than the DM_SCAN_MSG_API_START that you are chasing. I'm still trying to find my way around the mind numbing maze of files and functions in 2.2.0 so I haven't started working with the newer releases yet.
Randy
User avatar
By KHE
#212926
I am using SDK 2.4.2. I did succeed in getting freeRtos working in Arduino but it needs a lot of cleanup work b4 I can tell why it works now....but, ... it does work.

I learned a bit about the amdtp naming convention while writing my own naming convention for the server version running under Arduino. amdtpScanDataDisc is an array in amdtp_main.c for the amdtps server example.

I modified it by commenting out the definition there, declaring an external version:

extern uint8_t amdtpScanDataDisc[22]; //Works

and placing the code for naming in a cpp file in my Arduino sketch:

void setLocalName( String s_Name ){
//following line works - came from amtdp_main.c close to beginning
//extern const uint8_t amdtpScanDataDisc[22] = {8,DM_ADV_TYPE_LOCAL_NAME,'R','E','V','1','_','3','W'};

int n = s_Name.length(); //Length of string set in ino file as global String (doesn't include teminator)
if ( n > 20) {
s_Name = s_Name.substring(0,20); //Only allow up to 20 char's
n = s_Name.length(); //need length to change to uint8_t (new length after substring)
}
int i = 2; //1st char(0) is adv type char + # of char's, 2nd char(1) is adv type
char c_AdvName[n+1]; //create Array large enough to hold chars of string + teminator char
strcpy(c_AdvName, s_Name.c_str()); //copy string to char array
//1st char in array must be = to # char's in name (no terminator) + 1 for adv. type. If off by even 1,
// the name will not show up in scans
amdtpScanDataDisc[0] = n+1; //set first array pos to # of char's + 1 for the type of adv packet
amdtpScanDataDisc[1] = DM_ADV_TYPE_LOCAL_NAME; // type of adv packet
for(i=2; i<n+2; i++){ //Add the char's from the string to the amdtpScanDataDisc array starting at pos 2
amdtpScanDataDisc = c_AdvName[i-2];
}
}


That may hopefully help to understand the character issues going on. Anyway, I agree...this is one massive complex example. I had originally thought I might want to write a BLE library based on this stuff, but I don't think I'll get around to that. Spring is coming so no more time to sit on the couch and play.
User avatar
By mysparkfun71451
#213149
Kerry,
I'm bothered by the fact that the throughput timer in the server, once started, continues to run and cause the function showThroughput() to be called, sending msgs to the uart terminal, even after selecting the menu options to stop sending data. In addition, I created two new menu options, one to have the Client close the connection, the other to request that the Server close the connection. Both options work but again the server throughput timer continues to run even after the connection is closed. I can stop this behavior by adding the function WsfTimerStop() to the servers "connection close" option, but then I can't restart it again (even using WsfTimerStartSec()) without resetting the board. I can also prevent the showThroughput() function from being called if connId == 0, but this seems to me to be just a bandaid. Have you encountered this situation and if it bothered you did you find a solution?
Randy
By paulvha
#213156
I have added in showThroughput() :

// only restart timer if throughput
if (gTotalDataBytesRecev != 0) WsfTimerStartSec(&measTpTimer, 1);
else measTpStarted = false;

This way it will restart again when data is received in amdtpDtpRecvCback()
User avatar
By mysparkfun71451
#213157
Thanks for the replies. I did figure out where I was going wrong with trying to restart the timer. I needed to set measTpStarted to false, as Paul has done in his code, along with making the WsfTimerStop() call so that the call to WsfTimerStartSec() in amdtpDtpRecvCback() would execute. Paul's addition of "if(gTotalDataBytes != 0)" is also a nice touch and cleans things up in the output.
Randy
User avatar
By mysparkfun71451
#213201
I finally made sense of why showThroughput() continues to get called even after there is no data exchange. The function WsfTimerStartSec() should not be in the showThroughput() function since it resets the timer every time that function is called. And since gTotalDataBytes is set to zero just before the call to the timer function, a throughput of zero gets displayed when the timer times out and the showThroughput function gets called again. This cycle will repeat for ever until the board is reset. What should be in the showThroughput function instead is "measTpStarted = false;" (which Paul added) in order to allow the WsfTimerStartSec() function to get called at the end of the amdtpDtpRecvCback() function, which is were the timer function belongs. With these changes to the showThroughput() function I only get msgs from that function when data has been exchanged and gTotalDataBytes > 0. Also, I no longer need to use the WsfTimerStop() function to kill the repetitive calls to showThroughput().
 Topic permissions

You can post new topics in this forum
You can reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum