Browse Source

Apply coding standards to M100, break up into functions

Scott Lahteine 7 years ago
parent
commit
03aa9a390e
3 changed files with 198 additions and 187 deletions
  1. 196
    185
      Marlin/M100_Free_Mem_Chk.cpp
  2. 1
    1
      Marlin/hex_print_routines.cpp
  3. 1
    1
      Marlin/hex_print_routines.h

+ 196
- 185
Marlin/M100_Free_Mem_Chk.cpp View File

26
  * This code watches the free memory block between the bottom of the heap and the top of the stack.
26
  * This code watches the free memory block between the bottom of the heap and the top of the stack.
27
  * This memory block is initialized and watched via the M100 command.
27
  * This memory block is initialized and watched via the M100 command.
28
  *
28
  *
29
- * M100 I Initializes the free memory block and prints vitals statistics about the area
30
- * M100 F Identifies how much of the free memory block remains free and unused.  It also
31
- *    detects and reports any corruption within the free memory block that may have
32
- *    happened due to errant firmware.
33
- * M100 D Does a hex display of the free memory block along with a flag for any errant
34
- *    data that does not match the expected value.
35
- * M100 C x Corrupts x locations within the free memory block.   This is useful to check the
36
- *    correctness of the M100 F and M100 D commands.
29
+ * M100 I   Initializes the free memory block and prints vitals statistics about the area
30
+ *
31
+ * M100 F   Identifies how much of the free memory block remains free and unused. It also
32
+ *          detects and reports any corruption within the free memory block that may have
33
+ *          happened due to errant firmware.
34
+ *
35
+ * M100 D   Does a hex display of the free memory block along with a flag for any errant
36
+ *          data that does not match the expected value.
37
+ *
38
+ * M100 C x Corrupts x locations within the free memory block. This is useful to check the
39
+ *          correctness of the M100 F and M100 D commands.
37
  *
40
  *
38
  * Initial version by Roxy-3D
41
  * Initial version by Roxy-3D
39
  */
42
  */
40
-#define M100_FREE_MEMORY_DUMPER     // Comment out to remove Dump sub-command
41
-#define M100_FREE_MEMORY_CORRUPTOR    // Comment out to remove Corrupt sub-command
43
+#define M100_FREE_MEMORY_DUMPER     // Enable for the `M110 D` Dump sub-command
44
+#define M100_FREE_MEMORY_CORRUPTOR  // Enable for the `M100 C` Corrupt sub-command
42
 
45
 
43
-#include "Marlin.h"
46
+#include "MarlinConfig.h"
44
 
47
 
45
 #if ENABLED(M100_FREE_MEMORY_WATCHER)
48
 #if ENABLED(M100_FREE_MEMORY_WATCHER)
49
+
50
+#define TEST_BYTE 0xE5
51
+
46
 extern char* __brkval;
52
 extern char* __brkval;
47
 extern size_t  __heap_start, __heap_end, __flp;
53
 extern size_t  __heap_start, __heap_end, __flp;
48
 extern char __bss_end;
54
 extern char __bss_end;
49
 
55
 
56
+#include "Marlin.h"
57
+#include "hex_print_routines.h"
58
+
50
 //
59
 //
51
-// Utility functions used by M100 to get its work done.
60
+// Utility functions
52
 //
61
 //
53
 
62
 
54
-#include "hex_print_routines.h"
63
+#define END_OF_HEAP() (__brkval ? __brkval : &__bss_end)
55
 
64
 
