Changing Only Certain Bits in Byte in Python - python

I'm working with a PCF8574 and I have a set of configurations that I need to send to the device. I have communication working and I'm using an I2C write_byte command. In the table below if a cell doesn't have a value then it's state should not be changed.
I know it's a bit manipulation "game" to get the combination of operators correct but I'm not having luck so far finding the right combination to yield what I want.
As an example, when the PCF8574 is powered up it's default state is 0b11111111. If I want to change to state 'B' (0bxxx10x1x, where x means don't change) what function could I create which would set the part to correctly be 0b11110111?
My current test solution isn't the way I think it should be implemented but it seems to work:
from smbus2 import SMBus
i2c_port_num = 1
pcfAddress = 0x38
pcfBits = 'xxx00xxx'
curSetting = i2cBus.read_byte(pcfAddress)
def checkBit(newSetting, bits):
for i in range(0, len(bits)):
if(bits[i]) != 'x':
print("position", i, "is", bits[i])
if int(bits[i]) == 0:
newSetting &=~(1<<i)
elif int(bits[i]) == 1:
newSetting |= (1<<i)
return(newSetting)
changeState = checkBit(curSetting, pcfBits)
i2cBus.write_byte(pcfAddress, changeState)

Related

Infer ip subnet using bit operations? [duplicate]

I'm working with the ipaddress module in Python and trying to figure out a way of calculating the next available subnet (of either the same prefix or a different prefix) that doesn't overlap the existing subnet (the new subnet MUST be greater than the old one).
Lets say I start with network:
from ipaddress import IPv4Network
# From 10.90.1.0 to 10.90.1.31
main_net = IPv4Network("10.90.1.0/27")
I know the next available address is going to be 10.90.1.32, I can even figure this out quite easily by doing:
next_ip = main_net.broadcast_address + 1
# will output 10.90.1.32
print(next_ip)
If I wanted to find the next /27, I just create a new network like so:
# From 10.90.1.32 to 10.90.1.63
new_net = IPv4Network(f"{next_ip}/27")
This is all very straightforward so far, but now what if the next subnet I am looking for is a /26 or a /28 - how can I find the next minimum start IP address for either of these cases in Python?
I have explored using the supernet method, for example I could do something like this:
# Will print 10.90.1.0/26
print(main_net.supernet(new_prefix=27))
The problem with this method is that it will print 10.90.1.0/26 which overlaps the existing 10.90.1.0/27 network, I could make a loop and get it to keep generated the next /26 until they stop overlapping, but it seems inefficient to me. Surely, there is a better way?
Thanks to the help of Ron Maupin's helpful comment leading to a useful guide, I have managed to make a function that does this. I still want to test it a bit more but believe it is correct:
def calculate_next_ip_network(ip_bytes, current_prefix, next_prefix):
next_prefix_mask = (~((1 << (32 - next_prefix)) - 1)) & 0xFFFFFFFF
if next_prefix <= current_prefix:
bit_shift = 32 - next_prefix
else:
bit_shift = 32 - current_prefix
new_ip = (((next_prefix_mask & ip_bytes) >> bit_shift) + 1) << bit_shift
return bytes([new_ip >> i & 0xFF for i in (24, 16, 8, 0)])
Usage:
nt = IPv4Network("10.90.1.56/29")
current_prefix = nt.prefixlen
next_prefix = 25
ip_bytes = int.from_bytes(nt.network_address.packed, byteorder="big")
next_ip = calculate_next_ip_network(ip_bytes, current_prefix, next_prefix)
print(IPv4Address(next_ip))
# Should print "10.90.1.128"

Maya python connect to multiple input

