FreeEMS  0.2.0-SNAPSHOT-282-g9efc524
blockDetailsLookup.c
Go to the documentation of this file.
1 /* FreeEMS - the open source engine management system
2  *
3  * Copyright 2008-2013 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  * @ingroup communicationsFiles
30  *
31  * @brief Memory block details lookup
32  *
33  * This file holds the single function lookupBlockDetails() which
34  * functions as a sort of address book for logical blocks of memory.
35  */
36 
37 
38 #define BLOCK_DETAILS_LOOKUP_C
39 #include "inc/freeEMS.h"
40 #include "inc/interrupts.h"
41 #include "inc/locationIDs.h"
43 #include "inc/blockDetailsLookup.h"
44 
45 
46 /** @brief Lookup memory block details.
47  *
48  * Flash only blocks leave the RAM address and page values
49  * set to zero. ID's that don't exist return an error code.
50  *
51  * @note This function is an exception to the style rule switch statement
52  * blocks of using a {} pair for each case statement. Readability is better
53  * without them in this case.
54  *
55  * @param locationID is the ID of the memory location for which details are required.
56  * @param details is a pointer to the blockDetails struct to populate with the details.
57  *
58  * @return An error code. Zero means success, anything else is a failure.
59  */
60 unsigned short lookupBlockDetails(unsigned short locationID, blockDetails* details){
61  /* Initialise the four values needed for operations on memory at 0 for error checking */
62  details->RAMPage = 0;
63  details->FlashPage = 0;
64  details->RAMAddress = 0;
65  details->FlashAddress = 0;
66 
67  /* Initialise the block size to 1024 to save code space and increase readability */
68  details->size = sizeof(mainTable);
69 
70  // No need to set parent value to zero as ignored unless flag set, done for clarity in hex stream.
71  details->parent = 0;
72 
73  /* Look up the locations and set non default sizes */
74  switch (locationID) {
75  /* flash only fixed conf full blocks */
77  details->FlashPage = PPAGE;
78  details->FlashAddress = (void*)&fixedConfigs1;
79  break;
81  details->FlashPage = PPAGE;
82  details->FlashAddress = (void*)&fixedConfigs2;
83  break;
84 
85  /* lookup tables */
87  details->size = sizeof(IATTransferTable);
88  details->FlashPage = LOOKUP_PPAGE;
90  break;
92  details->size = sizeof(CHTTransferTable);
93  details->FlashPage = LOOKUP_PPAGE;
95  break;
96 #ifdef ALL_CONFIG
98  details->size = sizeof(MAFTransferTable);
99  details->FlashPage = LOOKUP_PPAGE;
101  break;
103  details->size = sizeof(TestTransferTable);
104  details->FlashPage = LOOKUP_PPAGE;
106  break;
107 #endif
108  /* fuel tables */
110  details->RAMPage = RPAGE_FUEL_ONE;
111  details->FlashPage = FUELTABLES_PPAGE;
112  details->RAMAddress = (void*)&TablesA;
114  break;
115 #ifdef ALL_CONFIG
117  details->RAMPage = RPAGE_FUEL_ONE;
118  details->FlashPage = FUELTABLES_PPAGE;
119  details->RAMAddress = (void*)&TablesB;
121  break;
122 #endif
124  details->RAMPage = RPAGE_FUEL_ONE;
125  details->FlashPage = FUELTABLES_PPAGE;
126  details->RAMAddress = (void*)&TablesC;
128  break;
130  details->RAMPage = RPAGE_FUEL_ONE;
131  details->FlashPage = FUELTABLES_PPAGE;
132  details->RAMAddress = (void*)&TablesD;
134  break;
135 #ifdef ALL_CONFIG
137  details->RAMPage = RPAGE_FUEL_TWO;
138  details->FlashPage = FUELTABLES_PPAGE;
139  details->RAMAddress = (void*)&TablesA;
141  break;
143  details->RAMPage = RPAGE_FUEL_TWO;
144  details->FlashPage = FUELTABLES_PPAGE;
145  details->RAMAddress = (void*)&TablesB;
147  break;
149  details->RAMPage = RPAGE_FUEL_TWO;
150  details->FlashPage = FUELTABLES_PPAGE;
151  details->RAMAddress = (void*)&TablesC;
153  break;
155  details->RAMPage = RPAGE_FUEL_TWO;
156  details->FlashPage = FUELTABLES_PPAGE;
157  details->RAMAddress = (void*)&TablesD;
159  break;
160 #endif
161 
162  /* timing tables */
164  details->RAMPage = RPAGE_TIME_ONE;
165  details->FlashPage = TIMETABLES_PPAGE;
166  details->RAMAddress = (void*)&TablesA;
168  break;
169 #ifdef ALL_CONFIG
171  details->RAMPage = RPAGE_TIME_ONE;
172  details->FlashPage = TIMETABLES_PPAGE;
173  details->RAMAddress = (void*)&TablesB;
175  break;
177  details->RAMPage = RPAGE_TIME_ONE;
178  details->FlashPage = TIMETABLES_PPAGE;
179  details->RAMAddress = (void*)&TablesC;
181  break;
183  details->RAMPage = RPAGE_TIME_ONE;
184  details->FlashPage = TIMETABLES_PPAGE;
185  details->RAMAddress = (void*)&TablesD;
187  break;
189  details->RAMPage = RPAGE_TIME_TWO;
190  details->FlashPage = TIMETABLES_PPAGE;
191  details->RAMAddress = (void*)&TablesA;
193  break;
195  details->RAMPage = RPAGE_TIME_TWO;
196  details->FlashPage = TIMETABLES_PPAGE;
197  details->RAMAddress = (void*)&TablesB;
199  break;
201  details->RAMPage = RPAGE_TIME_TWO;
202  details->FlashPage = TIMETABLES_PPAGE;
203  details->RAMAddress = (void*)&TablesC;
205  break;
207  details->RAMPage = RPAGE_TIME_TWO;
208  details->FlashPage = TIMETABLES_PPAGE;
209  details->RAMAddress = (void*)&TablesD;
211  break;
212 #endif
213 
214  /* small table full blocks */
216  details->RAMPage = RPAGE_TUNE_ONE;
217  details->FlashPage = TUNETABLES_PPAGE;
218  details->RAMAddress = (void*)&TablesA;
220  break;
222  details->RAMPage = RPAGE_TUNE_ONE;
223  details->FlashPage = TUNETABLES_PPAGE;
224  details->RAMAddress = (void*)&TablesB;
226  break;
227 #ifdef ALL_CONFIG
229  details->RAMPage = RPAGE_TUNE_ONE;
230  details->FlashPage = TUNETABLES_PPAGE;
231  details->RAMAddress = (void*)&TablesC;
233  break;
235  details->RAMPage = RPAGE_TUNE_ONE;
236  details->FlashPage = TUNETABLES_PPAGE;
237  details->RAMAddress = (void*)&TablesD;
239  break;
241  details->RAMPage = RPAGE_TUNE_TWO;
242  details->FlashPage = TUNETABLES_PPAGE;
243  details->RAMAddress = (void*)&TablesA;
245  break;
247  details->RAMPage = RPAGE_TUNE_TWO;
248  details->FlashPage = TUNETABLES_PPAGE;
249  details->RAMAddress = (void*)&TablesB;
251  break;
253  details->RAMPage = RPAGE_TUNE_TWO;
254  details->FlashPage = TUNETABLES_PPAGE;
255  details->RAMAddress = (void*)&TablesC;
257  break;
259  details->RAMPage = RPAGE_TUNE_TWO;
260  details->FlashPage = TUNETABLES_PPAGE;
261  details->RAMAddress = (void*)&TablesD;
263  break;
264 #endif
265 
266  /* TablesA small tables */
268  details->size = sizeof(twoDTableUS);
269  details->RAMPage = RPAGE_TUNE_ONE;
270  details->FlashPage = TUNETABLES_PPAGE;
271  details->RAMAddress = (void*)&TablesA.SmallTablesA.dwellDesiredVersusVoltageTable;
273  details->parent = SmallTablesALocationID;
274  break;
276  details->size = sizeof(twoDTableUS);
277  details->RAMPage = RPAGE_TUNE_ONE;
278  details->FlashPage = TUNETABLES_PPAGE;
279  details->RAMAddress = (void*)&TablesA.SmallTablesA.injectorDeadTimeTable;
281  details->parent = SmallTablesALocationID;
282  break;
283 #ifdef ALL_CONFIG
285  details->size = sizeof(twoDTableUS);
286  details->RAMPage = RPAGE_TUNE_ONE;
287  details->FlashPage = TUNETABLES_PPAGE;
288  details->RAMAddress = (void*)&TablesA.SmallTablesA.postStartEnrichmentTable;
290  details->parent = SmallTablesALocationID;
291  break;
293  details->size = sizeof(twoDTableUS);
294  details->RAMPage = RPAGE_TUNE_ONE;
295  details->FlashPage = TUNETABLES_PPAGE;
296  details->RAMAddress = (void*)&TablesA.SmallTablesA.engineTempEnrichmentTableFixed;
298  details->parent = SmallTablesALocationID;
299  break;
300 #endif
302  details->size = sizeof(twoDTableUS);
303  details->RAMPage = RPAGE_TUNE_ONE;
304  details->FlashPage = TUNETABLES_PPAGE;
305  details->RAMAddress = (void*)&TablesA.SmallTablesA.primingVolumeTable;
307  details->parent = SmallTablesALocationID;
308  break;
310  details->size = sizeof(twoDTableUS);
311  details->RAMPage = RPAGE_TUNE_ONE;
312  details->FlashPage = TUNETABLES_PPAGE;
313  details->RAMAddress = (void*)&TablesA.SmallTablesA.engineTempEnrichmentTablePercent;
315  details->parent = SmallTablesALocationID;
316  break;
318  details->size = sizeof(twoDTableUS);
319  details->RAMPage = RPAGE_TUNE_ONE;
320  details->FlashPage = TUNETABLES_PPAGE;
321  details->RAMAddress = (void*)&TablesA.SmallTablesA.dwellVersusRPMTable;
323  details->parent = SmallTablesALocationID;
324  break;
326  details->size = sizeof(twoDTableUS);
327  details->RAMPage = RPAGE_TUNE_ONE;
328  details->FlashPage = TUNETABLES_PPAGE;
329  details->RAMAddress = (void*)&TablesA.SmallTablesA.blendVersusRPMTable;
331  details->parent = SmallTablesALocationID;
332  break;
333 
334 #ifdef ALL_CONFIG
336  details->size = sizeof(twoDTableUS);
337  details->RAMPage = RPAGE_TUNE_TWO;
338  details->FlashPage = TUNETABLES_PPAGE;
339  details->RAMAddress = (void*)&TablesA.SmallTablesA.dwellDesiredVersusVoltageTable;
341  details->parent = SmallTablesA2LocationID;
342  break;
344  details->size = sizeof(twoDTableUS);
345  details->RAMPage = RPAGE_TUNE_TWO;
346  details->FlashPage = TUNETABLES_PPAGE;
347  details->RAMAddress = (void*)&TablesA.SmallTablesA.injectorDeadTimeTable;
349  details->parent = SmallTablesA2LocationID;
350  break;
352  details->size = sizeof(twoDTableUS);
353  details->RAMPage = RPAGE_TUNE_TWO;
354  details->FlashPage = TUNETABLES_PPAGE;
355  details->RAMAddress = (void*)&TablesA.SmallTablesA.postStartEnrichmentTable;
357  details->parent = SmallTablesA2LocationID;
358  break;
360  details->size = sizeof(twoDTableUS);
361  details->RAMPage = RPAGE_TUNE_TWO;
362  details->FlashPage = TUNETABLES_PPAGE;
363  details->RAMAddress = (void*)&TablesA.SmallTablesA.engineTempEnrichmentTableFixed;
365  details->parent = SmallTablesA2LocationID;
366  break;
368  details->size = sizeof(twoDTableUS);
369  details->RAMPage = RPAGE_TUNE_TWO;
370  details->FlashPage = TUNETABLES_PPAGE;
371  details->RAMAddress = (void*)&TablesA.SmallTablesA.primingVolumeTable;
373  details->parent = SmallTablesA2LocationID;
374  break;
376  details->size = sizeof(twoDTableUS);
377  details->RAMPage = RPAGE_TUNE_TWO;
378  details->FlashPage = TUNETABLES_PPAGE;
379  details->RAMAddress = (void*)&TablesA.SmallTablesA.engineTempEnrichmentTablePercent;
381  details->parent = SmallTablesA2LocationID;
382  break;
384  details->size = sizeof(twoDTableUS);
385  details->RAMPage = RPAGE_TUNE_TWO;
386  details->FlashPage = TUNETABLES_PPAGE;
387  details->RAMAddress = (void*)&TablesA.SmallTablesA.dwellVersusRPMTable;
389  details->parent = SmallTablesA2LocationID;
390  break;
392  details->size = sizeof(twoDTableUS);
393  details->RAMPage = RPAGE_TUNE_TWO;
394  details->FlashPage = TUNETABLES_PPAGE;
395  details->RAMAddress = (void*)&TablesA.SmallTablesA.blendVersusRPMTable;
397  details->parent = SmallTablesA2LocationID;
398  break;
399 #endif
400  /* TablesB small tables */
402  details->size = sizeof(loggingSetting);
403  details->RAMPage = RPAGE_TUNE_ONE;
404  details->FlashPage = TUNETABLES_PPAGE;
405  details->RAMAddress = (void*)&TablesB.SmallTablesB.loggingSettings;
407  details->parent = SmallTablesBLocationID;
408  break;
409 #ifdef ALL_CONFIG
411  details->size = sizeof(loggingSetting);
412  details->RAMPage = RPAGE_TUNE_TWO;
413  details->FlashPage = TUNETABLES_PPAGE;
414  details->RAMAddress = (void*)&TablesB.SmallTablesB.loggingSettings;
416  details->parent = SmallTablesB2LocationID;
417  break;
418 #endif
419 
420  /* TablesC small tables */
421  // TODO add data chunks from TablesC when some are put in
422 
423  /* TablesD small tables */
424  // TODO add data chunks from TablesD when some are put in
425 
426 #ifdef ALL_CONFIG
427  /* filler block entries */
428  case fillerALocationID:
429  details->size = SMALL_TABLES_1_FILLER_SIZE;
430  details->RAMPage = RPAGE_TUNE_ONE;
431  details->FlashPage = TUNETABLES_PPAGE;
432  details->RAMAddress = (void*)&TablesA.SmallTablesA.filler;
433  details->FlashAddress = fillerALocation;
434  details->parent = SmallTablesALocationID;
435  break;
436  case fillerA2LocationID:
437  details->size = SMALL_TABLES_1_FILLER_SIZE;
438  details->RAMPage = RPAGE_TUNE_TWO;
439  details->FlashPage = TUNETABLES_PPAGE;
440  details->RAMAddress = (void*)&TablesA.SmallTablesA.filler;
441  details->FlashAddress = fillerA2Location;
442  details->parent = SmallTablesA2LocationID;
443  break;
444  case fillerBLocationID:
445  details->size = SMALL_TABLES_2_FILLER_SIZE;
446  details->RAMPage = RPAGE_TUNE_ONE;
447  details->FlashPage = TUNETABLES_PPAGE;
448  details->RAMAddress = (void*)&TablesB.SmallTablesB.filler;
449  details->FlashAddress = fillerBLocation;
450  details->parent = SmallTablesBLocationID;
451  break;
452  case fillerB2LocationID:
453  details->size = SMALL_TABLES_2_FILLER_SIZE;
454  details->RAMPage = RPAGE_TUNE_TWO;
455  details->FlashPage = TUNETABLES_PPAGE;
456  details->RAMAddress = (void*)&TablesB.SmallTablesB.filler;
457  details->FlashAddress = fillerB2Location;
458  details->parent = SmallTablesB2LocationID;
459  break;
460  case fillerCLocationID:
461  details->size = SMALL_TABLES_3_FILLER_SIZE;
462  details->RAMPage = RPAGE_TUNE_ONE;
463  details->FlashPage = TUNETABLES_PPAGE;
464  details->RAMAddress = (void*)&TablesC.SmallTablesC.filler;
465  details->FlashAddress = fillerCLocation;
466  details->parent = SmallTablesCLocationID;
467  break;
468  case fillerC2LocationID:
469  details->size = SMALL_TABLES_3_FILLER_SIZE;
470  details->RAMPage = RPAGE_TUNE_TWO;
471  details->FlashPage = TUNETABLES_PPAGE;
472  details->RAMAddress = (void*)&TablesC.SmallTablesC.filler;
473  details->FlashAddress = fillerC2Location;
474  details->parent = SmallTablesC2LocationID;
475  break;
476  case fillerDLocationID:
477  details->size = SMALL_TABLES_4_FILLER_SIZE;
478  details->RAMPage = RPAGE_TUNE_ONE;
479  details->FlashPage = TUNETABLES_PPAGE;
480  details->RAMAddress = (void*)&TablesD.SmallTablesD.filler;
481  details->FlashAddress = fillerDLocation;
482  details->parent = SmallTablesDLocationID;
483  break;
484  case fillerD2LocationID:
485  details->size = SMALL_TABLES_4_FILLER_SIZE;
486  details->RAMPage = RPAGE_TUNE_TWO;
487  details->FlashPage = TUNETABLES_PPAGE;
488  details->RAMAddress = (void*)&TablesD.SmallTablesD.filler;
489  details->FlashAddress = fillerD2Location;
490  details->parent = SmallTablesD2LocationID;
491  break;
492 #endif
493 
494  /* Fixed conf 1 small chunks */
496  details->size = sizeof(engineSetting);
497  details->FlashPage = PPAGE;
498  details->FlashAddress = (void*)&(fixedConfigs1.engineSettings);
499  details->parent = FixedConfig1LocationID;
500  break;
502  details->size = sizeof(serialSetting);
503  details->FlashPage = PPAGE;
504  details->FlashAddress = (void*)&(fixedConfigs1.serialSettings);
505  details->parent = FixedConfig1LocationID;
506  break;
508  details->size = sizeof(coarseBitBangSetting);
509  details->FlashPage = PPAGE;
510  details->FlashAddress = (void*)&(fixedConfigs1.coarseBitBangSettings);
511  details->parent = FixedConfig1LocationID;
512  break;
514  details->size = sizeof(schedulingSetting);
515  details->FlashPage = PPAGE;
516  details->FlashAddress = (void*)&(fixedConfigs1.schedulingSettings);
517  details->parent = FixedConfig1LocationID;
518  break;
520  details->size = sizeof(cutAndLimiterSetting);
521  details->FlashPage = PPAGE;
522  details->FlashAddress = (void*)&(fixedConfigs1.cutAndLimiterSettings);
523  details->parent = FixedConfig1LocationID;
524  break;
526  details->size = sizeof(simpleGPIOSetting);
527  details->FlashPage = PPAGE;
528  details->FlashAddress = (void*)&(fixedConfigs1.simpleGPIOSettings);
529  details->parent = FixedConfig1LocationID;
530  break;
532  details->size = userTextFieldArrayLength1;
533  details->FlashPage = PPAGE;
534  details->FlashAddress = (void*)&(fixedConfigs1.userTextField);
535  details->parent = FixedConfig1LocationID;
536  break;
537 
538  /* Fixed conf 2 small chunks */
540  details->size = sizeof(sensorSource);
541  details->FlashPage = PPAGE;
542  details->FlashAddress = (void*)&(fixedConfigs2.sensorSources);
543  details->parent = FixedConfig2LocationID;
544  break;
546  details->size = sizeof(sensorPreset);
547  details->FlashPage = PPAGE;
548  details->FlashAddress = (void*)&(fixedConfigs2.sensorPresets);
549  details->parent = FixedConfig2LocationID;
550  break;
552  details->size = sizeof(sensorRange);
553  details->FlashPage = PPAGE;
554  details->FlashAddress = (void*)&(fixedConfigs2.sensorRanges);
555  details->parent = FixedConfig2LocationID;
556  break;
558  details->size = sizeof(sensorSetting);
559  details->FlashPage = PPAGE;
560  details->FlashAddress = (void*)&(fixedConfigs2.sensorSettings);
561  details->parent = FixedConfig2LocationID;
562  break;
564  details->size = sizeof(algorithmSetting);
565  details->FlashPage = PPAGE;
566  details->FlashAddress = (void*)&(fixedConfigs2.algorithmSettings);
567  details->parent = FixedConfig2LocationID;
568  break;
570  details->size = sizeof(inputOutputSetting);
571  details->FlashPage = PPAGE;
572  details->FlashAddress = (void*)&(fixedConfigs2.inputOutputSettings);
573  details->parent = FixedConfig2LocationID;
574  break;
576  details->size = sizeof(decoderSetting);
577  details->FlashPage = PPAGE;
578  details->FlashAddress = (void*)&(fixedConfigs2.decoderSettings);
579  details->parent = FixedConfig2LocationID;
580  break;
582  details->size = userTextFieldArrayLength2;
583  details->FlashPage = PPAGE;
584  details->FlashAddress = (void*)&(fixedConfigs2.userTextField2);
585  details->parent = FixedConfig2LocationID;
586  break;
587 
588 // Internal blocks of variables that are sometimes useful to read out
590  details->size = sizeof(ADCBuffer);
591  details->RAMPage = RPAGE_LINEAR;
592  details->RAMAddress = (void*)ADCBuffers;
593  break;
594  case coreVarsLocationID:
595  details->size = sizeof(CoreVar);
596  details->RAMPage = RPAGE_LINEAR;
597  details->RAMAddress = (void*)CoreVars;
598  break;
600  details->size = sizeof(DerivedVar);
601  details->RAMPage = RPAGE_LINEAR;
602  details->RAMAddress = (void*)DerivedVars;
603  break;
605  details->size = sizeof(KeyUserDebug);
606  details->RAMPage = RPAGE_LINEAR;
607  details->RAMAddress = &KeyUserDebugs;
608  break;
609  case CountersLocationID:
610  details->size = sizeof(Counter);
611  details->RAMPage = RPAGE_LINEAR;
612  details->RAMAddress = &Counters;
613  break;
614  case ClocksLocationID:
615  details->size = sizeof(Clock);
616  details->RAMPage = RPAGE_LINEAR;
617  details->RAMAddress = &Clocks;
618  break;
620  details->size = sizeof(Flaggable);
621  details->RAMPage = RPAGE_LINEAR;
622  details->RAMAddress = &Flaggables;
623  break;
625  details->size = sizeof(Flaggable2);
626  details->RAMPage = RPAGE_LINEAR;
627  details->RAMAddress = &Flaggables2;
628  break;
629 
630  default:
631  /* Return early if locationID is not valid. */
632  return locationIDNotFound;
633  }
634 
635 
636  // Setup all of the flags for various groups here
637  // Setting flags above is wrong, keep it all in one place, here!
638 
639  // Initialise the flags to having flash, everything does at the moment, and indexable, most is, negate at end for those that don't.
641 
642  if(locationID < MainTable_TwoDTableUS_Border){
644  }else if(locationID < TwoDTableUS_SmallTableFullBlocks_Border){
646  }else if(locationID < SmallTableFullBlocks_SmallTableFillers_Border){
648  details->flags &= ~block_is_indexable;
649  }else if(locationID < SmallTableFillers_FlashLookupTables_Border){
650  details->flags |= block_has_parent | block_is_in_ram;
651  details->flags &= ~block_is_indexable;
652  }else if(locationID < FlashLookupTables_SmallTableConfigs_Border){
654  details->flags &= ~block_is_indexable;
655  }else if(locationID < SmallTableConfigs_FixedConfigBlocks_Border){
657  }else if(locationID < FixedConfigBlocks_FixedConfigSubBlocks_Border){
658  details->flags |= block_for_backup_restore;
659  }else if(locationID < FixedConfigSubBlocks_Border_ReadOnlyVarBlocks){
661  }else{ // RO variable blocks exposed polling and streaming
663  details->flags &= ~block_is_in_flash;
664  }
665 
666 /* Fall through to not return error */
667  return 0;
668 }