Skip to content

Unpack isn't working #4

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
fakecrusader opened this issue Jan 8, 2019 · 19 comments
Closed

Unpack isn't working #4

fakecrusader opened this issue Jan 8, 2019 · 19 comments

Comments

@fakecrusader
Copy link

fakecrusader commented Jan 8, 2019

I am using this library with RPi3 but encounter runtime errors when reading the temperature or reference temperature. The temperature functions use "unpack" when returning the results of register reads. The read_register function returns 3 bytes and although the comments say the unpack will adjust it to the right size I get a runtime error instead saying 4 bytes are expected.
A bit of diagnostic work showed that the bytearray was there and contained 3 bytes. I don't understand the unpack syntax to the point where it should be adding a byte :

raw_temp = unpack(">i", self._read_register(_MAX31856_LTCBH_REG, 3))[0]

There just seems to be a null byte declaration stuck on the end with no link symbol such as '+' as you might expect. It doesn't throw a syntax error but also doesn't seem to work.

Researching similar unpack errors I came across "int.from_bytes()" as a newer Python feature. I gave it a try instead of the "unpack" code and it worked.

`def temperature(self):

    self._perform_one_shot_measurement()

    # unpack the 3-byte temperature as 4 bytes
    # raw_temp = unpack(">i", self._read_register(_MAX31856_LTCBH_REG, 3))[0]
    raw_temp = int.from_bytes(self._read_register(_MAX31856_LTCBH_REG, 3),'big')
    # shift to remove extra byte from unpack needing 4 bytes
    # raw_temp >>= 8

    # effectively shift raw_read >> 12 to convert pseudo-float
    temp_float = (raw_temp / 4096.0)

    return temp_float`

This gave me what look like accurate temperatures, pending further calibration.
Any idea why the original code failed for me? It seems the code isn't as portable as it could be?

@ladyada
Copy link
Member

ladyada commented Jan 8, 2019

python3 is a little pickier than circuitpython on what you can pass into unpack

@kattni @brennen @caternuson can one of y'all check this out and fix

@siddacious
Copy link
Contributor

I can take a look at this after work.

@ladyada
Copy link
Member

ladyada commented Jan 8, 2019

thanks! yah plz stick to unpack, but i think you'll need to either extend or shrink the bytearray - circuitpython is blase' about the # of bytes matching the unpack string :)

@fakecrusader
Copy link
Author

python3 is a little pickier than circuitpython on what you can pass into unpack

Does this mean that Circuitpython (or micropython?) had its own "unpack" implementation that is now replaced by the fact that it's running under Python3 on the RPi? Does that explain the odd (to me) syntax, i.e. it's not vanilla unpack?

@ladyada
Copy link
Member

ladyada commented Jan 8, 2019 via email

@caternuson
Copy link
Contributor

@siddacious it's as @ladyada says, so will need to pad the bytearray somehow before calling unpack. Do you want to PR that?

Python 3 struct.unpack i expects 4 bytes:
https://docs.python.org/3/library/struct.html#format-characters
and can't take a joke.

Issue recreated:

pi@raspberrypi:~ $ python3
Python 3.5.3 (default, Sep 27 2018, 17:25:39) 
[GCC 6.3.0 20170516] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import board, busio
>>> import digitalio
>>> import adafruit_max31856
>>> spi = busio.SPI(board.SCK, board.MOSI, board.MISO)
>>> cs = digitalio.DigitalInOut(board.D21)
>>> cs.direction = digitalio.Direction.OUTPUT
>>> tc = adafruit_max31856.MAX31856(spi, cs)
>>> tc.temperature
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/local/lib/python3.5/dist-packages/adafruit_max31856.py", line 159, in temperature
    raw_temp = unpack(">i", self._read_register(_MAX31856_LTCBH_REG, 3))[0]
struct.error: unpack requires a bytes object of length 4
>>> 

Played with a nominal fix:

