| Xmega IEC60730 Class B Library 1.0 |

All Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
classb_interrupt_monitor.c
Go to the documentation of this file.
1 /* This file has been prepared for Doxygen automatic documentation generation.*/
2 /**
3 * \file
4 *
5 * \brief
6 * This file contains functions for monitoring the frequency of execution of
7 * registered interrupts.
8 *
9 * \par Application note:
10 * AVR1610: Guide to IEC60730 Class B compliance with XMEGA
11 *
12 * \par Documentation
13 * For comprehensive code documentation, supported compilers, compiler
14 * settings and supported devices see readme.html
15 *
16 * \author
17 * Atmel Corporation: http://www.atmel.com \n
18 * Support email: avr@atmel.com
19 *
20 * Copyright (C) 2012 Atmel Corporation. All rights reserved.
21 *
22 * \page License
23 *
24 * Redistribution and use in source and binary forms, with or without
25 * modification, are permitted provided that the following conditions are met:
26 *
27 * 1. Redistributions of source code must retain the above copyright notice,
28 * this list of conditions and the following disclaimer.
29 *
30 * 2. Redistributions in binary form must reproduce the above copyright notice,
31 * this list of conditions and the following disclaimer in the documentation
32 * and/or other materials provided with the distribution.
33 *
34 * 3. The name of Atmel may not be used to endorse or promote products derived
35 * from this software without specific prior written permission.
36 *
37 * 4. This software may only be redistributed and used in connection with an
38 * Atmel AVR product.
39 *
40 * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
41 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
42 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
43 * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
44 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
45 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
46 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
47 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
48 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
49 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
50 * DAMAGE.
51 */
52
53
54 #include "classb_interrupt_monitor.h"
55
56 //! \brief Array of data structures for the interrupts that should be monitored
57 struct intmon_interrupt monitored_interrupts[N_INTERRUPTS];
58
59
60 /** \brief Registers an interrupt.
61 *
62 * This function registers the information that the monitor needs in order to
63 * check an interrupt. It should be called from the main application. Interrupts
64 * must be declared in \ref classb_int_identifiers in the configuration file.
65 * Note that by default the interrupt is not active for monitoring, i.e. the
66 * state is \c OFF.
67 *
68 * \param identifier Interrupt identifier. Use symbol declared in \ref classb_int_identifiers
69 * \param reference Number of expected executions for the interrupt within an RTC period:
70 * <tt>F_INT (Hz) * CLASSB_RTC_INT_PERIOD / CLASSB_RTC_FREQ (Hz) </tt>
71 * \param tolerance The allowed deviation (%) with respect to interrupt_counter for the interrupt counter.
72 * \callergraph
73 */
74 void classb_intmon_reg_int(enum classb_int_identifiers identifier, uint16_t reference, uint8_t tolerance)
75 {
76
77 monitored_interrupts[identifier].n = reference;
78 monitored_interrupts[identifier].c = 0;
79 monitored_interrupts[identifier].l = (reference * tolerance) / 100;
80 monitored_interrupts[identifier].s = OFF;
81
82 }
83
84 /*! \brief Increases the interrupt counter of the specified interrupt.
85 *
86 * This is called from the interrupt routine and it will increases the counter
87 * if the interrupt is \c ON.
88 *
89 * \param identifier Interrupt identifier. Use symbol declared in \ref classb_int_identifiers
90 *
91 * \callergraph
92 */
93 void classb_intmon_increase( enum classb_int_identifiers identifier )
94 {
95
96 if (monitored_interrupts[identifier].s == ON)
97 monitored_interrupts[identifier].c++;
98
99 }
100
101 /*! \brief Set a state for the specified interrupt.
102 *
103 * This function should be called from the main application to enable or disable monitoring this interrupt.
104 * The application can only set the state to ENABLE or DISABLE, otherwise the error handler will be called.
105 * i.e. only the monitor can set \c ON and \c OFF states. Further, if \ref CLASSB_STRICT is defined, it is not allowed
106 * to enable an interrupt in the \c ON state, or disable an interrupt in the \c OFF state.
107 *
108 * \param identifier Interrupt identifier. Use symbol declared in \ref classb_int_identifiers.
109 * \param state Interrupt state. Use symbol declared in \ref classb_int_states.
110 *
111 * \callergraph
112 */
113 void classb_intmon_set_state( enum classb_int_identifiers identifier, enum classb_int_states state )
114 {
115
116 switch (state)
117 {
118 case ENABLE:
119 #ifdef CLASSB_STRICT
120 if (monitored_interrupts[identifier].s != OFF)
121 {
122 CLASSB_ERROR_HANDLER_INTERRUPT();
123 break;
124 }
125 #endif
126 break;
127
128 case DISABLE:
129 #ifdef CLASSB_STRICT
130 if (monitored_interrupts[identifier].s != ON)
131 {
132 CLASSB_ERROR_HANDLER_INTERRUPT();
133 break;
134 }
135 #endif
136 break;
137 default:
138 CLASSB_ERROR_HANDLER_INTERRUPT();
139 }
140
141 // Set the new state only if CLASSB_CONDITION1_INTERRUPT is true.
142 if(CLASSB_CONDITION1_INTERRUPT)
143 monitored_interrupts[identifier].s = state;
144
145 }
146
147
148
149 //! \internal\brief Returns the absolute value of the difference between two numbers.
150 static inline uint16_t abs_diff(uint16_t a, uint16_t b)
151 {
152 return (a > b)?(a - b):(b - a);
153 }
154
155 /*! \brief The interrupt monitor.
156 *
157 * For each registered interrupt, this function compares the counter with
158 * the expected value. There is an error if the difference is greater
159 * than the limit or if the interrupt is disabled and the counter is different
160 * than zero. If \ref CLASSB_CONDITION2_INTERRUPT is true, the monitor will stop
161 * immediately, i.e. the remaining interrupts are not checked.
162 *
163 * \note This should be called back from the RTC interrupt. See \ref rtc_driver.
164 *
165 * \callergraph
166 */
167 void classb_intmon_callback()
168 {
169
170 for (uint8_t i = 0; i < N_INTERRUPTS; i++ )
171 {
172
173 switch (monitored_interrupts[i].s)
174 {
175 case ON:
176 // Check whether the counter is within the allowed range
177 if ( (uint16_t) abs_diff(monitored_interrupts[i].c, monitored_interrupts[i].n) > monitored_interrupts[i].l) {
178 CLASSB_ERROR_HANDLER_INTERRUPT();
179 break;
180 }
181 // Reset counter
182 monitored_interrupts[i].c = 0;
183 break;
184 case OFF:
185 // The counter is only increased when the state is ON.
186 if (monitored_interrupts[i].c)
187 CLASSB_ERROR_HANDLER_INTERRUPT();
188 break;
189 case ENABLE:
190 // Change state
191 monitored_interrupts[i].s = ON;
192 break;
193 case DISABLE:
194 // Change state and reset the counter
195 monitored_interrupts[i].s = OFF;
196 monitored_interrupts[i].c = 0;
197 break;
198 default:
199 CLASSB_ERROR_HANDLER_INTERRUPT();
200 }
201
202 // If CLASSB_CONDITION2_INTERRUPT is true, there is no need to check the other interrupts.
203 if (CLASSB_CONDITION2_INTERRUPT)
204 break;
205 }
206 }