56
-char* top_of_stack();
57
-int how_many_E5s_are_here(char*);
58
-int free_memory_is_corrupted();         // int not bool!!!!  it will tell us how many blocks of
59
-                                        // free memory it found.
60
-void gcode_M100() {
61
-  static bool m100_not_initialized = true;
62
-  char* sp, *ptr;
63
-  int i, j, n;
64
-  //
65
-  // M100 D dumps the free memory block from __brkval to the stack pointer.
66
-  // malloc() eats memory from the start of the block and the stack grows
67
-  // up from the bottom of the block.    Solid 0xE5's indicate nothing has
68
-  // used that memory yet.   There should not be anything but 0xE5's within
69
-  // the block of 0xE5's.  If there is, that would indicate memory corruption
70
-  // probably caused by bad pointers.  Any unexpected values will be flagged in
71
-  // the right hand column to help spotting them.
72
-  //
73
-    SERIAL_ECHOPAIR("\n__brkval : 0x", hex_word((uint16_t)__brkval) );
74
-    SERIAL_ECHOPAIR("\n__bss_end : 0x", hex_word((uint16_t)&__bss_end));
75
-  //
76
-  // With out malloc() we need to be smart and use &__bss_end
77
-  //
78
-    ptr = __brkval ? __brkval : &__bss_end;    
79
-    SERIAL_ECHOPAIR("\nstart of free space : 0x", hex_word((uint16_t)ptr));
80
-
81
-    sp = top_of_stack();
82
-    SERIAL_ECHOLNPAIR("\nStack Pointer : 0x", hex_word((uint16_t)sp));
83
-
84
-  #if ENABLED(M100_FREE_MEMORY_DUMPER) // Disable to remove Dump sub-command
85
-    if (code_seen('D')) {
86
-      //
87
-      // We want to start and end the dump on a nice 16 byte boundry even though
88
-      // the values we are using are not 16 byte aligned.
89
-      //
90
-      ptr = (char*) ((uint16_t) ptr & 0xfff0);
91
-      sp  = (char*) ((uint16_t) sp  | 0x000f);
92
-
93
-      n = sp - ptr;
94
-      //
95
-      // This is the main loop of the Dump command.
96
-      //
97
-      while (ptr < sp) {
98
-        print_hex_word((uint16_t)ptr); // Print the address
99
-        SERIAL_CHAR(':');
100
-        for (i = 0; i < 16; i++) {      // and 16 data bytes
101
-          if (i==8)
102
-            SERIAL_CHAR('-');
103
-          print_hex_byte(*(ptr + i));
104
-          SERIAL_CHAR(' ');
105
-        }
106
-        SERIAL_CHAR('|');         // now show where non 0xE5's are
107
-        for (i = 0; i < 16; i++)
108
-          SERIAL_CHAR((*(ptr + i) == (char)0xe5) ? ' ' : '?');
109
-        SERIAL_EOL;
110
-        ptr += 16;
111
-        idle();
65
+// Location of a variable on its stack frame. Returns a value above
66
+// the stack (once the function returns to the caller).
67
+char* top_of_stack() {
68
+  char x;
69
+  return &x + 1; // x is pulled on return;
70
+}
71
+
72
+// Count the number of test bytes at the specified location.
73
+int16_t count_test_bytes(const char * const ptr) {
74
+  for (uint16_t i = 0; i < 32000; i++)
75
+    if (ptr[i] != TEST_BYTE)
76
+      return i - 1;
77
+
78
+  return -1;
79
+}
80
+
81
+// Return a count of free memory blocks.
82
+uint16_t free_memory_is_corrupted(char * const ptr, const uint16_t size) {
83
+  // Find the longest block of test bytes in the given buffer
84
+  uint16_t block_cnt = 0;
85
+  for (uint16_t i = 0; i < size; i++) {
86
+    if (ptr[i] == TEST_BYTE) {
87
+      const uint16_t j = count_test_bytes(ptr + i);
88
+      if (j > 8) {
89
+        //SERIAL_ECHOPAIR("Found ", j);
90
+        //SERIAL_ECHOLNPAIR(" bytes free at 0x", hex_word((uint16_t)ptr + i));
91
+        i += j;
92
+        block_cnt++;
112
       }
93
       }
113
-      return;
114
     }
94
     }
115
-  #endif
116
-  //
117
-  // M100 F   requests the code to return the number of free bytes in the memory pool along with
118
-  // other vital statistics that define the memory pool.
119
-  //
120
-  if (code_seen('F')) {
121
-    int max_cnt = -1, block_cnt = 0;
122
-    uint16_t max_addr=0;
123
-    ptr =  __brkval ? __brkval : &__bss_end;
124
-    sp = top_of_stack();
125
-    n = sp - ptr;
126
-    // Scan through the range looking for the biggest block of 0xE5's we can find
127
-    for (i = 0; i < n; i++) {
128
-      if (*(ptr + i) == (char)0xe5) {
129
-        j = how_many_E5s_are_here(ptr + i);
130
-        if (j > 8) {
131
-          SERIAL_ECHOPAIR("Found ", j);
132
-          SERIAL_ECHOLNPAIR(" bytes free at 0x", hex_word((uint16_t)(ptr + i)));
133
-          if (j > max_cnt) {  
134
-            max_cnt  = j;    
135
-            max_addr = (uint16_t) ptr + i;
136
-          }
137
-          i += j;
138
-          block_cnt++;
139
-        }
95
+  }
96
+  //if (block_cnt > 1) {
97
+  //  SERIAL_ECHOLNPGM("\nMemory Corruption detected in free memory area.");
98
+  //  SERIAL_ECHOLNPAIR("\nLargest free block is ", max_cnt);
99
+  //}
100
+  return block_cnt;
101
+}
102
+
103
+//
104
+// M100 sub-commands
105
+//
106
+
107
+#if ENABLED(M100_FREE_MEMORY_DUMPER)
108
+  /**
109
+   * M100 D
110
+   *  Dump the free memory block from __brkval to the stack pointer.
111
+   *  malloc() eats memory from the start of the block and the stack grows
112
+   *  up from the bottom of the block. Solid test bytes indicate nothing has
113
+   *  used that memory yet. There should not be anything but test bytes within
114
+   *  the block. If so, it may indicate memory corruption due to a bad pointer.
115
+   *  Unexpected bytes are flagged in the right column.
116
+   */
117
+  void dump_free_memory(char *ptr, char *sp) {
118
+    //
119
+    // Start and end the dump on a nice 16 byte boundary
120
+    // (even though the values are not 16-byte aligned).
121
+    //
122
+    ptr = (char*)((uint16_t)ptr & 0xFFF0); // Align to 16-byte boundary
123
+    sp  = (char*)((uint16_t)sp  | 0x000F); // Align sp to the 15th byte (at or above sp)
124
+
125
+    // Dump command main loop
126
+    while (ptr < sp) {
127
+      print_hex_word((uint16_t)ptr);      // Print the address
128
+      SERIAL_CHAR(':');
129
+      for (uint8_t i = 0; i < 16; i++) {  // and 16 data bytes
130
+        if (i == 8) SERIAL_CHAR('-');
131
+        print_hex_byte(ptr[i]);
132
+        SERIAL_CHAR(' ');
140
       }
133
       }
134
+      SERIAL_CHAR('|');                   // Point out non test bytes
135
+      for (uint8_t i = 0; i < 16; i++)
136
+        SERIAL_CHAR(ptr[i] == TEST_BYTE ? ' ' : '?');
137
+      SERIAL_EOL;
138
+      ptr += 16;
139
+      idle();
141
     }
140
     }
142
-    if (block_cnt > 1) {
143
-      SERIAL_ECHOLNPGM("\nMemory Corruption detected in free memory area.");
144
-      SERIAL_ECHOPAIR("\nLargest free block is ", max_cnt);
145
-      SERIAL_ECHOLNPAIR(" bytes big at 0x", hex_word(max_addr));
141
+  }
142
+#endif // M100_FREE_MEMORY_DUMPER
143
+
144
+/**
145
+ * M100 F
146
+ *  Return the number of free bytes in the memory pool,
147
+ *  with other vital statistics defining the pool.
148
+ */
149
+void free_memory_pool_report(const char * const ptr, const uint16_t size) {
150
+  int16_t max_cnt = -1;
151
+  uint16_t block_cnt = 0;
152
+  char *max_addr = NULL;
153
+  // Find the longest block of test bytes in the buffer
154
+  for (uint16_t i = 0; i < size; i++) {
155
+    char * const addr = ptr + i;
156
+    if (*addr == TEST_BYTE) {
157
+      const uint16_t j = count_test_bytes(addr);
158
+      if (j > 8) {
159
+        SERIAL_ECHOPAIR("Found ", j);
160
+        SERIAL_ECHOLNPAIR(" bytes free at 0x", hex_word((uint16_t)addr));
161
+        if (j > max_cnt) {
162
+          max_cnt  = j;
163
+          max_addr = addr;
164
+        }
165
+        i += j;
166
+        block_cnt++;
167
+      }
146
     }
168
     }
147
-    SERIAL_ECHOLNPAIR("free_memory_is_corrupted() = ", free_memory_is_corrupted()); 
148
-    return;
149
   }
169
   }
150
-  //
151
-  // M100 C x  Corrupts x locations in the free memory pool and reports the locations of the corruption.
152
-  // This is useful to check the correctness of the M100 D and the M100 F commands.
153
-  //
154
-  #if ENABLED(M100_FREE_MEMORY_CORRUPTOR)
170
+  if (block_cnt > 1) {
171
+    SERIAL_ECHOLNPGM("\nMemory Corruption detected in free memory area.");
172
+    SERIAL_ECHOPAIR("\nLargest free block is ", max_cnt);
173
+    SERIAL_ECHOLNPAIR(" bytes at 0x", hex_word((uint16_t)max_addr));
174
+  }
175
+  SERIAL_ECHOLNPAIR("free_memory_is_corrupted() = ", free_memory_is_corrupted(ptr, size));
176
+}
177
+
178
+#if ENABLED(M100_FREE_MEMORY_CORRUPTOR)
179
+  /**
180
+   * M100 C<num>
181
+   *  Corrupt <num> locations in the free memory pool and report the corrupt addresses.
182
+   *  This is useful to check the correctness of the M100 D and the M100 F commands.
183
+   */
184
+  void corrupt_free_memory(char *ptr, const uint16_t size) {
155
     if (code_seen('C')) {
185
     if (code_seen('C')) {
156
-      int x = code_value_int(); // x gets the # of locations to corrupt within the memory pool
157
-      SERIAL_ECHOLNPGM("Corrupting free memory block.\n");
158
       ptr += 8;
186
       ptr += 8;
159
-      sp = top_of_stack();
160
-      n = sp - ptr - 250;    // -250 just to keep us from finding interrupt activity that
161
-                            // has altered the stack.
162
-      j = n / (x + 1);
163
-      for (i = 1; i <= x; i++) {
164
-        *(ptr + (i * j)) = i;
165
-        SERIAL_ECHOPAIR("\nCorrupting address: 0x", hex_word((uint16_t)(ptr + i * j)));
166
-      }
167
-      SERIAL_ECHOLNPGM("\n");
168
-      return;
169
-    }
170
-  #endif
171
-  //
172
-  // M100 I    Initializes the free memory pool so it can be watched and prints vital
173
-  // statistics that define the free memory pool.
174
-  //
175
-  if (m100_not_initialized || code_seen('I')) {            // If no sub-command is specified, the first time
176
-    SERIAL_ECHOLNPGM("Initializing free memory block.\n"); // this happens, it will Initialize.
177
-                                                           // Repeated M100 with no sub-command will not destroy the
178
-                                                           // state of the initialized free memory pool.
179
-    ptr += 8;
180
-    SERIAL_ECHOLNPGM("\n");
181
-    n = sp - ptr - 250;    // -250 just to keep us from finding interrupt activity that
182
-    // has altered the stack.
183
-    SERIAL_ECHO(n);
184
-    SERIAL_ECHOLNPGM(" bytes of memory initialized.\n");
185
-    for (i = 0; i < n; i++)
186
-      *(ptr + i) = (char)0xe5;
187
-    for (i = 0; i < n; i++) {
188
-      if (*(ptr + i) != (char)0xe5) {
189
-        SERIAL_ECHOPAIR("? address : ", hex_word(ptr+i) );
190
-        SERIAL_ECHOPAIR("=", hex_byte(*(ptr + i)) );
191
-        SERIAL_ECHOLNPGM("\n");
187
+      const uint16_t near_top = top_of_stack() - ptr - 250, // -250 to avoid interrupt activity that's altered the stack.
188
+                     j = near_top / (size + 1);
189
+
190
+      SERIAL_ECHOLNPGM("Corrupting free memory block.\n");
191
+      for (uint16_t i = 1; i <= size; i++) {
192
+        char * const addr = ptr + i * j;
193
+        *addr = i;
194
+        SERIAL_ECHOPAIR("\nCorrupting address: 0x", hex_word((uint16_t)addr));
192
       }
195
       }
196
+      SERIAL_EOL;
193
     }
197
     }
194
-    m100_not_initialized = false;
195
-    return;
196
   }
198
   }
197
-  return;
198
-}
199
+#endif // M100_FREE_MEMORY_CORRUPTOR
199
 
