Using adafruit_debouncer on a keyboard matrix - adafruit-circuitpython

I am implementing a key matrix in Circuitpython on a Raspberry Pi Pico.
I have gotten to the point where I can scan and read fine. Now I need to add debouncing. I would like to use adafruit_debouncer for that.
First I fell for the mistake of simply debouncing the column input-pins with hilarious results as the debouncer tried to make sense of the values while the rows where being scanned...
Now I want to create a debouncer for each key and I think I should be able to use adafruit_debouncer by not giving it a DigitalIO-instance to work on but a lambda that looks at a specific cell in my two-dimensional array of key states.
Given two suitably sized 2D-arrays of keystates and debouncers I create them like this:
for rowindex in range(len(rowpins)):
for colindex in range(len(colpins)):
debouncers[rowindex][colindex] = adafruit_debouncer.Debouncer(lambda: keystates[rowindex][colindex])
After doing each scan that updates keystates[][], putting in Trues and Falses according to wether a key is down or not, I then iterate over debouncers[][], call update() on each and then query their value.
Unfortunately no debouncer seems to be able to see the True values from the array. At least none ever report a True themselves.
What is my mistake?

Related

Skip assigning if found duplicates

I have a procedure that assigns values and sends it back. I need to implement a change that it would skip the assigning process whenever it finds duplicate iban code. It would be in this FOR EACH. Some kind of IF or something else. Basically, when it finds an iban code that was already used and assigned it would not assign it for the second or third time. I am new to OpenEdge Progress so it is really hard for me to understand correctly the syntax and write the code by myself yet. So if anyone could explain how I should implement this, give any pieces of advice or tips I would be very thankful.
FOR EACH viewpoint WHERE viewpoint.cif = cif.cif AND NOT viewpoint.close NO-LOCK:
DEFINE VARIABLE cIban AS CHARACTER NO-UNDO.
FIND FIRST paaa WHERE paaa.cif EQ cif.cif AND paaa.paaa = viewpoint.aaa AND NOT paaa.close NO-LOCK NO-ERROR.
cIban = viewpoint.aaa.
IF AVAILABLE paaa THEN DO:
cIban = paaa.vaaa.
CREATE tt_account_rights.
ASSIGN
tt_account_rights.iban = cIban.
END.
You have not shown the definition of tt_account_rights but assuming that "iban" is a uniquely indexed field in tt_account_rights you probably want something like:
DEFINE VARIABLE cIban AS CHARACTER NO-UNDO.
FOR EACH viewpoint WHERE viewpoint.cif = cif.cif AND NOT viewpoint.close NO-LOCK:
FIND FIRST paaa WHERE paaa.cif EQ cif.cif AND paaa.paaa = viewpoint.aaa AND NOT paaa.close NO-LOCK NO-ERROR.
cIban = viewpoint.aaa.
IF AVAILABLE paaa THEN DO:
cIban = paaa.vaaa.
find tt_account_rights where tt_account_rights.iban = cIban no-error.
if not available tt_account_rights then
do:
CREATE tt_account_rights.
ASSIGN
tt_account_rights.iban = cIban.
end.
END.
Some bonus perspective:
1) Try to express elements of the WHERE clause as equality matches whenever possible. This is the most significant contributor to query efficiency. So instead of saying "NOT viewpoint.close" code it as "viewpoint.close = NO".
2) Do NOT automatically throw FIRST after every FIND. You may have been exposed to some code where that is the "standard". It is none the less bad coding. If the FIND is unique it adds no value (it does NOT improve performance in that case). If the FIND is not unique and you do as you have done above and assign a value from that record you are, effectively, making that FIRST record special. Which is a violation of 3rd normal form (there is now a fact about the record which is not related to the key, the whole key and nothing but the key). What if the 2nd record has a different iBan? What if different WHERE clauses return different "1st" records?
There are cases where FIRST is appropriate. The point is that it is not ALWAYS correct and it should not be added to every FIND statement without any thought about why you are putting it there and what the impact of that keyword really is.
3) It is clearer to put the NO-LOCK (or EXCLUSIVE-LOCK or SHARE-LOCK) immediately after the table name rather than towards the end of the statement. The syntax works either way but from a readability perspective it is better to have the lock phrase right by the table.

Delete a key-value pair in BerkeleyDB

Is there any way to delete key-value pair where the key start with sub-string1 and ends with sub-string2 in BerkeleyDB without iterating through all the keys in the DB?
For ex:
$sub1 = "B015";
$sub2 = "5646";
I want to delete
$key = "B015HGUJJ75646"
Note: It is guaranteed that there will be only one key for the combination of $sub1 and $sub2.
This can be done by taking an iterator of the DB and checking every key for the condition, but that will be very in-efficient for large DBs. Is there any way to do it without iterating through the complete DB?
If you're using a RECNO database, you're probably out of luck. But, if you can use a BTREE, you have a couple of options.
First, and probably easiest is to iterate over only the portion of the database that makes sense. Assuming you're using the default key comparison function, you can use DB_SET_RANGE to position the starting cursor (iterator) at the start of your partial key string. In your example, this might be "B0150000000000". You then scan forwards with DB_NEXT, looking at each key in turn. When either you find the key you're looking for, or if the key you find doesn't start with "B015", you're done.
Another technique that could be applicable to your situation is to redefine the key comparison function. If, as you state, there is only one combination of $sub1 and $sub2, then perhaps you only need to compare those sections of the keys to guarantee uniqueness? Here's an example of a full string comparison (I'm assuming you're using perl, just from the syntax you supplied above) from https://www2.informatik.hu-berlin.de/Themen/manuals/perl/DB_File.html :
sub Compare
{
my ($key1, $key2) = #_ ;
"\L$key1" cmp "\L$key2" ;
}
$DB_BTREE->{compare} = 'Compare' ;
So, if you can rig things such that you're only comparing the starting and ending four characters, you should be able to drop the database iterator directly onto the key you're interested in.

