Wednesday, November 9, 2011

Output a VB.NET System.Data.DataTable to HTML

It is not very difficult to write this code snippet, but believe me, you will not find snippets as easy as this one. You don't need to read anything except this paragraph. The DataTable to use is called dt, the HTML code is attached to the page as a Literal Control.

Dim html As New System.Text.StringBuilder
Dim i as Integer
html.AppendLine("<table><tr>")
For Each col As System.Data.DataColumn In dt.Columns
   html.AppendLine("<th>" & col.Caption & "</th>")
Next
html.AppendLine("</tr>")
For Each dr As System.Data.DataRow In dt.Rows
   html.AppendLine("<tr>")
   For i = 0 To dr.ItemArray.Length - 1
      html.AppendLine("<td>" & dr.ItemArray(i).ToString & "</td>")
   Next
   html.AppendLine("</tr>")
Next
html.AppendLine("</table>")
Page.Controls.Add(New System.Web.UI.LiteralControl(html.ToString))

Monday, November 7, 2011

AVR task scheduler

For some projects it is necessary to be able to execute periodic tasks every view seconds or maybe every day at 8.00 a.m. This post will describe a solution for an AVR µC. It consists of several files so the best will be to start with the main function.
#include <avr/sleep.h>
#include <util/atomic.h>
#include <util/delay.h>
#include <stdlib.h>
#include <stdio.h>

#include "interrupthandler.h"
#include "rtc.h"
#include "scheduler.h"
#include "timertasks.h"

#define CPU_PRESCALE(n) (CLKPR = 0x80, CLKPR = (n))
#define CPU_16MHz       0x00
#define CPU_125kHz      0x07

void init();
unsigned char checkForInterrupt();

struct Task *test1Task;
struct Task *test2Task;

void main(void) __attribute__((noreturn));

void main()
{
    char interrupts;
    init();

    while(1)
    {
        while (!(interrupts = checkForInterrupt()))
            //put controller into idle mode until an interrupt occurs
            sleep_mode();
        if (interrupts & TIMER_INTERRUPT)
        {
            executeScheduler();
        }
    }
}

void init()
{
    cli();
    // make sure that voltage is at 5V
    CPU_PRESCALE(CPU_125kHz);  // power supply still ramping up voltage
    _delay_ms(1);              // actual delay 128 ms when F_OSC is 16000000
    // set for 16 MHz clock, and make sure the LED is on
    CPU_PRESCALE(CPU_16MHz);

    // set the prescaler for timer 1 to 1024
    TCCR1B |= (1 << CS12) | (1 << CS10);

    //16MHz (FCPU) / 1024 (CS1 = 5) -> 15625 incr/sec
    //65536 = 49911 + 15625 (number of values in TCNT1) -> 1 overflows/sec
    TCNT1 = 49911;
    /* Enable Timer Overflow Interrupts */
    TIMSK1 |= (1 << TOIE1);

    init_rtc();
    init_scheduler();

    test1Task = makeTask();
    test1Task->function = test1TaskFunction;
    addTimerTask(test1Task, MINUTELY);

    test2Task = makeTask();
    test2Task->function = test2TaskFunction;
    test2Task->delay = 200;
    addTimerTask(test2Task, CUSTOM);

    //enable interrupts
    sei();
    set_sleep_mode(SLEEP_MODE_IDLE);
}

inline unsigned char checkForInterrupt()
{
    unsigned char interrupts;
    ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
    {
        interrupts = interrupt;
        interrupt = 0;
    }
    return interrupts;
} 
The main function consists of the initialisation of the used system components. It also defines the tasks which should be executed. We define one task test1Task which should be executed every minute and one task test2Task which will be executed every 200 seconds. Additionally we enable timer1 to interrupt the main loop every second. To save energy we let the controller go to sleep if nothing is to do. The interrupt is able to awake the controller until it will be send to sleep again.
The interrupt routine is quite easy and short as it should be. Let's have a look at it.
#ifndef __INTERRUPTHANDLER_H__
#define __INTERRUPTHANDLER_H__

