Arduino - 5 questions for real Wire.write() and Wire.read() explanation - arduino

I Googled this a lot, and it seems that I am not the only one having problems with really understanding Wire.write() and Wire.read(). Being novice, I almost never use libraries that are already written by somebody, I try to create my class for module in order to truly understand how this module works and to learn how to manipulate with it. I've read few books and too many tutorials, but I could summarise these in two:
a) all tutorials are just showing the very basics of how to use these methods and b) they don't actually explain the steps, like everything is totally self explanatory. Call me stupid, but I have the feeling like somebody told me that 1 + 1 = 2, and then gave me some polynomial equation to solve :(
All book examples and almost all tutorials look like this imaginary example:
Wire.beginTransmission(Module_Address); //Use this to start transmission
Wire.write(0); // go to first register
Wire.endTransmission(); // end this
//To read
Wire.requestFrom(Module_Address, 3); //Read three registers
Wire.read(); //Read first register
Wire.read(); //Read second register
Wire.read(); //Read third register
And that's it about reading.
When it comes to writing, it's even worse:
Wire.beginTransmission(Module_Address); //Use this to start transmission
Wire.write(0); // go to first register
Wire.write(something); //Write to first register
Wire.write(something); //write to second register
Wire.endTransmission(); // end this
So far, working with ANY module I got, it was NEVER that easy. Usually, every register has more than one "option" inside. For example, lets say that imaginary module has First read register like this:
ADDRESS | BIT 7 | BIT 6 | BIT 5 | BIT 4 | BIT 3 | BIT 2 | BIT 1 | BIT 0
data Byte1 | mute .| option2.........|.....................option3.......................
To read only option 3, I would use this code:
Wire.beginTransmission(module_address);
Wire.write(0);
Wire.endTransmission();
Wire.requestFrom(module_address, 1);
byte readings = Wire.read() & 0x1F; //0x1F is hexadecimal of binary 0001111 for option 3 in register 1
QUESTION 1
What does this '&' after Wire.read() REALLY means? (I know that it points to option within register, but I do not really understand this, why is it there)
QUESTION 2
Why the previous problem isn't written anywhere? So many tutorials, so many books, but I "discovered" it by accident when I tried to figure out how one library was working.
QUESTION 3
Imagine that hypothetical module has third register in write mode looking like this:
ADDRESS | BIT 7 | BIT 6 | BIT 5 | BIT 4 | BIT 3 | BIT 2 | BIT 1 | BIT 0
data Byte3 | write flag.......| option2.........|......................option3........
How to write flag without affecting option 2 and option 3? Or in other words, how to write to register 3's write flag? If I take 11000000 could affect because maybe I do not know what exactly option 2 and 3 do, or I do not wish to interfere with default setup.
QUESTION 4
Certain modules have to be written in binary-coded decimal. Let's say, that you have a timer and you wish to set 17 seconds for countdown to 0.And to do that, you need to write number 17 to register one, but number should be binary-coded decimal. 17 as binary-coded is: 0001 0111. But when you do this:
Wire.beginTransmission(module_address);
Wire.write(0);
Wire.write(00010111);
Wire.endTransmission();
You get different number, 13 or 10 (can't recall what number, I know it was wrong).
However, when doing this conversion: 17/10*16 + 17%10 it writes correct number 17.
Yes, I also accidentally found this out. BUT, where is this equation from? I searched (obviously wrong) as much as I could, but there was nothing about it. So, how did somebody come with this equation?
QUESTION 5
Probably a dumb off-topic question, BUT:
should Arduino library be written in a way that others could find it difficult to figure out the idea behind it? In other words, to figure out what the developer was exactly doing? I remember that one person used a lot of messy code to read something from sensor and then formula to convert it from binary-coded decimal to print it to Serial Monitor, while the same thing could be done with simply
Serial.print(read_byte, HEX);
It's not that I am smarter (or better) than them, I just don't understand why somebody would write a complex code when there is no(really) need for that.
Thanks a lot for any help :)

Questions 1. - 4.: Are all covered by Bit Manipulation tutorial on AVRFreaks forum Tutorials. So in short:
1) The & is used for bit masking in this case.
2) If you look for "Bit manipulation" then there are loads of Tutorials.
3) It's possible by Bit manipulation. How? For in memory variable just use bit masking. To clear two bits: var &= 0b00111111 to set two bits: var |= 0b11000000. If you don't have register value, you have to Read & Modify & Write it back. If you can't read the value (for example it's internal address like for eeproms) you have to have this value in memory anyways.
4) In C++ numbers starting by zero are in Octal base. If you want binary, you have to use 0b00010111. For the HEX base you have to use 0xFF. This is not explicitly mentioned in that tutorial, but both are used here.
5) It should be as clear as possible. But for the begginers without good knowlege of C++ it's hard anyway. For me is most difficult to read the code without indentation or even worst with bad indentation, bad variable names. The libraries are usually written by advanced users, so it's not so hard to understand with some background like knowing the datasheet for used MCUs and so on.
BTW: wrong comments are also bad for understanding:
//0x1F is hexadecimal of binary 0001111 for option 3 in register 1
The value 0x1F is definitely not 0001111 in binary but 00011111 (or better: 0b00011111)