200
 
200
-// top_of_stack() returns the location of a variable on its stack frame.  The value returned is above
201
-// the stack once the function returns to the caller.
201
+/**
202
+ * M100 I
203
+ *  Init memory for the M100 tests. (Automatically applied on the first M100.)
204
+ */
205
+void init_free_memory(char *ptr, int16_t size) {
206
+  SERIAL_ECHOLNPGM("Initializing free memory block.\n\n");
202
 
207
 
203
-char* top_of_stack() {
204
-  char x;
205
-  return &x + 1; // x is pulled on return;
206
-}
208
+  size -= 250;    // -250 to avoid interrupt activity that's altered the stack.
209
+  if (size < 0) return;
207
 
210
 
208
-// how_many_E5s_are_here() is a utility function to easily find out how many 0xE5's are
209
-// at the specified location.  Having this logic as a function simplifies the search code.
210
-//
211
-int how_many_E5s_are_here(char* p) {
212
-  int n;
213
-  for (n = 0; n < 32000; n++) {
214
-    if (*(p + n) != (char)0xe5)
215
-      return n - 1;
211
+  ptr += 8;
212
+  memset(ptr, TEST_BYTE, size);
213
+
214
+  SERIAL_ECHO(size);
215
+  SERIAL_ECHOLNPGM(" bytes of memory initialized.\n");
216
+
217
+  for (uint16_t i = 0; i < size; i++) {
218
+    if (ptr[i] != TEST_BYTE) {
219
+      SERIAL_ECHOPAIR("? address : 0x", hex_word((uint16_t)ptr + i));
220
+      SERIAL_ECHOPAIR("=", hex_byte(ptr[i]));
221
+      SERIAL_EOL; SERIAL_EOL;
222
+    }
216
   }
223
   }
217
-  return -1;
218
 }
224
 }