#include <avr/interrupt.h>

#include "rtc.h"

#define TIMER_INTERRUPT 1

volatile unsigned char interrupt = 0;

ISR(TIMER1_OVF_vect)
{
    /* Timer 1 overflow */
    interrupt |= TIMER_INTERRUPT;
    TCNT1 = 49911; //see main for explanation
    //add time in which the irq occurs to the current time
    addTimerPeriode();
}

#endif //__INTERRUPTHANDLER_H__
Nothing spectacular happens here. We only tell the real time clock that the interrupt occurred and it should add another period.
Before we come to the really interesting part of this post we should take a short time to introduce the real time clock. It provides us the possibility to get the current time either as Unix timestamp or as a human readable struct with year, month and so on.
It consists of the header:
#ifndef __RTC_H__
#define __RTC_H__

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

#define TIMER_PERIODE 1

struct tm
{
  int tm_sec;         /* Seconds.   [0-60] (1 leap second) */
  int tm_min;         /* Minutes.   [0-59] */
  int tm_hour;         /* Hours.   [0-23] */
  int tm_mday;         /* Day.      [1-31] */
  int tm_mon;         /* Month.   [0-11] */
  int tm_year;         /* Year   - 1900.  */
  int tm_wday;         /* Day of week.   [0-6] Sunday == 0 */
  int tm_yday;         /* Days in year.[0-365]   */
  int tm_isdst;         /* DST.      [-1/0/1]*/
};

#define SECS_PER_MINUTE    (60L)
#define SECS_PER_HOUR   (SECS_PER_MINUTE * 60L)
#define SECS_PER_DAY       (SECS_PER_HOUR * 24L)

#define __isleap(year) ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))
#define DIV(a, b) ((a) / (b) - ((a) % (b) < 0))
#define LEAPS_THRU_END_OF(y) (DIV (y, 4) - DIV (y, 100) + DIV (y, 400))

extern unsigned long int _currentTime;
extern struct tm _currentTimeStruct;

//initialises the real time clock
void init_rtc();
int __offtime(unsigned long int *t, long int offset, struct tm *tp);
unsigned long unixtime(int, int, int, int, int, int);
struct tm *getCurrentTimeStruct();

//add timer periode to time variable. only the timer interrupt should call this!!!
void addTimerPeriode();

inline unsigned long int getCurrentTime()
{
    return _currentTime;
}

#endif //__RTC_H__
which defines the struct, a view constants and functions to calculate the human readable time out of the Unix timestamp.
Here is the implementation of it:
#include "rtc.h"

unsigned long int currentTime = 0;
struct tm currentTimeStruct;

const unsigned short int __mon_yday[2][13] =
  {
    /* Normal years.  */
    { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
    /* Leap years.  */
    { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 } };

void init_rtc()
{
    currentTime = unixtime(2011, 7, 20, 10, 0, 0);
}

void addTimerPeriode()
{
    currentTime += TIMER_PERIODE;
    __offtime(&currentTime, 0L, &currentTimeStruct);
}

struct tm *getCurrentTimeStruct()
{
    return &currentTimeStruct;
}

/* Compute the `struct tm' representation of *T,
 offset OFFSET seconds east of UTC,
 and store year, yday, mon, mday, wday, hour, min, sec into *TP.
 Return nonzero if successful.  */
int __offtime(unsigned long int *t, long int offset, struct tm *tp)
{
    long int days, rem, y;
    const unsigned short int *ip;

    days = *t / SECS_PER_DAY;
    rem = *t % SECS_PER_DAY;
    rem += offset;
    while (rem < 0) {
        rem += SECS_PER_DAY;
        --days;
    }
    while (rem >= SECS_PER_DAY) {
        rem -= SECS_PER_DAY;
        ++days;
    }
    tp->tm_hour = rem / SECS_PER_HOUR;
    rem %= SECS_PER_HOUR;
    tp->tm_min = rem / 60;
    tp->tm_sec = rem % 60;
    /* January 1, 1970 was a Thursday.  */
    tp->tm_wday = (4 + days) % 7;
    if (tp->tm_wday < 0)
        tp->tm_wday += 7;
    y = 1970;

    while (days < 0 || days >= (__isleap (y) ? 366 : 365)) {
        /* Guess a corrected year, assuming 365 days per year.  */
        long int yg = y + days / 365 - (days % 365 < 0);

        /* Adjust DAYS and Y to match the guessed year.  */
        days -= ((yg - y) * 365 + LEAPS_THRU_END_OF (yg - 1)
                - LEAPS_THRU_END_OF (y - 1));
        y = yg;
    }
    tp->tm_year = y - 1900;
    if (tp->tm_year != y - 1900) {
        /* The year cannot be represented due to overflow.  */
        // __set_errno (EOVERFLOW);
        return 0;
    }
    tp->tm_yday = days;
    ip = __mon_yday[__isleap(y)];
    for (y = 11; days < (long int) ip[y]; --y)
        continue;
    days -= ip[y];
    tp->tm_mon = y;
    tp->tm_mday = days + 1;
    return 1;
}

/**
 * Converts the parameters to unix timestamp
 */
unsigned long unixtime(int year, int month, int day, int hour, int minute, int second)
{
    const short days_to_monthstart[12] = /* ohne Schalttag */
    { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };

    unsigned long unix_time;
    unsigned long years = year - 1970;
    int leapyear = ((year - 1) - 1968) / 4 - ((year - 1) - 1900) / 100
            + ((year - 1) - 1600) / 400;

    unix_time = second + 60L * minute + SECS_PER_HOUR * hour
            + (days_to_monthstart[month] + day - 1L) * SECS_PER_DAY
            + (years * 365L + leapyear) * SECS_PER_DAY;

    if ((month > 2) && (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0)))
        unix_time += SECS_PER_DAY; /* +Schalttag wenn jahr Schaltjahr ist */

    return unix_time;
}
Now it is time to get to the real interesting things of this post. The actual scheduler.
#ifndef __SCHEDULER_H__
#define __SCHEDULER_H__

#include <stdlib.h>

#include "rtc.h"
#include "utils.h"

#define ONESHOT        0
#define DAYLY        1
#define HOURLY        2
#define MINUTELY    3
#define CUSTOM        4

struct Task
{
    long int expires;        //how long to execute the task
    void (*function)();        //the function which is called when the task expires
    long int delay;         //delay in seconds. 0 means one shot
    struct tm *executeOn;    //the time when the task should be executed
    short executed;            //a flag which indicates the task as executed
};

// list of tasks
struct TaskNode
{
    struct Task *task;
    struct TaskNode *next;
    struct TaskNode *prev;
};

void init_scheduler();

/**
 * Add a task which will be called according to the given timestamp
 */
void addSchedulerTask(struct Task *, struct tm *, short);

/**
 * A periodic task
 */
void addTimerTask(struct Task *, short);

/**
 * Add a task to the execution list. This function should only be called from addTimerTask or
 * addSchedulerTask.
 * @see addTimerTask
 * @see addSchedulerTask
 */
void addTask(struct Task *);

/**
 * Remove the given task from the execution list.
 */
void removeTask(struct Task *);

/**
 * Only tasks which are not oneshots can be restarted.
 */
void restartTask(struct Task *);

/**
 * This function must be called periodically (here every second). If a task expires it will be executed.
 */
void executeScheduler();

#endif //__SCHEDULER_H__
The header of the scheduler is straight forward. It defines some functions to initialise the scheduler, add and remove tasks and restart them. Additionally there is a function called executeScheduler. This is the function where every thing will happen. A struct for a task is defined by a counter called expires. It will hold the time until the function given to the task is executed the next time. The variable delay holds the time to which expires will be reset after the task is executed. If delay is zero the task will be removed after execution. For scheduler tasks the task also holds a timestamp. The last flag marks the task as executed. This is necessary for scheduler tasks. The next thing which is defined here is a simple list. For convenience it holds the pointer to the next task as well as the pointer to the previous one. If a task has to be removed this leads to much less effort to do this instead of walking through the whole list again. As one can see this give us a performance benefit as well. And now, here is the scheduler implementation itself.
#include "scheduler.h"

