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 
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  */
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  */
114 {
115 
116  switch (state)
117  {
118  case ENABLE:
119 #ifdef CLASSB_STRICT
120  if (monitored_interrupts[identifier].s != OFF)
121  {
123  break;
124  }
125 #endif
126  break;
127 
128  case DISABLE:
129 #ifdef CLASSB_STRICT
130  if (monitored_interrupts[identifier].s != ON)
131  {
133  break;
134  }
135 #endif
136  break;
137  default:
139  }
140 
141  // Set the new state only if CLASSB_CONDITION1_INTERRUPT is true.
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  */
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) {
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)
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:
200  }
201 
202  // If CLASSB_CONDITION2_INTERRUPT is true, there is no need to check the other interrupts.
204  break;
205  }
206 }