11import re
2+ from math import log2
23from functools import partial
34from pandas import DataFrame , Series
45from typing import Iterable , Callable , Union
5- from harp .model import BitMask , GroupMask , MaskValueItem , Model , Register
6+ from harp .model import BitMask , GroupMask , MaskValueItem , Model , PayloadMember , Register
67from harp .io import read
78
89_camel_to_snake_regex = re .compile (r"(?<!^)(?=[A-Z])" )
@@ -40,10 +41,6 @@ def _id_camel_to_snake(id: str):
4041 return _camel_to_snake_regex .sub ("_" , id ).lower ()
4142
4243
43- def _keys_camel_to_snake (keys : Iterable [str ]):
44- return [_id_camel_to_snake (k ) for k in keys ]
45-
46-
4744def _create_bit_parser (mask : Union [int , MaskValueItem ]):
4845 def parser (xs : Series ) -> Series :
4946 return (xs & mask ) != 0
@@ -63,12 +60,55 @@ def parser(df: DataFrame):
6360 return parser
6461
6562
63+ def _create_groupmask_lookup (groupMask : GroupMask ):
64+ return {v .root : n for n , v in groupMask .values .items ()}
65+
66+
6667def _create_groupmask_parser (name : str , groupMask : GroupMask ):
67- name = _id_camel_to_snake (name )
68- lookup = {v .root : n for n , v in groupMask .values .items ()}
68+ lookup = _create_groupmask_lookup (groupMask )
6969
7070 def parser (df : DataFrame ):
71- return DataFrame ({name : df .map (lambda x : lookup [x ])})
71+ return DataFrame ({name : df [0 ].map (lookup )})
72+
73+ return parser
74+
75+
76+ def _mask_shift (mask : int ):
77+ lsb = mask & (~ mask + 1 )
78+ return int (log2 (lsb ))
79+
80+
81+ def _create_payloadmember_parser (device : Model , member : PayloadMember ):
82+ offset = member .offset
83+ if offset is None :
84+ offset = 0
85+
86+ shift = None
87+ if member .mask is not None :
88+ shift = _mask_shift (member .mask )
89+
90+ lookup = None
91+ if member .maskType is not None :
92+ key = member .maskType .root
93+ groupMask = device .groupMasks .get (key )
94+ if groupMask is not None :
95+ lookup = _create_groupmask_lookup (groupMask )
96+
97+ is_boolean = False
98+ if member .interfaceType is not None :
99+ is_boolean = member .interfaceType .root == "bool"
100+
101+ def parser (df : DataFrame ):
102+ series = df [offset ]
103+ if member .mask is not None :
104+ series = series & member .mask
105+ if shift > 0 :
106+ series = Series (series .values >> shift , series .index )
107+ if is_boolean :
108+ series = series != 0
109+ elif lookup is not None :
110+ series = series .map (lookup )
111+ return series
72112
73113 return parser
74114
@@ -92,9 +132,15 @@ def _create_register_reader(device: Model, name: str):
92132 return RegisterReader (register , reader )
93133
94134 if register .payloadSpec is not None :
95- columns = register .payloadSpec .keys ()
96- columns = _keys_camel_to_snake (columns )
97- reader = partial (reader , columns = columns )
135+ payload_parsers = [
136+ (_id_camel_to_snake (key ), _create_payloadmember_parser (device , member ))
137+ for key , member in register .payloadSpec .items ()
138+ ]
139+
140+ def parser (df : DataFrame ):
141+ return DataFrame ({n : f (df ) for n , f in payload_parsers }, index = df .index )
142+
143+ reader = _compose (parser , reader )
98144 return RegisterReader (register , reader )
99145
100146 columns = [_id_camel_to_snake (name )]
0 commit comments