struct TaskNode *list;

void init_scheduler()
{
    list = 0;
}

void addTimerTask(struct Task *task, short repeat)
{
    switch (repeat)
    {
        case CUSTOM:
            break;
        case ONESHOT:
            task->delay = 0;
            break;
        case DAYLY:
            task->delay = SECS_PER_DAY;
            break;
        case HOURLY:
            task->delay = SECS_PER_HOUR;
            break;
        case MINUTELY:
            task->delay = SECS_PER_MINUTE;
            break;
    }
    task->expires = task->delay;
    task->executeOn = 0; //indicate the task as timer task
    addTask(task);
}

void addSchedulerTask(struct Task *task, struct tm *time, short oneshot)
{
    if (oneshot)
        task->delay = 0;
    else
        task->delay = 1;
    task->executeOn = time;
    task->executed = 0;
    addTask(task);
}

void addTask(struct Task *task)
{
    struct TaskNode *current = list;
    struct TaskNode *previous = 0;
    //empty list
    if (current == 0)
    {
        list = makeTaskNode();
        current = list;
    }
    else
    {
        while (current != 0)
        {
            previous = current;
            current = current->next;
        }
        current = makeTaskNode();
        previous->next = current;
    }
    current->prev = previous;
    current->next = 0;
    current->task = task;
}

void removeTask(struct Task *task)
{
    struct TaskNode *current = list;
    while (current != 0)
    {
        if (current->task == task)
        {
            struct TaskNode *prev = current->prev;
            struct TaskNode *next = current->next;
            if (prev != 0)
                prev->next = next;
            if (next != 0)
                next->prev = prev;
            freeTaskNode(current);
        }
    }
}

void executeScheduler()
{
    struct TaskNode *current = list;
    while (current != 0)
    {
        struct Task *task = current->task;
        if (task == 0)
        {
            current = current->next;
            continue;
        }
        if (task->executeOn == 0) //timer task
        {
            task->expires--;
            if (task->expires <= 0)
            {
                task->function();
                task->expires = task->delay;
            }
        }
        else //scheduler task
        {
            struct tm *currentTime = getCurrentTimeStruct();

            short exec = 1;
            exec &=    ((task->executeOn->tm_year == -1) | (task->executeOn->tm_year == currentTime->tm_year));
            exec &=    ((task->executeOn->tm_mon == -1) | (task->executeOn->tm_mon == currentTime->tm_mon));
            exec &=    ((task->executeOn->tm_mday == -1) | (task->executeOn->tm_mday == currentTime->tm_mday));
            exec &=    ((task->executeOn->tm_hour == -1) | (task->executeOn->tm_hour == currentTime->tm_hour));
            exec &=    ((task->executeOn->tm_min == -1) | (task->executeOn->tm_min == currentTime->tm_min));
            exec &=    ((task->executeOn->tm_sec == -1) | (task->executeOn->tm_sec == currentTime->tm_sec));
            if (!exec)
                task->executed = 0;
            if (exec && task->executed == 0)
            {
                task->function();
                task->executed = 1;
            }
        }
        if (task->delay == 0)
        {
            current = current->next;
            removeTask(task);
            continue;
        }
        current = current->next;
    }
}

void restartTask(struct Task *task)
{
    if (task->delay > 0)
        task->expires = task->delay;
}
The add and remove functions are very simple. The just add a little bit of convenience by setting everything necessary and put the task into the list or remove it from there. The execute function walks through the list of tasks. If there is a task which expires variable is less or equal to zero it executes its function. After that the expires variable is set back to the delay value. If this delay is 0 the task is removed from the list. If the executeOn variable is set it will be checked if the current time corresponds to the values set in the timestamp. A -1 means do not care. If all interesting values match the current time the task will be executed. The executed flag is needed here because setting the minutes to e. g. 10 would execute the task every second as long as the current times minutes are set to 10 otherwise.

I will appreciate to read your comments to this simple implementation of a task scheduler for microcontrollers.