app.c 12 KB
Newer Older
Martin Horauer's avatar
Martin Horauer committed
1
2
3
4
5
6
/**
 * \file app.c
 *
 * \mainpage Application for USB communication tests
 *
 * \brief This program extends the APP_UART1_ECHO application with a native
Martin Horauer's avatar
Martin Horauer committed
7
 *        USB communication. The APP_UART1_ECHO application receives characters
Martin Horauer's avatar
Martin Horauer committed
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
 *        via UART using a Receive ISR - when an entire message is received,
 *        it sends the message to a communication Task AppTaskCom for
 *        further processing (reply).
 *        You need a TTL-USB cable connected to UART1 P0.0 and P0.1 to test
 *        this application.
 *
 *        USB communication is done in the AppTaskUSB. This task periodically
 *        checks for incoming messages and handles the reply. To run this
 *        demo perform the following tasks:
 *        (1) Build & flash the application using the Makefile or import the
 *        project into Eclipse and run the application.
 *        (2) Connect a MicroUSB cable to the *native USB* port next to the
 *        Ethernet jack.
 *        (3) Compile the "usb_demo_pc" program. The program performs a
 *        low-level USB communication relying on the libusb library.
 *        Launch the resulting program and enter a number between 1 and 1000
 *        at the programs prompt. The program sends a string that is replied by
 *        XMC application in reverse order.
 *
 * \author Beneder Roman, Martin Horauer, UAS Technikum Wien
 * \revision 0.2
 * \date 02-2018
 */

/******************************************************************* INCLUDES */
#include <app_cfg.h>
#include <cpu_core.h>
#include <os.h>

#include <bsp.h>
#include <bsp_sys.h>
#include <bsp_int.h>
#include <usb_demo_lib.h>

#include <string.h>
#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>

#include <xmc_uart.h>
#include <xmc_gpio.h>

#include <GPIO.h>

#include <lib_math.h>

#if SEMI_HOSTING
#include <debug_lib.h>
#endif

#if JLINK_RTT
#include <SEGGER_RTT.h>
#include <SEGGER_RTT_Conf.h>
#endif

/******************************************************************** DEFINES */
#define ACK  0x6
#define MAX_MSG_LENGTH 20
#define NUM_MSG        3

/********************************************************* FILE LOCAL GLOBALS */
static  CPU_STK  AppStartTaskStk[APP_CFG_TASK_START_STK_SIZE];            // <1>
static  OS_TCB   AppStartTaskTCB;

static  CPU_STK  AppTaskComStk[APP_CFG_TASK_COM_STK_SIZE];
static  OS_TCB   AppTaskComTCB;

static  CPU_STK  AppTaskUSBStk[APP_CFG_TASK_USB_STK_SIZE];
static  OS_TCB   AppTaskUSBTCB;

// Memory Block                                                           // <2>
OS_MEM      Mem_Partition;
CPU_CHAR    MyPartitionStorage[NUM_MSG - 1][MAX_MSG_LENGTH];
// Message Queue
OS_Q        UART_ISR;

/****************************************************** FILE LOCAL PROTOTYPES */
static  void AppTaskStart (void  *p_arg);
static  void AppTaskCreate (void);
static  void AppObjCreate (void);
static  void AppTaskCom (void  *p_arg);
static  void AppTaskUSB (void  *p_arg);

/************************************************************ FUNCTIONS/TASKS */

/*********************************************************************** MAIN */
/**
 * \function main
 * \params none
 * \returns 0 always
 *
 * \brief This is the standard entry point for C code.
 */
int main (void)
{
	OS_ERR  err;

	// Disable all interrupts                                               // <3>
	BSP_IntDisAll();
	// Enable Interrupt UART, & USB
	BSP_IntEn (BSP_INT_ID_USIC1_01); //**
	BSP_IntEn (BSP_INT_ID_USIC1_00); //**
	BSP_IntEn (BSP_INT_ID_USB0_00); //**

// init SEMI Hosting DEBUG Support                                        // <4>
#if SEMI_HOSTING
	initRetargetSwo();
#endif

// init JLINK RTT DEBUG Support
#if JLINK_RTT
	SEGGER_RTT_ConfigDownBuffer (0, NULL, NULL, 0,
				     SEGGER_RTT_MODE_BLOCK_IF_FIFO_FULL);
	SEGGER_RTT_ConfigUpBuffer (0, NULL, NULL, 0,
				   SEGGER_RTT_MODE_BLOCK_IF_FIFO_FULL);
#endif

	// Init uC/OS-III
	OSInit (&err);                                                          // <5>
	if (err != OS_ERR_NONE)
		APP_TRACE_DBG ("Error OSInit: main\n");

	/* Create the start task */                                             // <6>
	OSTaskCreate ( (OS_TCB     *) &AppStartTaskTCB,
		       (CPU_CHAR   *) "Startup Task",
		       (OS_TASK_PTR) AppTaskStart,
		       (void       *) 0,
		       (OS_PRIO) APP_CFG_TASK_START_PRIO,
		       (CPU_STK    *) &AppStartTaskStk[0],
		       (CPU_STK_SIZE) APP_CFG_TASK_START_STK_SIZE / 10u,
		       (CPU_STK_SIZE) APP_CFG_TASK_START_STK_SIZE,
		       (OS_MSG_QTY) 0u,
		       (OS_TICK) 0u,
		       (void       *) 0,
		       (OS_OPT) (OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR),
		       (OS_ERR     *) &err);

	// Start multitasking (i.e., give control to uC/OS-III)
	OSStart (&err);                                                         // <7>
	if (err != OS_ERR_NONE)
		APP_TRACE_DBG ("Error OSStart: main\n");

	while (1) {                                                             // <8>
		APP_TRACE_DBG ("Ouch, should have never gotten here! - main\n");
	}
	return 0;
}

