Using adl_atCmdPreParser_t to direct call custom AT handler

Hi All,

My first post. awneil, your posts are very helpful. Thanks for your effort.

I have solved many problems from previous posts and the OpenAT Framework Tutorial, but I am stuck on this issue. Sorry if this is a fundamental C programming question but I have spend many frustrating hours on this.

I want to run my custom AT command via SMS. I know the adl_atCmdSend and adl_atCmdCreate will not work so I am trying to call my command handler function directly. I cannot figure out how to load the adl_atCmdPreParser_t struct correctly.

I am using the following function to test with.

void Test_ATJE(void) {

	int i;
	ascii aOrig[200], aPar[50];

	static wm_lstTable_t ListTable = {

	adl_atCmdPreParser_t parms  = {
		.StrData[0] = 0,			// Incoming command address ??? I don't get this syntax ???
		.Type = ADL_CMD_TYPE_PARA,	// Type
		.NbPara = 0,               	// Number of parameters
		.Port = ADL_PORT_NONE,     	// Port
		.ParaList = wm_lstCreate(WM_LIST_NONE, &ListTable),     // List of parameters
		.StrLength = 0,       		// Incoming command length
		.NI = 0,           			// Notification Identifier
		.Contxt = (void*)NULL  		// Context

	adl_atCmdPreParser_t *ppars;

	sprintf(aOrig, "ATJE=10,20,30,40");		// My custom AT command test string
	//parms.StrData = aOrig;				// ??? crashes ???
	sprintf(buff, "StrData[1] = %s", parms.StrData);
	TRACE(( 2, buff ));

	for ( i=0 ; ; i++ ) {
		if (wm_strGetParameterString(aPar, aOrig, i+1) == NULL)
		ret16 = wm_lstAddItem(parms.ParaList, (void*)aPar);
		if (ret16 == ERROR)
			sprintf(buff, "Add item %s ERRORed", aPar);
			sprintf(buff, "Added item %s at position %d", aPar, ret16);
		TRACE((2, buff ));
	sprintf(buff, "pars.ParaList membersB - 0=%s, 1=%s, 2=%s, 3=%s",
			(ascii*)wm_lstGetItem ( parms.ParaList, 0),
			(ascii*)wm_lstGetItem ( parms.ParaList, 1),
			(ascii*)wm_lstGetItem ( parms.ParaList, 2),
			(ascii*)wm_lstGetItem ( parms.ParaList, 3));

	ppars = &parms;
	sprintf(buff, "pars.ParaList membersA - 0=%s, 1=%s, 2=%s, 3=%s",
			ADL_GET_PARAM(ppars, 0),
			ADL_GET_PARAM(ppars, 1),
			ADL_GET_PARAM(ppars, 2),
			ADL_GET_PARAM(ppars, 3));

	parms.NbPara = (u8)wm_lstGetCount(parms.ParaList);
	sprintf(buff, "Total added items = %d", parms.NbPara);
	TRACE((2, buff ));

	parms.StrLength = strlen(aOrig);
	sprintf(buff, "pars.StrLength = %d", parms.StrLength);
	TRACE((2, buff ));

	if (strstr(aOrig, "ATJE?") > 0)
		parms.Type = ADL_CMD_TYPE_READ;
	if (strstr(aOrig, "ATJE=?") > 0)
		parms.Type = ADL_CMD_TYPE_TEST;

	ATJE_CMD_handler( &parms );
  1. I don’t understand how ‘ascii StrData[1]’ can be used as a pointer as it is only one byte long. How do I use it to point to my string?

  2. Am I doing the right thing by initializing parms, my instance of adl_atCmdPreParser_t?

  3. Am I initializing and loading the wm_lst_t ParaList properly?

  4. Should I be destroying anything before exiting this function?

Any assistance much appreciated.

What version of Open-AT are you using?

Recent versions do have the facility to call custom AT commands from the application - don’t they :question:

I wouldn’t do that.

Rather, I would have a “worker” function to actually do the work, and the command handler just parses the parameters from the user.

Your SMS handler would also do the parsing (there are library functions for this), and call the “worker” function.

I’m not sure that it’s really sufficiently documented nor intended for you to do that.
Hence the above suggestion.

This is a standard ‘C’ programming trick for having a variable-length field at the end of a data structure.

Thanks for your quick response.

ati9 details are:
“DWL”,“V08b11”,“”,“Sierra Wireless”,55236,“122210 15:25”,“e8a16b54”,“00010000”
“FW”,“FW_SRC_746_8.Q2687RDG”,“R7.46.0.201108091301.FXT009”,“Sierra Wireless”,2216044,“080911 13:01”,“2f1beedd”,“00020000”
-“Developer Studio”,“”
-“Open AT Embedded Software Suite package”,“”
-“Open AT OS Package”,“”
-“Firmware Package”,“”
-“WIP Plug-in Package”,“”

I was not aware of this. All I have to go on is previous posts and the Framework Tutorial document. This would be very convenient.

I receive an AT command string via SMS, and I have a very comprehensive custom AT command handler function that works great when AT command is entered in the normal way. But, in this scenario, I am not sure what the ‘command handler’ is that you refer to.

Up to this point, I have been parsing the user string with wm_strGetParameterString and processing it manually with a function that effectively duplicated all the functionality of my custom command handler. It worked, but seemed very inefficient, so I was looking for a better way.

I am more than happy not to do it if there is a better way :slight_smile:

Yes, I get this. I reserve a chunk of memory the sizeof(adl_atCmdPreParser_t) plus the length of my string. Put the struct at the start and copy in my string at &StrData[0]. I am sure I could get this to work. Although it is a moot point if I can just use my custom AT command handler.

Thanks for bearing with me, I am on a pretty steep learning curve here.

You need to look in the ADL User Guide.

Don’t have mine to hand, but look for a …CommandSubscribeExt… function, or similar

The thing that you actually specified in the subscription.

So just take the duplicate functionality out into a separate function. And call that function from both your SMS handler and your custom AT command handler

I did what you suggested and got it all working. I do know what a command handler is, I just was not sure which one you were referring to.

Thanks for your assistance.

fyi, outdated, but I met the same problem quite a while ago, 2009 or so? This … ls/ve_at.c is the same workaround as you suggested. The advantage of it is that it will also work without linking to siwi libs, e.g. a standalone simulator, but perhaps the RTE actually works nowadays.


Thanks for your response and the link Jeroen. I got it working by basically doing what awneil suggested.

Apparently the latest version of OpenAT will allow me to call my own custom AT commands. But I admit, I am a bit confused about all the different software blocks and tools involved, how they relate and what is compatible with what, let alone am I running the latest version of them all.

But I am loving the learning. I read on and always stumble across the answer eventually.