Revision 196
changing stuff to correct labs
lab2/utils.h | ||
---|---|---|
1 |
#ifndef UTILS_H_INCLUDED |
|
2 |
#define UTILS_H_INCLUDED |
|
3 |
|
|
4 |
int(util_get_LSB)(uint16_t val, uint8_t *lsb); |
|
5 |
|
|
6 |
int(util_get_MSB)(uint16_t val, uint8_t *msb); |
|
7 |
|
|
8 |
#ifdef LAB3 |
|
9 |
uint32_t sys_inb_counter; |
|
10 |
#endif |
|
11 |
|
|
12 |
int (util_sys_inb)(int port, uint8_t *value); |
|
13 |
|
|
14 |
#endif //UTILS_H_INCLUDED |
|
15 | 0 |
lab2/i8254.h | ||
---|---|---|
1 |
#ifndef _LCOM_I8254_H_ |
|
2 |
#define _LCOM_I8254_H_ |
|
3 |
|
|
4 |
#include <lcom/lcf.h> |
|
5 |
|
|
6 |
/** @defgroup i8254 i8254 |
|
7 |
* @{ |
|
8 |
* |
|
9 |
* Constants for programming the i8254 Timer. Needs to be completed. |
|
10 |
*/ |
|
11 |
|
|
12 |
#define TIMER_FREQ 1193182 /**< @brief clock frequency for timer in PC and AT */ |
|
13 |
#define TIMER_MIN_FREQ (TIMER_FREQ/UINT16_MAX) + ((TIMER_FREQ % UINT16_MAX) ? 1 : 0) /**< @brief mininum frequency for timer */ |
|
14 |
#define TIMER0_IRQ 0 /**< @brief Timer 0 IRQ line */ |
|
15 |
|
|
16 |
/* I/O port addresses */ |
|
17 |
|
|
18 |
#define TIMER_0 0x40 /**< @brief Timer 0 count register */ |
|
19 |
#define TIMER_1 0x41 /**< @brief Timer 1 count register */ |
|
20 |
#define TIMER_2 0x42 /**< @brief Timer 2 count register */ |
|
21 |
#define TIMER_CTRL 0x43 /**< @brief Control register */ |
|
22 |
|
|
23 |
#define SPEAKER_CTRL 0x61 /**< @brief Register for speaker control */ |
|
24 |
|
|
25 |
/* Timer control */ |
|
26 |
|
|
27 |
/* Timer selection: bits 7 and 6 */ |
|
28 |
|
|
29 |
#define TIMER_SEL0 0x00 /**< @brief Control Word for Timer 0 */ |
|
30 |
#define TIMER_SEL1 BIT(6) /**< @brief Control Word for Timer 1 */ |
|
31 |
#define TIMER_SEL2 BIT(7) /**< @brief Control Word for Timer 2 */ |
|
32 |
#define TIMER_RB_CMD (BIT(7) | BIT(6)) /**< @brief Read Back Command */ |
|
33 |
|
|
34 |
/* Register selection: bits 5 and 4 */ |
|
35 |
|
|
36 |
#define TIMER_LSB BIT(4) /**< @brief Initialize Counter LSB only */ |
|
37 |
#define TIMER_MSB BIT(5) /**< @brief Initialize Counter MSB only */ |
|
38 |
#define TIMER_LSB_MSB (TIMER_LSB | TIMER_MSB) /**< @brief Initialize LSB first and MSB afterwards */ |
|
39 |
#define TIMER_INMODE_MASK 0x30 //0011 0000 |
|
40 |
#define TIMER_INMODE_POS 4 |
|
41 |
|
|
42 |
/* Operating mode: bits 3, 2 and 1 */ |
|
43 |
|
|
44 |
#define TIMER_SQR_WAVE (BIT(2) | BIT(1)) /**< @brief Mode 3: square wave generator */ |
|
45 |
#define TIMER_RATE_GEN BIT(2) /**< @brief Mode 2: rate generator */ |
|
46 |
#define TIMER_MODE_MASK 0x0E /**< @brief Mask for mode */ |
|
47 |
#define TIMER_MODE_POS 1 /**< @brief Position of smallest bit from mode */ |
|
48 |
#define TIMER_MODE_2ALT 0x6 /**< @brief Alternative notation for mode 2 */ |
|
49 |
#define TIMER_MODE_3ALT 0x7 /**< @brief Alternative notation for mode 3 */ |
|
50 |
#define TIMER_MODE_RED2 0x03 /**< @brief Reduce 3-bit mode to 2-bit mode */ |
|
51 |
|
|
52 |
/* Counting mode: bit 0 */ |
|
53 |
|
|
54 |
#define TIMER_BCD 0x01 /**< @brief Count in BCD */ |
|
55 |
#define TIMER_BIN 0x00 /**< @brief Count in binary */ |
|
56 |
|
|
57 |
/* READ-BACK COMMAND FORMAT */ |
|
58 |
|
|
59 |
#define TIMER_RB_COUNT_ BIT(5) |
|
60 |
#define TIMER_RB_STATUS_ BIT(4) |
|
61 |
#define TIMER_RB_SEL(n) BIT((n) + 1) |
|
62 |
|
|
63 |
/**@}*/ |
|
64 |
|
|
65 |
#endif /* _LCOM_I8254_H */ |
|
66 | 0 |
lab2/timer.c | ||
---|---|---|
1 |
#include <lcom/lcf.h> |
|
2 |
#include <lcom/timer.h> |
|
3 |
|
|
4 |
#include <stdint.h> |
|
5 |
|
|
6 |
#include "i8254.h" |
|
7 |
|
|
8 |
int (timer_set_frequency)(uint8_t timer, uint32_t freq) { |
|
9 |
|
|
10 |
// Frequencies out this range are not supported (by limitation of hardware) |
|
11 |
if (freq > TIMER_FREQ || freq < TIMER_MIN_FREQ) { |
|
12 |
printf("%s: Frequency out of range, must be between %d and %d.\n", __func__, TIMER_MIN_FREQ, TIMER_FREQ); |
|
13 |
return 1; |
|
14 |
} |
|
15 |
|
|
16 |
uint8_t status = 0; |
|
17 |
if (timer_get_conf(timer, &status)) return 1; |
|
18 |
//Make command |
|
19 |
uint8_t write_cmd = 0; |
|
20 |
//Select timer |
|
21 |
switch(timer) { |
|
22 |
case 0: write_cmd |= TIMER_SEL0; break; |
|
23 |
case 1: write_cmd |= TIMER_SEL1; break; |
|
24 |
case 2: write_cmd |= TIMER_SEL2; break; |
|
25 |
default: return 1; |
|
26 |
} |
|
27 |
//Change both LSB and MSB |
|
28 |
write_cmd |= TIMER_LSB_MSB; |
|
29 |
//Keep 4 least significant bits |
|
30 |
write_cmd |= (status & (TIMER_MODE_MASK | TIMER_BCD)); |
|
31 |
//Write cmd |
|
32 |
if (sys_outb(TIMER_CTRL, write_cmd)) return 1; |
|
33 |
|
|
34 |
// counter_init = clock/freq |
|
35 |
uint16_t counter_init = (uint16_t)(TIMER_FREQ / freq); |
|
36 |
|
|
37 |
int timer_port = 0; |
|
38 |
switch(timer) { |
|
39 |
case 0: timer_port = TIMER_0; break; |
|
40 |
case 1: timer_port = TIMER_1; break; |
|
41 |
case 2: timer_port = TIMER_2; break; |
|
42 |
default: return 1; |
|
43 |
} |
|
44 |
uint8_t lsb = 0, msb = 0; |
|
45 |
/* Split the 16 bits word in two bytes */ |
|
46 |
if (util_get_LSB(counter_init, &lsb)) return 1; |
|
47 |
if (util_get_MSB(counter_init, &msb)) return 1; |
|
48 |
|
|
49 |
/* Write the 8 LSB of the counter */ |
|
50 |
if (sys_outb(timer_port, lsb)) return 1; |
|
51 |
/* Write the 8 MSB of the counter */ |
|
52 |
if (sys_outb(timer_port, msb)) return 1; |
|
53 |
|
|
54 |
return 0; |
|
55 |
} |
|
56 |
|
|
57 |
int hook_id; |
|
58 |
|
|
59 |
int (timer_subscribe_int)(uint8_t *bit_no) { |
|
60 |
if(bit_no == NULL) return 1; |
|
61 |
hook_id = 2; |
|
62 |
*bit_no = hook_id; |
|
63 |
/* Subscribe Timer 0 Interrupts */ |
|
64 |
return sys_irqsetpolicy(TIMER0_IRQ, IRQ_REENABLE, &hook_id); |
|
65 |
} |
|
66 |
|
|
67 |
int (timer_unsubscribe_int)() { |
|
68 |
/* Unsubscribe Timer 0 Interrupts */ |
|
69 |
if(sys_irqrmpolicy(&hook_id)) return 1; |
|
70 |
return 0; |
|
71 |
} |
|
72 |
|
|
73 |
int no_interrupts = 0; |
|
74 |
void (timer_int_handler)() { |
|
75 |
no_interrupts++; |
|
76 |
} |
|
77 |
|
|
78 |
int (timer_get_conf)(uint8_t timer, uint8_t *st) { |
|
79 |
if(st == NULL) return 1; |
|
80 |
// Write read-back command to TIMER_CTRL |
|
81 |
u32_t cmd = TIMER_RB_CMD | TIMER_RB_COUNT_ | TIMER_RB_SEL(timer); |
|
82 |
if(sys_outb(TIMER_CTRL, cmd)) return 1; |
|
83 |
int read_port; |
|
84 |
switch(timer) { |
|
85 |
case 0: read_port = TIMER_0; break; |
|
86 |
case 1: read_port = TIMER_1; break; |
|
87 |
case 2: read_port = TIMER_2; break; |
|
88 |
default: return 1; |
|
89 |
} |
|
90 |
if(util_sys_inb(read_port, st)) return 1; |
|
91 |
return 0; |
|
92 |
} |
|
93 |
|
|
94 |
int (timer_display_conf)(uint8_t timer, uint8_t st, enum timer_status_field field) { |
|
95 |
union timer_status_field_val conf; |
|
96 |
uint8_t in_mode; |
|
97 |
switch(field){ |
|
98 |
case tsf_all: |
|
99 |
conf.byte = st; /* Full Status Byte */ |
|
100 |
break; |
|
101 |
case tsf_initial: |
|
102 |
/* Counter Initial Value Loading Mode */ |
|
103 |
in_mode = (st & TIMER_INMODE_MASK) >> TIMER_INMODE_POS; |
|
104 |
switch(in_mode){ |
|
105 |
case 0: conf.in_mode = INVAL_val ; break; //000 |
|
106 |
case 1: conf.in_mode = LSB_only ; break; //001 |
|
107 |
case 2: conf.in_mode = MSB_only ; break; //010 |
|
108 |
case 3: conf.in_mode = MSB_after_LSB; break; //011 |
|
109 |
default: return 1; |
|
110 |
} |
|
111 |
break; |
|
112 |
case tsf_mode: |
|
113 |
/* Counting Mode */ |
|
114 |
conf.count_mode = (st & TIMER_MODE_MASK)>>TIMER_MODE_POS; |
|
115 |
if(conf.count_mode == TIMER_MODE_2ALT || conf.count_mode == TIMER_MODE_3ALT) |
|
116 |
conf.count_mode &= TIMER_MODE_RED2; |
|
117 |
break; |
|
118 |
case tsf_base: |
|
119 |
/* Representation of Counter Initial Value */ |
|
120 |
conf.bcd = st & TIMER_BCD; |
|
121 |
break; |
|
122 |
default: return 1; |
|
123 |
} |
|
124 |
if(timer_print_config(timer, field, conf)) return 1; |
|
125 |
return 0; |
|
126 |
} |
|
127 | 0 |
lab2/utils.c | ||
---|---|---|
1 |
#include <lcom/lcf.h> |
|
2 |
|
|
3 |
#include <stdint.h> |
|
4 |
|
|
5 |
int(util_get_LSB)(uint16_t val, uint8_t *lsb) { |
|
6 |
if (lsb == NULL) return 1; |
|
7 |
*lsb = val; |
|
8 |
return 0; |
|
9 |
} |
|
10 |
|
|
11 |
int(util_get_MSB)(uint16_t val, uint8_t *msb) { |
|
12 |
if (msb == NULL) return 1; |
|
13 |
*msb = (val >> 8); |
|
14 |
return 0; |
|
15 |
} |
|
16 |
|
|
17 |
#ifdef LAB3 |
|
18 |
uint32_t sys_inb_counter = 0; |
|
19 |
#endif |
|
20 |
|
|
21 |
int (util_sys_inb)(int port, uint8_t *value) { |
|
22 |
if(value == NULL) return 1; |
|
23 |
uint32_t n = 0; |
|
24 |
if(sys_inb(port, &n)) return 1; |
|
25 |
*value = n; |
|
26 |
#ifdef LAB3 |
|
27 |
++sys_inb_counter; |
|
28 |
#endif |
|
29 |
return 0; |
|
30 |
} |
|
31 | 0 |
lab2/lab2.c | ||
---|---|---|
1 |
#include <lcom/lcf.h> |
|
2 |
#include <lcom/lab2.h> |
|
3 |
|
|
4 |
#include <stdbool.h> |
|
5 |
#include <stdint.h> |
|
6 |
|
|
7 |
int main(int argc, char *argv[]) { |
|
8 |
// sets the language of LCF messages (can be either EN-US or PT-PT) |
|
9 |
lcf_set_language("EN-US"); |
|
10 |
|
|
11 |
// enables to log function invocations that are being "wrapped" by LCF |
|
12 |
// [comment this out if you don't want/need it] |
|
13 |
lcf_trace_calls("/home/lcom/labs/lab2/trace.txt"); |
|
14 |
|
|
15 |
// enables to save the output of printf function calls on a file |
|
16 |
// [comment this out if you don't want/need it] |
|
17 |
lcf_log_output("/home/lcom/labs/lab2/output.txt"); |
|
18 |
|
|
19 |
// handles control over to LCF |
|
20 |
// [LCF handles command line arguments and invokes the right function] |
|
21 |
if (lcf_start(argc, argv)) |
|
22 |
return 1; |
|
23 |
|
|
24 |
// LCF clean up tasks |
|
25 |
// [must be the last statement before return] |
|
26 |
lcf_cleanup(); |
|
27 |
|
|
28 |
return 0; |
|
29 |
} |
|
30 |
|
|
31 |
int(timer_test_read_config)(uint8_t timer, enum timer_status_field field){ |
|
32 |
uint8_t state = 0; |
|
33 |
if(timer_get_conf(timer, &state)) return 1; |
|
34 |
if(timer_display_conf(timer, state, field)) return 1; |
|
35 |
return 0; |
|
36 |
} |
|
37 |
|
|
38 |
int(timer_test_time_base)(uint8_t timer, uint32_t freq) { |
|
39 |
if (timer_set_frequency(timer, freq)) return 1; |
|
40 |
return 0; |
|
41 |
} |
|
42 |
|
|
43 |
extern int no_interrupts; |
|
44 |
|
|
45 |
int(timer_test_int)(uint8_t time) { |
|
46 |
const int frequency = 60; // Frequency asummed at 60Hz |
|
47 |
int ipc_status, r; |
|
48 |
message msg; |
|
49 |
uint8_t timer_id = 0; |
|
50 |
no_interrupts = 0; |
|
51 |
if (timer_subscribe_int(&timer_id)) return 1; |
|
52 |
int irq_set = BIT(timer_id); |
|
53 |
while (time) { |
|
54 |
/* Get a request message. */ |
|
55 |
if ((r = driver_receive(ANY, &msg, &ipc_status)) != 0) { |
|
56 |
printf("driver_receive failed with %d", r); |
|
57 |
continue; |
|
58 |
} |
|
59 |
if (is_ipc_notify(ipc_status)) { /* received notification */ |
|
60 |
switch (_ENDPOINT_P(msg.m_source)) { |
|
61 |
case HARDWARE: /* hardware interrupt notification */ |
|
62 |
if (msg.m_notify.interrupts & irq_set) { /* subscribed interrupt */ |
|
63 |
timer_int_handler(); |
|
64 |
if (!(no_interrupts % frequency)) { /* second elapsed */ |
|
65 |
timer_print_elapsed_time(); |
|
66 |
time--; |
|
67 |
} |
|
68 |
} |
|
69 |
break; |
|
70 |
default: |
|
71 |
break; /* no other notifications expected: do nothing */ |
|
72 |
} |
|
73 |
} else { /* received standart message, not a notification */ |
|
74 |
/* no standart message expected: do nothing */ |
|
75 |
} |
|
76 |
} |
|
77 |
if (timer_unsubscribe_int()) return 1; |
|
78 |
return 0; |
|
79 |
} |
|
80 | 0 |
lab2/include/errors.h | ||
---|---|---|
1 |
#ifndef ERRORS_H_INCLUDED |
|
2 |
#define ERRORS_H_INCLUDED |
|
3 |
|
|
4 |
/** @brief Error Codes */ |
|
5 |
enum errors { |
|
6 |
SUCCESS = 0, /** @brief Sucessful */ |
|
7 |
NULL_PTR, /** @brief Null Pointer Error */ |
|
8 |
LCF_ERROR, /** @brief Error originated on LCF */ |
|
9 |
SBCR_ERROR, /** @brief Error on Subscribing Interrupt */ |
|
10 |
UNSBCR_ERROR, /** @brief Error on Unsubscring Interrupt*/ |
|
11 |
READ_ERROR, /** @brief Error on Reading from Port */ |
|
12 |
WRITE_ERROR, /** @brief Error on Writing to Port */ |
|
13 |
TIMEOUT_ERROR, /** @brief Timeout error */ |
|
14 |
INVALID_COMMAND, /** @brief Invalid Command issued */ |
|
15 |
INVALID_STATE, /** @brief State machine reached an invalid state */ |
|
16 |
BIOS_CALL_ERROR, /** @brief Error upon BIOS call */ |
|
17 |
OUT_OF_RANGE, /** @brief Accessing area out of range of memory */ |
|
18 |
ALLOC_ERROR, /** @brief Memory allocation error */ |
|
19 |
LOGIC_ERROR, /** @brief Logic error */ |
|
20 |
OTHER_ERROR /** @brief Unspecified error */ |
|
21 |
}; |
|
22 |
|
|
23 |
#endif //ERRORS_H_INCLUDED |
|
0 | 24 |
lab2/include/i8254.h | ||
---|---|---|
1 |
#ifndef _LCOM_I8254_H_ |
|
2 |
#define _LCOM_I8254_H_ |
|
3 |
|
|
4 |
/** @defgroup i8254 i8254 |
|
5 |
* |
|
6 |
* Constants for programming the i8254 Timer. Needs to be completed. |
|
7 |
*/ |
|
8 |
|
|
9 |
#define TIMER_FREQ 1193182 /**< @brief clock frequency for timer in PC and AT */ |
|
10 |
#define TIMER_MIN_FREQ (TIMER_FREQ/UINT16_MAX) + ((TIMER_FREQ % UINT16_MAX) ? 1 : 0) /**< @brief mininum frequency for timer */ |
|
11 |
#define TIMER0_IRQ 0 /**< @brief Timer 0 IRQ line */ |
|
12 |
|
|
13 |
/* I/O port addresses */ |
|
14 |
|
|
15 |
#define TIMER_0 0x40 /**< @brief Timer 0 count register */ |
|
16 |
#define TIMER_1 0x41 /**< @brief Timer 1 count register */ |
|
17 |
#define TIMER_2 0x42 /**< @brief Timer 2 count register */ |
|
18 |
#define TIMER_CTRL 0x43 /**< @brief Control register */ |
|
19 |
|
|
20 |
#define SPEAKER_CTRL 0x61 /**< @brief Register for speaker control */ |
|
21 |
|
|
22 |
/* Timer control */ |
|
23 |
|
|
24 |
/* Timer selection: bits 7 and 6 */ |
|
25 |
|
|
26 |
#define TIMER_SEL0 0x00 /**< @brief Control Word for Timer 0 */ |
|
27 |
#define TIMER_SEL1 BIT(6) /**< @brief Control Word for Timer 1 */ |
|
28 |
#define TIMER_SEL2 BIT(7) /**< @brief Control Word for Timer 2 */ |
|
29 |
#define TIMER_RB_CMD (BIT(7) | BIT(6)) /**< @brief Read Back Command */ |
|
30 |
|
|
31 |
/* Register selection: bits 5 and 4 */ |
|
32 |
|
|
33 |
#define TIMER_LSB BIT(4) /**< @brief Initialize Counter LSB only */ |
|
34 |
#define TIMER_MSB BIT(5) /**< @brief Initialize Counter MSB only */ |
|
35 |
#define TIMER_LSB_MSB (TIMER_LSB | TIMER_MSB) /**< @brief Initialize LSB first and MSB afterwards */ |
|
36 |
#define TIMER_INMODE_MASK 0x30 /**< @brief Mask for Timer Counter Mode */ |
|
37 |
#define TIMER_INMODE_POS 4 /**< @brief Bit position of Timer Counter Mode */ |
|
38 |
|
|
39 |
/* Operating mode: bits 3, 2 and 1 */ |
|
40 |
|
|
41 |
#define TIMER_SQR_WAVE (BIT(2) | BIT(1)) /**< @brief Mode 3: square wave generator */ |
|
42 |
#define TIMER_RATE_GEN BIT(2) /**< @brief Mode 2: rate generator */ |
|
43 |
#define TIMER_MODE_MASK 0x0E /**< @brief Mask for mode */ |
|
44 |
#define TIMER_MODE_POS 1 /**< @brief Position of smallest bit from mode */ |
|
45 |
#define TIMER_MODE_2ALT 0x6 /**< @brief Alternative notation for mode 2 */ |
|
46 |
#define TIMER_MODE_3ALT 0x7 /**< @brief Alternative notation for mode 3 */ |
|
47 |
#define TIMER_MODE_RED2 0x03 /**< @brief Reduce 3-bit mode to 2-bit mode */ |
|
48 |
|
|
49 |
/* Counting mode: bit 0 */ |
|
50 |
|
|
51 |
#define TIMER_BCD 0x01 /**< @brief Count in BCD */ |
|
52 |
#define TIMER_BIN 0x00 /**< @brief Count in binary */ |
|
53 |
|
|
54 |
/* READ-BACK COMMAND FORMAT */ |
|
55 |
|
|
56 |
#define TIMER_RB_COUNT_ BIT(5) /**< @brief Read counter value on read-back (0 to activate) */ |
|
57 |
#define TIMER_RB_STATUS_ BIT(4) /**< @brief Read status value on read-back (0 to activate) */ |
|
58 |
#define TIMER_RB_SEL(n) BIT((n) + 1) /**< @brief Select timer to read information from */ |
|
59 |
|
|
60 |
/**@}*/ |
|
61 |
|
|
62 |
#endif /* _LCOM_I8254_H */ |
|
0 | 63 |
lab2/include/timer.h | ||
---|---|---|
1 |
/** |
|
2 |
* This file concerns everything related to the timer |
|
3 |
*/ |
|
4 |
|
|
5 |
#ifndef TIMER_H_INCLUDED |
|
6 |
#define TIMER_H_INCLUDED |
|
7 |
|
|
8 |
//7.1 timer_test_read_config() |
|
9 |
int (timer_get_conf)(uint8_t timer, uint8_t *st); |
|
10 |
int (timer_display_conf)(uint8_t timer, uint8_t st, enum timer_status_field field); |
|
11 |
//7.2 timer_test_time_base() |
|
12 |
int (timer_set_frequency)(uint8_t timer, uint32_t freq); |
|
13 |
//7.3 timer_test_int() |
|
14 |
void (timer_int_handler)(void); |
|
15 |
int (subscribe_timer_interrupt)(uint8_t interrupt_bit, int *interrupt_id); |
|
16 |
uint32_t no_interrupts; |
|
17 |
|
|
18 |
#endif //TIMER_H_INCLUDED |
|
0 | 19 |
lab2/include/utils.h | ||
---|---|---|
1 |
#ifndef UTILS_H_INCLUDED |
|
2 |
#define UTILS_H_INCLUDED |
|
3 |
|
|
4 |
/** |
|
5 |
* @brief Gets the least significant byte of a 16-bit variable |
|
6 |
* @param val 16-bit variable |
|
7 |
* @param lsb Pointer to a 8-bit variable to store the value of the LSB |
|
8 |
* @return ERROR_CODE code representing the result of the operation, SUCCESS code is returned if everything is OK |
|
9 |
*/ |
|
10 |
int(util_get_LSB)(uint16_t val, uint8_t *lsb); |
|
11 |
|
|
12 |
/** |
|
13 |
* @brief Gets the most significant byte of a 16-bit variable |
|
14 |
* @param val 16-bit variable |
|
15 |
* @param lsb Pointer to a 8-bit variable to store the value of the MSB |
|
16 |
* @return ERROR_CODE code representing the result of the operation, SUCCESS code is returned if everything is OK |
|
17 |
*/ |
|
18 |
int(util_get_MSB)(uint16_t val, uint8_t *msb); |
|
19 |
|
|
20 |
/** |
|
21 |
* @brief sys_inb wrapper |
|
22 |
* @param port Port to read from |
|
23 |
* @param value Pointer to byte to store value read |
|
24 |
* @return ERROR_CODE code representing the result of the operation, SUCCESS code is returned if everything is OK |
|
25 |
*/ |
|
26 |
int (util_sys_inb)(int port, uint8_t *value); |
|
27 |
|
|
28 |
/** |
|
29 |
* @brief Unsubcribes Interrupts |
|
30 |
* @param interrupt_id Interrupt ID, value via arguments on subscription of the interrupt_id |
|
31 |
* @see subscribe_kbc_interrupt, subscribe_timer_interrupt |
|
32 |
* @return ERROR_CODE code representing the result of the operation, SUCCESS code is returned if everything is OK |
|
33 |
*/ |
|
34 |
int (unsubscribe_interrupt)(int *interrupt_id); |
|
35 |
|
|
36 |
/** |
|
37 |
* @brief Gets the minimum value out of two values. |
|
38 |
* @param a First value |
|
39 |
* @param b Second value |
|
40 |
* @return The minimum of the two values |
|
41 |
*/ |
|
42 |
int32_t min(int32_t a, int32_t b); |
|
43 |
|
|
44 |
/** |
|
45 |
* @brief Gets the maximum value out of two values. |
|
46 |
* @param a First value |
|
47 |
* @param b Second value |
|
48 |
* @return The maximum of the two values |
|
49 |
*/ |
|
50 |
int32_t max(int32_t a, int32_t b); |
|
51 |
|
|
52 |
|
|
53 |
#endif //UTILS_H_INCLUDED |
|
0 | 54 |
lab2/src/lab2.c | ||
---|---|---|
1 |
#include <lcom/lcf.h> |
|
2 |
#include <lcom/lab2.h> |
|
3 |
|
|
4 |
#include <stdbool.h> |
|
5 |
#include <stdint.h> |
|
6 |
|
|
7 |
#include "timer.h" |
|
8 |
|
|
9 |
int main(int argc, char *argv[]) { |
|
10 |
// sets the language of LCF messages (can be either EN-US or PT-PT) |
|
11 |
lcf_set_language("EN-US"); |
|
12 |
|
|
13 |
// enables to log function invocations that are being "wrapped" by LCF |
|
14 |
// [comment this out if you don't want/need it] |
|
15 |
lcf_trace_calls("/home/lcom/labs/lab2/trace.txt"); |
|
16 |
|
|
17 |
// enables to save the output of printf function calls on a file |
|
18 |
// [comment this out if you don't want/need it] |
|
19 |
lcf_log_output("/home/lcom/labs/lab2/output.txt"); |
|
20 |
|
|
21 |
// handles control over to LCF |
|
22 |
// [LCF handles command line arguments and invokes the right function] |
|
23 |
if (lcf_start(argc, argv)) |
|
24 |
return 1; |
|
25 |
|
|
26 |
// LCF clean up tasks |
|
27 |
// [must be the last statement before return] |
|
28 |
lcf_cleanup(); |
|
29 |
|
|
30 |
return 0; |
|
31 |
} |
|
32 |
|
|
33 |
int(timer_test_read_config)(uint8_t timer, enum timer_status_field field){ |
|
34 |
uint8_t state = 0; |
|
35 |
if(timer_get_conf(timer, &state)) return 1; |
|
36 |
if(timer_display_conf(timer, state, field)) return 1; |
|
37 |
return 0; |
|
38 |
} |
|
39 |
|
|
40 |
int(timer_test_time_base)(uint8_t timer, uint32_t freq) { |
|
41 |
if (timer_set_frequency(timer, freq)) return 1; |
|
42 |
return 0; |
|
43 |
} |
|
44 |
|
|
45 |
int(timer_test_int)(uint8_t time) { |
|
46 |
const int frequency = 60; // Frequency asummed at 60Hz |
|
47 |
int ipc_status, r; |
|
48 |
message msg; |
|
49 |
uint8_t timer_id = 0; |
|
50 |
no_interrupts = 0; |
|
51 |
if (timer_subscribe_int(&timer_id)) return 1; |
|
52 |
int irq_set = BIT(timer_id); |
|
53 |
while (time) { |
|
54 |
/* Get a request message. */ |
|
55 |
if ((r = driver_receive(ANY, &msg, &ipc_status)) != 0) { |
|
56 |
printf("driver_receive failed with %d", r); |
|
57 |
continue; |
|
58 |
} |
|
59 |
if (is_ipc_notify(ipc_status)) { /* received notification */ |
|
60 |
switch (_ENDPOINT_P(msg.m_source)) { |
|
61 |
case HARDWARE: /* hardware interrupt notification */ |
|
62 |
if (msg.m_notify.interrupts & irq_set) { /* subscribed interrupt */ |
|
63 |
timer_int_handler(); |
|
64 |
if (!(no_interrupts % frequency)) { /* second elapsed */ |
|
65 |
timer_print_elapsed_time(); |
|
66 |
time--; |
|
67 |
} |
|
68 |
} |
|
69 |
break; |
|
70 |
default: |
|
71 |
break; /* no other notifications expected: do nothing */ |
|
72 |
} |
|
73 |
} else { /* received standart message, not a notification */ |
|
74 |
/* no standart message expected: do nothing */ |
|
75 |
} |
|
76 |
} |
|
77 |
if (timer_unsubscribe_int()) return 1; |
|
78 |
return 0; |
|
79 |
} |
|
0 | 80 |
lab2/src/timer.c | ||
---|---|---|
1 |
#include <lcom/lcf.h> |
|
2 |
|
|
3 |
#include "timer.h" |
|
4 |
|
|
5 |
#include "i8254.h" |
|
6 |
#include "utils.h" |
|
7 |
#include "errors.h" |
|
8 |
|
|
9 |
//7.1 timer_test_read_config() |
|
10 |
int (timer_get_conf)(uint8_t timer, uint8_t *st) { |
|
11 |
if(st == NULL) return 1; |
|
12 |
// Write read-back command to TIMER_CTRL |
|
13 |
u32_t cmd = TIMER_RB_CMD | TIMER_RB_COUNT_ | TIMER_RB_SEL(timer); |
|
14 |
if(sys_outb(TIMER_CTRL, cmd)) return 1; |
|
15 |
int read_port; |
|
16 |
switch(timer) { |
|
17 |
case 0: read_port = TIMER_0; break; |
|
18 |
case 1: read_port = TIMER_1; break; |
|
19 |
case 2: read_port = TIMER_2; break; |
|
20 |
default: return 1; |
|
21 |
} |
|
22 |
if(util_sys_inb(read_port, st)) return 1; |
|
23 |
return 0; |
|
24 |
} |
|
25 |
int (timer_display_conf)(uint8_t timer, uint8_t st, enum timer_status_field field) { |
|
26 |
union timer_status_field_val conf; |
|
27 |
uint8_t in_mode; |
|
28 |
switch(field){ |
|
29 |
case tsf_all: |
|
30 |
conf.byte = st; /* Full Status Byte */ |
|
31 |
break; |
|
32 |
case tsf_initial: |
|
33 |
/* Counter Initial Value Loading Mode */ |
|
34 |
in_mode = (st & TIMER_INMODE_MASK) >> TIMER_INMODE_POS; |
|
35 |
switch(in_mode){ |
|
36 |
case 0: conf.in_mode = INVAL_val ; break; //000 |
|
37 |
case 1: conf.in_mode = LSB_only ; break; //001 |
|
38 |
case 2: conf.in_mode = MSB_only ; break; //010 |
|
39 |
case 3: conf.in_mode = MSB_after_LSB; break; //011 |
|
40 |
default: return 1; |
|
41 |
} |
|
42 |
break; |
|
43 |
case tsf_mode: |
|
44 |
/* Counting Mode */ |
|
45 |
conf.count_mode = (st & TIMER_MODE_MASK)>>TIMER_MODE_POS; |
|
46 |
if(conf.count_mode == TIMER_MODE_2ALT || conf.count_mode == TIMER_MODE_3ALT) |
|
47 |
conf.count_mode &= TIMER_MODE_RED2; |
|
48 |
break; |
|
49 |
case tsf_base: |
|
50 |
/* Representation of Counter Initial Value */ |
|
51 |
conf.bcd = st & TIMER_BCD; |
|
52 |
break; |
|
53 |
default: return 1; |
|
54 |
} |
|
55 |
if(timer_print_config(timer, field, conf)) return 1; |
|
56 |
return 0; |
|
57 |
} |
|
58 |
//7.2 timer_test_time_base() |
|
59 |
int (timer_set_frequency)(uint8_t timer, uint32_t freq) { |
|
60 |
|
|
61 |
// Frequencies out this range are not supported (by limitation of hardware) |
|
62 |
if (freq > TIMER_FREQ || freq < TIMER_MIN_FREQ) { |
|
63 |
printf("%s: Frequency out of range, must be between %d and %d.\n", __func__, TIMER_MIN_FREQ, TIMER_FREQ); |
|
64 |
return 1; |
|
65 |
} |
|
66 |
|
|
67 |
uint8_t status = 0; |
|
68 |
if (timer_get_conf(timer, &status)) return 1; |
|
69 |
//Make command |
|
70 |
uint8_t write_cmd = 0; |
|
71 |
//Select timer |
|
72 |
switch(timer) { |
|
73 |
case 0: write_cmd |= TIMER_SEL0; break; |
|
74 |
case 1: write_cmd |= TIMER_SEL1; break; |
|
75 |
case 2: write_cmd |= TIMER_SEL2; break; |
|
76 |
default: return 1; |
|
77 |
} |
|
78 |
//Change both LSB and MSB |
|
79 |
write_cmd |= TIMER_LSB_MSB; |
|
80 |
//Keep 4 least significant bits |
|
81 |
write_cmd |= (status & (TIMER_MODE_MASK | TIMER_BCD)); |
|
82 |
//Write cmd |
|
83 |
if (sys_outb(TIMER_CTRL, write_cmd)) return 1; |
|
84 |
|
|
85 |
// counter_init = clock/freq |
|
86 |
uint16_t counter_init = (uint16_t)(TIMER_FREQ / freq); |
|
87 |
|
|
88 |
int timer_port = 0; |
|
89 |
switch(timer) { |
|
90 |
case 0: timer_port = TIMER_0; break; |
|
91 |
case 1: timer_port = TIMER_1; break; |
|
92 |
case 2: timer_port = TIMER_2; break; |
|
93 |
default: return 1; |
|
94 |
} |
|
95 |
uint8_t lsb = 0, msb = 0; |
|
96 |
/* Split the 16 bits word in two bytes */ |
|
97 |
if (util_get_LSB(counter_init, &lsb)) return 1; |
|
98 |
if (util_get_MSB(counter_init, &msb)) return 1; |
|
99 |
|
|
100 |
/* Write the 8 LSB of the counter */ |
|
101 |
if (sys_outb(timer_port, lsb)) return 1; |
|
102 |
/* Write the 8 MSB of the counter */ |
|
103 |
if (sys_outb(timer_port, msb)) return 1; |
|
104 |
|
|
105 |
return 0; |
|
106 |
} |
|
107 |
//7.3 timer_test_int() |
|
108 |
void (timer_int_handler)(void) { |
|
109 |
no_interrupts++; |
|
110 |
} |
|
111 |
#ifdef LAB2 |
|
112 |
static int hook_id; |
|
113 |
int (timer_subscribe_int)(uint8_t *bit_no) { |
|
114 |
if(bit_no == NULL) return NULL_PTR; |
|
115 |
hook_id = 2; |
|
116 |
*bit_no = hook_id; |
|
117 |
return sys_irqsetpolicy(TIMER0_IRQ, IRQ_REENABLE, &hook_id); |
|
118 |
} |
|
119 |
int (timer_unsubscribe_int)() { |
|
120 |
return unsubscribe_interrupt(&hook_id); |
|
121 |
} |
|
122 |
#endif |
|
123 |
int (subscribe_timer_interrupt)(uint8_t interrupt_bit, int *interrupt_id) { |
|
124 |
if (interrupt_id == NULL) return 1; |
|
125 |
*interrupt_id = interrupt_bit; |
|
126 |
return (sys_irqsetpolicy(TIMER0_IRQ, IRQ_REENABLE, interrupt_id)); |
|
127 |
} |
|
128 |
uint32_t no_interrupts = 0; |
|
0 | 129 |
lab2/src/utils.c | ||
---|---|---|
1 |
#include <lcom/lcf.h> |
|
2 |
|
|
3 |
#include "utils.h" |
|
4 |
|
|
5 |
#include <stdint.h> |
|
6 |
#include "errors.h" |
|
7 |
|
|
8 |
int(util_get_LSB)(uint16_t val, uint8_t *lsb) { |
|
9 |
if (lsb == NULL) return NULL_PTR; |
|
10 |
*lsb = val; |
|
11 |
return SUCCESS; |
|
12 |
} |
|
13 |
|
|
14 |
int(util_get_MSB)(uint16_t val, uint8_t *msb) { |
|
15 |
if (msb == NULL) return NULL_PTR; |
|
16 |
*msb = (val >> 8); |
|
17 |
return SUCCESS; |
|
18 |
} |
|
19 |
|
|
20 |
int (util_sys_inb)(int port, uint8_t *value) { |
|
21 |
if(value == NULL) return NULL_PTR; |
|
22 |
uint32_t n = 0; |
|
23 |
if(sys_inb(port, &n)) return READ_ERROR; |
|
24 |
*value = n; |
|
25 |
return SUCCESS; |
|
26 |
} |
|
27 |
|
|
28 |
int (unsubscribe_interrupt)(int *interrupt_id) { |
|
29 |
if (interrupt_id == NULL) return NULL_PTR; |
|
30 |
if(sys_irqrmpolicy(interrupt_id)) return UNSBCR_ERROR; |
|
31 |
return SUCCESS; |
|
32 |
} |
|
33 |
|
|
34 |
int32_t min(int32_t a, int32_t b){ return (b < a ? b : a); } |
|
35 |
int32_t max(int32_t a, int32_t b){ return (a < b ? b : a); } |
|
0 | 36 |
lab2/Makefile | ||
---|---|---|
1 | 1 |
# name of the program (Minix service) |
2 |
PROG=lab2
|
|
2 |
PROG=lab2 |
|
3 | 3 |
|
4 |
.PATH: ${.CURDIR}/src |
|
5 |
|
|
4 | 6 |
# source code files to be compiled |
5 | 7 |
SRCS = lab2.c timer.c utils.c |
6 | 8 |
|
7 | 9 |
# additional compilation flags |
8 | 10 |
# "-Wall -Wextra -Werror -I . -std=c11 -Wno-unused-parameter" are already set |
9 |
CFLAGS += -pedantic |
|
11 |
CFLAGS += -pedantic -I./include -D LAB2
|
|
10 | 12 |
|
11 | 13 |
# list of library dependencies (for Lab 2, only LCF library) |
12 | 14 |
DPADD += ${LIBLCF} |
Also available in: Unified diff