Skip to content

Commit 6e2168e

Browse files
committed
two more misc. scripts
1 parent c2c6ea5 commit 6e2168e

2 files changed

Lines changed: 301 additions & 0 deletions

File tree

misc/IntelHexValidator.py

Lines changed: 175 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,175 @@
1+
# -*- coding: utf-8 -*-
2+
'''
3+
IHEX_VALIDATOR calculates the checksum of a single intel hex formatted record
4+
'''
5+
6+
from Npp import notepad, editor, NOTIFICATION, SCINTILLANOTIFICATION, ANNOTATIONVISIBLE, MARGINTYPE
7+
import struct
8+
9+
# Record Format
10+
# :LLAAAATT[DD...]CC
11+
12+
# : is the colon that starts every Intel HEX record.
13+
# LL is the record-length field that represents the number of data bytes (dd) in the record.
14+
# AAAA is the address field that represents the starting address for subsequent data in the record.
15+
# TT is the field that represents the HEX record type, which may be one of the following:
16+
# 00 - data record
17+
# 01 - end-of-file record
18+
# 02 - extended segment address record
19+
# 04 - extended linear address record
20+
# 05 - start linear address record (MDK-ARM only)
21+
# DD is a data field that represents one byte of data. A record may have multiple data bytes.
22+
# The number of data bytes in the record must match the number specified by the ll field.
23+
# CC is the checksum field that represents the checksum of the record.
24+
# The checksum is calculated by summing the values of all hexadecimal digit pairs in
25+
# the record modulo 256 and taking the two's complement.
26+
#
27+
# example = :10246200464C5549442050524F46494C4500464C33
28+
#
29+
# : 10 2462 00 464C5549442050524F46494C4500464C 33
30+
# | || |||| || || CC->Checksum
31+
# | || |||| || DD->Data
32+
# | || |||| TT->Record Type
33+
# | || AAAA->Address
34+
# | LL->Record Length
35+
# :->Colon
36+
37+
38+
# testdata
39+
# :10001300AC12AD13AE10AF1112002F8E0E8F0F2244
40+
# :10000300E50B250DF509E50A350CF5081200132259
41+
# :03000000020023D8
42+
# :0C002300787FE4F6D8FD7581130200031D
43+
# :10002F00EFF88DF0A4FFEDC5F0CEA42EFEEC88F016
44+
# :04003F00A42EFE22CB
45+
# :00000001FF
46+
47+
48+
class IHEX_VALIDATOR:
49+
50+
def __init__(self):
51+
self.document_is_of_interest = False
52+
self.debug_mode = False
53+
self.ANON_STYLE = 20 # (0-18 reserved by ihex lexer)
54+
55+
editor.callbackSync(self.on_updateui, [SCINTILLANOTIFICATION.UPDATEUI])
56+
notepad.callback(self.on_langchanged, [NOTIFICATION.LANGCHANGED])
57+
notepad.callback(self.on_bufferactivated, [NOTIFICATION.BUFFERACTIVATED])
58+
59+
60+
def __set_annotation(self, line, text):
61+
'''
62+
Shows an annotated line under the caret line
63+
Args:
64+
line = integer, 0-based line number of the caret line
65+
text = string, text to be shown
66+
Returns:
67+
None
68+
'''
69+
70+
editor.styleSetFore(self.ANON_STYLE, (128,255,0))
71+
editor.styleSetBack(self.ANON_STYLE, notepad.getEditorDefaultBackgroundColor())
72+
editor.annotationSetVisible(ANNOTATIONVISIBLE.STANDARD)
73+
editor.annotationSetText(line, text)
74+
editor.annotationSetStyle(line, self.ANON_STYLE)
75+
76+
77+
def calculate_checksum(self):
78+
'''
79+
Calculates the checksum of the caret line
80+
Args:
81+
None
82+
Returns:
83+
None
84+
'''
85+
line = editor.getCurLine().strip()
86+
line_length = len(line)
87+
record_length = line_length-1
88+
if line.startswith(':') and line_length > 10 and (record_length % 2 == 0):
89+
if record_length == int(line[1:3],16) *2 + 8:
90+
length_assumed = True
91+
x = line[1:].decode('hex')
92+
else:
93+
length_assumed = False
94+
x = line[1:-2].decode('hex')
95+
total = sum(struct.unpack('<' + 'B'*len(x), x))
96+
int_checksum = ~total & 0xFF
97+
checksum = format(0 if int_checksum == 0xFF else int_checksum+1, '02X')
98+
if self.debug_mode:
99+
print('calculated checksum is {}'.format(checksum))
100+
if checksum != line[-2:]:
101+
self.__set_annotation(editor.lineFromPosition(editor.getCurrentPos()),
102+
'{}{}'.format(' '*line_length if length_assumed else ' '*(line_length-2),
103+
checksum))
104+
else:
105+
editor.annotationClearAll()
106+
107+
108+
def check_lexer(self):
109+
'''
110+
Checks if the current document is of interest
111+
and sets the flag accordingly
112+
Args:
113+
None
114+
Returns:
115+
None
116+
'''
117+
self.document_is_of_interest = notepad.getLanguageName(notepad.getLangType()) == 'Intel HEX'
118+
if self.debug_mode:
119+
print('document is of interest:{}'.format(self.document_is_of_interest))
120+
121+
122+
def on_bufferactivated(self, args):
123+
'''
124+
Callback which gets called every time one switches a document.
125+
Triggers the check if the document is of interest.
126+
Args:
127+
provided by notepad object but none are of interest
128+
Returns:
129+
None
130+
'''
131+
self.check_lexer()
132+
133+
134+
def on_updateui(self, args):
135+
'''
136+
Callback which gets called every time scintilla
137+
(aka the editor) changed something within the document.
138+
Triggers the styling function if the document is of interest.
139+
Args:
140+
provided by scintilla but none are of interest
141+
Returns:
142+
None
143+
'''
144+
if self.document_is_of_interest:
145+
self.calculate_checksum()
146+
147+
148+
def on_langchanged(self, args):
149+
'''
150+
Callback gets called every time one uses the Language menu to set a lexer
151+
Triggers the check if the document is of interest
152+
Args:
153+
provided by notepad object but none are of interest
154+
Returns:
155+
None
156+
'''
157+
self.check_lexer()
158+
159+
160+
def main(self):
161+
'''
162+
Main function entry point.
163+
Simulates two events to enforce detection of current document
164+
and potential validating.
165+
Args:
166+
None
167+
Returns:
168+
None
169+
'''
170+
self.on_bufferactivated(None)
171+
self.on_updateui(None)
172+
173+
174+
IHEX_VALIDATOR().main()
175+

misc/TreeNodeCalculator.py

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
# -*- coding: utf-8 -*-
2+
'''
3+
TreeNodeCalculator scans a tree-like text and sums up the items.
4+
The folder-like lines are not counted.
5+
Number of items is added on position 80 on each folder-like line.
6+
It is assumed that the data is
7+
a) using either space or tabs doing the intend but NOT mixed ones
8+
b) one root node in a document
9+
c) items are only in the last level and NOT in between.
10+
'''
11+
from Npp import editor
12+
13+
# example test data
14+
# root
15+
# level1
16+
# item1
17+
# item2
18+
# level1
19+
# level2
20+
# item3
21+
# item4
22+
# level2
23+
# level3
24+
# item5
25+
# item6
26+
# level1
27+
# item7
28+
# item8
29+
30+
# would be modified to
31+
32+
# root 8
33+
# level1 2
34+
# item1
35+
# item2
36+
# level1 4
37+
# level2 2
38+
# item3
39+
# item4
40+
# level2 2
41+
# level3 2
42+
# item5
43+
# item6
44+
# level1 2
45+
# item7
46+
# item8
47+
48+
class Node:
49+
'''
50+
helper class which counts the items and updates the parents recursively.
51+
'''
52+
def __init__(self, line, parent=None):
53+
'''
54+
store on which line the parent is and initialze the object itself
55+
'''
56+
self.line = line
57+
self.parent = parent
58+
self.items = 0
59+
60+
def add(self):
61+
'''
62+
add the current found item and call its parents recursively
63+
'''
64+
if self.parent:
65+
self.parent.add()
66+
self.items += 1
67+
68+
def result(self):
69+
'''
70+
return the calculated items for each parent together with the parent line
71+
'''
72+
if self.parent:
73+
self.parent.result()
74+
return self.line, self.items
75+
76+
77+
# Calculate the level
78+
def get_level(line): return len(line) - len(line.lstrip())
79+
80+
81+
lines = editor.getText().splitlines()
82+
max_lines = len(lines)-1
83+
current_line = 0
84+
level_stack = []
85+
save_popped_levels = []
86+
87+
# loop through all lines and build the needed Node objects
88+
while current_line < max_lines:
89+
if lines[current_line].strip() != '':
90+
current_level = get_level(lines[current_line])
91+
92+
if current_level >= get_level(lines[current_line+1]):
93+
level_stack[-1][0].add()
94+
else:
95+
if current_level == 0:
96+
level_stack = []
97+
p = Node(current_line, None)
98+
else:
99+
while True:
100+
if level_stack[-1][1] >= current_level:
101+
save_popped_levels.append(level_stack.pop())
102+
else:
103+
break
104+
p = Node(current_line, level_stack[-1][0])
105+
106+
level_stack.append((p, current_level))
107+
108+
current_line +=1
109+
110+
# last line
111+
prev_level = current_level
112+
if lines[current_line].strip() != '':
113+
if prev_level == get_level(lines[current_line]):
114+
level_stack[-1][0].add()
115+
116+
# create a list of all Node objects
117+
results = [x[0].result() for x in level_stack]
118+
results.extend([x[0].result() for x in save_popped_levels])
119+
120+
# reformat the resulting content
121+
for line, _sum in sorted(results):
122+
lines[line] = '{0:<{1}}{2}'.format(lines[line][:80],
123+
80,
124+
_sum)
125+
# set the new content
126+
editor.setText('\r\n'.join(lines))

0 commit comments

Comments
 (0)