FreeEMS  0.2.0-SNAPSHOT-285-g028e24c
utils.c
Go to the documentation of this file.
1 /* FreeEMS - the open source engine management system
2  *
3  * Copyright 2008-2012 Fred Cooke
4  *
5  * This file is part of the FreeEMS project.
6  *
7  * FreeEMS software is free software: you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation, either version 3 of the License, or
10  * (at your option) any later version.
11  *
12  * FreeEMS software is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with any FreeEMS software. If not, see http://www.gnu.org/licenses/
19  *
20  * We ask that if you make any changes to this file you email them upstream to
21  * us at admin(at)diyefi(dot)org or, even better, fork the code on github.com!
22  *
23  * Thank you for choosing FreeEMS to run your engine!
24  */
25 
26 
27 /** @file
28  *
29  * @brief Utility functions only
30  *
31  * General purpose utility functions that are used in various places throughout
32  * the code base. Functions should only be placed here if they are not strongly
33  * related to any other set of functionality.
34  */
35 
36 
37 #define UTILS_C
38 #include "inc/freeEMS.h"
39 #include "inc/commsISRs.h"
40 #include "inc/utils.h"
41 #include <string.h>
42 
43 
44 /** @brief Add two unsigned shorts safely
45  *
46  * This will either return short max or the sum of the two arguments.
47  *
48  * @param addend1
49  * @param addend2
50  */
51 unsigned short safeAdd(unsigned short addend1, unsigned short addend2){
52  if((SHORTMAX - addend1) > addend2){
53  return addend1 + addend2;
54  }else{
55  return SHORTMAX;
56  }
57 }
58 
59 
60 /** @brief Add signed short to an unsigned short safely
61  *
62  * This will either return short max, zero, or the sum of the two arguments.
63  *
64  * @param addend1
65  * @param addend2
66  */
67 unsigned short safeTrim(unsigned short addend1, signed short addend2){
68 
69  if(addend2 < 0){
70  if(addend1 > -addend2){
71  return addend1 + addend2;
72  }else{
73  return 0;
74  }
75  }else if(addend2 > 0){
76  if(addend2 < (SHORTMAX - addend1)){
77  return addend1 + addend2;
78  }else{
79  return SHORTMAX;
80  }
81  }else{
82  return addend1;
83  }
84 }
85 
86 
87 /** @brief Scale without overflow
88  *
89  * Takes a base value and a scaler where 0x8000/32768 means 100%, 0 means 0%
90  * and 0xFFFF/65535 means 200%, and returns the baseValue multiplied, in effect, by the
91  * resulting percentage figure.
92  *
93  * @param baseValue
94  * @param dividend
95  * @param divisor
96  */
97 unsigned short safeScale(unsigned short baseValue, unsigned short dividend, unsigned short divisor){
98  /* Perform the scaling */
99  unsigned short scaled = ((unsigned long)baseValue * dividend) / divisor;
100 
101  /* If the trim is greater than 100% then the trimmedPW MUST be larger */
102  /* If it's less than 100% it can't have overflowed. If it's not larger, it overflowed */
103  if((dividend > divisor) && (baseValue > scaled)){
104  return SHORTMAX;
105  }else{
106  return scaled;
107  }
108 }
109 
110 
111 /** @brief Setup tune switching
112  *
113  * Place the correct set of tables in RAM based on a boolean parameter
114  *
115  * @todo TODO change parameter style to be a pointer to a register and a mask?
116  *
117  * @param bool which set of data to enable.
118  */
119 void setupPagedRAM(unsigned char bool){
120  if(bool){
124  }else{
128  }
129 
131 }
132 
133 
134 /** @brief Demonstrate PWM
135  *
136  * Demonstrate basic PWM module usage by setting duty to scaled ADC inputs.
137  */
138 void adjustPWM(){
139  PWMDTY0 = ATD0DR0 >> 2; // scale raw adc to a duty
140  PWMDTY1 = ATD0DR1 >> 2; // scale raw adc to a duty
141  PWMDTY2 = ATD0DR2 >> 2; // scale raw adc to a duty
142  PWMDTY3 = ATD0DR3 >> 2; // scale raw adc to a duty
143  PWMDTY4 = ATD0DR4 >> 2; // scale raw adc to a duty
144  PWMDTY5 = ATD0DR5 >> 2; // scale raw adc to a duty
145  PWMDTY6 = ATD0DR6 >> 2; // scale raw adc to a duty
146  PWMDTY7 = ATD0DR7 >> 2; // scale raw adc to a duty (user led instead at the moment, see init)
147 }
148 
149 
150 /** @brief Read ADCs one at a time
151  *
152  * Read ADCs into the correct bank one at a time by name.
153  *
154  * @param Arrays a pointer to an ADCBuffer struct to store ADC values in.
155  */
156 void sampleEachADC(ADCBuffer *Arrays){
157  /* ATD0 */
158  Arrays->IAT = ATD0DR0;
159  Arrays->CHT = ATD0DR1;
160  Arrays->TPS = ATD0DR2;
161  Arrays->EGO = ATD0DR3;
162  Arrays->MAP = ATD0DR4;
163  Arrays->AAP = ATD0DR5;
164  Arrays->BRV = ATD0DR6;
165  Arrays->MAT = ATD0DR7;
166 
167  /* ATD1 */
168  Arrays->EGO2 = ATD1DR0;
169  Arrays->IAP = ATD1DR1;
170  Arrays->MAF = ATD1DR2;
171  Arrays->SpareADC3 = ATD1DR3;
172  Arrays->SpareADC4 = ATD1DR4;
173  Arrays->SpareADC5 = ATD1DR5;
174  Arrays->SpareADC6 = ATD1DR6;
175  Arrays->SpareADC7 = ATD1DR7;
176 }
177 
178 
179 /** @brief Read ADCs in a loop
180  *
181  * Read ADCs into the correct bank in a loop using pointers.
182  *
183  * @param Arrays a pointer to an ADCBuffer struct to store ADC values in.
184  */
185 void sampleLoopADC(ADCBuffer *Arrays){
186  // get the address of the ADC array
187  unsigned short addr = (unsigned short)Arrays;
188 
189  //sendUS(addr);
190  unsigned char loop;
191  /* (value of((address of ADCBuffers struct) + (offset to start of bank(0 or half struct length)) + (offset to particular ADC (loopcounter * 4)) + (offset to correct element(0 or 2)))) =
192  * (value of((address of ARRAY block) + (loop counter * 2))) */
193 
194  for(loop=0;loop<16;loop += 2){
195  /* Do the first block */
196  DVUSP(addr + loop) = DVUSP(ATD0_BASE + loop);
197 
198  /* Do the second block */
199  DVUSP(addr + 16 + loop) = DVUSP(ATD1_BASE + loop);
200  /// @todo TODO this needs to be split into two loops one for the small block and one for the big one for the future chips.
201  }
202 }
203 
204 
205 /* @brief Read ADCs with memcpy()
206  *
207  * Read ADCs into the correct bank using two fixed calls to memcpy()
208  *
209  * @param Arrays a pointer to an ADCBuffer struct to store ADC values in.
210  *
211  * @warning this will corrupt your comms if you use it... don't use it
212  * @bug this will corrupt your comms if you use it... don't use it
213  *
214 void sampleBlockADC(ADCBuffer *Arrays){
215  memcpy(Arrays, (void*)ATD0_BASE, 16);
216  memcpy(Arrays+16, (void*)ATD1_BASE, 16);
217 }*/
218 
219 
220 /** @brief Sleep for X milli seconds
221  *
222  * Run in a nested loop repeatedly for X milli seconds.
223  *
224  * @param ms the number of milli seconds to kill
225  */
226 void sleep(unsigned short ms){
227  unsigned short j, k;
228  for(j=0;j<ms;j++){
229  for(k=0;k<5714;k++){
230  }
231  }
232 }
233 
234 
235 /** @brief Sleep for X micro seconds
236  *
237  * Run in a nested loop repeatedly for X micro seconds.
238  *
239  * @note Very approximate...
240  *
241  * @param us the number of micro seconds to kill
242  */
243 void sleepMicro(unsigned short us){
244  unsigned short j, k;
245  for(j=0;j<us;j++){
246  for(k=0;k<6;k++){
247  }
248  }
249 }
250 
251 
252 /** @brief Simple checksum
253  *
254  * Generate a simple additive checksum for a block of data.
255  *
256  * @param block a pointer to a memory region to checksum.
257  * @param length how large the memory region to checksum is.
258  *
259  * @return a simple additive checksum.
260  */
261 unsigned char checksum(unsigned char *block, unsigned short length){
262  unsigned char sum = 0;
263  while (length-- > 0){
264  sum += *block++;
265  }
266  return sum;
267 }
268 
269 
270 /** @brief Homebrew strcpy()
271  *
272  * strcpy() wouldn't compile for me for some reason so I wrote my own.
273  *
274  * @param dest where to copy the null terminated string to.
275  * @param source where to copy the null terminated string from.
276  *
277  * @return the length of the string copied, including the zero byte terminator.
278  */
279 unsigned short stringCopy(unsigned char* dest, unsigned char* source){
280  unsigned short length = 0;
281  do {
282  *dest++ = *source++;
283  length++;
284  } while(*(source-1) != 0);
285  return length;
286 }
287 
288 /**
289  * @returns a one based index of the failure point
290  *
291  * @note this will return a positive result with bad data in the last position of a maximum sized block
292  */
293 unsigned short compare(unsigned char* original, unsigned char* toCheck, unsigned short length){
294  unsigned short i;
295  for(i=0;i<length;i++){
296  if(original[i] != toCheck[i]){
297  return i + 1; // zero = success
298  }
299  }
300  return 0;
301 }