Skip to content
GitLab
Explore
Sign in
Register
Primary navigation
Search or go to…
Project
M
marlin-anet-a8
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Wiki
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Build
Pipelines
Jobs
Pipeline schedules
Artifacts
Deploy
Releases
Package registry
Container registry
Model registry
Operate
Environments
Terraform modules
Monitor
Incidents
Service Desk
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
GitLab community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
Jonas Leder
marlin-anet-a8
Commits
03aa9a39
Commit
03aa9a39
authored
Apr 11, 2017
by
Scott Lahteine
Browse files
Options
Downloads
Patches
Plain Diff
Apply coding standards to M100, break up into functions
parent
ba85faab
Branches
Branches containing commit
Tags
2.0.0
Tags containing commit
No related merge requests found
Changes
3
Show whitespace changes
Inline
Side-by-side
Showing
3 changed files
Marlin/M100_Free_Mem_Chk.cpp
+196
-185
196 additions, 185 deletions
Marlin/M100_Free_Mem_Chk.cpp
Marlin/hex_print_routines.cpp
+1
-1
1 addition, 1 deletion
Marlin/hex_print_routines.cpp
Marlin/hex_print_routines.h
+1
-1
1 addition, 1 deletion
Marlin/hex_print_routines.h
with
198 additions
and
187 deletions
Marlin/M100_Free_Mem_Chk.cpp
+
196
−
185
View file @
03aa9a39
...
...
@@ -27,112 +27,140 @@
* This memory block is initialized and watched via the M100 command.
*
* M100 I Initializes the free memory block and prints vitals statistics about the area
*
* M100 F Identifies how much of the free memory block remains free and unused. It also
* detects and reports any corruption within the free memory block that may have
* happened due to errant firmware.
*
* M100 D Does a hex display of the free memory block along with a flag for any errant
* data that does not match the expected value.
*
* M100 C x Corrupts x locations within the free memory block. This is useful to check the
* correctness of the M100 F and M100 D commands.
*
* Initial version by Roxy-3D
*/
#define M100_FREE_MEMORY_DUMPER //
Comment out to remove
Dump sub-command
#define M100_FREE_MEMORY_CORRUPTOR
//
Comment out to remove
Corrupt sub-command
#define M100_FREE_MEMORY_DUMPER //
Enable for the `M110 D`
Dump sub-command
#define M100_FREE_MEMORY_CORRUPTOR //
Enable for the `M100 C`
Corrupt sub-command
#include
"Marlin.h"
#include
"Marlin
Config
.h"
#if ENABLED(M100_FREE_MEMORY_WATCHER)
#define TEST_BYTE 0xE5
extern
char
*
__brkval
;
extern
size_t
__heap_start
,
__heap_end
,
__flp
;
extern
char
__bss_end
;
//
// Utility functions used by M100 to get its work done.
//
#include
"Marlin.h"
#include
"hex_print_routines.h"
char
*
top_of_stack
();
int
how_many_E5s_are_here
(
char
*
);
int
free_memory_is_corrupted
();
// int not bool!!!! it will tell us how many blocks of
// free memory it found.
void
gcode_M100
()
{
static
bool
m100_not_initialized
=
true
;
char
*
sp
,
*
ptr
;
int
i
,
j
,
n
;
//
// M100 D dumps the free memory block from __brkval to the stack pointer.
// malloc() eats memory from the start of the block and the stack grows
// up from the bottom of the block. Solid 0xE5's indicate nothing has
// used that memory yet. There should not be anything but 0xE5's within
// the block of 0xE5's. If there is, that would indicate memory corruption
// probably caused by bad pointers. Any unexpected values will be flagged in
// the right hand column to help spotting them.
// Utility functions
//
SERIAL_ECHOPAIR
(
"
\n
__brkval : 0x"
,
hex_word
((
uint16_t
)
__brkval
)
);
SERIAL_ECHOPAIR
(
"
\n
__bss_end : 0x"
,
hex_word
((
uint16_t
)
&
__bss_end
));
//
// With out malloc() we need to be smart and use &__bss_end
//
ptr
=
__brkval
?
__brkval
:
&
__bss_end
;
SERIAL_ECHOPAIR
(
"
\n
start of free space : 0x"
,
hex_word
((
uint16_t
)
ptr
));
sp
=
top_of_stack
();
SERIAL_ECHOLNPAIR
(
"
\n
Stack Pointer : 0x"
,
hex_word
((
uint16_t
)
sp
));
#define END_OF_HEAP() (__brkval ? __brkval : &__bss_end)
// Location of a variable on its stack frame. Returns a value above
// the stack (once the function returns to the caller).
char
*
top_of_stack
()
{
char
x
;
return
&
x
+
1
;
// x is pulled on return;
}
// Count the number of test bytes at the specified location.
int16_t
count_test_bytes
(
const
char
*
const
ptr
)
{
for
(
uint16_t
i
=
0
;
i
<
32000
;
i
++
)
if
(
ptr
[
i
]
!=
TEST_BYTE
)
return
i
-
1
;
return
-
1
;
}
// Return a count of free memory blocks.
uint16_t
free_memory_is_corrupted
(
char
*
const
ptr
,
const
uint16_t
size
)
{
// Find the longest block of test bytes in the given buffer
uint16_t
block_cnt
=
0
;
for
(
uint16_t
i
=
0
;
i
<
size
;
i
++
)
{
if
(
ptr
[
i
]
==
TEST_BYTE
)
{
const
uint16_t
j
=
count_test_bytes
(
ptr
+
i
);
if
(
j
>
8
)
{
//SERIAL_ECHOPAIR("Found ", j);
//SERIAL_ECHOLNPAIR(" bytes free at 0x", hex_word((uint16_t)ptr + i));
i
+=
j
;
block_cnt
++
;
}
}
}
//if (block_cnt > 1) {
// SERIAL_ECHOLNPGM("\nMemory Corruption detected in free memory area.");
// SERIAL_ECHOLNPAIR("\nLargest free block is ", max_cnt);
//}
return
block_cnt
;
}
#if ENABLED(M100_FREE_MEMORY_DUMPER) // Disable to remove Dump sub-command
if
(
code_seen
(
'D'
))
{
//
// We want to start and end the dump on a nice 16 byte boundry even though
// the values we are using are not 16 byte aligned.
// M100 sub-commands
//
ptr
=
(
char
*
)
((
uint16_t
)
ptr
&
0xfff0
);
sp
=
(
char
*
)
((
uint16_t
)
sp
|
0x000f
);
n
=
sp
-
ptr
;
#if ENABLED(M100_FREE_MEMORY_DUMPER)
/**
* M100 D
* Dump the free memory block from __brkval to the stack pointer.
* malloc() eats memory from the start of the block and the stack grows
* up from the bottom of the block. Solid test bytes indicate nothing has
* used that memory yet. There should not be anything but test bytes within
* the block. If so, it may indicate memory corruption due to a bad pointer.
* Unexpected bytes are flagged in the right column.
*/
void
dump_free_memory
(
char
*
ptr
,
char
*
sp
)
{
//
// This is the main loop of the Dump command.
// Start and end the dump on a nice 16 byte boundary
// (even though the values are not 16-byte aligned).
//
ptr
=
(
char
*
)((
uint16_t
)
ptr
&
0xFFF0
);
// Align to 16-byte boundary
sp
=
(
char
*
)((
uint16_t
)
sp
|
0x000F
);
// Align sp to the 15th byte (at or above sp)
// Dump command main loop
while
(
ptr
<
sp
)
{
print_hex_word
((
uint16_t
)
ptr
);
// Print the address
SERIAL_CHAR
(
':'
);
for
(
i
=
0
;
i
<
16
;
i
++
)
{
// and 16 data bytes
if
(
i
==
8
)
SERIAL_CHAR
(
'-'
);
print_hex_byte
(
*
(
ptr
+
i
));
for
(
uint8_t
i
=
0
;
i
<
16
;
i
++
)
{
// and 16 data bytes
if
(
i
==
8
)
SERIAL_CHAR
(
'-'
);
print_hex_byte
(
ptr
[
i
]);
SERIAL_CHAR
(
' '
);
}
SERIAL_CHAR
(
'|'
);
// now show where non 0xE5's are
for
(
i
=
0
;
i
<
16
;
i
++
)
SERIAL_CHAR
(
(
*
(
ptr
+
i
)
==
(
char
)
0xe5
)
?
' '
:
'?'
);
SERIAL_CHAR
(
'|'
);
// Point out non test bytes
for
(
uint8_t
i
=
0
;
i
<
16
;
i
++
)
SERIAL_CHAR
(
ptr
[
i
]
==
TEST_BYTE
?
' '
:
'?'
);
SERIAL_EOL
;
ptr
+=
16
;
idle
();
}
return
;
}
#endif
//
// M100 F requests the code to return the number of free bytes in the memory pool along with
// other vital statistics that define the memory pool.
//
if
(
code_seen
(
'F'
))
{
int
max_cnt
=
-
1
,
block_cnt
=
0
;
uint16_t
max_addr
=
0
;
ptr
=
__brkval
?
__brkval
:
&
__bss_end
;
sp
=
top_of_stack
();
n
=
sp
-
ptr
;
// Scan through the range looking for the biggest block of 0xE5's we can find
for
(
i
=
0
;
i
<
n
;
i
++
)
{
if
(
*
(
ptr
+
i
)
==
(
char
)
0xe5
)
{
j
=
how_many_E5s_are_here
(
ptr
+
i
);
#endif // M100_FREE_MEMORY_DUMPER
/**
* M100 F
* Return the number of free bytes in the memory pool,
* with other vital statistics defining the pool.
*/
void
free_memory_pool_report
(
const
char
*
const
ptr
,
const
uint16_t
size
)
{
int16_t
max_cnt
=
-
1
;
uint16_t
block_cnt
=
0
;
char
*
max_addr
=
NULL
;
// Find the longest block of test bytes in the buffer
for
(
uint16_t
i
=
0
;
i
<
size
;
i
++
)
{
char
*
const
addr
=
ptr
+
i
;
if
(
*
addr
==
TEST_BYTE
)
{
const
uint16_t
j
=
count_test_bytes
(
addr
);
if
(
j
>
8
)
{
SERIAL_ECHOPAIR
(
"Found "
,
j
);
SERIAL_ECHOLNPAIR
(
" bytes free at 0x"
,
hex_word
((
uint16_t
)
(
ptr
+
i
)
));
SERIAL_ECHOLNPAIR
(
" bytes free at 0x"
,
hex_word
((
uint16_t
)
addr
));
if
(
j
>
max_cnt
)
{
max_cnt
=
j
;
max_addr
=
(
uint16_t
)
ptr
+
i
;
max_addr
=
addr
;
}
i
+=
j
;
block_cnt
++
;
...
...
@@ -142,111 +170,94 @@ void gcode_M100() {
if
(
block_cnt
>
1
)
{
SERIAL_ECHOLNPGM
(
"
\n
Memory Corruption detected in free memory area."
);
SERIAL_ECHOPAIR
(
"
\n
Largest free block is "
,
max_cnt
);
SERIAL_ECHOLNPAIR
(
" bytes
big
at 0x"
,
hex_word
(
max_addr
));
SERIAL_ECHOLNPAIR
(
" bytes at 0x"
,
hex_word
(
(
uint16_t
)
max_addr
));
}
SERIAL_ECHOLNPAIR
(
"free_memory_is_corrupted() = "
,
free_memory_is_corrupted
());
return
;
SERIAL_ECHOLNPAIR
(
"free_memory_is_corrupted() = "
,
free_memory_is_corrupted
(
ptr
,
size
));
}
//
// M100 C x Corrupts x locations in the free memory pool and reports the locations of the corruption.
// This is useful to check the correctness of the M100 D and the M100 F commands.
//
#if ENABLED(M100_FREE_MEMORY_CORRUPTOR)
/**
* M100 C<num>
* Corrupt <num> locations in the free memory pool and report the corrupt addresses.
* This is useful to check the correctness of the M100 D and the M100 F commands.
*/
void
corrupt_free_memory
(
char
*
ptr
,
const
uint16_t
size
)
{
if
(
code_seen
(
'C'
))
{
int
x
=
code_value_int
();
// x gets the # of locations to corrupt within the memory pool
SERIAL_ECHOLNPGM
(
"Corrupting free memory block.
\n
"
);
ptr
+=
8
;
sp
=
top_of_stack
();
n
=
sp
-
ptr
-
250
;
// -250 just to keep us from finding interrupt activity that
// has altered the stack.
j
=
n
/
(
x
+
1
);
for
(
i
=
1
;
i
<=
x
;
i
++
)
{
*
(
ptr
+
(
i
*
j
))
=
i
;
SERIAL_ECHOPAIR
(
"
\n
Corrupting address: 0x"
,
hex_word
((
uint16_t
)(
ptr
+
i
*
j
)));
const
uint16_t
near_top
=
top_of_stack
()
-
ptr
-
250
,
// -250 to avoid interrupt activity that's altered the stack.
j
=
near_top
/
(
size
+
1
);
SERIAL_ECHOLNPGM
(
"Corrupting free memory block.
\n
"
);
for
(
uint16_t
i
=
1
;
i
<=
size
;
i
++
)
{
char
*
const
addr
=
ptr
+
i
*
j
;
*
addr
=
i
;
SERIAL_ECHOPAIR
(
"
\n
Corrupting address: 0x"
,
hex_word
((
uint16_t
)
addr
));
}
SERIAL_ECHOLNPGM
(
"
\n
"
);
return
;
SERIAL_EOL
;
}
#endif
//
// M100 I Initializes the free memory pool so it can be watched and prints vital
// statistics that define the free memory pool.
//
if
(
m100_not_initialized
||
code_seen
(
'I'
))
{
// If no sub-command is specified, the first time
SERIAL_ECHOLNPGM
(
"Initializing free memory block.
\n
"
);
// this happens, it will Initialize.
// Repeated M100 with no sub-command will not destroy the
// state of the initialized free memory pool.
}
#endif // M100_FREE_MEMORY_CORRUPTOR
/**
* M100 I
* Init memory for the M100 tests. (Automatically applied on the first M100.)
*/
void
init_free_memory
(
char
*
ptr
,
int16_t
size
)
{
SERIAL_ECHOLNPGM
(
"Initializing free memory block.
\n\n
"
);
size
-=
250
;
// -250 to avoid interrupt activity that's altered the stack.
if
(
size
<
0
)
return
;
ptr
+=
8
;
SERIAL_ECHOLNPGM
(
"
\n
"
);
n
=
sp
-
ptr
-
250
;
// -250 just to keep us from finding interrupt activity that
// has altered the stack.
SERIAL_ECHO
(
n
);
memset
(
ptr
,
TEST_BYTE
,
size
);
SERIAL_ECHO
(
size
);
SERIAL_ECHOLNPGM
(
" bytes of memory initialized.
\n
"
);
for
(
i
=
0
;
i
<
n
;
i
++
)
*
(
ptr
+
i
)
=
(
char
)
0xe5
;
for
(
i
=
0
;
i
<
n
;
i
++
)
{
if
(
*
(
ptr
+
i
)
!=
(
char
)
0xe5
)
{
SERIAL_ECHOPAIR
(
"? address : "
,
hex_word
(
ptr
+
i
)
);
SERIAL_ECHOPAIR
(
"="
,
hex_byte
(
*
(
ptr
+
i
))
);
SERIAL_ECHOLNPGM
(
"
\n
"
);
for
(
uint16_t
i
=
0
;
i
<
size
;
i
++
)
{
if
(
ptr
[
i
]
!=
TEST_BYTE
)
{
SERIAL_ECHOPAIR
(
"? address : 0x"
,
hex_word
((
uint16_t
)
ptr
+
i
));
SERIAL_ECHOPAIR
(
"="
,
hex_byte
(
ptr
[
i
]));
SERIAL_EOL
;
SERIAL_EOL
;
}
}
m100_not_initialized
=
false
;
return
;
}
return
;
}
// top_of_stack() returns the location of a variable on its stack frame. The value returned is above
// the stack once the function returns to the caller.
/**
* M100: Free Memory Check
*/
void
gcode_M100
()
{
SERIAL_ECHOPAIR
(
"
\n
__brkval : 0x"
,
hex_word
((
uint16_t
)
__brkval
));
SERIAL_ECHOPAIR
(
"
\n
__bss_end : 0x"
,
hex_word
((
uint16_t
)
&
__bss_end
));
char
*
top_of_stack
()
{
char
x
;
return
&
x
+
1
;
// x is pulled on return;
}
char
*
ptr
=
END_OF_HEAP
(),
*
sp
=
top_of_stack
();
// how_many_E5s_are_here() is a utility function to easily find out how many 0xE5's are
// at the specified location. Having this logic as a function simplifies the search code.
//
int
how_many_E5s_are_here
(
char
*
p
)
{
int
n
;
for
(
n
=
0
;
n
<
32000
;
n
++
)
{
if
(
*
(
p
+
n
)
!=
(
char
)
0xe5
)
return
n
-
1
;
}
return
-
1
;
}
SERIAL_ECHOPAIR
(
"
\n
start of free space : 0x"
,
hex_word
((
uint16_t
)
ptr
));
SERIAL_ECHOLNPAIR
(
"
\n
Stack Pointer : 0x"
,
hex_word
((
uint16_t
)
sp
));
// Always init on the first invocation of M100
static
bool
m100_not_initialized
=
true
;
if
(
m100_not_initialized
||
code_seen
(
'I'
))
{
m100_not_initialized
=
false
;
init_free_memory
(
ptr
,
sp
-
ptr
);
}
int
free_memory_is_corrupted
()
{
char
*
sp
,
*
ptr
;
int
block_cnt
=
0
,
i
,
j
,
n
;
#if ENABLED(M100_FREE_MEMORY_DUMPER)
ptr
=
__brkval
?
__brkval
:
&
__bss_end
;
sp
=
top_of_stack
(
);
if
(
code_seen
(
'D'
))
return
dump_free_memory
(
ptr
,
sp
);
n
=
sp
-
ptr
;
#endif
// Scan through the range looking for the biggest block of 0xE5's we can find
for
(
i
=
0
;
i
<
n
;
i
++
)
{
if
(
*
(
ptr
+
i
)
==
(
char
)
0xe5
)
{
j
=
how_many_E5s_are_here
(
ptr
+
i
);
if
(
j
>
8
)
{
// SERIAL_ECHOPAIR("Found ", j);
// SERIAL_ECHOLNPAIR(" bytes free at 0x", hex_word((uint16_t)(ptr + i)));
if
(
code_seen
(
'F'
))
return
free_memory_pool_report
(
ptr
,
sp
-
ptr
);
i
+=
j
;
block_cnt
++
;
}
}
}
#if ENABLED(M100_FREE_MEMORY_CORRUPTOR)
// if (block_cnt > 1) {
// SERIAL_ECHOLNPGM("\nMemory Corruption detected in free memory area.");
// SERIAL_ECHOLNPAIR("\nLargest free block is ", max_cnt);
// }
return
block_cnt
;
}
if
(
code_seen
(
'C'
))
return
corrupt_free_memory
(
ptr
,
code_value_int
());
#endif
}
#endif // M100_FREE_MEMORY_WATCHER
This diff is collapsed.
Click to expand it.
Marlin/hex_print_routines.cpp
+
1
−
1
View file @
03aa9a39
This diff is collapsed.
Click to expand it.
Marlin/hex_print_routines.h
+
1
−
1
View file @
03aa9a39
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment