Simple UART Echo Program

Hi!
I’m glad to be the first one that puts a code on this section.
Any improvements to my code will be appreciated.

Title
Simple UART Echo Program

Synopsis
My code is a simple application that set UART1 to Data mode, reads Data and then echoes it to the same port.
If ‘Esc’ key is pressed UART1 is set back to AT mode.

Software version
Developer Studio 1.1.2
Build Version 1.1.2.201005261706-R4588

Hardware version
WMP150

Features/Services covered
FCM

Plug-ins used

/*
| DESCRIPTION:
|   UART Example
|
|
|	Refer to: AT_Command_Interface_Guide.pdf
|	Refer to: ADL_User_Guide_v6_31.pdf
|
|	Program state diagram:
|	----------------------
|	(Config uart)-->(set data mode)-->(echo uart1 char) --ESC recived-->(switch to AT MODE)
|
 */


/*----------------------------- includes ---------------------------------*/
#include "adl_global.h" /* Application development layer */

/*-------------------------------- defines -------------------------------*/
#define UART_1 ADL_AT_PORT_TYPE(ADL_PORT_UART1,ADL_AT_RSP) /* refer to ADL User Guide pag 67, rspflag */

/* --- UART Config enums --- */
/* Data format */
enum UART_FORMAT{

	NO_USE,
	DATA8_STOP2,
	DATA8_STOP1_PARITY1,
	DATA8_STOP1,
	DATA7_STOP2,
	DATA7_STOP1_PARITY1,
	DATA7_STOP1

};

/* parity bit config */
enum UART_PARITY{

	ODD,
	EVEN,
	MARK,
	SPACE,
	NONE_PARITY

};

/* flow control */
enum UART_FLOW_CONTROL{

	CTS_RTS,
	NO_CTS_RTS

};

/* UART mode type */
enum UART_TYPE{

	DATAMODE,
	ATMODE

};

/*----------------------------- data types ---------------------------*/


/*------------------------------ variables ---------------------------*/

/*  can anybody help me with stack size???? */
const u16 wm_apmCustomStackSize = 1024*3; 	/* application stack size (trial&error to determine size)*/

s8 handle_uart1;							/* UART1 handler */
u8 mode_uart1;								/* UART1 mode type */


/*---------------------------- Function prototypes --------------------------*/
/*---------------------------------------------------------------------------
| Portability: WMP 100/150
|----------------------------------------------------------------------------
| Routine description:
|  * Configures UART1 as specified by parameters
|	 If all ok returns 0 else -1
|---------------------------------------------------------------------------
| Parameters description:
|	u8 mode: AT COMMANDS or DATA mode
|	int speed: port baud rate
|	u8 format: data format
|	u8 parity: parity bit
|	u8 flow_control: flow control
|	*see defines
/---------------------------------------------------------------------------*/
int initUART1(u8 mode, int speed, u8 format, u8 parity, u8 flow_control);

/*---------------------------------------------------------------------------
| Portability: WMP 100/150
|----------------------------------------------------------------------------
| Routine description:
|  * Handler of control events in UART, sets UART mode
|	 If all ok returns TRUE else FALSE
|---------------------------------------------------------------------------
| Parameters description:
|	adl_fcmEvent_e evnt: FCM event that raised handler.
/---------------------------------------------------------------------------*/
static bool EvhCrtlUart1(adl_fcmEvent_e evnt);

/*---------------------------------------------------------------------------
| Portability: WMP 100/150
|----------------------------------------------------------------------------
| Routine description:
|  * Handler when data recived, echo data until ESC recived, then switch to ATMODE
|---------------------------------------------------------------------------
| Parameters description:
|	u16 datalength: number of bytes recived
|	u8 *data: pointer to data recived
/---------------------------------------------------------------------------*/
static bool EvhDataUart1(u16 datalength, u8 *data);