/*************************************************************** STARTUP TASK */
/**
 * \function AppTaskStart
 * \ params p_arg ... argument passed to AppTaskStart() by
 *                    OSTaskCreate()
 * \returns none
 *
 * \brief Startup (init) task that loads board support functions,
 *        initializes CPU services, the memory, the systick timer,
 *        etc. and finally invokes other application tasks.
 */
static void AppTaskStart (void *p_arg)
{
	CPU_INT32U  cpu_clk_freq;
	CPU_INT32U  cnts;
	OS_ERR      err;

	(void) p_arg;
	// initialize BSP functions
	BSP_Init();                                                             // <9>
	// initialize the uC/CPU services
	CPU_Init();
	// determine SysTick reference frequency
	cpu_clk_freq = BSP_SysClkFreqGet();
	// determine nbr SysTick increments
	cnts = cpu_clk_freq / (CPU_INT32U) OSCfg_TickRate_Hz;
	// init uCOS-III periodic time src (SysTick)
	OS_CPU_SysTickInit (cnts);
	// initialize memory management module
	Mem_Init();
	// initialize mathematical module
	Math_Init();

// compute CPU capacity with no task running
#if (OS_CFG_STAT_TASK_EN > 0u)                                           // <10>
	OSStatTaskCPUUsageInit (&err);
	if (err != OS_ERR_NONE)
		APP_TRACE_DBG ("Error OSStatTaskCPUUsageInit: AppTaskStart\n");
#endif

	APP_TRACE_INFO ("Creating Application Objects...\n");                // <11>
	// create application objects
	AppObjCreate();

	APP_TRACE_INFO ("Creating Application Tasks...\n");                  // <12>
	// create application tasks
	AppTaskCreate();

	while (DEF_TRUE) {                                                     // <13>
		// Suspend current task
		OSTaskSuspend ( (OS_TCB *) 0, &err);
		if (err != OS_ERR_NONE)
			APP_TRACE_DBG ("Error OSTaskSuspend: AppTaskStart\n");
	}
}

/************************************************* Create Application Objects */
/**
 * \function AppObjCreate()
 * \brief Creates application objects.
 * \params none
 * \returns none
 */
static void AppObjCreate (void)
{
	OS_ERR      err;

	// Create Shared Memory
	OSMemCreate ( (OS_MEM    *) &Mem_Partition,
		      (CPU_CHAR  *) "Mem Partition",
		      (void      *) &MyPartitionStorage[0][0],
		      (OS_MEM_QTY)  NUM_MSG,
		      (OS_MEM_SIZE) MAX_MSG_LENGTH * sizeof (CPU_CHAR),
		      (OS_ERR    *) &err);
	if (err != OS_ERR_NONE)
		APP_TRACE_DBG ("Error OSMemCreate: AppObjCreate\n");

	// Create Message Queue
	OSQCreate ( (OS_Q *)     &UART_ISR,
		    (CPU_CHAR *) "ISR Queue",
		    (OS_MSG_QTY) NUM_MSG,
		    (OS_ERR   *) &err);
	if (err != OS_ERR_NONE)
		APP_TRACE_DBG ("Error OSQCreate: AppObjCreate\n");
}

/*************************************************** Create Application Tasks */
/**
 * \function AppTaskCreate()
 * \brief Creates one application task.
 * \params none
 * \returns none
 */
