/* config.h
 * PSR 6schedlat assignment
 * DO NOT MODIFY
 */

#include <xlnx_zynq7k.h>

/* Register offsets (see TRM B.32) */
#define ZYNQ_TIMER_CLOCK_CTRL       (0x00)
#define ZYNQ_TIMER_COUNTER_CTRL     (0x0c)
#define ZYNQ_TIMER_COUNTER_VAL      (0x18)
#define ZYNQ_TIMER_INTERVAL         (0x24)
#define ZYNQ_TIMER_INTERRUPT        (0x54)
#define ZYNQ_TIMER_INTERRUPT_EN     (0x60)
/* Register bit definitions */
#define INTERRUPT_EN_IV             (0x01)
#define CTRL_EN                     (0<<0)
#define CTRL_DIS                    (1<<0)
#define CTRL_INT                    (1<<1)
#define CLOCK_PRESCALE              (0x01 << 1)
#define CLOCK_PRESCALE_EN           (0x1)
/* Register access */
#define TTC0_TIMER2_CLOCK_CTRL      (*((volatile UINT32 *)(ZYNQ7K_TTC0_TIMER2_BASE + ZYNQ_TIMER_CLOCK_CTRL)))
#define TTC0_TIMER2_COUNTER_CTRL    (*((volatile UINT32 *)(ZYNQ7K_TTC0_TIMER2_BASE + ZYNQ_TIMER_COUNTER_CTRL)))
#define TTC0_TIMER2_COUNTER_VAL     (*((volatile UINT32 *)(ZYNQ7K_TTC0_TIMER2_BASE + ZYNQ_TIMER_COUNTER_VAL)))
#define TTC0_TIMER2_INTERVAL        (*((volatile UINT32 *)(ZYNQ7K_TTC0_TIMER2_BASE + ZYNQ_TIMER_INTERVAL)))
#define TTC0_TIMER2_INTERRUPT       (*((volatile UINT32 *)(ZYNQ7K_TTC0_TIMER2_BASE + ZYNQ_TIMER_INTERRUPT)))
#define TTC0_TIMER2_INTERRUPT_EN    (*((volatile UINT32 *)(ZYNQ7K_TTC0_TIMER2_BASE + ZYNQ_TIMER_INTERRUPT_EN)))

/* sysClkRateSet(CLOCK_RATE) */
#define CLOCK_RATE 1000

/* Semaphore that is passed between `timer_isr` and Service task. */
SEM_ID isr_semaphore;

/*
 * timer_isr()
 *
 *  This function is attached to timer as an interrupt handler.
 *  On every call, this function reads and stores the timer value
 *  and releases `isr_semaphore`.
 */
void timer_isr(void);

/*
 * ServiceTask()
 *  : (int) o -- "optional" argument, you can use it freely if you want to
 *
 *  This function is spawned as a Service task with name `tService`.
 *
 *  Service task is running in a loop, waiting for `isr_semaphore`
 *  to be unlocked. After successfully taking this semaphore, timer
 *  value is read and stored.
 */
void ServiceTask(int o);

/*
 * MonitorTask()
 *  : (int) o -- "optional" argument, you can use it freely if you want to
 *
 *  This function is spawned as a Monitor task with name `tMonitor`.
 *
 *  Monitor task is running in a loop, printing out measurement data
 *  from both `timer_isr` and Service task. After printing, task is
 *  suspended for 1 second.
 *
 *  Data format:
 *  The functions prints out three rows every time:
 *   1) First row is the x-axis, values in microseconds, ordered in a strictly
 *      increasing sequence.
 *   2) Second row is histogram for "interrupt--timer_isr" latency. The sequence
 *      has the same size as first row (number of elements) and the values
 *      correspond to the x-axis (number of occurences of given latency).
 *   3) Third row is histogram for "interrupt--ServiceTask" latency. The rest is
 *      same as the second row.
 *   Printed out values are delimited by comma ',' only. Rows are ended with '\n'.
 */
void MonitorTask(int o);

/*
 * CreateTasks()
 *  : (int) seconds -- how many seconds should the measurement last
 *                     0 = INFINITE
 *
 *  Entry point function.
 *
 *  This function makes a measurement of interrupt latency.
 *  First, it prepares registers of the hardware and links
 *  `timer_isr` function as an interrupt handler.
 *  Then, Service and Monitor tasks are spawned.
 *
 *  Whole application (that is, after running this function),
 *  should print to stdout 'Measurement started' message. Then,
 *  every 1 second measurement data are printed. At the end,
 *  after `seconds` seconds have passed, the 'Measurement finished'
 *  message is printed and application is terminated (all tasks deleted,
 *  and interrupt is disabled + disconnected).
 *
 *  Note:
 *  See Monitor task for more information about the measurement data
 *  format.
 *
 *  Example:
 *      -> CreateTasks(1)
 *      Measurement started
 *      0,1,2,3,4,5,6,7
 *      59,984,34,0,45,3,784,35
 *      0,0,0,0,0,13,1159,772
 *      Measurement finished
 *
 *      -> CreateTasks(2)
 *      Measurement started
 *      0,1,2,3,4,5,6,7
 *      59,984,34,0,45,3,784,35
 *      0,0,0,0,0,13,1159,772
 *      0,1,2,3,4,5,6,7
 *      147,1751,134,5,85,13,997,80
 *      0,0,0,0,0,30,1909,1273
 *      Measurement finished
 */
void CreateTasks(int measurements);