/*---------------------------------------------------------------------------
| Portability: WMP 100/150
|----------------------------------------------------------------------------
| Routine description:
|  * Handler of port configuration using AT, al responses are ignored
|---------------------------------------------------------------------------
| Parameters description:
|	adl_atResponse_t *Rsp: response from AT command
/---------------------------------------------------------------------------*/
static void EvhConfUartx(adl_atResponse_t *Rsp);


/*-------------------------------- Functions --------------------------------*/

int initUART1(u8 mode, int speed, u8 format, u8 parity, u8 flow_control){

	char comand[15];
	/* Check if port available*/
	if(adl_fcmIsAvailable(ADL_FCM_FLOW_V24_UART1))
	{
		/* Save UART operation mode: DATA o AT*/
		mode_uart1=mode;

		/* subscribe to FCM uart service */
		handle_uart1=adl_fcmSubscribe(ADL_FCM_FLOW_V24_UART1, EvhCrtlUart1,EvhDataUart1);

		/* config parity with AT Command*/
		wm_sprintf(comand,"AT+ICF=%d,%d", format, parity);
		adl_atCmdCreate(comand, UART_1,EvhConfUartx,NULL);

		/* speed  with AT Command*/
		wm_sprintf(comand,"AT+IPR=%d", speed);
		adl_atCmdCreate(comand, UART_1,EvhConfUartx,NULL);

		/* flow control  with AT Command*/
		switch(flow_control){
		/* hardware flow control */
		case CTS_RTS:
			adl_atCmdCreate("AT+IFC=2,2",UART_1,EvhConfUartx,NULL);
			break;
			/* no hardware flow control */
		case NO_CTS_RTS:
			adl_atCmdCreate("AT+IFC=0,0",UART_1,EvhConfUartx,NULL);
			break;
		}
		/* save configuration */
		adl_atCmdCreate("AT&W", UART_1, (adl_atRspHandler_t)EvhConfUartx,NULL);
		return 0;
	}
	return -1;

}/*initUART1*/


static bool EvhCrtlUart1(adl_fcmEvent_e evnt){
	switch (evnt)
    {
    /* when com is open, operation mode is defined */
    case ADL_FCM_EVENT_FLOW_OPENNED:
    	/*  DATA MODE */
    	if(mode_uart1 == DATAMODE){
    		adl_atSendResponse(ADL_AT_RSP, "\r\nUART1: Data Mode");
    		adl_fcmSwitchV24State(handle_uart1,ADL_FCM_V24_STATE_DATA);
    	}
    	/* AT MODE */
    	else if(mode_uart1 == ATMODE){
    		adl_atSendResponse(ADL_AT_RSP, "\r\nUART1: AT Mode");
    		adl_fcmSwitchV24State(handle_uart1,ADL_FCM_V24_STATE_AT);
    	}
    	break;

    case ADL_FCM_EVENT_V24_DATA_MODE:
    	/* DATA MODE OK */
    	break;

    case ADL_FCM_EVENT_V24_AT_MODE:
    	/* AT MODE OK */
    	break;

    case ADL_FCM_EVENT_RESUME:
    	break;

    case ADL_FCM_EVENT_MEM_RELEASE:
    	break;

    default:
    	return FALSE;
    	break;
    }
    return TRUE;
}/*EvhCrtlUart1*/




static bool EvhDataUart1(u16 datalength, u8 *data){

	/* when data recived echo it */
	s8 error;

	/* check for ESC to switch to AT MODE */
	if(data[0] == 27)
	{
		adl_fcmSwitchV24State(handle_uart1,ADL_FCM_V24_STATE_AT);
	}
	else
	{
		error = adl_fcmSendData(handle_uart1,data,datalength);
		switch(error){
		case ADL_RET_ERR_PARAM:
			adl_atSendResponse(ADL_AT_RSP,"FCM send data: parameter incorrect value");
			break;
		case ADL_RET_ERR_UNKNOWN_HDL:
			adl_atSendResponse(ADL_AT_RSP,"FCM send data: unknown handle");
			break;
		case ADL_RET_ERR_BAD_STATE:
			adl_atSendResponse(ADL_AT_RSP,"FCM send data: not ready to send data");
			break;
		case ADL_FCM_RET_ERR_WAIT_RESUME:
			adl_atSendResponse(ADL_AT_RSP,"FCM send data: flow has no more credit");
			break;
		case ADL_RET_ERR_SERVICE_LOCKED:
			adl_atSendResponse(ADL_AT_RSP,"FCM send data: from a low level");
			break;
		}
	}
	return TRUE;

}/*EvhDataUart1*/

static void EvhConfUartx(adl_atResponse_t *Rsp){

}/*EvhConfUartx*/


void adl_main ( adl_InitType_e InitType )
{
	initUART1(DATAMODE, 115200 , DATA8_STOP1 , NONE_PARITY , NO_CTS_RTS);
}/*adl_main*/

EDIT 15/03/2011: bugs fixed.

To use this code, you will need to do the following (assuming Developer Studio 1.2.0):

  1. File > New > Open-AT Project
  2. Enter a Name for the project
  3. Adjust the project location, if you wish
  4. Ensure ‘Project Type’ is set to ‘Application’
  5. Next >
  6. Choose the required ‘SDK Profile’. This automatically selects the corresponding ‘OS’ and ‘Firmware’ versions - they must match the versions installed on the target hardware
  7. NO plug-ins are required
  8. Next >
  9. Do not select a Sample
  10. Next >
  11. Select only ‘[Target] ARM EABI GCC’ - this will create an image to be downloaded and run on the target hardware.
  12. Finish. Developer Studio will now create a “blank” project and, eventually, opens the ‘Application Settings’ editor
  13. Close the ‘Application Settings’ editor - leaving everything at defaults
  14. Open the ‘main.c’ file in the project’s ‘src’ folder
  15. Delete the entire contents of the file, and paste-in the code from the forum (note the ‘Select All’ link in the code box)
  16. At the end of the ‘main.c’ file:
    Delete the line: void adl_main ( adl_InitType_e InitType )
    Replace it with: void main_task ( void )
  17. Save the file
  18. Click the hammer icon to build the project
  19. When the build finishes, check the ‘Problems’ tab for any problems - there should be none!
  20. Click the ‘Target Management’ button to switch to the Target Management Perspective
  21. Ensure that the target device is powered-up and connected and two UARTs are connected to COM ports of the PC:
  • UART1 must be connected to a terminal program (eg, Hyperterminal);
  • The other UART (either UART2 or the USB) will be used by the Developer Studio.
  1. In Developer Studio, Select the required COM port (not the one with UART1) in the ‘Devices’ pane - ensure that the check mark is on the required port
  2. Ensure that the port settings are correct (button with the the “screwdriver & spanner” icon)
  3. Open the port - Developer Studio should automatically switch the device to ‘Development’ mode
  4. Click the ‘Download a dwl file’ button (icon looks like a parcel tied up with string)
  5. Click the ‘Workspace’ button, and choose the .dwl file for the project
  6. OK
  7. When the download completes, the device will restart automatically
  8. If the application doesn’t start automatically, issue the AT+WOPEN=1 command to start it (this won’t have to be done again unless the application is explicitly stopped with AT+WOPEN=0)
  9. When the application is running, “UART1: Data Mode” will be sent on UART1, and anything sent to that port will be echoed; ie, anything you type into the terminal will be sent straight back to you!
  10. You can escape from the echo mode by sending an ESC character

Thanks awneil for explain how to execute it!

As I’ve commented in this post:
[url]https://forum.sierrawireless.com/t/ds-1-2-0-create-a-tradional-app-no-task-table/4875/1]
It’s possible to run it in DS 1.2.0 without modifying the code.

there is a serious bug in there:

int initUART1(u8 mode, int speed, u8 format, u8 parity, u8 flow_control){

char comand[10];

this buffer is being overrun by

/* speed with AT Command*/
wm_sprintf(comand,“AT+IPR=%d”, speed);
adl_atCmdCreate(comand, UART_1, (adl_atRspHandler_t)EvhConfUartx,NULL);

and the command fails

I would strongly recommend that you do not use casts like that!

The cast is unnecessary, but it will mask any compiler warnings or errors if your handler prototype is wrong!

I really struggled to find in the docs how to turn AT off to be able to use the port. Thank you for this example ! I was lost without it. In my app I have no interest in AT commands.

Questions:

Even with fcm, even setting wip debug to USB a lot of stuff still wants to go to Uart1, I wasted 4 hours trying to get the http api working & only saw the ‘Feature not supported’ message after running the example code. anything I can do to set everything to USB & leave the Uarts permanently in data mode ?

Is there any method to set Uart control lines (CTS) without enabling flow control ?

My void main_task ( void ) is exiting & the application then runs via timers & events, some of the example are like this too. Is this correct usage ?

Every now & then, especially If I leave it overnight. The unit goes into a state where it reboots every 10 seconds doing an RTK dump into the trace log. Seems to recover if I reset & re download same app. Anything to read in that dump ?.

Any tips to make sure it is stable over long periods without human intervention, my main app includes a state model to automatically reconnect GPRS & IP links. I’m talking more on the longterm stability of the AT OS.

You should really post those questions as a separate thread

bugs fixed.

Thanks Josepvr

This helped immensly. I cant understand why Sierra didnt have something similar already written!

Matt

Thank you for commenting my code.
I encourage everybody to post their codes to increase this community.

Using this code I wasn’t able to set the baud rate of the UART. It seemed to run the format and parity AT command but failed on subsequent AT commands. Is anyone else experiencing this? Using 7.44 on an FXT003

In what way, exactly, did it “fail” :question:

The adl_atResponse_t *Rsp from all three adl_atCmdCreate functions returned “OK” . The two subsequent calls after the first are not successfully executed irrespective of the “OK” response. The baud rate for instance remains set at 115200(Default) as confirmed using realterm.

Is it possible the modem is failing to execute the commands before switching to datamode?

Note that you need to distinguish an OK [b]result code /b returned by the API function call from an “OK” response returned by the actual AT Command.

Are you sure that you’re getting an “OK” response returned by the actual AT Command?

You are right mattw.
There is a bug in my code… i’m sorry :blush:
You have to save uart configuration after setting it.

In function

int initUART1

add next line after setting parameters:

adl_atCmdCreate("AT&W", UART_1, (adl_atRspHandler_t)EvhConfUartx,NULL);

Now, code in first post is fixed.

I am starting development on an aftermarket kit where Uart2 is already hardwired to a gps receiver. How do I go about setting developer studio to Uart1?

Great step-by-step example thread for us newcomers btw.

You don’t.

DS knows nothing about UARTs - it just sees the COM ports (which may be “virtual”) on the PC.

So you just use whicher COM port is connected to your UART1…

Awneil - maybe you can guide me

I connect to my device usb, open the correct COM port in DS and send at commands using the console view. AT commands go through fine so I have a good connection.

Now I try to upload the latest firmware… I go to the status box in the target management view and click the little package symbol beside the Firmware heading. I pick the latest package from the drop down list and start upload. The green status bar completes and then I get the error popup saying “No target detected”.

If I use at+wdwl in DS or any other terminal program I get error response +CME ERROR: 3 which stands for operation not supported.

I am using the Xact Technologies dev board utilizing the WMP100. Xact has their own dwl loader program but I am waiting on it getting updated… Based on what I have described do you think I missing a step in the upload process or is it just that my pcb won’t accept software from DS?

I am sorry I know this is pretty vague

This really has nothing to do with this thread - or even this section of the forum!

It would be better to start a new thread in a more appropriate section, and give a link back to this for reference.

What version of firmware are you using?

The ability to update the firmware over USB is relatively recent:

The firmware version they ship does not support AT+WDWL on the USB port

Ok well that explains it. So if I update the firmware via Uart I should afterwards be able to use the usb functionality? Thanks

Btw I have started a new thread if you would like to respond further:

https://forum.sierrawireless.com/t/using-ds-with-xact-dev-board/5277/1