I'm looking for how to turn bytes into a signed int using lua 5.1.5, so far I've only been able to find solutions for lua 5.2 onward, and they are not backward compatible.
I have solutions for how to turn bytes into unsigned integers, like so:
payload_t.temperature=tonumber(utility.hex2str(string.sub(payload,32,33)),16)
First of all I'll assume that you actually have a byte string rather than a hex string given; if your string is a hex string, you can trivially convert it to a byte string using gsub:
function hex2bytes(str)
-- assert that it is indeed a string of hex digit pairs
assert(#str % 2 == 0 and not str:match"[^%x]")
return str:gsub("%x%x", function(hex) return tonumber(hex, 16) end)
end
Now, let's convert this byte string to an integer. I'll assume little endian (least significant byte first); should your string be big endian (most significant byte first) you'll have to reverse it using str:reverse() before you read it.
Reading an unsigned integer is pretty straightforward:
function bytes2uint(str)
local uint = 0
for i = 1, #str do
uint = uint + str:byte(i) * 0x100^(i-1)
end
return uint
end
I'll assume your integers are stored using Two's complement. In this case the higher 2^n values (equivalent to the first bit being set or the value being >= 2^(n-1)) the uint can take represent negative numbers, with the smallest value (2^(n-1)) representing the largest negative value (-2^(n-1)). Thus you can simply subtract the unsigned value from 2^n, the (exclusive) max value for the uint:
function bytes2int(str)
local uint = bytes2uint(str)
local max = 0x100 ^ #str
if uint >= max / 2 then
return uint - max
end
return uint
end
Related
I have a 16-bit in a string but this is the representation of a signed number. Is there a way/function that do the converson from signed bits to decimal ?
The function tonumber() assumes the bits are unsigned.
Lua 5.3/5.4
Use string.unpack with a format string <i2 to read the binary string. (use >i2 for big endian data)
--0x8000 ---> -32768
local v = string.unpack('<i2', '\x00\x80')
Lua 5.2/5.1
There is no string.unpack, so you have to read each byte of the string, then compute the value manually.
local l, h = string.byte('\x00\x80', 1, 2)
local v = h * 256 + l --big endian: v = l * 256 + h
if v > 32767 then v = v - 65536 end
byte 0: min_value (0-3 bit)
max_value (4-7 bit)
The byte0 should be the min and max values combined.
min and max values are both integers (in 0-15 range).
I should convert them into 4-bit binary, and combine them somehow? (how?)
E.g.
min_value=2 // 0010
max_value=3 // 0011
The result should be an Uint8, and the value: 00100011
You can use the shift left operator << to get the result you want:
result = ((min_value << 4) + max_value).toRadixString(2).padLeft(8, '0');
Im developing an app using BLE where iPhone device is the peripheral, and will respond to write requests of type CBATTRequest from the Central.
My take is that this represents a byte array from value of CBATTRequest via request.value of type NSData that I can unpack to read packet # etc. Given the size (octets) and position of each field, how can I unpack and read each value, conceptually and technically?. And how would I go about constructing/packing this same byte array as if I was preparing to send this request? Since I will have to pack data in the same manner for the response.
When you receive the data, it's probably in a CBATTRequest. The data is contained in a member value of type NSData. The member length tells the length in bytes/octects.
CBATTRequest* request = ...;
NSData* value = request.value;
int packetLen = value.length;
It then makes sense to cast this to a struct that corresponds to the structure of the packet:
struct Packet {
unsgined char pktNo;
unsigned char ctrlCmd;
unsigned char txPowerRequest;
unsigned char uuid[2];
unsigned char txCnt;
unsigned char userPayload[14];
};
Packet* packet= (Packet)value.bytes;
Note that packet is of variable length. So only part of the userPayload is valid. The valid length is:
int userPayloadLength = packetLen - 6;
Now you can easily access the members:
int packetNumber = packet->pktNo;
To construct a similar packet, you would approach is slightly similarly.
Packet reponse;
response.pktNo = ...;
reponse.ctrlCmd = ...;
int userPayloadLength = 5;
NSData* value = [NSData dataWithBytes: &response length: userPayloadLength + 6];
Bit 4 to 0 set to 0x01 for..
This most likely is relative to a single octect, e.g. to ctrlCmd. To test it:
if (((packet->ctrlCmd >> 0) & 0x1f) == 0x01) ...
0x1f is the bit mask for 5 consecutive bits set (bit 0 to 5). >> 0 doesn't do anything but would be required if the bits were shifted, e.g. for bit 2 to 5 you would need to shift by 2.
A typical UUID is 16 bytes long. So I assume byte index 13 & 12 refers to bytes 12 and 13 within a 16 byte UUID (as only two bytes are transmitted). The remaining bytes are probably fixed to the base Bluetooth UUID:
00000000-0000-1000-8000-00805F9B34FB
Sometime arc4random() gives negative number also in objective C.
My code is as follow:
Try 1:
long ii = arc4random();
Try 2:
int i = arc4random();
How can I only get positivite random number?
Thank you,
No, it's always positive as it returns an unsigned 32-bit integer (manpage):
u_int32_t arc4random(void);
You are treating it as a signed integer, which is incorrect.
You should use the arc4random_uniform() function. this is the most common random function used.
arc4random_uniform() function
Returns a random number between 0 and the inserted parameter minus 1.
For example arc4random_uniform(3) may return 0, 1 or 2 but not 3.
Example
u_int32_t randomPositiveNo = arc4random_uniform(5) + 1; //to get the range 1 - 5
I'm trying the second day to send a midi signal. I'm using following code:
int pitchValue = 8191 //or -8192;
int msb = ?;
int lsb = ?;
UInt8 midiData[] = { 0xe0, msb, lsb};
[midi sendBytes:midiData size:sizeof(midiData)];
I don't understand how to calculate msb and lsb. I tried pitchValue << 8. But it's working incorrect, When I'm looking to events using midi tool I see min -8192 and +8064 max. I want to get -8192 and +8191.
Sorry if question is simple.
Pitch bend data is offset to avoid any sign bit concerns. The maximum negative deviation is sent as a value of zero, not -8192, so you have to compensate for that, something like this Python code:
def EncodePitchBend(value):
''' return a 2-tuple containing (msb, lsb) '''
if (value < -8192) or (value > 8191):
raise ValueError
value += 8192
return (((value >> 7) & 0x7F), (value & 0x7f))
Since MIDI data bytes are limited to 7 bits, you need to split pitchValue into two 7-bit values:
int msb = (pitchValue + 8192) >> 7 & 0x7F;
int lsb = (pitchValue + 8192) & 0x7F;
Edit: as #bgporter pointed out, pitch wheel values are offset by 8192 so that "zero" (i.e. the center position) is at 8192 (0x2000) so I edited my answer to offset pitchValue by 8192.