static void  AppTaskCreate (void)
{
	OS_ERR      err;

	// create AppTask_COM
	OSTaskCreate ( (OS_TCB     *) &AppTaskComTCB,
		       (CPU_CHAR   *) "TaskCOM",
		       (OS_TASK_PTR) AppTaskCom,
		       (void       *) 0,
		       (OS_PRIO) APP_CFG_TASK_COM_PRIO,
		       (CPU_STK    *) &AppTaskComStk[0],
		       (CPU_STK_SIZE) APP_CFG_TASK_COM_STK_SIZE / 10u,
		       (CPU_STK_SIZE) APP_CFG_TASK_COM_STK_SIZE,
		       (OS_MSG_QTY) 0u,
		       (OS_TICK) 0u,
		       (void       *) 0,
		       (OS_OPT) (OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR),
		       (OS_ERR     *) &err);
	if (err != OS_ERR_NONE)
		APP_TRACE_DBG ("Error OSTaskCreate: AppTaskCreate\n");

	// create AppTask_USB
	OSTaskCreate ( (OS_TCB     *) &AppTaskUSBTCB,
		       (CPU_CHAR   *) "TaskUSB",
		       (OS_TASK_PTR) AppTaskUSB,
		       (void       *) 0,
		       (OS_PRIO) APP_CFG_TASK_USB_PRIO,
		       (CPU_STK    *) &AppTaskUSBStk[0],
		       (CPU_STK_SIZE) APP_CFG_TASK_USB_STK_SIZE / 10u,
		       (CPU_STK_SIZE) APP_CFG_TASK_USB_STK_SIZE,
		       (OS_MSG_QTY) 0u,
		       (OS_TICK) 0u,
		       (void       *) 0,
		       (OS_OPT) (OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR),
		       (OS_ERR     *) &err);
	if (err != OS_ERR_NONE)
		APP_TRACE_DBG ("Error OSTaskCreate: AppTaskCreate\n");
}

/*********************************** Communication Application Task */
/**
 * \function AppTaskCom
 * \ params p_arg ... argument passed to AppTaskCom() by
 *                    AppTaskCreate()
 * \returns none
 *
 * \brief Task for Communication between UART_ISR and Task1
 *        was developed by F. Ney according to the following pattern:
 *
 * https://doc.micrium.com/display/osiiidoc/Keeping+the+Data+in+Scope
 */
static void AppTaskCom (void *p_arg)
{
	void        *p_msg;
	OS_ERR      err;
	OS_MSG_SIZE msg_size;
	CPU_TS      ts;
	CPU_CHAR    msg[MAX_MSG_LENGTH];
	CPU_INT08U  i = 0;
	CPU_CHAR    debug_msg[MAX_MSG_LENGTH + 30];

	(void) p_arg;                                                          // <14>
	APP_TRACE_INFO ("Entering AppTaskCom ...\n");
	while (DEF_TRUE) {
		// empty the message buffer
		memset (&msg, 0, MAX_MSG_LENGTH);                                    // <15>

		// wait until a message is received
		p_msg = OSQPend (&UART_ISR,                                          // <16>
				 0,
				 OS_OPT_PEND_BLOCKING,
				 &msg_size,
				 &ts,
				 &err);
		if (err != OS_ERR_NONE)
			APP_TRACE_DBG ("Error OSQPend: AppTaskCom\n");

		// obtain message we received
		memcpy (msg, (CPU_CHAR*) p_msg, msg_size - 1);                       // <17>

		// release the memory partition allocated in the UART service routine
		OSMemPut (&Mem_Partition, p_msg, &err);                              // <18>
		if (err != OS_ERR_NONE)
			APP_TRACE_DBG ("Error OSMemPut: AppTaskCom\n");

		// send ACK in return
		XMC_UART_CH_Transmit (XMC_UART1_CH1, ACK);                           // <19>

		// print the received message to the debug interface
		sprintf (debug_msg, "Msg: %s\tLength: %d\n", msg, msg_size - 1);     // <20>
		APP_TRACE_INFO (debug_msg);

		// send the received message back via the UART pre-text with "XMC: "
		XMC_UART_CH_Transmit (XMC_UART1_CH1, 'X');                           // <21>
		XMC_UART_CH_Transmit (XMC_UART1_CH1, 'M');
		XMC_UART_CH_Transmit (XMC_UART1_CH1, 'C');
		XMC_UART_CH_Transmit (XMC_UART1_CH1, ':');
		XMC_UART_CH_Transmit (XMC_UART1_CH1, ' ');
		for (i = 0; i <= msg_size; i++) {
			XMC_UART_CH_Transmit (XMC_UART1_CH1, msg[i]);
		}
		XMC_UART_CH_Transmit (XMC_UART1_CH1, '\n');
	}
}

/*********************************** USB Communication Application Task */
/**
 * \function AppTaskUSB
 * \ params p_arg ... argument passed to AppTaskUSB() by
 *                    AppTaskCreate()
 * \returns none
 *
 * \brief Task for Communication between AppTaskUSB and the PC.
 */
static void AppTaskUSB (void *p_arg)
{
	OS_ERR      err;

	uint8_t run = 1;
	int8_t retusb = 0;
	char text[SIZE] = {"\0"};

	if (init() > 0)
		run = 0;

	while (run) {
		if ( (retusb = usb_incomming (text)) < 0) {
			run = 0;
		} else if (retusb == RECEIVE) {
			change (text);
			if (usb_transfer (text) < 0)
				run = 0;
			memset (text, '\0', strlen (text));
		}
		OSTimeDly (10, OS_OPT_TIME_DLY, &err);
	}

	//Switches on the LED P1.0 in case of an error.
	error_message_led();
}

/************************************************************************ EOF */
/******************************************************************************/