219
 
225
 
226
+/**
227
+ * M100: Free Memory Check
228
+ */
229
+void gcode_M100() {
230
+  SERIAL_ECHOPAIR("\n__brkval : 0x", hex_word((uint16_t)__brkval));
231
+  SERIAL_ECHOPAIR("\n__bss_end : 0x", hex_word((uint16_t)&__bss_end));
220
 
232
 
221
-int free_memory_is_corrupted() {
222
-  char *sp, *ptr;
223
-  int block_cnt = 0, i, j, n;
233
+  char *ptr = END_OF_HEAP(), *sp = top_of_stack();
224
 
234
 
225
-    ptr = __brkval ? __brkval : &__bss_end;    
226
-    sp = top_of_stack();
235
+  SERIAL_ECHOPAIR("\nstart of free space : 0x", hex_word((uint16_t)ptr));
236
+  SERIAL_ECHOLNPAIR("\nStack Pointer : 0x", hex_word((uint16_t)sp));
227
 
237
 
228
-    n = sp - ptr;
238
+  // Always init on the first invocation of M100
239
+  static bool m100_not_initialized = true;
240
+  if (m100_not_initialized || code_seen('I')) {
241
+    m100_not_initialized = false;
242
+    init_free_memory(ptr, sp - ptr);
243
+  }
229
 
244
 
230
-    // Scan through the range looking for the biggest block of 0xE5's we can find
231
-    for (i = 0; i < n; i++) {
232
-      if (*(ptr + i) == (char)0xe5) {
233
-        j = how_many_E5s_are_here(ptr + i);
234
-        if (j > 8) {
235
-//        SERIAL_ECHOPAIR("Found ", j);
236
-//        SERIAL_ECHOLNPAIR(" bytes free at 0x", hex_word((uint16_t)(ptr + i)));
245
+  #if ENABLED(M100_FREE_MEMORY_DUMPER)
237
 
246
 
238
-          i += j;
239
-          block_cnt++;
240
-        }
241
-      }
242
-    }
247
+    if (code_seen('D'))
248
+      return dump_free_memory(ptr, sp);
243
 
249
 
244
-//  if (block_cnt > 1) {
245
-//    SERIAL_ECHOLNPGM("\nMemory Corruption detected in free memory area.");
246
-//   SERIAL_ECHOLNPAIR("\nLargest free block is ", max_cnt);
247
-//  }
248
-    return block_cnt;
249
-  }
250
+  #endif
250
 
251
 
251
-#endif
252
+  if (code_seen('F'))
253
+    return free_memory_pool_report(ptr, sp - ptr);
254
+
255
+  #if ENABLED(M100_FREE_MEMORY_CORRUPTOR)
256
+
257
+    if (code_seen('C'))
258
+      return corrupt_free_memory(ptr, code_value_int());
259
+
260
+  #endif
261
+}
252
 