How to create three dimensional array with QHash?

I want to create QHash with three arguments:
QHash <int, QString, float> myhash;
I know that I have to use nested QHash, so I did:
QHash <int, QHash<QString, float> > myhash;
But I could not figure out how I can insert values to myhash.
I tried to create another Qhash and insert this into my myhash, but I does not make any sence, since I have exactly 1 pair data for one key.
What I want basically is :
0, "string1", 1.5
1, "string2", 1.2 etc.
How I can create efficiently (in terms of lookup time (the reason I am using QHash)) the above arrays. And how to insert values afterwards.
Thanks forward.
With QHash <int, QHash<QString, float> > myhash;, you can simply do this to set values:
myhash[42]["fortytwo"] = 42.42;
You can use the same syntax to access elements, but note that when accessed with non-const operator[], these entries will actually be created in the hash. So it's often better to use value() method:
if (myhash.value(43).value("fortytwo") >= 42) { /*...*/ }
Note that for QHash and QMap, accessing key which is not in the map is ok, default constructed value is returned in that case. Above for first it means and empty hash, and for second, value 0.0f.
To compare this to the method of using QPair from the other answer, this has the particular advantage that you can access elements by "rows" easily, if it matters for your use case (just make sure you have the nested hashes in the right order). Also, with this method, you could use different container for different dimensions, like if you need one dimension to be sorted use QMap (which is sorted by key) for that, and QHash (which is more efficient) for the dimension which doesn't need sorting. Additionally, you can have any number of dimensions easily, just add more nested containers.
On the other hand, if the key is logically a pair of values which are never separated, and data is not really (from programming perspective) organized as a two-dimensional table, then using QPair for key is probably better.
Unrelated to the question: to improve efficiency, in Qt 5 and C++11 you could use QStringLiteral("fortytwo") to have the QString created already at compile time.
Use a QPair as your key:
QHash<QPair<int,QString>,float> myhash;
Insert values:
myhash.insert(QPair<int,QString>(1,"string1"),12.);
or
QPair<int,QString> p(1,"string1");
myhash[p] = 12.

Combination of List and Hash in Qt

I need a data structure in which each element has a specific index but can also be retrieved using a key.
I need that data structure for model-view Programming in Qt.
On the one hand, the View asks for an element in a specific row.
On the other hand, the model wants to insert and modify elements with a given key.
Both operations should run in O(1).
Here is an example of what I want:
The View sees the following:
list[0]: "Alice", aged 22
list[1]: "Carol", aged 15
list[2]: "Bob", aged 23
The Model sees:
hash["Alice"]: "Alice", aged 22
hash["Bob"]: "Bob", aged 23
hash["Carol"]: "Carol", aged 15
My idea was the following: I have a QList<Value> and a QHash<Key, Value*>.
The hash points to the place in the list, where the corresponding element is stored.
This is the code to insert/edit values:
if (hash.contains(key))
*hash[key] = value;
else
{
int i = list.size();
list << value;
hash[key] = &list[i];
}
The problem is that this code does not always work.
Sometimes it works as expected, but it happens that the data structure is not consistent any more.
I suspect, it is because QList moves it's content through memory because it allocates new space or something like that.
Operations which are important (should run in expected O(1)):
Insert key/value pair (appends the value to the end of the list)
Look up and modify a value using a key
Look up and modify a value using an index
Other operations which have to be possible, but don't have to be possible in constant run time:
Delete an element by index
Delete an element by key
Insert in the middle of the array
Swap elements in the array / sort array
Get the index of a key
My two questions are:
Is there any data structure which does what I want?
If there is not, how could I fix this or is there a better approach?
Approach 1: Instead of the pointer, you can store the list index in the hash. Then you have one more indirection (from the hash, you get the index, then you retrieve from the list), but it is still O(1). The difference in speed should not be too much.
Approach 2: Both the list and the hash operate with pointers. Then they will stay valid. However, deleting based on index or key will become O(n), as you have to find the object manually in the non-corresponding container.
I also wonder how you want to solve the issue of deletion by index or insertion in the middle anyway. In both cases, the hash will point to wrong entries (both in your approach and Approach 1). Here you would be forced to go with Approach 2.

Alternative to search through a packed+unpacked array in systemverilog

I have this strange situation where i am currently doing this:
if (!this.randomize(delay) with {delay inside {strm};})
......
where
rand bit [2:0] delay;
bit [15:0] strm [bit [15:0]];
Now I want this delay to go in round robin from 0->....->7->0 and so on, but it should satisfy the condition that it should be present in strm. So I want something like
while (delay not in strm) begin
delay+=1;
end
Other than going though each and every index (2^16-1) is there any other way of finding if it exists in this packed+unpacked array? Thanks in advance!
If you are not aware, you are declaring strm as an associative array (aka a hash), where the key and the data are both 16 bit values.
If you want strm to be a fixed-size 2^16 entry array of 16-bit values, the declaration would be:
bit[15:0] strm [2**16];
With associative arrays you can use array.exists(key) to determine if the key is in the array. But it seems this may not be what you are trying to do.
With unpacked arrays, you can use the inside operator to test for set membership. But my simulator (Incisive) does not like this usage outside of a randomization call. So you may need to search for it yourself. However you don't have to iterate the entire array if you sort it first. And you can do that with array.sort().
I would also point out that you are looking for a 3-bit value in some sort of array of 16-bit values. This doesn't really make sense, so you may want to clarify your question.

Resources