I’m really sorry if I’m asking a question that’s been already answered but I couldn’t find an answer.
I’m writing a code that would allow me to connect a translate of several controllers into a blendWeighted node input channels. The amount of the controllers may vary depending on the selection. I’m struggling with the part where they need to connect to a single blendWeighted node input. Could someone tell me how I could connect every new controller to the next input channel of the blendWeighted node?
I’m sorry if my code is a bit childlike, I’m still learning ^^;
sel = mc.ls(sl=True, fl=True)
drvConnect = []
for i in sel:
name = i.split('_Crv')[0]
dGP = mc.createNode('transform', n='%s_Drv'%name, p=i)
drvConnect.append(dGP)
sh = mc.listRelatives(i, shapes=True)[0]
blendX = mc.createNode('blendWeighted', n='%s_X'%name)
blendY = mc.createNode('blendWeighted', n='%s_Y'%name)
blendZ = mc.createNode('blendWeighted', n='%s_Z'%name)
mc.connectAttr(dGP + '.translateX', blendX +'.input')
mc.connectAttr(dGP + '.translateY', blendY +'.input')
mc.connectAttr(dGP + '.translateZ', blendZ +'.input')
I assume you only want to create a single blendWeighted node. If that's the case, consider that the blendWeighted node's input attribute is an array attribute, so if you want to connect multiple items to it you would need to specify the target index.
For example, to connect the three translate outputs of a node to the first three inputs of the blend node you would use something like this:
mc.connectAttr('ctrl.translateX', 'blend.input[0]')
mc.connectAttr('ctrl.translateY', 'blend.input[1]')
mc.connectAttr('ctrl.translateZ', 'blend.input[2]')
(Maya will take care of creating the items in the array)
In our case you could simply keep a counter of the added items while you loop through the selection and the transform components (just a guide - not tested):
sel = mc.ls(sl=True, fl=True)
drvConnect = []
blendNode = mc.createNode('blendWeighted', n='blend_main')
for i in sel:
name = i.split('_Crv')[0]
dGP = mc.createNode('transform', n='%s_Drv'%name, p=i)
drvConnect.append(dGP)
for comp in ('X', 'Y', 'Z'):
mc.connectAttr(
'{}.translate{}'.format(dGP, comp),
'{}.input[{}]'.format(blendNode, blendIndex))
blendIndex += 1

Error building bitstring in python 3.5 : the datatype is being set to U32 without my control