262
 
263
+#endif // M100_FREE_MEMORY_WATCHER

+ 1
- 1
Marlin/hex_print_routines.cpp View File

43
   return _hex;
43
   return _hex;
44
 }
44
 }
45
 
45
 
46
-void print_hex_nybble(const uint8_t n) { SERIAL_CHAR(hex_nybble(n));  }
46
+void print_hex_nybble(const uint8_t n) { SERIAL_CHAR(hex_nybble(n)); }
47
 void print_hex_byte(const uint8_t b)   { SERIAL_ECHO(hex_byte(b)); }
47
 void print_hex_byte(const uint8_t b)   { SERIAL_ECHO(hex_byte(b)); }
48
 void print_hex_word(const uint16_t w)  { SERIAL_ECHO(hex_word(w)); }
48
 void print_hex_word(const uint16_t w)  { SERIAL_ECHO(hex_word(w)); }
49
 
49
 

+ 1
- 1
Marlin/hex_print_routines.h View File

42
 void print_hex_word(const uint16_t w);
42
 void print_hex_word(const uint16_t w);
43
 
43
 
44
 #endif // AUTO_BED_LEVELING_UBL || M100_FREE_MEMORY_WATCHER
44
 #endif // AUTO_BED_LEVELING_UBL || M100_FREE_MEMORY_WATCHER
45
-#endif // HEX_PRINT_ROUTINES_H
45
+#endif // HEX_PRINT_ROUTINES_H

Loading…
Cancel
Save