0

this is mostly a ruby question.

I'm stuck trying to parse some bytes from an i2c device to a float value on ruby.

Long story:

I'm trying to read a float value from an i2c device with raspberry pi and an AtTiny85 (the device). i'm able to read its value from console through i2ctools

Example:

i2cset -y 0 0x25 0x00; sleep 1; i2cget -y 0 0x25 0x00; i2cget -y 0 0x25 0x00; i2cget -y 0 0x25 0x00; i2cget -y 0 0x25 0x00

Gives me:

0x3e
0x00
0x80
0x92

that means 0.12549046, which is a value in volts that i'm able to check with my multimeter and is ok. (the order of the bytes is 0x3e008092)

Now i need to get this float value from a ruby script, I'm using the i2c gem.

A comment on this site suggest the following conversion method:

hex_string = '42880000'
float = [hex_string.to_i(16)].pack('L').unpack('F')[0]
# => 68.0

float = 66.2
hex_string  = [float].pack('F').unpack('L')[0].to_s(16)
# => 42846666

But i haven't been able to get this string of hex values. This fraction of code:

require "i2c/i2c"
require "i2c/backends/i2c-dev"

@i2c = ::I2C.create("/dev/i2c-0")
sharp = 0x25

@i2c.write(sharp, 0)

sleep 1

puts @i2c.read(sharp, 4).inspect

Puts on screen

">\x00\x00P"

Where the characters '>' and 'P' are the ASCII values of the byte in that position, but then i cannot know where/how to split the string and clean it up to at least try the method showed above.

I could write a C program to read the value and printf it to console or something and run it from ruby, but i think that would be an awful solution.

Some ideas on how can this be done would be very helpful!

Greetings.

2 Answers 2

0

I came with something:

bytes = []

for i in (0..3) do
  bytes << @i2c.read_byte(sharp).unpack('*C*')[0].to_s(16)
  bytes[i] = "00" unless bytes[i] != "0"
end

bytes = bytes.join.to_s
float = [bytes.to_i(16)].pack('L').unpack('F')[0]

puts float.to_s

Not shure about unpack(' * C * ') though, but it works. If it's a better way to do it i'd be glad with another answer.

Greetings!

Sign up to request clarification or add additional context in comments.

Comments

0

You probably just need to use unpack with a format of g, or possible e depending on the endianness.

@i2c.read(sharp, 4).unpack('g')[0]

The example you are referring to is taking a string of hex digits and first converting it to a binary string (that’s the [hex_string.to_i(16)].pack('L') part) before converting to an integer (the L directive is for 32 bit integers). The data you have is already a binary string, so you just need to convert it directly with the appropriate directive for unpack.

Have a read of the documentation for unpack and pack.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.