I'm using a function to build an array of strings (which happens to be 0s and 1s only), which are rather large. The function works when I am building smaller strings, but somehow the data type seems to be restricting the size of the string to 32 characters long (U32), without my having asked for it. Am I missing something simple?
As I build the strings, I am first casting them as lists so as to more easily manipulate individual characters before joining them into a string again. Am I somehow limiting my ability to use 'larger' data types by my method? The value of np.max(CM1) in this case is something like ~300 (one recent run yielded 253), but the string only come out 32 characters long...
''' Function to derive genome and count mutations in provided list of cells '''
def derive_genome_biopsy(biopsy_list, family_dict, CM1):
derived_genomes_inBx = np.zeros(len(biopsy_list)).astype(str)
for position, cell in np.ndenumerate(biopsy_list):
if cell == 0: continue
temp_parent = 2
bitstring = list('1')
bitstring += (np.max(CM1)-1)*'0'
if cell == 1:
derived_genomes_inBx[position] = ''.join(bitstring)
continue
else:
while temp_parent > 1:
temp_parent = family_dict[cell]
bitstring[cell-1] = '1'
if temp_parent == 1: break
cell = family_dict[cell]
derived_genomes_inBx[position] = ''.join(bitstring)
return derived_genomes_inBx
The specific error message I get is:
Traceback (most recent call last):
File "biopsyCA.py", line 77, in <module>
if genome[site] == '1':
IndexError: string index out of range
family_dict is a dictionary which carries a list of parents and children that the algorithm above works through to reconstruct the 'genome' of individuals from the branching family tree. it basically sets positions in the bitstring to '1' if your parent had it, then if your grandparent etc... until you get to the first bit, which is always '1', then it should be done.
The 32 character limitation comes from the conversion of float64 array to string array in this line:
derived_genomes_inBx = np.zeros(len(biopsy_list)).astype(str)
The resulting array contains datatype S32 values which limit the contents to 32 characters.
To change this limit, use 'S300' or larger instead of str.
You may also use map(str, np.zeros(len(biopsy_list)) to get more flexible string list and convert it back to numpy array with numpy.array() after you have populated it.
Thanks to help from a number of folks here and local, I finally got this working and the working function is:
''' Function to derive genome and count mutations in provided list of cells '''
def derive_genome_biopsy(biopsy_list, family_dict, CM1):
derived_genomes_inBx = list(map(str, np.zeros(len(biopsy_list))))
for biopsy in range(0,len(biopsy_list)):
if biopsy_list[biopsy] == 0:
bitstring = (np.max(CM1))*'0'
derived_genomes_inBx[biopsy] = ''.join(bitstring)
continue
bitstring = list('1')
bitstring += (np.max(CM1)-1)*'0'
if biopsy_list[biopsy] == 1:
derived_genomes_inBx[biopsy] = ''.join(bitstring)
continue
else:
temp_parent = family_dict[biopsy_list[biopsy]]
bitstring[biopsy_list[biopsy]-1] = '1'
while temp_parent > 1:
temp_parent = family_dict[position]
bitstring[temp_parent-1] = '1'
if temp_parent == 1: break
derived_genomes_inBx[biopsy] = ''.join(bitstring)
return derived_genomes_inBx
The original problem was as Teppo Tammisto pointed out an issue with the 'str' datastructure taking 'S32' format. Once I changed to using the list(map(str, ...) functionality a few more issues arose with the original code, which I've now fixed. When I finish this thesis chapter I'll publish the whole family of functions to use to virtually 'biopsy' a cellular automaton model (well, just an array really) and reconstruct 'genomes' from family tree data and the current automaton state vector.
Thanks all!

Force scapy to re-dissect a layer after changes

I am working with a fork of scapy (a Python packet manipulation tool) called scapy-com. This implements 802.15.4 and Zigbee parsing/manipulation, amongst other protocols.
A quirk of the Zigbee protcol is found in the network level security header. Initially, the security level (which defines the encryption and length of message integrity code) is set correctly, but is then set to 0 (no encryption) before it is sent. From the spec:
The security level sub-field of the security control field shall be
over-written by the 3-bit all-zero string '000'
The spec can be found here. The relevant section is "4.3.1.1 Security Processing of Outgoing Frames".
This means that packet captures indicate that no encryption or message integrity code is in use. The security level must be communicated out-of-band.
scapy-com doesn't deal with this. It naively parses the security level and sets the length of the MIC to 0. The code that does this is:
def util_mic_len(pkt):
''' Calculate the length of the attribute value field '''
# NWK security level 0 seems to implicitly be same as 5
if ( pkt.nwk_seclevel == 0 ): # no encryption, no mic
return 0
elif ( pkt.nwk_seclevel == 1 ): # MIC-32
return 4
elif ( pkt.nwk_seclevel == 2 ): # MIC-64
return 8
elif ( pkt.nwk_seclevel == 3 ): # MIC-128
return 16
elif ( pkt.nwk_seclevel == 4 ): # ENC
return 0
elif ( pkt.nwk_seclevel == 5 ): # ENC-MIC-32
return 4
elif ( pkt.nwk_seclevel == 6 ): # ENC-MIC-64
return 8
elif ( pkt.nwk_seclevel == 7 ): # ENC-MIC-128
return 16
else:
return 0
The project that uses scapy-com attempts to deal with this by setting the security level to 5:
#TODO: Investigate and issue a different fix:
# https://code.google.com/p/killerbee/issues/detail?id=30
# This function destroys the packet, therefore work on a copy - #cutaway
pkt = pkt.copy() #this is hack to fix the below line
pkt.nwk_seclevel=5 #the issue appears to be when this is set
mic = pkt.mic
However, this doesn't work - the message integrity code has already been set. I have worked around this by simply altering the util_mic_len function to set the mic length correctly.
The question is, how should the Zigbee parser be changed so that altering the nwk_seclevel after the initial dissection causes the mic length to be updated?
I can see two solutions:
Change the scapy-com code so that changing nwk_seclevel automatically changes the mic length.
Re-dissect the packets from outside scapy-com as they are changed.
The issue with 1 is I have no idea about how to go about it.
The issue with 2 is that I have some idea but can't get it to work - I can't work out how to call dissect on a packet after it has been loaded. Calling pkt.dissect(pkt) seems to not work and looks odd.
What is the best or recommended solution here?
Fixing scapy sounds right solution.
scapy-com is quite old. Zigbee specific code in scapy-com is 1244 lines of code, which in large part are enumerations and field lists. So, it should not be too hard to migrate it to scapy-python3. If you would assist in migrating it to scapy-python3 http://github.com/phaethon/scapy , I could help with fixing the issue.
The project you are referring to is KillerBee and I had this exact problem with decryption. I simply "fixed" the code thusly:
from struct import pack
f = pkt.getlayer(ZigbeeSecurityHeader).fields
pkt.nwk_seclevel = 5
nwk_mic = pkt.mic
nwk_encrypted = f['data'][:-6]
ext_source = f['ext_source']
nwk_sec_ctrl_byte = str(pkt.getlayer(ZigbeeSecurityHeader))[0]
nwk_nonce = struct.pack('Q',ext_source) + struct.pack('I',f['fc']) + nwk_sec_ctrl_byte
nwk_crop_size = 4 + 2 + len(pkt.getlayer(ZigbeeSecurityHeader).fields['data']) # The length of the encrypted data, mic and FCS
# the Security Control Field flags have to be adjusted before this is calculated, so we store their original values so we can reset them later
zigbeeData = pkt.getlayer(ZigbeeNWK).do_build()
zigbeeData = zigbeeData[:-nwk_crop_size]
(nwk_payload, nwk_micCheck) = zigbee_crypt.decrypt_ccm(nkey, nwk_nonce, nwk_mic, nwk_encrypted, zigbeeData)

TMC222 Stepper Controller, motor busy function

I am currently working on a robot that has to traverse a maze.
For the robot I am using a TMC222 Stepper controller and the software is coded in Python.
I am in need of a function which can tell me when the motors are busy so that the robot will seize all other activity while the motors are running.
My idea is to check the current position on the motors and compare it to the target position, but i haven't gotten it to work yet.
My current attempt:
def isRunning(self):
print("IS RUNNING TEST")
fullstatus=self.getFullStatus2()
#print("FULL STATUS: " + str(fullstatus[0]) + " 2 " + str(fullstatus[1]))
actLeft=fullstatus[0][1]<<8 | fullstatus[0][2]<<0
actRight=fullstatus[1][1]<<8 | fullstatus[1][2]<<0
tarLeft=fullstatus[0][3]<<8 | fullstatus[0][4]<<0
tarRight=fullstatus[1][3]<<8 | fullstatus[1][4]<<0
value = (actLeft==tarLeft) and (actRight==tarRight)
value = not value
# print("isbusy="+str(value))
print 'ActPos = ' + str(actLeft)
print 'TarPos = ' + str(tarLeft)
return value
It would be helpful to see your getFullStatus2() code as well, since it's unclear to me how you're getting a multidimensional output.
In general, you can form a 16-bit "word" from two 8-bit bytes just as you have it:
Word = HB << 8 | LB << 0
Where HB and LB are the high (bits 15-8) and low (bits 7-0) bytes.
That being said, there are multiple ways to detect motor stall. The ideal way would be an external pressure switch that closed when it hit a wall. Another would be to monitor the motor's current, when the motor faces resistance (when accelerating or in stall), the current will rise.
Since it looks like neither of these are possible, I'd use still a different approach, monitoring the motor's position (presumably from some sort of encoder) over time.
Lets say you have a function get_position() that returns an unsigned 16-bit integer. You should be able to write something like:
class MotorPosition(object):
def __init__(self):
readings = []
def poll(self):
p = get_position()
self.readings.append(readings)
# If the list is now too long, remove the oldest entries
if len(self.readings) > 5:
self.readings.pop(0)
def get_deltas():
deltas = []
for x,y in zip(self.readings[1:4], self.readings[0:3]):
d = x - y
# Wraparound detection
if (d < -THRESHOLD): d += 65536
elif(d > THRESHOLD): d -= 65536
deltas.append(d)
return deltas
def get_average_delta():
deltas = self.get_deltas()
return sum(deltas) / float(len(deltas))
Note that this assumes you're polling the encoder fast enough and with consistent frequency.
You could then monitor the average delta (from get_average_delta()) and if it drops below some value, you consider the motor stalled.
Assumptions:
This is the datasheet for the controller you're using
Your I²C code is working correctly

Categories

Resources