Related

Wiegand card numbers are seen different on Hikvision and ZKteco

I have a problem with two access control panels, one is Hikvision and the other one is a ZKTeco CCA-400, those two panels see the Wiegand card in a different way, this is a big problem because I cannot import cards from ZKteco to Hikvision or the other way around.
Currently I have a card that is physically labeled with the following:
0002821060 043,03012
Hikvision panel sees the card as: 2821060
ZKTeco panel sees the card as: 04303012
My final goal is to understand why is this happening and build a custom Wiegand rule on the Hikvision in order to transform the card id's to be seen identical by both panels.
I searched and couldn't figure it out, so in my pursuit to debug this issue I connected a Wiegand reader to a Arduino UNO just to see that is coming on the wire from the reader, the results just made the problem even confusing:
I tried to Wiegand libraries:
https://github.com/paulo-raca/YetAnotherArduinoWiegandLibrary
and
https://github.com/monkeyboard/Wiegand-Protocol-Library-for-Arduino
Surprise!
The first library sees the card as:
Read 26 bits. 0001010110000101111000100100000000
FC = 43, CC = 3012
This is exactly what the ZKTeco panel sees.
The second library sees the card as:
Card readed: 24bits / 2B0BC4
That in decimal is 2821060, exactly what the Hikvision is seeing.
Can anyone explain to me why this is happening ? From reading the docs of the protocol is pretty straight forward and should not really have two independent ID's.
Hopefully I managed to explain the issue in a good way.
Thanks!
It sounds like the difference in what you are seeing is the two parity bits. Each half of the number encoded into the card has its own parity bit, with one half odd parity, and the other half even parity. In addition to detecting read errors, these two bits allow detection of use of a Wiegand card normally vs. upside-down.
You might check that by determining the reaction of the two devices to running the card through with the front side toward the back. My guess would be the one that only reports 24-bits may ignore reversed reads, but the other might report a different number (with bits reversed from the first one.)
I worked for Kastle Systems on what was probably the first commercial application of Wiegand cards for security almost 40 years ago. The parity scheme was similar to that used on UPC barcode readers. I see there are still documents out on the web describing the, Wiegand Kastle format 32-bit format, which looks like it may be helpful to you.
I managed to sort this out, it seems that ZKTeco and Hikvision handles the conversion from HEX to DEC in a different way, that's the reason there are two different numbers on the card.
So it goes like this, we have a card that has physically printed the following sequence of numbers: 0002821060 043,03012
We convert 2821060 to HEX = 2B0BC4 ( This is what ZKTeco sees )
For Hikvision:
We convert 2B to DEC = 43
We convert 0BC4 to DEC = 3012
The result decimal number is 43 3012, pretty close to what the access panel sees. Now, we have to pad it so it has 8 digits like this:
04303012
If the first bits are <100 in decimal we have to add a 0 in front.
We also need to pad the rest of the bits so the second part reaches a length of 5 digits.
Conclusion:
Hikvision correctly converts the card to Wiegand 26 format ( facility code + card id ), ZKTeco instead converts the entire card number to decimal directly without splitting the facility id / card id.
Hopefully this will be helpful to other people having to deal with this type of access control panels.
I wrote a fragment of messy code that will convert a ZK exported personel file to Hikvision card format.
import sys
def convert(dec):
h = hex(dec)
h = h[2:]
#print "HEX {}".format(h)
first = h[:2]
first = int(h[:2], 16)
if first < 100:
first = "0{}".format(first)
second = int(h[2:6],16)
first = str(first)
second = str(second)
if len(first)+len(second) == 8:
final = "{}{}".format(first,second)
else:
final = "{}0{}".format(first,second)
#print "HIK {}".format(final)
#print "ZK {}".format(int(h,16))
return str(final)
pid=1
with open("zk.csv") as f:
lis = [line.split(",") for line in f]
for i, x in enumerate(lis):
persid = pid
if x[1] == "":
name = "Fara nume"
else:
name = "{} {}".format(x[1], x[2])
cardid = convert(int(x[3]))
if cardid[:1] == "0":
cardid = "'{}".format(cardid)
print "{},NAN,{},1,,,,,{},,".format(pid, name, cardid)
pid+=1
This is the only post on internet I am finding on this topic. I report similar issue. Please do not delete as was done previously because this might help someone.
What I did is convert serialized RFID to site+cardID (hikvision way) with Excel:
M88 is DEC2HEX(L88) (M88 is the Hex of the serialized card number)
first 3 decimal digits
=IF(LEN(HEX2DEC(MID(M88;1;2)))=1;"00"&HEX2DEC(MID(M88;1;2));IF(LEN(HEX2DEC(MID(M88;1;2)))=2;"0"&HEX2DEC(MID(M88;1;2));HEX2DEC(MID(M88;1;2))))
last 5 decimal digits
=IF(LEN(HEX2DEC(MID(M88;3;4)))<5;"0"&HEX2DEC(MID(M88;3;4));HEX2DEC(MID(M88;3;4)))
This is a good calculator I've found but not suitable for hundreds of lines of RFIDs
https://btrockford.com/security/card-access-control/proximity-card-calculator/
Probably there is an option to use custom Wiegand rules to modify the hikvision default behavior (I didn't have success with that till now).

Finding similar hashes

I'm trying to find 2 different plain text words that create very similar hashes.
I'm using the hashing method 'whirlpool', but I don't really need my question to be answered in the case or whirlpool, if you can using md5 or something easier that's ok.
The similarities i'm looking for is that they contain the same number of letters (doesnt matter how much they're jangled up)
i.e
plaintext 'test'
hash 1: abbb5 has 1 a , 3 b's , one 5
plaintext 'blahblah'
hash 2: b5bab must have the same, but doesnt matter what order.
I'm sure I can read up on how they're created and break it down and reverse it, but I am just wondering if what I'm talking about occurs.
I'm wondering because I haven't found a match of what I'm explaining (I created a PoC to run threw random words / letters till it recreated a similar match), but then again It would take forever doing it the way i was dong it. and was wondering if anyone with real knowledge of hashes / encryption would help me out.
So you can do it like this:
create an empty sorted map \
create a 64 bit counter (you don't need more than 2^63 inputs, in all probability, since you would be dead before they would be calculated - unless quantum crypto really takes off)
use the counter as input, probably easiest to encode it in 8 bytes;
use this as input for your hash function;
encode output of hash in hex (use ASCII bytes, for speed);
sort hex on number / alphabetically (same thing really)
check if sorted hex result is a key in the map
if it is, show hex result, the old counter from the map & the current counter (and stop)
if it isn't, put the sorted hex result in the map, with the counter as value
increase counter, goto 3
That's all folks. Results for SHA-1:
011122344667788899999aaaabbbcccddeeeefff for both 320324 and 429678
I don't know why you want to do this for hex, the hashes will be so large that they won't look too much alike. If your alphabet is smaller, your code will run (even) quicker. If you use whole output bytes (i.e. 00 to FF instead of 0 to F) instead of hex, it will take much more time - a quick (non-optimized) test on my machine shows it doesn't finish in minutes and then runs out of memory.

Using strconv for negative hex values in Go

I've been building an assembler for no good reason the past day or so using Go so I can get familiar with the language. It's my first real program using Go so I expected problems, but I have a consistent bug coming up time and time again. I just figured out other hacky ways to fix it in other cases, but this time I think I need an answer so I feel like I'm actually doing this right.
Basically, I have to parse tons of byte values. Some of these are signed bytes so -1 = 0xFF and so on. When calculating the address of a label I need to find the offset of it from the current address. The following code is a stripped down basic version of what I use to get the offset:
// lbladdr holds the target label address
// address holds current address in memory
// label[x] holds the offset
if address > lbladdr {
lbladdr -= address
}
label[x] = strconv.FormatInt(int64(lbladdr), 16)
This works for positive values, but when I get a negative address (address > lbladdr) then instead of getting a value like FE I get -2. I don't get why the standard library would append a negative sign to a hex number and I haven't been able to find anything in the documentation about it. I've looked a lot of other places but I can't seem to find anyone with the same problem either.
I hope it's just something on my end that is a simple fix.
It's perfectly reasonable to use a negative sign on hexadecimal numbers. I know that when working with assembly it's common to use the actual bitpattern for the register you are representing in hex to represent the signs. However Go doesn't know you are doing that. Neither is go's formatting function written to support hex values as they would be in a CPU register. Further the bitpatterns will differ depending on the register size (16 vs 32 vs 64 and big vs little endian). you would be storing them in. So the base isn't enough to print them the way you want. You will need to write your own formatting lib that supports formatting for the type of Register you want to represent.
It's by design: http://golang.org/src/pkg/strconv/itoa.go?s=628:668#L8
What you may want is to cast to uint64:
package main
import (
"fmt"
"strconv"
)
func main() {
i := -1
fmt.Printf("%x\n", uint64(i))
fmt.Println(strconv.FormatUint(uint64(i), 16))
}

Driving Dual 7 Segment Display Using Arduino

Okay, so I am trying to drive a 7 segment based display in order to display temperature in degrees celcius. So, I have two displays, plus one extra LED to indicate positive and negative numbers.
My problem lies in the software. I have to find some way of driving these displays, which means converting a given integer into the relevant voltages on the pins, which means that for each of the two displays I need to know the number of tens and number of 1s in the integer.
So far, what I have come up with will not be very nice for an arduino as it relies on division.
tens = numberToDisplay / 10;
ones = numberToDisplay % 10;
I have admittedly not tested this yet, but I think I can assume that for a microcontroller with limited division capabilities this is not an optimal solution.
I have wracked my brain and looked around for a solution using addition/subtraction/bitwise but I cannot think of one at all. This division is the only one I can see.
For this application it's fine. You don't need to get bothered with performance in a simple thermometer.
If however you do need something quicker than division and modulo, then bitwise operations come to help. Basically you would use bitwise & operator, to compare your value to display with patterns describing digits to be displayed on the display.
See the project here for example: http://fritzing.org/projects/2-digit-7-segment-0-99-counting-with-arduino/
You might also try using a 7-seg display driver chip to simplify your output and save pins. The MC14511BCP (a "4511") is a good one. It'll translate binary coded decimal (BCD) to the appropriate 7-seg configuration. Spec sheets are available here and they can be commonly found at electronics parts stores online.

Is there any sense in performing binary AND with a number where all bits are set to 1

Greetings everybody. I have seen examples of such operations for so many times that I begin to think that I am getting something wrong with binary arithmetic. Is there any sense to perform the following:
byte value = someAnotherByteValue & 0xFF;
I don't really understand this, because it does not change anything anyway. Thanks for help.
P.S.
I was trying to search for information both elsewhere and here, but unsuccessfully.
EDIT:
Well, off course i assume that someAnotherByteValue is 8 bits long, the problem is that i don't get why so many people ( i mean professionals ) use such things in their code. For example in SharpZlib there is:
buffer_ |= (uint)((window_[windowStart_++] & 0xff |
(window_[windowStart_++] & 0xff) << 8) << bitsInBuffer_);
where window_ is a byte buffer.
The most likely reason is to make the code more self-documenting. In your particular example, it is not the size of someAnotherByteValue that matters, but rather the fact that value is a byte. This makes the & redundant in every language I am aware of. But, to give an example of where it would be needed, if this were Java and someAnotherByteValue was a byte, then the line int value = someAnotherByteValue; could give a completely different result than int value = someAnotherByteValue & 0xff. This is because Java's long, int, short, and byte types are signed, and the rules for conversion and sign extension have to be accounted for.
If you always use the idiom value = someAnotherByteValue & 0xFF then, no matter what the types of the variable are, you know that value is receiving the low 8 bits of someAnotherByteValue.
uint s1 = (uint)(initial & 0xffff);
There is a point to this because uint is 32 bits, while 0xffff is 16 bits. The line selects the 16 least significant bits from initial.
Nope.. There is no use in doing this. Should you be using a value that is having its importance more than 8 bits, then the above statement has some meaning. Otherwise, its the same as the input.
If sizeof(someAnotherByteValue) is more than 8 bits and you want to extract the least signficant 8 bits from someAnotherByteValue then it makes sense. Otherwise, there is no use.
No, there is no point so long as you are dealing with a byte. If value was a long then the lower 8 bits would be the lower 8 bits of someAnotherByteValue and the rest would be zero.
In a language like C++ where operators can be overloaded, it's possible but unlikely that the & operator has been overloaded. That would be pretty unusual and bad practice though.
EDIT: Well, off course i assume that
someAnotherByteValue is 8 bits long,
the problem is that i don't get why so
many people ( i mean professionals )
use such things in their code. For
example in Jon Skeet's MiscUtil there
is:
uint s1 = (uint)(initial & 0xffff);
where initial is int.
In this particular case, the author might be trying to convert an int to a uint. The & with 0xffff would ensure that it would still convert Lowest 2 Bytes, even if the system is not one which has a 2 byte int type.
To be picky, there is no guaranty regarding a machine's byte size. There is no reason to assume in a extremely portable program that the architecture byte is 8 bits wide. To the best of my memory, according to the C standard (for example), a char is one byte, short is wider or the same as char, int is wider or the same as short, long is wider or the same as int and so on. Hence, theoretically there can be a compiler where a long is actually one byte wide, and that byte will be, say, 10 bits wide. Now, to ensure your program behaves the same on that machine, you need to use that (seemingly redundant) coding style.
"Byte" # Wikipedia gives examples for such peculiar architectures.

Resources