>>> raw = tc._read_register(0x0c, 3)
>>> len(raw)
3
>>> unpack(">i", raw)[0]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
struct.error: unpack requires a bytes object of length 4
>>> raw[0:0] = b'\x00'
>>> len(raw)
4
>>> unpack(">i", raw)[0]
92640
>>> 

NOTE be careful not to redefine your class level _BUFFER in fixing this. I think my example above does that.

>>> len(tc._BUFFER)
4

yeah python

@siddacious
Copy link
Contributor

@siddacious Yup, I can PR it but I'll have to test on a metro/feather and get you or someone else to test on a PI because I don't have one.

@caternuson
Copy link
Contributor

Cool. I can test on RPi setup. And good idea to make sure it works on CP - maybe CP requires things t be blasé and won't like you being serious. :)

@coffeegoat
Copy link

This problem still seems to exist when using the reference.temperature property. I get the following error:

File "ReadMax31856Fault4.py", line 35, in
CJTemp2 = max31856.reference_temperature
File "/home/pi/.local/lib/python3.5/site-packages/adafruit_max31856.py", line 174, in reference_temperature
raw_read = unpack(">h", self._read_register(_MAX31856_CJTH_REG, 2))[0]
struct.error: unpack requires a bytes object of length 2

I can read the value using a simple "_read_register" request, but the property is apparently nonworking. I found similar results with the reference_temperature_thresholds property, though the error is slightly different:

File "ReadMax31856Fault4.py", line 38, in
Threshold = max31856.reference_temperature_thresholds
File "/home/pi/.local/lib/python3.5/site-packages/adafruit_max31856.py", line 209, in reference_temperature_thresholds
return (float(unpack("b", self._read_register(_MAX31856_CJLF_REG, 1))[0]),
struct.error: unpack requires a bytes object of length 1

I'm barely python literate so I can't help with that but I'm working with a PI and a MAX31856 so I'd be happy to do some hardware testing.

@siddacious
Copy link
Contributor

@coffeegoat Sorry to hear that! I'll take a look.

@caternuson
Copy link
Contributor

@siddacious
Copy link
Contributor

@caternuson That's a good idea. I can take a look at it in a while but if you want to give it a go, by all means do so.

@caternuson
Copy link
Contributor

Nah, don't let me hold you up. Go for it. I was just passing by and took a looksie. Might be as simple as:

 return self._BUFFER[:length]

but not sure what kind of thread that might pull. So worth testing.

@coffeegoat
Copy link

I poked at it a bit more, and this snippet worked:

` def reference_temperature(self):
"""The temperature of the cold junction in degrees celsius. (read-only)"""
self._perform_one_shot_measurement()

    raw_read = unpack(">i", self._read_register(_MAX31856_CJTH_REG, 2))[0]

    raw_read >>=16

    cold_junction_temp = raw_read / 256.0

    return cold_junction_temp`

I'm not super clear on the syntax, but I modeled it after the read function with the key difference being the data type and made the assumption that we should only be seeing a couple of bits. It seems to give reasonable values.

@caternuson
Copy link
Contributor

Maybe this should've been a new/separate issue, but hopefully this is an easy fix, so reopening.

PR submitted - checkout #6

@caternuson caternuson reopened this Jun 25, 2019
@caternuson
Copy link
Contributor

@coffeegoat Please try the 0.8.3 version of the library when it becomes available:
https://github.com/adafruit/Adafruit_CircuitPython_MAX31856/releases/tag/0.8.3

@coffeegoat
Copy link

@caternuson I'll check version 0.8.3 tomorrow morning, I've got a test running right now and don't want to swap libraries in the middle.

@coffeegoat
Copy link

We have success, that fixed it, was it only the minor change in to add:
return self._BUFFER[:length]

@caternuson
Copy link
Contributor

Yep. That was the main change. Then had to add some padding to a call that requested 3 bytes that needed to get unpacked with an i, which wants 4 bytes. You can actually see all the code changes in the PR:
#6
Select the "Files changed" tab to view.

Glad that fixed it. Thanks for letting us know.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants