It is not exciting to read a lot of general stuff about software API's, so let's code our first real-life application right now.
Jump start example - Heart Beat Blinky LED
This example aims to show how straightfoward it is to code a "heart beat" LED task with YasK. An complex blink pattern is not so easy to program from scratch. See how clean and linear this code looks. This code is so strange: it contains neither while(), nor for() loops, and just one if-then-else statement.
This piece of code implements the most important concepts of YasK, so look at it carefully, please.
The hear_beat task drives the LED as follows :
while(true) {
ON: 30 ms
OFF: 150 ms
ON: 30 ms
OFF: 700 ms
}
The code of the heart_beat task:
short heart_beat( YASK_MSG_T *msg)
{
static char mbx = YASK_NONE; // mailbox handle
if( msg)
{
switch( msg->idn)
{
case 1: // LED On 1
IOSset_bit( LED_PORT, LED_BIT);
// Start the first timer (30 ms) and execute case 2 when done
YASKpost( mbx, // mailbox
2, // message identifier
0, // optional indentifier
30, // time out
YASK_PRI_TSK); // message priority
break;
case 2: // LED Off 1
IOSreset_bit( LED_PORT, LED_BIT);
// Start the second timer (150 ms) and execute case 3 when done
YASKpost( mbx, 3, 0, 150, YASK_PRI_TSK);
break;
case 3: // LED On 2
IOSset_bit( LED_PORT, LED_BIT);
// Start the third timer (30 ms) and execute case 4 when done
YASKpost( mbx, 4, 0, 30, YASK_PRI_TSK);
break;
case 4: // LED Off 2
IOSreset_bit( LED_PORT, LED_BIT);
// Start the fourth timer (700 ms) and execute case 1 when done
YASKpost( mbx, 1, 0, 700, YASK_PRI_TSK);
break;
default: // Warn if an unknown message is received
printf("heart_beat: Unknowkn message %d\r\n", msg->idn);
break;
} // End of switch on received message identifier
}
else // come here if I am called with a NULL message
{
// get a mailbox handle on myself (this task) and give it a friendly name
mbx = YASKregister( heart_beat, // Recipient task
"HeartBeat"); // Friendly mailbox name
// Start blinking immediately: execute case 1 as soon as possible
// YASKpost( mailbox, identifier, option, delay, priority)
YASKpost( mbx, 1, 0, 0, YASK_PRI_TSK);
} // End of if/else on message
return 0;
} // End of heart_beat()
Explanations:
short heart_beat( YASK_MSG_T *msg)
The heart_beat task is a regular C function with only one input parameter: YASK_MSG_T *msg. This input contains the message sent to the task. The task returns a short integer upon completion.
static char mbx = YASK_NONE; // mailbox handle
The variable mbx contains a mailbox handle. This handle is simply an index of an internal array of YasK. This handle is provided by YasK when I register the mailbox. The variable must be static in order to keep this handle between two activations of the task.
if( msg)
{
This test checks if the received message is not NULL. YasK never sends NULL messages to a task, so when a task receives a NULL message, that generally means that the task needs to be started. This occurs once during program start up.
switch( msg->idn)
{
Once I have checked that the received message contains information, I start a switch/case statement based on the identifier contained in the message. The identifier is an unsigned char.
case 1: // LED On
IOSset_bit( LED_PORT, LED_BIT);
In case 1, I first set the output port wired to my LED in order to light it. IOSset_bit is a macro that does this job. This macro does not belong to YasK. In your implementation, you will put here your own code.
YASKpost( mbx, // mailbox
2, // message identifier
0, // optional indentifier
30, // time out (ms)
YASK_PRI_TSK); // message priority
break;
Once the led is lighted, I need to wait 30 ms before I turn it off. The YASKpost call does this job. The YASKpost call is the most important routine of YasK's API. It simply puts a message in a recipient's mailbox and returns. YasK will then struggle to deliver the message to the recipient task in time.
The 5 input parameters of the YASKpost call are the following:
- mbx is the mailbox in which I put the message. in this case it is the own mailbox of the heart_beat task - this will be clarified soon
- 2: this message identifier will be put inside the message received by the recipient task (heart_beat = me)
- 0: this is an optional identifier, not used here
- 30: the message will be delivered once this 30 ms has timed out
- YASK_PRI_TSK: this is the standard priority of a message
Keep in mind that the YASKpost call does not wait during 30 ms. It puts the message in the mailbox and returns immediately an integer telling whether the message has been succesffully posted or not.
after the YASKpost call, we can break.
case 2: // LED Off 1
IOSreset_bit( LED_PORT, LED_BIT);
// Start the second timer (150 ms) and execute case 3 when done
YASKpost( mbx, 3, 0, 150, YASK_PRI_TSK);
break;
Once the 30 ms time out triggered in case 1 is done, YasK delivers the message to me. The identifier of this message is 2, so case 2 will be selected in the switch/case statement.
In case 2, I turn the LED off and call YASKpost with a identifier set to 3 and a time out set to 150 milliseconds. YasK will wake me up in 150 ms with a message identifier of 3.
case 3: // LED On 2
IOSset_bit( LED_PORT, LED_BIT);
// Start the third timer (30 ms) and execute case 4 when done
YASKpost( mbx, 4, 0, 30, YASK_PRI_TSK);
break;
When YasK delivers message identifer 3, I must light the LED again and sleep during 30 ms before executing case 4.
case 4: // LED Off 2
IOSreset_bit( LED_PORT, LED_BIT);
// Start the fourth timer (700 ms) and execute case 1 when done
YASKpost( mbx, 1, 0, 700, YASK_PRI_TSK);
break;
when I receive message identifier 4, I turn the LED off and sleep during 700 ms. YasK will then wake me up with message identifer 1 and the whole process will start again.
Now we need to see what happens if the task is called with a NULL message:
else // come here if I am called with a NULL message
{
// get a mailbox handle on myself (this task) and give it a friendly name
mbx = YASKregister( heart_beat, // Recipient task
"HeartBeat"); // Friendly mailbox name
The heart_beat routine is called with a NULL message once during start-up. During this first call, the task gets a mailbox from YasK and saves it in the local static mbx variable.This is simply done by the YASKregister call. The first parameter is the recipient task associated to the mailbox, the second parameter is a friendly name. Here the recipient of the messages will be myself (heart_beat).
Once I have got a mailbox, the task needs to start cycling:
YASKpost( mbx, // maiblox hande: me
1, // Identifier
0, // Optionnal identifier
0, // Send message immediately
YASK_PRI_TSK); // Standard priority
} // End of if/else on message
return 0;
} // End of heart_beat()
To start the task, call YASKpost with a message identifier set to 1 and a time out set to 0. YasK will send it as soon as possible.
Jump start example - Use Heart Beat Blinky LED
To use your brand new heart_beat task, create a function called app_main like the one below:
// My main routine must be called "app_main"
void app_main( void)
{
// Initialize my hardware
board_hw_init();
// Start blinking the LED
heart_beat( NULL);
} // End off app_main()
Your routine cannot be called "main" because, main is part of YasK. Your startup routine is called by YasK during the program startup.
After board initialization, just call your heart_beat task with a NULL parameter, and it will start.